Whamcloud - gitweb
LU-16887 scrub: delete OI when inode missing 63/51263/3
authorAlexander Boyko <alexander.boyko@hpe.com>
Thu, 1 Jun 2023 14:19:40 +0000 (10:19 -0400)
committerOleg Drokin <green@whamcloud.com>
Tue, 20 Jun 2023 03:49:02 +0000 (03:49 +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.

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/fs/lustre-release/+/51263
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Vitaly Fertman <vitaly.fertman@hpe.com>
Reviewed-by: Lai Siyao <lai.siyao@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/osd-ldiskfs/osd_handler.c
lustre/osd-ldiskfs/osd_scrub.c
lustre/tests/sanity-scrub.sh

index 88105ca..d0bfa4f 100644 (file)
@@ -488,10 +488,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;
 
        /*
@@ -510,32 +511,27 @@ 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)) {
                CWARN("%s: bad inode: ino = %u: rc = %d\n",
                      osd_dev2name(dev), id->oii_ino, -ENOENT);
-               iput(inode);
-               inode = ERR_PTR(-ENOENT);
+               rc = -ENOENT;
        } else  if (osd_is_ea_inode(inode)) {
                /*
                 * EA inode is internal ldiskfs object, should don't visible
                 * on osd
                 */
                CDEBUG(D_INODE, "EA inode: ino = %u\n", id->oii_ino);
-               iput(inode);
-               inode = ERR_PTR(-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)
@@ -551,6 +547,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;
 }
 
@@ -645,9 +660,8 @@ static struct inode *osd_iget_check(struct osd_thread_info *info,
         */
 
 again:
-       inode = osd_iget(info, dev, id);
-       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;
 
index b3d5712..3a125ab 100644 (file)
@@ -474,10 +474,20 @@ iget:
                        break;
                }
        } else if (osd_id_eq(lid, lid2)) {
-               if (converted)
-                       sf->sf_items_updated++;
+               /*
+                * OI records from request and current are the same
+                * checking inode generation at osd_iget()
+                */
+               if (!inode) {
+                       inode = osd_iget(info, dev, lid);
+                       if (IS_ERR(inode))
+                               ops = DTO_INDEX_DELETE;
+               }
 
-               GOTO(out, rc = 0);
+               if (converted && !IS_ERR(inode)) {
+                       sf->sf_items_updated++;
+                       GOTO(out, rc = 0);
+               }
        } else {
                if (!scrub->os_partial_scan) {
                        spin_lock(&scrub->os_lock);
@@ -545,9 +555,10 @@ out:
                } else if (oii) {
                        /* release fixed inconsistent item */
                        CDEBUG(D_LFSCK,
-                              "%s: inconsistent OI "DFID" -> %u/%u fixed\n",
+                              "%s: inconsistent OI "DFID" -> %u/%u %s\n",
                               osd_dev2name(dev), PFID(fid), lid->oii_ino,
-                              lid->oii_gen);
+                              lid->oii_gen, ops == DTO_INDEX_DELETE ?
+                              "deleted" : "fixed");
                        spin_lock(&scrub->os_lock);
                        list_del_init(&oii->oii_list);
                        spin_unlock(&scrub->os_lock);
index 5d0d8fe..b5f8f88 100644 (file)
@@ -1423,6 +1423,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}