posix: MM0 task page access issues fixed.

This commit is contained in:
Bahadir Balban
2009-11-05 19:04:19 +02:00
parent d306d6b451
commit e28658c10e
11 changed files with 55 additions and 155 deletions

View File

@@ -149,7 +149,6 @@ struct tcb_head {
struct tcb *find_task(int tid);
void global_add_task(struct tcb *task);
void global_remove_task(struct tcb *task);
void task_map_prefault_utcb(struct tcb *mapper, struct tcb *owner);
int task_mmap_segments(struct tcb *task, struct vm_file *file, struct exec_file_desc *efd,
struct args_struct *args, struct args_struct *env);
int task_setup_registers(struct tcb *task, unsigned int pc,
@@ -159,13 +158,11 @@ int tcb_destroy(struct tcb *task);
int task_start(struct tcb *task);
int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags);
int task_release_vmas(struct task_vma_head *vma_head);
int task_prefault_regions(struct tcb *task, struct vm_file *f);
struct tcb *task_create(struct tcb *orig,
struct task_ids *ids,
unsigned int ctrl_flags,
unsigned int alloc_flags);
int prefault_range(struct tcb *task, unsigned long start,
unsigned long end, unsigned int vm_flags);
int task_prefault_range(struct tcb *task, unsigned long start,
unsigned long end, unsigned int vm_flags);
#endif /* __TASK_H__ */

View File

@@ -227,19 +227,13 @@ void vm_print_objects(struct link *vmo_list);
void vm_print_files(struct link *file_list);
/* Used for pre-faulting a page from mm0 */
int prefault_page(struct tcb *task, unsigned long address,
unsigned int vmflags);
struct page *task_prefault_page(struct tcb *task, unsigned long address,
unsigned int vmflags);
struct page *page_init(struct page *page);
struct page *find_page(struct vm_object *vmo, unsigned long page_offset);
void *pager_map_page(struct vm_file *f, unsigned long page_offset);
void pager_unmap_page(void *vaddr);
/* To get currently mapped page of a virtual address on a task */
struct page *task_virt_to_page(struct tcb *t, unsigned long virtual,
unsigned int vm_flags);
int validate_task_range(struct tcb *t, unsigned long start,
unsigned long end, unsigned int vmflags);
/* Changes all shadows and their ptes to read-only */
int vm_freeze_shadows(struct tcb *task);
@@ -247,7 +241,7 @@ int vm_compare_prot_flags(unsigned int current, unsigned int needed);
int task_insert_vma(struct vm_area *vma, struct link *vma_list);
/* Main page fault entry point */
int page_fault_handler(struct tcb *faulty_task, fault_kdata_t *fkdata);
struct page *page_fault_handler(struct tcb *faulty_task, fault_kdata_t *fkdata);
int vma_copy_links(struct vm_area *new_vma, struct vm_area *vma);
int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link);

View File

@@ -78,10 +78,16 @@ void handle_requests(void)
/* This has no receive phase */
return;
case L4_IPC_TAG_PFAULT:
case L4_IPC_TAG_PFAULT: {
struct page *p;
/* Handle page fault. */
ret = page_fault_handler(sender, (fault_kdata_t *)&mr[0]);
if (IS_ERR(p = page_fault_handler(sender, (fault_kdata_t *)&mr[0])))
ret = (int)p;
else
ret = 0;
break;
}
case L4_IPC_TAG_SHMGET: {
ret = sys_shmget((key_t)mr[0], (int)mr[1], (int)mr[2]);

View File

@@ -649,7 +649,7 @@ struct page *copy_on_write(struct fault_data *fault)
* FIXME: Add VM_DIRTY bit for every page that has write-faulted.
*/
int __do_page_fault(struct fault_data *fault)
struct page *__do_page_fault(struct fault_data *fault)
{
unsigned int reason = fault->reason;
unsigned int vma_flags = fault->vma->flags;
@@ -741,7 +741,7 @@ out_success:
page_align(fault->address), fault->task->tid);
// vm_object_print(page->owner);
return 0;
return page;
}
/*
@@ -841,7 +841,7 @@ int vm_freeze_shadows(struct tcb *task)
* - page needs write access:
* action: read the page in, give write access.
*/
int do_page_fault(struct fault_data *fault)
struct page *do_page_fault(struct fault_data *fault)
{
unsigned int vma_flags = (fault->vma) ? fault->vma->flags : VM_NONE;
unsigned int reason = fault->reason;
@@ -869,9 +869,8 @@ int do_page_fault(struct fault_data *fault)
return __do_page_fault(fault);
}
int page_fault_handler(struct tcb *sender, fault_kdata_t *fkdata)
struct page *page_fault_handler(struct tcb *sender, fault_kdata_t *fkdata)
{
int err;
struct fault_data fault = {
/* Fault data from kernel */
.kdata = fkdata,
@@ -888,14 +887,7 @@ int page_fault_handler(struct tcb *sender, fault_kdata_t *fkdata)
"Bad things will happen.\n");
/* Handle the actual fault */
err = do_page_fault(&fault);
/*
* Return the ipc and by doing so restart the faulty thread.
* FIXME: We could kill the thread if there was an error???
* Perhaps via a kill message to kernel?
*/
return err;
return do_page_fault(&fault);
}
int vm_compare_prot_flags(unsigned int current, unsigned int needed)
@@ -914,75 +906,15 @@ int vm_compare_prot_flags(unsigned int current, unsigned int needed)
return 0;
}
/*
* Makes the virtual to page translation for a given user task.
* It traverses the vm_objects and returns the first encountered
* instance of the page. If page is not mapped in the task's address
* space, (not faulted at all), returns error.
*/
struct page *task_virt_to_page(struct tcb *t, unsigned long virtual, unsigned int vm_flags)
{
unsigned long vma_offset;
unsigned long file_offset;
struct vm_obj_link *vmo_link;
struct vm_area *vma;
struct page *page;
/* First find the vma that maps that virtual address */
if (!(vma = find_vma(virtual, &t->vm_area_head->list))) {
//printf("%s: No VMA found for 0x%x on task: %d\n",
// __FUNCTION__, virtual, t->tid);
return PTR_ERR(-EINVAL);
}
/* Find the pfn offset of virtual address in this vma */
BUG_ON(__pfn(virtual) < vma->pfn_start ||
__pfn(virtual) > vma->pfn_end);
vma_offset = __pfn(virtual) - vma->pfn_start;
/* Find the file offset of virtual address in this file */
file_offset = vma->file_offset + vma_offset;
/* Get the first object, either original file or a shadow */
if (!(vmo_link = vma_next_link(&vma->vm_obj_list, &vma->vm_obj_list))) {
printf("%s:%s: No vm object in vma!\n",
__TASKNAME__, __FUNCTION__);
BUG();
}
/* Traverse the list of read-only vm objects and search for the page */
while (IS_ERR(page = vmo_link->obj->pager->ops.page_in(vmo_link->obj,
file_offset))) {
if (!(vmo_link = vma_next_link(&vmo_link->list,
&vma->vm_obj_list))) {
printf("%s:%s: Traversed all shadows and the original "
"file's vm_object, but could not find the "
"page in this vma.\n",__TASKNAME__,
__FUNCTION__);
BUG();
}
}
/* Found one, but does it have the right permissions */
if (!vm_compare_prot_flags(vmo_link->obj->flags, vm_flags))
return PTR_ERR(-EFAULT);
// printf("%s: %s: Found page with file_offset: 0x%x\n",
// __TASKNAME__, __FUNCTION__, page->offset);
// vm_object_print(vmo_link->obj);
return page;
}
/*
* Prefaults the page with given virtual address, to given task
* with given reasons. Multiple reasons are allowed, they are
* handled separately in order.
*/
int prefault_page(struct tcb *task, unsigned long address,
unsigned int vmflags)
struct page *task_prefault_page(struct tcb *task, unsigned long address,
unsigned int vmflags)
{
int err;
struct page *p;
struct fault_data fault = {
.task = task,
.address = address,
@@ -994,30 +926,29 @@ int prefault_page(struct tcb *task, unsigned long address,
/* Find the vma */
if (!(fault.vma = find_vma(fault.address,
&fault.task->vm_area_head->list))) {
err = -EINVAL;
dprintf("%s: Invalid: No vma for given address. %d\n",
__FUNCTION__, err);
return err;
__FUNCTION__, -EINVAL);
return PTR_ERR(-EINVAL);
}
/* Flags may indicate multiple fault reasons. First do the read */
if (vmflags & VM_READ) {
fault.pte_flags = VM_NONE;
fault.reason = VM_READ;
if ((err = do_page_fault(&fault)) < 0)
return err;
if (IS_ERR(p = do_page_fault(&fault)))
return p;
}
/* Now write */
if (vmflags & VM_WRITE) {
fault.pte_flags = VM_READ;
fault.reason = VM_WRITE;
if ((err = do_page_fault(&fault)) < 0)
return err;
if (IS_ERR(p = do_page_fault(&fault)))
return p;
}
/* No exec or any other fault reason allowed. */
BUG_ON(vmflags & ~(VM_READ | VM_WRITE));
return 0;
return p;
}

View File

@@ -552,16 +552,16 @@ int copy_cache_pages(struct vm_file *vmfile, struct tcb *task, void *buf,
copysize = min(copysize, PAGE_SIZE - page_offset(task_offset));
if (read)
page_copy(task_virt_to_page(task, task_offset,
VM_READ | VM_WRITE),
page_copy(task_prefault_page(task, task_offset,
VM_READ | VM_WRITE),
file_page,
page_offset(task_offset),
page_offset(file_offset),
copysize);
else
page_copy(file_page,
task_virt_to_page(task, task_offset,
VM_READ),
task_prefault_page(task, task_offset,
VM_READ),
page_offset(file_offset),
page_offset(task_offset),
copysize);

View File

@@ -150,8 +150,7 @@ int pager_setup_task(void)
}
/* Pager must prefault its utcb */
prefault_page(task, task->utcb_address,
VM_READ | VM_WRITE);
task_prefault_page(task, task->utcb_address, VM_READ | VM_WRITE);
/* Add the task to the global task list */
global_add_task(task);
@@ -557,9 +556,9 @@ void copy_init_process(void)
}
/* Prefault it */
if ((err = prefault_range(self, (unsigned long)mapped,
img_size,
VM_READ | VM_WRITE)) < 0) {
if ((err = task_prefault_range(self, (unsigned long)mapped,
img_size, VM_READ | VM_WRITE))
< 0) {
printf("FATAL: Prefaulting init image failed.\n");
BUG();
}

View File

@@ -179,7 +179,7 @@ void *pager_validate_map_user_range2(struct tcb *user, void *userptr,
/* Map every page contiguously in the allocated virtual address range */
for (unsigned long addr = start; addr < end; addr += PAGE_SIZE) {
struct page *p = task_virt_to_page(user, addr, vm_flags);
struct page *p = task_prefault_page(user, addr, vm_flags);
if (IS_ERR(p)) {
/* Unmap pages mapped so far */
@@ -191,7 +191,7 @@ void *pager_validate_map_user_range2(struct tcb *user, void *userptr,
return p;
}
l4_map((void *)page_to_phys(task_virt_to_page(user, addr, vm_flags)),
l4_map((void *)page_to_phys(p),
virt, 1, MAP_USR_RW_FLAGS, self_tid());
virt += PAGE_SIZE;
}

View File

@@ -383,7 +383,7 @@ int shpage_map_to_task(struct tcb *owner, struct tcb *mapper, unsigned int flags
/* Prefault the owner's shared page to mapper's address space */
if (flags & SHPAGE_PREFAULT)
for (int i = 0; i < __pfn(DEFAULT_SHPAGE_SIZE); i++)
prefault_page(mapper, (unsigned long)owner->shared_page +
task_prefault_page(mapper, (unsigned long)owner->shared_page +
__pfn_to_addr(i), VM_READ | VM_WRITE);
return 0;
}

View File

@@ -504,14 +504,14 @@ int task_copy_args_to_user(char *user_stack,
return 0;
}
int prefault_range(struct tcb *task, unsigned long start,
unsigned long size, unsigned int vm_flags)
int task_prefault_range(struct tcb *task, unsigned long start,
unsigned long size, unsigned int vm_flags)
{
int err;
struct page *p;
for (unsigned long i = start; i < start + size; i += PAGE_SIZE)
if ((err = prefault_page(task, i, vm_flags)) < 0)
return err;
if (IS_ERR(p = task_prefault_page(task, i, vm_flags)))
return (int)p;
return 0;
}
@@ -553,9 +553,8 @@ int task_map_stack(struct vm_file *f, struct exec_file_desc *efd,
return (int)mapped;
}
/* Prefault the stack for writing. */
BUG_ON(prefault_range(task, task->args_start,
stack_used, VM_READ | VM_WRITE) < 0);
/* FIXME: Probably not necessary anymore. Prefault the stack for writing. */
//BUG_ON(task_prefault_range(task, task->args_start, stack_used, VM_READ | VM_WRITE) < 0);
/* Map the stack's part that will contain args and environment */
if (IS_ERR(args_on_stack =
@@ -597,12 +596,9 @@ int task_map_bss(struct vm_file *f, struct exec_file_desc *efd, struct tcb *task
struct page *last_data_page;
void *pagebuf, *bss;
/* Prefault the last data page */
BUG_ON(prefault_page(task, task->data_end,
VM_READ | VM_WRITE) < 0);
/* Get the page */
last_data_page = task_virt_to_page(task, task->data_end,
VM_READ | VM_WRITE);
last_data_page = task_prefault_page(task, task->data_end,
VM_READ | VM_WRITE);
/* Map the page. FIXME: PAGE COLOR!!! */
pagebuf = l4_map_helper((void *)page_to_phys(last_data_page), 1);
@@ -759,26 +755,3 @@ int task_start(struct tcb *task)
return 0;
}
/*
* Prefaults all mapped regions of a task. The reason we have this is
* some servers are in the page fault handling path (e.g. fs0), and we
* don't want them to fault and cause deadlocks and circular deps.
*
* Normally fs0 faults dont cause dependencies because its faults
* are handled by the boot pager, which is part of mm0. BUT: It may
* cause deadlocks because fs0 may fault while serving a request
* from mm0.(Which is expected to also handle the fault).
*/
int task_prefault_regions(struct tcb *task, struct vm_file *f)
{
struct vm_area *vma;
list_foreach_struct(vma, &task->vm_area_head->list, list) {
for (int pfn = vma->pfn_start; pfn < vma->pfn_end; pfn++)
BUG_ON(prefault_page(task, __pfn_to_addr(pfn),
VM_READ | VM_WRITE) < 0);
}
return 0;
}

View File

@@ -58,16 +58,16 @@ void *pager_validate_map_user_range(struct tcb *user, void *userptr,
return 0;
/* Map first page and calculate the mapped address of pointer */
mapped = l4_map_helper((void *)page_to_phys(task_virt_to_page(user, start,
vm_flags)), 1);
mapped = l4_map_helper((void *)page_to_phys(task_prefault_page(user, start,
vm_flags)), 1);
mapped = (void *)(((unsigned long)mapped) |
((unsigned long)(PAGE_MASK & (unsigned long)userptr)));
/* Map the rest of the pages, if any */
for (unsigned long i = start + PAGE_SIZE; i < end; i += PAGE_SIZE)
l4_map_helper((void *)page_to_phys(task_virt_to_page(user,
start + i,
vm_flags)), 1);
l4_map_helper((void *)
page_to_phys(task_prefault_page(user, start + i,
vm_flags)), 1);
return mapped;
}

View File

@@ -32,7 +32,7 @@ int main(int argc, char *argv[])
char *parent_of_all;
char pidbuf[10];
printf("New task started: %d\n", __raw_tid(getpid()));
// printf("New task started: %d\n", __raw_tid(getpid()));
/* Convert current pid to string */
sprintf(pidbuf, "%d", getpid());
@@ -45,7 +45,7 @@ int main(int argc, char *argv[])
goto out;
}
printf("New task continues: %d\n", __raw_tid(getpid()));
// printf("New task continues: %d\n", __raw_tid(getpid()));
/* Get parent of all pid as a string from environment */
parent_of_all = getenv("parent_of_all");