/fs
hierarchy
Directories in /fs
correspond to (and can replace) entries in
/etc/fstab
(or vfstab
, or whatever your operating
system uses). This hierarchy is intended to have the same structure on all
systems. It is still experimental; this specification is subject to
incompatible changes in the future, if they turn out to be needed for certain
systems. If you know of systems where this scheme as currently specified
would be problematic, please let me know. This design is discussed on
the prjware list.
A filesystem is configured in a directory in /fs
, e.g.,
/fs/std-root/
contains the configuration of the root filesystem.
A directory in /fs
has the following entries:
mount
- the directory where the filesystem is
mounted.
fstype
- a file containing the name of the filesystem
type, suitable for passing to mount -t
on Linux, mount
-F
on Solaris, etc.
dev
- the block or character device used for mounting the
filesystem.
rdev
- the block or character device used for checking the
filesystem for errors. Some systems use the same device for mounting and
checking; in such cases, rdev
might be a symlink to
dev
, or vice versa. Other systems require different
devices, so we always use separate names.
check
- a program to run to check the filesystem for
errors. This should not require user interaction. Typically, this is a
symlink to the fsck
program specific to this filesystem
type, or a script invoking such a program with any needed otions to let
it run non-interactively. The corresponding rdev
filename
should be passed as an argument when running this program.
mount-opts
- a file containing options suitable for
passing to mount -o
. The filesystem is typically mounted
with these options.
(All of these might be symlinks to files somewhere else, but they typically
will not be, except perhaps dev
, rdev
, and
check
. In particular, mount
directories should not
generally be symlinks to traditional mount points such as /usr
;
see below.)
Entries in /fs
may be symlinks, and a filesystem may have more
than one name. Names beginning with std-
are reserved for
global use: they need not be present on every system, but when they are
present, they should have the properties assigned here. Currently defined
standard names:
std-root
: the root filesystem.
/fs/std-root/mount
is a symlink to
"/.
".
std-var
: a filesystem normally mounted read-write,
possibly noexec
, and probably tuned for performance. Logs,
spools, etc., are typically stored here.
When configuring a filesystem, I have an idea of which files I'll
store on it, but I might change my mind later. Thus, every filesystem
contains what looks like a subset of /
; a filesystem
shouldn't contain, e.g., /usr
files directly, expecting
to be mounted on /usr
. Instead, it should contain a
usr
directory containing any /usr
files on
that filesystem. Files are never accessed by their names in /fs;
instead, we set up symlinks such as /usr ->
fs/stuff/mount/usr
, and files are accessed via those symlinks.
(It's like Plan 9, but without as much help from the kernel.)
/usr
itself is no longer to be thought of as a filesystem
- even if there is one filesystem that contains all of
/usr
and only /usr
, we've made the
distinction between the filesystem storing the files and the name
"/usr
". A filesystem can become full. A part
of the namespace cannot - we can always make symlinks to files stored
on other filesystems. "lost+found
" directories don't
clutter up the namespace where files are accessed. Storing a file on
a particular filesystem does not mean that it must appear in any
particular part of the namespace (except under
"/fs
", where they're easily ignored). Even
filesystems like /proc
can be configured this way, but
since we can't control their contents to the same degree as normal
filesystems, /proc
would be a symlink to
fs/proc/mount
instead of fs/proc/mount/proc
.
There is no need for a filesystem configuration to specify whether it can be mounted by non-root users; that can be handled in general privilege-management tools like sudo.
We can use symlinks to simultaneously satisfy these desirable conditions:
/fs/pkgs
mainly devoted to
/package
,;
std-root
filesystem;
/package
as long as they are on a mounted filesystem;
pkgs
filesystem while the
root filesystem is mounted read-only;
Similarly for a "home
" filesystem and
root
's home directory. Things that must be on the
std-root
filesystem are stored in /slash
, which
(just like /fs/*/mount
) looks like a subset of /
.
When pkgs
is not mounted, we see:
lrwxrwxrwx /package -> fs/pkgs/mount/package lrwxrwxrwx /fs/pkgs/mount/package -> /slash/package drwxr-xr-t /slash/package lrwxrwxrwx /slash/package/admin/daemontools -> daemontools-0.76 drwxr-xr-x /slash/package/admin/daemontools-0.76 lrwxrwxrwx /package/admin/daemontools = /slash/package/admin/daemontools drwxr-xr-x /package/admin/daemontools-0.76 = /slash/package/admin/daemontools-0.76
When pkgs
is mounted, we see:
lrwxrwxrwx /package -> fs/pkgs/mount/package drwxr-xr-t /fs/pkgs/mount/package lrwxrwxrwx /fs/pkgs/mount/package/admin/daemontools -> /slash/package/admin/daemontools lrwxrwxrwx /fs/pkgs/mount/package/admin/daemontools-0.76 -> /slash/package/admin/daemontools-0.76 lrwxrwxrwx /package/admin/daemontools = /fs/pkgs/mount/package/admin/daemontools lrwxrwxrwx /package/admin/daemontools-0.76 = /fs/pkgs/mount/package/admin/daemontools-0.76
The trick here is that the "pkgs
" filesystem's
"mount
" directory is not empty when the filesystem is
unmounted; there is a symlink in place of where the real contents would be,
pointing to the portion of the packages that are available on the
std-root
filesystem. We don't have to create another symlink
for each package on the "pkgs
" filesystem - just one
for each on the std-root
filesystem; there are fewer of these,
so we can forget about this trick most of the time. Also, installing a
package on the "pkgs
" filesystem doesn't require any
modifications to the std-root
filesystem, so
std-root
can be read-only. This trick can be used for other
contents of other filesystems as well, but it will apply to a directory (and
its descendents), not necessarily a package. In /package
,
packages just happen to correspond to directories.
/fs
I use the scripts fscheck
,
fsmake
,
fsmount
, and
fsumount
to work with my /fs
filesystems. (I also use this
fsck.reiser
script as the
/fs/*/check
script for my
ReiserFS filesystems.) Example uses
are in my boot scripts
. If you
do not have minutils
installed, you can substitute mount -n
and
umount -n
for minmount
and
minumount
. (I would use -n
because
/etc/mtab
is a symlink to proc/mounts
on my Linux
systems. /etc/mtab
is capable of being inaccurate if maintained
by userspace code. /proc/mounts
is always correct, though not
quite as available.)
You may find this a useful addition to your shell startup script. (It may
need to be in a script invoked in place of the shell, which then
exec
s the interactive shell.) If your shell initializes
$PWD
to the symlink-free name of the current directory, and
you'd rather not be bothered with which filesystem you happen to be on, then
this will remove the "/fs/*/mount
" prefix from
$PWD
.
case "$PWD" in /fs/*/mount/*) PWD="${PWD#/fs/*/mount}"; export PWD;; /slash/*) PWD="${PWD#/slash}"; export PWD;; esac
Dan Rench has a similar scheme for user
ids to replace /etc/passwd
.
See also tcb.