Assignment/VFS

From WoxWiki

Jump to: navigation, search
Assignment Out: Oct. 12 (Monday)
Assignment Due: Oct. 26 (Monday 11:59PM)

This is the section CS169-only project in which you will be writing a virtual file system. CS167 students have a similar, but separate project here.

Please remember to read the course Programming Guide for good style guidelines.

Contents

Introduction

The virtual file system (VFS) is an interface providing a clearly defined link between the operating system kernel and the various file systems. The VFS makes it simple to add many different file systems to your kernel and give them a single UNIX-style interfaced: with a VFS, you can play music by writing to /dev/audio, you can list your processes by reading /proc/, and things you don't want to see to /dev/null. Once of the reason Linux has taken over the world is that it supports lots of different file systems -- e.g. users who don't want to copy all of their Windows files over to a Linux file system can keep them safely on an NTFS partition.l

In this assignment, as before, we will be giving you a bunch of header files and method declarations. You will supply most of the implementation. You will be working in the vfs/ directory of your source tree. You will be manipulating the kernel data structures for files (file_t and vnode_t) by writing much of UNIX's system call interface. We will be providing you with a simple in-memory file system for testing (testfs). You will also need to write the special files to interact with devices.

There is a large section in the Hackers Guide dedicated to the VFS, you should definitely read it before starting.

Mounting

Before a file can be accessed, the file system containing the file must be mounted (a scary-sounding term for setting a couple of pointers). In standard UNIX, a superuser can use the system call mount(2) to do this. In your Weenix there is only one file system, and it will be mounted internally at bootstrap time.

In idleproc a call is made to vfs_init(). This in turn calls mountproc() to mount the file system of type VFS_ROOTFS_TYPE. In the final implementation of Weenix the root file system type will be "s5fs", but since you have not implemented that yet you will be using "testfs", which is an in-memory file system that provides all of the operations of a S5FS except link and getpage.

The mounted file system is represented by a fs_t structure that is dynamically allocated at mount time.

Note that you do not have to handle mounting a file system on top of an existing file system, or deal with mount point issues, but you may implement it if you so desire, see the additional features page for details.

The Assignment

The following is a brief check-list of all the features which you will be adding to Weenix in this assignment:

  • Setting up the file system: vfs.c vnode.c file.c
  • The "testfs" file system: testfs.c (mostly provided)
  • Path name to vnode conversion: namev.c
  • Opening files: open.c
  • VFS syscall implementation: vfs_syscall.c

Code Overview

We now go into the function by function breakdown of the assignment.

Setting up the File System

Functions you should take note of in vfs/vfs.c:

    int vfs_init(void);

Functions you should take note of in vfs/vnode.c:

    void     vnode_init (void);
    vnode_t *vget      (struct fs *fs, int vno);
    void     vput       (vnode_t *vn);
    void     vref       (vnode_t *vn);

See the Hackers Guide for information about reference counting.

Functions you should take note of in vfs/file.c:

    void    file_init(void);
    file_t *fget(int fd);
    void    fput(file_t *f);
    void    fref(file_t *f);

See the Hackers Guide for information about reference counting.

Functions you should write in vfs/vnode.c:

    int special_file_read  (vnode_t *file, int offset, void *buf, int count);
    int special_file_write (vnode_t *file, int offset, void *buf, int count);

The "testfs" File System

The "testfs" file system is an extremely simple file system that provides a basic implementation of all the file system operations except link() and getpage(). Of course there is no need for getpage() until VM and link() is not implemented because it would require reference counting. We decided not to implement reference counting because it reduces the complexity of the code. This makes the code easier to understand and makes the one function you need to implement easier.

Of course this simplicity comes at a cost. For instance, "testfs" does not support multiple processes very well. Since there are no reference counts, once process can delete a file that another process has open and the kernel will do nothing about it. Keep this in mind when testing.

Functions you need to write in vfs/testfs.c:

    int testfs_readdir (vnode_t *dir, int offset, struct dirent *d);

Pathname to vnode Conversion

At this point you will have a file system mounted, but still no way to convert a pathname into the vnode associated with the file at that path. This is where the namev.c functions come into play.

There are multiple functions which work together to implement all of our name-to-vnode conversion needs. We will give you a summary in the source code comments and you will implement them all. Keeping track of vnode reference counts can be tricky here. Copious commenting and dbg() will serve you well. Finally, do not forget that lookup() takes care of the special case where name is ".." in a root directory.

Functions you will need to implement in vfs/namev.c:

    int lookup     (vnode_t *dir, const char *name, int len, vnode_t **result);
    int dir_namev  (const char *pathname, int *namelen, const char **name, vnode_t *base, vnode_t **res_vnode);
    int open_namev (const char *pathname, int flag, int mode, vnode_t **res_vnode, vnode_t *base);

Opening Files

The functions herein will allow you to actually open files in a process. When you have open files you should have some sort of protection mechanism so that one process cannot delete a file that another process is using. You can do that either here or in the S5 layer. Although the choice is up to you, it is somewhat easier to do it in the S5 layer and not worry about it here.

Functions you will need to write in vfs/open.c:

    int do_open (const char *filename, in oflags);

VFS Syscall Implementation

At this point you have mounted your "testfs", can look up paths in it, and open files. Now you want to write the code that will allow you to interface with your file system from user space. When a user space program makes a call to read(2), your do_read() function will eventually be called. Thus you must be vigilant in checking for any and all types of errors that might occur (after all you are dealing with "user" input now) and return the appropriate error code.

Note that for each of these functions, it is Weenix convention that you will handle error conditions by returning -errno if there is an error (not -1 as will eventually be returned to the user). A return value less than zero is assumed to be an error. You should read corresponding syscall man pages for hints on both errno return values and the implementation of these functions. Read the manpage for errno for a breakdown of what all the error values mean. This may look like a lot of functions, but you write one syscall, it is easy to get all of them. Pay attention to the comments and use a lot of dbg().

Functions you will need to write in vfs/vfs_syscall.c:

    int do_read    (int fd, void *buf, size_t nbytes);
    int do_write   (int fd, const void *buf, size_t nbytes);
    int do_close   (int fd);
    int do_dup     (int fd);
    int do_dup2    (int ofd, int nfd);
    int do_mknod   (const char *path, int mode, unsigned devid);
    int do_mkdir   (const char *path);
    int do_rmdir   (const char *path);
    int do_unlink  (const char *path);
    int do_link    (const char *from, const char *to);
    int do_rename  (const char *oldname, const char *newname);
    int do_chdir   (const char *const char path);
    int do_getdent (int fd, struct dirent *dirp);
    int do_lseek   (int fd, int offset, int whence);
    int do_stat    (const char *path, struct stat *buf);

Test Code

You should have lots of good test code. What does this mean? It means that you should be able to demonstrate fairly clearly -- via tty I/O and debug statements -- that you have successfully implemented as much as possible without having S5FS yet. Moreover, you want to be sure that you reference counts are correct (when your Weenix shuts down, vfs_shutdown() will check reference counts and panic if something is wrong). Basically, convince yourself that this works and get ready for the next assignment -- implementing the real file system.

To help your test code we have included a kernel-mode version of the vfstest program you will see again once you have a user space. You can find it in vfs/vfs_privtest.c. This is not a complete test suite. If you are able to run it and have your Weenix shutdown without panicking you are off to a good start, but this is not sufficient.

Compilation

Remember to turn the VFS project on in your Makefile.defines and make clean your project before you try to run your changes.

Handing In

As with kern, you are required to hand in your kernel when you are done with the assignment. This is because we like to keep a close eye on your progress. Remember your grade is based on your demo and not your hadning, so do a good job with your demo. Hand in using the following command:

    $ make clean;/course/cs169/bin/cs169_handin vfs
Personal tools