diff --git a/tasks/fs0/include/fs.h b/tasks/fs0/include/fs.h index 2c22004..65454ed 100644 --- a/tasks/fs0/include/fs.h +++ b/tasks/fs0/include/fs.h @@ -86,7 +86,7 @@ struct dentry { struct list_head children; /* List of children dentries */ struct list_head vref; /* For vnode's dirent reference list */ struct list_head cache_list; /* Dentry cache reference */ - struct vnode *vnode; /* The vnode associated with dirent */ + struct vnode *vnode; /* The vnode associated with dentry */ struct dentry_ops ops; }; diff --git a/tasks/fs0/include/syscalls.h b/tasks/fs0/include/syscalls.h index 887d4d0..3b6a078 100644 --- a/tasks/fs0/include/syscalls.h +++ b/tasks/fs0/include/syscalls.h @@ -6,9 +6,16 @@ #ifndef __FS0_SYSCALLS_H__ #define __FS0_SYSCALLS_H__ +/* Posix calls */ int sys_open(l4id_t sender, char *pathname, int flags, u32 mode); -int sys_read(l4id_t sender, int fd, void *buf, int cnt); -int sys_write(l4id_t sender, int fd, void *buf, int cnt); -int sys_lseek(l4id_t sender, int fd, unsigned long offset, int whence); +int sys_readdir(l4id_t sender, int fd, void *buf, int count); +int sys_mkdir(l4id_t sender, const char *pathname, unsigned int mode); +int sys_chdir(l4id_t sender, const char *pathname); +/* Calls from pager that completes a posix call */ +int pager_sys_read(l4id_t sender, unsigned long vnum, unsigned long f_offset, + unsigned long npages, void *pagebuf); + +int pager_sys_write(l4id_t sender, unsigned long vnum, unsigned long f_offset, + unsigned long npages, void *pagebuf); #endif /* __FS0_SYSCALLS_H__ */ diff --git a/tasks/fs0/include/task.h b/tasks/fs0/include/task.h index b0aefb7..0c76ade 100644 --- a/tasks/fs0/include/task.h +++ b/tasks/fs0/include/task.h @@ -18,6 +18,8 @@ struct tcb { struct list_head list; int fd[TASK_OFILES_MAX]; struct id_pool *fdpool; + struct vnode *curdir; + struct vnode *rootdir; }; struct tcb *find_task(int tid); diff --git a/tasks/fs0/include/vfs.h b/tasks/fs0/include/vfs.h index e15e352..3d55d14 100644 --- a/tasks/fs0/include/vfs.h +++ b/tasks/fs0/include/vfs.h @@ -7,6 +7,7 @@ #include #include #include +#include extern struct list_head vnode_cache; extern struct list_head dentry_cache; @@ -92,7 +93,7 @@ extern struct vfs_mountpoint vfs_root; int vfs_mount_root(struct superblock *sb); struct vnode *generic_vnode_lookup(struct vnode *thisnode, char *path); -struct vnode *vfs_lookup_bypath(struct superblock *sb, char *path); +struct vnode *vfs_lookup_bypath(struct tcb *task, char *path); struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum); #endif /* __VFS_H__ */ diff --git a/tasks/fs0/main.c b/tasks/fs0/main.c index 5c65904..8e7f20a 100644 --- a/tasks/fs0/main.c +++ b/tasks/fs0/main.c @@ -33,10 +33,8 @@ * - Add mkdir * - Add create * - Add read/write -> This will need page cache and mm0 involvement. - */ - -/* TODO: - * Assign memfs dentry fields same as in posix + * + * Done those, too. but untested. */ /* Synchronise with pager via a `wait' tagged ipc with destination as pager */ @@ -74,16 +72,24 @@ void handle_fs_requests(void) printf("%s: Synced with waiting thread.\n", __TASKNAME__); break; case L4_IPC_TAG_OPEN: - sys_open(sender, (void *)mr[0], (int)mr[1], (u32)mr[2]); + sys_open(sender, (void *)mr[0], (int)mr[1], (unsigned int)mr[2]); break; - case L4_IPC_TAG_READ: - sys_read(sender, (int)mr[0], (void *)mr[1], (int)mr[2]); + case L4_IPC_TAG_MKDIR: + sys_mkdir(sender, (const char *)mr[0], (unsigned int)mr[1]); break; - case L4_IPC_TAG_WRITE: - sys_write(sender, (int)mr[0], (void *)mr[1], (int)mr[2]); + case L4_IPC_TAG_CHDIR: + sys_chdir(sender, (const char *)mr[0]); break; - case L4_IPC_TAG_LSEEK: - sys_lseek(sender, (int)mr[0], (int)mr[1], (int)mr[2]); + case L4_IPC_TAG_READDIR: + sys_readdir(sender, (int)mr[0], (void *)mr[1], (int)mr[2]); + break; + case L4_IPC_TAG_PAGER_READ: + pager_sys_read(sender, (unsigned long)mr[0], (unsigned long)mr[1], + (unsigned long)mr[2], (void *)mr[3]); + break; + case L4_IPC_TAG_PAGER_WRITE: + pager_sys_write(sender, (unsigned long)mr[0], (unsigned long)mr[1], + (unsigned long)mr[2], (void *)mr[3]); break; default: printf("%s: Unrecognised ipc tag (%d)" diff --git a/tasks/fs0/src/memfs/file.c b/tasks/fs0/src/memfs/file.c index 3f8a069..2315f53 100644 --- a/tasks/fs0/src/memfs/file.c +++ b/tasks/fs0/src/memfs/file.c @@ -16,7 +16,7 @@ #if 0 -/* +/* * FIXME: read_write() could be more layered using these functions. */ void *memfs_read_block(struct vnode *v, int blknum) diff --git a/tasks/fs0/src/memfs/memfs.c b/tasks/fs0/src/memfs/memfs.c index 42e8699..09d4494 100644 --- a/tasks/fs0/src/memfs/memfs.c +++ b/tasks/fs0/src/memfs/memfs.c @@ -66,6 +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); diff --git a/tasks/fs0/src/syscalls.c b/tasks/fs0/src/syscalls.c index 92b7acd..581475d 100644 --- a/tasks/fs0/src/syscalls.c +++ b/tasks/fs0/src/syscalls.c @@ -25,7 +25,7 @@ * for handling syscalls that access file content (i.e. read/write) since * it maintains the page cache. */ -int send_pager_sys_open(l4id_t sender, int fd, unsigned long vnum, unsigned long size) +int pager_sys_open(l4id_t sender, int fd, unsigned long vnum, unsigned long size) { int err; @@ -34,7 +34,7 @@ int send_pager_sys_open(l4id_t sender, int fd, unsigned long vnum, unsigned long write_mr(L4SYS_ARG2, vnum); write_mr(L4SYS_ARG3, size); - if ((err = l4_send(PAGER_TID, L4_IPC_TAG_PAGER_SYSOPEN)) < 0) { + if ((err = l4_send(PAGER_TID, L4_IPC_TAG_PAGER_OPEN)) < 0) { printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err); return err; } @@ -43,7 +43,7 @@ int send_pager_sys_open(l4id_t sender, int fd, unsigned long vnum, unsigned long } /* Creates a node under a directory, e.g. a file, directory. */ -int vfs_create(const char *pathname, unsigned int mode) +int vfs_create(struct tcb *task, const char *pathname, unsigned int mode) { char *pathbuf = alloca(strlen(pathname) + 1); char *parentpath = pathbuf; @@ -57,7 +57,7 @@ int vfs_create(const char *pathname, unsigned int mode) nodename = splitpath_end(&parentpath, '/'); /* Check that the parent directory exists. */ - if (IS_ERR(vparent = vfs_lookup_bypath(vfs_root.pivot->sb, parentpath))) + if (IS_ERR(vparent = vfs_lookup_bypath(task, parentpath))) return (int)vparent; /* The parent vnode must be a directory. */ @@ -80,58 +80,127 @@ int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode) { char *pathbuf = alloca(strlen(pathname) + 1); struct vnode *v; - struct tcb *t; + struct tcb *task; int fd; int err; strcpy(pathbuf, pathname); + /* Get the task */ + BUG_ON(!(task = find_task(sender))); + /* Get the vnode */ - if (IS_ERR(v = vfs_lookup_bypath(vfs_root.pivot->sb, pathbuf))) { + if (IS_ERR(v = vfs_lookup_bypath(task, pathbuf))) { if (!flags & O_CREAT) { return (int)v; } else { - if ((err = vfs_create(pathname, mode)) < 0) + if ((err = vfs_create(task, pathname, mode)) < 0) return err; } } - /* Get the task */ - BUG_ON(!(t = find_task(sender))); /* Get a new fd */ - BUG_ON(!(fd = id_new(t->fdpool))); + BUG_ON(!(fd = id_new(task->fdpool))); /* Assign the new fd with the vnode's number */ - t->fd[fd] = v->vnum; + task->fd[fd] = v->vnum; /* Tell the pager about opened vnode information */ - BUG_ON(send_pager_sys_open(sender, fd, v->vnum, v->size) < 0); + BUG_ON(pager_sys_open(sender, fd, v->vnum, v->size) < 0); return 0; } int sys_mkdir(l4id_t sender, const char *pathname, unsigned int mode) { - return vfs_create(pathname, mode); + struct tcb *task; + + /* Get the task */ + BUG_ON(!(task = find_task(sender))); + + return vfs_create(task, pathname, mode); } -int sys_read(l4id_t sender, int fd, void *buf, int count) +int sys_chdir(l4id_t sender, const char *pathname) { - return 0; -} + char *pathbuf = alloca(strlen(pathname) + 1); + struct vnode *v; + struct tcb *task; -int sys_write(l4id_t sender, int fd, const void *buf, int count) -{ - return 0; -} + strcpy(pathbuf, pathname); + + /* Get the task */ + BUG_ON(!(task = find_task(sender))); + + /* Get the vnode */ + if (IS_ERR(v = vfs_lookup_bypath(task, pathbuf))) + return (int)v; + + /* Ensure it's a directory */ + if (!vfs_isdir(v)) + return -ENOTDIR; + + /* Assign the current directory pointer */ + task->curdir = v; -int sys_lseek(l4id_t sender, int fd, int offset, int whence) -{ return 0; } /* - * Reads @count bytes of posix struct dirents into @buf + * Note this can be solely called by the pager and is not the posix read call. + * That call is in the pager. This merely supplies the pages the pager needs + * if they're not in the page cache. + */ +int pager_sys_read(l4id_t sender, unsigned long vnum, unsigned long f_offset, + unsigned long npages, void *pagebuf) +{ + struct vnode *v; + int err; + + if (sender != PAGER_TID) + return -EINVAL; + + /* Lookup vnode */ + if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum))) + return -EINVAL; /* No such vnode */ + + /* Ensure vnode is not a directory */ + if (vfs_isdir(v)) + return -EISDIR; + + if ((err = v->fops.read(v, f_offset, npages, pagebuf)) < 0) + return err; + + return 0; +} + +int pager_sys_write(l4id_t sender, unsigned long vnum, unsigned long f_offset, + unsigned long npages, void *pagebuf) +{ + struct vnode *v; + int err; + + if (sender != PAGER_TID) + return -EINVAL; + + /* Lookup vnode */ + if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum))) + return -EINVAL; /* No such vnode */ + + /* Ensure vnode is not a directory */ + if (vfs_isdir(v)) + return -EISDIR; + + if ((err = v->fops.write(v, f_offset, npages, pagebuf)) < 0) + return err; + + return 0; +} + +/* + * Reads @count bytes of posix struct dirents into @buf. This implements + * the raw dirent read syscall upon which readdir() etc. posix calls + * can be built in userspace. */ int sys_readdir(l4id_t sender, int fd, void *buf, int count) { diff --git a/tasks/fs0/src/task.c b/tasks/fs0/src/task.c index 2e7cde1..a9d992d 100644 --- a/tasks/fs0/src/task.c +++ b/tasks/fs0/src/task.c @@ -11,6 +11,8 @@ #include #include #include +#include + struct tcb_head { struct list_head list; @@ -88,10 +90,12 @@ int init_task_structs(l4id_t *tdata) struct tcb *t; int total = tdata[0]; - for (int i = 0; i < total; i++) + for (int i = 0; i < total; i++) { if (IS_ERR(t = create_tcb(tdata[1 + i]))) return (int)t; - + t->rootdir = vfs_root.pivot; + t->curdir = vfs_root.pivot; + } return 0; } diff --git a/tasks/fs0/src/vfs.c b/tasks/fs0/src/vfs.c index d52a5c2..bac17c1 100644 --- a/tasks/fs0/src/vfs.c +++ b/tasks/fs0/src/vfs.c @@ -5,6 +5,7 @@ */ #include #include +#include struct list_head vnode_cache; struct list_head dentry_cache; @@ -56,22 +57,25 @@ 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 superblock *sb, char *path) +struct vnode *vfs_lookup_bypath(struct tcb *task, char *path) { - /* If it's just / we already got it. */ + /* If it's the root or current dir, we already got it. */ if (!strcmp(path, "/")) - return sb->root; + return task->rootdir; + if (!strcmp(path, ".")) + return task->curdir; /* * This does vfs cache + fs lookup. */ - return generic_vnode_lookup(sb->root, path); + return generic_vnode_lookup(task->rootdir, path); } int vfs_mount_root(struct superblock *sb) { - /* Lookup the root vnode of this superblock */ - vfs_root.pivot = vfs_lookup_bypath(sb, "/"); + /* Lookup the root vnode of this superblock. + * The root superblock has vnode number 0. */ + vfs_root.pivot = vfs_lookup_byvnum(sb, 0); vfs_root.sb = sb; return 0; diff --git a/tasks/libl4/include/l4lib/ipcdefs.h b/tasks/libl4/include/l4lib/ipcdefs.h index 6e91472..b6a2a94 100644 --- a/tasks/libl4/include/l4lib/ipcdefs.h +++ b/tasks/libl4/include/l4lib/ipcdefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Bahadir Balban + * Copyright (C) 2007, 2008 Bahadir Balban * * This file contains ipc definitions that are needed for server tasks * to communicate with each other. For example common shared memory ids @@ -40,9 +40,14 @@ #define L4_IPC_TAG_CLOSE 16 #define L4_IPC_TAG_BRK 17 #define L4_IPC_TAG_READDIR 18 +#define L4_IPC_TAG_MKDIR 19 +#define L4_IPC_TAG_MMAP2 20 +#define L4_IPC_TAG_CHDIR 21 /* Tags for ipc between fs0 and mm0 */ -#define L4_IPC_TAG_PAGER_SYSOPEN 25 -#define L4_IPC_TAG_TASKDATA 26 +#define L4_IPC_TAG_TASKDATA 25 +#define L4_IPC_TAG_PAGER_OPEN 26 /* vfs sends the pager open file data. */ +#define L4_IPC_TAG_PAGER_READ 27 /* Pager reads file contents from vfs */ +#define L4_IPC_TAG_PAGER_WRITE 28 /* Pager writes file contents to vfs */ #endif /* __IPCDEFS_H__ */ diff --git a/tasks/mm0/include/syscalls.h b/tasks/mm0/include/syscalls.h index d8be7a7..390580c 100644 --- a/tasks/mm0/include/syscalls.h +++ b/tasks/mm0/include/syscalls.h @@ -24,6 +24,8 @@ struct sys_mmap_args { int sys_mmap(l4id_t sender, void *start, size_t length, int prot, int flags, int fd, off_t offset); +int sys_munmap(l4id_t sender, void *vaddr, unsigned long size); + struct sys_shmat_args { l4id_t shmid; const void *shmaddr; diff --git a/tasks/mm0/main.c b/tasks/mm0/main.c index fdb479a..38d6f10 100644 --- a/tasks/mm0/main.c +++ b/tasks/mm0/main.c @@ -65,6 +65,7 @@ void handle_requests(void) break; case L4_IPC_TAG_TASKDATA: + /* Send runnable task information to fs0 */ send_task_data(sender); break; @@ -84,7 +85,7 @@ void handle_requests(void) sys_shmdt(sender, (void *)mr[0]); break; - case L4_IPC_TAG_PAGER_SYSOPEN: + case L4_IPC_TAG_PAGER_OPEN: /* vfs opens a file and tells us about it here. */ vfs_receive_sys_open(sender, (l4id_t)mr[0], (int)mr[1], (unsigned long)mr[2], (unsigned long)mr[3]); @@ -98,19 +99,24 @@ void handle_requests(void) sys_write(sender, (int)mr[0], (void *)mr[1], (int)mr[2]); break; + case L4_IPC_TAG_MMAP2: { + struct sys_mmap_args *args = (struct sys_mmap_args *)mr[0]; + sys_mmap(sender, args->start, args->length, args->prot, + args->flags, args->fd, args->offset); + } case L4_IPC_TAG_MMAP: { struct sys_mmap_args *args = (struct sys_mmap_args *)&mr[0]; - BUG(); /* FIXME: There are 8 arguments to ipc whereas there are 7 mrs available. Fix this by increasing MRs to 8 ??? */ - sys_mmap(sender, args->start, args->length, args->prot, args->flags, args->fd, args->offset); + sys_mmap(sender, args->start, args->length, args->prot, + args->flags, args->fd, __pfn(args->offset)); break; } case L4_IPC_TAG_BRK: { // sys_brk(sender, (void *)mr[0]); // break; } + case L4_IPC_TAG_MUNMAP: { - /* TODO: Use arg struct instead */ -// sys_munmap(sender, (void *)mr[0], (int)mr[1]); + sys_munmap(sender, (void *)mr[0], (unsigned long)mr[1]); break; } case L4_IPC_TAG_MSYNC: { diff --git a/tasks/mm0/src/mmap.c b/tasks/mm0/src/mmap.c index 9230138..74a063f 100644 --- a/tasks/mm0/src/mmap.c +++ b/tasks/mm0/src/mmap.c @@ -194,7 +194,6 @@ struct vm_area *vma_split(struct vm_area *vma, struct tcb *task, if (!(new = vma_new(0, 0, 0, 0, 0))) return 0; - /* * Some sanity checks to show that splitter range does end up * producing two smaller vmas. @@ -367,6 +366,15 @@ pgtable_unmap: return 0; } +int sys_munmap(l4id_t sender, void *vaddr, unsigned long size) +{ + struct tcb *task; + + BUG_ON(!(task = find_task(sender))); + + return do_munmap(vaddr, size, task); +} + static struct vm_area * is_vma_mergeable(unsigned long pfn_start, unsigned long pfn_end, unsigned int flags, struct vm_area *vma) @@ -480,15 +488,35 @@ int do_mmap(struct vm_file *mapfile, unsigned long f_offset, struct tcb *t, /* mmap system call implementation */ int sys_mmap(l4id_t sender, void *start, size_t length, int prot, - int flags, int fd, off_t offset) + int flags, int fd, unsigned long pfn) { + unsigned long npages = __pfn(page_align_up(length)); + struct tcb * task; + int err; + + BUG_ON(!(task = find_task(sender))); + + if (fd < 0 || fd > TASK_OFILES_MAX) + return -EINVAL; + + if ((unsigned long)start < USER_AREA_START || (unsigned long)start >= USER_AREA_END) + return -EINVAL; + + /* TODO: + * Check that @start does not already have a mapping. + * Check that pfn + npages range is within the file range. + * Check that posix flags passed match those defined in vm_area.h + */ + if ((err = do_mmap(task->fd[fd].vmfile, __pfn_to_addr(pfn), task, + (unsigned long)start, flags, npages)) < 0) + return err; + return 0; } /* Sets the end of data segment for sender */ int sys_brk(l4id_t sender, void *ds_end) { - // do_brk(find_task(sender), ds_end); return 0; } diff --git a/tasks/mm0/src/task.c b/tasks/mm0/src/task.c index 2cdee93..e99c6e3 100644 --- a/tasks/mm0/src/task.c +++ b/tasks/mm0/src/task.c @@ -173,6 +173,7 @@ error: BUG(); } + void init_pm(struct initdata *initdata) { start_boot_tasks(initdata, &tcb_head);