Allocate memory when dumping pipes with M_WAITOK flag. On a system with huge number of pipes, M_NOWAIT failes almost always, because of memory fragmentation. My fix is different than the patch proposed by Pawel Malachowski, because in FreeBSD 5.x we cannot sleep while holding dummynet mutex (in 4.x there is no such lock). PR: kern/46557 Submitted by: Eugene Grosbein Reviewed by: mlaier --- ip_dummynet.c Wed Aug 18 00:05:54 2004 +++ sys/netinet/ip_dummynet.c Wed Aug 25 11:31:30 2004 @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.83 2004/08/17 22:05:54 andre Exp $ + * $FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.84 2004/08/25 09:31:30 pjd Exp $ */ #define DUMMYNET_DEBUG @@ -1867,17 +1867,14 @@ return (char *)qp ; } -static int -dummynet_get(struct sockopt *sopt) +static size_t +dn_calc_size(void) { - char *buf, *bp ; /* bp is the "copy-pointer" */ - size_t size ; struct dn_flow_set *set ; struct dn_pipe *p ; - int error=0 ; + size_t size ; - /* XXX lock held too long */ - DUMMYNET_LOCK(); + DUMMYNET_LOCK_ASSERT(); /* * compute size of data structures: list of pipes and flow_sets. */ @@ -1887,8 +1884,35 @@ for (set = all_flow_sets ; set ; set = set->next ) size += sizeof ( *set ) + set->rq_elements * sizeof(struct dn_flow_queue); - buf = malloc(size, M_TEMP, M_NOWAIT); - if (buf == 0) { + return size ; +} + +static int +dummynet_get(struct sockopt *sopt) +{ + char *buf, *bp ; /* bp is the "copy-pointer" */ + size_t size ; + struct dn_flow_set *set ; + struct dn_pipe *p ; + int error=0, i ; + + /* XXX lock held too long */ + DUMMYNET_LOCK(); + /* + * XXX: Ugly, but we need to allocate memory with M_WAITOK flag and we + * cannot use this flag while holding a mutex. + */ + for (i = 0; i < 10; i++) { + size = dn_calc_size(); + DUMMYNET_UNLOCK(); + buf = malloc(size, M_TEMP, M_WAITOK); + DUMMYNET_LOCK(); + if (size == dn_calc_size()) + break; + free(buf, M_TEMP); + buf = NULL; + } + if (buf == NULL) { DUMMYNET_UNLOCK(); return ENOBUFS ; }