Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 Aug 2006 13:26:40 +0400
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        Peter Holm <peter@holm.cc>
Cc:        current@FreeBSD.org
Subject:   Re: zonelimit livelock
Message-ID:  <20060829092640.GM76666@FreeBSD.org>
In-Reply-To: <20060828165542.GA78024@peter.osted.lan>
References:  <20060828165542.GA78024@peter.osted.lan>

next in thread | previous in thread | raw e-mail | index | archive | help

--Uwl7UQhJk99r8jnw
Content-Type: text/plain; charset=koi8-r
Content-Disposition: inline

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

--Uwl7UQhJk99r8jnw
Content-Type: text/plain; charset=koi8-r
Content-Disposition: attachment; filename="zone_pack.diff"

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.
  */

--Uwl7UQhJk99r8jnw--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20060829092640.GM76666>