Name a filesystem by its kernel id, never its device name (hq ADR 0325 fourth review)

An ext4 or xfs library mounted by UUID can come back from a reboot as another device
(/dev/sdb1 as /dev/sdc1); naming the filesystem by mountinfo's source read that as a
move, stripped the warranted library's entries and asked for a new Approve. A
filesystem is now named by statfs's f_fsid (from the UUID, or the ZFS dataset), its
type and its mount point. Entries left on the filesystem a folder is on now are
merged back or held, never walked away, and a TakenOn naming a mount point is not
taken.
This commit is contained in:
2026-10-12 19:10:18 +02:00
parent 21cd036232
commit f00f9c2a2f
6 changed files with 147 additions and 32 deletions
+91 -10
View File
@@ -1028,24 +1028,31 @@ func TestALeftoverWithNoAccessIdsIsSaidUnderAPathFreeName(t *testing.T) {
}
}
// Review (third) low: another filesystem mounted at the same point is not the one the warrant was for.
func TestAnotherFilesystemAtTheSameMountPointIsNotTaken(t *testing.T) {
// placedPool is a folder of a library on a pool the test says is mounted, with the pool's device name and filesystem
// id as the test sets them, taken under a warrant.
func placedPool(t *testing.T, source, fsid *string) (pool, lib, taken string) {
t.Helper()
dir := aclFolder(t)
pool := filepath.Join(dir, "pool")
lib := filepath.Join(pool, "media")
pool = filepath.Join(dir, "pool")
lib = filepath.Join(pool, "media")
if err := os.MkdirAll(filepath.Join(lib, "old"), 0o755); err != nil {
t.Fatal(err)
}
keeping(t, []string{pool}, nil)
source := "tank/a"
was := MountSource
wasSource, wasFsid := MountSource, MountFsid
MountSource = func(point string) (string, string) {
if point == pool {
return source, "zfs"
return *source, "ext4"
}
return "", ""
}
defer func() { MountSource = was }()
MountFsid = func(point string) string {
if point == pool {
return *fsid
}
return ""
}
t.Cleanup(func() { MountSource, MountFsid = wasSource, wasFsid })
notTaken := accessJSON("radarr.media", lib, "read-write", false, "mesh-radarr:61001:read-write:container")
if _, _, err := applyAccesses(t, store.State{}, notTaken); err != nil {
t.Fatal(err)
@@ -1055,11 +1062,18 @@ func TestAnotherFilesystemAtTheSameMountPointIsNotTaken(t *testing.T) {
t.Fatal(err)
}
<-done
taken := accessJSON("radarr.media", lib, "read-write", true, "mesh-radarr:61001:read-write:container")
taken = accessJSON("radarr.media", lib, "read-write", true, "mesh-radarr:61001:read-write:container")
if report, _, _ := applyAccesses(t, store.State{}, taken); outcomeOf(report, "radarr.media").Action == "waiting" {
t.Fatal("the folder taken waits on its own filesystem")
}
source = "tank/b" // another pool imported at the same mount point
return pool, lib, taken
}
// Review (third) low: another filesystem mounted at the same point is not the one the warrant was for.
func TestAnotherFilesystemAtTheSameMountPointIsNotTaken(t *testing.T) {
source, fsid := "/dev/sdb1", "0a0b0c0d01020304"
_, lib, taken := placedPool(t, &source, &fsid)
fsid = "1111222233334444" // another filesystem mounted at the same point
report, _, err := applyAccesses(t, store.State{}, taken)
if err != nil {
t.Fatal(err)
@@ -1072,6 +1086,28 @@ func TestAnotherFilesystemAtTheSameMountPointIsNotTaken(t *testing.T) {
}
}
// Review (fourth): the same filesystem whose device the kernel renamed across a reboot (/dev/sdb1 to /dev/sdc1, one
// filesystem id) is the same filesystem: still taken, still kept, and none of its entries walked away.
func TestADeviceRenamedIsTheSameFilesystem(t *testing.T) {
source, fsid := "/dev/sdb1", "0a0b0c0d01020304"
_, lib, taken := placedPool(t, &source, &fsid)
source = "/dev/sdc1"
report, _, err := applyAccesses(t, store.State{}, taken)
if err != nil {
t.Fatal(err)
}
if o := outcomeOf(report, "radarr.media"); o.Action == "waiting" {
t.Fatalf("a device renamed reads as another filesystem: %+v", o)
}
ReconcileKept(context.Background())
if got := effectiveOn(t, filepath.Join(lib, "old"), radarr); got != 7 {
t.Fatalf("the library's entries were walked away: the identity may %s", permWords(got))
}
if left := Leftovers(); len(left) != 0 {
t.Fatalf("a device renamed leaves entries said as left: %+v", left)
}
}
// Review L4: the controller's word that a folder was taken holds for the filesystem the warrant was carried out on;
// moved to another, it is not taken, the wait names the new filesystem, and nothing is walked.
func TestAMovedFolderIsNotTakenOnTheOldWarrant(t *testing.T) {
@@ -1148,3 +1184,48 @@ func TestAHungReadIsSharedByEveryoneWhoAsks(t *testing.T) {
t.Fatalf("%d reads of one path were started while the first hung", started)
}
}
// Review (fourth): entries left on the filesystem the folder is on now are never walked away — merged back into
// the folder's users when it is kept there, held while it is not.
func TestEntriesLeftOnTheFilesystemTheFolderIsOnAreNeverWalkedAway(t *testing.T) {
source, fsid := "/dev/sdb1", "0a0b0c0d01020304"
pool, lib, _ := placedPool(t, &source, &fsid)
rec, _ := keptRecord(lib)
users := rec.Users
for _, kept := range []bool{false, true} {
_ = KeptFolders.Update(lib, func(f *store.KeptFolder, _ bool) bool {
f.Kept, f.Users = kept, nil
f.Left = []store.KeptLeft{{Mount: pool, Placed: f.Placed, Users: users}}
return true
})
ReconcileKept(context.Background())
if got := effectiveOn(t, filepath.Join(lib, "old"), radarr); got != 7 {
t.Fatalf("kept=%v: entries on the folder's own filesystem were walked away", kept)
}
r, _ := keptRecord(lib)
if kept && (len(r.Left) != 0 || len(r.Users) != 1) {
t.Errorf("kept: not merged back into the folder's users: %+v", r)
}
if !kept && len(r.Left) != 1 {
t.Errorf("not kept: the entries' record was dropped: %+v", r)
}
}
}
// Review (fourth): a TakenOn naming a mount point (an unmerged build's record) is not taken on whatever is mounted
// there now.
func TestATakenOnOfTheOldFormIsNotTaken(t *testing.T) {
dir := aclFolder(t)
keeping(t, nil, nil)
lib := filepath.Join(dir, "media")
if err := os.MkdirAll(filepath.Join(lib, "old"), 0o755); err != nil {
t.Fatal(err)
}
_ = KeptFolders.Update(lib, func(f *store.KeptFolder, _ bool) bool {
f.Mount, f.TakenOn = "/", "/"
return true
})
if v := AccessVerdict(context.Background(), lib, true, true); v.Kind != VerdictWaitKeep {
t.Fatalf("an old-form record is read as taken: %s", v.Kind)
}
}