From a2491059692e009fb6044266508f1b265013c95d Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Tue, 13 Oct 2009 11:33:25 +0300 Subject: [PATCH] Integrated vm_files with vnodes. execve is not working as expected. --- conts/posix/mm0/fs/memfs/vnode.c | 2 +- conts/posix/mm0/fs/vfs.c | 6 +- conts/posix/mm0/include/file.h | 14 +- conts/posix/mm0/include/task.h | 1 - conts/posix/mm0/include/vfs.h | 4 +- conts/posix/mm0/include/vm_area.h | 18 +- conts/posix/mm0/main.c | 5 - conts/posix/mm0/mm/dev.c | 3 +- conts/posix/mm0/mm/execve.c | 48 ++- conts/posix/mm0/mm/fault.c | 3 +- conts/posix/mm0/mm/file.c | 562 +++++++++++++++--------------- conts/posix/mm0/mm/mmap.c | 7 +- conts/posix/mm0/mm/pagers.c | 30 +- conts/posix/mm0/mm/shm.c | 13 +- conts/posix/mm0/mm/test.c | 2 - conts/posix/mm0/mm/vm_object.c | 7 +- conts/posix/test0/container.c | 6 +- conts/posix/test0/include/tests.h | 2 +- conts/posix/test0/main.c | 3 +- conts/posix/test0/src/exectest.c | 37 +- conts/posix/test0/src/forktest.c | 2 +- 21 files changed, 400 insertions(+), 375 deletions(-) diff --git a/conts/posix/mm0/fs/memfs/vnode.c b/conts/posix/mm0/fs/memfs/vnode.c index 0ebfa6a..d18cb97 100644 --- a/conts/posix/mm0/fs/memfs/vnode.c +++ b/conts/posix/mm0/fs/memfs/vnode.c @@ -358,7 +358,7 @@ int memfs_vnode_readdir(struct vnode *v) * in the vnode cache. If it's not there, the lookup function * allocates and reads it for us as well. */ - newv = newd->vnode = vfs_lookup_byvnum(v->sb, memfsd[i].inum); + newv = newd->vnode = vfs_vnode_lookup_byvnum(v->sb, memfsd[i].inum); if (!newv) { printf("Filesystem seems to be broken. Directory has" "inode number: %d, but no such inode found.\n", diff --git a/conts/posix/mm0/fs/vfs.c b/conts/posix/mm0/fs/vfs.c index f15b9d1..d7b51aa 100644 --- a/conts/posix/mm0/fs/vfs.c +++ b/conts/posix/mm0/fs/vfs.c @@ -20,7 +20,7 @@ struct id_pool *vfs_fsidx_pool; * If nothing is found, it reads the vnode from disk into cache. This is called * by system calls since tasks keep an fd-to-vnum table. */ -struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum) +struct vnode *vfs_vnode_lookup_byvnum(struct superblock *sb, unsigned long vnum) { struct vnode *v; int err; @@ -51,7 +51,7 @@ struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum) * have, the other is their vnum. This one checks the vnode cache by the path * first. If nothing is found, it reads the vnode from disk into the cache. */ -struct vnode *vfs_lookup_bypath(struct pathdata *pdata) +struct vnode *vfs_vnode_lookup_bypath(struct pathdata *pdata) { const char *firstcomp; @@ -69,7 +69,7 @@ int vfs_mount_root(struct superblock *sb) * Lookup the root vnode of this superblock. * The root superblock has vnode number 0. */ - vfs_root.pivot = vfs_lookup_byvnum(sb, sb->fsidx | 0); + vfs_root.pivot = vfs_vnode_lookup_byvnum(sb, sb->fsidx | 0); vfs_root.sb = sb; return 0; diff --git a/conts/posix/mm0/include/file.h b/conts/posix/mm0/include/file.h index 8d49d3c..4d153c1 100644 --- a/conts/posix/mm0/include/file.h +++ b/conts/posix/mm0/include/file.h @@ -6,10 +6,10 @@ #include /* FIXME: Remove this and refer to internal headers */ #include -int vfs_read(unsigned long vnum, unsigned long f_offset, unsigned long npages, - void *pagebuf); -int vfs_write(unsigned long vnum, unsigned long f_offset, unsigned long npages, - void *pagebuf); +int vfs_read(struct vnode *v, unsigned long f_offset, + unsigned long npages, void *pagebuf); +int vfs_write(struct vnode *v, unsigned long f_offset, + unsigned long npages, void *pagebuf); int sys_read(struct tcb *sender, int fd, void *buf, int count); int sys_write(struct tcb *sender, int fd, void *buf, int count); int sys_lseek(struct tcb *sender, int fd, off_t offset, int whence); @@ -24,12 +24,6 @@ int flush_file_pages(struct vm_file *f); int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start, unsigned long pfn_end); -struct vfs_file_data { - unsigned long vnum; -}; - -#define vm_file_to_vnum(f) \ - (((struct vfs_file_data *)((f)->priv_data))->vnum) struct vm_file *vfs_file_create(void); diff --git a/conts/posix/mm0/include/task.h b/conts/posix/mm0/include/task.h index 9eff55b..e5f8f30 100644 --- a/conts/posix/mm0/include/task.h +++ b/conts/posix/mm0/include/task.h @@ -40,7 +40,6 @@ struct vm_file; struct file_descriptor { - unsigned long vnum; unsigned long cursor; struct vm_file *vmfile; }; diff --git a/conts/posix/mm0/include/vfs.h b/conts/posix/mm0/include/vfs.h index 2b8978e..cd08ed3 100644 --- a/conts/posix/mm0/include/vfs.h +++ b/conts/posix/mm0/include/vfs.h @@ -93,8 +93,8 @@ extern struct vfs_mountpoint vfs_root; int vfs_mount_root(struct superblock *sb); struct vnode *generic_vnode_lookup(struct vnode *thisnode, struct pathdata *p, const char *component); -struct vnode *vfs_lookup_bypath(struct pathdata *p); -struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum); +struct vnode *vfs_vnode_lookup_bypath(struct pathdata *p); +struct vnode *vfs_vnode_lookup_byvnum(struct superblock *sb, unsigned long vnum); int vfs_init(void); diff --git a/conts/posix/mm0/include/vm_area.h b/conts/posix/mm0/include/vm_area.h index 21cab02..2b7a2d4 100644 --- a/conts/posix/mm0/include/vm_area.h +++ b/conts/posix/mm0/include/vm_area.h @@ -47,7 +47,6 @@ enum VM_FILE_TYPE { VM_FILE_DEVZERO = 1, VM_FILE_VFS, - VM_FILE_BOOTFILE, VM_FILE_SHM, }; @@ -66,17 +65,10 @@ struct page { }; extern struct page *page_array; -/* - * A suggestion to how a non-page_array (i.e. a device) - * page could tell its physical address. - */ -struct devpage { - struct page page; - unsigned long phys; -}; - #define page_refcnt(x) ((x)->count + 1) #define virtual(x) ((x)->virtual) + +/* TODO: Calculate these by indexing each bank according to pfn */ #define phys_to_page(x) (page_array + __pfn((x) - membank[0].start)) #define page_to_phys(x) (__pfn_to_addr((((void *)(x)) - \ (void *)page_array) / \ @@ -131,11 +123,12 @@ struct vm_object { struct vm_file { int openers; struct link list; - unsigned long length; unsigned int type; + unsigned long length; struct vm_object vm_obj; void (*destroy_priv_data)(struct vm_file *f); - void *priv_data; /* Device pagers use to access device info */ + struct vnode *vnode; + void *private_file_data; /* FIXME: To be removed and placed into vnode!!! */ }; /* To create per-vma vm_object lists */ @@ -210,7 +203,6 @@ struct page *find_page(struct vm_object *obj, unsigned long pfn); /* Pagers */ extern struct vm_pager file_pager; -extern struct vm_pager bootfile_pager; extern struct vm_pager devzero_pager; extern struct vm_pager swap_pager; diff --git a/conts/posix/mm0/main.c b/conts/posix/mm0/main.c index c123081..cb6f0c6 100644 --- a/conts/posix/mm0/main.c +++ b/conts/posix/mm0/main.c @@ -153,11 +153,6 @@ void handle_requests(void) return; /* else we're done */ } - /* - * FIXME: Fix all these syscalls to read any - * buffer data from the caller task's utcb. - */ - /* FS0 System calls */ case L4_IPC_TAG_OPEN: ret = sys_open(sender, utcb_full_buffer(), (int)mr[0], (unsigned int)mr[1]); diff --git a/conts/posix/mm0/mm/dev.c b/conts/posix/mm0/mm/dev.c index 736c76f..c81eb0e 100644 --- a/conts/posix/mm0/mm/dev.c +++ b/conts/posix/mm0/mm/dev.c @@ -4,6 +4,7 @@ #include #include #include +#include /* * This is yet unused, it is more of an anticipation @@ -19,7 +20,7 @@ struct page *memdev_page_in(struct vm_object *vm_obj, unsigned long pfn_offset) { struct vm_file *f = vm_object_to_file(vm_obj); - struct mmap_device *memdev = f->priv_data; + struct mmap_device *memdev = f->vnode->inode; struct page *page; /* Check if its within device boundary */ diff --git a/conts/posix/mm0/mm/execve.c b/conts/posix/mm0/mm/execve.c index 49f33b5..a200e90 100644 --- a/conts/posix/mm0/mm/execve.c +++ b/conts/posix/mm0/mm/execve.c @@ -37,13 +37,13 @@ int task_setup_from_executable(struct vm_file *vmfile, struct tcb *task, int init_execve(char *filepath) { - unsigned long vnum, length; struct vm_file *vmfile; struct exec_file_desc efd; - struct tcb *new_task; + struct tcb *new_task, *self; struct args_struct args, env; char *env_string = "pagerid=0"; int err; + int fd; struct task_ids ids = { .tid = TASK_ID_INVALID, @@ -65,33 +65,26 @@ int init_execve(char *filepath) strncpy(env.argv[0], env_string, strlen(env_string) + 1); env.size = sizeof(env.argv) + strlen(env_string) + 1; - /* Get file info from vfs */ - if ((err = vfs_open_bypath(filepath, &vnum, &length)) < 0) - return err; - - /* Create and get the file structure */ - if (IS_ERR(vmfile = do_open2(0, 0, vnum, length))) - return (int)vmfile; - -#if 0 + self = find_task(self_tid()); if ((fd = sys_open(self, filepath, O_RDONLY, 0)) < 0) { printf("FATAL: Could not open file " - "to execute initial task.\n"); + "to write initial task.\n"); BUG(); } -#endif + /* Get the low-level vmfile */ + vmfile = self->files->fd[fd].vmfile; if (IS_ERR(new_task = task_create(0, &ids, THREAD_NEW_SPACE, TCB_NO_SHARING))) { - vm_file_put(vmfile); /* FIXME: sys_close() ??? */ + sys_close(self, fd); return (int)new_task; } /* Fill and validate tcb memory segment markers from executable file */ if ((err = task_setup_from_executable(vmfile, new_task, &efd)) < 0) { - vm_file_put(vmfile); + sys_close(self, fd); kfree(new_task); return err; } @@ -99,7 +92,7 @@ int init_execve(char *filepath) /* Map task's new segment markers as virtual memory regions */ if ((err = task_mmap_segments(new_task, vmfile, &efd, &args, &env)) < 0) { - vm_file_put(vmfile); + sys_close(self, fd); kfree(new_task); return err; } @@ -123,29 +116,28 @@ int init_execve(char *filepath) int do_execve(struct tcb *sender, char *filename, struct args_struct *args, struct args_struct *env) { - unsigned long vnum, length; struct vm_file *vmfile; struct exec_file_desc efd; - struct tcb *new_task, *tgleader; + struct tcb *new_task, *tgleader, *self; int err; + int fd; - /* Get file info from vfs */ - if ((err = vfs_open_bypath(filename, &vnum, &length)) < 0) - return err; + self = find_task(self_tid()); + if ((fd = sys_open(self, filename, O_RDONLY, 0)) < 0) + return fd; - /* Create and get the file structure */ - if (IS_ERR(vmfile = do_open2(0, 0, vnum, length))) - return (int)vmfile; + /* Get the low-level vmfile */ + vmfile = self->files->fd[fd].vmfile; /* Create a new tcb */ if (IS_ERR(new_task = tcb_alloc_init(TCB_NO_SHARING))) { - vm_file_put(vmfile); + sys_close(self, fd); return (int)new_task; } /* Fill and validate tcb memory segment markers from executable file */ if ((err = task_setup_from_executable(vmfile, new_task, &efd)) < 0) { - vm_file_put(vmfile); + sys_close(self, fd); kfree(new_task); return err; } @@ -175,7 +167,7 @@ int do_execve(struct tcb *sender, char *filename, struct args_struct *args, * exit() except destroying the actual thread. */ if ((err = execve_recycle_task(new_task, tgleader)) < 0) { - vm_file_put(vmfile); + sys_close(self, fd); kfree(new_task); return err; } @@ -183,7 +175,7 @@ int do_execve(struct tcb *sender, char *filename, struct args_struct *args, /* Map task's new segment markers as virtual memory regions */ if ((err = task_mmap_segments(new_task, vmfile, &efd, args, env)) < 0) { - vm_file_put(vmfile); + sys_close(self, fd); kfree(new_task); return err; } diff --git a/conts/posix/mm0/mm/fault.c b/conts/posix/mm0/mm/fault.c index ffa8c14..71ec3e6 100644 --- a/conts/posix/mm0/mm/fault.c +++ b/conts/posix/mm0/mm/fault.c @@ -330,8 +330,7 @@ int vm_object_is_deletable(struct vm_object *obj) return 0; else if (f->type == VM_FILE_SHM) return 1; - else if (f->type == VM_FILE_BOOTFILE || - f->type == VM_FILE_VFS) { + else if (f->type == VM_FILE_VFS) { if (f->openers == 0) return 1; else diff --git a/conts/posix/mm0/mm/file.c b/conts/posix/mm0/mm/file.c index 499c297..ecaa2de 100644 --- a/conts/posix/mm0/mm/file.c +++ b/conts/posix/mm0/mm/file.c @@ -64,15 +64,9 @@ int page_copy(struct page *dst, struct page *src, return 0; } -int vfs_read(unsigned long vnum, unsigned long file_offset, +int vfs_read(struct vnode *v, unsigned long file_offset, unsigned long npages, void *pagebuf) { - struct vnode *v; - - /* Lookup vnode */ - if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum))) - return -EINVAL; - /* Ensure vnode is not a directory */ if (vfs_isdir(v)) return -EISDIR; @@ -95,46 +89,9 @@ void print_vnode(struct vnode *v) } - -/* - * Different from vfs_open(), which validates an already opened - * file descriptor, this call opens a new vfs file by the pager - * using the given path. The vnum handle and file length is returned - * since the pager uses this information to access file pages. - */ -int vfs_open_bypath(const char *pathname, unsigned long *vnum, unsigned long *length) -{ - struct pathdata *pdata; - struct tcb *task = 0; - struct vnode *v; - int retval; - - /* Parse path data */ - if (IS_ERR(pdata = pathdata_parse(pathname, - alloca(strlen(pathname) + 1), - task))) - return (int)pdata; - - /* Search the vnode by that path */ - if (IS_ERR(v = vfs_lookup_bypath(pdata))) { - retval = (int)v; - goto out; - } - - *vnum = v->vnum; - *length = v->size; - - return 0; - -out: - pathdata_destroy(pdata); - return retval; -} - - /* Creates a node under a directory, e.g. a file, directory. */ -struct vnode *vfs_create(struct tcb *task, struct pathdata *pdata, - unsigned int mode) +struct vnode *vfs_vnode_create(struct tcb *task, struct pathdata *pdata, + unsigned int mode) { struct vnode *vparent, *newnode; const char *nodename; @@ -143,7 +100,7 @@ struct vnode *vfs_create(struct tcb *task, struct pathdata *pdata, nodename = pathdata_last_component(pdata); /* Check that the parent directory exists. */ - if (IS_ERR(vparent = vfs_lookup_bypath(pdata))) + if (IS_ERR(vparent = vfs_vnode_lookup_bypath(pdata))) return vparent; /* The parent vnode must be a directory. */ @@ -158,62 +115,6 @@ struct vnode *vfs_create(struct tcb *task, struct pathdata *pdata, return newnode; } -/* FIXME: - * - Is it already open? - * - Allocate a copy of path string since lookup destroys it - * - Check flags and mode. - */ -int sys_open(struct tcb *task, const char *pathname, int flags, unsigned int mode) -{ - struct pathdata *pdata; - struct vnode *v; - int fd; - int retval; - - // printf("%s/%s\n", __TASKNAME__, __FUNCTION__); - - /* Parse path data */ - if (IS_ERR(pdata = pathdata_parse(pathname, - alloca(strlen(pathname) + 1), - task))) - return (int)pdata; - - /* Creating new file */ - if (flags & O_CREAT) { - /* Make sure mode identifies a file */ - mode |= S_IFREG; - if (IS_ERR(v = vfs_create(task, pdata, mode))) { - retval = (int)v; - goto out; - } - } else { - /* Not creating, just opening, get the vnode */ - if (IS_ERR(v = vfs_lookup_bypath(pdata))) { - retval = (int)v; - goto out; - } - } - - /* Get a new fd */ - BUG_ON((fd = id_new(task->files->fdpool)) < 0); - retval = fd; - - /* TODO: - * Why assign just vnum? Why not vmfile, vnode etc? - * - * This is because vmfile is going to be created when - * the file pages are accessed. Need to trace this - * behaviour. - */ - - /* Assign the new fd with the vnode's number */ - task->files->fd[fd].vnum = v->vnum; - -out: - pathdata_destroy(pdata); - return retval; -} - int sys_mkdir(struct tcb *task, const char *pathname, unsigned int mode) { struct pathdata *pdata; @@ -230,7 +131,7 @@ int sys_mkdir(struct tcb *task, const char *pathname, unsigned int mode) mode |= S_IFDIR; /* Create the directory or fail */ - if (IS_ERR(v = vfs_create(task, pdata, mode))) + if (IS_ERR(v = vfs_vnode_create(task, pdata, mode))) ret = (int)v; /* Destroy extracted path data */ @@ -251,7 +152,7 @@ int sys_chdir(struct tcb *task, const char *pathname) return (int)pdata; /* Get the vnode */ - if (IS_ERR(v = vfs_lookup_bypath(pdata))) { + if (IS_ERR(v = vfs_vnode_lookup_bypath(pdata))) { ret = (int)v; goto out; } @@ -287,22 +188,13 @@ void fill_kstat(struct vnode *v, struct kstat *ks) int sys_fstat(struct tcb *task, int fd, void *statbuf) { - struct vnode *v; - unsigned long vnum; - - /* Get the vnum */ - if (fd < 0 || fd > TASK_FILES_MAX || !task->files->fd[fd].vnum) + /* Check that fd is valid */ + if (fd < 0 || fd > TASK_FILES_MAX || + !task->files->fd[fd].vmfile) return -EBADF; - BUG(); /* Could just return vmfile->vnode here. */ - vnum = task->files->fd[fd].vnum; - - /* Lookup vnode */ - if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum))) - return -EINVAL; - /* Fill in the c0-style stat structure */ - fill_kstat(v, statbuf); + fill_kstat(task->files->fd[fd].vmfile->vnode, statbuf); return 0; } @@ -325,7 +217,7 @@ int sys_stat(struct tcb *task, const char *pathname, void *statbuf) return (int)pdata; /* Get the vnode */ - if (IS_ERR(v = vfs_lookup_bypath(pdata))) { + if (IS_ERR(v = vfs_vnode_lookup_bypath(pdata))) { ret = (int)v; goto out; } @@ -339,121 +231,6 @@ out: return ret; } -/* - * Initialise a new file and the descriptor for it from given file data. - * Could be called by an actual task or a pager - */ -struct vm_file *do_open2(struct tcb *task, int fd, unsigned long vnum, unsigned long length) -{ - struct vm_file *vmfile; - - /* Is this an open by a task (as opposed to by the pager)? */ - if (task) { - /* fd slot must be empty */ - BUG_ON(task->files->fd[fd].vnum != 0); - BUG_ON(task->files->fd[fd].cursor != 0); - - /* Assign vnum to given fd on the task */ - task->files->fd[fd].vnum = vnum; - task->files->fd[fd].cursor = 0; - } - - /* Check if that vm_file is already in the list */ - list_foreach_struct(vmfile, &global_vm_files.list, list) { - - /* Check whether it is a vfs file and if so vnums match. */ - if ((vmfile->type & VM_FILE_VFS) && - vm_file_to_vnum(vmfile) == vnum) { - - /* Task opener? */ - if (task) - /* Add a reference to it from the task */ - task->files->fd[fd].vmfile = vmfile; - - vmfile->openers++; - return vmfile; - } - } - - /* Otherwise allocate a new one for this vnode */ - if (IS_ERR(vmfile = vfs_file_create())) - return vmfile; - - /* Initialise and add a reference to it from the task */ - vm_file_to_vnum(vmfile) = vnum; - vmfile->length = length; - vmfile->vm_obj.pager = &file_pager; - - /* Task opener? */ - if (task) - task->files->fd[fd].vmfile = vmfile; - vmfile->openers++; - - /* Add to file list */ - global_add_vm_file(vmfile); - - return vmfile; -} - -/* - * When a task does a read/write/mmap request on a file, if - * the file descriptor is unknown to the pager, this call - * asks vfs if that file has been opened, and any other - * relevant information. - */ -int file_open(struct tcb *task, int fd) -{ - struct vnode *v; - struct vm_file *vmfile; - - if (fd < 0 || fd > TASK_FILES_MAX) - return -EINVAL; - - /* Check if that fd has been opened */ - if (!task->files->fd[fd].vnum) - return -EBADF; - - /* Search the vnode by that vnum */ - if (IS_ERR(v = vfs_lookup_byvnum(vfs_root.pivot->sb, - task->files->fd[fd].vnum))) - return (int)v; - - /* Cursor must be zero */ - BUG_ON(task->files->fd[fd].cursor != 0); - - /* Check that vm_file is already in the list */ - list_foreach_struct(vmfile, &global_vm_files.list, list) { - - /* Check whether it is a vfs file and if so vnums match. */ - if ((vmfile->type & VM_FILE_VFS) && - vm_file_to_vnum(vmfile) == v->vnum) { - - /* Add a reference to it from the task */ - task->files->fd[fd].vmfile = vmfile; - vmfile->openers++; - return 0; - } - } - - /* Otherwise allocate a new one for this vnode */ - if (IS_ERR(vmfile = vfs_file_create())) - return (int)vmfile; - - /* Assign file information */ - vm_file_to_vnum(vmfile) = v->vnum; - vmfile->length = v->size; - - /* Add a reference to it from the task */ - vmfile->vm_obj.pager = &file_pager; - task->files->fd[fd].vmfile = vmfile; - vmfile->openers++; - - /* Add to file list */ - global_add_vm_file(vmfile); - - return 0; -} - /* * Inserts the page to vmfile's list in order of page frame offset. @@ -513,7 +290,7 @@ int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start, if (IS_ERR(page)) { printf("%s: %s:Could not read page %d " "from file with vnum: 0x%lu\n", __TASKNAME__, - __FUNCTION__, f_offset, vm_file_to_vnum(vmfile)); + __FUNCTION__, f_offset, vmfile->vnode->vnum); return (int)page; } } @@ -524,19 +301,14 @@ int read_file_pages(struct vm_file *vmfile, unsigned long pfn_start, /* * The buffer must be contiguous by page, if npages > 1. */ -int vfs_write(unsigned long vnum, unsigned long file_offset, +int vfs_write(struct vnode *v, unsigned long file_offset, unsigned long npages, void *pagebuf) { - struct vnode *v; int fwrite_end; int ret; // printf("%s/%s\n", __TASKNAME__, __FUNCTION__); - /* Lookup vnode */ - if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum))) - return -EINVAL; - /* Ensure vnode is not a directory */ if (vfs_isdir(v)) return -EISDIR; @@ -564,12 +336,7 @@ int vfs_write(unsigned long vnum, unsigned long file_offset, /* Writes updated file stats back to vfs. (e.g. new file size) */ int vfs_update_file_stats(struct vm_file *f) { - unsigned long vnum = vm_file_to_vnum(f); - struct vnode *v; - - /* Lookup vnode */ - if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum))) - return -EINVAL; + struct vnode *v = f->vnode; v->size = f->length; v->sb->ops->write_vnode(v->sb, v); @@ -596,7 +363,7 @@ int write_file_pages(struct vm_file *f, unsigned long pfn_start, if (err < 0) { printf("%s: %s:Could not write page %d " "to file with vnum: 0x%lu\n", __TASKNAME__, - __FUNCTION__, f_offset, vm_file_to_vnum(f)); + __FUNCTION__, f_offset, f->vnode->vnum); return err; } } @@ -635,6 +402,10 @@ int fsync_common(struct tcb *task, int fd) if (!task->files->fd[fd].vmfile) return 0; + printf("Thread %d flushing fd: %d, vnum: 0x%lx, vnode: %p\n", + task->tid, fd, task->files->fd[fd].vmfile->vnode->vnum, + task->files->fd[fd].vmfile->vnode); + /* Finish I/O on file */ if ((err = flush_file_pages(task->files->fd[fd].vmfile)) < 0) return err; @@ -651,6 +422,9 @@ void vm_file_put(struct vm_file *file) /* No links or openers, delete the file */ vm_file_delete(file); + /* FIXME: + * Shall we delete the cached vnode here as well??? + */ } /* @@ -672,18 +446,12 @@ int do_close(struct tcb *task, int fd) return err; } - /* - * If there was no IO on it, we may not know the file, - * we simply return here. Since we notify VFS about the - * close, it can tell us if the fd was open or not. - */ if (!task->files->fd[fd].vmfile) return 0; /* Reduce file refcount etc. */ vm_file_put(task->files->fd[fd].vmfile); - task->files->fd[fd].vnum = 0; task->files->fd[fd].cursor = 0; task->files->fd[fd].vmfile = 0; @@ -824,10 +592,19 @@ int write_cache_pages(struct vm_file *vmfile, struct tcb *task, void *buf, left = count; /* Copy the first page and unmap. */ - copysize = (left < PAGE_SIZE) ? left : PAGE_SIZE; + if (is_page_aligned(buf)) { + copysize = (left < PAGE_SIZE) ? left : PAGE_SIZE; + } else { + if (left < (PAGE_MASK & (unsigned long)buf)) + copysize = left; + else + copysize = (PAGE_MASK & + (unsigned long)buf); + } copy_offset = (unsigned long)buf; page_copy(head, task_virt_to_page(task, copy_offset), - cursor_offset, copy_offset & PAGE_MASK, copysize); + cursor_offset, copy_offset & PAGE_MASK, + copysize); head->flags |= VM_DIRTY; head->owner->flags |= VM_DIRTY; left -= copysize; @@ -928,10 +705,10 @@ int sys_read(struct tcb *task, int fd, void *buf, int count) struct vm_file *vmfile; int ret = 0; - /* Check fd validity */ - if (!task->files->fd[fd].vmfile) - if ((ret = file_open(task, fd)) < 0) - return ret; + /* Check that fd is valid */ + if (fd < 0 || fd > TASK_FILES_MAX || + !task->files->fd[fd].vmfile) + return -EBADF; /* Check count validity */ @@ -998,10 +775,10 @@ int sys_write(struct tcb *task, int fd, void *buf, int count) struct vm_file *vmfile; int ret = 0; - /* Check fd validity */ - if (!task->files->fd[fd].vmfile) - if ((ret = file_open(task, fd)) < 0) - return ret; + /* Check that fd is valid */ + if (fd < 0 || fd > TASK_FILES_MAX || + !task->files->fd[fd].vmfile) + return -EBADF; /* Check count validity */ if (count < 0) @@ -1009,7 +786,6 @@ int sys_write(struct tcb *task, int fd, void *buf, int count) else if (!count) return 0; - /* Check user buffer validity. */ if ((ret = pager_validate_user_range(task, buf, (unsigned long)count, @@ -1019,6 +795,8 @@ int sys_write(struct tcb *task, int fd, void *buf, int count) vmfile = task->files->fd[fd].vmfile; cursor = task->files->fd[fd].cursor; + printf("Thread %d writing to fd: %d, vnum: 0x%lx, vnode: %p\n", task->tid, fd, vmfile->vnode->vnum, vmfile->vnode); + /* See what pages user wants to write */ pfn_wstart = __pfn(cursor); pfn_wend = __pfn(page_align_up(cursor + count)); @@ -1098,10 +876,10 @@ int sys_lseek(struct tcb *task, int fd, off_t offset, int whence) int retval = 0; unsigned long long total, cursor; - /* Check fd validity */ - if (!task->files->fd[fd].vmfile) - if ((retval = file_open(task, fd)) < 0) - return retval; + /* Check that fd is valid */ + if (fd < 0 || fd > TASK_FILES_MAX || + !task->files->fd[fd].vmfile) + return -EBADF; /* Offset validity */ if (offset < 0) @@ -1179,7 +957,6 @@ int sys_readdir(struct tcb *t, int fd, int count, char *dirbuf) { int dirent_size = sizeof(struct dirent); int total = 0, nbytes = 0; - unsigned long vnum; struct vnode *v; struct dentry *d; char *buf = dirbuf; @@ -1193,14 +970,11 @@ int sys_readdir(struct tcb *t, int fd, int count, char *dirbuf) /* Check address is in task's utcb */ - if (fd < 0 || fd > TASK_FILES_MAX || !t->files->fd[fd].vnum) + if (fd < 0 || fd > TASK_FILES_MAX || + !t->files->fd[fd].vmfile->vnode) return -EBADF; - vnum = t->files->fd[fd].vnum; - - /* Lookup vnode */ - if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum))) - return -EINVAL; + v = t->files->fd[fd].vmfile->vnode; d = link_to_struct(v->dentries.next, struct dentry, vref); @@ -1232,3 +1006,239 @@ int sys_readdir(struct tcb *t, int fd, int count, char *dirbuf) return nbytes + total; } +/* FIXME: + * - Is it already open? + * - Check flags and mode. + */ +int sys_open(struct tcb *task, const char *pathname, + int flags, unsigned int mode) +{ + struct pathdata *pdata; + struct vnode *v; + struct vm_file *vmfile; + int retval; + int fd; + + + /* Parse path data */ + if (IS_ERR(pdata = pathdata_parse(pathname, + alloca(strlen(pathname) + 1), + task))) + return (int)pdata; + + /* Creating new file */ + if (flags & O_CREAT) { + /* Make sure mode identifies a file */ + mode |= S_IFREG; + + /* Create new vnode */ + if (IS_ERR(v = vfs_vnode_create(task, pdata, mode))) { + retval = (int)v; + goto out; + } + } else { + /* Not creating. Get the existing vnode */ + if (IS_ERR(v = vfs_vnode_lookup_bypath(pdata))) { + retval = (int)v; + goto out; + } + } + + /* Get a new fd */ + BUG_ON((fd = id_new(task->files->fdpool)) < 0); + retval = fd; + + /* Check if that vm_file is already in the list */ + list_foreach_struct(vmfile, &global_vm_files.list, list) { + + /* Compare vnode pointer */ + if (vmfile->vnode == v) { + /* Add a reference to it from the task */ + task->files->fd[fd].vmfile = vmfile; + + vmfile->openers++; + retval = 0; + goto out; + } + } + + /* Create a new vm_file for this vnode */ + if (IS_ERR(vmfile = vfs_file_create())) { + retval = (int)vmfile; + goto out; + } + + /* Assign file information */ + vmfile->vnode = v; + vmfile->length = vmfile->vnode->size; + + /* Add a reference to it from the task */ + vmfile->vm_obj.pager = &file_pager; + task->files->fd[fd].vmfile = vmfile; + vmfile->openers++; + + /* Add to file list */ + global_add_vm_file(vmfile); + +out: + if (retval < 0) + printf("Thread %d Opening %s, fd: %d, error: %d\n", task->tid, pathname, fd, retval); + else + printf("Thread %d Opening %s, fd: %d, vnum: %lx, vnode: %p\n", task->tid, pathname, fd, v->vnum, v); + pathdata_destroy(pdata); + return retval; +} + +#if 0 +/* + * Different from vfs_open(), which validates an already opened + * file descriptor, this call opens a new vfs file by the pager + * using the given path. The vnum handle and file length is returned + * since the pager uses this information to access file pages. + */ +int vfs_open_bypath(const char *pathname, unsigned long *vnum, unsigned long *length) +{ + struct pathdata *pdata; + struct tcb *task = 0; + struct vnode *v; + int retval; + + /* Parse path data */ + if (IS_ERR(pdata = pathdata_parse(pathname, + alloca(strlen(pathname) + 1), + task))) + return (int)pdata; + + /* Search the vnode by that path */ + if (IS_ERR(v = vfs_lookup_bypath(pdata))) { + retval = (int)v; + goto out; + } + + *vnum = v->vnum; + *length = v->size; + + return 0; + +out: + pathdata_destroy(pdata); + return retval; +} + +/* + * Initialise a new file and the descriptor for it from given file data. + * Could be called by an actual task or a pager + */ +struct vm_file *do_open2(struct tcb *task, int fd, unsigned long vnum, unsigned long length) +{ + struct vm_file *vmfile; + + /* Is this an open by a task (as opposed to by the pager)? */ + if (task) { + /* fd slot must be empty */ + BUG_ON(task->files->fd[fd].vnum != 0); + BUG_ON(task->files->fd[fd].cursor != 0); + + /* Assign vnum to given fd on the task */ + task->files->fd[fd].vnum = vnum; + task->files->fd[fd].cursor = 0; + } + + /* Check if that vm_file is already in the list */ + list_foreach_struct(vmfile, &global_vm_files.list, list) { + + /* Check whether it is a vfs file and if so vnums match. */ + if ((vmfile->type & VM_FILE_VFS) && + vm_file_to_vnum(vmfile) == vnum) { + + /* Task opener? */ + if (task) + /* Add a reference to it from the task */ + task->files->fd[fd].vmfile = vmfile; + + vmfile->openers++; + return vmfile; + } + } + + /* Otherwise allocate a new one for this vnode */ + if (IS_ERR(vmfile = vfs_file_create())) + return vmfile; + + /* Initialise and add a reference to it from the task */ + vm_file_to_vnum(vmfile) = vnum; + vmfile->length = length; + vmfile->vm_obj.pager = &file_pager; + + /* Task opener? */ + if (task) + task->files->fd[fd].vmfile = vmfile; + vmfile->openers++; + + /* Add to file list */ + global_add_vm_file(vmfile); + + return vmfile; +} + +/* + * When a task does a read/write/mmap request on a file, if + * the file descriptor is unknown to the pager, this call + * asks vfs if that file has been opened, and any other + * relevant information. + */ +int file_open(struct tcb *task, int fd) +{ + struct vnode *v; + struct vm_file *vmfile; + + if (fd < 0 || fd > TASK_FILES_MAX) + return -EINVAL; + + /* Check if that fd has been opened */ + if (!task->files->fd[fd].vnum) + return -EBADF; + + /* Search the vnode by that vnum */ + if (IS_ERR(v = vfs_lookup_byvnum(vfs_root.pivot->sb, + task->files->fd[fd].vnum))) + return (int)v; + + /* Cursor must be zero */ + BUG_ON(task->files->fd[fd].cursor != 0); + + /* Check that vm_file is already in the list */ + list_foreach_struct(vmfile, &global_vm_files.list, list) { + + /* Check whether it is a vfs file and if so vnums match. */ + if ((vmfile->type & VM_FILE_VFS) && + vm_file_to_vnum(vmfile) == v->vnum) { + + /* Add a reference to it from the task */ + task->files->fd[fd].vmfile = vmfile; + vmfile->openers++; + return 0; + } + } + + /* Otherwise allocate a new one for this vnode */ + if (IS_ERR(vmfile = vfs_file_create())) + return (int)vmfile; + + /* Assign file information */ + vm_file_to_vnum(vmfile) = v->vnum; + vmfile->length = v->size; + + /* Add a reference to it from the task */ + vmfile->vm_obj.pager = &file_pager; + task->files->fd[fd].vmfile = vmfile; + vmfile->openers++; + + /* Add to file list */ + global_add_vm_file(vmfile); + + return 0; +} + +#endif + diff --git a/conts/posix/mm0/mm/mmap.c b/conts/posix/mm0/mm/mmap.c index f0476e5..90b6972 100644 --- a/conts/posix/mm0/mm/mmap.c +++ b/conts/posix/mm0/mm/mmap.c @@ -328,13 +328,12 @@ void *__sys_mmap(struct tcb *task, void *start, size_t length, int prot, { unsigned int vmflags = 0; struct vm_file *file = 0; - int err; /* Check file validity */ if (!(flags & MAP_ANONYMOUS)) - if (!task->files->fd[fd].vmfile) - if ((err = file_open(task, fd)) < 0) - return PTR_ERR(err); + if (fd < 0 || fd > TASK_FILES_MAX || + !task->files->fd[fd].vmfile) + return PTR_ERR(-EBADF); /* Check file offset is page aligned */ if (!is_page_aligned(file_offset)) diff --git a/conts/posix/mm0/mm/pagers.c b/conts/posix/mm0/mm/pagers.c index ec8b0e1..c934263 100644 --- a/conts/posix/mm0/mm/pagers.c +++ b/conts/posix/mm0/mm/pagers.c @@ -13,6 +13,7 @@ #include #include #include +#include struct page *page_init(struct page *page) { @@ -97,11 +98,11 @@ int file_page_out(struct vm_object *vm_obj, unsigned long page_offset) /* Map the page to self */ l4_map(paddr, vaddr, 1, MAP_USR_RW_FLAGS, self_tid()); - //printf("%s/%s: Writing to vnode %lu, at pgoff 0x%lu, %d pages, buf at %p\n", - // __TASKNAME__, __FUNCTION__, vm_file_to_vnum(f), page_offset, 1, vaddr); + printf("%s/%s: Writing to vnode %lu, at pgoff 0x%lu, %d pages, buf at %p\n", + __TASKNAME__, __FUNCTION__, f->vnode->vnum, page_offset, 1, vaddr); /* Syscall to vfs to write page back to file. */ - if ((err = vfs_write(vm_file_to_vnum(f), page_offset, 1, vaddr)) < 0) + if ((err = vfs_write(f->vnode, page_offset, 1, vaddr)) < 0) goto out_err; /* Unmap it from self */ @@ -146,10 +147,13 @@ struct page *file_page_in(struct vm_object *vm_obj, unsigned long page_offset) l4_map(paddr, vaddr, 1, MAP_USR_RW_FLAGS, self_tid()); /* Syscall to vfs to read into the page. */ - if ((err = vfs_read(vm_file_to_vnum(f), page_offset, + if ((err = vfs_read(f->vnode, page_offset, 1, vaddr)) < 0) goto out_err; + printf("%s/%s: Reading into vnode %lu, at pgoff 0x%lu, %d pages, buf at %p\n", + __TASKNAME__, __FUNCTION__, f->vnode->vnum, page_offset, 1, vaddr); + /* Unmap it from vfs */ l4_unmap(vaddr, 1, self_tid()); l4_del_virtual(vaddr, 1); @@ -249,6 +253,7 @@ int bootfile_release_pages(struct vm_object *vm_obj) return 0; } +#if 0 /* Returns the page with given offset in this vm_object */ struct page *bootfile_page_in(struct vm_object *vm_obj, unsigned long offset) @@ -330,13 +335,26 @@ int init_boot_files(struct initdata *initdata) return 0; } +#endif + +/* + * FIXME: + * Problem is that devzero is a character device and we don't have a + * character device subsystem yet. + * + * Therefore even though the vm_file for devzero requires a vnode, + * currently it has no vnode field, and the information (the zero page) + * that needs to be stored in the dynamic vnode is now stored in the + * field file_private_data in the vm_file, which really needs to be + * removed. + */ /* Returns the page with given offset in this vm_object */ struct page *devzero_page_in(struct vm_object *vm_obj, unsigned long page_offset) { struct vm_file *devzero = vm_object_to_file(vm_obj); - struct page *zpage = devzero->priv_data; + struct page *zpage = devzero->private_file_data; BUG_ON(!(devzero->type & VM_FILE_DEVZERO)); @@ -381,7 +399,7 @@ int init_devzero(void) /* Allocate and initialise devzero file */ devzero = vm_file_create(); devzero->type = VM_FILE_DEVZERO; - devzero->priv_data = zpage; + devzero->private_file_data = zpage; devzero->length = page_align(~0UL); /* So we dont wraparound to 0! */ devzero->vm_obj.npages = __pfn(devzero->length); devzero->vm_obj.pager = &devzero_pager; diff --git a/conts/posix/mm0/mm/shm.c b/conts/posix/mm0/mm/shm.c index 055d2d6..7338bf1 100644 --- a/conts/posix/mm0/mm/shm.c +++ b/conts/posix/mm0/mm/shm.c @@ -25,8 +25,15 @@ #include #include +/* + * FIXME: + * + * All this stuff is stored as file_private_data in the vm_file. + * However they need to have a pseudo-fs infrastructure that + * stores all internals under the vnode->inode field. + */ #define shm_file_to_desc(shm_file) \ - ((struct shm_descriptor *)shm_file->priv_data) + ((struct shm_descriptor *)(shm_file)->private_file_data) /* Unique shared memory ids */ static struct id_pool *shm_ids; @@ -181,7 +188,7 @@ void shm_destroy_priv_data(struct vm_file *shm_file) BUG_ON(id_del(shm_ids, shm_desc->shmid) < 0); /* Now delete the private data itself */ - kfree(shm_file->priv_data); + kfree(shm_file_to_desc(shm_file)); } /* Creates an shm area and glues its details with shm pager and devzero */ @@ -213,7 +220,7 @@ struct vm_file *shm_new(key_t key, unsigned long npages) /* Initialise the file */ shm_file->length = __pfn_to_addr(npages); shm_file->type = VM_FILE_SHM; - shm_file->priv_data = shm_desc; + shm_file->private_file_data = shm_desc; shm_file->destroy_priv_data = shm_destroy_priv_data; /* Initialise the vm object */ diff --git a/conts/posix/mm0/mm/test.c b/conts/posix/mm0/mm/test.c index e04ab66..e84e67b 100644 --- a/conts/posix/mm0/mm/test.c +++ b/conts/posix/mm0/mm/test.c @@ -80,8 +80,6 @@ int mm0_test_global_vm_integrity(void) vmstat.vm_files++; if (f->type == VM_FILE_SHM) vmstat.shm_files++; - else if (f->type == VM_FILE_BOOTFILE) - vmstat.boot_files++; else if (f->type == VM_FILE_VFS) vmstat.vfs_files++; else if (f->type == VM_FILE_DEVZERO) diff --git a/conts/posix/mm0/mm/vm_object.c b/conts/posix/mm0/mm/vm_object.c index 1caf454..e5de25c 100644 --- a/conts/posix/mm0/mm/vm_object.c +++ b/conts/posix/mm0/mm/vm_object.c @@ -82,8 +82,6 @@ void vm_object_print(struct vm_object *vmo) if (f->type == VM_FILE_DEVZERO) ftype = "devzero"; - else if (f->type == VM_FILE_BOOTFILE) - ftype = "bootfile"; else if (f->type == VM_FILE_SHM) ftype = "shm file"; else if (f->type == VM_FILE_VFS) @@ -160,7 +158,6 @@ struct vm_file *vfs_file_create(void) if (IS_ERR(f)) return f; - f->priv_data = kzalloc(sizeof(struct vfs_file_data)); f->type = VM_FILE_VFS; return f; @@ -195,11 +192,11 @@ int vm_object_delete(struct vm_object *vmo) if (vmo->flags & VM_OBJ_FILE) { f = vm_object_to_file(vmo); BUG_ON(!list_empty(&f->list)); - if (f->priv_data) { + if (f->private_file_data) { if (f->destroy_priv_data) f->destroy_priv_data(f); else - kfree(f->priv_data); + kfree(f->private_file_data); } kfree(f); } else if (vmo->flags & VM_OBJ_SHADOW) diff --git a/conts/posix/test0/container.c b/conts/posix/test0/container.c index f9734f1..66af085 100644 --- a/conts/posix/test0/container.c +++ b/conts/posix/test0/container.c @@ -15,15 +15,15 @@ int main(int argc, char *argv[]); int __container_init(int argc, char **argv) { void *envp = &argv[argc + 1]; - char *pagerval; +// char *pagerval; if ((char *)envp == *argv) envp = &argv[argc]; __libposix_init(envp); - pagerval = getenv("pagerid"); - printf("Pager id: %s\n", pagerval); + //pagerval = getenv("pagerid"); + //printf("Pager id: %s\n", pagerval); /* Generic L4 thread initialisation */ __l4_init(); diff --git a/conts/posix/test0/include/tests.h b/conts/posix/test0/include/tests.h index d24b7e5..ba219b0 100644 --- a/conts/posix/test0/include/tests.h +++ b/conts/posix/test0/include/tests.h @@ -3,7 +3,7 @@ #define __TASKNAME__ "test0" -//#define TEST_VERBOSE_PRINT + #define TEST_VERBOSE_PRINT #if defined (TEST_VERBOSE_PRINT) #define test_printf(...) printf(__VA_ARGS__) #else diff --git a/conts/posix/test0/main.c b/conts/posix/test0/main.c index 4632d30..65dd75a 100644 --- a/conts/posix/test0/main.c +++ b/conts/posix/test0/main.c @@ -36,6 +36,7 @@ int main(int argc, char *argv[]) printf("\n%s: Running POSIX API tests.\n", __TASKNAME__); +/* dirtest(); mmaptest(); @@ -55,7 +56,7 @@ int main(int argc, char *argv[]) if (parent_of_all == getpid()) { user_mutex_test(); } - +*/ exectest(parent_of_all); while (1) diff --git a/conts/posix/test0/src/exectest.c b/conts/posix/test0/src/exectest.c index 9adbe8e..dc32e4b 100644 --- a/conts/posix/test0/src/exectest.c +++ b/conts/posix/test0/src/exectest.c @@ -1,15 +1,17 @@ /* * Execve test. */ - #include #include -#include #include +#include #include #include #include #include +#include + +#define PAGE_SIZE 0x1000 extern char _start_test_exec[]; extern char _end_test_exec[]; @@ -19,20 +21,25 @@ int exectest(pid_t parent_of_all) int fd, err; void *exec_start = (void *)_start_test_exec; unsigned long size = _end_test_exec - _start_test_exec; + char filename[128]; + char env_string[30]; int left, cnt; char *argv[5]; - char filename[128]; char *envp[2]; - char env_string[30]; + void *buf; memset(filename, 0, 128); - sprintf(filename, "/home/bahadir/execfile%d", getpid()); + sprintf(filename, "/execfile%d", getpid()); /* First create a new file and write the executable data to that file */ if ((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) { err = errno; test_printf("OPEN: %d, for %s\n", errno, filename); - /* If it is a minor error like EEXIST, create one with different name */ + + /* + * If it is a minor error like EEXIST, + * create one with different name + */ if (errno == EEXIST) { sprintf(filename, "/home/bahadir/execfile%d-2", getpid()); @@ -49,7 +56,7 @@ int exectest(pid_t parent_of_all) } left = size; - test_printf("Writing %d bytes to %s\n", left, filename); + test_printf("Writing %x bytes to %s\n", left, filename); while (left != 0) { if ((cnt = write(fd, exec_start, left)) < 0) goto out_err; @@ -60,6 +67,22 @@ int exectest(pid_t parent_of_all) goto out_err; } + /* Reopen */ + if ((fd = open(filename, O_RDONLY, S_IRWXU)) < 0) { + err = errno; + test_printf("OPEN: %d, for %s\n", errno, filename); + + } + + printf("Reopened %s\n", filename); + buf = alloca(PAGE_SIZE); + read(fd, buf, PAGE_SIZE); + + if (memcmp(exec_start, buf, PAGE_SIZE)) + printf("First page of read and written file doesn't match\n"); + else + printf("First page matches.\n"); + /* Set up some arguments */ argv[0] = "FIRST ARG"; argv[1] = "SECOND ARG"; diff --git a/conts/posix/test0/src/forktest.c b/conts/posix/test0/src/forktest.c index bb68203..9780685 100644 --- a/conts/posix/test0/src/forktest.c +++ b/conts/posix/test0/src/forktest.c @@ -17,7 +17,7 @@ int forktest(void) /* 16 forks */ - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 1; i++) { test_printf("%d: Forking...\n", getpid()); if (fork() < 0) goto out_err;