Index: vm/uma.h =================================================================== RCS file: /home/ncvs/src/sys/vm/uma.h,v retrieving revision 1.28 diff -u -p -r1.28 uma.h --- vm/uma.h 8 Oct 2005 21:03:54 -0000 1.28 +++ vm/uma.h 23 May 2006 08:08:08 -0000 @@ -139,6 +139,21 @@ typedef void (*uma_fini)(void *mem, int * */ +/* + * Zone low on memory callback + * + * Arguments: + * zone Zone the callback called for. + * + * Returns: + * 0 on failure. UMA subsystem should msleep() awaiting for free memory. + * n on success. UMA subsystem should try again to allocate an item. + * + * Discussion: + * This routine is called synchronously from allocation code path, + * when zone reaches its maximum number of allocations. + */ +typedef int (*uma_mlow)(uma_zone_t zone); /* Function proto types */ @@ -246,6 +261,15 @@ uma_zone_t uma_zsecond_create(char *name void uma_zdestroy(uma_zone_t zone); /* + * Drains caches from an uma zone. + * + * Arguments: + * zone The zone we want to drain. + * + */ +void uma_zdrain(uma_zone_t zone); + +/* * Allocates an item out of a zone * * Arguments: @@ -417,6 +441,18 @@ int uma_zone_set_obj(uma_zone_t zone, st void uma_zone_set_max(uma_zone_t zone, int nitems); /* + * Sets a callback that would be called when zone is low + * on memory. + * + * Arguments: + * zone The zone to work on. + * + * Returns: + * Nothing + */ +void uma_zone_set_mlow(uma_zone_t zone, uma_mlow func); + +/* * The following two routines (uma_zone_set_init/fini) * are used to set the backend init/fini pair which acts on an * object as it becomes allocated and is placed in a slab within Index: vm/uma_core.c =================================================================== RCS file: /home/ncvs/src/sys/vm/uma_core.c,v retrieving revision 1.139 diff -u -p -r1.139 uma_core.c --- vm/uma_core.c 18 Jul 2006 01:13:18 -0000 1.139 +++ vm/uma_core.c 2 Aug 2006 12:48:08 -0000 @@ -675,7 +675,6 @@ bucket_cache_drain(uma_zone_t zone) * * Arguments: * zone The zone to free pages from - * all Should we drain all items? * * Returns: * Nothing. @@ -767,6 +766,15 @@ finished: } /* + * Public method for zone_drain(). + */ +void +uma_zdrain(uma_zone_t zone) +{ + zone_drain(zone); +} + +/* * Allocate a new slab for a zone. This does not insert the slab onto a list. * * Arguments: @@ -1952,6 +1960,7 @@ uma_zone_slab(uma_zone_t zone, int flags { uma_slab_t slab; uma_keg_t keg; + int ntries = 1; keg = zone->uz_keg; @@ -2009,9 +2018,13 @@ uma_zone_slab(uma_zone_t zone, int flags if (flags & M_NOWAIT) break; - else - msleep(keg, &keg->uk_lock, PVM, - "zonelimit", 0); + + if (ntries && zone->uz_mlow && (*zone->uz_mlow)(zone)) { + ntries = 0; + continue; + } + + msleep(keg, &keg->uk_lock, PVM, "zonelimit", 0); continue; } keg->uk_recurse++; @@ -2522,6 +2535,15 @@ uma_zone_set_max(uma_zone_t zone, int ni /* See uma.h */ void +uma_zone_set_mlow(uma_zone_t zone, uma_mlow func) +{ + ZONE_LOCK(zone); + zone->uz_mlow = func; + ZONE_UNLOCK(zone); +} + +/* See uma.h */ +void uma_zone_set_init(uma_zone_t zone, uma_init uminit) { ZONE_LOCK(zone); Index: vm/uma_int.h =================================================================== RCS file: /home/ncvs/src/sys/vm/uma_int.h,v retrieving revision 1.37 diff -u -p -r1.37 uma_int.h --- vm/uma_int.h 4 Aug 2005 10:03:53 -0000 1.37 +++ vm/uma_int.h 23 May 2006 08:08:20 -0000 @@ -301,6 +301,7 @@ struct uma_zone { uma_dtor uz_dtor; /* Destructor */ uma_init uz_init; /* Initializer for each item */ uma_fini uz_fini; /* Discards memory */ + uma_mlow uz_mlow; /* Called when zone is low on memory */ u_int64_t uz_allocs; /* Total number of allocations */ u_int64_t uz_frees; /* Total number of frees */ Index: kern/kern_mbuf.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_mbuf.c,v retrieving revision 1.25 diff -u -p -r1.25 kern_mbuf.c --- kern/kern_mbuf.c 10 Jun 2006 14:34:07 -0000 1.25 +++ kern/kern_mbuf.c 16 Aug 2006 17:41:37 -0000 @@ -164,6 +164,7 @@ static void mb_dtor_pack(void *, int, vo static int mb_zinit_pack(void *, int, int); static void mb_zfini_pack(void *, int); static int mt_zinit_vlan(void *, int, int); +static int mb_zonelow_clust(uma_zone_t); static void mb_reclaim(void *); static void mbuf_init(void *); @@ -199,8 +200,10 @@ mbuf_init(void *dummy) NULL, NULL, #endif UMA_ALIGN_PTR, UMA_ZONE_REFCNT); - if (nmbclusters > 0) + if (nmbclusters > 0) { uma_zone_set_max(zone_clust, nmbclusters); + uma_zone_set_mlow(zone_clust, mb_zonelow_clust); + } zone_pack = uma_zsecond_create(MBUF_PACKET_MEM_NAME, mb_ctor_pack, mb_dtor_pack, mb_zinit_pack, mb_zfini_pack, zone_mbuf); @@ -450,6 +453,18 @@ mb_dtor_clust(void *mem, int size, void } /* + * The Mbuf Cluster low on memory callback. + */ +static int +mb_zonelow_clust(uma_zone_t zone) +{ + + KASSERT(zone == zone_clust, ("%s called on uknown zone", __func__)); + uma_zdrain(zone_pack); + return (1); +} + +/* * The Packet secondary zone's init routine, executed on the * object's transition from mbuf keg slab to zone cache. */