kernel - remove bounds on buffer cache nbuf count for 64-bit
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 15 Sep 2012 17:00:54 +0000 (10:00 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 15 Sep 2012 17:03:44 +0000 (10:03 -0700)
* Remove arbitrary 1GB buffer cache limitation

* Adjusted numerous 'int' fields to 'long'.  Even though nbuf is not
  likely to exceed 2 billion buffers, byte calculations using the
  variable began overflowing so just convert that and various other
  variables to long.

* Make sure we don't blow-out the temporary valloc() space in early boot
  due to nbufs being too large.

* Unbound 'kern.nbuf' specifications in /boot/loader.conf as well.

14 files changed:
sys/boot/common/loader.8
sys/cpu/x86_64/include/param.h
sys/kern/subr_param.c
sys/kern/vfs_bio.c
sys/platform/pc32/i386/machdep.c
sys/platform/pc64/x86_64/machdep.c
sys/platform/vkernel/i386/autoconf.c
sys/platform/vkernel64/x86_64/autoconf.c
sys/sys/buf.h
sys/vfs/nfs/nfs_subs.c
sys/vfs/nwfs/nwfs_vfsops.c
sys/vfs/smbfs/smbfs_vfsops.c
sys/vm/vm_pager.c
sys/vm/vnode_pager.c

index 2d691f6..00ef18d 100644 (file)
@@ -698,7 +698,8 @@ Modifies
 .It Va kern.maxbcache
 Limits the amount of KVM reserved for use by the
 buffer cache, specified in bytes.
-The default maximum is 200MB.
+The default maximum is 200MB on 32-bit and
+unspecified on 64-bit.
 This parameter is used to
 prevent the buffer cache from eating too much
 .Tn KVM
index 9445e76..c6d8ca2 100644 (file)
  * the VM page cache is not effected), can be changed via
  * kern.maxbcache /boot/loader.conf variable.
  *
- * On x86_64 boxes this can also improve HAMMER's flushing and cache
- * performance so use a much higher value than i386.
+ * This value is unbounded on 64-bit boxes, boot code will limit the
+ * buffer cache size to a portion of available physical memory.
  */
 #ifndef VM_BCACHE_SIZE_MAX
-#define VM_BCACHE_SIZE_MAX     (1000L * 1024 * 1024)
+#define VM_BCACHE_SIZE_MAX     0
 #endif
 
 /*
index 71f7b64..f9315b8 100644 (file)
@@ -84,8 +84,8 @@ int   maxfilesperuser;                /* per-user open files limit */
 int    maxposixlocksperuid;            /* max # POSIX locks per uid */
 int    ncallout;                       /* maximum # of timer events */
 int    mbuf_wait = 32;                 /* mbuf sleep time in ticks */
-int    nbuf;
-int    nswbuf;
+long   nbuf;
+long   nswbuf;
 long   maxswzone;                      /* max swmeta KVA storage */
 long   maxbcache;                      /* max buffer cache KVA storage */
 int    vmm_guest = 0;                  /* Running as virtual machine guest? */
@@ -222,7 +222,7 @@ init_param2(int physpages)
         * Unless overriden, NBUF is typically 0 (auto-sized later).
         */
        nbuf = NBUF;
-       TUNABLE_INT_FETCH("kern.nbuf", &nbuf);
+       TUNABLE_LONG_FETCH("kern.nbuf", &nbuf);
 
        ncallout = 16 + maxproc + maxfiles;
        TUNABLE_INT_FETCH("kern.ncallout", &ncallout);
index 22a7c20..f880bb4 100644 (file)
@@ -125,17 +125,17 @@ long bufspace;                    /* locked by buffer_map */
 long maxbufspace;
 static long bufmallocspace;    /* atomic ops */
 long maxbufmallocspace, lobufspace, hibufspace;
-static int bufreusecnt, bufdefragcnt, buffreekvacnt;
+static long bufreusecnt, bufdefragcnt, buffreekvacnt;
 static long lorunningspace;
 static long hirunningspace;
-static int runningbufreq;              /* locked by bufcspin */
+static long runningbufreq;             /* locked by bufcspin */
 static long dirtykvaspace;             /* locked by bufcspin */
 static long dirtybufspace;             /* locked by bufcspin */
-static int dirtybufcount;              /* locked by bufcspin */
+static long dirtybufcount;             /* locked by bufcspin */
 static long dirtybufspacehw;           /* locked by bufcspin */
-static int dirtybufcounthw;            /* locked by bufcspin */
+static long dirtybufcounthw;           /* locked by bufcspin */
 static long runningbufspace;           /* locked by bufcspin */
-static int runningbufcount;            /* locked by bufcspin */
+static long runningbufcount;           /* locked by bufcspin */
 long lodirtybufspace;
 long hidirtybufspace;
 static int getnewbufcalls;
@@ -174,7 +174,7 @@ SYSCTL_UINT(_vfs, OID_AUTO, vm_cycle_point, CTLFLAG_RW, &vm_cycle_point, 0,
 /*
  * Sysctls determining current state of the buffer cache.
  */
-SYSCTL_INT(_vfs, OID_AUTO, nbuf, CTLFLAG_RD, &nbuf, 0,
+SYSCTL_LONG(_vfs, OID_AUTO, nbuf, CTLFLAG_RD, &nbuf, 0,
        "Total number of buffers in buffer cache");
 SYSCTL_LONG(_vfs, OID_AUTO, dirtykvaspace, CTLFLAG_RD, &dirtykvaspace, 0,
        "KVA reserved by dirty buffers (all)");
@@ -182,13 +182,13 @@ SYSCTL_LONG(_vfs, OID_AUTO, dirtybufspace, CTLFLAG_RD, &dirtybufspace, 0,
        "Pending bytes of dirty buffers (all)");
 SYSCTL_LONG(_vfs, OID_AUTO, dirtybufspacehw, CTLFLAG_RD, &dirtybufspacehw, 0,
        "Pending bytes of dirty buffers (heavy weight)");
-SYSCTL_INT(_vfs, OID_AUTO, dirtybufcount, CTLFLAG_RD, &dirtybufcount, 0,
+SYSCTL_LONG(_vfs, OID_AUTO, dirtybufcount, CTLFLAG_RD, &dirtybufcount, 0,
        "Pending number of dirty buffers");
-SYSCTL_INT(_vfs, OID_AUTO, dirtybufcounthw, CTLFLAG_RD, &dirtybufcounthw, 0,
+SYSCTL_LONG(_vfs, OID_AUTO, dirtybufcounthw, CTLFLAG_RD, &dirtybufcounthw, 0,
        "Pending number of dirty buffers (heavy weight)");
 SYSCTL_LONG(_vfs, OID_AUTO, runningbufspace, CTLFLAG_RD, &runningbufspace, 0,
        "I/O bytes currently in progress due to asynchronous writes");
-SYSCTL_INT(_vfs, OID_AUTO, runningbufcount, CTLFLAG_RD, &runningbufcount, 0,
+SYSCTL_LONG(_vfs, OID_AUTO, runningbufcount, CTLFLAG_RD, &runningbufcount, 0,
        "I/O buffers currently in progress due to asynchronous writes");
 SYSCTL_LONG(_vfs, OID_AUTO, maxbufspace, CTLFLAG_RD, &maxbufspace, 0,
        "Hard limit on maximum amount of memory usable for buffer space");
@@ -619,7 +619,7 @@ bufinit(void)
 {
        struct buf *bp;
        vm_offset_t bogus_offset;
-       int i;
+       long i;
 
        /* next, make a null set of free lists */
        for (i = 0; i < BUFFER_QUEUES; i++)
@@ -650,8 +650,8 @@ bufinit(void)
         * this may result in KVM fragmentation which is not handled optimally
         * by the system.
         */
-       maxbufspace = (long)nbuf * BKVASIZE;
-       hibufspace = imax(3 * maxbufspace / 4, maxbufspace - MAXBSIZE * 10);
+       maxbufspace = nbuf * BKVASIZE;
+       hibufspace = lmax(3 * maxbufspace / 4, maxbufspace - MAXBSIZE * 10);
        lobufspace = hibufspace - MAXBSIZE;
 
        lorunningspace = 512 * 1024;
@@ -4730,7 +4730,7 @@ scan_all_buffers(int (*callback)(struct buf *, void *), void *info)
 {
        int count = 0;
        int error;
-       int n;
+       long n;
 
        for (n = 0; n < nbuf; ++n) {
                if ((error = callback(&buf[n], info)) < 0) {
index c402678..ea0e248 100644 (file)
@@ -317,7 +317,7 @@ again:
        }
 
        /* limit to 128 on i386 */
-       nswbuf = max(min(nbuf/4, 128), 16);
+       nswbuf = lmax(lmin(nbuf / 4, 128), 16);
 #ifdef NSWBUF_MIN
        if (nswbuf < NSWBUF_MIN)
                nswbuf = NSWBUF_MIN;
index 0916cd1..2da248c 100644 (file)
@@ -318,8 +318,8 @@ again:
         * factor represents the 1/4 x ram conversion.
         */
        if (nbuf == 0) {
-               int factor = 4 * BKVASIZE / 1024;
-               int kbytes = physmem * (PAGE_SIZE / 1024);
+               long factor = 4 * BKVASIZE / 1024;
+               long kbytes = physmem * (PAGE_SIZE / 1024);
 
                nbuf = 50;
                if (kbytes > 4096)
@@ -334,12 +334,37 @@ again:
         * Do not allow the buffer_map to be more then 1/2 the size of the
         * kernel_map.
         */
-       if (nbuf > (virtual_end - virtual_start) / (BKVASIZE * 2)) {
-               nbuf = (virtual_end - virtual_start) / (BKVASIZE * 2);
-               kprintf("Warning: nbufs capped at %d\n", nbuf);
+       if (nbuf > (virtual_end - virtual_start +
+                   virtual2_end - virtual2_start) / (BKVASIZE * 2)) {
+               nbuf = (virtual_end - virtual_start +
+                       virtual2_end - virtual2_start) / (BKVASIZE * 2);
+               kprintf("Warning: nbufs capped at %ld due to kvm\n", nbuf);
        }
 
-       nswbuf = max(min(nbuf/4, 256), 16);
+       /*
+        * Do not allow the buffer_map to use more than 50% of available
+        * physical-equivalent memory.  Since the VM pages which back
+        * individual buffers are typically wired, having too many bufs
+        * can prevent the system from paging properly.
+        */
+       if (nbuf > physmem * PAGE_SIZE / (BKVASIZE * 2)) {
+               nbuf = physmem * PAGE_SIZE / (BKVASIZE * 2);
+               kprintf("Warning: nbufs capped at %ld due to physmem\n", nbuf);
+       }
+
+       /*
+        * Do not allow the sizeof(struct buf) * nbuf to exceed half of
+        * the valloc space which is just the virtual_end - virtual_start
+        * section.  We use valloc() to allocate the buf header array.
+        */
+       if (nbuf > (virtual_end - virtual_start) / sizeof(struct buf) / 2) {
+               nbuf = (virtual_end - virtual_start) /
+                      sizeof(struct buf) / 2;
+               kprintf("Warning: nbufs capped at %ld due to valloc "
+                       "considerations", nbuf);
+       }
+
+       nswbuf = lmax(lmin(nbuf / 4, 256), 16);
 #ifdef NSWBUF_MIN
        if (nswbuf < NSWBUF_MIN)
                nswbuf = NSWBUF_MIN;
@@ -364,17 +389,20 @@ again:
 
        /*
         * End of second pass, addresses have been assigned
+        *
+        * nbuf is an int, make sure we don't overflow the field.
         */
        if ((vm_size_t)(v - firstaddr) != size)
                panic("startup: table size inconsistency");
 
        kmem_suballoc(&kernel_map, &clean_map, &clean_sva, &clean_eva,
-                     (nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size);
+                     ((vm_offset_t)nbuf * BKVASIZE) +
+                     (nswbuf * MAXPHYS) + pager_map_size);
        kmem_suballoc(&clean_map, &buffer_map, &buffer_sva, &buffer_eva,
-                     (nbuf*BKVASIZE));
+                     ((vm_offset_t)nbuf * BKVASIZE));
        buffer_map.system_map = 1;
        kmem_suballoc(&clean_map, &pager_map, &pager_sva, &pager_eva,
-                     (nswbuf*MAXPHYS) + pager_map_size);
+                     ((vm_offset_t)nswbuf * MAXPHYS) + pager_map_size);
        pager_map.system_map = 1;
 
 #if defined(USERCONFIG)
index 0518838..171fa76 100644 (file)
@@ -148,7 +148,7 @@ cpu_startup(void *dummy)
                kprintf("Warning: nbufs capped at %d\n", nbuf);
        }
 
-       nswbuf = max(min(nbuf/4, 256), 16);
+       nswbuf = lmax(lmin(nbuf / 4, 256), 16);
 #ifdef NSWBUF_MIN
        if (nswbuf < NSWBUF_MIN)
                nswbuf = NSWBUF_MIN;
index 6291b68..bdbb122 100644 (file)
@@ -146,7 +146,7 @@ cpu_startup(void *dummy)
                kprintf("Warning: nbufs capped at %d\n", nbuf);
        }
 
-       nswbuf = max(min(nbuf/4, 256), 16);
+       nswbuf = lmax(lmin(nbuf / 4, 256), 16);
 #ifdef NSWBUF_MIN
        if (nswbuf < NSWBUF_MIN)
                nswbuf = NSWBUF_MIN;
index aa5af8c..4665d6a 100644 (file)
@@ -376,7 +376,7 @@ struct cluster_save {
 #define B_SYNC         0x02            /* Do all allocations synchronously. */
 
 #ifdef _KERNEL
-extern int     nbuf;                   /* The number of buffer headers */
+extern long    nbuf;                   /* The number of buffer headers */
 extern long    maxswzone;              /* Max KVA for swap structures */
 extern long    maxbcache;              /* Max KVA for buffer cache */
 extern long    hidirtybufspace;
@@ -385,7 +385,7 @@ extern struct buf *buf;                     /* The buffer headers. */
 extern char    *buffers;               /* The buffer contents. */
 extern int     bufpages;               /* Number of memory pages in the buffer pool. */
 extern struct  buf *swbuf;             /* Swap I/O buffer headers. */
-extern int     nswbuf;                 /* Number of swap I/O buffer headers. */
+extern long    nswbuf;                 /* Number of swap I/O buffer headers. */
 extern int     bioq_reorder_burst_interval;
 extern int     bioq_reorder_burst_bytes;
 extern int     bioq_reorder_minor_interval;
index 0e12c6c..42a2668 100644 (file)
@@ -105,7 +105,7 @@ int nfs_ticks;
  */
 struct lwkt_token nfs_token = LWKT_TOKEN_INITIALIZER(unp_token);
 
-static int nfs_pbuf_freecnt = -1;      /* start out unlimited */
+static long nfs_pbuf_freecnt = -1;     /* start out unlimited */
 
 struct nfsmount_head nfs_mountq = TAILQ_HEAD_INITIALIZER(nfs_mountq);
 struct nfssvc_sockhead nfssvc_sockhead;
index 5d1ec33..d6e8aaf 100644 (file)
@@ -94,7 +94,7 @@ VFS_SET(nwfs_vfsops, nwfs, VFCF_NETWORK);
 MODULE_VERSION(nwfs, 1);
 MODULE_DEPEND(nwfs, ncp, 1, 1, 1);
 
-int nwfs_pbuf_freecnt = -1;    /* start out unlimited */
+long nwfs_pbuf_freecnt = -1;   /* start out unlimited */
 static int nwfsid = 1;
 
 static int
index 6c9f68c..4a686d4 100644 (file)
@@ -117,7 +117,7 @@ MODULE_DEPEND(smbfs, netsmb, NSMB_VERSION, NSMB_VERSION, NSMB_VERSION);
 MODULE_DEPEND(smbfs, libiconv, 1, 1, 2);
 MODULE_DEPEND(smbfs, libmchain, 1, 1, 1);
 
-int smbfs_pbuf_freecnt = -1;   /* start out unlimited */
+long smbfs_pbuf_freecnt = -1;  /* start out unlimited */
 
 static int
 smbfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
index 720e636..b022c13 100644 (file)
@@ -185,7 +185,7 @@ struct vm_map pager_map;
 
 static int bswneeded_raw;
 static int bswneeded_kva;
-static int nswbuf_raw;
+static long nswbuf_raw;
 static struct buf *swbuf_raw;
 static vm_offset_t swapbkva;           /* swap buffers kva */
 static struct swqueue bswlist_raw;     /* without kva */
@@ -219,7 +219,7 @@ void
 vm_pager_bufferinit(void)
 {
        struct buf *bp;
-       int i;
+       long i;
 
        /*
         * Reserve KVM space for pbuf data.
index 585ddb3..84a4498 100644 (file)
@@ -92,7 +92,7 @@ struct pagerops vnodepagerops = {
 static struct krate vbadrate = { 1 };
 static struct krate vresrate = { 1 };
 
-int vnode_pbuf_freecnt = -1;   /* start out unlimited */
+long vnode_pbuf_freecnt = -1;  /* start out unlimited */
 
 /*
  * Allocate a VM object for a vnode, typically a regular file vnode.