From a9420d3dc9ef19f6ca6728482981e2fe6acec0e3 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Tue, 15 Apr 2008 00:51:58 +0100 Subject: [PATCH] mkdir almost working. Added changes to pathname lookup code so that the root directory special case is handled properly. --- tasks/fs0/include/fs.h | 4 +-- tasks/fs0/include/path.h | 26 ++++++++++++++ tasks/fs0/include/vfs.h | 15 ++------ tasks/fs0/src/lib/pathstr.c | 4 --- tasks/fs0/src/lookup.c | 70 ++++++++++++++++++++++++++++++++----- tasks/fs0/src/memfs/file.c | 13 ++++--- tasks/fs0/src/memfs/memfs.c | 9 +++-- tasks/fs0/src/memfs/vnode.c | 11 +++--- tasks/fs0/src/syscalls.c | 47 ++++++++++++++++--------- tasks/fs0/src/vfs.c | 12 ++----- tasks/test0/src/dirtest.c | 14 ++++++++ 11 files changed, 159 insertions(+), 66 deletions(-) create mode 100644 tasks/fs0/include/path.h diff --git a/tasks/fs0/include/fs.h b/tasks/fs0/include/fs.h index 2758b8d..d60f685 100644 --- a/tasks/fs0/include/fs.h +++ b/tasks/fs0/include/fs.h @@ -10,7 +10,7 @@ #include #include #include - +#include typedef void (*vnode_op_t)(void); typedef void (*file_op_t)(void); @@ -46,7 +46,7 @@ struct file_ops { /* Operations that work on vnode fields and associations between vnodes */ struct vnode_ops { vnode_op_t create; - struct vnode *(*lookup)(struct vnode *root, char *path); + struct vnode *(*lookup)(struct vnode *root, struct pathdata *pdata); int (*readdir)(struct vnode *v); int (*filldir)(void *buf, struct vnode *v, int count); vnode_op_t link; diff --git a/tasks/fs0/include/path.h b/tasks/fs0/include/path.h new file mode 100644 index 0000000..fa86b97 --- /dev/null +++ b/tasks/fs0/include/path.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008 Bahadir Balban + * + * Path lookup related information + */ +#ifndef __PATH_H__ +#define __PATH_H__ + +/* + * FIXME: + * These ought to be strings and split/comparison functions should + * always use strings because formats like UTF-8 wouldn't work. + */ +#define VFS_CHAR_SEP '/' +#define VFS_STR_ROOTDIR "/" +#define VFS_STR_PARDIR ".." +#define VFS_STR_CURDIR "." +#define VFS_STR_XATDIR "...." + +struct pathdata { + struct tcb *task; + int root; + char *path; +}; + +#endif /* __PATH_H__ */ diff --git a/tasks/fs0/include/vfs.h b/tasks/fs0/include/vfs.h index 6b9122a..6000f82 100644 --- a/tasks/fs0/include/vfs.h +++ b/tasks/fs0/include/vfs.h @@ -8,20 +8,11 @@ #include #include #include +#include extern struct list_head vnode_cache; extern struct list_head dentry_cache; -/* - * FIXME: - * These ought to be strings and split/comparison functions should - * always use strings because formats like UTF-8 wouldn't work. - */ -#define VFS_STR_SEP '/' -#define VFS_STR_PARDIR ".." -#define VFS_STR_CURDIR "." -#define VFS_STR_XATDIR "...." - /* * This is a temporary replacement for page cache support provided by mm0. * Normally mm0 tracks all vnode pages, but this is used to track pages in @@ -91,8 +82,8 @@ struct vfs_mountpoint { 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 tcb *task, char *path); +struct vnode *generic_vnode_lookup(struct vnode *thisnode, struct pathdata *p); +struct vnode *vfs_lookup_bypath(struct tcb *task, struct pathdata *p); struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum); #endif /* __VFS_H__ */ diff --git a/tasks/fs0/src/lib/pathstr.c b/tasks/fs0/src/lib/pathstr.c index 738d419..8492da7 100644 --- a/tasks/fs0/src/lib/pathstr.c +++ b/tasks/fs0/src/lib/pathstr.c @@ -31,10 +31,6 @@ char *splitpath(char **str, char sep) char *cursor = *str; char *end; - /* Root is the special case, return it as is. */ - if (strcmp(*str, "/")) - return *str; - /* Move forward until no seperator */ while (*cursor == sep) { *cursor = '\0'; diff --git a/tasks/fs0/src/lookup.c b/tasks/fs0/src/lookup.c index effd865..410a017 100644 --- a/tasks/fs0/src/lookup.c +++ b/tasks/fs0/src/lookup.c @@ -14,47 +14,99 @@ * and their vnodes, this itself checks all those children on that level for * a match, but it also calls lookup, which recursively checks lower levels. */ -struct vnode *lookup_dentry_children(struct dentry *parentdir, char *path) +struct vnode *lookup_dentry_children(struct dentry *parentdir, + struct pathdata *pdata) { struct dentry *childdir; struct vnode *v; list_for_each_entry(childdir, &parentdir->children, child) /* Non-zero result means either found it or error occured */ - if ((v = childdir->vnode->ops.lookup(childdir->vnode, path))) + if ((v = childdir->vnode->ops.lookup(childdir->vnode, pdata))) return v; /* Out of all children dentries, neither was a match, so we return 0 */ return PTR_ERR(-ENOENT); } -/* Lookup, recursive, assuming single-mountpoint */ -struct vnode *generic_vnode_lookup(struct vnode *thisnode, char *path) +/* + * Check if we're really at root, return root string if so, and + * move the pdata string cursor to next component or the end of string. + */ +char *pathdata_handle_root(struct pathdata *pdata) { - char *component = splitpath(&path, VFS_STR_SEP); + char *cursor = pdata->path; + + /* Only handle if root */ + if (!pdata->root) + return 0; + + /* Move forward until no seperator */ + while (*cursor == VFS_CHAR_SEP) { + *cursor = '\0'; /* Zero out separators */ + cursor++; /* Move to next */ + } + + /* + * Moved the cursor either to first char of + * next component, or the end of string + * (in which case cursor = '\0') + */ + pdata->path = cursor; + + /* We have handled the root case, now turn it off */ + pdata->root = 0; + + /* + * Modified pdata appropriately, return the root + * component. It's the root representer string, e.g. "/" + */ + return VFS_STR_ROOTDIR; +} + +/* Lookup, recursive, assuming single-mountpoint */ +struct vnode *generic_vnode_lookup(struct vnode *thisnode, + struct pathdata *pdata) +{ + char *component; struct dentry *d; struct vnode *found; int err; + /* + * Determine first component, taking root as special case. + * + * path (root = 0) -> first path component + * path (root = 1) -> VFS_STR_ROOTDIR + * where path = { "//comp1/comp2", "/", "/comp1/comp2", "comp1/comp2" } + */ + + /* Handle the special root case */ + if (pdata->root) + component = pathdata_handle_root(pdata); + /* Handle paths normally */ + else + component = splitpath(&pdata->path, VFS_CHAR_SEP); + /* Does this path component match with any of this vnode's dentries? */ list_for_each_entry(d, &thisnode->dentries, vref) { if (d->ops.compare(d, component)) { /* Is this a directory? */ if (vfs_isdir(thisnode)) { /* Are there any more path components? */ - if (path) { + if (*pdata->path) { /* Read directory contents */ if ((err = d->vnode->ops.readdir(d->vnode)) < 0) return PTR_ERR(err); /* Search all children one level below. */ - if ((found = lookup_dentry_children(d, path))) + if ((found = lookup_dentry_children(d, pdata))) /* Either found, or non-zero error */ return found; } else return thisnode; } else { /* Its a file */ - if (path) /* There's still path, but not directory */ + if (*pdata->path) /* There's still path, but not directory */ return PTR_ERR(-ENOTDIR); else /* No path left, found it, so return file */ return thisnode; @@ -68,7 +120,7 @@ struct vnode *generic_vnode_lookup(struct vnode *thisnode, char *path) int generic_dentry_compare(struct dentry *d, char *name) { - if (!strcmp(d->name, name)) + if (!strcmp(d->name, name) || !strcmp(name, VFS_STR_CURDIR)) return 1; else return 0; diff --git a/tasks/fs0/src/memfs/file.c b/tasks/fs0/src/memfs/file.c index d9560fa..8649a50 100644 --- a/tasks/fs0/src/memfs/file.c +++ b/tasks/fs0/src/memfs/file.c @@ -93,7 +93,7 @@ int memfs_file_read_write(struct vnode *v, unsigned int pfn, } else { /* Write-specific operations */ /* Is the write beyond current file size? */ if (v->size < ((pfn + npages) * (blocksize))) { - unsigned long diff = pfn + npages - __pfn(v->size); + unsigned long pagediff = pfn + npages - __pfn(v->size); unsigned long holes; /* @@ -102,19 +102,18 @@ int memfs_file_read_write(struct vnode *v, unsigned int pfn, */ if (pfn > __pfn(v->size)) holes = pfn - __pfn(v->size); + else + holes = 0; /* Allocate new blocks */ - for (int x = 0; x < diff; x++) - if (!(i->block[__pfn(v->size) + x] = memfs_alloc_block(memfs_sb))) + for (int x = 0; x < pagediff; x++) + if (!(i->block[__pfn(v->size) + x] = + memfs_alloc_block(v->sb->fs_super))) return -ENOSPC; /* Zero out the holes. FIXME: How do we zero out non-page-aligned bytes?` */ for (int x = 0; x < holes; x++) memset(i->block[__pfn(v->size) + x], 0, blocksize); - - /* Update size and the inode. FIXME: How do we handle non page-aligned size */ - v->size = (pfn + npages) * blocksize; - v->sb->ops->write_vnode(v->sb, v); } /* Copy the data from page buffer into inode blocks */ diff --git a/tasks/fs0/src/memfs/memfs.c b/tasks/fs0/src/memfs/memfs.c index 61ed890..71c5eda 100644 --- a/tasks/fs0/src/memfs/memfs.c +++ b/tasks/fs0/src/memfs/memfs.c @@ -135,8 +135,13 @@ int memfs_init_rootdir(struct superblock *sb) if (!(d = vfs_alloc_dentry())) return -ENOMEM; - /* Initialise it. NOTE: On root, parent is itself */ - strncpy(d->name, "/", VFS_DNAME_MAX); + /* + * Initialise it. + * NOTE: On root, parent is itself. + * NOTE: Root has no name. This helps since splitpath + * cuts out the '/' and "" is left for root name search. + */ + strncpy(d->name, VFS_STR_ROOTDIR, VFS_DNAME_MAX); d->ops = generic_dentry_operations; d->parent = d; d->vnode = v; diff --git a/tasks/fs0/src/memfs/vnode.c b/tasks/fs0/src/memfs/vnode.c index 02f1348..650459c 100644 --- a/tasks/fs0/src/memfs/vnode.c +++ b/tasks/fs0/src/memfs/vnode.c @@ -228,8 +228,6 @@ int memfs_vnode_mknod(struct vnode *v, char *dirname, unsigned int mode) BUG_ON(parent->vref.next != &v->dentries); BUG_ON(!vfs_isdir(v)); - printf("Parent name: %s\n", parent->name); - /* Populate the children */ if ((err = v->ops.readdir(v)) < 0) return err; @@ -263,8 +261,9 @@ int memfs_vnode_mknod(struct vnode *v, char *dirname, unsigned int mode) /* Write the updated directory buffer back to disk block */ v->fops.write(v, 0, 1, v->dirbuf.buffer); - /* Update parent vnode */ + /* Update parent vnode size */ v->size += sizeof(*memfsd); + v->sb->ops->write_vnode(v->sb, v); /* Allocate a new vfs dentry */ if (!(newd = vfs_alloc_dentry())) @@ -382,7 +381,10 @@ int memfs_vnode_readdir(struct vnode *v) return 0; } - +/* + * Copies fs-specific dirent data into user buffer in + * generic struct dirent format. + */ int memfs_vnode_filldir(void *userbuf, struct vnode *v, int count) { int nbytes; @@ -412,6 +414,7 @@ struct vnode_ops memfs_vnode_operations = { .readdir = memfs_vnode_readdir, .filldir = memfs_vnode_filldir, .mknod = memfs_vnode_mknod, + .lookup = generic_vnode_lookup, }; struct superblock_ops memfs_superblock_operations = { diff --git a/tasks/fs0/src/syscalls.c b/tasks/fs0/src/syscalls.c index 5bcacd8..4f20f7f 100644 --- a/tasks/fs0/src/syscalls.c +++ b/tasks/fs0/src/syscalls.c @@ -43,21 +43,17 @@ int pager_sys_open(l4id_t sender, int fd, unsigned long vnum, unsigned long size } /* Creates a node under a directory, e.g. a file, directory. */ -int vfs_create(struct tcb *task, const char *pathname, unsigned int mode) +int vfs_create(struct tcb *task, struct pathdata *pdata, unsigned int mode) { - char *pathbuf = alloca(strlen(pathname) + 1); - char *parentpath = pathbuf; struct vnode *vparent; char *nodename; int err; - strcpy(pathbuf, pathname); - /* The last component is to be created */ - nodename = splitpath_end(&parentpath, '/'); + nodename = splitpath_end(&pdata->path, '/'); /* Check that the parent directory exists. */ - if (IS_ERR(vparent = vfs_lookup_bypath(task, parentpath))) + if (IS_ERR(vparent = vfs_lookup_bypath(task, pdata))) return (int)vparent; /* The parent vnode must be a directory. */ @@ -71,6 +67,17 @@ int vfs_create(struct tcb *task, const char *pathname, unsigned int mode) return 0; } +void init_path_data(struct pathdata *pdata, const char *pathname, + void *pathbuf, struct tcb *task) +{ + pdata->path = pathbuf; + strcpy(pdata->path, pathname); + pdata->task = task; + + if (pdata->path[0] == '/') + pdata->root = 1; +} + /* FIXME: * - Is it already open? * - Allocate a copy of path string since lookup destroys it @@ -78,24 +85,25 @@ int vfs_create(struct tcb *task, const char *pathname, unsigned int mode) */ int sys_open(l4id_t sender, const char *pathname, int flags, unsigned int mode) { - char *pathbuf = alloca(strlen(pathname) + 1); + struct pathdata pdata; struct vnode *v; struct tcb *task; int fd; int err; - strcpy(pathbuf, pathname); - /* Get the task */ BUG_ON(!(task = find_task(sender))); + /* Initialise pdata */ + init_path_data(&pdata, pathname, alloca(strlen(pathname) + 1), task); + /* Get the vnode */ - if (IS_ERR(v = vfs_lookup_bypath(task, pathbuf))) { + if (IS_ERR(v = vfs_lookup_bypath(task, &pdata))) { if (!(flags & O_CREAT)) { l4_ipc_return((int)v); return 0; } else { - if ((err = vfs_create(task, pathname, mode)) < 0) { + if ((err = vfs_create(task, &pdata, mode)) < 0) { l4_ipc_return(err); return 0; } @@ -123,27 +131,32 @@ int sys_close(l4id_t sender, int fd) int sys_mkdir(l4id_t sender, const char *pathname, unsigned int mode) { struct tcb *task; + struct pathdata pdata; /* Get the task */ BUG_ON(!(task = find_task(sender))); - l4_ipc_return(vfs_create(task, pathname, mode)); + /* Init path data */ + init_path_data(&pdata, pathname, alloca(strlen(pathname) + 1), task); + + l4_ipc_return(vfs_create(task, &pdata, mode)); return 0; } int sys_chdir(l4id_t sender, const char *pathname) { - char *pathbuf = alloca(strlen(pathname) + 1); struct vnode *v; struct tcb *task; - - strcpy(pathbuf, pathname); + struct pathdata pdata; /* Get the task */ BUG_ON(!(task = find_task(sender))); + /* Init path data */ + init_path_data(&pdata, pathname, alloca(strlen(pathname) + 1), task); + /* Get the vnode */ - if (IS_ERR(v = vfs_lookup_bypath(task, pathbuf))) + if (IS_ERR(v = vfs_lookup_bypath(task, &pdata))) return (int)v; /* Ensure it's a directory */ diff --git a/tasks/fs0/src/vfs.c b/tasks/fs0/src/vfs.c index 7a703f6..aa42f72 100644 --- a/tasks/fs0/src/vfs.c +++ b/tasks/fs0/src/vfs.c @@ -57,18 +57,12 @@ 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 tcb *task, char *path) +struct vnode *vfs_lookup_bypath(struct tcb *task, struct pathdata *pdata) { struct vnode *vstart; - /* Is it the root or current directory? If so, we already got it. */ - if (!strcmp(path, "/")) - return task->rootdir; - if (!strcmp(path, ".")) - return task->curdir; - /* Do we start from root or curdir? */ - if (path[0] == '/') + if (pdata->root) vstart = task->rootdir; else vstart = task->curdir; @@ -76,7 +70,7 @@ struct vnode *vfs_lookup_bypath(struct tcb *task, char *path) /* * This does vfs cache + fs lookup. */ - return generic_vnode_lookup(vstart, path); + return vstart->ops.lookup(vstart, pdata); } int vfs_mount_root(struct superblock *sb) diff --git a/tasks/test0/src/dirtest.c b/tasks/test0/src/dirtest.c index 49f8847..f7eea0c 100644 --- a/tasks/test0/src/dirtest.c +++ b/tasks/test0/src/dirtest.c @@ -136,6 +136,20 @@ int dirtest(void) printf("\nCreating directories: usr, etc, tmp, var, home, opt, bin, boot, lib, dev\n"); if (mkdir("/usr", 0) < 0) perror("MKDIR"); + if (mkdir("/etc", 0) < 0) + perror("MKDIR"); + if (mkdir("/tmp", 0) < 0) + perror("MKDIR"); + if (mkdir("/var", 0) < 0) + perror("MKDIR"); + if (mkdir("/bin", 0) < 0) + perror("MKDIR"); + if (mkdir("/boot", 0) < 0) + perror("MKDIR"); + if (mkdir("/lib", 0) < 0) + perror("MKDIR"); + if (mkdir("/dev", 0) < 0) + perror("MKDIR"); printf("\nlsdir root directory:\n"); lsdir("/");