Fixed minor faults. More progress on vma merge.

More to be done about vm object flags, page refcounts etc.
This commit is contained in:
Bahadir Balban
2008-03-11 01:07:44 +00:00
parent e8561aa541
commit 8447cd6ce3
4 changed files with 56 additions and 32 deletions
+9 -5
View File
@@ -1,7 +1,7 @@
/* /*
* Virtual memory area descriptors. * Virtual memory area descriptors.
* *
* Copyright (C) 2007 Bahadir Balban * Copyright (C) 2007, 2008 Bahadir Balban
*/ */
#ifndef __VM_AREA_H__ #ifndef __VM_AREA_H__
#define __VM_AREA_H__ #define __VM_AREA_H__
@@ -41,7 +41,7 @@ struct devpage {
}; };
struct page { struct page {
int count; /* Refcount */ int refcnt; /* Refcount */
struct spinlock lock; /* Page lock. */ struct spinlock lock; /* Page lock. */
struct list_head list; /* For list of a vm_object's in-memory pages */ struct list_head list; /* For list of a vm_object's in-memory pages */
struct vm_object *owner;/* The vm_object the page belongs to */ struct vm_object *owner;/* The vm_object the page belongs to */
@@ -68,8 +68,11 @@ struct fault_data {
}; };
struct vm_pager_ops { struct vm_pager_ops {
struct page *(*page_in)(struct vm_object *vm_obj, unsigned long pfn_offset); struct page *(*page_in)(struct vm_object *vm_obj,
struct page *(*page_out)(struct vm_object *vm_obj, unsigned long pfn_offset); unsigned long pfn_offset);
struct page *(*page_out)(struct vm_object *vm_obj,
unsigned long pfn_offset);
int (*release_pages)(struct vm_object *vm_obj);
}; };
/* Describes the pager task that handles a vm_area. */ /* Describes the pager task that handles a vm_area. */
@@ -115,7 +118,8 @@ struct vm_object {
unsigned int flags; /* Defines the type and flags of the object */ unsigned int flags; /* Defines the type and flags of the object */
struct list_head list; /* List of all vm objects in memory */ struct list_head list; /* List of all vm objects in memory */
struct vm_pager *pager; /* The pager for this object */ struct vm_pager *pager; /* The pager for this object */
struct list_head page_cache; /* List of in-memory pages */ struct list_head page_cache;/* List of in-memory pages */
struct vm_object_ops ops; /* Operations on the object */
}; };
/* In memory representation of either a vfs file, a device. */ /* In memory representation of either a vfs file, a device. */
+23 -25
View File
@@ -145,7 +145,7 @@ int vm_object_check_subset(struct vm_object *copier,
} }
/* Merges link 1 to link 2 */ /* Merges link 1 to link 2 */
int do_vma_merge_link(struct vm_obj_link *link1, struct vm_obj_link *link2) int vma_do_merge_link(struct vm_obj_link *link1, struct vm_obj_link *link2)
{ {
struct vm_object *obj1 = link1->obj; struct vm_object *obj1 = link1->obj;
struct vm_object *obj2 = link2->obj; struct vm_object *obj2 = link2->obj;
@@ -192,18 +192,10 @@ int vma_merge_link(struct vm_obj_link *vmo_link)
BUG_ON(!list_empty(&vmo_link->obj->shadowers)); BUG_ON(!list_empty(&vmo_link->obj->shadowers));
/* Do the actual merge */ /* Do the actual merge */
do_vma_merge_link(vmo_link, sh_link); vma_do_merge_link(vmo_link, sh_link);
} }
/*
* To merge, the object should use the last shadow
* reference left, but this reference must be changed
* to point at the vm_obj_link rather than the object
* itself, because it's not possible to find the link
* from the object.
*/
struct vm_obj_link *vma_create_shadow(void) struct vm_obj_link *vma_create_shadow(void)
{ {
struct vm_object *vmo; struct vm_object *vmo;
@@ -212,11 +204,12 @@ struct vm_obj_link *vma_create_shadow(void)
if (!(vmo_link = kzalloc(sizeof(*vmo_link)))) if (!(vmo_link = kzalloc(sizeof(*vmo_link))))
return 0; return 0;
if (!(vmo = vm_object_alloc_init())) { if (!(vmo = vm_object_create())) {
kfree(vmo_link); kfree(vmo_link);
return 0; return 0;
} }
INIT_LIST_HEAD(&vmo_link->list); INIT_LIST_HEAD(&vmo_link->list);
vmo->type = VM_OBJ_SHADOW;
vmo_link->obj = vmo; vmo_link->obj = vmo;
return vmo_link; return vmo_link;
@@ -250,7 +243,7 @@ struct page *copy_page(struct page *orig)
/* TODO: /* TODO:
* - Why not allocate a swap descriptor in vma_create_shadow() rather than * - Why not allocate a swap descriptor in vma_create_shadow() rather than
* a bare vm_object? It will be needed. * a bare vm_object? It will be needed.
* * - Does vm_write clash with any other object flags???
* - Check refcounting of shadows, their references, page refs, * - Check refcounting of shadows, their references, page refs,
* reduces increases etc. * reduces increases etc.
*/ */
@@ -303,21 +296,23 @@ int copy_on_write(struct fault_data *fault)
/* Shadow is the copier object */ /* Shadow is the copier object */
copier_link = shadow_link; copier_link = shadow_link;
} else { } else {
/* No new shadows, topmost vmo is the copier object */ /* No new shadows, the topmost r/w vmo is the copier object */
copier_link = vmo_link; copier_link = vmo_link;
/* /*
* We start page search on read-only objects. If the first * We start page search on read-only objects. If the first
* one was writable, go to next which must be read-only. * one was writable, go to next which must be read-only.
*/ */
BUG_ON(!(vmo_link = vma_next_object(vmo_link, &vma->vm_obj_list))); BUG_ON(!(vmo_link = vma_next_object(vmo_link,
&vma->vm_obj_list)));
BUG_ON(vmo_link->obj->flags & VM_WRITE); BUG_ON(vmo_link->obj->flags & VM_WRITE);
} }
/* Traverse the list of read-only vm objects and search for the page */ /* Traverse the list of read-only vm objects and search for the page */
while (!(page = vmo_link->obj->pager.ops->page_in(vmo_link->obj, while (!(page = vmo_link->obj->pager.ops->page_in(vmo_link->obj,
file_offset))) { file_offset))) {
if (!(vmo_link = vma_next_object(vmo_link, &vma->vm_obj_list))) { if (!(vmo_link = vma_next_object(vmo_link,
&vma->vm_obj_list))) {
printf("%s:%s: Traversed all shadows and the original " printf("%s:%s: Traversed all shadows and the original "
"file's vm_object, but could not find the " "file's vm_object, but could not find the "
"faulty page in this vma.\n",__TASKNAME__, "faulty page in this vma.\n",__TASKNAME__,
@@ -341,17 +336,18 @@ int copy_on_write(struct fault_data *fault)
/* Add the page to owner's list of in-memory pages */ /* Add the page to owner's list of in-memory pages */
BUG_ON(!list_empty(&new_page->list)); BUG_ON(!list_empty(&new_page->list));
insert_page_olist(page, shadow_link->obj); insert_page_olist(new_page, new_page->owner->obj);
spin_unlock(&page->lock); spin_unlock(&page->lock);
/* Map it to faulty task */ /* Map the new page to faulty task */
l4_map(page_to_phys(page), (void *)page_align(fault->address), 1, l4_map(page_to_phys(new_page), (void *)page_align(fault->address), 1,
(reason & VM_READ) ? MAP_USR_RO_FLAGS : MAP_USR_RW_FLAGS, (reason & VM_READ) ? MAP_USR_RO_FLAGS : MAP_USR_RW_FLAGS,
fault->task->tid); fault->task->tid);
/* /*
* Check possible shadow collapses. Does the copier shadow * Finished handling the actual fault, now check for possible
* completely shadow the one underlying it? * shadow collapses. Does the copier shadow completely shadow
* the one underlying it?
*/ */
if (!(vmo_link = vma_next_object(copier_link, &vma->vm_obj_list))) { if (!(vmo_link = vma_next_object(copier_link, &vma->vm_obj_list))) {
/* Copier must have an object under it */ /* Copier must have an object under it */
@@ -365,12 +361,14 @@ int copy_on_write(struct fault_data *fault)
vma_drop_link(copier_link, vmo_link); vma_drop_link(copier_link, vmo_link);
/* vm object reference down to one? */ /* vm object reference down to one? */
if (vmo_link->obj->refcnt == 1) { if (vmo_link->obj->refcnt == 1)
BUG(); /* Check that the mergers are both shadows!!! */ /* The object is mergeable? i.e. not a file? */
/* TODO: Fill this in! Merge with the only reference */ if (vmo_link->type != VM_OBJ_FILE)
vm_object_merge(vmo_link); /* Merge it with its only shadower */
} vm_object_merge(vmo_link);
} }
return 0;
} }
+21
View File
@@ -23,6 +23,25 @@ struct page *find_page(struct vm_object *obj, unsigned long pfn)
return 0; return 0;
} }
int default_release_pages(struct vm_object *vm_obj)
{
struct page *p;
struct list_head *n;
void *phys;
list_for_each_entry_safe(p, n, &vm_obj->page_cache, list) {
list_del(&p->list);
BUG_ON(p->refcnt);
/* Return page back to allocator */
free_page(page_to_phys(p));
/* Free the page structure */
kfree(p);
}
return 0;
}
struct page *file_page_in(struct vm_object *vm_obj, unsigned long page_offset) struct page *file_page_in(struct vm_object *vm_obj, unsigned long page_offset)
{ {
struct vm_file *f = vm_object_to_file(vm_obj); struct vm_file *f = vm_object_to_file(vm_obj);
@@ -103,6 +122,7 @@ int read_file_pages(struct vm_file *f, unsigned long pfn_start,
struct vm_pager file_pager = { struct vm_pager file_pager = {
.ops = { .ops = {
.page_in = file_page_in, .page_in = file_page_in,
.release_pages = default_release_pages,
}, },
}; };
@@ -128,6 +148,7 @@ struct page *swap_page_in(struct vm_object *vm_obj, unsigned long file_offset)
struct vm_pager swap_pager = { struct vm_pager swap_pager = {
.ops = { .ops = {
.page_in = swap_page_in, .page_in = swap_page_in,
.release_pages = default_release_pages,
}, },
}; };
+3 -2
View File
@@ -25,7 +25,7 @@ struct vm_object *vm_object_init(struct vm_object *obj)
} }
/* Allocate and initialise a vmfile, and return it */ /* Allocate and initialise a vmfile, and return it */
struct vm_object *vm_object_alloc_init(void) struct vm_object *vm_object_create(void)
{ {
struct vm_object *obj; struct vm_object *obj;
@@ -35,7 +35,7 @@ struct vm_object *vm_object_alloc_init(void)
return vm_object_init(obj); return vm_object_init(obj);
} }
struct vm_file *vm_file_alloc_init(void) struct vm_file *vm_file_create(void)
{ {
struct vm_file *f; struct vm_file *f;
@@ -44,6 +44,7 @@ struct vm_file *vm_file_alloc_init(void)
INIT_LIST_HEAD(&f->file_list); INIT_LIST_HEAD(&f->file_list);
vm_object_init(&f->vm_obj); vm_object_init(&f->vm_obj);
f->vm_obj->type = VM_OBJ_FILE;
return f; return f;
} }