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:
Bahadir Balban
2008-02-27 01:17:36 +00:00
parent 2a5cdf80b5
commit 0c9b42121a
9 changed files with 144 additions and 76 deletions

40
README
View File

@@ -38,17 +38,35 @@ Codezero. These system calls provide purely mechanism; threads and address
spaces, and the methods of inter-process communication between them. Anything
beyond these are policy and they are implemented in the userspace. Due to this
rigorously simple design the same microkernel can be used to design completely
different operating systems. In terms of other features, the microkernel is
preemptive, and smp-ready. Currently only synchronous communication is
implemented, but this will change in the near future.
different operating systems.
MM0 is the systm task that implements memory management. It contains memory and
In terms of other features, the microkernel is preemptive, and smp-ready.
Currently only synchronous communication is implemented, but this will change in
the near future.
MM0 is the system task that implements memory management. It contains memory and
page allocators. It implements demand paging by managing page faults, physical
pages and their file/task associations.
pages and their file/task associations. It provides the default paging mechanism
on Codezero.
FS0 is the system task that implements a simple, modern virtual filesystem layer.
Since it abstracts the low-level filesystem details, it is a relatively easy job
to port a new filesystem to be used under FS0.
It is designed to serve file requests from MM0. Since it abstracts the low-level
filesystem details, it is a relatively easy job to port a new filesystem to be
used under FS0.
MM0 and FS0 both reside in the userspace, and they are not mandatory services.
For example the virtual and physical memory resources can be partitioned by
Codezero among pagers, and a third-party pager can override Codezero's MM0
pager on the same run-time, and implement an independent paging behaviour
for its own memory partition. This feature provides the option of having an
adjustable mixture of generalisation and specialisation at the same run-time, by
using a combination of Codezero's abstract posix-like page/file management
services and an application-specific pager that depends on its own paging
abilities. For example a critical task could both use posix-like files
benefiting from the abstraction and simplification that it brings, but at the
same time rely on its own page-fault handling for its critical data so that even
though it handles its memory in a specialised way, it does not depend on another
pager's grace for correct, stable operation.
License:
@@ -75,8 +93,8 @@ code. Linux is well established, and targets a broad range of platforms and
uses, but consequently embedded platforms don't always get enough emphasis. Also
such well established, mature systems tend to oppose major design overhauls,
which limits innovation to a certain extent. In addition, their code base is so
big, that it gets more and more difficult to understand how the system works.
Usually much of the code is irrelevant to the problem, in case of embedded
big, that it gets more and more difficult to understand how their internals
work. Usually much of the code is irrelevant to the problem, in case of embedded
systems. Codezero is written from scratch to solely target embedded systems and
as such the source code is %100 relevant. It is small and free from legacy code.
Finally monolithic kernels may have issues with dependability due to much of the
@@ -99,3 +117,7 @@ development methodologies, Codezero project aims to keep up with the latest OS
literature and provide the opportunity to incorporate the latest ideas in OS
technology.

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();