schfs: mount a snapshot by name, read-only
`mount -t schfs @golden /mnt` mounts a snapshot. The source argument
finally means something: sys_mount ignored it outright, because there was
one volume and nothing to choose between. `@name` rather than a path
because a snapshot is not a device -- there is no node in /dev for it and
there should not be, since it lives inside the volume already mounted.
A second volume rather than a parameter threaded through all 23 schfs_k*
entry points. Only the read side can ever address it, so the write path
keeps talking to the live volume and needed no change; the four read
entry points grew _dev variants and pick the volume from the device the
inode already carries. One fs_ops table serves both, because every entry
takes an inode and dispatches on it -- a second table would be the same
pointers under a different name.
It needs its own device number: a snapshot's object ids are the *same
numbers* as the live tree's, so one device would make the two views alias
in the inode cache and hand a reader whichever was cached first.
Three things this turned up, none of them new but all of them reachable
for the first time:
- sys_mount refused with `dev == SCHFS_DEV`, meaning "do not mount SchFS
onto SchFS". A snapshot's mount point is necessarily on the live root,
so that refused the entire feature. The real condition is mounting a
device onto *itself*, which is `dev == fsdev`.
- createat allocates an inode and then panics if dirlink fails --
reasonable about a writable filesystem, a crash on a read-only one.
The refusal now happens before anything is allocated. Unlink and
rename already handled a refusal properly.
- a refused create reported ENOENT, so writing to a snapshot said "No
such file or directory" -- the sentence a shell prints for every
create failure. It reports EROFS now.
Verified in the running system against an image built with
--snapshot golden: the mount succeeds, ls lists the snapshot's tree,
/mnt2/etc/motd reads back through it, and a write is refused with
"Read-only file system".
One at a time, and no umount path for it yet: mount_del_by_root removes
the mount table entry, but ksnap_unmount is only called on the failure
paths. schfs-check passes; bootcheck 108 [ok].
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
36614b69c5
commit
3919f1446e
6 changed files with 345 additions and 18 deletions
|
|
@ -275,10 +275,25 @@ extern const struct fs_ops schfs_ops;
|
|||
// Defined in fs/procfs.c -- the synthetic /proc.
|
||||
extern const struct fs_ops procfs_ops;
|
||||
|
||||
// Is this filesystem read-only?
|
||||
//
|
||||
// A mounted snapshot is. Callers must ask *before* they start mutating: the
|
||||
// create path allocates an inode and then panics if the dirlink fails, which is
|
||||
// a reasonable assumption about a writable filesystem and a crash on a
|
||||
// read-only one.
|
||||
int
|
||||
fs_readonly(uint dev)
|
||||
{
|
||||
return dev == SCHFS_SNAP_DEV;
|
||||
}
|
||||
|
||||
static const struct fs_ops *
|
||||
ops_for(uint dev)
|
||||
{
|
||||
if (dev == SCHFS_DEV) return &schfs_ops;
|
||||
// A mounted snapshot is the same filesystem seen through an older root, so it
|
||||
// is the same operations; they dispatch on the device themselves.
|
||||
if (dev == SCHFS_SNAP_DEV) return &schfs_ops;
|
||||
if (dev == PROCFS_DEV) return &procfs_ops;
|
||||
return &v1_ops;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue