CS 161: Operating Systems

Tuesday/Thursday 1:00-2:30

Pierce 301

Home Syllabus Assignments Resources Piazza

Using SFS

This is a brief handout that explains how to format, mount, and use SFS volumes in OS/161.

Disk Devices and Images

The disks you configure in System/161 are probed by OS/161 and numbered in the order they're found on the system bus. The first disk is lhd0 (LAMEbus Hard Drive #0), the second is lhd1, etc. The data for each disk is kept in the file named in sys161.conf; in the default configuration the data for lhd0 appears in LHD0.img and the data for lhd1 appears in LHD1.img. The disk image files contain a header created by System/161, which is supposed to make it hard to trash files by accidentally using them as disk images.

Creating Disk Images

Create disk images with the disk161 utility, as follows:

   disk161 create LHD1.img 10M
This creates a 10 megabyte image under the name LHD1.img. You can also change the size of an image with disk161 resize, and dump the size and some other information with disk161 info.

Formatting the Disk

Before you can use SFS on a disk you need to format the disk to prepare the on-disk structures. The program mksfs does this task. It can be run either from inside OS/161 or from outside. You need to give it a volume name; this can be used to address the volume later from inside OS/161. This handout will assume your volume is going to be called "mydisk".

To format lhd1 from inside OS/161, do this:

   OS/161$ /sbin/mksfs lhd1raw: mydisk

The "raw" addendum to lhd1 gives mksfs the raw physical blocks of the disk. The pathname lhd1: names the logical volume mounted on the disk instead, which won't work before it's formatted or mounted. See the section below on naming for further discussion.

To format from outside OS/161, use the native-host-compiled version of mksfs, host-mksfs, which is compiled as part of the system build and placed in the hostbin directory. This knows about System/161's disk headers, but it doesn't know how to compute OS/161's device names, so you need to give it the name of the disk image file you want to put a filesystem on.

   cs161a% hostbin/host-mksfs LHD1.img mydisk


Once you have a filesystem, you can mount it from inside OS/161 using the "mount" command in the OS/161 menu:
   OS/161 kernel [? for menu]: mount sfs lhd1
The first argument sfs is the filesystem type (we currently have only sfs, but one could add more), and the second argument is the device name. OS/161 will print
   vfs: Mounted mydisk: on lhd1
and you're in business.


At this point you can access your SFS filesystem. To make it easier it is often convenient to make the root directory of your filesystem the current directory, which you can do with cd from either the shell or the menu. Both the names lhd1: and mydisk: name this directory, so you can do either

   OS/161 kernel [? for menu]: cd lhd1:
   OS/161 kernel [? for menu]: cd mydisk:
Likewise, files on the filesystem can be named with either lhd1: or mydisk: as a prefix. The command
   OS/161$ /bin/cp sys161.conf mydisk:sys161.conf
copies sys161.conf to the root directory of your new SFS volume. For further discussion, see the section on naming below.

SFS as Root Directory

OS/161 has an extra concept called the "bootfs", which is the volume used when you give a path name beginning with a slash. This allows using Unix-style paths like /bin/sh as well as OS/161-style paths like emu0:bin/sh.

The default bootfs is emu0:. You can change it from the kernel menu:

   OS/161 kernel [? for menu]: bootfs lhd1
Unless you've copied the userland programs to your SFS volume, this will make paths like /bin/cp stop working. Use emu0:bin/sh instead.

Copying the userland programs to your SFS volume is a hassle, but doing so and then setting your filesystem as the bootfs is a good way to test it.

Depending on staff time we may be able to make available a tool that packages up the userland programs (akin to the way the top level "make install" works) on an SFS volume, which you can then easily mount and use as the bootfs. (The tool exists but has to be dug out and polished up before it'll be useful to anyone.)


To make sure the state of your filesystem on disk is consistent, it should always be unmounted when you're done with it. This can be done from the kernel menu:

   OS/161 kernel [? for menu]: unmount lhd1
and OS/161 will say
   vfs: Unmounted lhd1:
If you do a clean shutdown (with q or /sbin/poweroff and friends) the VFS code will attempt to unmount all mounted filesystems. However, if you ^C out of System/161 or if your kernel dies, you're out of luck.

You can't unmount a volume that has files still open on it; it will complain that it's busy. If this is happening to you, first make sure that the filesystem is not (or no longer) the bootfs and that it's not the current directory of any process or thread, including the menu. If it still won't unmount, it's time to go looking for bugs in your vnode reference counting.

Note that you can usually avoid the worst consequences of failure to unmount by running sync to flush the buffer cache and other structures back to disk. This can be done either from the menu or the shell.

Crash Recovery and Checking

We provide you with a checking tool for SFS, called sfsck. It can be run either from inside OS/161 or outside, in a similar manner to mksfs and the other SFS tools. It will check the filesystem image for various problems and for various kinds of inconsistency and report what it finds. Sometimes it can fix the problems it finds; sometimes not. Its primary purpose is as a diagnostic tool.

After crashing with an SFS volume mounted, always run sfsck on that volume. Because OS/161 by default makes no attempt to guarantee that the state of the filesystem after a crash will be recoverable, sfsck may or may not be able to patch up what it finds, and what's left may or may not still contain useful data. However, if sfsck manages to clean up the volume, you can probably at least mount it again without getting in trouble. Mounting a corrupt or inconsistent SFS volume will often lead to panics. It is possible to waste a lot of time trying to figure out what's wrong if you forget this. Don't get caught by it. (This is true of many real file systems as well, although it's obviously an undesirable property.)

Moreover, when you are actively working on FS code, as you are for assignment 4, always fsck your volume after testing and unmounting. Your filesystem should be consistent on disk after it is unmounted cleanly. If it is not, it means you have a bug, possibly a serious bug.

Note that because of limitations in the SFS on-disk structure, many forms of filesystem corruption that you may have seen reported in the past by fsck tools for other file system types, such as unreferenced inodes, will show up as "blocks erroneously shown used (or free) in the bitmap". Unlike in e.g. FFS, in SFS such bitmap problems often reflect something seriously wrong.

Diagnosis/Debugging Tips

The dumpsfs program prints the superblock, free block bitmap, and root directory of an SFS volume. This can be helpful; unfortunately, as it exists it's rather limited. (Ideally it would be able to dump inodes and do other things.)

To dump a particular block, say block 10, from the volume, you can do this:

   cs161a% dd if=LHD1.img bs=512 skip=11 count=1 | hexdump -C
(The number of blocks to skip over is one greater than you'd expect because of the System/161 disk header.)


As has been mentioned previously, OS/161 uses volume:path or device:path names rather than Unix's pure (and singly-rooted) path names.

Thus, the null device in OS/161 is addressed as null:, and a file "frobozz" found on the volume "mydisk" is addressed as mydisk:frobozz. In Unix, the null device is by convention /dev/null, and volume names are mostly not used; instead the volume "mydisk" is mounted somewhere (perhaps /mnt) and then the file "frobozz" appears as /mnt/frobozz.

This model resembles Windows/DOS naming somewhat (apart from not being restricted to single-letter volume names) but was actually taken from AmigaDOS.

The name of an SFS volume is the string you passed to mksfs when you created it. In addition to this name, you can also address the volume by the name of the device where it's mounted. Mostly this will be the lhd1 device (the second disk device) as we normally make the first disk device the swap disk for VM. Thus if the volume "mydisk" is mounted on lhd1 you can address the file "frobozz" on it as "lhd1:frobozz" as well as "mydisk:frobozz". These are two names for the same file. Similarly, both mydisk: and lhd1: are names for the root directory of the volume.

To access the raw disk device (the uninterpreted collection of sectors that make up the disk) add "raw" to the base device name: lhd1raw:. This is the name you give to programs that manipulate the raw disk, like mksfs and sfsck.

The raw disk device is an interface to the disk image file as you see it outside System/161. Thus,

   OS/161$ mksfs lhd1raw: mydisk
   jharvard% hostbin/host-mksfs LHD1.img mydisk
are the same.

Name Lookup

When given a path name, the VFS code first splits the device name off the front. The device name is looked up in the table of device names (this happens in vfslist.c) and the vnode for the device in question, or for the root directory of the volume if it's a filesystem name (a volume label, or the non-raw name of a disk device) is used as a starting point for path lookup.

If there is no device name, but the name begins with a slash, the bootfs setting (by default "emu0:") is used as the starting point. This allows using Unix-style absolute paths like /bin/sh as well as OS/161-style paths.

If there is no device and no leading slash either, the path is taken to be relative to the current directory, and the current thread/process's current directory is used as the starting point for lookup.

Path lookup then continues on the filesystem involved via vnode function dispatch.


People sometimes wonder why OS/161 doesn't use Unix-style singly-rooted paths. There are two chief reasons for this decision.

The first is that it's simpler. With the OS/161 syntax each device or volume is independent and name lookup does not need to move from one volume to another. (Unless you implement symbolic links, which aren't included by default.) Therefore, all OS/161 needs to manage the top-level namespace is a table of device names; this is simple and straightforward.

By contrast, in a singly-rooted tree, volumes other than the root volume have to be grafted into the tree somehow. The hooks for this are called mount points, magic nodes in the namespace where the root directory of one volume appears as a subdirectory somewhere inside another volume. Implementing mount points is not that difficult; but it is substantially more complicated than having a table of independent volumes.

Furthermore, in a singly-rooted tree the root volume is a special case. All other volumes are mounted somewhere inside another volume; but the root volume hangs in thin air all by itself. In most Unixes there's a whole pile of extra code to handle mounting the root directory during boot... and more to allow unmounting it during shutdown. In OS/161 we avoid the need for this.

The second reason is that one of the file system assignments that OS/161 supports (but that we don't do in CS161) is implementing subdirectories and directory lookup. It is problematic to provide an implementation of mount points that works cleanly with student-implemented directories, and also problematic to not provide mount points at all and make students implement them. (And while it would also be possible to not have mount points and just have only one volume, then one would have to give up on emufs in order to use SFS; this would be a huge hassle.)