From ee0a5eb928ae5ccdf1a0e619b4ba6e93d19db5fb Mon Sep 17 00:00:00 2001 From: ups Date: Tue, 18 Jul 2006 22:34:27 +0000 Subject: Fix race conditions on enumerating pcb lists by moving the initialization ( and where appropriate the destruction) of the pcb mutex to the init/finit functions of the pcb zones. This allows locking of the pcb entries and race condition free comparison of the generation count. Rearrange locking a bit to avoid extra locking operation to update the generation count in in_pcballoc(). (in_pcballoc now returns the pcb locked) I am planning to convert pcb list handling from a type safe to a reference count model soon. ( As this allows really freeing the PCBs) Reviewed by: rwatson@, mohans@ MFC after: 1 week --- sys/netinet/tcp_timewait.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'sys/netinet/tcp_timewait.c') diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 89bd41c..676b22e 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -262,6 +262,14 @@ tcp_zone_change(void *tag) uma_zone_set_max(tcptw_zone, maxsockets / 5); } +static int +tcp_inpcb_init(void *mem, int size, int flags) +{ + struct inpcb *inp = (struct inpcb *) mem; + INP_LOCK_INIT(inp, "inp", "tcpinp"); + return (0); +} + void tcp_init(void) { @@ -290,7 +298,7 @@ tcp_init(void) tcbinfo.porthashbase = hashinit(hashsize, M_PCB, &tcbinfo.porthashmask); tcbinfo.ipi_zone = uma_zcreate("inpcb", sizeof(struct inpcb), - NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); + NULL, NULL, tcp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); uma_zone_set_max(tcbinfo.ipi_zone, maxsockets); #ifdef INET6 #define TCP_MINPROTOHDR (sizeof(struct ip6_hdr) + sizeof(struct tcphdr)) @@ -989,6 +997,7 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS) error = 0; for (i = 0; i < n; i++) { inp = inp_list[i]; + INP_LOCK(inp); if (inp->inp_gencnt <= gencnt) { struct xtcpcb xt; void *inp_ppcb; @@ -1012,8 +1021,11 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS) xt.xt_socket.xso_protocol = IPPROTO_TCP; } xt.xt_inp.inp_gencnt = inp->inp_gencnt; + INP_UNLOCK(inp); error = SYSCTL_OUT(req, &xt, sizeof xt); - } + } else + INP_UNLOCK(inp); + } if (!error) { /* -- cgit v1.1