Whamcloud - gitweb
LU-16887 scrub: delete OI when inode missing
authorAlexander Boyko <alexander.boyko@hpe.com>
Thu, 11 Apr 2024 11:22:17 +0000 (19:22 +0800)
committerAndreas Dilger <adilger@whamcloud.com>
Mon, 15 Apr 2024 09:53:53 +0000 (09:53 +0000)
osd_iget_check() function have no ability to check
OI when osd_iget() returns error, because inode is
lost during error. Let's return old logic.

Scrub doesn't check consistency between OI and inode
for items from inconsistent list. When OI points to
worng inode, OI record should be deleted.
(This part of 51263 had been merged into b_es6_0 along with
https://review.whamcloud.com/52037)

Lustre-change: https://review.whamcloud.com/51263
Lustre-commit: c24a090ec389ae9ca2bedb4c7e3ee777deb63c7f

Fixes: 716de353b ("LU-15542 osd-ldiskfs: exclude EA inode from processing")
HPE-bug-id: LUS-11540, LUS-11585
Signed-off-by: Alexander Boyko <alexander.boyko@hpe.com>
Change-Id: Ic1618db1c8ee24bb307a9cf3f5ca98441a739b7f
Reviewed-on: https://review.whamcloud.com/c/ex/lustre-release/+/54709
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
lustre/osd-ldiskfs/osd_handler.c
lustre/tests/sanity-scrub.sh

index e5e6c67..9226234 100644 (file)
@@ -498,10 +498,11 @@ int osd_get_lma(struct osd_thread_info *info, struct inode *inode,
 /*
  * retrieve object from backend ext fs.
  **/
-struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
-                      struct osd_inode_id *id)
+static struct inode *osd_iget2(struct osd_thread_info *info,
+                              struct osd_device *dev, struct osd_inode_id *id,
+                              int *err)
 {
-       int rc;
+       int rc = 0;
        struct inode *inode = NULL;
 
        /*
@@ -520,25 +521,20 @@ struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
                CDEBUG(D_INODE, "unmatched inode: ino = %u, oii_gen = %u, "
                       "i_generation = %u\n",
                       id->oii_ino, id->oii_gen, inode->i_generation);
-               iput(inode);
-               inode = ERR_PTR(-ESTALE);
+               rc = -ESTALE;
        } else if (inode->i_nlink == 0) {
                /*
                 * due to parallel readdir and unlink,
                 * we can have dead inode here.
                 */
                CDEBUG(D_INODE, "stale inode: ino = %u\n", id->oii_ino);
-               iput(inode);
-               inode = ERR_PTR(-ESTALE);
+               rc = -ESTALE;
        } else if (is_bad_inode(inode)) {
-               rc = -ENOENT;
                CWARN("%s: bad inode: ino = %u: rc = %d\n",
-                     osd_dev2name(dev), id->oii_ino, rc);
-               iput(inode);
-               inode = ERR_PTR(rc);
+                     osd_dev2name(dev), id->oii_ino, -ENOENT);
+               rc = -ENOENT;
        } else if ((rc = osd_attach_jinode(inode))) {
-               iput(inode);
-               inode = ERR_PTR(rc);
+               CDEBUG(D_INODE, "jbd: ino = %u rc = %d\n", id->oii_ino, rc);
        } else {
                ldiskfs_clear_inode_state(inode, LDISKFS_STATE_LUSTRE_DESTROY);
                if (id->oii_gen == OSD_OII_NOGEN)
@@ -554,6 +550,25 @@ struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
                if (!(inode->i_flags & S_NOCMTIME))
                        inode->i_flags |= S_NOCMTIME;
        }
+
+       *err = rc;
+
+       return inode;
+}
+
+struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
+                      struct osd_inode_id *id)
+{
+       struct inode *inode;
+       int rc = 0;
+
+       inode = osd_iget2(info, dev, id, &rc);
+
+       if (rc) {
+               iput(inode);
+               inode = ERR_PTR(rc);
+       }
+
        return inode;
 }
 
@@ -648,9 +663,8 @@ static struct inode *osd_iget_check(struct osd_thread_info *info,
         */
 
 again:
-       inode = osd_ldiskfs_iget(osd_sb(dev), id->oii_ino);
-       if (IS_ERR(inode)) {
-               rc = PTR_ERR(inode);
+       inode = osd_iget2(info, dev, id, &rc);
+       if (rc) {
                if (!trusted && (rc == -ENOENT || rc == -ESTALE))
                        goto check_oi;
 
@@ -659,40 +673,6 @@ again:
                GOTO(put, rc);
        }
 
-       if (is_bad_inode(inode)) {
-               rc = -ENOENT;
-               if (!trusted)
-                       goto check_oi;
-
-               CDEBUG(D_INODE, "bad inode for FID: "DFID", ino = %u\n",
-                      PFID(fid), id->oii_ino);
-               GOTO(put, rc);
-       }
-
-       if (id->oii_gen != OSD_OII_NOGEN &&
-           inode->i_generation != id->oii_gen) {
-               rc = -ESTALE;
-               if (!trusted)
-                       goto check_oi;
-
-               CDEBUG(D_INODE, "unmatched inode for FID: "DFID", ino = %u, "
-                      "oii_gen = %u, i_generation = %u\n", PFID(fid),
-                      id->oii_ino, id->oii_gen, inode->i_generation);
-               GOTO(put, rc);
-       }
-
-       if (inode->i_nlink == 0) {
-               rc = -ENOENT;
-               if (!trusted)
-                       goto check_oi;
-
-               CDEBUG(D_INODE, "stale inode for FID: "DFID", ino = %u\n",
-                      PFID(fid), id->oii_ino);
-               GOTO(put, rc);
-       }
-
-       ldiskfs_clear_inode_state(inode, LDISKFS_STATE_LUSTRE_DESTROY);
-
 check_oi:
        if (rc != 0) {
                __u32 saved_ino = id->oii_ino;
@@ -766,7 +746,7 @@ check_oi:
                        rc = -ENOENT;
                else
                        rc = -EREMCHG;
-       } else {
+       } else if (!IS_ERR(inode)) {
                if (id->oii_gen == OSD_OII_NOGEN)
                        osd_id_gen(id, inode->i_ino, inode->i_generation);
 
index 19c5a4e..da0e05f 100755 (executable)
@@ -1450,6 +1450,38 @@ test_20() {
 }
 run_test 20 "Don't trigger OI scrub for irreparable oi repeatedly"
 
+test_21() {
+       [ $MDSCOUNT -lt 2 ] && skip "needs >= 2 MDTs"
+       [ "$mds1_FSTYPE" != "ldiskfs" ] && skip_env "ldiskfs only test"
+
+       local timeout
+       local td=$TMP/$tdir
+       local device=$(mdsdevname 1)
+
+       echo $device
+
+       timeout=$(do_facet mds2 "$LCTL get_param -n \
+               mdt.$FSNAME-MDT0001.recovery_time_hard")
+       for idx in $(seq $MDSCOUNT); do
+           stop mds${idx}
+       done
+
+       #test reproduce simple situation, when  OI record exist
+       #and inode was reused/wrong. Scrub should handle it.
+       do_facet mds1 "mkdir -p $td && mount -t ldiskfs $device $td &&
+           rm -rf $td/update_log_dir/*; umount $td; rm -rf $td"
+
+       for idx in $(seq $MDSCOUNT); do
+           start mds${idx} $(mdsdevname $idx) $MDS_MOUNT_OPTS ||
+               error "mount mds$idx failed"
+       done
+
+       wait_recovery_complete mds2 $((timeout + TIMEOUT))
+
+}
+run_test 21 "don't hang MDS recovery when failed to get update log"
+
+
 # restore MDS/OST size
 MDSSIZE=${SAVED_MDSSIZE}
 OSTSIZE=${SAVED_OSTSIZE}