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 tcb_head {
struct list_head list;
int total; /* Total threads */
};
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);
void task_map_prefault_utcb(struct tcb *mapper, struct tcb *owner);
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);
struct tcb *tcb_alloc_init(unsigned int flags);
int tcb_destroy(struct tcb *task);
int task_exec(struct vm_file *f, unsigned long task_region_start,
unsigned long task_region_end, struct task_ids *ids);
struct tcb *task_exec(struct vm_file *f, unsigned long task_region_start,
unsigned long task_region_end, 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 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_object_delete(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 */
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_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__ */

View File

@@ -100,7 +100,7 @@ int sys_fork(struct tcb *parent)
vfs_notify_fork(child, parent);
/* Add child to global task list */
task_add_global(child);
global_add_task(child);
/* Start forked child. */
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);
/* Add child to global task list */
task_add_global(child);
global_add_task(child);
/* Start forked child. */
printf("%s/%s: Starting forked child.\n", __TASKNAME__, __FUNCTION__);

View File

@@ -18,6 +18,8 @@
#include <memory.h>
#include <shm.h>
#include <file.h>
#include <test.h>
/* 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)
@@ -117,6 +119,20 @@ static inline int vm_object_is_droppable(struct vm_object *shadow,
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.
* 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));
/* 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 */
list_add(&front->shref, &redundant->orig_obj->shdw_list);
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,
struct vm_obj_link, linkref);
@@ -264,13 +280,14 @@ int vm_object_is_deletable(struct vm_object *obj)
{
struct vm_file *f;
printf("%s: Checking: ", __FUNCTION__);
vm_object_print(obj);
//printf("%s: Checking: ", __FUNCTION__);
//vm_object_print(obj);
if (obj->nlinks != 0)
return 0;
BUG_ON(obj->shadows != 0);
BUG_ON(!list_empty(&obj->shref));
if (obj->flags & VM_OBJ_SHADOW)
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,
* decides and takes action on the dropped object, depending on
* 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.
* exit has: !prev, next || !next
* shadow drop has: prev, next
*/
/*
* 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)
{
@@ -316,66 +338,76 @@ int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link)
/* Drop the link */
obj = vma_drop_link(link);
/*
* If there was an object in front, that implies it was
* a shadow. Current object has lost it, so deduce it.
*/
/* If there is an object in front, this is a shadow drop */
if (prev) {
BUG_ON(!(prev->obj->flags & VM_OBJ_SHADOW));
BUG_ON(!(prev->obj->flags & VM_WRITE));
BUG_ON(--obj->shadows < 0);
list_del_init(&prev->obj->shref);
}
vm_object_print(obj);
/*
* If there was an object after, that implies current object
* is a shadow, deduce it from the object after.
*/
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);
/* Remove prev from current object's shadow list */
BUG_ON(list_empty(&prev->obj->shref));
list_del_init(&prev->obj->shref);
/*
* Furthermore, if there was an object in front,
* that means front will become a shadow of after.
* We don't allow dropping non-shadow objects yet,
* (see ...is_droppable) so there must be a next.
*/
if (prev) {
list_add(&prev->obj->shref,
&next->obj->shdw_list);
prev->obj->orig_obj = next->obj;
BUG_ON(!next);
/* prev is now shadow of next */
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++;
}
/* 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:
*/
if(vm_object_is_deletable(obj)) {
/* Now deal with the object itself */
if (vm_object_is_deletable(obj)) {
dprintf("Deleting object:\n");
// vm_object_print(obj);
vm_object_delete(obj);
}
/*
* 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) {
} else if ((obj->flags & VM_OBJ_SHADOW) &&
obj->nlinks == 1 && obj->shadows == 1) {
dprintf("Merging object:\n");
// vm_object_print(obj);
vma_merge_object(obj);
}
mm0_test_global_vm_integrity();
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
* l l l l l l T
* Sobj Sobj Sobj
* l l l l l l l T
*
* l l l l l l l T
* Sobj
@@ -439,7 +471,6 @@ int vma_drop_merge_delete_all_old(struct vm_area *vma)
return 0;
}
/* TODO:
* - Why not allocate a swap descriptor in vma_create_shadow() rather than
* 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->pager = &swap_pager;
vmo_link->obj->shadows++;
printf("%s: ", __FUNCTION__);
vm_object_print(vmo_link->obj);
dprintf("%s: Created a shadow:\n", __TASKNAME__);
// vm_object_print(shadow);
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);
/* Add to global object list */
list_add(&shadow->list, &vm_object_list);
global_add_vm_object(shadow);
} else {
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);
new_page->owner->npages++;
mm0_test_global_vm_integrity();
/* Shared faults don't have shadows so we don't look for collapses */
if (!(vma->flags & VMA_SHARED)) {

View File

@@ -13,12 +13,9 @@
#include <l4/api/kip.h>
#include <posix/sys/types.h>
#include <string.h>
#include <globals.h>
#include <file.h>
/* List of all generic files */
LIST_HEAD(vm_file_list);
/* Copy from one page's buffer into another page */
int page_copy(struct page *dst, struct page *src,
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;
/* 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. */
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++;
/* Add to file list */
list_add(&vmfile->list, &vm_file_list);
/* Add to object list */
list_add(&vmfile->vm_obj.list, &vm_object_list);
global_add_vm_file(vmfile);
return 0;
}

View File

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

View File

@@ -9,6 +9,7 @@
#include <mm/alloc_page.h>
#include <vm_area.h>
#include <string.h>
#include <globals.h>
#include <file.h>
#include <init.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.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 */
list_add_tail(&boot_file->list, &initdata->boot_file_list);
}
@@ -332,7 +330,7 @@ struct vm_file *get_devzero(void)
{
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)
return f;
return 0;
@@ -364,8 +362,7 @@ int init_devzero(void)
zpage->refcnt++;
zpage->owner = &devzero->vm_obj;
list_add(&devzero->vm_obj.list, &vm_object_list);
list_add(&devzero->list, &vm_file_list);
global_add_vm_file(devzero);
return 0;
}

View File

@@ -9,6 +9,7 @@
#include <mmap.h>
#include <utcb.h>
#include <vm_area.h>
#include <globals.h>
#include <kmalloc/kmalloc.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h>
@@ -28,9 +29,6 @@
#define shm_file_to_desc(shm_file) \
((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 */
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;
list_for_each_entry_safe(shm_file, n, &shm_file_list, list) {
if (shm_file_to_desc(shm_file)->shmid == shmid)
list_for_each_entry_safe(shm_file, n, &global_vm_files.list, list) {
if (shm_file->type == VM_FILE_SHM &&
shm_file_to_desc(shm_file)->shmid == shmid)
return do_shmat(shm_file, shmaddr,
shmflg, task);
}
@@ -159,8 +158,9 @@ int sys_shmdt(struct tcb *task, const void *shmaddr)
struct vm_file *shm_file, *n;
int err;
list_for_each_entry_safe(shm_file, n, &shm_file_list, list) {
if (shm_file_to_desc(shm_file)->shm_addr == shmaddr) {
list_for_each_entry_safe(shm_file, n, &global_vm_files.list, list) {
if (shm_file->type == VM_FILE_SHM &&
shm_file_to_desc(shm_file)->shm_addr == shmaddr) {
if ((err = do_shmdt(task, shm_file) < 0))
return err;
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;
/* Add to shm file and global object list */
list_add(&shm_file->list, &shm_file_list);
list_add(&shm_file->vm_obj.list, &vm_object_list);
global_add_vm_file(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 shm_descriptor *shm_desc;
list_for_each_entry(shm_file, &shm_file_list, list) {
shm_desc = shm_file_to_desc(shm_file);
/* Found the key, shmat that area */
if (shm_desc->key == key)
return do_shmat(shm_file, shmaddr,
0, task);
list_for_each_entry(shm_file, &global_vm_files.list, list) {
if(shm_file->type == VM_FILE_SHM) {
shm_desc = shm_file_to_desc(shm_file);
/* Found the key, shmat that area */
if (shm_desc->key == key)
return do_shmat(shm_file, shmaddr,
0, task);
}
}
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)
{
unsigned long npages = __pfn(page_align_up(size));
struct shm_descriptor *shm_desc;
struct vm_file *shm;
/* 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;
}
list_for_each_entry(shm, &shm_file_list, list) {
struct shm_descriptor *shm_desc = shm_file_to_desc(shm);
list_for_each_entry(shm, &global_vm_files.list, list) {
if (shm->type != VM_FILE_SHM)
continue;
shm_desc = shm_file_to_desc(shm);
if (shm_desc->key == key) {
/*

View File

@@ -27,34 +27,40 @@
#include <task.h>
#include <shm.h>
#include <mmap.h>
#include <globals.h>
struct tcb_head {
struct list_head list;
int total; /* Total threads */
} tcb_head = {
.list = { &tcb_head.list, &tcb_head.list },
struct global_list global_tasks = {
.list = { &global_tasks.list, &global_tasks.list },
.total = 0,
};
void print_tasks(void)
{
struct tcb *task;
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);
}
}
void task_add_global(struct tcb *task)
void global_add_task(struct tcb *task)
{
list_add_tail(&task->list, &tcb_head.list);
tcb_head.total++;
BUG_ON(!list_empty(&task->list));
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 *t;
list_for_each_entry(t, &tcb_head.list, list) {
list_for_each_entry(t, &global_tasks.list, list) {
/* A temporary precaution */
BUG_ON(t->tid != t->spid);
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. */
int tcb_destroy(struct tcb *task)
{
list_del(&task->list);
tcb_head.total--;
global_remove_task(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
* execution of a new task.
*/
int task_exec(struct vm_file *f, unsigned long task_region_start,
unsigned long task_region_end, struct task_ids *ids)
struct tcb *task_exec(struct vm_file *f, unsigned long task_region_start,
unsigned long task_region_end, struct task_ids *ids)
{
struct tcb *task;
int err;
if (IS_ERR(task = task_create(0, ids, THREAD_NEW_SPACE,
TCB_NO_SHARING)))
return (int)task;
return task;
if ((err = task_setup_regions(f, task, task_region_start,
task_region_end)) < 0)
return err;
return PTR_ERR(err);
if ((err = task_mmap_regions(task, f)) < 0)
return err;
if (ids->tid == VFS_TID)
if ((err = task_prefault_regions(task, f)) < 0)
return err;
return PTR_ERR(err);
if ((err = task_setup_registers(task, 0, 0, 0)) < 0)
return err;
return PTR_ERR(err);
/* Add the task to the global task list */
task_add_global(task);
global_add_task(task);
/* Add the file to global vm lists */
list_del_init(&f->list);
list_del_init(&f->vm_obj.list);
list_add(&f->list, &vm_file_list);
list_add(&f->vm_obj.list, &vm_object_list);
global_add_vm_file(f);
/* Prefault all its regions */
if (ids->tid == VFS_TID)
task_prefault_regions(task, f);
/* Start the task */
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 */
@@ -495,10 +498,10 @@ int send_task_data(struct tcb *vfs)
tdata_head = (struct task_data_head *)vfs->utcb;
/* 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 */
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].utcb_address = (unsigned long)t->utcb;
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/api/errno.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)
{
@@ -51,8 +97,21 @@ void vm_object_print(struct vm_object *vmo)
// printf("\n");
}
/* Global list of in-memory vm objects. */
LIST_HEAD(vm_object_list);
void vm_print_files(struct list_head *files)
{
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)
{
@@ -118,7 +177,11 @@ int vm_object_delete(struct vm_object *vmo)
vmo->pager->ops.release_pages(vmo);
/* 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 */
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->link_list));
BUG_ON(!list_empty(&vmo->page_cache));
BUG_ON(!list_empty(&vmo->shref));
/* Obtain and free via the base object */
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)
{
/* Delete it from global file list */
list_del_init(&f->list);
/* Delete file via base object */
return vm_object_delete(&f->vm_obj);
}