zonelimit livelock
Gleb Smirnoff
glebius at FreeBSD.org
Tue Aug 29 09:26:49 UTC 2006
On Mon, Aug 28, 2006 at 06:55:42PM +0200, Peter Holm wrote:
P> While stress testing GENERIC HEAD from Aug 26 13:08 UTC I ran into
P> this livelock:
P>
P> http://people.freebsd.org/~pho/stress/log/cons206.html
Which test leads to this?
btw, I have a patch against that. It isn't perfect, since it
does zone purging synchronously. And Suleiman said, that
the patch didn't help in his case.
--
Totus tuus, Glebius.
GLEBIUS-RIPN GLEB-RIPE
-------------- next part --------------
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.
*/
More information about the freebsd-current
mailing list