Module Name:    src
Committed By:   dyoung
Date:           Fri Jun  3 20:01:00 UTC 2011

Modified Files:
        src/sys/netinet: tcp_vtw.c

Log Message:
Don't sleep until memory becomes available.

Use kmem_zalloc() instead of kmem_alloc() + bzero().

During initialization, try to get all of the memory we need for the
vestigial time-wait structures before we set any of the structures up,
and if any single allocation fails, release all of the memory.

This should help low-memory hosts.  A much better fix postpones
allocating any memory until vtw is enabled through the sysctl.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/netinet/tcp_vtw.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet/tcp_vtw.c
diff -u src/sys/netinet/tcp_vtw.c:1.5 src/sys/netinet/tcp_vtw.c:1.6
--- src/sys/netinet/tcp_vtw.c:1.5	Fri Jun  3 17:11:34 2011
+++ src/sys/netinet/tcp_vtw.c	Fri Jun  3 20:01:00 2011
@@ -77,7 +77,7 @@
 #include <machine/stdarg.h>
 #include <netinet/tcp_vtw.h>
 
-__KERNEL_RCSID(0, "$NetBSD: tcp_vtw.c,v 1.5 2011/06/03 17:11:34 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_vtw.c,v 1.6 2011/06/03 20:01:00 dyoung Exp $");
 
 #define db_trace(__a, __b)	do { } while (/*CONSTCOND*/0)
 
@@ -166,22 +166,15 @@
  * We allocate 2x as much, as we have two hashes: full and lport only.
  */
 static void
-fatp_init(fatp_ctl_t *fat, uint32_t n, uint32_t m)
+fatp_init(fatp_ctl_t *fat, uint32_t n, uint32_t m,
+    fatp_t *fat_base, fatp_t **fat_hash)
 {
 	fatp_t	*fp;
 
 	KASSERT(n <= FATP_MAX / 2);
 
-	fat->hash   = kmem_alloc(2*m * sizeof (fatp_t *), KM_SLEEP);
-	fat->base   = kmem_alloc(2*n * sizeof (fatp_t), KM_SLEEP);
-
-	if (!fat->base) {
-		if (fat->hash)
-			kmem_free(fat->hash, 2*m * sizeof (fatp_t *));
-
-		bzero(fat, sizeof (*fat));
-		return;
-	}
+	fat->hash = fat_hash;
+	fat->base = fat_base;
 
 	fat->port = &fat->hash[m];
 
@@ -190,9 +183,6 @@
 	fat->nfree  = 0;
 	fat->nalloc = 2*n;
 
-	bzero(fat->hash, 2*m * sizeof (fatp_t *));
-	bzero(fat->base, 2*n * sizeof (fatp_t));
-
 	/* Initialise the free list.
 	 */
 	for (fp = fat->lim; fp >= fat->base; --fp) {
@@ -1240,69 +1230,63 @@
  * by the operator.
  */
 static void
-vtw_init(fatp_ctl_t *fat, vtw_ctl_t *ctl, uint32_t n)
+vtw_init(fatp_ctl_t *fat, vtw_ctl_t *ctl, const uint32_t n, vtw_t *ctl_base_v)
 {
-	int i;
-	int sz = (ctl->is_v4 ? sizeof (vtw_v4_t) : sizeof (vtw_v6_t));
+	int class_n, i;
+	vtw_t	*base;
 
-	ctl->base.v4 = kmem_alloc(n * sz, KM_SLEEP);
-	if (ctl->base.v4) {
-		vtw_t	*base;
-		int	class_n;
+	ctl->base.v = ctl_base_v;
 
-		bzero(ctl->base.v4, n * sz);
+	if (ctl->is_v4) {
+		ctl->lim.v4    = ctl->base.v4 + n - 1;
+		ctl->alloc.v4  = ctl->base.v4;
+	} else {
+		ctl->lim.v6    = ctl->base.v6 + n - 1;
+		ctl->alloc.v6  = ctl->base.v6;
+	}
 
-		if (ctl->is_v4) {
-			ctl->lim.v4    = ctl->base.v4 + n - 1;
-			ctl->alloc.v4  = ctl->base.v4;
-		} else {
-			ctl->lim.v6    = ctl->base.v6 + n - 1;
-			ctl->alloc.v6  = ctl->base.v6;
-		}
+	ctl->nfree  = n;
+	ctl->ctl    = ctl;
 
-		ctl->nfree  = n;
-		ctl->ctl    = ctl;
+	ctl->idx_bits = 32;
+	for (ctl->idx_mask = ~0; (ctl->idx_mask & (n-1)) == n-1; ) {
+		ctl->idx_mask >>= 1;
+		ctl->idx_bits  -= 1;
+	}
 
-		ctl->idx_bits = 32;
-		for (ctl->idx_mask = ~0; (ctl->idx_mask & (n-1)) == n-1; ) {
-			ctl->idx_mask >>= 1;
-			ctl->idx_bits  -= 1;
-		}
+	ctl->idx_mask <<= 1;
+	ctl->idx_mask  |= 1;
+	ctl->idx_bits  += 1;
 
-		ctl->idx_mask <<= 1;
-		ctl->idx_mask  |= 1;
-		ctl->idx_bits  += 1;
+	ctl->fat = fat;
+	fat->vtw = ctl;
 
-		ctl->fat = fat;
-		fat->vtw = ctl;
+	/* Divide the resources equally amongst the classes.
+	 * This is not optimal, as the different classes
+	 * arrive and leave at different rates, but it is
+	 * the best I can do for now.
+	 */
+	class_n = n / (VTW_NCLASS-1);
+	base    = ctl->base.v;
 
-		/* Divide the resources equally amongst the classes.
-		 * This is not optimal, as the different classes
-		 * arrive and leave at different rates, but it is
-		 * the best I can do for now.
-		 */
-		class_n = n / (VTW_NCLASS-1);
-		base    = ctl->base.v;
+	for (i = 1; i < VTW_NCLASS; ++i) {
+		int j;
 
-		for (i = 1; i < VTW_NCLASS; ++i) {
-			int j;
+		ctl[i] = ctl[0];
+		ctl[i].clidx = i;
 
-			ctl[i] = ctl[0];
-			ctl[i].clidx = i;
+		ctl[i].base.v = base;
+		ctl[i].alloc  = ctl[i].base;
 
-			ctl[i].base.v = base;
-			ctl[i].alloc  = ctl[i].base;
-
-			for (j = 0; j < class_n - 1; ++j) {
-				if (tcp_msl_enable)
-					base->msl_class = i;
-				base = vtw_next(ctl, base);
-			}
-
-			ctl[i].lim.v = base;
+		for (j = 0; j < class_n - 1; ++j) {
+			if (tcp_msl_enable)
+				base->msl_class = i;
 			base = vtw_next(ctl, base);
-			ctl[i].nfree = class_n;
 		}
+
+		ctl[i].lim.v = base;
+		base = vtw_next(ctl, base);
+		ctl[i].nfree = class_n;
 	}
 
 	vtw_debug_init();
@@ -1778,36 +1762,62 @@
 {
 	fatp_ctl_t	*fat;
 	vtw_ctl_t	*ctl;
+	fatp_t		*fat_base;
+	fatp_t		**fat_hash;
+	vtw_t		*ctl_base_v;
+	uint32_t	n, m;
+	size_t sz;
+
+	KASSERT(powerof2(tcp_vtw_entries));
 
 	if (!vtw_select(af, &fat, &ctl))
 		return EAFNOSUPPORT;
 
-	if (!fat->base) {
-		uint32_t	n, m;
-
-		KASSERT(powerof2(tcp_vtw_entries));
+	if (fat->hash != NULL) {
+		KASSERT(fat->base != NULL && ctl->base.v != NULL);
+		return 0;
+	}
 
-		/* Allocate 10% more capacity in the fat pointers.
-		 * We should only need ~#hash additional based on
-		 * how they age, but TIME_WAIT assassination could cause
-		 * sparse fat pointer utilisation.
-		 */
-		m = 512;
-		n = 2*m + (11 * (tcp_vtw_entries / fatp_ntags())) / 10;
+	/* Allocate 10% more capacity in the fat pointers.
+	 * We should only need ~#hash additional based on
+	 * how they age, but TIME_WAIT assassination could cause
+	 * sparse fat pointer utilisation.
+	 */
+	m = 512;
+	n = 2*m + (11 * (tcp_vtw_entries / fatp_ntags())) / 10;
+	sz = (ctl->is_v4 ? sizeof(vtw_v4_t) : sizeof(vtw_v6_t));
+
+	fat_hash = kmem_zalloc(2*m * sizeof(fatp_t *), KM_NOSLEEP);
+
+	if (fat_hash == NULL) {
+		printf("%s: could not allocate %zu bytes for "
+		    "hash anchors", __func__, 2*m * sizeof(fatp_t *));
+		return ENOMEM;
+	}
 
-		fatp_init(fat, n, m);
+	fat_base = kmem_zalloc(2*n * sizeof(fatp_t), KM_NOSLEEP);
 
-		if (!fat->base)
-			return ENOMEM;
+	if (fat_base == NULL) {
+		kmem_free(fat_hash, 2*m * sizeof (fatp_t *));
+		printf("%s: could not allocate %zu bytes for "
+		    "fatp_t array", __func__, 2*n * sizeof(fatp_t));
+		return ENOMEM;
 	}
 
-	if (!ctl->base.v) {
+	ctl_base_v = kmem_zalloc(tcp_vtw_entries * sz, KM_NOSLEEP);
 
-		vtw_init(fat, ctl, tcp_vtw_entries);
-		if (!ctl->base.v)
-			return ENOMEM;
+	if (ctl_base_v == NULL) {
+		kmem_free(fat_hash, 2*m * sizeof (fatp_t *));
+		kmem_free(fat_base, 2*n * sizeof(fatp_t));
+		printf("%s: could not allocate %zu bytes for "
+		    "vtw_t array", __func__, tcp_vtw_entries * sz);
+		return ENOMEM;
 	}
 
+	fatp_init(fat, n, m, fat_base, fat_hash);
+
+	vtw_init(fat, ctl, tcp_vtw_entries, ctl_base_v);
+
 	return 0;
 }
 

Reply via email to