Changeset View
Standalone View
vm_reserv.c
Show First 20 Lines • Show All 1,024 Lines • ▼ Show 20 Lines | |||||
* population count and map are reset to their initial state. | * population count and map are reset to their initial state. | ||||
* | * | ||||
* The given reservation must not be in the partially populated reservation | * The given reservation must not be in the partially populated reservation | ||||
* queue. The free page queue lock must be held. | * queue. The free page queue lock must be held. | ||||
*/ | */ | ||||
static void | static void | ||||
vm_reserv_break(vm_reserv_t rv) | vm_reserv_break(vm_reserv_t rv) | ||||
{ | { | ||||
int begin_zeroes, hi, i, lo; | int bitpos, hi, i, lo; | ||||
u_long changes; | |||||
pho: Is this the right ordering of "int" and "u_long"? | |||||
vm_reserv_assert_locked(rv); | vm_reserv_assert_locked(rv); | ||||
CTR5(KTR_VM, "%s: rv %p object %p popcnt %d inpartpop %d", | CTR5(KTR_VM, "%s: rv %p object %p popcnt %d inpartpop %d", | ||||
__FUNCTION__, rv, rv->object, rv->popcnt, rv->inpartpopq); | __FUNCTION__, rv, rv->object, rv->popcnt, rv->inpartpopq); | ||||
vm_reserv_remove(rv); | vm_reserv_remove(rv); | ||||
rv->pages->psind = 0; | rv->pages->psind = 0; | ||||
i = hi = 0; | hi = lo = 0; | ||||
do { | for (i = 0; i <= NPOPMAP; i++) { | ||||
/* Find the next 0 bit. Any previous 0 bits are < "hi". */ | if (i == NPOPMAP) | ||||
lo = ffsl(~(((1UL << hi) - 1) | rv->popmap[i])); | changes = 1; | ||||
Not Done Inline ActionsI suggest quoting "changes" to make it more clear that you're referring to a variable. markj: I suggest quoting "changes" to make it more clear that you're referring to a variable. | |||||
if (lo == 0) { | else { | ||||
/* Redundantly clears bits < "hi". */ | changes = rv->popmap[i]; | ||||
changes ^= (changes << 1) | (hi == lo); | |||||
rv->popmap[i] = 0; | rv->popmap[i] = 0; | ||||
rv->popcnt -= NBPOPMAP - hi; | |||||
while (++i < NPOPMAP) { | |||||
lo = ffsl(~rv->popmap[i]); | |||||
if (lo == 0) { | |||||
rv->popmap[i] = 0; | |||||
rv->popcnt -= NBPOPMAP; | |||||
} else | |||||
break; | |||||
} | } | ||||
if (i == NPOPMAP) | while (changes != 0) { | ||||
break; | bitpos = ffsl(changes) - 1; | ||||
Not Done Inline ActionsStyle: the comment formatting is off: /* * If the ... markj: Style: the comment formatting is off:
```
/*
* If the ...
``` | |||||
hi = 0; | changes ^= 1UL << bitpos; | ||||
} | if (lo == hi) | ||||
KASSERT(lo > 0, ("vm_reserv_break: lo is %d", lo)); | lo = NBPOPMAP * i + bitpos; | ||||
Not Done Inline ActionsI can't see how this works for a fully populated reservation. Suppose NPOMAP is 1. On both iterations of the outer loop, changes will be 1. On the first iteration, lo == hi == 0 and we set lo = 0. On the second iteration we will set lo = 64 but won't free any pages before exiting the loop. What am I missing? markj: I can't see how this works for a fully populated reservation. Suppose NPOMAP is 1. On both… | |||||
Done Inline ActionsBy "fully populated", I assume that you mean that all bits of rv->popmap[i] are set for all i. On the first iteration of the loop: so we do not set lo to 0, but it remains 0. I agree that we won't free any pages, but there are no pages to be freed, and this matches the current behavior. dougm: By "fully populated", I assume that you mean that all bits of rv->popmap[i] are set for all i. | |||||
Done Inline ActionsJust in case "fully populated" means all zeroes, we'll set lo to 0 on the first loop, and hi to 64 on the second, before freeing all 64 pages. dougm: Just in case "fully populated" means all zeroes, we'll set lo to 0 on the first loop, and hi to… | |||||
Not Done Inline ActionsSorry for the noise, I had an inverted sense of what this function is supposed to do. markj: Sorry for the noise, I had an inverted sense of what this function is supposed to do. | |||||
/* Convert from ffsl() to ordinary bit numbering. */ | else { | ||||
lo--; | hi = NBPOPMAP * i + bitpos; | ||||
if (lo > 0) { | |||||
/* Redundantly clears bits < "hi". */ | |||||
rv->popmap[i] &= ~((1UL << lo) - 1); | |||||
rv->popcnt -= lo - hi; | |||||
} | |||||
begin_zeroes = NBPOPMAP * i + lo; | |||||
/* Find the next 1 bit. */ | |||||
do | |||||
hi = ffsl(rv->popmap[i]); | |||||
while (hi == 0 && ++i < NPOPMAP); | |||||
if (i != NPOPMAP) | |||||
/* Convert from ffsl() to ordinary bit numbering. */ | |||||
hi--; | |||||
vm_domain_free_lock(VM_DOMAIN(rv->domain)); | vm_domain_free_lock(VM_DOMAIN(rv->domain)); | ||||
vm_phys_free_contig(&rv->pages[begin_zeroes], NBPOPMAP * i + | vm_phys_free_contig(&rv->pages[lo], hi - lo); | ||||
hi - begin_zeroes); | |||||
vm_domain_free_unlock(VM_DOMAIN(rv->domain)); | vm_domain_free_unlock(VM_DOMAIN(rv->domain)); | ||||
} while (i < NPOPMAP); | lo = hi; | ||||
KASSERT(rv->popcnt == 0, | } | ||||
("vm_reserv_break: reserv %p's popcnt is corrupted", rv)); | } | ||||
} | |||||
rv->popcnt = 0; | |||||
counter_u64_add(vm_reserv_broken, 1); | counter_u64_add(vm_reserv_broken, 1); | ||||
} | } | ||||
/* | /* | ||||
* Breaks all reservations belonging to the given object. | * Breaks all reservations belonging to the given object. | ||||
*/ | */ | ||||
void | void | ||||
vm_reserv_break_all(vm_object_t object) | vm_reserv_break_all(vm_object_t object) | ||||
▲ Show 20 Lines • Show All 193 Lines • ▼ Show 20 Lines | |||||
* The free page queue lock must be held. | * The free page queue lock must be held. | ||||
*/ | */ | ||||
boolean_t | boolean_t | ||||
vm_reserv_reclaim_contig(int domain, u_long npages, vm_paddr_t low, | vm_reserv_reclaim_contig(int domain, u_long npages, vm_paddr_t low, | ||||
vm_paddr_t high, u_long alignment, vm_paddr_t boundary) | vm_paddr_t high, u_long alignment, vm_paddr_t boundary) | ||||
{ | { | ||||
vm_paddr_t pa, size; | vm_paddr_t pa, size; | ||||
vm_reserv_t rv, rvn; | vm_reserv_t rv, rvn; | ||||
int hi, i, lo, low_index, next_free; | int bitpos, hi, i, lo, low_index; | ||||
u_long changes; | |||||
if (npages > VM_LEVEL_0_NPAGES - 1) | if (npages > VM_LEVEL_0_NPAGES - 1) | ||||
return (FALSE); | return (FALSE); | ||||
size = npages << PAGE_SHIFT; | size = npages << PAGE_SHIFT; | ||||
vm_reserv_domain_lock(domain); | vm_reserv_domain_lock(domain); | ||||
again: | again: | ||||
for (rv = TAILQ_FIRST(&vm_rvq_partpop[domain]); rv != NULL; rv = rvn) { | for (rv = TAILQ_FIRST(&vm_rvq_partpop[domain]); rv != NULL; rv = rvn) { | ||||
rvn = TAILQ_NEXT(rv, partpopq); | rvn = TAILQ_NEXT(rv, partpopq); | ||||
Show All 17 Lines | if (vm_reserv_trylock(rv) == 0) { | ||||
continue; | continue; | ||||
} | } | ||||
} else | } else | ||||
vm_reserv_domain_unlock(domain); | vm_reserv_domain_unlock(domain); | ||||
if (pa < low) { | if (pa < low) { | ||||
/* Start the search for free pages at "low". */ | /* Start the search for free pages at "low". */ | ||||
low_index = (low + PAGE_MASK - pa) >> PAGE_SHIFT; | low_index = (low + PAGE_MASK - pa) >> PAGE_SHIFT; | ||||
i = low_index / NBPOPMAP; | i = low_index / NBPOPMAP; | ||||
hi = low_index % NBPOPMAP; | bitpos = low_index % NBPOPMAP; | ||||
} else | changes = rv->popmap[i] | ((1UL << bitpos) - 1); | ||||
i = hi = 0; | } else { | ||||
i = 0; | |||||
changes = rv->popmap[i]; | |||||
} | |||||
lo = hi = 0; | |||||
changes ^= (changes << 1) | 1; | |||||
do { | do { | ||||
/* Find the next free page. */ | if (lo >= hi) { | ||||
lo = ffsl(~(((1UL << hi) - 1) | rv->popmap[i])); | while (changes == 0 && ++i < NPOPMAP) { | ||||
while (lo == 0 && ++i < NPOPMAP) | changes = rv->popmap[i]; | ||||
lo = ffsl(~rv->popmap[i]); | changes ^= (changes << 1) | (lo == hi); | ||||
} | |||||
if (i == NPOPMAP) | if (i == NPOPMAP) | ||||
break; | bitpos = 0; | ||||
/* Convert from ffsl() to ordinary bit numbering. */ | else { | ||||
lo--; | bitpos = ffsl(changes) - 1; | ||||
next_free = NBPOPMAP * i + lo; | changes ^= 1UL << bitpos; | ||||
pa = VM_PAGE_TO_PHYS(&rv->pages[next_free]); | } | ||||
if (lo == hi) { | |||||
lo = NBPOPMAP * i + bitpos; | |||||
continue; | |||||
} | |||||
hi = NBPOPMAP * i + bitpos; | |||||
} | |||||
pa = VM_PAGE_TO_PHYS(&rv->pages[lo]); | |||||
KASSERT(pa >= low, | KASSERT(pa >= low, | ||||
("vm_reserv_reclaim_contig: pa is too low")); | ("vm_reserv_reclaim_contig: pa is too low")); | ||||
if (pa + size > high) { | if (pa + size > high) { | ||||
/* The rest of this reservation is too high. */ | /* The rest of this reservation is too high. */ | ||||
break; | break; | ||||
} else if ((pa & (alignment - 1)) != 0 || | } | ||||
if ((pa & (alignment - 1)) != 0 || | |||||
((pa ^ (pa + size - 1)) & ~(boundary - 1)) != 0) { | ((pa ^ (pa + size - 1)) & ~(boundary - 1)) != 0) { | ||||
/* | /* | ||||
* The current page doesn't meet the alignment | * The current page doesn't meet the alignment | ||||
* and/or boundary requirements. Continue | * and/or boundary requirements. Continue | ||||
* searching this reservation until the rest | * searching this reservation until the rest | ||||
* of its free pages are either excluded or | * of its free pages are either excluded or | ||||
* exhausted. | * exhausted. | ||||
*/ | */ | ||||
hi = lo + 1; | ++lo; | ||||
if (hi >= NBPOPMAP) { | continue; | ||||
hi = 0; | |||||
i++; | |||||
} | } | ||||
if ((hi - lo) * PAGE_SIZE < size) { | |||||
lo = hi; | |||||
continue; | continue; | ||||
} | } | ||||
/* Find the next used page. */ | |||||
hi = ffsl(rv->popmap[i] & ~((1UL << lo) - 1)); | |||||
while (hi == 0 && ++i < NPOPMAP) { | |||||
if ((NBPOPMAP * i - next_free) * PAGE_SIZE >= | |||||
size) { | |||||
vm_reserv_reclaim(rv); | vm_reserv_reclaim(rv); | ||||
vm_reserv_unlock(rv); | vm_reserv_unlock(rv); | ||||
return (TRUE); | return (TRUE); | ||||
} | |||||
hi = ffsl(rv->popmap[i]); | |||||
} | |||||
/* Convert from ffsl() to ordinary bit numbering. */ | |||||
if (i != NPOPMAP) | |||||
hi--; | |||||
if ((NBPOPMAP * i + hi - next_free) * PAGE_SIZE >= | |||||
size) { | |||||
vm_reserv_reclaim(rv); | |||||
vm_reserv_unlock(rv); | |||||
return (TRUE); | |||||
} | |||||
} while (i < NPOPMAP); | } while (i < NPOPMAP); | ||||
vm_reserv_unlock(rv); | vm_reserv_unlock(rv); | ||||
vm_reserv_domain_lock(domain); | vm_reserv_domain_lock(domain); | ||||
if (rvn != NULL && !rvn->inpartpopq) | if (rvn != NULL && !rvn->inpartpopq) | ||||
goto again; | goto again; | ||||
} | } | ||||
vm_reserv_domain_unlock(domain); | vm_reserv_domain_unlock(domain); | ||||
return (FALSE); | return (FALSE); | ||||
▲ Show 20 Lines • Show All 121 Lines • Show Last 20 Lines |
Is this the right ordering of "int" and "u_long"?