Files
erofs-freebsd-out-tree/tests/TC132-nfs-file-handle-stability.md
T
2026-08-18 09:20:44 +02:00

3.7 KiB

Test Case: FreeBSD NFS File-Handle Stability and Image Replacement

Test ID: TC132-nfs-file-handle-stability Category: NFS Export Priority: Critical Regression: Constant generation could resolve an old handle in a replacement image

Objective

Verify 16-byte EROFS FIDs with full 64-bit NIDs and stable superblock-seeded per-inode generations. The same image remounted on the same explicit md unit must preserve the complete fhandle_t; a different image with the same device number and NID must reject the old handle with ESTALE. Verify va_gen and handle generation are identical.

Preconditions

  • FreeBSD 15 and tests/nfs_fh_tool.c compiled as nfs_fh_tool.
  • Deterministic nfs-a.erofs and nfs-b.erofs from the metadata/VFS fixture generator. They contain the same NIDs/content but different UUIDs.
  • Use one explicit md unit for every remount/replacement step because FreeBSD stores the filesystem ID outside the filesystem-private FID.

Direct Handle Procedure

Perform these steps before starting NFS clients, so the direct EROFS mount can be unmounted and replaced without EBUSY.

  1. Attach nfs-a.erofs to md80 and mount it.

  2. Capture regular, directory, symlink (lcapture), and FIFO handles. For the regular file:

    ./nfs_fh_tool describe a.fh
    ./nfs_fh_tool stat a.fh
    stat -f 'gen=%v ino=%i' /mnt/repo22-erofs/basic/regular.txt
    

    Assert len=16, pad=0, full NID preservation, nonzero generation, and describe gen == stat st_gen.

  3. Verify malformed versus stale classification:

    ./nfs_fh_tool mutate a.fh bad-len.fh len 15
    ./nfs_fh_tool mutate a.fh bad-pad.fh pad 1
    ./nfs_fh_tool mutate a.fh bad-gen.fh gen_xor 1
    ./nfs_fh_tool mutate a.fh bad-nid.fh nid_hi 0xffffffff
    
    ./nfs_fh_tool expect-stat bad-len.fh EINVAL
    ./nfs_fh_tool expect-open bad-len.fh EINVAL
    ./nfs_fh_tool expect-stat bad-pad.fh EINVAL
    ./nfs_fh_tool expect-open bad-pad.fh EINVAL
    ./nfs_fh_tool expect-stat bad-gen.fh ESTALE
    ./nfs_fh_tool expect-open bad-gen.fh ESTALE
    ./nfs_fh_tool expect-stat bad-nid.fh ESTALE
    ./nfs_fh_tool expect-open bad-nid.fh ESTALE
    
  4. Unmount, detach, reattach the same image to md80, remount, capture a-remount.fh, compare complete handle bytes, and read through the old handle.

  5. Unmount/detach, attach nfs-b.erofs to the same md80, and remount. Capture b.fh; it must have the same NID and fsid but a different generation. Both fhstat(a.fh) and fhopen(a.fh) must return ESTALE, while b.fh succeeds.

NFS Restart Procedure

After the replacement test is cleaned up, mount/export the qualified NFS fixture and mount the NFS client. Keep a client descriptor open across nfsd restart, but prevent the restarted daemon from inheriting the test descriptor:

exec 3< /mnt/repo22-nfs/basic/regular.txt
service nfsd onerestart 3<&-
cat <&3 > open-after-restart.out
exec 3<&-
cmp open-after-restart.out /mnt/repo22-erofs/basic/regular.txt

Without 3<&- on the service command, nfsd inherits the NFS-client descriptor and can keep the client mount busy during cleanup.

Metabox and Multidevice Regression

  • Capture/resolve a metabox bit-63 NID and mutate it beyond the metabox backing range; expect ESTALE only for invalid NID/generation.
  • For an external-data file, a valid handle must still resolve after the data provider is detached; the subsequent read preserves ENXIO/I/O error rather than rewriting it to ESTALE.

Cleanup

Unmount NFS clients first while rpcbind/mountd/nfsd still run. Then clear and reload /etc/exports, stop nfsd, mountd, and rpcbind, unmount EROFS, detach md providers, and unload the module. Assert every mount, md, module, service PID, and export entry is gone.