mirror of
https://github.com/drasko/codezero.git
synced 2026-01-19 06:13:16 +01:00
Adds reading pages into page-cache in an ordered manner.
Added reading pages from the page cache into user buffer for sys_read. Increases stack sizes to 4 pages. Updated README to include more details about multi-pager environments.
This commit is contained in:
@@ -66,15 +66,12 @@ int memfs_format_filesystem(void *buffer)
|
||||
INIT_LIST_HEAD(&sb->inode_cache_list);
|
||||
memfs_init_caches(sb);
|
||||
|
||||
/*
|
||||
* TODO: Make sure root vnode has a vnode number of 0 !!!.
|
||||
* This is used in early root lookup.
|
||||
*/
|
||||
BUG();
|
||||
|
||||
/* We allocate and fix a root inode so the sb is ready for mount */
|
||||
sb->root = memfs_create_inode(sb);
|
||||
|
||||
/* Some early-init code relies on root having inode number 0 */
|
||||
BUG_ON(sb->root->inum != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,15 +113,7 @@ int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode)
|
||||
|
||||
int sys_close(l4id_t sender, int fd)
|
||||
{
|
||||
struct vnode *v;
|
||||
|
||||
/* Get the task */
|
||||
BUG_ON(!(task = find_task(sender)));
|
||||
|
||||
/* Lookup vnode */
|
||||
if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
|
||||
return -EINVAL; /* No such vnode */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_mkdir(l4id_t sender, const char *pathname, unsigned int mode)
|
||||
|
||||
@@ -112,6 +112,9 @@ static inline struct vm_area *find_vma(unsigned long addr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Adds a page to its vmfile's page cache in order of offset. */
|
||||
int insert_page_olist(struct page *this, struct vm_file *f);
|
||||
|
||||
/* Pagers */
|
||||
extern struct vm_pager default_file_pager;
|
||||
extern struct vm_pager boot_file_pager;
|
||||
|
||||
@@ -20,13 +20,6 @@
|
||||
#include <syscalls.h>
|
||||
#include <file.h>
|
||||
|
||||
/* FIXME:LOCKING:FIXME:LOCKING:FIXME:LOCKING
|
||||
* NOTE: For multithreadded MM0, not suprisingly, we need locking on
|
||||
* vmas, vm_files, and all global variables. Also at times, the per-task
|
||||
* lists of items (e.g. vmas) must be entirely locked. Pages already have
|
||||
* locking.
|
||||
*/
|
||||
|
||||
void handle_requests(void)
|
||||
{
|
||||
/* Generic ipc data */
|
||||
|
||||
@@ -130,7 +130,7 @@ int do_file_page(struct fault_data *fault)
|
||||
|
||||
/* Add the page to it's owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &page->owner->page_cache_list);
|
||||
insert_page_olist(page, page->owner);
|
||||
spin_unlock(&page->lock);
|
||||
//printf("%s: Mapped new page @ 0x%x to task: %d\n", __TASKNAME__,
|
||||
// fault->address, fault->task->tid);
|
||||
@@ -184,7 +184,7 @@ int do_file_page(struct fault_data *fault)
|
||||
|
||||
/* Add the page to it's owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &page->owner->page_cache_list);
|
||||
insert_page_olist(page, page->owner);
|
||||
spin_unlock(&page->lock);
|
||||
|
||||
/*
|
||||
@@ -244,7 +244,7 @@ int do_file_page(struct fault_data *fault)
|
||||
|
||||
/* Add the page to it's owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &page->owner->page_cache_list);
|
||||
insert_page_olist(page, page->owner);
|
||||
spin_unlock(&page->lock);
|
||||
} else
|
||||
BUG();
|
||||
@@ -333,7 +333,7 @@ int do_anon_page(struct fault_data *fault)
|
||||
|
||||
/* Add the page to it's owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &page->owner->page_cache_list);
|
||||
insert_page_olist(page, page->owner);
|
||||
|
||||
/* The offset of this page in its owner file */
|
||||
page->f_offset = __pfn(fault->address)
|
||||
@@ -391,15 +391,15 @@ int do_page_fault(struct fault_data *fault)
|
||||
|
||||
/* vma flags show no access */
|
||||
if (vma_flags & VM_NONE) {
|
||||
printf("Illegal access, tid: %d, address: %x\n",
|
||||
fault->task->tid, fault->address);
|
||||
printf("Illegal access, tid: %d, address: 0x%x, PC @ 0x%x,\n",
|
||||
fault->task->tid, fault->address, fault->kdata->faulty_pc);
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* The access reason is not included in the vma's listed flags */
|
||||
if (!(reason & vma_flags)) {
|
||||
printf("Illegal access, tid: %d, address: %x\n",
|
||||
fault->task->tid, fault->address);
|
||||
printf("Illegal access, tid: %d, address: 0x%x, PC @ 0x%x\n",
|
||||
fault->task->tid, fault->address, fault->kdata->faulty_pc);
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
||||
@@ -132,18 +132,55 @@ int vfs_receive_sys_open(l4id_t sender, l4id_t opener, int fd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: Implement this */
|
||||
struct page *find_page(struct vm_file *f, unsigned long pfn)
|
||||
{
|
||||
struct page *p;
|
||||
|
||||
list_for_each_entry(p, &f->page_cache_list, list) {
|
||||
list_for_each_entry(p, &f->page_cache_list, list)
|
||||
if (p->f_offset == pfn)
|
||||
return p;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inserts the page to vmfile's list in order of page frame offset.
|
||||
* We use an ordered list instead of a radix or btree for now.
|
||||
*/
|
||||
int insert_page_olist(struct page *this, struct vm_file *f)
|
||||
{
|
||||
struct page *before, *after;
|
||||
|
||||
/* Add if list is empty */
|
||||
if (list_empty(&f->page_cache_list)) {
|
||||
list_add_tail(&this->list, &f->page_cache_list);
|
||||
return 0;
|
||||
}
|
||||
/* Else find the right interval */
|
||||
list_for_each_entry(before, &f->page_cache_list, list) {
|
||||
after = list_entry(before->list.next, struct page, list);
|
||||
|
||||
/* If there's only one in list */
|
||||
if (before->list.next == &f->page_cache_list) {
|
||||
/* Add to end if greater */
|
||||
if (this->f_offset > before->f_offset)
|
||||
list_add_tail(&this->list, &before->list);
|
||||
/* Add to beginning if smaller */
|
||||
else if (this->f_offset < before->f_offset)
|
||||
list_add(&this->list, &before->list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this page is in-between two other, insert it there */
|
||||
if (before->f_offset < this->f_offset &&
|
||||
after->f_offset > this->f_offset) {
|
||||
list_add_tail(&this->list, &before->list);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
BUG();
|
||||
}
|
||||
|
||||
/*
|
||||
* This reads-in a range of pages from a file and populates the page cache
|
||||
* just like a page fault, but its not in the page fault path.
|
||||
@@ -180,7 +217,7 @@ int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start,
|
||||
|
||||
/* Add the page to owner's list of in-memory pages */
|
||||
BUG_ON(!list_empty(&page->list));
|
||||
list_add(&page->list, &vmfile->page_cache_list);
|
||||
insert_page_olist(page, vmfile);
|
||||
spin_unlock(&page->lock);
|
||||
}
|
||||
}
|
||||
@@ -188,11 +225,49 @@ int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reads a page range from an ordered list of pages into buffer */
|
||||
int read_cache_pages(struct vm_file *vmfile, void *buf, unsigned long pfn_start,
|
||||
unsigned long pfn_end, unsigned long offset,
|
||||
int count)
|
||||
{
|
||||
struct page *head, *next;
|
||||
int copysize, left;
|
||||
|
||||
list_for_each_entry(head, &vmfile->page_cache_list, list)
|
||||
if (head->f_offset == pfn_start)
|
||||
goto copy;
|
||||
BUG();
|
||||
|
||||
copy:
|
||||
left = count;
|
||||
|
||||
/* Copy the first page */
|
||||
copysize = (left <= PAGE_SIZE) ? left : PAGE_SIZE;
|
||||
memcpy(buf, (void *)phys_to_virt((void *)page_to_phys(head)) + offset,
|
||||
copysize);
|
||||
left -= copysize;
|
||||
|
||||
/* Copy the rest. Urgh, lots of arithmetic here. */
|
||||
list_for_each_entry(next, &head->list, list) {
|
||||
if (left == 0 || next->f_offset == pfn_end)
|
||||
break;
|
||||
copysize = (left <= PAGE_SIZE) ? left : PAGE_SIZE;
|
||||
memcpy(buf + count - left,
|
||||
(void *)phys_to_virt((void *)page_to_phys(next)),
|
||||
copysize);
|
||||
left -= copysize;
|
||||
}
|
||||
BUG_ON(left != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sys_read(l4id_t sender, int fd, void *buf, int count)
|
||||
{
|
||||
unsigned long foff_pfn_start, foff_pfn_end;
|
||||
unsigned long cursor, first_pgoff;
|
||||
struct vm_file *vmfile;
|
||||
unsigned long cursor;
|
||||
struct tcb *t;
|
||||
int err;
|
||||
|
||||
@@ -208,43 +283,26 @@ int sys_read(l4id_t sender, int fd, void *buf, int count)
|
||||
foff_pfn_start = __pfn(cursor);
|
||||
foff_pfn_end = __pfn(page_align_up(cursor + count));
|
||||
|
||||
/* Read the page range into the cache from file */
|
||||
if ((err = read_file_pages(vmfile, foff_pfn_start, foff_pfn_end) < 0))
|
||||
return err;
|
||||
|
||||
/*
|
||||
* FIXME: If vmfiles are mapped contiguously on mm0, then these reads
|
||||
* can be implemented as a straightforward copy as below.
|
||||
*
|
||||
* The problem is that in-memory file pages are usually non-contiguous.
|
||||
* memcpy(buf, (void *)(vmfile->base + cursor), count);
|
||||
*/
|
||||
/* The offset of cursor on first page */
|
||||
first_pgoff = PAGE_MASK & cursor;
|
||||
|
||||
/* Read it into the user buffer from the cache */
|
||||
if ((err = read_cache_pages(vmfile, buf, foff_pfn_start, foff_pfn_end,
|
||||
first_pgoff, count)) < 0)
|
||||
return err;
|
||||
|
||||
/* Update cursor on success */
|
||||
t->fd[fd].cursor += count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_write(l4id_t sender, int fd, void *buf, int count)
|
||||
{
|
||||
unsigned long foff_pfn_start, foff_pfn_end;
|
||||
struct vm_file *vmfile;
|
||||
unsigned long cursor;
|
||||
struct tcb *t;
|
||||
int err;
|
||||
|
||||
BUG_ON(!(t = find_task(sender)));
|
||||
|
||||
/* TODO: Check user buffer and count validity */
|
||||
if (fd < 0 || fd > TASK_OFILES_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
vmfile = t->fd[fd].vmfile;
|
||||
cursor = t->fd[fd].cursor;
|
||||
|
||||
foff_pfn_start = __pfn(cursor);
|
||||
foff_pfn_end = __pfn(page_align_up(cursor + count));
|
||||
|
||||
if ((err = write_file_pages(vmfile, foff_pfn_start, foff_pfn_end) < 0))
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +127,9 @@ int start_boot_tasks(struct initdata *initdata, struct tcb_head *tcbs)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* mmap each task's stack as single page anonymous memory. */
|
||||
if ((err = do_mmap(0, 0, task, USER_AREA_END - PAGE_SIZE,
|
||||
VM_READ | VM_WRITE | VMA_ANON, 1) < 0)) {
|
||||
/* mmap each task's stack as 4-page anonymous memory. */
|
||||
if ((err = do_mmap(0, 0, task, USER_AREA_END - PAGE_SIZE * 4,
|
||||
VM_READ | VM_WRITE | VMA_ANON, 4) < 0)) {
|
||||
printf("do_mmap: Mapping stack failed with %d.\n", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,12 @@ void main(void)
|
||||
{
|
||||
printf("\n%s: Started with tid %d.\n", __TASKNAME__, self_tid());
|
||||
/* Sync with pager */
|
||||
wait_pager(0);
|
||||
|
||||
dirtest();
|
||||
|
||||
while (1)
|
||||
wait_pager(0);
|
||||
|
||||
#if 0
|
||||
/* Check mmap/munmap */
|
||||
mmaptest();
|
||||
|
||||
Reference in New Issue
Block a user