Index: sys/kern/uipc_socket.c =================================================================== --- sys/kern/uipc_socket.c +++ sys/kern/uipc_socket.c @@ -583,34 +583,44 @@ struct socket * sonewconn(struct socket *head, int connstatus) { - static struct timeval lastover; - static struct timeval overinterval = { 60, 0 }; - static int overcount; - + const struct timeval overinterval = { 60, 0 }; struct socket *so; - u_int over; + int overcount; + u_int qlen; + bool dolog, over; SOLISTEN_LOCK(head); over = (head->sol_qlen > 3 * head->sol_qlimit / 2); - SOLISTEN_UNLOCK(head); #ifdef REGRESSION if (regression_sonewconn_earlytest && over) { #else if (over) { #endif - overcount++; + head->sol_overcount++; + dolog = !!ratecheck(&head->sol_lastover, &overinterval); - if (ratecheck(&lastover, &overinterval)) { + /* + * If we're going to log, copy the overflow count and queue + * length from the listen socket before dropping the lock. + * Also, reset the overflow count. + */ + if (dolog) { + overcount = head->sol_overcount; + head->sol_overcount = 0; + qlen = head->sol_qlen; + } + SOLISTEN_UNLOCK(head); + + if (dolog) { log(LOG_DEBUG, "%s: pcb %p: Listen queue overflow: " "%i already in queue awaiting acceptance " "(%d occurrences)\n", - __func__, head->so_pcb, head->sol_qlen, overcount); - - overcount = 0; + __func__, head->so_pcb, qlen, overcount); } return (NULL); } + SOLISTEN_UNLOCK(head); VNET_ASSERT(head->so_vnet != NULL, ("%s: so %p vnet is NULL", __func__, head)); so = soalloc(head->so_vnet); Index: sys/sys/socketvar.h =================================================================== --- sys/sys/socketvar.h +++ sys/sys/socketvar.h @@ -172,6 +172,10 @@ short sol_sbsnd_flags; sbintime_t sol_sbrcv_timeo; sbintime_t sol_sbsnd_timeo; + + /* Information tracking listen queue overflows. */ + struct timeval sol_lastover; /* (e) */ + int sol_overcount; /* (e) */ }; }; };