Add a facility to register a range of physical addresses to be used
for allocation of fictitious pages, for which PHYS_TO_VM_PAGE() returns proper fictitious vm_page_t. The range should be de-registered after consumer stopped using it. De-inline the PHYS_TO_VM_PAGE() since it now carries code to iterate over registered ranges. A hash container might be developed instead of range registration interface, and fake pages could be put automatically into the hash, were PHYS_TO_VM_PAGE() could look them up later. This should be considered before the MFC of the commit is done. Sponsored by: The FreeBSD Foundation Reviewed by: alc MFC after: 1 month
This commit is contained in:
parent
1ad1048d19
commit
9ff1ec42a4
@ -633,6 +633,30 @@ vm_page_unhold_pages(vm_page_t *ma, int count)
|
||||
mtx_unlock(mtx);
|
||||
}
|
||||
|
||||
vm_page_t
|
||||
PHYS_TO_VM_PAGE(vm_paddr_t pa)
|
||||
{
|
||||
vm_page_t m;
|
||||
|
||||
#ifdef VM_PHYSSEG_SPARSE
|
||||
m = vm_phys_paddr_to_vm_page(pa);
|
||||
if (m == NULL)
|
||||
m = vm_phys_fictitious_to_vm_page(pa);
|
||||
return (m);
|
||||
#elif defined(VM_PHYSSEG_DENSE)
|
||||
long pi;
|
||||
|
||||
pi = atop(pa);
|
||||
if (pi >= first_page && pi < vm_page_array_size) {
|
||||
m = &vm_page_array[pi - first_page];
|
||||
return (m);
|
||||
}
|
||||
return (vm_phys_fictitious_to_vm_page(pa));
|
||||
#else
|
||||
#error "Either VM_PHYSSEG_DENSE or VM_PHYSSEG_SPARSE must be defined."
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* vm_page_getfake:
|
||||
*
|
||||
|
@ -321,19 +321,7 @@ extern long first_page; /* first physical page number */
|
||||
|
||||
vm_page_t vm_phys_paddr_to_vm_page(vm_paddr_t pa);
|
||||
|
||||
static __inline vm_page_t PHYS_TO_VM_PAGE(vm_paddr_t pa);
|
||||
|
||||
static __inline vm_page_t
|
||||
PHYS_TO_VM_PAGE(vm_paddr_t pa)
|
||||
{
|
||||
#ifdef VM_PHYSSEG_SPARSE
|
||||
return (vm_phys_paddr_to_vm_page(pa));
|
||||
#elif defined(VM_PHYSSEG_DENSE)
|
||||
return (&vm_page_array[atop(pa) - first_page]);
|
||||
#else
|
||||
#error "Either VM_PHYSSEG_DENSE or VM_PHYSSEG_SPARSE must be defined."
|
||||
#endif
|
||||
}
|
||||
vm_page_t PHYS_TO_VM_PAGE(vm_paddr_t pa);
|
||||
|
||||
extern struct vpglocks vm_page_queue_lock;
|
||||
|
||||
|
117
sys/vm/vm_phys.c
117
sys/vm/vm_phys.c
@ -87,6 +87,15 @@ static struct vm_phys_seg vm_phys_segs[VM_PHYSSEG_MAX];
|
||||
|
||||
static int vm_phys_nsegs;
|
||||
|
||||
#define VM_PHYS_FICTITIOUS_NSEGS 8
|
||||
static struct vm_phys_fictitious_seg {
|
||||
vm_paddr_t start;
|
||||
vm_paddr_t end;
|
||||
vm_page_t first_page;
|
||||
} vm_phys_fictitious_segs[VM_PHYS_FICTITIOUS_NSEGS];
|
||||
static struct mtx vm_phys_fictitious_reg_mtx;
|
||||
MALLOC_DEFINE(M_FICT_PAGES, "", "");
|
||||
|
||||
static struct vm_freelist
|
||||
vm_phys_free_queues[VM_RAW_NFREELIST][VM_NFREEPOOL][VM_NFREEORDER];
|
||||
static struct vm_freelist
|
||||
@ -366,6 +375,8 @@ vm_phys_init(void)
|
||||
for (flind = 0; flind < vm_nfreelists; flind++)
|
||||
vm_phys_lookup_lists[0][flind] = &vm_phys_free_queues[flind];
|
||||
#endif
|
||||
|
||||
mtx_init(&vm_phys_fictitious_reg_mtx, "vmfctr", NULL, MTX_DEF);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -510,6 +521,112 @@ vm_phys_paddr_to_vm_page(vm_paddr_t pa)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
vm_page_t
|
||||
vm_phys_fictitious_to_vm_page(vm_paddr_t pa)
|
||||
{
|
||||
struct vm_phys_fictitious_seg *seg;
|
||||
vm_page_t m;
|
||||
int segind;
|
||||
|
||||
m = NULL;
|
||||
for (segind = 0; segind < VM_PHYS_FICTITIOUS_NSEGS; segind++) {
|
||||
seg = &vm_phys_fictitious_segs[segind];
|
||||
if (pa >= seg->start && pa < seg->end) {
|
||||
m = &seg->first_page[atop(pa - seg->start)];
|
||||
KASSERT((m->flags & PG_FICTITIOUS) != 0,
|
||||
("%p not fictitious", m));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (m);
|
||||
}
|
||||
|
||||
int
|
||||
vm_phys_fictitious_reg_range(vm_paddr_t start, vm_paddr_t end,
|
||||
vm_memattr_t memattr)
|
||||
{
|
||||
struct vm_phys_fictitious_seg *seg;
|
||||
vm_page_t fp;
|
||||
long i, page_count;
|
||||
int segind;
|
||||
#ifdef VM_PHYSSEG_DENSE
|
||||
long pi;
|
||||
boolean_t malloced;
|
||||
#endif
|
||||
|
||||
page_count = (end - start) / PAGE_SIZE;
|
||||
|
||||
#ifdef VM_PHYSSEG_DENSE
|
||||
pi = atop(start);
|
||||
if (pi >= first_page && atop(end) < vm_page_array_size) {
|
||||
fp = &vm_page_array[pi - first_page];
|
||||
malloced = FALSE;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
fp = malloc(page_count * sizeof(struct vm_page), M_FICT_PAGES,
|
||||
M_WAITOK | M_ZERO);
|
||||
#ifdef VM_PHYSSEG_DENSE
|
||||
malloced = TRUE;
|
||||
#endif
|
||||
}
|
||||
for (i = 0; i < page_count; i++) {
|
||||
vm_page_initfake(&fp[i], start + PAGE_SIZE * i, memattr);
|
||||
pmap_page_init(&fp[i]);
|
||||
fp[i].oflags &= ~(VPO_BUSY | VPO_UNMANAGED);
|
||||
}
|
||||
mtx_lock(&vm_phys_fictitious_reg_mtx);
|
||||
for (segind = 0; segind < VM_PHYS_FICTITIOUS_NSEGS; segind++) {
|
||||
seg = &vm_phys_fictitious_segs[segind];
|
||||
if (seg->start == 0 && seg->end == 0) {
|
||||
seg->start = start;
|
||||
seg->end = end;
|
||||
seg->first_page = fp;
|
||||
mtx_unlock(&vm_phys_fictitious_reg_mtx);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&vm_phys_fictitious_reg_mtx);
|
||||
#ifdef VM_PHYSSEG_DENSE
|
||||
if (malloced)
|
||||
#endif
|
||||
free(fp, M_FICT_PAGES);
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
void
|
||||
vm_phys_fictitious_unreg_range(vm_paddr_t start, vm_paddr_t end)
|
||||
{
|
||||
struct vm_phys_fictitious_seg *seg;
|
||||
vm_page_t fp;
|
||||
int segind;
|
||||
#ifdef VM_PHYSSEG_DENSE
|
||||
long pi;
|
||||
#endif
|
||||
|
||||
#ifdef VM_PHYSSEG_DENSE
|
||||
pi = atop(start);
|
||||
#endif
|
||||
|
||||
mtx_lock(&vm_phys_fictitious_reg_mtx);
|
||||
for (segind = 0; segind < VM_PHYS_FICTITIOUS_NSEGS; segind++) {
|
||||
seg = &vm_phys_fictitious_segs[segind];
|
||||
if (seg->start == start && seg->end == end) {
|
||||
seg->start = seg->end = 0;
|
||||
fp = seg->first_page;
|
||||
seg->first_page = NULL;
|
||||
mtx_unlock(&vm_phys_fictitious_reg_mtx);
|
||||
#ifdef VM_PHYSSEG_DENSE
|
||||
if (pi < first_page || atop(end) >= vm_page_array_size)
|
||||
#endif
|
||||
free(fp, M_FICT_PAGES);
|
||||
return;
|
||||
}
|
||||
}
|
||||
mtx_unlock(&vm_phys_fictitious_reg_mtx);
|
||||
KASSERT(0, ("Unregistering not registered fictitious range"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the segment containing the given physical address.
|
||||
*/
|
||||
|
@ -57,6 +57,10 @@ vm_page_t vm_phys_alloc_contig(u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
u_long alignment, vm_paddr_t boundary);
|
||||
vm_page_t vm_phys_alloc_freelist_pages(int flind, int pool, int order);
|
||||
vm_page_t vm_phys_alloc_pages(int pool, int order);
|
||||
int vm_phys_fictitious_reg_range(vm_paddr_t start, vm_paddr_t end,
|
||||
vm_memattr_t memattr);
|
||||
void vm_phys_fictitious_unreg_range(vm_paddr_t start, vm_paddr_t end);
|
||||
vm_page_t vm_phys_fictitious_to_vm_page(vm_paddr_t pa);
|
||||
void vm_phys_free_contig(vm_page_t m, u_long npages);
|
||||
void vm_phys_free_pages(vm_page_t m, int order);
|
||||
void vm_phys_init(void);
|
||||
|
Loading…
Reference in New Issue
Block a user