1) explain dir_namev(const char *pathname, size_t *namelen, const char **name, vnode_t *base, vnode_t **res_vnode) a) Explain the following: For example: dir_namev("/s5fs/bin/ls", &namelen, &name, NULL, &res_vnode) would put 2 in namelen, "ls" in name, and a pointer to the vnode corresponding to "/s5fs/bin" in res_vnode. i) it should say that name POINTS to "ls" 2) "./weenix -n" means starting with a blank disk - i.e., the only thing in the disk is the root directory a) the root inode is "cached" inside the OS b) there is something called "vfs_root_vn" mentioned in dir_namev() c) grep vfs_root_vn kernel/*/*.c kernel/fs/namev.c: * vfs_root_vn. dir_namev() should call lookup() to take care of resolving each kernel/fs/vfs.c:vnode_t *vfs_root_vn; kernel/fs/vfs.c: * - set vfs_root_vn appropriately kernel/fs/vfs.c: vfs_root_vn = fs->fs_root; kernel/fs/vfs.c: fs->fs_mtpt = vfs_root_vn; kernel/fs/vfs.c: KASSERT(vfs_root_vn); kernel/fs/vfs.c: vn = vfs_root_vn; kernel/fs/vfs.c: vfs_root_vn = NULL; /* not /really/ necessary... */ d) vfs_root_vn is AFS-independent and is a polymorphic pointer, how/where/when does this pointer get "bound"? kernel/fs/vfs.c: vfs_root_vn = fs->fs_root; assigning a value to a polymorphic pointer is sometimes known as "binding" e) fs is the AFS and its interface is fs->fs_op, what functions can be reached via this interface? What does a "file system" object do? look at "kernel/include/fs/vfs.h" for the definition of fs_ops_t (something_ops_t is an array of function pointers): read_vnode(vn): "initialize" vnode vn (bind pointers inside vn) delete_vnode(vn): opposite of read_vnode(vn) query_vnode(vn): check if inode's link count is > 1 umount(fs): unmount the file system fs so, basically, a "file system" object is used to initialize newly created vnodes! e) fs is the AFS and its interface is fs->fs_op, how do you call an AFS-specific file system function? How do you call through a polymorphic pointer? grep fs_op kernel/*/*.c kernel/fs/pipe.c:static fs_ops_t pipe_fsops = { kernel/fs/pipe.c: .fs_op = &pipe_fsops, kernel/fs/vfs.c: if (vn->vn_fs->fs_op->umount) { kernel/fs/vfs.c: ret = vn->vn_fs->fs_op->umount(fs); kernel/fs/vnode.c: KASSERT(vn->vn_fs->fs_op && vn->vn_fs->fs_op->read_vnode); kernel/fs/vnode.c: vn->vn_fs->fs_op->read_vnode(vn); kernel/fs/vnode.c: && !vn->vn_fs->fs_op->query_vnode(vn)) { kernel/fs/vnode.c: if (vn->vn_fs->fs_op->delete_vnode) { kernel/fs/vnode.c: vn->vn_fs->fs_op->delete_vnode(vn); 3) grep vn_ops kernel/fs/*.c kernel/fs/file.c: if (vn->vn_ops->acquire) { kernel/fs/file.c: vn->vn_ops->acquire(vn, f); kernel/fs/file.c: if (vn->vn_ops->release) { kernel/fs/file.c: vn->vn_ops->release(vn, f); kernel/fs/pipe.c: vnode->vn_ops = &pipe_vops; kernel/fs/vfs_syscall.c: * Finally call the dir's mkdir vn_ops. Return what it returns. kernel/fs/vfs_syscall.c: * o call the destination dir's (to) link vn_ops. kernel/fs/vn_mmobj_ops.c: return v->vn_ops->fillpage(v, (int)PN_TO_ADDR(pf->pf_pagenum), pf->pf_addr); kernel/fs/vn_mmobj_ops.c: return v->vn_ops->dirtypage(v, (int) PN_TO_ADDR(pf->pf_pagenum)); kernel/fs/vn_mmobj_ops.c: return v->vn_ops->cleanpage(v, (int) PN_TO_ADDR(pf->pf_pagenum), pf->pf_addr); kernel/fs/vnode.c: vn->vn_ops = &bytedev_spec_vops; kernel/fs/vnode.c: vn->vn_ops = &blockdev_spec_vops; kernel/fs/vnode.c: KASSERT(vnode->vn_fs->fs_root->vn_ops->stat != NULL); kernel/fs/vnode.c: return vnode->vn_fs->fs_root->vn_ops->stat(vnode, ss); a) vn_ops contains the address of an array of function pointers (&bytedev_spec_vops or &blockdev_spec_vops) b) you don't have to call a function using the (func_name)(...) syntax, you can just do func_name(...) 4) vnode is complicated, it has a bunch of polymorphic pointers: struct vnode_ops *vn_ops; struct fs *vn_fs; void *vn_i; bytedev_t *vn_cdev; blockdev_t *vn_bdev; 5) important to understand vget(), vref(), vput(): vnode_t *vget(struct fs *fs, ino_t vno): given, inode number vno, find inode in fs and return corresponding vnode if such inode already has a corresponding vnode, return that vnode (and increment refcount on that vnode) if such inode does not have a corresponding vnode, create a vnode for it and set refcount to 1 Note: this is where a vnode gets created! void vref(vnode_t *vn): increment refcount void vput(vnode_t *vn): decrement refcount, if refcount reaches 0, free it look at all the dbg(DBG_VNREF, ...) calls in these functions! to turn these code on, include "vnref" in DBG in Config.mk 6) grep vn_ops kernel/fs/*/*.c kernel/fs/ramfs/ramfs.c: vn->vn_ops = &ramfs_file_vops; kernel/fs/ramfs/ramfs.c: vn->vn_ops = &ramfs_dir_vops; kernel/fs/ramfs/ramfs.c: vn->vn_ops = NULL; kernel/fs/ramfs/ramfs.c: vn->vn_ops = NULL; a) vn_ops contains the address of an array of function pointers (&ramfs_file_vops or &ramfs_dir_vops) i) where is vn->vn_ops set? in ramfs_read_vnode() ii) what is ramfs_read_vnode()? it's a member of ramfs_ops (which is an array of function pointers) 7) look at kernel/fs/vfs_syscall.c a) read the comment for do_read() 8) look at kernel/test/vfstest/vfstest.c a) read the code for paths_equal(p1,p2) b) read the code for syscall_fail(expr,err) 9) look at kernel/fs/faber_fs_test.c a) read faber_fs_thread_test() and faber_directory_test() they are kshell commands and not first procedures