diff --git a/README b/README index 7e1ab74..c8db758 100644 --- a/README +++ b/README @@ -46,7 +46,7 @@ MM0 is the systm 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. -FS0 is the system task implements a simple, modern virtual filesystem layer. +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. diff --git a/tasks/fs0/include/fs.h b/tasks/fs0/include/fs.h index 112d3e7..c34faf2 100644 --- a/tasks/fs0/include/fs.h +++ b/tasks/fs0/include/fs.h @@ -47,7 +47,7 @@ struct file_ops { struct vnode_ops { vnode_op_t create; struct vnode *(*lookup)(struct vnode *root, char *path); - void * (*readdir)(struct vnode *v, void *dirbuf); + void *(*readdir)(struct vnode *v, void *dirbuf); vnode_op_t link; vnode_op_t unlink; vnode_op_t mkdir; @@ -97,6 +97,7 @@ struct vnode { struct file_ops fops; /* File-related operations on this vnode */ struct list_head dentries; /* Dirents that refer to this vnode */ struct list_head state_list; /* List for vnode's dirty/clean state */ + struct list_head cache_list; /* For adding the vnode to vnode cache */ u32 type; /* Vnode type, dev? socket? dir? ... */ u32 mode; /* Permissions */ u32 owner; /* Owner */ diff --git a/tasks/fs0/include/memfs/memfs.h b/tasks/fs0/include/memfs/memfs.h index 7d87e8d..eae95e6 100644 --- a/tasks/fs0/include/memfs/memfs.h +++ b/tasks/fs0/include/memfs/memfs.h @@ -75,8 +75,9 @@ struct memfs_superblock { #define MEMFS_DNAME_MAX 32 struct memfs_dentry { - u32 inum; /* Inode number */ - u32 nlength; /* Name length */ + u32 inum; /* Inode number */ + u32 offset; /* Dentry offset in its buffer */ + u32 rlength; /* Record length */ u8 name[MEMFS_DNAME_MAX]; /* Name string */ }; diff --git a/tasks/fs0/include/vfs.h b/tasks/fs0/include/vfs.h index b753d1f..037f21f 100644 --- a/tasks/fs0/include/vfs.h +++ b/tasks/fs0/include/vfs.h @@ -6,6 +6,17 @@ #include #include +/* Buffer to keep directory content. This is the only vnode content + * that fs0 maintains. All other file data is in mm0 page cache. + */ +struct dirbuf { + struct list_head list; + unsigned long bufsize; + u8 *buffer; +}; +extern struct list_head vnode_cache; +extern struct list_head dentry_cache; + /* * FIXME: * These ought to be strings and split/comparison functions should @@ -58,12 +69,16 @@ static inline struct vnode *vfs_alloc_vnode(void) INIT_LIST_HEAD(&v->dentries); INIT_LIST_HEAD(&v->state_list); + INIT_LIST_HEAD(&v->cache_list); + list_add(&v->cache_list, &vnode_cache); return v; } static inline void vfs_free_vnode(struct vnode *v) { + BUG(); /* Are the dentries freed ??? */ + list_del(&v->cache_list); kfree(v); } @@ -84,6 +99,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(struct superblock *sb, char *path); +struct vnode *vfs_lookup_bypath(struct superblock *sb, 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 a3d074f..ebd28b0 100644 --- a/tasks/fs0/main.c +++ b/tasks/fs0/main.c @@ -16,6 +16,19 @@ #include #include +/* + * TODO: + * - Have a dentry cache searchable by name + * - Have a vnode cache searchable by vnum (and name?) + * - fs-specific readdir would read contents by page range, and add vnodes/dentries + * to their caches, while populating the directory vnode being read. + * - Have 2 vfs_lookup() flavors, one that searches a path, one that searches a vnum. + * - dirbuf is either allocated by low-level readdir, or else by a higher level, i.e. + * either high-level vfs code, or the mm0 page cache. + * - readdir provides a posix-compliant dirent structure list in dirbuf. + * - memfs dentries should be identical to posix struct dirents. + */ + /* Synchronise with pager via a `wait' tagged ipc with destination as pager */ void wait_pager(l4id_t partner) { diff --git a/tasks/fs0/src/init.c b/tasks/fs0/src/init.c index 07a35aa..307548f 100644 --- a/tasks/fs0/src/init.c +++ b/tasks/fs0/src/init.c @@ -75,6 +75,8 @@ int initialise(void) memfs_format_filesystem(rootdev_blocks); INIT_LIST_HEAD(&vm_file_list); + INIT_LIST_HEAD(&vnode_cache); + INIT_LIST_HEAD(&dentry_cache); /* Search for a filesystem on the root device */ BUG_ON(IS_ERR(root_sb = vfs_probe_filesystems(rootdev_blocks))); diff --git a/tasks/fs0/src/syscalls.c b/tasks/fs0/src/syscalls.c index 4039de7..19a50de 100644 --- a/tasks/fs0/src/syscalls.c +++ b/tasks/fs0/src/syscalls.c @@ -91,6 +91,7 @@ int sys_read(l4id_t sender, int fd, void *buf, int count) int sys_readdir(l4id_t sender, int fd, void *buf, int count) { struct vnode *v; + struct tcb *t; /* Get the task */ BUG_ON(!(t = find_task(sender))); @@ -104,7 +105,7 @@ int sys_readdir(l4id_t sender, int fd, void *buf, int count) /* Simply read its contents */ v->ops.readdir(v, buf, count); -` + return 0; } diff --git a/tasks/fs0/src/vfs.c b/tasks/fs0/src/vfs.c index 997fee1..27e2734 100644 --- a/tasks/fs0/src/vfs.c +++ b/tasks/fs0/src/vfs.c @@ -6,12 +6,49 @@ #include #include -struct vnode *vfs_lookup(struct superblock *sb, char *path) +struct list_head vnode_cache; +struct list_head dentry_cache; + +/* + * Vnodes in the vnode cache have 2 keys. One is their dentry names, the other + * is their vnum. This one checks the vnode cache by the given vnum first. + * If nothing is found, it reads the vnode from disk into cache. + */ +struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum) +{ + struct vnode *v; + + /* Check the vnode cache by vnum */ + list_for_each_entry(v, vnode_cache, cache_list) + if (v->vnum == vnum) + return v; + + /* Otherwise ask the filesystem: + * TODO: + * vfs_alloc_vnode() -> This should also add the empty vnode to vnode cache. + * read_vnode() -> read it from filesystem. + * return what's read. + */ +} + +/* + * Vnodes in the vnode cache have 2 keys. One is their dentry name, 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) { /* If it's just / we already got it. */ if (!strcmp(path, "/")) return sb->root; + /* TODO: Check the vnode cache by path component + * + * This should split the path into components and compare + * each of them with each vnode's dentry list. + */ + + /* It's not in the cache, look it up from filesystem. */ return sb->root->ops.lookup(sb->root, path); } @@ -28,7 +65,7 @@ struct vfs_mountpoint vfs_root; int vfs_mount_root(struct superblock *sb) { /* Lookup the root vnode of this superblock */ - vfs_root.pivot = vfs_lookup(sb, "/"); + vfs_root.pivot = vfs_lookup_bypath(sb, "/"); vfs_root.sb = sb; return 0;