physical page management: eliminate static page frame array and
maintain page structures dynamically covering only file mappings. use hash table for address <-> page structure conversion.
This commit is contained in:
@ -430,7 +430,7 @@ static int fileobj_get_page(struct memobj *memobj, off_t off, int p2align, uintp
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
phys = virt_to_phys(virt);
|
phys = virt_to_phys(virt);
|
||||||
page = phys_to_page(phys);
|
page = phys_to_page_insert_hash(phys);
|
||||||
if (page->mode != PM_NONE) {
|
if (page->mode != PM_NONE) {
|
||||||
panic("fileobj_get_page:invalid new page");
|
panic("fileobj_get_page:invalid new page");
|
||||||
}
|
}
|
||||||
@ -502,10 +502,10 @@ static uintptr_t fileobj_copy_page(
|
|||||||
|
|
||||||
memobj_lock(memobj);
|
memobj_lock(memobj);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (orgpage->mode != PM_MAPPED) {
|
if (!orgpage || orgpage->mode != PM_MAPPED) {
|
||||||
kprintf("fileobj_copy_page(%p,%lx,%d):"
|
kprintf("fileobj_copy_page(%p,%lx,%d):"
|
||||||
"invalid cow page. %x\n",
|
"invalid cow page. %x\n",
|
||||||
memobj, orgpa, p2align, orgpage->mode);
|
memobj, orgpa, p2align, orgpage ? orgpage->mode : 0);
|
||||||
panic("fileobj_copy_page:invalid cow page");
|
panic("fileobj_copy_page:invalid cow page");
|
||||||
}
|
}
|
||||||
count = ihk_atomic_read(&orgpage->count);
|
count = ihk_atomic_read(&orgpage->count);
|
||||||
@ -527,7 +527,9 @@ static uintptr_t fileobj_copy_page(
|
|||||||
memcpy(newkva, orgkva, pgsize);
|
memcpy(newkva, orgkva, pgsize);
|
||||||
ihk_atomic_dec(&orgpage->count);
|
ihk_atomic_dec(&orgpage->count);
|
||||||
newpa = virt_to_phys(newkva);
|
newpa = virt_to_phys(newkva);
|
||||||
|
if (phys_to_page(newpa)) {
|
||||||
page_map(phys_to_page(newpa));
|
page_map(phys_to_page(newpa));
|
||||||
|
}
|
||||||
newkva = NULL; /* avoid ihk_mc_free_pages() */
|
newkva = NULL; /* avoid ihk_mc_free_pages() */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -563,6 +565,11 @@ static int fileobj_flush_page(struct memobj *memobj, uintptr_t phys,
|
|||||||
ssize_t ss;
|
ssize_t ss;
|
||||||
|
|
||||||
page = phys_to_page(phys);
|
page = phys_to_page(phys);
|
||||||
|
if (!page) {
|
||||||
|
kprintf("%s: warning: tried to flush non-existing page for phys addr: 0x%lx\n",
|
||||||
|
__FUNCTION__, phys);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
memobj_unlock(&obj->memobj);
|
memobj_unlock(&obj->memobj);
|
||||||
|
|
||||||
ihk_mc_syscall_arg0(&ctx) = PAGER_REQ_WRITE;
|
ihk_mc_syscall_arg0(&ctx) = PAGER_REQ_WRITE;
|
||||||
|
|||||||
@ -17,8 +17,9 @@
|
|||||||
|
|
||||||
struct page {
|
struct page {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
struct list_head hash;
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
uint8_t padding[3];
|
uint64_t phys;
|
||||||
ihk_atomic_t count;
|
ihk_atomic_t count;
|
||||||
off_t offset;
|
off_t offset;
|
||||||
};
|
};
|
||||||
@ -38,6 +39,7 @@ enum page_mode {
|
|||||||
struct page *phys_to_page(uintptr_t phys);
|
struct page *phys_to_page(uintptr_t phys);
|
||||||
uintptr_t page_to_phys(struct page *page);
|
uintptr_t page_to_phys(struct page *page);
|
||||||
int page_unmap(struct page *page);
|
int page_unmap(struct page *page);
|
||||||
|
struct page *phys_to_page_insert_hash(uint64_t phys);
|
||||||
|
|
||||||
void begin_free_pages_pending(void);
|
void begin_free_pages_pending(void);
|
||||||
void finish_free_pages_pending(void);
|
void finish_free_pages_pending(void);
|
||||||
|
|||||||
136
kernel/mem.c
136
kernel/mem.c
@ -50,7 +50,6 @@
|
|||||||
|
|
||||||
static struct ihk_page_allocator_desc *pa_allocator;
|
static struct ihk_page_allocator_desc *pa_allocator;
|
||||||
static unsigned long pa_start, pa_end;
|
static unsigned long pa_start, pa_end;
|
||||||
static struct page *pa_pages;
|
|
||||||
|
|
||||||
extern void unhandled_page_fault(struct thread *, void *, void *);
|
extern void unhandled_page_fault(struct thread *, void *, void *);
|
||||||
extern int interrupt_from_user(void *);
|
extern int interrupt_from_user(void *);
|
||||||
@ -99,9 +98,7 @@ static void free_pages(void *va, int npages)
|
|||||||
struct page *page;
|
struct page *page;
|
||||||
|
|
||||||
page = phys_to_page(virt_to_phys(va));
|
page = phys_to_page(virt_to_phys(va));
|
||||||
if (!page) {
|
if (page) {
|
||||||
panic("free_pages:struct page not found");
|
|
||||||
}
|
|
||||||
if (page->mode != PM_NONE) {
|
if (page->mode != PM_NONE) {
|
||||||
panic("free_pages:not PM_NONE");
|
panic("free_pages:not PM_NONE");
|
||||||
}
|
}
|
||||||
@ -111,6 +108,7 @@ static void free_pages(void *va, int npages)
|
|||||||
list_add_tail(&page->list, pendings);
|
list_add_tail(&page->list, pendings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ihk_pagealloc_free(pa_allocator, virt_to_phys(va), npages);
|
ihk_pagealloc_free(pa_allocator, virt_to_phys(va), npages);
|
||||||
}
|
}
|
||||||
@ -392,16 +390,11 @@ out:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void page_allocator_init(void)
|
static void page_allocator_init(uint64_t start, uint64_t end, int initial)
|
||||||
{
|
{
|
||||||
unsigned long page_map_pa, pages;
|
unsigned long page_map_pa, pages;
|
||||||
void *page_map;
|
void *page_map;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
uint64_t start;
|
|
||||||
uint64_t end;
|
|
||||||
|
|
||||||
start = ihk_mc_get_memory_address(IHK_MC_GMA_AVAIL_START, 0);
|
|
||||||
end = ihk_mc_get_memory_address(IHK_MC_GMA_AVAIL_END, 0);
|
|
||||||
|
|
||||||
start &= PAGE_MASK;
|
start &= PAGE_MASK;
|
||||||
pa_start = start & LARGE_PAGE_MASK;
|
pa_start = start & LARGE_PAGE_MASK;
|
||||||
@ -475,32 +468,94 @@ static void numa_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PHYS_PAGE_HASH_SHIFT (10)
|
||||||
|
#define PHYS_PAGE_HASH_SIZE (1 << PHYS_PAGE_HASH_SHIFT)
|
||||||
|
#define PHYS_PAGE_HASH_MASK (PHYS_PAGE_HASH_SIZE - 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Page hash only tracks pages that are mapped in non-anymous mappings
|
||||||
|
* and thus it is initially empty.
|
||||||
|
*/
|
||||||
|
struct list_head page_hash[PHYS_PAGE_HASH_SIZE];
|
||||||
|
ihk_spinlock_t page_hash_locks[PHYS_PAGE_HASH_SIZE];
|
||||||
|
|
||||||
|
static void page_init(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < PHYS_PAGE_HASH_SIZE; ++i) {
|
||||||
|
ihk_mc_spinlock_init(&page_hash_locks[i]);
|
||||||
|
INIT_LIST_HEAD(&page_hash[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: page_hash_lock must be held */
|
||||||
|
static struct page *__phys_to_page(uintptr_t phys)
|
||||||
|
{
|
||||||
|
int hash = (phys >> PAGE_SHIFT) & PHYS_PAGE_HASH_MASK;
|
||||||
|
struct page *page_iter, *page = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(page_iter, &page_hash[hash], hash) {
|
||||||
|
if (page_iter->phys == phys) {
|
||||||
|
page = page_iter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
struct page *phys_to_page(uintptr_t phys)
|
struct page *phys_to_page(uintptr_t phys)
|
||||||
{
|
{
|
||||||
int64_t ix;
|
int hash = (phys >> PAGE_SHIFT) & PHYS_PAGE_HASH_MASK;
|
||||||
|
struct page *page = NULL;
|
||||||
|
unsigned long irqflags;
|
||||||
|
|
||||||
if ((phys < pa_start) || (pa_end <= phys)) {
|
irqflags = ihk_mc_spinlock_lock(&page_hash_locks[hash]);
|
||||||
return NULL;
|
page = __phys_to_page(phys);
|
||||||
}
|
ihk_mc_spinlock_unlock(&page_hash_locks[hash], irqflags);
|
||||||
|
|
||||||
ix = (phys - pa_start) >> PAGE_SHIFT;
|
return page;
|
||||||
return &pa_pages[ix];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t page_to_phys(struct page *page)
|
uintptr_t page_to_phys(struct page *page)
|
||||||
{
|
{
|
||||||
int64_t ix;
|
return page ? page->phys : 0;
|
||||||
uintptr_t phys;
|
|
||||||
|
|
||||||
ix = page - pa_pages;
|
|
||||||
phys = pa_start + (ix << PAGE_SHIFT);
|
|
||||||
if ((phys < pa_start) || (pa_end <= phys)) {
|
|
||||||
ekprintf("page_to_phys(%p):not a pa_pages[]:%p %lx-%lx\n",
|
|
||||||
page, pa_pages, pa_start, pa_end);
|
|
||||||
panic("page_to_phys");
|
|
||||||
}
|
}
|
||||||
return phys;
|
|
||||||
|
/*
|
||||||
|
* Allocate page and add to hash if it doesn't exist yet.
|
||||||
|
* NOTE: page->count is zero for new pages and the caller
|
||||||
|
* is responsible to increase it.
|
||||||
|
*/
|
||||||
|
struct page *phys_to_page_insert_hash(uint64_t phys)
|
||||||
|
{
|
||||||
|
int hash = (phys >> PAGE_SHIFT) & PHYS_PAGE_HASH_MASK;
|
||||||
|
struct page *page = NULL;
|
||||||
|
unsigned long irqflags;
|
||||||
|
|
||||||
|
irqflags = ihk_mc_spinlock_lock(&page_hash_locks[hash]);
|
||||||
|
page = __phys_to_page(phys);
|
||||||
|
if (!page) {
|
||||||
|
int hash = (phys >> PAGE_SHIFT) & PHYS_PAGE_HASH_MASK;
|
||||||
|
page = kmalloc(sizeof(*page), IHK_MC_AP_CRITICAL);
|
||||||
|
if (!page) {
|
||||||
|
kprintf("%s: error allocating page\n", __FUNCTION__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add(&page->hash, &page_hash[hash]);
|
||||||
|
page->phys = phys;
|
||||||
|
page->mode = PM_NONE;
|
||||||
|
INIT_LIST_HEAD(&page->list);
|
||||||
|
ihk_atomic_set(&page->count, 0);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
ihk_mc_spinlock_unlock(&page_hash_locks[hash], irqflags);
|
||||||
|
|
||||||
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
int page_unmap(struct page *page)
|
int page_unmap(struct page *page)
|
||||||
@ -513,35 +568,19 @@ int page_unmap(struct page *page)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no mapping exist */
|
/* no mapping exist TODO: why is this check??
|
||||||
if (page->mode != PM_MAPPED) {
|
if (page->mode != PM_MAPPED) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
list_del(&page->list);
|
list_del(&page->hash);
|
||||||
page->mode = PM_NONE;
|
page->mode = PM_NONE;
|
||||||
|
kfree(page);
|
||||||
dkprintf("page_unmap(%p %x %d): 1\n", page, page->mode, page->count);
|
dkprintf("page_unmap(%p %x %d): 1\n", page, page->mode, page->count);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void page_init(void)
|
|
||||||
{
|
|
||||||
size_t npages;
|
|
||||||
size_t allocsize;
|
|
||||||
size_t allocpages;
|
|
||||||
|
|
||||||
if (sizeof(ihk_atomic_t) != sizeof(uint32_t)) {
|
|
||||||
panic("sizeof(ihk_atomic_t) is not 32 bit");
|
|
||||||
}
|
|
||||||
npages = (pa_end - pa_start) >> PAGE_SHIFT;
|
|
||||||
allocsize = sizeof(struct page) * npages;
|
|
||||||
allocpages = (allocsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
||||||
|
|
||||||
pa_pages = ihk_mc_alloc_pages(allocpages, IHK_MC_AP_CRITICAL);
|
|
||||||
memset(pa_pages, 0, allocsize);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *memdebug = NULL;
|
static char *memdebug = NULL;
|
||||||
|
|
||||||
static void *___kmalloc(int size, enum ihk_mc_ap_flag flag);
|
static void *___kmalloc(int size, enum ihk_mc_ap_flag flag);
|
||||||
@ -667,7 +706,10 @@ void ihk_mc_clean_micpa(void){
|
|||||||
void mem_init(void)
|
void mem_init(void)
|
||||||
{
|
{
|
||||||
numa_init();
|
numa_init();
|
||||||
page_allocator_init();
|
page_allocator_init(
|
||||||
|
ihk_mc_get_memory_address(IHK_MC_GMA_AVAIL_START, 0),
|
||||||
|
ihk_mc_get_memory_address(IHK_MC_GMA_AVAIL_END, 0), 1);
|
||||||
|
|
||||||
page_init();
|
page_init();
|
||||||
|
|
||||||
/* Prepare the kernel virtual map space */
|
/* Prepare the kernel virtual map space */
|
||||||
|
|||||||
@ -1542,9 +1542,11 @@ retry:
|
|||||||
__FUNCTION__, pgaddr, pgsize);
|
__FUNCTION__, pgaddr, pgsize);
|
||||||
memset(virt, 0, pgsize);
|
memset(virt, 0, pgsize);
|
||||||
phys = virt_to_phys(virt);
|
phys = virt_to_phys(virt);
|
||||||
|
if (phys_to_page(phys)) {
|
||||||
page_map(phys_to_page(phys));
|
page_map(phys_to_page(phys));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
phys = pte_get_phys(ptep);
|
phys = pte_get_phys(ptep);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -404,7 +404,7 @@ static int shmobj_get_page(struct memobj *memobj, off_t off, int p2align,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
phys = virt_to_phys(virt);
|
phys = virt_to_phys(virt);
|
||||||
page = phys_to_page(phys);
|
page = phys_to_page_insert_hash(phys);
|
||||||
if (page->mode != PM_NONE) {
|
if (page->mode != PM_NONE) {
|
||||||
fkprintf("shmobj_get_page(%p,%#lx,%d,%p):"
|
fkprintf("shmobj_get_page(%p,%#lx,%d,%p):"
|
||||||
"page %p %#lx %d %d %#lx\n",
|
"page %p %#lx %d %d %#lx\n",
|
||||||
|
|||||||
@ -112,7 +112,7 @@ static int alloc_zeroobj(void)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
phys = virt_to_phys(virt);
|
phys = virt_to_phys(virt);
|
||||||
page = phys_to_page(phys);
|
page = phys_to_page_insert_hash(phys);
|
||||||
|
|
||||||
if (page->mode != PM_NONE) {
|
if (page->mode != PM_NONE) {
|
||||||
fkprintf("alloc_zeroobj():"
|
fkprintf("alloc_zeroobj():"
|
||||||
|
|||||||
Reference in New Issue
Block a user