schfs: several snapshots at once, and unmount gives the slot back
Two loose ends from the mount-by-name commit, both closed. A slot is a device number, so supporting more than one snapshot is a small array rather than a redesign: SCHFS_SNAP_DEV through SCHFS_SNAP_DEV + SCHFS_SNAP_SLOTS - 1, each with its own volume and its own scratch pages, allocated on first use. Four of them -- "one at a time" is an odd thing to have to explain, and the cost is two pages per slot. Not many, because each one is a device number and those are a small fixed space. The leak mattered more. umount removed the mount table entry and left the slot marked in use, so a snapshot could be unmounted and then never mounted again until reboot. sys_umount2 releases it now, keyed off the device it already has in hand. Verified in the running system: two snapshots mounted at once, both readable, both unmounted, and a third mount afterwards succeeds and reads correctly -- which is the case that failed before. schfs-check passes; bootcheck 108 [ok]. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3919f1446e
commit
b34779111a
6 changed files with 75 additions and 47 deletions
|
|
@ -180,9 +180,10 @@ uint64 schfs_kroot(void);
|
|||
// The read path takes a device number so the VFS can address either view; there
|
||||
// is no write path, because a snapshot that could be written to would not be
|
||||
// one. See kernel/fs/schfs/kmount.c.
|
||||
// Returns the device number of the slot the snapshot landed in, or negative.
|
||||
int schfs_ksnap_mount(const char *name, unsigned namelen);
|
||||
void schfs_ksnap_unmount(void);
|
||||
uint64 schfs_ksnap_root(void);
|
||||
void schfs_ksnap_unmount(uint dev);
|
||||
uint64 schfs_ksnap_root(uint dev);
|
||||
long schfs_kread_dev(uint dev, uint64 ino, uint64 off, void *buf,
|
||||
unsigned n);
|
||||
int schfs_kstat_dev(uint dev, uint64 ino, struct schfs_inode *out);
|
||||
|
|
|
|||
|
|
@ -102,12 +102,21 @@ struct inode {
|
|||
|
||||
// Device number that means "the synthetic /proc". Like SCHFS_DEV, it is
|
||||
// deliberately nowhere near a real disk's 0 or 1.
|
||||
// A mounted snapshot. Same block device, a different tree root, read-only.
|
||||
// It needs its own device number because an inode is identified by (dev, inum)
|
||||
// and a snapshot's object ids are the *same numbers* as the live tree's -- one
|
||||
// number would make the two views alias in the inode cache and hand a reader
|
||||
// whichever was cached first.
|
||||
#define SCHFS_SNAP_DEV 66
|
||||
// Mounted snapshots. Same block device, an older tree root, read-only.
|
||||
//
|
||||
// Each needs its own device number because an inode is identified by
|
||||
// (dev, inum) and a snapshot's object ids are the *same numbers* as the live
|
||||
// tree's -- one number would make the views alias in the inode cache and hand
|
||||
// a reader whichever was cached first. So a slot is a device: SCHFS_SNAP_DEV
|
||||
// through SCHFS_SNAP_DEV + SCHFS_SNAP_SLOTS - 1.
|
||||
//
|
||||
// Four rather than one because "one at a time" is an odd thing to explain and
|
||||
// the cost is two scratch pages per slot, allocated on first use. Four rather
|
||||
// than many because each is a device number and they are a fixed, small space.
|
||||
#define SCHFS_SNAP_SLOTS 4
|
||||
#define SCHFS_SNAP_DEV 66
|
||||
#define SCHFS_IS_SNAP_DEV(d) \
|
||||
((d) >= SCHFS_SNAP_DEV && (d) < SCHFS_SNAP_DEV + SCHFS_SNAP_SLOTS)
|
||||
|
||||
#define PROCFS_DEV 65
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue