Print this page
1631 kernel panic in tcp_input_data
*** 19,28 ****
--- 19,29 ----
* CDDL HEADER END
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/* This file contains all TCP input processing functions. */
#include <sys/types.h>
*** 2228,2237 ****
--- 2229,2346 ----
return (mp1);
}
}
/*
+ * Dummy socket upcalls for if/when the conn_t gets detached from a
+ * direct-callback sonode via a user-driven close(). Easy to catch with
+ * DTrace FBT, and should be mostly harmless.
+ */
+
+ /* ARGSUSED */
+ static sock_upper_handle_t
+ tcp_dummy_newconn(sock_upper_handle_t x, sock_lower_handle_t y,
+ sock_downcalls_t *z, cred_t *cr, pid_t pid, sock_upcalls_t **ignored)
+ {
+ ASSERT(0); /* Panic in debug, otherwise ignore. */
+ return (NULL);
+ }
+
+ /* ARGSUSED */
+ static void
+ tcp_dummy_connected(sock_upper_handle_t x, sock_connid_t y, cred_t *cr,
+ pid_t pid)
+ {
+ ASSERT(x == NULL);
+ /* Normally we'd crhold(cr) and attach it to socket state. */
+ /* LINTED */
+ }
+
+ /* ARGSUSED */
+ static int
+ tcp_dummy_disconnected(sock_upper_handle_t x, sock_connid_t y, int blah)
+ {
+ ASSERT(0); /* Panic in debug, otherwise ignore. */
+ return (-1);
+ }
+
+ /* ARGSUSED */
+ static void
+ tcp_dummy_opctl(sock_upper_handle_t x, sock_opctl_action_t y, uintptr_t blah)
+ {
+ ASSERT(x == NULL);
+ /* We really want this one to be a harmless NOP for now. */
+ /* LINTED */
+ }
+
+ /* ARGSUSED */
+ static ssize_t
+ tcp_dummy_recv(sock_upper_handle_t x, mblk_t *mp, size_t len, int flags,
+ int *error, boolean_t *push)
+ {
+ ASSERT(x == NULL);
+
+ /*
+ * Consume the message, set ESHUTDOWN, and return an error.
+ * Nobody's home!
+ */
+ freemsg(mp);
+ *error = ESHUTDOWN;
+ return (-1);
+ }
+
+ /* ARGSUSED */
+ static void
+ tcp_dummy_set_proto_props(sock_upper_handle_t x, struct sock_proto_props *y)
+ {
+ ASSERT(0); /* Panic in debug, otherwise ignore. */
+ }
+
+ /* ARGSUSED */
+ static void
+ tcp_dummy_txq_full(sock_upper_handle_t x, boolean_t y)
+ {
+ ASSERT(0); /* Panic in debug, otherwise ignore. */
+ }
+
+ /* ARGSUSED */
+ static void
+ tcp_dummy_signal_oob(sock_upper_handle_t x, ssize_t len)
+ {
+ ASSERT(x == NULL);
+ /* Otherwise, this would signal socket state about OOB data. */
+ }
+
+ /* ARGSUSED */
+ static void
+ tcp_dummy_set_error(sock_upper_handle_t x, int err)
+ {
+ ASSERT(0); /* Panic in debug, otherwise ignore. */
+ }
+
+ /* ARGSUSED */
+ static void
+ tcp_dummy_onearg(sock_upper_handle_t x)
+ {
+ ASSERT(0); /* Panic in debug, otherwise ignore. */
+ }
+
+ static sock_upcalls_t tcp_dummy_upcalls = {
+ tcp_dummy_newconn,
+ tcp_dummy_connected,
+ tcp_dummy_disconnected,
+ tcp_dummy_opctl,
+ tcp_dummy_recv,
+ tcp_dummy_set_proto_props,
+ tcp_dummy_txq_full,
+ tcp_dummy_signal_oob,
+ tcp_dummy_onearg,
+ tcp_dummy_set_error,
+ tcp_dummy_onearg
+ };
+
+ /*
* Handle M_DATA messages from IP. Its called directly from IP via
* squeue for received IP packets.
*
* The first argument is always the connp/tcp to which the mp belongs.
* There are no exceptions to this rule. The caller has already put
*** 2269,2278 ****
--- 2378,2388 ----
int mss;
conn_t *connp = (conn_t *)arg;
squeue_t *sqp = (squeue_t *)arg2;
tcp_t *tcp = connp->conn_tcp;
tcp_stack_t *tcps = tcp->tcp_tcps;
+ sock_upcalls_t *sockupcalls;
/*
* RST from fused tcp loopback peer should trigger an unfuse.
*/
if (tcp->tcp_fused) {
*** 2394,2403 ****
--- 2504,2518 ----
mp->b_wptr = (uchar_t *)tcpha + TCP_HDR_LENGTH(tcpha);
seg_len = 0;
}
}
+ sockupcalls = connp->conn_upcalls;
+ /* A conn_t may have belonged to a now-closed socket. Be careful. */
+ if (sockupcalls == NULL)
+ sockupcalls = &tcp_dummy_upcalls;
+
switch (tcp->tcp_state) {
case TCPS_SYN_SENT:
if (connp->conn_final_sqp == NULL &&
tcp_outbound_squeue_switch && sqp != NULL) {
ASSERT(connp->conn_initial_sqp == connp->conn_sqp);
*** 2605,2616 ****
ira->ira_cred,
ira->ira_cpid);
}
putnext(connp->conn_rq, mp1);
} else {
! (*connp->conn_upcalls->
! su_connected)
(connp->conn_upper_handle,
tcp->tcp_connid,
ira->ira_cred,
ira->ira_cpid);
freemsg(mp1);
--- 2720,2730 ----
ira->ira_cred,
ira->ira_cpid);
}
putnext(connp->conn_rq, mp1);
} else {
! (*sockupcalls->su_connected)
(connp->conn_upper_handle,
tcp->tcp_connid,
ira->ira_cred,
ira->ira_cpid);
freemsg(mp1);
*** 2633,2643 ****
mblk_setcred(mp1, ira->ira_cred,
ira->ira_cpid);
}
putnext(connp->conn_rq, mp1);
} else {
! (*connp->conn_upcalls->su_connected)
(connp->conn_upper_handle,
tcp->tcp_connid, ira->ira_cred,
ira->ira_cpid);
freemsg(mp1);
}
--- 2747,2757 ----
mblk_setcred(mp1, ira->ira_cred,
ira->ira_cpid);
}
putnext(connp->conn_rq, mp1);
} else {
! (*sockupcalls->su_connected)
(connp->conn_upper_handle,
tcp->tcp_connid, ira->ira_cred,
ira->ira_cpid);
freemsg(mp1);
}
*** 3007,3018 ****
if ((flags & TH_URG) &&
(!tcp->tcp_urp_last_valid || SEQ_GT(urp + seg_seq,
tcp->tcp_urp_last))) {
if (IPCL_IS_NONSTR(connp)) {
if (!TCP_IS_DETACHED(tcp)) {
! (*connp->conn_upcalls->
! su_signal_oob)
(connp->conn_upper_handle,
urp);
}
} else {
mp1 = allocb(0, BPRI_MED);
--- 3121,3131 ----
if ((flags & TH_URG) &&
(!tcp->tcp_urp_last_valid || SEQ_GT(urp + seg_seq,
tcp->tcp_urp_last))) {
if (IPCL_IS_NONSTR(connp)) {
if (!TCP_IS_DETACHED(tcp)) {
! (*sockupcalls->su_signal_oob)
(connp->conn_upper_handle,
urp);
}
} else {
mp1 = allocb(0, BPRI_MED);
*** 3286,3296 ****
* Neither TH_SEND_URP_MARK nor TH_MARKNEXT_NEEDED
* are used by non-STREAMS sockets.
*/
if (IPCL_IS_NONSTR(connp)) {
if (!TCP_IS_DETACHED(tcp)) {
! (*connp->conn_upcalls->su_signal_oob)
(connp->conn_upper_handle, urp);
}
} else {
/*
* If we haven't generated the signal yet for
--- 3399,3409 ----
* Neither TH_SEND_URP_MARK nor TH_MARKNEXT_NEEDED
* are used by non-STREAMS sockets.
*/
if (IPCL_IS_NONSTR(connp)) {
if (!TCP_IS_DETACHED(tcp)) {
! (*sockupcalls->su_signal_oob)
(connp->conn_upper_handle, urp);
}
} else {
/*
* If we haven't generated the signal yet for
*** 3445,3455 ****
* have to allocate the T_exdata_ind, if we can.
*/
if (IPCL_IS_NONSTR(connp)) {
int error;
! (*connp->conn_upcalls->su_recv)
(connp->conn_upper_handle, mp, seg_len,
MSG_OOB, &error, NULL);
/*
* We should never be in middle of a
* fallback, the squeue guarantees that.
--- 3558,3568 ----
* have to allocate the T_exdata_ind, if we can.
*/
if (IPCL_IS_NONSTR(connp)) {
int error;
! (*sockupcalls->su_recv)
(connp->conn_upper_handle, mp, seg_len,
MSG_OOB, &error, NULL);
/*
* We should never be in middle of a
* fallback, the squeue guarantees that.
*** 4624,4635 ****
* Non-STREAMS socket
*/
boolean_t push = flags & (TH_PUSH|TH_FIN);
int error;
! if ((*connp->conn_upcalls->su_recv)(
! connp->conn_upper_handle,
mp, seg_len, 0, &error, &push) <= 0) {
/*
* We should never be in middle of a
* fallback, the squeue guarantees that.
*/
--- 4737,4747 ----
* Non-STREAMS socket
*/
boolean_t push = flags & (TH_PUSH|TH_FIN);
int error;
! if ((*sockupcalls->su_recv)(connp->conn_upper_handle,
mp, seg_len, 0, &error, &push) <= 0) {
/*
* We should never be in middle of a
* fallback, the squeue guarantees that.
*/
*** 4867,4878 ****
ASSERT(!tcp->tcp_detached);
if (IPCL_IS_NONSTR(connp)) {
ASSERT(tcp->tcp_ordrel_mp == NULL);
tcp->tcp_ordrel_done = B_TRUE;
! (*connp->conn_upcalls->su_opctl)
! (connp->conn_upper_handle, SOCK_OPCTL_SHUT_RECV, 0);
goto done;
}
if (tcp->tcp_rcv_list != NULL) {
/*
--- 4979,4990 ----
ASSERT(!tcp->tcp_detached);
if (IPCL_IS_NONSTR(connp)) {
ASSERT(tcp->tcp_ordrel_mp == NULL);
tcp->tcp_ordrel_done = B_TRUE;
! (*sockupcalls->su_opctl)(connp->conn_upper_handle,
! SOCK_OPCTL_SHUT_RECV, 0);
goto done;
}
if (tcp->tcp_rcv_list != NULL) {
/*