svn commit: r275347 - head/sys/vm
Konstantin Belousov
kib at FreeBSD.org
Sun Nov 30 20:20:56 UTC 2014
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 */
More information about the svn-src-head
mailing list