kernel - Correct bug in malloc_type ks_memuse/ks_inuse management
authorMatthew Dillon <dillon@apollo.backplane.com>
Sun, 19 Sep 2010 16:43:09 +0000 (09:43 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sun, 19 Sep 2010 16:43:09 +0000 (09:43 -0700)
* The new kfree() was improperly adjust ks_memuse/ks_inuse for the wrong
  cpu, leading to MP races which could cause the memory statistics to go
  negative and trigger a panic.

* When calculating loosememuse it is possible to race another cpu and
  come up with an incorrect value.  The race itself is ok, loosememuse
  is not supposed to be 100% deterministic, but even so do not allow
  the value to underflow or we will wind up asserting.

sys/kern/kern_slaballoc.c

index 41ccd6e..a04b209 100644 (file)
@@ -502,6 +502,8 @@ kmalloc(unsigned long size, struct malloc_type *type, int flags)
        for (i = ttl = 0; i < ncpus; ++i)
            ttl += type->ks_memuse[i];
        type->ks_loosememuse = ttl;     /* not MP synchronized */
+       if ((ssize_t)ttl < 0)           /* deal with occassional race */
+               ttl = 0;
        if (ttl >= type->ks_limit) {
            if (flags & M_NULLOK) {
                logmemory(malloc_end, NULL, type, size, flags);
@@ -1110,11 +1112,13 @@ kfree(void *ptr, struct malloc_type *type)
        /*
         * Making these adjustments now allow us to avoid passing (type)
         * to the remote cpu.  Note that ks_inuse/ks_memuse is being
-        * adjusted on a different cpu, but it should all still sum up
-        * properly and cancel out.
+        * adjusted on OUR cpu, not the zone cpu, but it should all still
+        * sum up properly and cancel out.
         */
-       --type->ks_inuse[z->z_Cpu];
-       type->ks_memuse[z->z_Cpu] -= z->z_ChunkSize;
+       crit_enter();
+       --type->ks_inuse[gd->gd_cpuid];
+       type->ks_memuse[gd->gd_cpuid] -= z->z_ChunkSize;
+       crit_exit();
 
        /*
         * WARNING! This code competes with other cpus.  Once we