Fix a race in the manipulation of the V_tcp_sack_globalholes global variable,

which is currently not protected by any type of lock. When triggered, the bug
would sometimes cause a panic when the TCP activity to an affected machine
eventually slowed during a lull. The panic only occurs if INVARIANTS is compiled
into the kernel, and has laid dormant for some time as a result of INVARIANTS
being off by default except in FreeBSD-CURRENT.

Switch to atomic operations in the locations where the variable is changed.
Reads have not been updated to be protected by atomics, so there is a
possibility of accounting errors in any given calculation where the variable is
read. This is considered unlikely to occur in the wild, and will not cause
serious harm on rare occasions where it does.

Thanks to Robert Watson for debugging help.

Reported by:	Kamigishi Rei <spambox at haruhiism dot net>
Tested by:	Kamigishi Rei <spambox at haruhiism dot net>
Reviewed by:	silby
Approved by:	re (rwatson), kensmith (mentor temporarily unavailable)
This commit is contained in:
Lawrence Stewart 2009-07-13 11:59:38 +00:00
parent 237fbe0a1c
commit 91a5ebde45

View File

@ -273,7 +273,7 @@ tcp_sackhole_alloc(struct tcpcb *tp, tcp_seq start, tcp_seq end)
hole->rxmit = start; hole->rxmit = start;
tp->snd_numholes++; tp->snd_numholes++;
V_tcp_sack_globalholes++; atomic_add_int(&V_tcp_sack_globalholes, 1);
return hole; return hole;
} }
@ -289,7 +289,7 @@ tcp_sackhole_free(struct tcpcb *tp, struct sackhole *hole)
uma_zfree(V_sack_hole_zone, hole); uma_zfree(V_sack_hole_zone, hole);
tp->snd_numholes--; tp->snd_numholes--;
V_tcp_sack_globalholes--; atomic_subtract_int(&V_tcp_sack_globalholes, 1);
KASSERT(tp->snd_numholes >= 0, ("tp->snd_numholes >= 0")); KASSERT(tp->snd_numholes >= 0, ("tp->snd_numholes >= 0"));
KASSERT(V_tcp_sack_globalholes >= 0, ("tcp_sack_globalholes >= 0")); KASSERT(V_tcp_sack_globalholes >= 0, ("tcp_sack_globalholes >= 0"));