Author: kib
Date: Sun Nov 30 20:20:55 2014
New Revision: 275347
URL: https://svnweb.freebsd.org/changeset/base/275347

Log:
  Provide mutual exclusion between zone allocation/destruction and
  uma_reclaim().  Reclamation code must not see half-constructed or
  destructed zones.  Do this by bracing uma_zcreate() and uma_zdestroy()
  into a shared-locked sx, and take the sx exclusively in uma_reclaim().
  
  Usually zones are not created/destroyed during the system operation,
  but tmpfs mounts do cause zone operations and exposed the bug.
  
  Another solution could be to only expose a new keg on uma_kegs list
  after the corresponding zone is fully constructed, and similar
  treatment for the destruction.  But it probably requires more risky
  code rearrangement as well.
  
  Reported and tested by:       pho
  Discussed with:       avg
  Sponsored by: The FreeBSD Foundation
  MFC after:    2 weeks

Modified:
  head/sys/vm/uma_core.c

Modified: head/sys/vm/uma_core.c
==============================================================================
--- head/sys/vm/uma_core.c      Sun Nov 30 20:12:47 2014        (r275346)
+++ head/sys/vm/uma_core.c      Sun Nov 30 20:20:55 2014        (r275347)
@@ -146,6 +146,8 @@ static LIST_HEAD(,uma_slab) uma_boot_pag
 /* This mutex protects the boot time pages list */
 static struct mtx_padalign uma_boot_pages_mtx;
 
+static struct sx uma_drain_lock;
+
 /* Is the VM done starting up? */
 static int booted = 0;
 #define        UMA_STARTUP     1
@@ -1876,6 +1878,7 @@ uma_startup2(void)
 {
        booted = UMA_STARTUP2;
        bucket_enable();
+       sx_init(&uma_drain_lock, "umadrain");
 #ifdef UMA_DEBUG
        printf("UMA startup2 complete.\n");
 #endif
@@ -1930,6 +1933,8 @@ uma_zcreate(const char *name, size_t siz
 
 {
        struct uma_zctor_args args;
+       uma_zone_t res;
+       bool locked;
 
        /* This stuff is essential for the zone ctor */
        memset(&args, 0, sizeof(args));
@@ -1943,7 +1948,16 @@ uma_zcreate(const char *name, size_t siz
        args.flags = flags;
        args.keg = NULL;
 
-       return (zone_alloc_item(zones, &args, M_WAITOK));
+       if (booted < UMA_STARTUP2) {
+               locked = false;
+       } else {
+               sx_slock(&uma_drain_lock);
+               locked = true;
+       }
+       res = zone_alloc_item(zones, &args, M_WAITOK);
+       if (locked)
+               sx_sunlock(&uma_drain_lock);
+       return (res);
 }
 
 /* See uma.h */
@@ -1953,6 +1967,8 @@ uma_zsecond_create(char *name, uma_ctor 
 {
        struct uma_zctor_args args;
        uma_keg_t keg;
+       uma_zone_t res;
+       bool locked;
 
        keg = zone_first_keg(master);
        memset(&args, 0, sizeof(args));
@@ -1966,8 +1982,17 @@ uma_zsecond_create(char *name, uma_ctor 
        args.flags = keg->uk_flags | UMA_ZONE_SECONDARY;
        args.keg = keg;
 
+       if (booted < UMA_STARTUP2) {
+               locked = false;
+       } else {
+               sx_slock(&uma_drain_lock);
+               locked = true;
+       }
        /* XXX Attaches only one keg of potentially many. */
-       return (zone_alloc_item(zones, &args, M_WAITOK));
+       res = zone_alloc_item(zones, &args, M_WAITOK);
+       if (locked)
+               sx_sunlock(&uma_drain_lock);
+       return (res);
 }
 
 /* See uma.h */
@@ -2085,7 +2110,9 @@ void
 uma_zdestroy(uma_zone_t zone)
 {
 
+       sx_slock(&uma_drain_lock);
        zone_free_item(zones, zone, NULL, SKIP_NONE);
+       sx_sunlock(&uma_drain_lock);
 }
 
 /* See uma.h */
@@ -3205,6 +3232,7 @@ uma_reclaim(void)
 #ifdef UMA_DEBUG
        printf("UMA: vm asked us to release pages!\n");
 #endif
+       sx_xlock(&uma_drain_lock);
        bucket_enable();
        zone_foreach(zone_drain);
        if (vm_page_count_min()) {
@@ -3219,6 +3247,7 @@ uma_reclaim(void)
        zone_drain(slabzone);
        zone_drain(slabrefzone);
        bucket_zone_drain();
+       sx_xunlock(&uma_drain_lock);
 }
 
 /* See uma.h */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to