tcp_timewait() performs multiple non-atomic reads on the tcptw
structure, so assert the inpcb lock associated with the tcptw. Also assert the tcbinfo lock, as tcp_timewait() may call tcp_twclose() or tcp_2msl_rest(), which require it. Since tcp_timewait() is already called with that lock from tcp_input(), this doesn't change current locking, merely documents reasons for it. In tcp_twstart(), assert the tcbinfo lock, as tcp_timer_2msl_rest() is called, which requires that lock. In tcp_twclose(), assert the tcbinfo lock, as tcp_timer_2msl_stop() is called, which requires that lock. Document the locking strategy for the time wait queues in tcp_timer.c, which consists of protecting the time wait queues in the same manner as the tcbinfo structure (using the tcbinfo lock). In tcp_timer_2msl_reset(), assert the tcbinfo lock, as the time wait queues are modified. In tcp_timer_2msl_stop(), assert the tcbinfo lock, as the time wait queues may be modified. In tcp_timer_2msl_tw(), assert the tcbinfo lock, as the time wait queues may be modified. MFC after: 2 weeks
This commit is contained in:
parent
53e97a895b
commit
75d5a09a05
@ -3062,6 +3062,10 @@ tcp_timewait(tw, to, th, m, tlen)
|
||||
const int isipv6 = 0;
|
||||
#endif
|
||||
|
||||
/* tcbinfo lock required for tcp_twclose(), tcp_2msl_reset. */
|
||||
INP_INFO_WLOCK_ASSERT(&tcbinfo);
|
||||
INP_LOCK_ASSERT(tw->tw_inpcb);
|
||||
|
||||
thflags = th->th_flags;
|
||||
|
||||
/*
|
||||
|
@ -3062,6 +3062,10 @@ tcp_timewait(tw, to, th, m, tlen)
|
||||
const int isipv6 = 0;
|
||||
#endif
|
||||
|
||||
/* tcbinfo lock required for tcp_twclose(), tcp_2msl_reset. */
|
||||
INP_INFO_WLOCK_ASSERT(&tcbinfo);
|
||||
INP_LOCK_ASSERT(tw->tw_inpcb);
|
||||
|
||||
thflags = th->th_flags;
|
||||
|
||||
/*
|
||||
|
@ -1624,6 +1624,7 @@ tcp_twstart(tp)
|
||||
int tw_time, acknow;
|
||||
struct socket *so;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(&tcbinfo); /* tcp_timer_2msl_reset(). */
|
||||
INP_LOCK_ASSERT(tp->t_inpcb);
|
||||
|
||||
tw = uma_zalloc(tcptw_zone, M_NOWAIT);
|
||||
@ -1722,6 +1723,7 @@ tcp_twclose(struct tcptw *tw, int reuse)
|
||||
struct inpcb *inp;
|
||||
|
||||
inp = tw->tw_inpcb;
|
||||
INP_INFO_WLOCK_ASSERT(&tcbinfo); /* tcp_timer_2msl_stop(). */
|
||||
INP_LOCK_ASSERT(inp);
|
||||
|
||||
tw->tw_inpcb = NULL;
|
||||
|
@ -246,6 +246,12 @@ tcp_timer_2msl(xtp)
|
||||
INP_INFO_WUNLOCK(&tcbinfo);
|
||||
}
|
||||
|
||||
/*
|
||||
* The timed wait lists contain references to each of the TCP sessions
|
||||
* currently TIME_WAIT state. The list pointers, including the list pointers
|
||||
* in each tcptw structure, are protected using the global tcbinfo lock,
|
||||
* which must be held over list iteration and modification.
|
||||
*/
|
||||
struct twlist {
|
||||
LIST_HEAD(, tcptw) tw_list;
|
||||
struct tcptw tw_tail;
|
||||
@ -273,6 +279,7 @@ tcp_timer_2msl_reset(struct tcptw *tw, int timeo)
|
||||
int i;
|
||||
struct tcptw *tw_tail;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(&tcbinfo);
|
||||
if (tw->tw_time != 0)
|
||||
LIST_REMOVE(tw, tw_2msl);
|
||||
tw->tw_time = timeo + ticks;
|
||||
@ -285,6 +292,7 @@ void
|
||||
tcp_timer_2msl_stop(struct tcptw *tw)
|
||||
{
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(&tcbinfo);
|
||||
if (tw->tw_time != 0)
|
||||
LIST_REMOVE(tw, tw_2msl);
|
||||
}
|
||||
@ -296,6 +304,7 @@ tcp_timer_2msl_tw(int reuse)
|
||||
struct twlist *twl;
|
||||
int i;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(&tcbinfo);
|
||||
for (i = 0; i < 2; i++) {
|
||||
twl = tw_2msl_list[i];
|
||||
tw_tail = &twl->tw_tail;
|
||||
|
@ -1624,6 +1624,7 @@ tcp_twstart(tp)
|
||||
int tw_time, acknow;
|
||||
struct socket *so;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(&tcbinfo); /* tcp_timer_2msl_reset(). */
|
||||
INP_LOCK_ASSERT(tp->t_inpcb);
|
||||
|
||||
tw = uma_zalloc(tcptw_zone, M_NOWAIT);
|
||||
@ -1722,6 +1723,7 @@ tcp_twclose(struct tcptw *tw, int reuse)
|
||||
struct inpcb *inp;
|
||||
|
||||
inp = tw->tw_inpcb;
|
||||
INP_INFO_WLOCK_ASSERT(&tcbinfo); /* tcp_timer_2msl_stop(). */
|
||||
INP_LOCK_ASSERT(inp);
|
||||
|
||||
tw->tw_inpcb = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user