Whamcloud - gitweb
LU-18791 lmv: report an overflowed nlink correctly 57/58357/9
authorcoreytesdahl <corey.tesdahl@hpe.com>
Wed, 4 Dec 2024 22:37:06 +0000 (16:37 -0600)
committerOleg Drokin <green@whamcloud.com>
Wed, 26 Mar 2025 04:02:30 +0000 (04:02 +0000)
inode nlink count should be set to 1 if any component
stripe in stripped dir has overflowed and been set to 1

HPE-bug-id: LUS-12747
Signed-off-by: Corey Tesdahl <corey.tesdahl@hpe.com>
Change-Id: I2a3b6f5bd846d11d768ee1979b7f11f0e7cf1c88
Signed-off-by: Alexander Zarochentsev <alexander.zarochentsev@hpe.com>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/58357
Reviewed-by: Andrew Perepechko <andrew.perepechko@hpe.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/lmv/lmv_obd.c
lustre/tests/sanity.sh

index 9b7d205..2d34110 100644 (file)
@@ -4215,6 +4215,7 @@ static int lmv_merge_attr(struct obd_export *exp,
        const struct lmv_stripe_md *lsm = &lso->lso_lsm;
        int rc;
        int i;
+       int nlink_overflow = 0;
 
        if (!lmv_dir_striped(lso))
                return 0;
@@ -4237,11 +4238,12 @@ static int lmv_merge_attr(struct obd_export *exp,
                       (s64)inode_get_ctime_sec(inode),
                       (s64)inode_get_mtime_sec(inode));
 
-               /* for slave stripe, it needs to subtract nlink for . and .. */
-               if (i != 0)
-                       attr->cat_nlink += inode->i_nlink - 2;
-               else
-                       attr->cat_nlink = inode->i_nlink;
+               /* nlink==1 is a special value meaning nlink overflow
+                * for directories on Ldiskfs.
+                */
+               nlink_overflow |= (inode->i_nlink == 1);
+               /* not counting . and .. for each stripe */
+               attr->cat_nlink += inode->i_nlink - 2;
 
                attr->cat_size += i_size_read(inode);
                attr->cat_blocks += inode->i_blocks;
@@ -4255,6 +4257,14 @@ static int lmv_merge_attr(struct obd_export *exp,
                if (attr->cat_mtime < inode_get_mtime_sec(inode))
                        attr->cat_mtime = inode_get_mtime_sec(inode);
        }
+       if (nlink_overflow)
+               /* Indicate that nlink is not correct for a striped dir the
+                * same way it is done in Ldiskfs by setting nlink = 1.
+                */
+               attr->cat_nlink = 1;
+       else
+               /* add 2 for . and .. */
+               attr->cat_nlink += 2;
        return 0;
 }
 
index 9e21ed2..a6484aa 100755 (executable)
@@ -6247,7 +6247,7 @@ test_51b() {
 
        # create files
        createmany -d $dir/d $nrdirs || {
-               unlinkmany $dir/d $nrdirs
+               unlinkmany -d $dir/d $nrdirs
                error "failed to create $nrdirs subdirs in MDT$mdtidx:$dir"
        }
 
@@ -6284,6 +6284,39 @@ test_51b() {
 }
 run_test 51b "exceed 64k subdirectory nlink limit on create, verify unlink"
 
+test_51c() {
+       (( MDSCOUNT > 1 )) || skip "needs >= 2 MDTs"
+       local dir=$DIR/$tdir-c2
+       local nrdirs=$((65536 * 2 + 2000))
+       local mdtidx
+
+       trap cleanup_print_lfs_df EXIT
+
+       $LFS mkdir -c 2 -H fnv_1a_64 $dir
+       while read mtdidx rest; do
+               local mdtname=$FSNAME-MDT$(printf "%04x" $mdtidx)
+               local numfree=$(lctl get_param -n mdc.$mdtname*.filesfree)
+               local blkfree=$(lctl get_param -n mdc.$mdtname*.kbytesavail)
+
+               (( numfree < nrdirs / 2 || blkfree / $(fs_inode_ksize) < nrdirs / 2 )) &&
+                       skip "not enough inodes or blocks for mdt$mdtidx"
+       done < <( $LFS getdirstripe $dir | awk '{ if ($2 ~ /\[0x.*:0x.*:0x.*\]/) {  print $1; } }' )
+
+       createmany -d $dir/d $nrdirs ||
+               error "failed to create $nrdirs subdirs in $dir"
+       # nlink for the striped dir should be either 1
+       # (ldiskfs, nlink is overflowed at least in one stripe)
+       # or $ndirs + 2
+       local nlinks=$(stat -c %h $dir)
+       (( nlinks == 1 || nlinks == nrdirs + 2 )) ||
+               error "Wrong nlink count of $nlinks"
+
+       unlinkmany -d $dir/d $nrdirs || error "Removal of the subdirs failed"
+       rmdir $dir || error "rmdir failed"
+       cleanup_print_lfs_df
+}
+run_test 51c "exceed 64k subdirectory count per dir stripe, verify nlink count"
+
 test_51d_sub() {
        local stripecount=$1
        local nfiles=$2