78 lines
2.9 KiB
Markdown
78 lines
2.9 KiB
Markdown
# Test Case: NFS Per-Inode Generation on Same-Superblock Replacement
|
|
|
|
**Test ID**: TC154-nfs-per-inode-generation
|
|
**Category**: NFS Export
|
|
**Priority**: Critical
|
|
**Regression**: A mount-wide superblock hash aliases a replacement inode at the same NID
|
|
|
|
## Objective
|
|
|
|
Verify that an EROFS file handle keeps the existing 16-byte FreeBSD FID ABI but
|
|
uses a stable per-inode generation. Remounting an unchanged image must preserve
|
|
the complete handle. Replacing it with an image whose superblock block, UUID,
|
|
NID, and file content are identical but whose raw inode metadata differs must
|
|
make the old handle return `ESTALE`.
|
|
|
|
Also verify that a valid-NID handle resolving to a malformed replacement inode
|
|
returns the positive inode-read errno instead of a negative Linux errno or a
|
|
successful alias.
|
|
|
|
## Fixture
|
|
|
|
Generate all review fixtures on the host:
|
|
|
|
```sh
|
|
python3 tests/review_fixtures.py make \
|
|
--output /work/build/repo22-review-fixes-fixtures
|
|
```
|
|
|
|
For `nfs-inode-a.erofs`, `nfs-inode-b.erofs`, and
|
|
`nfs-inode-corrupt.erofs`, require the helper evidence to prove:
|
|
|
|
- target `/zz-identity.txt` has the same NID and inode offset;
|
|
- the inode lies after the complete superblock checksum block;
|
|
- the complete checksum block and declared superblock are byte-identical;
|
|
- A and B differ only in the compact inode `i_mtime` field;
|
|
- the helper's superblock-seeded raw-inode FNV generations are nonzero and
|
|
different;
|
|
- all three images retain a valid superblock checksum.
|
|
|
|
## Procedure
|
|
|
|
1. Compile `tests/nfs_fh_tool.c` natively on FreeBSD 15.
|
|
2. Attach image A to an explicit md unit, mount it, capture `a.fh`, and compare
|
|
`nfs_fh_tool describe`, `nfs_fh_tool stat`, and `stat -f '%v'`. The FID and
|
|
`st_gen` values must equal `generation_a` in `fixture-manifest.json`.
|
|
3. Unmount and detach image A, then reattach the unchanged image to the same md
|
|
unit. Capture `a-remount.fh`, require a byte-for-byte handle match, and read
|
|
through `a.fh`.
|
|
4. Replace A with image B on the same md unit. Capture `b.fh`, require the same
|
|
fsid and NID but `generation_b`, then run:
|
|
|
|
```sh
|
|
nfs_fh_tool expect-stat a.fh ESTALE
|
|
nfs_fh_tool expect-open a.fh ESTALE
|
|
nfs_fh_tool stat b.fh
|
|
```
|
|
|
|
5. Replace B with `nfs-inode-corrupt.erofs` on the same md unit. Resolving
|
|
`a.fh` must return positive FreeBSD `EOPNOTSUPP` (45) from inode decoding:
|
|
|
|
```sh
|
|
nfs_fh_tool expect-stat a.fh 45
|
|
nfs_fh_tool expect-open a.fh 45
|
|
```
|
|
|
|
6. Compare pre/post dmesg, unmount, detach the md unit, and unload the exact
|
|
module under test.
|
|
|
|
## Expected Results
|
|
|
|
- Image A has an identical handle and generation across remounts.
|
|
- Image B's same-NID replacement has a different generation and both old-handle
|
|
operations return `ESTALE`.
|
|
- The new handle resolves successfully and `va_gen == FID.gen`.
|
|
- The malformed inode propagates errno 45 as a positive error and never returns
|
|
a vnode.
|
|
- The FID remains exactly 16 bytes with unchanged field offsets.
|