Turns out that when a receiver forwards through its TNS's the
processing code holds the read lock (when processing a FWD-TSN for pr-sctp). If it finds stranded data that can be given to the application, it calls sctp_add_to_readq(). The readq function also grabs this lock. So if INVAR is on we get a double recurse on a non-recursive lock and panic. This fix will change it so that readq() function gets a flag to tell if the lock is held, if so then it does not get the lock. Approved by: re@freebsd.org (Kostik Belousov) MFC after: 1 week
This commit is contained in:
parent
958fafa951
commit
cfde3ff70b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195918
@ -1960,7 +1960,7 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
|
||||
/* not that we need this */
|
||||
control->tail_mbuf = m_notify;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
|
||||
&stcb->sctp_socket->so_rcv, 1, so_locked);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
|
||||
}
|
||||
|
||||
|
||||
|
@ -388,7 +388,8 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
else
|
||||
end = 0;
|
||||
sctp_add_to_readq(stcb->sctp_ep,
|
||||
stcb, control, &stcb->sctp_socket->so_rcv, end, SCTP_SO_NOT_LOCKED);
|
||||
stcb, control, &stcb->sctp_socket->so_rcv, end,
|
||||
SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
cntDel++;
|
||||
} else {
|
||||
if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG)
|
||||
@ -516,7 +517,8 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
nr_tsn = ctl->sinfo_tsn;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
ctl,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1,
|
||||
SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY -now something is
|
||||
* delivered, calculate
|
||||
@ -685,8 +687,8 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
nr_tsn = control->sinfo_tsn;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
|
||||
&stcb->sctp_socket->so_rcv, 1,
|
||||
SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY this is the chunk that should be tagged nr gapped
|
||||
* calculate the gap and such then tag this TSN nr
|
||||
@ -739,7 +741,9 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
nr_tsn = control->sinfo_tsn;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1,
|
||||
SCTP_READ_LOCK_NOT_HELD,
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY this is the chunk that should be
|
||||
* tagged nr gapped calculate the gap and
|
||||
@ -1910,7 +1914,9 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
if (control == NULL) {
|
||||
goto failed_express_del;
|
||||
}
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control, &stcb->sctp_socket->so_rcv,
|
||||
1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
|
||||
/*
|
||||
* EY here I should check if this delivered tsn is
|
||||
@ -2248,7 +2254,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
/* queue directly into socket buffer */
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
|
||||
/*
|
||||
* EY It is added to the read queue in prev if block
|
||||
@ -5722,7 +5728,7 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
|
||||
nr_tsn = ctl->sinfo_tsn;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
ctl,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY this is the chunk that should be
|
||||
* tagged nr gapped calculate the gap and
|
||||
@ -5823,7 +5829,7 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
|
||||
nr_tsn = ctl->sinfo_tsn;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
ctl,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY this is the chunk that should be
|
||||
* tagged nr gapped calculate the gap and
|
||||
|
@ -2839,7 +2839,8 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
|
||||
control->spec_flags = M_NOTIFICATION;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, so_locked);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
|
||||
so_locked);
|
||||
if (event == SCTP_COMM_LOST) {
|
||||
/* Wake up any sleeper */
|
||||
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
||||
@ -2935,7 +2936,9 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
|
||||
control->tail_mbuf = m_notify;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1,
|
||||
SCTP_READ_LOCK_NOT_HELD,
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
|
||||
|
||||
@ -3016,7 +3019,9 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
|
||||
control->spec_flags = M_NOTIFICATION;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, so_locked);
|
||||
&stcb->sctp_socket->so_rcv, 1,
|
||||
SCTP_READ_LOCK_NOT_HELD,
|
||||
so_locked);
|
||||
}
|
||||
|
||||
|
||||
@ -3090,7 +3095,7 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
|
||||
control->spec_flags = M_NOTIFICATION;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, so_locked);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
|
||||
}
|
||||
|
||||
|
||||
@ -3137,7 +3142,7 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
|
||||
control->tail_mbuf = m_notify;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
|
||||
/* This always must be called with the read-queue LOCKED in the INP */
|
||||
@ -3277,7 +3282,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
|
||||
control->tail_mbuf = m_notify;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3324,7 +3329,7 @@ sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
|
||||
/* not that we need this */
|
||||
control->tail_mbuf = m_notify;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
|
||||
&stcb->sctp_socket->so_rcv, 1, so_locked);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
|
||||
}
|
||||
|
||||
|
||||
@ -3380,7 +3385,7 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int number_entries, int flag
|
||||
control->tail_mbuf = m_notify;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
|
||||
|
||||
@ -3446,7 +3451,7 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
|
||||
control->tail_mbuf = m_notify;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
|
||||
|
||||
@ -4301,6 +4306,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
|
||||
struct sctp_queued_to_read *control,
|
||||
struct sockbuf *sb,
|
||||
int end,
|
||||
int inp_read_lock_held,
|
||||
int so_locked
|
||||
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
||||
SCTP_UNUSED
|
||||
@ -4321,7 +4327,8 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
SCTP_INP_READ_LOCK(inp);
|
||||
if (inp_read_lock_held == 0)
|
||||
SCTP_INP_READ_LOCK(inp);
|
||||
if (!(control->spec_flags & M_NOTIFICATION)) {
|
||||
atomic_add_int(&inp->total_recvs, 1);
|
||||
if (!control->do_not_ref_stcb) {
|
||||
@ -4362,14 +4369,16 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
|
||||
control->tail_mbuf = prev;
|
||||
} else {
|
||||
/* Everything got collapsed out?? */
|
||||
SCTP_INP_READ_UNLOCK(inp);
|
||||
if (inp_read_lock_held == 0)
|
||||
SCTP_INP_READ_UNLOCK(inp);
|
||||
return;
|
||||
}
|
||||
if (end) {
|
||||
control->end_added = 1;
|
||||
}
|
||||
TAILQ_INSERT_TAIL(&inp->read_queue, control, next);
|
||||
SCTP_INP_READ_UNLOCK(inp);
|
||||
if (inp_read_lock_held == 0)
|
||||
SCTP_INP_READ_UNLOCK(inp);
|
||||
if (inp && inp->sctp_socket) {
|
||||
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
|
||||
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
|
||||
|
@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#if defined(_KERNEL) || defined(__Userspace__)
|
||||
|
||||
#define SCTP_READ_LOCK_HELD 1
|
||||
#define SCTP_READ_LOCK_NOT_HELD 0
|
||||
|
||||
#ifdef SCTP_ASOCLOG_OF_TSNS
|
||||
void sctp_print_out_track_log(struct sctp_tcb *stcb);
|
||||
@ -103,6 +105,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
|
||||
struct sctp_queued_to_read *control,
|
||||
struct sockbuf *sb,
|
||||
int end,
|
||||
int inpread_locked,
|
||||
int so_locked
|
||||
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
||||
SCTP_UNUSED
|
||||
|
Loading…
Reference in New Issue
Block a user