Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_phys.c
Show First 20 Lines • Show All 928 Lines • ▼ Show 20 Lines | for (pind = 0; pind < VM_NFREEPOOL; pind++) { | ||||
return (m); | return (m); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* | /* | ||||
* Find the vm_page corresponding to the given physical address, which must lie | |||||
* within the given physical memory segment. | |||||
*/ | |||||
static vm_page_t | |||||
vm_phys_seg_paddr_to_vm_page(struct vm_phys_seg *seg, vm_paddr_t pa) | |||||
dougm: This could be applied at vm_page.c:787, if it were visible there. | |||||
markjAuthorUnsubmitted Done Inline ActionsI made the function externally visible. markj: I made the function externally visible. | |||||
{ | |||||
KASSERT(pa >= seg->start && pa < seg->end, | |||||
("%s: pa %#jx is out of range", __func__, pa)); | |||||
return (&seg->first_page[atop(pa - seg->start)]); | |||||
} | |||||
/* | |||||
* Find the vm_page corresponding to the given physical address. | * Find the vm_page corresponding to the given physical address. | ||||
*/ | */ | ||||
vm_page_t | vm_page_t | ||||
vm_phys_paddr_to_vm_page(vm_paddr_t pa) | vm_phys_paddr_to_vm_page(vm_paddr_t pa) | ||||
{ | { | ||||
struct vm_phys_seg *seg; | struct vm_phys_seg *seg; | ||||
if ((seg = vm_phys_paddr_to_seg(pa)) != NULL) | if ((seg = vm_phys_paddr_to_seg(pa)) != NULL) | ||||
return (&seg->first_page[atop(pa - seg->start)]); | return (vm_phys_seg_paddr_to_vm_page(seg, pa)); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
vm_page_t | vm_page_t | ||||
vm_phys_fictitious_to_vm_page(vm_paddr_t pa) | vm_phys_fictitious_to_vm_page(vm_paddr_t pa) | ||||
{ | { | ||||
struct vm_phys_fictitious_seg tmp, *seg; | struct vm_phys_fictitious_seg tmp, *seg; | ||||
vm_page_t m; | vm_page_t m; | ||||
m = NULL; | m = NULL; | ||||
tmp.start = pa; | tmp.start = pa; | ||||
tmp.end = 0; | tmp.end = 0; | ||||
rw_rlock(&vm_phys_fictitious_reg_lock); | rw_rlock(&vm_phys_fictitious_reg_lock); | ||||
seg = RB_FIND(fict_tree, &vm_phys_fictitious_tree, &tmp); | seg = RB_FIND(fict_tree, &vm_phys_fictitious_tree, &tmp); | ||||
rw_runlock(&vm_phys_fictitious_reg_lock); | rw_runlock(&vm_phys_fictitious_reg_lock); | ||||
if (seg == NULL) | if (seg == NULL) | ||||
return (NULL); | return (NULL); | ||||
m = &seg->first_page[atop(pa - seg->start)]; | m = &seg->first_page[atop(pa - seg->start)]; | ||||
dougmUnsubmitted Not Done Inline ActionsIf could be used here, if the fields of vm_phys_fictitious_seg were reordered. dougm: If could be used here, if the fields of vm_phys_fictitious_seg were reordered. | |||||
markjAuthorUnsubmitted Done Inline ActionsI think I'd prefer to leave this case as it is. If there were more instances of this pattern, I'd be more inclined to take the suggestion. markj: I think I'd prefer to leave this case as it is. If there were more instances of this pattern… | |||||
KASSERT((m->flags & PG_FICTITIOUS) != 0, ("%p not fictitious", m)); | KASSERT((m->flags & PG_FICTITIOUS) != 0, ("%p not fictitious", m)); | ||||
return (m); | return (m); | ||||
} | } | ||||
static inline void | static inline void | ||||
vm_phys_fictitious_init_range(vm_page_t range, vm_paddr_t start, | vm_phys_fictitious_init_range(vm_page_t range, vm_paddr_t start, | ||||
long page_count, vm_memattr_t memattr) | long page_count, vm_memattr_t memattr) | ||||
▲ Show 20 Lines • Show All 179 Lines • ▼ Show 20 Lines | vm_phys_free_pages(vm_page_t m, int order) | ||||
seg = &vm_phys_segs[m->segind]; | seg = &vm_phys_segs[m->segind]; | ||||
vm_domain_free_assert_locked(VM_DOMAIN(seg->domain)); | vm_domain_free_assert_locked(VM_DOMAIN(seg->domain)); | ||||
if (order < VM_NFREEORDER - 1) { | if (order < VM_NFREEORDER - 1) { | ||||
pa = VM_PAGE_TO_PHYS(m); | pa = VM_PAGE_TO_PHYS(m); | ||||
do { | do { | ||||
pa ^= ((vm_paddr_t)1 << (PAGE_SHIFT + order)); | pa ^= ((vm_paddr_t)1 << (PAGE_SHIFT + order)); | ||||
if (pa < seg->start || pa >= seg->end) | if (pa < seg->start || pa >= seg->end) | ||||
break; | break; | ||||
m_buddy = &seg->first_page[atop(pa - seg->start)]; | m_buddy = vm_phys_seg_paddr_to_vm_page(seg, pa); | ||||
if (m_buddy->order != order) | if (m_buddy->order != order) | ||||
break; | break; | ||||
fl = (*seg->free_queues)[m_buddy->pool]; | fl = (*seg->free_queues)[m_buddy->pool]; | ||||
vm_freelist_rem(fl, m_buddy, order); | vm_freelist_rem(fl, m_buddy, order); | ||||
if (m_buddy->pool != m->pool) | if (m_buddy->pool != m->pool) | ||||
vm_phys_set_pool(m->pool, m_buddy, order); | vm_phys_set_pool(m->pool, m_buddy, order); | ||||
order++; | order++; | ||||
pa &= ~(((vm_paddr_t)1 << (PAGE_SHIFT + order)) - 1); | pa &= ~(((vm_paddr_t)1 << (PAGE_SHIFT + order)) - 1); | ||||
m = &seg->first_page[atop(pa - seg->start)]; | m = vm_phys_seg_paddr_to_vm_page(seg, pa); | ||||
} while (order < VM_NFREEORDER - 1); | } while (order < VM_NFREEORDER - 1); | ||||
} | } | ||||
fl = (*seg->free_queues)[m->pool]; | fl = (*seg->free_queues)[m->pool]; | ||||
vm_freelist_add(fl, m, order, 1); | vm_freelist_add(fl, m, order, 1); | ||||
} | } | ||||
/* | /* | ||||
* Free a contiguous, arbitrarily sized set of physical pages, without | * Free a contiguous, arbitrarily sized set of physical pages, without | ||||
▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | for (seg = &vm_phys_segs[segind]; seg < end_seg; seg++) { | ||||
if (seg->domain != domain) | if (seg->domain != domain) | ||||
continue; | continue; | ||||
if (seg->start >= high) | if (seg->start >= high) | ||||
return (-1); | return (-1); | ||||
pa_start = MAX(low, seg->start); | pa_start = MAX(low, seg->start); | ||||
pa_end = MIN(high, seg->end); | pa_end = MIN(high, seg->end); | ||||
if (pa_end - pa_start < ptoa(npages)) | if (pa_end - pa_start < ptoa(npages)) | ||||
continue; | continue; | ||||
bounds[0] = &seg->first_page[atop(pa_start - seg->start)]; | bounds[0] = vm_phys_seg_paddr_to_vm_page(seg, pa_start); | ||||
bounds[1] = &seg->first_page[atop(pa_end - seg->start)]; | bounds[1] = vm_phys_seg_paddr_to_vm_page(seg, pa_end); | ||||
return (seg - vm_phys_segs); | return (seg - vm_phys_segs); | ||||
} | } | ||||
return (-1); | return (-1); | ||||
} | } | ||||
/* | /* | ||||
* Search for the given physical page "m" in the free lists. If the search | * Search for the given physical page "m" in the free lists. If the search | ||||
* succeeds, remove "m" from the free lists and return true. Otherwise, return | * succeeds, remove "m" from the free lists and return true. Otherwise, return | ||||
Show All 17 Lines | vm_phys_unfree_page(vm_page_t m) | ||||
*/ | */ | ||||
seg = &vm_phys_segs[m->segind]; | seg = &vm_phys_segs[m->segind]; | ||||
vm_domain_free_assert_locked(VM_DOMAIN(seg->domain)); | vm_domain_free_assert_locked(VM_DOMAIN(seg->domain)); | ||||
for (m_set = m, order = 0; m_set->order == VM_NFREEORDER && | for (m_set = m, order = 0; m_set->order == VM_NFREEORDER && | ||||
order < VM_NFREEORDER - 1; ) { | order < VM_NFREEORDER - 1; ) { | ||||
order++; | order++; | ||||
pa = m->phys_addr & (~(vm_paddr_t)0 << (PAGE_SHIFT + order)); | pa = m->phys_addr & (~(vm_paddr_t)0 << (PAGE_SHIFT + order)); | ||||
if (pa >= seg->start) | if (pa >= seg->start) | ||||
m_set = &seg->first_page[atop(pa - seg->start)]; | m_set = vm_phys_seg_paddr_to_vm_page(seg, pa); | ||||
else | else | ||||
return (false); | return (false); | ||||
} | } | ||||
if (m_set->order < order) | if (m_set->order < order) | ||||
return (false); | return (false); | ||||
if (m_set->order == VM_NFREEORDER) | if (m_set->order == VM_NFREEORDER) | ||||
return (false); | return (false); | ||||
KASSERT(m_set->order < VM_NFREEORDER, | KASSERT(m_set->order < VM_NFREEORDER, | ||||
("vm_phys_unfree_page: page %p has unexpected order %d", | ("vm_phys_unfree_page: page %p has unexpected order %d", | ||||
m_set, m_set->order)); | m_set, m_set->order)); | ||||
/* | /* | ||||
* Next, remove "m_set" from the free lists. Finally, extract | * Next, remove "m_set" from the free lists. Finally, extract | ||||
* "m" from "m_set" using an iterative algorithm: While "m_set" | * "m" from "m_set" using an iterative algorithm: While "m_set" | ||||
* is larger than a page, shrink "m_set" by returning the half | * is larger than a page, shrink "m_set" by returning the half | ||||
* of "m_set" that does not contain "m" to the free lists. | * of "m_set" that does not contain "m" to the free lists. | ||||
*/ | */ | ||||
fl = (*seg->free_queues)[m_set->pool]; | fl = (*seg->free_queues)[m_set->pool]; | ||||
order = m_set->order; | order = m_set->order; | ||||
vm_freelist_rem(fl, m_set, order); | vm_freelist_rem(fl, m_set, order); | ||||
while (order > 0) { | while (order > 0) { | ||||
order--; | order--; | ||||
pa_half = m_set->phys_addr ^ (1 << (PAGE_SHIFT + order)); | pa_half = m_set->phys_addr ^ (1 << (PAGE_SHIFT + order)); | ||||
if (m->phys_addr < pa_half) | if (m->phys_addr < pa_half) | ||||
m_tmp = &seg->first_page[atop(pa_half - seg->start)]; | m_tmp = vm_phys_seg_paddr_to_vm_page(seg, pa_half); | ||||
else { | else { | ||||
m_tmp = m_set; | m_tmp = m_set; | ||||
m_set = &seg->first_page[atop(pa_half - seg->start)]; | m_set = vm_phys_seg_paddr_to_vm_page(seg, pa_half); | ||||
} | } | ||||
vm_freelist_add(fl, m_tmp, order, 0); | vm_freelist_add(fl, m_tmp, order, 0); | ||||
} | } | ||||
KASSERT(m_set == m, ("vm_phys_unfree_page: fatal inconsistency")); | KASSERT(m_set == m, ("vm_phys_unfree_page: fatal inconsistency")); | ||||
return (true); | return (true); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 514 Lines • Show Last 20 Lines |
This could be applied at vm_page.c:787, if it were visible there.