Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/netinet Don't sleep until memory becomes available.



details:   https://anonhg.NetBSD.org/src/rev/1d47e19b7550
branches:  trunk
changeset: 765721:1d47e19b7550
user:      dyoung <dyoung%NetBSD.org@localhost>
date:      Fri Jun 03 20:01:00 2011 +0000

description:
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.

diffstat:

 sys/netinet/tcp_vtw.c |  204 ++++++++++++++++++++++++++-----------------------
 1 files changed, 107 insertions(+), 97 deletions(-)

diffs (258 lines):

diff -r af4355850c30 -r 1d47e19b7550 sys/netinet/tcp_vtw.c
--- a/sys/netinet/tcp_vtw.c     Fri Jun 03 19:45:13 2011 +0000
+++ b/sys/netinet/tcp_vtw.c     Fri Jun 03 20:01:00 2011 +0000
@@ -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));
-
-       ctl->base.v4 = kmem_alloc(n * sz, KM_SLEEP);
-       if (ctl->base.v4) {
-               vtw_t   *base;
-               int     class_n;
-
-               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;
-               }
-
-               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;
+       int class_n, i;
+       vtw_t   *base;
+
+       ctl->base.v = ctl_base_v;
+
+       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->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->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;
+
+       for (i = 1; i < VTW_NCLASS; ++i) {
+               int j;
+
+               ctl[i] = ctl[0];
+               ctl[i].clidx = i;
+
+               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->idx_mask <<= 1;
-               ctl->idx_mask  |= 1;
-               ctl->idx_bits  += 1;
-
-               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;
-
-               for (i = 1; i < VTW_NCLASS; ++i) {
-                       int j;
-
-                       ctl[i] = ctl[0];
-                       ctl[i].clidx = i;
-
-                       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;
-                       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));
-
-               /* 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;
-
-               fatp_init(fat, n, m);
-
-               if (!fat->base)
-                       return ENOMEM;
+       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;
+       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;
        }
 
-       if (!ctl->base.v) {
-
-               vtw_init(fat, ctl, tcp_vtw_entries);
-               if (!ctl->base.v)
-                       return ENOMEM;
+       fat_base = kmem_zalloc(2*n * sizeof(fatp_t), KM_NOSLEEP);
+
+       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;
        }
 
+       ctl_base_v = kmem_zalloc(tcp_vtw_entries * sz, KM_NOSLEEP);
+
+       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;
 }
 



Home | Main Index | Thread Index | Old Index