Bugfixes, enhancements

- Fixed an important bug with shadow object handling.
  When a shadow is dropped, if there are references left
  to it, both the object in front and dropped object becomes
  a shadow of the original object underneath. We had thought
  of this case but had not increase the shadow count.

- Added a test mechanism that tests the number of objects,
  vmfiles, shadows etc. by first counting them and trying to
  reach the same number by other means, i.e. per-object-shadow counts.
  It discovered a plethora of bugs.

- Added new set of functions to register objects, files and tasks
  globally with the pager, these functions introduce a refcount as
  well as adding structures to linked lists.

- fork/exit now seems to work stably i.e. no negative shadow counts etc.
This commit is contained in:
Bahadir Balban
2008-10-24 13:45:39 +03:00
parent b3693de21b
commit 651901d8b9
13 changed files with 384 additions and 146 deletions

View File

@@ -0,0 +1,13 @@
#ifndef __GLOBALS_H__
#define __GLOBALS_H__
struct global_list {
int total;
struct list_head list;
};
extern struct global_list global_vm_files;
extern struct global_list global_vm_objects;
extern struct global_list global_tasks;
#endif /* __GLOBALS_H__ */

View File

@@ -111,8 +111,14 @@ struct task_data_head {
struct task_data tdata[]; struct task_data tdata[];
}; };
struct tcb_head {
struct list_head list;
int total; /* Total threads */
};
struct tcb *find_task(int tid); struct tcb *find_task(int tid);
void task_add_global(struct tcb *t); void global_add_task(struct tcb *task);
void global_remove_task(struct tcb *task);
int send_task_data(struct tcb *requester); int send_task_data(struct tcb *requester);
void task_map_prefault_utcb(struct tcb *mapper, struct tcb *owner); void task_map_prefault_utcb(struct tcb *mapper, struct tcb *owner);
int task_mmap_regions(struct tcb *task, struct vm_file *file); int task_mmap_regions(struct tcb *task, struct vm_file *file);
@@ -122,8 +128,8 @@ int task_setup_registers(struct tcb *task, unsigned int pc,
unsigned int sp, l4id_t pager); unsigned int sp, l4id_t pager);
struct tcb *tcb_alloc_init(unsigned int flags); struct tcb *tcb_alloc_init(unsigned int flags);
int tcb_destroy(struct tcb *task); int tcb_destroy(struct tcb *task);
int task_exec(struct vm_file *f, unsigned long task_region_start, struct tcb *task_exec(struct vm_file *f, unsigned long task_region_start,
unsigned long task_region_end, struct task_ids *ids); unsigned long task_region_end, struct task_ids *ids);
int task_start(struct tcb *task, struct task_ids *ids); int task_start(struct tcb *task, struct task_ids *ids);
int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags); int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags);
int task_release_vmas(struct task_vma_head *vma_head); int task_release_vmas(struct task_vma_head *vma_head);

7
tasks/mm0/include/test.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef __TEST_H__
#define __TEST_H__
int mm0_test_global_vm_integrity(void);
#endif /* __TEST_H__ */

View File

@@ -223,7 +223,8 @@ struct vm_file *vm_file_create(void);
int vm_file_delete(struct vm_file *f); int vm_file_delete(struct vm_file *f);
int vm_object_delete(struct vm_object *vmo); int vm_object_delete(struct vm_object *vmo);
void vm_object_print(struct vm_object *vmo); void vm_object_print(struct vm_object *vmo);
void vm_object_print1(struct vm_object *vmo); void vm_print_objects(struct list_head *vmo_list);
void vm_print_files(struct list_head *file_list);
/* Used for pre-faulting a page from mm0 */ /* Used for pre-faulting a page from mm0 */
int prefault_page(struct tcb *task, unsigned long address, int prefault_page(struct tcb *task, unsigned long address,
@@ -249,4 +250,9 @@ int page_fault_handler(struct tcb *faulty_task, fault_kdata_t *fkdata);
int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link); int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link);
int vma_drop_merge_delete_all(struct vm_area *vma); int vma_drop_merge_delete_all(struct vm_area *vma);
void global_add_vm_object(struct vm_object *obj);
void global_remove_vm_object(struct vm_object *obj);
void global_add_vm_file(struct vm_file *f);
void global_remove_vm_file(struct vm_file *f);
#endif /* __VM_AREA_H__ */ #endif /* __VM_AREA_H__ */

View File

@@ -100,7 +100,7 @@ int sys_fork(struct tcb *parent)
vfs_notify_fork(child, parent); vfs_notify_fork(child, parent);
/* Add child to global task list */ /* Add child to global task list */
task_add_global(child); global_add_task(child);
/* Start forked child. */ /* Start forked child. */
l4_thread_control(THREAD_RUN, &ids); l4_thread_control(THREAD_RUN, &ids);
@@ -145,7 +145,7 @@ int sys_clone(struct tcb *parent, void *child_stack, unsigned int flags)
vfs_notify_fork(child, parent); vfs_notify_fork(child, parent);
/* Add child to global task list */ /* Add child to global task list */
task_add_global(child); global_add_task(child);
/* Start forked child. */ /* Start forked child. */
printf("%s/%s: Starting forked child.\n", __TASKNAME__, __FUNCTION__); printf("%s/%s: Starting forked child.\n", __TASKNAME__, __FUNCTION__);

View File

@@ -18,6 +18,8 @@
#include <memory.h> #include <memory.h>
#include <shm.h> #include <shm.h>
#include <file.h> #include <file.h>
#include <test.h>
/* Given a page and the vma it is in, returns that page's virtual address */ /* Given a page and the vma it is in, returns that page's virtual address */
unsigned long vma_page_to_virtual(struct vm_area *vma, struct page *p) unsigned long vma_page_to_virtual(struct vm_area *vma, struct page *p)
@@ -117,6 +119,20 @@ static inline int vm_object_is_droppable(struct vm_object *shadow,
return 0; return 0;
} }
/*
* vma_merge_object()
*
* FIXME: Currently this is an optimisation that needs to go
* away when swapping is available. We have this solely because
* currently a shadow needs to identically mirror the whole
* object underneath, in order to drop it. A file that is 1MB
* long would spend 2MB until dropped. When swapping is available,
* we will go back to identical mirroring instead of merging the
* last shadow, since most unused pages would be swapped out.
*/
/* /*
* When one shadow object is redundant, merges it into the shadow in front of it. * When one shadow object is redundant, merges it into the shadow in front of it.
* Note it must be determined that it is redundant before calling this function. * Note it must be determined that it is redundant before calling this function.
@@ -164,13 +180,13 @@ int vma_merge_object(struct vm_object *redundant)
BUG_ON(!list_empty(&redundant->shdw_list)); BUG_ON(!list_empty(&redundant->shdw_list));
/* Redundant won't be a shadow of its next object */ /* Redundant won't be a shadow of its next object */
list_del(&redundant->shref); list_del_init(&redundant->shref);
/* Front is now a shadow of redundant's next object */ /* Front is now a shadow of redundant's next object */
list_add(&front->shref, &redundant->orig_obj->shdw_list); list_add(&front->shref, &redundant->orig_obj->shdw_list);
front->orig_obj = redundant->orig_obj; front->orig_obj = redundant->orig_obj;
/* Find, unlink and delete the last link for the object */ /* Find last link for the object */
last_link = list_entry(redundant->link_list.next, last_link = list_entry(redundant->link_list.next,
struct vm_obj_link, linkref); struct vm_obj_link, linkref);
@@ -264,13 +280,14 @@ int vm_object_is_deletable(struct vm_object *obj)
{ {
struct vm_file *f; struct vm_file *f;
printf("%s: Checking: ", __FUNCTION__); //printf("%s: Checking: ", __FUNCTION__);
vm_object_print(obj); //vm_object_print(obj);
if (obj->nlinks != 0) if (obj->nlinks != 0)
return 0; return 0;
BUG_ON(obj->shadows != 0); BUG_ON(obj->shadows != 0);
BUG_ON(!list_empty(&obj->shref));
if (obj->flags & VM_OBJ_SHADOW) if (obj->flags & VM_OBJ_SHADOW)
return 1; return 1;
@@ -296,10 +313,15 @@ int vm_object_is_deletable(struct vm_object *obj)
} }
/* /*
* Drops a link to an object if possible, and if it has dropped it, * exit has: !prev, next || !next
* decides and takes action on the dropped object, depending on * shadow drop has: prev, next
* how many links and shadows it has left, and the type of the object. */
* This covers both copy_on_write() shadow drops and exit() cases.
/*
* Shadow drops: Dropping a link to shadow does not mean the shadow's
* next object has lost a shadow. There may be other links to both. But
* when the shadow has dropped its last link, and is going to be deleted,
* it is then true that the shadow is lost by the next object.
*/ */
int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link) int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link)
{ {
@@ -316,66 +338,76 @@ int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link)
/* Drop the link */ /* Drop the link */
obj = vma_drop_link(link); obj = vma_drop_link(link);
/* /* If there is an object in front, this is a shadow drop */
* If there was an object in front, that implies it was
* a shadow. Current object has lost it, so deduce it.
*/
if (prev) { if (prev) {
BUG_ON(!(prev->obj->flags & VM_OBJ_SHADOW)); BUG_ON(!(prev->obj->flags & VM_OBJ_SHADOW));
BUG_ON(!(prev->obj->flags & VM_WRITE));
BUG_ON(--obj->shadows < 0); BUG_ON(--obj->shadows < 0);
list_del_init(&prev->obj->shref); vm_object_print(obj);
}
/* /* Remove prev from current object's shadow list */
* If there was an object after, that implies current object BUG_ON(list_empty(&prev->obj->shref));
* is a shadow, deduce it from the object after. list_del_init(&prev->obj->shref);
*/
if (next && (obj->flags & VM_OBJ_SHADOW)) {
BUG_ON(obj->orig_obj != next->obj);
BUG_ON(--next->obj->shadows < 0);
list_del_init(&obj->shref);
/* /*
* Furthermore, if there was an object in front, * We don't allow dropping non-shadow objects yet,
* that means front will become a shadow of after. * (see ...is_droppable) so there must be a next.
*/ */
if (prev) { BUG_ON(!next);
list_add(&prev->obj->shref,
&next->obj->shdw_list); /* prev is now shadow of next */
prev->obj->orig_obj = next->obj; list_add(&prev->obj->shref,
&next->obj->shdw_list);
prev->obj->orig_obj = next->obj;
/*
* No referrers left, meaning this object is not
* shadowing its original object anymore.
*/
if (obj->nlinks == 0) {
BUG_ON(obj->orig_obj != next->obj);
list_del_init(&obj->shref);
} else {
/*
* Dropped object still has referrers, which
* means next has gained a new shadow.
* Here's why:
*
* T1 and T2: T2: drop-
* prev->drop->next \
* became: T1: prev--- next
*
* Now we have both prev and current object
* in next's shadow list.
*/
next->obj->shadows++; next->obj->shadows++;
} }
/* It's an exit, we check if there's a shadow loss */
} else {
if (obj->nlinks == 0) {
/* Is it a shadow delete? Sort out next */
if (next && obj->flags & VM_OBJ_SHADOW) {
BUG_ON(obj->orig_obj != next->obj);
BUG_ON(--next->obj->shadows < 0);
vm_object_print(next->obj);
list_del_init(&obj->shref);
}
}
} }
/* /* Now deal with the object itself */
* Now deal with the object itself: if (vm_object_is_deletable(obj)) {
*/
if(vm_object_is_deletable(obj)) {
dprintf("Deleting object:\n"); dprintf("Deleting object:\n");
// vm_object_print(obj); // vm_object_print(obj);
vm_object_delete(obj); vm_object_delete(obj);
} } else if ((obj->flags & VM_OBJ_SHADOW) &&
obj->nlinks == 1 && obj->shadows == 1) {
/*
* Only one link and one shadow left.
* Merge it with its only shadow.
*
* FIXME: Currently this is an optimisation that needs to go
* away when swapping is available. We have this solely because
* currently a shadow needs to identically mirror the whole
* object underneath, in order to drop it. A file that is 1MB
* long would spend 2MB until dropped. When swapping is available,
* we will go back to identical mirroring instead of merging the
* last shadow, since most unused pages would be swapped out.
*/
if ((obj->flags & VM_OBJ_SHADOW) &&
obj->nlinks == 1 &&
obj->shadows == 1) {
dprintf("Merging object:\n"); dprintf("Merging object:\n");
// vm_object_print(obj); // vm_object_print(obj);
vma_merge_object(obj); vma_merge_object(obj);
} }
mm0_test_global_vm_integrity();
return 0; return 0;
} }
@@ -395,8 +427,8 @@ int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link)
* *
* Sobj Sobj Sobj Fobj * Sobj Sobj Sobj Fobj
* *
* Sobj Sobj * Sobj Sobj Sobj
* l l l l l l T * l l l l l l l T
* *
* l l l l l l l T * l l l l l l l T
* Sobj * Sobj
@@ -439,7 +471,6 @@ int vma_drop_merge_delete_all_old(struct vm_area *vma)
return 0; return 0;
} }
/* 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.
@@ -486,7 +517,8 @@ struct page *copy_on_write(struct fault_data *fault)
shadow->flags = VM_OBJ_SHADOW | VM_WRITE; shadow->flags = VM_OBJ_SHADOW | VM_WRITE;
shadow->pager = &swap_pager; shadow->pager = &swap_pager;
vmo_link->obj->shadows++; vmo_link->obj->shadows++;
printf("%s: ", __FUNCTION__);
vm_object_print(vmo_link->obj);
dprintf("%s: Created a shadow:\n", __TASKNAME__); dprintf("%s: Created a shadow:\n", __TASKNAME__);
// vm_object_print(shadow); // vm_object_print(shadow);
dprintf("%s: Original object:\n", __TASKNAME__); dprintf("%s: Original object:\n", __TASKNAME__);
@@ -506,7 +538,7 @@ struct page *copy_on_write(struct fault_data *fault)
list_add(&shadow->shref, &shadow->orig_obj->shdw_list); list_add(&shadow->shref, &shadow->orig_obj->shdw_list);
/* Add to global object list */ /* Add to global object list */
list_add(&shadow->list, &vm_object_list); global_add_vm_object(shadow);
} else { } else {
dprintf("No new shadows. Going to add to " dprintf("No new shadows. Going to add to "
@@ -555,6 +587,8 @@ struct page *copy_on_write(struct fault_data *fault)
insert_page_olist(new_page, new_page->owner); insert_page_olist(new_page, new_page->owner);
new_page->owner->npages++; new_page->owner->npages++;
mm0_test_global_vm_integrity();
/* Shared faults don't have shadows so we don't look for collapses */ /* Shared faults don't have shadows so we don't look for collapses */
if (!(vma->flags & VMA_SHARED)) { if (!(vma->flags & VMA_SHARED)) {

View File

@@ -13,12 +13,9 @@
#include <l4/api/kip.h> #include <l4/api/kip.h>
#include <posix/sys/types.h> #include <posix/sys/types.h>
#include <string.h> #include <string.h>
#include <globals.h>
#include <file.h> #include <file.h>
/* List of all generic files */
LIST_HEAD(vm_file_list);
/* Copy from one page's buffer into another page */ /* Copy from one page's buffer into another page */
int page_copy(struct page *dst, struct page *src, int page_copy(struct page *dst, struct page *src,
unsigned long dst_offset, unsigned long src_offset, unsigned long dst_offset, unsigned long src_offset,
@@ -134,7 +131,7 @@ int do_open(struct tcb *task, int fd, unsigned long vnum, unsigned long length)
task->files->fd[fd].cursor = 0; task->files->fd[fd].cursor = 0;
/* Check if that vm_file is already in the list */ /* Check if that vm_file is already in the list */
list_for_each_entry(vmfile, &vm_file_list, list) { list_for_each_entry(vmfile, &global_vm_files.list, list) {
/* Check whether it is a vfs file and if so vnums match. */ /* Check whether it is a vfs file and if so vnums match. */
if ((vmfile->type & VM_FILE_VFS) && if ((vmfile->type & VM_FILE_VFS) &&
@@ -159,10 +156,7 @@ int do_open(struct tcb *task, int fd, unsigned long vnum, unsigned long length)
vmfile->openers++; vmfile->openers++;
/* Add to file list */ /* Add to file list */
list_add(&vmfile->list, &vm_file_list); global_add_vm_file(vmfile);
/* Add to object list */
list_add(&vmfile->vm_obj.list, &vm_object_list);
return 0; return 0;
} }

View File

@@ -16,6 +16,7 @@
#include <file.h> #include <file.h>
#include <init.h> #include <init.h>
#include <utcb.h> #include <utcb.h>
#include <test.h>
/* A separate list than the generic file list that keeps just the boot files */ /* A separate list than the generic file list that keeps just the boot files */
LIST_HEAD(boot_file_list); LIST_HEAD(boot_file_list);
@@ -50,13 +51,10 @@ int mm0_task_init(struct vm_file *f, unsigned long task_start,
return err; return err;
/* Add the task to the global task list */ /* Add the task to the global task list */
task_add_global(task); global_add_task(task);
/* Add the file to global vm lists */ /* Add the file to global vm lists */
list_del_init(&f->list); global_add_vm_file(f);
list_del_init(&f->vm_obj.list);
list_add(&f->list, &vm_file_list);
list_add(&f->vm_obj.list, &vm_object_list);
return 0; return 0;
} }
@@ -78,13 +76,14 @@ struct vm_file *initdata_next_bootfile(struct initdata *initdata)
*/ */
int start_boot_tasks(struct initdata *initdata) int start_boot_tasks(struct initdata *initdata)
{ {
struct vm_file *file = 0, *fs0 = 0, *mm0 = 0, *n; struct vm_file *file = 0, *fs0_file = 0, *mm0_file = 0, *n;
struct tcb *fs0_task;
struct svc_image *img; struct svc_image *img;
struct task_ids ids; struct task_ids ids;
struct list_head files; struct list_head other_files;
int total = 0; int total = 0;
INIT_LIST_HEAD(&files); INIT_LIST_HEAD(&other_files);
/* Separate out special server tasks and regular files */ /* Separate out special server tasks and regular files */
do { do {
@@ -94,11 +93,11 @@ int start_boot_tasks(struct initdata *initdata)
BUG_ON(file->type != VM_FILE_BOOTFILE); BUG_ON(file->type != VM_FILE_BOOTFILE);
img = file->priv_data; img = file->priv_data;
if (!strcmp(img->name, __PAGERNAME__)) if (!strcmp(img->name, __PAGERNAME__))
mm0 = file; mm0_file = file;
else if (!strcmp(img->name, __VFSNAME__)) else if (!strcmp(img->name, __VFSNAME__))
fs0 = file; fs0_file = file;
else else
list_add(&file->list, &files); list_add(&file->list, &other_files);
} else } else
break; break;
} while (1); } while (1);
@@ -109,7 +108,7 @@ int start_boot_tasks(struct initdata *initdata)
ids.spid = PAGER_TID; ids.spid = PAGER_TID;
ids.tgid = PAGER_TID; ids.tgid = PAGER_TID;
if (mm0_task_init(mm0, INITTASK_AREA_START, INITTASK_AREA_END, &ids) < 0) if (mm0_task_init(mm0_file, INITTASK_AREA_START, INITTASK_AREA_END, &ids) < 0)
BUG(); BUG();
total++; total++;
@@ -119,18 +118,17 @@ int start_boot_tasks(struct initdata *initdata)
ids.tgid = VFS_TID; ids.tgid = VFS_TID;
printf("%s: Initialising fs0\n",__TASKNAME__); printf("%s: Initialising fs0\n",__TASKNAME__);
if (task_exec(fs0, USER_AREA_START, USER_AREA_END, &ids) < 0) BUG_ON((IS_ERR(fs0_task = task_exec(fs0_file, USER_AREA_START, USER_AREA_END, &ids))));
BUG();
total++; total++;
/* Initialise other tasks */ /* Initialise other tasks */
list_for_each_entry_safe(file, n, &files, list) { list_for_each_entry_safe(file, n, &other_files, list) {
printf("%s: Initialising new boot task.\n", __TASKNAME__); printf("%s: Initialising new boot task.\n", __TASKNAME__);
ids.tid = TASK_ID_INVALID; ids.tid = TASK_ID_INVALID;
ids.spid = TASK_ID_INVALID; ids.spid = TASK_ID_INVALID;
ids.tgid = TASK_ID_INVALID; ids.tgid = TASK_ID_INVALID;
if (task_exec(file, USER_AREA_START, USER_AREA_END, &ids) < 0) list_del_init(&file->list);
BUG(); BUG_ON(IS_ERR(task_exec(file, USER_AREA_START, USER_AREA_END, &ids)));
total++; total++;
} }
@@ -189,6 +187,7 @@ void initialise(void)
start_boot_tasks(&initdata); start_boot_tasks(&initdata);
mm0_test_global_vm_integrity();
printf("%s: Initialised the memory/process manager.\n", __TASKNAME__); printf("%s: Initialised the memory/process manager.\n", __TASKNAME__);
} }

View File

@@ -9,6 +9,7 @@
#include <mm/alloc_page.h> #include <mm/alloc_page.h>
#include <vm_area.h> #include <vm_area.h>
#include <string.h> #include <string.h>
#include <globals.h>
#include <file.h> #include <file.h>
#include <init.h> #include <init.h>
#include INC_ARCH(bootdesc.h) #include INC_ARCH(bootdesc.h)
@@ -295,9 +296,6 @@ int init_boot_files(struct initdata *initdata)
boot_file->vm_obj.flags = VM_OBJ_FILE; boot_file->vm_obj.flags = VM_OBJ_FILE;
boot_file->vm_obj.pager = &bootfile_pager; boot_file->vm_obj.pager = &bootfile_pager;
/* Add the object to global vm_object list */
list_add(&boot_file->vm_obj.list, &vm_object_list);
/* Add the file to initdata's bootfile list */ /* Add the file to initdata's bootfile list */
list_add_tail(&boot_file->list, &initdata->boot_file_list); list_add_tail(&boot_file->list, &initdata->boot_file_list);
} }
@@ -332,7 +330,7 @@ struct vm_file *get_devzero(void)
{ {
struct vm_file *f; struct vm_file *f;
list_for_each_entry(f, &vm_file_list, list) list_for_each_entry(f, &global_vm_files.list, list)
if (f->type == VM_FILE_DEVZERO) if (f->type == VM_FILE_DEVZERO)
return f; return f;
return 0; return 0;
@@ -364,8 +362,7 @@ int init_devzero(void)
zpage->refcnt++; zpage->refcnt++;
zpage->owner = &devzero->vm_obj; zpage->owner = &devzero->vm_obj;
list_add(&devzero->vm_obj.list, &vm_object_list); global_add_vm_file(devzero);
list_add(&devzero->list, &vm_file_list);
return 0; return 0;
} }

View File

@@ -9,6 +9,7 @@
#include <mmap.h> #include <mmap.h>
#include <utcb.h> #include <utcb.h>
#include <vm_area.h> #include <vm_area.h>
#include <globals.h>
#include <kmalloc/kmalloc.h> #include <kmalloc/kmalloc.h>
#include <l4lib/arch/syscalls.h> #include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h> #include <l4lib/arch/syslib.h>
@@ -28,9 +29,6 @@
#define shm_file_to_desc(shm_file) \ #define shm_file_to_desc(shm_file) \
((struct shm_descriptor *)shm_file->priv_data) ((struct shm_descriptor *)shm_file->priv_data)
/* The list of shared memory areas that are already set up and working */
static LIST_HEAD(shm_file_list);
/* Unique shared memory ids */ /* Unique shared memory ids */
static struct id_pool *shm_ids; static struct id_pool *shm_ids;
@@ -133,8 +131,9 @@ void *sys_shmat(struct tcb *task, l4id_t shmid, void *shmaddr, int shmflg)
{ {
struct vm_file *shm_file, *n; struct vm_file *shm_file, *n;
list_for_each_entry_safe(shm_file, n, &shm_file_list, list) { list_for_each_entry_safe(shm_file, n, &global_vm_files.list, list) {
if (shm_file_to_desc(shm_file)->shmid == shmid) if (shm_file->type == VM_FILE_SHM &&
shm_file_to_desc(shm_file)->shmid == shmid)
return do_shmat(shm_file, shmaddr, return do_shmat(shm_file, shmaddr,
shmflg, task); shmflg, task);
} }
@@ -159,8 +158,9 @@ int sys_shmdt(struct tcb *task, const void *shmaddr)
struct vm_file *shm_file, *n; struct vm_file *shm_file, *n;
int err; int err;
list_for_each_entry_safe(shm_file, n, &shm_file_list, list) { list_for_each_entry_safe(shm_file, n, &global_vm_files.list, list) {
if (shm_file_to_desc(shm_file)->shm_addr == shmaddr) { if (shm_file->type == VM_FILE_SHM &&
shm_file_to_desc(shm_file)->shm_addr == shmaddr) {
if ((err = do_shmdt(task, shm_file) < 0)) if ((err = do_shmdt(task, shm_file) < 0))
return err; return err;
else else
@@ -235,8 +235,7 @@ struct vm_file *shm_new(key_t key, unsigned long npages)
shm_file->vm_obj.flags = VM_OBJ_FILE | VM_WRITE; shm_file->vm_obj.flags = VM_OBJ_FILE | VM_WRITE;
/* Add to shm file and global object list */ /* Add to shm file and global object list */
list_add(&shm_file->list, &shm_file_list); global_add_vm_file(shm_file);
list_add(&shm_file->vm_obj.list, &vm_object_list);
return shm_file; return shm_file;
} }
@@ -250,12 +249,14 @@ void *shmat_shmget_internal(struct tcb *task, key_t key, void *shmaddr)
struct vm_file *shm_file; struct vm_file *shm_file;
struct shm_descriptor *shm_desc; struct shm_descriptor *shm_desc;
list_for_each_entry(shm_file, &shm_file_list, list) { list_for_each_entry(shm_file, &global_vm_files.list, list) {
shm_desc = shm_file_to_desc(shm_file); if(shm_file->type == VM_FILE_SHM) {
/* Found the key, shmat that area */ shm_desc = shm_file_to_desc(shm_file);
if (shm_desc->key == key) /* Found the key, shmat that area */
return do_shmat(shm_file, shmaddr, if (shm_desc->key == key)
0, task); return do_shmat(shm_file, shmaddr,
0, task);
}
} }
return PTR_ERR(-EEXIST); return PTR_ERR(-EEXIST);
@@ -268,6 +269,7 @@ void *shmat_shmget_internal(struct tcb *task, key_t key, void *shmaddr)
int sys_shmget(key_t key, int size, int shmflg) int sys_shmget(key_t key, int size, int shmflg)
{ {
unsigned long npages = __pfn(page_align_up(size)); unsigned long npages = __pfn(page_align_up(size));
struct shm_descriptor *shm_desc;
struct vm_file *shm; struct vm_file *shm;
/* First check argument validity */ /* First check argument validity */
@@ -286,8 +288,11 @@ int sys_shmget(key_t key, int size, int shmflg)
return shm_file_to_desc(shm)->shmid; return shm_file_to_desc(shm)->shmid;
} }
list_for_each_entry(shm, &shm_file_list, list) { list_for_each_entry(shm, &global_vm_files.list, list) {
struct shm_descriptor *shm_desc = shm_file_to_desc(shm); if (shm->type != VM_FILE_SHM)
continue;
shm_desc = shm_file_to_desc(shm);
if (shm_desc->key == key) { if (shm_desc->key == key) {
/* /*

View File

@@ -27,34 +27,40 @@
#include <task.h> #include <task.h>
#include <shm.h> #include <shm.h>
#include <mmap.h> #include <mmap.h>
#include <globals.h>
struct tcb_head { struct global_list global_tasks = {
struct list_head list; .list = { &global_tasks.list, &global_tasks.list },
int total; /* Total threads */ .total = 0,
} tcb_head = {
.list = { &tcb_head.list, &tcb_head.list },
}; };
void print_tasks(void) void print_tasks(void)
{ {
struct tcb *task; struct tcb *task;
printf("Tasks:\n========\n"); printf("Tasks:\n========\n");
list_for_each_entry(task, &tcb_head.list, list) { list_for_each_entry(task, &global_tasks.list, list) {
printf("Task tid: %d, spid: %d\n", task->tid, task->spid); printf("Task tid: %d, spid: %d\n", task->tid, task->spid);
} }
} }
void task_add_global(struct tcb *task) void global_add_task(struct tcb *task)
{ {
list_add_tail(&task->list, &tcb_head.list); BUG_ON(!list_empty(&task->list));
tcb_head.total++; list_add_tail(&task->list, &global_tasks.list);
global_tasks.total++;
}
void global_remove_task(struct tcb *task)
{
BUG_ON(list_empty(&task->list));
list_del_init(&task->list);
BUG_ON(--global_tasks.total < 0);
} }
struct tcb *find_task(int tid) struct tcb *find_task(int tid)
{ {
struct tcb *t; struct tcb *t;
list_for_each_entry(t, &tcb_head.list, list) { list_for_each_entry(t, &global_tasks.list, list) {
/* A temporary precaution */ /* A temporary precaution */
BUG_ON(t->tid != t->spid); BUG_ON(t->tid != t->spid);
if (t->tid == tid) { if (t->tid == tid) {
@@ -107,8 +113,7 @@ struct tcb *tcb_alloc_init(unsigned int flags)
/* NOTE: We may need to delete shared tcb parts here as well. */ /* NOTE: We may need to delete shared tcb parts here as well. */
int tcb_destroy(struct tcb *task) int tcb_destroy(struct tcb *task)
{ {
list_del(&task->list); global_remove_task(task);
tcb_head.total--;
kfree(task); kfree(task);
@@ -402,43 +407,41 @@ int task_prefault_regions(struct tcb *task, struct vm_file *f)
* Main entry point for the creation, initialisation and * Main entry point for the creation, initialisation and
* execution of a new task. * execution of a new task.
*/ */
int task_exec(struct vm_file *f, unsigned long task_region_start, struct tcb *task_exec(struct vm_file *f, unsigned long task_region_start,
unsigned long task_region_end, struct task_ids *ids) unsigned long task_region_end, struct task_ids *ids)
{ {
struct tcb *task; struct tcb *task;
int err; int err;
if (IS_ERR(task = task_create(0, ids, THREAD_NEW_SPACE, if (IS_ERR(task = task_create(0, ids, THREAD_NEW_SPACE,
TCB_NO_SHARING))) TCB_NO_SHARING)))
return (int)task; return task;
if ((err = task_setup_regions(f, task, task_region_start, if ((err = task_setup_regions(f, task, task_region_start,
task_region_end)) < 0) task_region_end)) < 0)
return err; return PTR_ERR(err);
if ((err = task_mmap_regions(task, f)) < 0) if ((err = task_mmap_regions(task, f)) < 0)
return err; return PTR_ERR(err);
if (ids->tid == VFS_TID)
if ((err = task_prefault_regions(task, f)) < 0)
return err;
if ((err = task_setup_registers(task, 0, 0, 0)) < 0) if ((err = task_setup_registers(task, 0, 0, 0)) < 0)
return err; return PTR_ERR(err);
/* Add the task to the global task list */ /* Add the task to the global task list */
task_add_global(task); global_add_task(task);
/* Add the file to global vm lists */ /* Add the file to global vm lists */
list_del_init(&f->list); global_add_vm_file(f);
list_del_init(&f->vm_obj.list);
list_add(&f->list, &vm_file_list);
list_add(&f->vm_obj.list, &vm_object_list);
/* Prefault all its regions */
if (ids->tid == VFS_TID)
task_prefault_regions(task, f);
/* Start the task */
if ((err = task_start(task, ids)) < 0) if ((err = task_start(task, ids)) < 0)
return err; return PTR_ERR(err);
return 0; return task;
} }
/* Maps and prefaults the utcb of a task into another task */ /* Maps and prefaults the utcb of a task into another task */
@@ -495,10 +498,10 @@ int send_task_data(struct tcb *vfs)
tdata_head = (struct task_data_head *)vfs->utcb; tdata_head = (struct task_data_head *)vfs->utcb;
/* First word is total number of tcbs */ /* First word is total number of tcbs */
tdata_head->total = tcb_head.total; tdata_head->total = global_tasks.total;
/* Write per-task data for all tasks */ /* Write per-task data for all tasks */
list_for_each_entry(t, &tcb_head.list, list) { list_for_each_entry(t, &global_tasks.list, list) {
tdata_head->tdata[li].tid = t->tid; tdata_head->tdata[li].tid = t->tid;
tdata_head->tdata[li].utcb_address = (unsigned long)t->utcb; tdata_head->tdata[li].utcb_address = (unsigned long)t->utcb;
li++; li++;

113
tasks/mm0/src/test.c Normal file
View File

@@ -0,0 +1,113 @@
/*
* These functions here do run-time checks on all fields
* of tasks, vmas, and vm objects to see that they
* have expected values.
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <vm_area.h>
#include <mmap.h>
#include <shm.h>
#include <globals.h>
struct vm_statistics {
int tasks;
int vm_objects;
int shadow_objects; /* Shadows counted by hand (well almost!) */
int shadows_referred; /* Shadows that objects say they have */
int file_objects;
int vm_files;
int tasks_total;
};
/* Count links in objects link list, and compare with nlinks */
int vm_object_test_link_count(struct vm_object *vmo)
{
int links = 0;
struct vm_obj_link *l;
list_for_each_entry(l, &vmo->link_list, linkref)
links++;
BUG_ON(links != vmo->nlinks);
return 0;
}
int vm_object_test_shadow_count(struct vm_object *vmo)
{
struct vm_object *sh;
int shadows = 0;
list_for_each_entry(sh, &vmo->shdw_list, shref)
shadows++;
BUG_ON(shadows != vmo->shadows);
return 0;
}
int mm0_test_global_vm_integrity(void)
{
struct tcb *task;
struct vm_object *vmo;
struct vm_statistics vmstat;
struct vm_file *f;
memset(&vmstat, 0, sizeof(vmstat));
/* Count all shadow and file objects */
list_for_each_entry(vmo, &global_vm_objects.list, list) {
vmstat.shadows_referred += vmo->shadows;
if (vmo->flags & VM_OBJ_SHADOW)
vmstat.shadow_objects++;
if (vmo->flags & VM_OBJ_FILE)
vmstat.file_objects++;
vmstat.vm_objects++;
vm_object_test_shadow_count(vmo);
vm_object_test_link_count(vmo);
}
/* Count all registered vmfiles */
list_for_each_entry(f, &global_vm_files.list, list)
vmstat.vm_files++;
if (vmstat.vm_files != global_vm_files.total) {
printf("Total counted files don't match "
"global_vm_files total\n");
BUG();
}
if (vmstat.vm_objects != global_vm_objects.total) {
printf("Total counted vm_objects don't "
"match global_vm_objects total\n");
BUG();
}
/* Total file objects must be equal to total vm files */
if (vmstat.vm_files != vmstat.file_objects) {
printf("\nTotal files don't match total file objects.\n");
printf("vm files:\n");
vm_print_files(&global_vm_files.list);
printf("\nvm objects:\n");
vm_print_objects(&global_vm_objects.list);
printf("\n");
BUG();
}
/* Counted and referred shadows must match */
BUG_ON(vmstat.shadow_objects != vmstat.shadows_referred);
/* Count all tasks */
list_for_each_entry(task, &global_tasks.list, list)
vmstat.tasks++;
if (vmstat.tasks != global_tasks.total) {
printf("Total counted tasks don't match global_tasks total\n");
BUG();
}
return 0;
}

View File

@@ -8,6 +8,52 @@
#include <l4/macros.h> #include <l4/macros.h>
#include <l4/api/errno.h> #include <l4/api/errno.h>
#include <kmalloc/kmalloc.h> #include <kmalloc/kmalloc.h>
#include <globals.h>
/* Global list of all in-memory files on the system */
struct global_list global_vm_files = {
.list = { &global_vm_files.list, &global_vm_files.list },
.total = 0,
};
/* Global list of in-memory vm objects in the system */
struct global_list global_vm_objects = {
.list = { &global_vm_objects.list, &global_vm_objects.list },
.total = 0,
};
void global_add_vm_object(struct vm_object *obj)
{
BUG_ON(!list_empty(&obj->list));
list_add(&obj->list, &global_vm_objects.list);
global_vm_objects.total++;
}
void global_remove_vm_object(struct vm_object *obj)
{
BUG_ON(list_empty(&obj->list));
list_del_init(&obj->list);
BUG_ON(--global_vm_objects.total < 0);
}
void global_add_vm_file(struct vm_file *f)
{
BUG_ON(!list_empty(&f->list));
list_add(&f->list, &global_vm_files.list);
global_vm_files.total++;
global_add_vm_object(&f->vm_obj);
}
void global_remove_vm_file(struct vm_file *f)
{
BUG_ON(list_empty(&f->list));
list_del_init(&f->list);
BUG_ON(--global_vm_files.total < 0);
global_remove_vm_object(&f->vm_obj);
}
void print_cache_pages(struct vm_object *vmo) void print_cache_pages(struct vm_object *vmo)
{ {
@@ -51,8 +97,21 @@ void vm_object_print(struct vm_object *vmo)
// printf("\n"); // printf("\n");
} }
/* Global list of in-memory vm objects. */ void vm_print_files(struct list_head *files)
LIST_HEAD(vm_object_list); {
struct vm_file *f;
list_for_each_entry(f, files, list)
vm_object_print(&f->vm_obj);
}
void vm_print_objects(struct list_head *objects)
{
struct vm_object *vmo;
list_for_each_entry(vmo, objects, list)
vm_object_print(vmo);
}
struct vm_object *vm_object_init(struct vm_object *obj) struct vm_object *vm_object_init(struct vm_object *obj)
{ {
@@ -118,7 +177,11 @@ int vm_object_delete(struct vm_object *vmo)
vmo->pager->ops.release_pages(vmo); vmo->pager->ops.release_pages(vmo);
/* Remove from global list */ /* Remove from global list */
list_del(&vmo->list); if (vmo->flags & VM_OBJ_FILE)
global_remove_vm_file(vm_object_to_file(vmo));
else if (vmo->flags & VM_OBJ_SHADOW)
global_remove_vm_object(vmo);
else BUG();
/* Check any references */ /* Check any references */
BUG_ON(vmo->nlinks); BUG_ON(vmo->nlinks);
@@ -126,6 +189,7 @@ int vm_object_delete(struct vm_object *vmo)
BUG_ON(!list_empty(&vmo->shdw_list)); BUG_ON(!list_empty(&vmo->shdw_list));
BUG_ON(!list_empty(&vmo->link_list)); BUG_ON(!list_empty(&vmo->link_list));
BUG_ON(!list_empty(&vmo->page_cache)); BUG_ON(!list_empty(&vmo->page_cache));
BUG_ON(!list_empty(&vmo->shref));
/* Obtain and free via the base object */ /* Obtain and free via the base object */
if (vmo->flags & VM_OBJ_FILE) { if (vmo->flags & VM_OBJ_FILE) {
@@ -147,9 +211,6 @@ int vm_object_delete(struct vm_object *vmo)
int vm_file_delete(struct vm_file *f) int vm_file_delete(struct vm_file *f)
{ {
/* Delete it from global file list */
list_del_init(&f->list);
/* Delete file via base object */ /* Delete file via base object */
return vm_object_delete(&f->vm_obj); return vm_object_delete(&f->vm_obj);
} }