From: Daejun Park Linking a file with copy up origin into a non-merge impure dir does not bump the dir version. readdir then reuses the impure dir cache built before the link. The new link is not in that cache. readdir reports its upper inode number as d_ino instead of st_ino. The test builds the cache, then links two files with origin into the dir: one from the dir itself and one from the overlay root. It checks that readdir finds each new link by its st_ino. Signed-off-by: Daejun Park --- On the overlayfs ovl-fixes branch (0d5e729c515f) with default overlay mount options, the test fails in 3 of 3 runs on ext4 and on xfs. With the kernel patch "ovl: bump the impure dir version when linking a file with origin", it passes in 3 of 3 runs on each. --- tests/overlay/013 | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++ tests/overlay/013.out | 2 ++ 2 files changed, 60 insertions(+) diff --git a/tests/overlay/013 b/tests/overlay/013 new file mode 100755 index 00000000..bc65076c --- /dev/null +++ b/tests/overlay/013 @@ -0,0 +1,58 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2026 Samsung Electronics. All Rights Reserved. +# +# FS QA Test 013 +# +# Test consistent d_ino of hard links in an impure dir. +# +# Overlayfs caches the d_ino of the entries with a copy up origin in a +# non-merge impure dir. Linking a file with copy up origin into the dir +# must invalidate that cache, so that readdir reports the new link with +# the same inode number as stat. +# +. ./common/preamble +_begin_fstest auto quick copyup hardlink + +_fixed_by_kernel_commit xxxxxxxxxxxx \ + "ovl: bump the impure dir version when linking a file with origin" + +_require_scratch +_require_test_program "t_dir_type" + +_scratch_mkfs >>$seqres.full 2>&1 + +lowerdir=$OVL_BASE_SCRATCH_MNT/$OVL_LOWER +mkdir -p $lowerdir +touch $lowerdir/foo $lowerdir/bar + +_scratch_mount + +impure_dir=$SCRATCH_MNT/impure_dir +mkdir $impure_dir + +# Expect readdir of $impure_dir to find by the st_ino of +check_d_ino() +{ + local name=$1 + local ino=$(stat -c '%i' $impure_dir/$name) + + $here/src/t_dir_type $impure_dir $ino | grep -q "^$name f$" || \ + echo "readdir d_ino of $name does not match st_ino $ino" +} + +# Copy up foo and link it into the pure upper dir, which makes the dir +# impure. Then read the dir, so its impure entries get cached. +ln $SCRATCH_MNT/foo $impure_dir/foo +check_d_ino foo + +# Link foo again inside the dir +ln $impure_dir/foo $impure_dir/foo_link +check_d_ino foo_link + +# Copy up bar and link it into the dir +ln $SCRATCH_MNT/bar $impure_dir/bar +check_d_ino bar + +echo "Silence is golden" +_exit 0 diff --git a/tests/overlay/013.out b/tests/overlay/013.out new file mode 100644 index 00000000..3e66423b --- /dev/null +++ b/tests/overlay/013.out @@ -0,0 +1,2 @@ +QA output created by 013 +Silence is golden --- base-commit: 71641219a506ac62bfa231592394265ca812670e change-id: 20261112-ovl013-hlink-7cf74a775d23 Best regards, -- Daejun Park