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; }