Changeset View
Standalone View
sys/vm/uma_core.c
Show First 20 Lines • Show All 3,641 Lines • ▼ Show 20 Lines | keg_fetch_free_slab(uma_keg_t keg, int domain, bool rr, int flags) | ||||
} | } | ||||
return (slab); | return (slab); | ||||
} | } | ||||
static uma_slab_t | static uma_slab_t | ||||
keg_fetch_slab(uma_keg_t keg, uma_zone_t zone, int rdomain, const int flags) | keg_fetch_slab(uma_keg_t keg, uma_zone_t zone, int rdomain, const int flags) | ||||
{ | { | ||||
struct vm_domainset_iter di; | struct vm_domainset_iter di; | ||||
struct domainset_ref dr, *drp; | |||||
uma_slab_t slab; | uma_slab_t slab; | ||||
int aflags, domain; | int aflags, domain; | ||||
bool rr; | bool rr; | ||||
restart: | restart: | ||||
/* | /* | ||||
* Use the keg's policy if upper layers haven't already specified a | * Use the keg's policy if upper layers haven't already specified a | ||||
* domain (as happens with first-touch zones). | * domain (as happens with first-touch zones). | ||||
* | * | ||||
* To avoid races we run the iterator with the keg lock held, but that | * To avoid races we run the iterator with the keg lock held, but that | ||||
* means that we cannot allow the vm_domainset layer to sleep. Thus, | * means that we cannot allow the vm_domainset layer to sleep. Thus, | ||||
* clear M_WAITOK and handle low memory conditions locally. | * clear M_WAITOK and handle low memory conditions locally. | ||||
*/ | */ | ||||
aflags = (flags & ~M_WAITOK) | M_NOWAIT; | |||||
rr = rdomain == UMA_ANYDOMAIN; | rr = rdomain == UMA_ANYDOMAIN; | ||||
if (rr) { | if (rr) { | ||||
aflags = (flags & ~M_WAITOK) | M_NOWAIT; | drp = &keg->uk_dr; | ||||
vm_domainset_iter_policy_ref_init(&di, &keg->uk_dr, &domain, | vm_domainset_iter_policy_ref_init(&di, drp, &domain, &aflags); | ||||
&aflags); | |||||
} else { | } else { | ||||
aflags = flags; | dr.dr_policy = DOMAINSET_PREF(rdomain); | ||||
domain = rdomain; | dr.dr_iter = rdomain; | ||||
drp = &dr; | |||||
vm_domainset_iter_policy_ref_init(&di, drp, &domain, &aflags); | |||||
} | } | ||||
for (;;) { | for (;;) { | ||||
slab = keg_fetch_free_slab(keg, domain, rr, flags); | slab = keg_fetch_free_slab(keg, domain, rr, flags); | ||||
if (slab != NULL) | if (slab != NULL) | ||||
return (slab); | return (slab); | ||||
/* | /* | ||||
* M_NOVM means don't ask at all! | * M_NOVM means don't ask at all! | ||||
*/ | */ | ||||
if (flags & M_NOVM) | if (flags & M_NOVM) | ||||
break; | break; | ||||
slab = keg_alloc_slab(keg, zone, domain, flags, aflags); | slab = keg_alloc_slab(keg, zone, domain, flags, aflags); | ||||
if (slab != NULL) | if (slab != NULL) | ||||
return (slab); | return (slab); | ||||
if (!rr && (flags & M_WAITOK) == 0) | if (!rr && (flags & M_WAITOK) == 0) | ||||
dgmorris_earthlink.net: Don't we want to leave the !rr check here? If we're M_NOWAIT and RR we want to check the next… | |||||
break; | break; | ||||
if (rr && vm_domainset_iter_policy(&di, &domain) != 0) { | if (vm_domainset_iter_policy(&di, &domain) != 0) { | ||||
if ((flags & M_WAITOK) != 0) { | if ((flags & M_WAITOK) != 0) { | ||||
vm_wait_doms(&keg->uk_dr.dr_policy->ds_mask, 0); | vm_wait_doms(drp->dr_policy->ds_mask, 0); | ||||
goto restart; | goto restart; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* We might not have been able to get a slab but another cpu | * We might not have been able to get a slab but another cpu | ||||
* could have while we were unlocked. Check again before we | * could have while we were unlocked. Check again before we | ||||
* fail. | * fail. | ||||
*/ | */ | ||||
if ((slab = keg_fetch_free_slab(keg, domain, rr, flags)) != NULL) | return (keg_fetch_free_slab(keg, rr ? domain : rdomain, true, flags)); | ||||
dgmorris_earthlink.netUnsubmitted Not Done Inline ActionsApologies if this is wrong - but in this case for rr we tried the domains above, so domain should be the last one we tried from vm_domainset_iter_policy(), right? Is that what we want to use as our attempt in keg_fetch_free_slab() or should we cache the first domain from the vm_domainset_iter_policy_ref_init() [the original RR "hand" as it were] and use that? I certainly suppose you can argue that if all domains are equally likely to be insufficient in these cases the last one visited in the RR search will rotate (just "behind" the RR hand as it were?), so that's good enough.. but thought this was worth checking on intent. dgmorris_earthlink.net: Apologies if this is wrong - but in this case for rr we tried the domains above, so domain… | |||||
markjAuthorUnsubmitted Done Inline Actionskeg_fetch_free_slab() will try all of the domains. So for RR we will start from the last domain from which we tried to allocate, but I think that's fairly arbitrary. Though, we are inconsistent here about how M_NOWAIT is handled when the domain is specified. In the loop above we try only to allocate from the requested domain, but here we're looping over all of them unconditionally. markj: keg_fetch_free_slab() will try all of the domains. So for RR we will start from the last domain… | |||||
return (slab); | |||||
return (NULL); | |||||
} | } | ||||
static void * | static void * | ||||
slab_alloc_item(uma_keg_t keg, uma_slab_t slab) | slab_alloc_item(uma_keg_t keg, uma_slab_t slab) | ||||
{ | { | ||||
uma_domain_t dom; | uma_domain_t dom; | ||||
void *item; | void *item; | ||||
int freei; | int freei; | ||||
▲ Show 20 Lines • Show All 1,849 Lines • Show Last 20 Lines |
Don't we want to leave the !rr check here? If we're M_NOWAIT and RR we want to check the next domain before giving up.