Whamcloud - gitweb
LU-9820 osd-ldiskfs: OI scrub speed limit fix
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_scrub.c
index 0a94e88..866dd04 100644 (file)
@@ -163,13 +163,13 @@ static int
 osd_scrub_convert_ff(struct osd_thread_info *info, struct osd_device *dev,
                     struct inode *inode, const struct lu_fid *fid)
 {
-       struct filter_fid_old   *ff      = &info->oti_ff;
-       struct dentry           *dentry  = &info->oti_obj_dentry;
-       struct lu_fid           *tfid    = &info->oti_fid;
-       handle_t                *jh;
-       int                      size    = 0;
-       int                      rc;
-       bool                     reset   = false;
+       struct filter_fid_18_23 *ff = &info->oti_ff_old;
+       struct dentry *dentry = &info->oti_obj_dentry;
+       struct lu_fid *tfid = &info->oti_fid;
+       bool fid_18_23 = false;
+       handle_t *jh;
+       int size = 0;
+       int rc;
        ENTRY;
 
        if (dev->od_scrub.os_scrub.os_file.sf_param & SP_DRYRUN)
@@ -207,19 +207,19 @@ osd_scrub_convert_ff(struct osd_thread_info *info, struct osd_device *dev,
        rc = __osd_xattr_get(inode, dentry, XATTR_NAME_FID, ff, sizeof(*ff));
        if (rc == sizeof(*ff)) {
                /* 2) delete the old XATTR_NAME_FID */
-               ll_vfs_dq_init(inode);
-               rc = inode->i_op->removexattr(dentry, XATTR_NAME_FID);
+               dquot_initialize(inode);
+               rc = ll_vfs_removexattr(dentry, inode, XATTR_NAME_FID);
                if (rc)
                        GOTO(stop, rc);
 
-               reset = true;
-       } else if (rc != -ENODATA && rc != sizeof(struct filter_fid)) {
+               fid_18_23 = true;
+       } else if (rc != -ENODATA && rc < (int)sizeof(struct filter_fid_24_29)) {
                GOTO(stop, rc = -EINVAL);
        }
 
        /* 3) make new LMA and add it */
        rc = osd_ea_fid_set(info, inode, tfid, LMAC_FID_ON_OST, 0);
-       if (reset) {
+       if (fid_18_23) {
                if (rc)
                        /* If failed, we should try to add the old back. */
                        size = sizeof(*ff);
@@ -339,9 +339,6 @@ iget:
                                GOTO(out, rc = 0);
                }
 
-               if (!scrub->os_partial_scan)
-                       scrub->os_full_speed = 1;
-
                switch (val) {
                case SCRUB_NEXT_NOLMA:
                        sf->sf_flags |= SF_UPGRADE;
@@ -367,9 +364,11 @@ iget:
 
                GOTO(out, rc = 0);
        } else {
-               if (!scrub->os_partial_scan)
+               if (!scrub->os_partial_scan) {
+                       spin_lock(&scrub->os_lock);
                        scrub->os_full_speed = 1;
-
+                       spin_unlock(&scrub->os_lock);
+               }
                sf->sf_flags |= SF_INCONSISTENT;
 
                /* XXX: If the device is restored from file-level backup, then
@@ -448,7 +447,6 @@ out:
 static int osd_scrub_prep(const struct lu_env *env, struct osd_device *dev)
 {
        struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
-       struct ptlrpc_thread *thread = &scrub->os_thread;
        struct scrub_file    *sf     = &scrub->os_file;
        __u32                 flags  = scrub->os_start_flags;
        int                   rc;
@@ -472,9 +470,9 @@ static int osd_scrub_prep(const struct lu_env *env, struct osd_device *dev)
        }
 
        if (flags & SS_RESET)
-               scrub_file_reset(scrub,
-                       LDISKFS_SB(osd_sb(dev))->s_es->s_uuid, 0);
+               scrub_file_reset(scrub, dev->od_uuid, 0);
 
+       spin_lock(&scrub->os_lock);
        if (flags & SS_AUTO_FULL) {
                scrub->os_full_speed = 1;
                scrub->os_partial_scan = 0;
@@ -492,7 +490,6 @@ static int osd_scrub_prep(const struct lu_env *env, struct osd_device *dev)
                scrub->os_partial_scan = 0;
        }
 
-       spin_lock(&scrub->os_lock);
        scrub->os_in_prior = 0;
        scrub->os_waiting = 0;
        scrub->os_paused = 0;
@@ -515,9 +512,9 @@ static int osd_scrub_prep(const struct lu_env *env, struct osd_device *dev)
        rc = scrub_file_store(env, scrub);
        if (rc == 0) {
                spin_lock(&scrub->os_lock);
-               thread_set_flags(thread, SVC_RUNNING);
+               scrub->os_running = 1;
                spin_unlock(&scrub->os_lock);
-               wake_up_all(&thread->t_ctl_waitq);
+               wake_up_var(scrub);
        }
        up_write(&scrub->os_rwsem);
 
@@ -537,7 +534,7 @@ static int osd_scrub_post(const struct lu_env *env, struct osd_device *dev,
 
        down_write(&scrub->os_rwsem);
        spin_lock(&scrub->os_lock);
-       thread_set_flags(&scrub->os_thread, SVC_STOPPING);
+       scrub->os_running = 0;
        spin_unlock(&scrub->os_lock);
        if (scrub->os_new_checked > 0) {
                sf->sf_items_checked += scrub->os_new_checked;
@@ -564,8 +561,9 @@ static int osd_scrub_post(const struct lu_env *env, struct osd_device *dev,
        } else {
                sf->sf_status = SS_FAILED;
        }
-       sf->sf_run_time += cfs_duration_sec(cfs_time_current() + HALF_SEC -
-                                           scrub->os_time_last_checkpoint);
+       sf->sf_run_time += ktime_get_seconds() -
+                          scrub->os_time_last_checkpoint;
+
        rc = scrub_file_store(env, scrub);
        up_write(&scrub->os_rwsem);
 
@@ -603,7 +601,7 @@ again:
                /* We should NOT find the same object more than once. */
                CERROR("%s: scan the same object multiple times at the pos: "
                       "group = %u, base = %u, offset = %u, start = %u\n",
-                      param->sb->s_id, (__u32)param->bg, param->gbase,
+                      osd_sb2name(param->sb), (__u32)param->bg, param->gbase,
                       offset, param->start);
                goto again;
        }
@@ -626,8 +624,8 @@ static int osd_scrub_check_local_fldb(struct osd_thread_info *info,
         *      quite possible for FID-on-MDT. */
        if (dev->od_is_ost)
                return SCRUB_NEXT_OSTOBJ_OLD;
-       else
-               return 0;
+
+       return 0;
 }
 
 static int osd_scrub_get_fid(struct osd_thread_info *info,
@@ -635,8 +633,8 @@ static int osd_scrub_get_fid(struct osd_thread_info *info,
                             struct lu_fid *fid, bool scrub)
 {
        struct lustre_mdt_attrs *lma = &info->oti_ost_attrs.loa_lma;
-       int rc;
        bool has_lma = false;
+       int rc;
 
        rc = osd_get_lma(info, inode, &info->oti_obj_dentry,
                         &info->oti_ost_attrs);
@@ -673,7 +671,7 @@ static int osd_scrub_get_fid(struct osd_thread_info *info,
                rc = osd_get_idif(info, inode, &info->oti_obj_dentry, fid);
                if (rc == 0) {
                        if (scrub)
-                               /* It is old 2.x (x <= 3) or 1.8 OST-object. */
+                               /* It is 2.3 or older OST-object. */
                                rc = SCRUB_NEXT_OSTOBJ_OLD;
                        return rc;
                }
@@ -684,7 +682,7 @@ static int osd_scrub_get_fid(struct osd_thread_info *info,
                                 * to generate its FID, ignore it directly. */
                                rc = SCRUB_NEXT_CONTINUE;
                        else
-                               /* It is 2.4 OST-object. */
+                               /* It is 2.4 or newer OST-object. */
                                rc = SCRUB_NEXT_OSTOBJ_OLD;
                        return rc;
                }
@@ -729,8 +727,15 @@ static int osd_iit_iget(struct osd_thread_info *info, struct osd_device *dev,
        /* Not handle the backend root object and agent parent object.
         * They are neither visible to namespace nor have OI mappings. */
        if (unlikely(pos == osd_sb(dev)->s_root->d_inode->i_ino ||
-                    pos == osd_remote_parent_ino(dev)))
+                    is_remote_parent_ino(dev, pos)))
+               RETURN(SCRUB_NEXT_CONTINUE);
+
+        /* Skip project quota inode since it is greater than s_first_ino. */
+#ifdef HAVE_PROJECT_QUOTA
+       if (ldiskfs_has_feature_project(sb) &&
+           pos == le32_to_cpu(LDISKFS_SB(sb)->s_es->s_prj_quota_inum))
                RETURN(SCRUB_NEXT_CONTINUE);
+#endif
 
        osd_id_gen(lid, pos, OSD_OII_NOGEN);
        inode = osd_iget(info, dev, lid);
@@ -771,25 +776,20 @@ static int osd_scrub_next(struct osd_thread_info *info, struct osd_device *dev,
                          struct osd_idmap_cache **oic, const bool noslot)
 {
        struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
-       struct ptlrpc_thread *thread = &scrub->os_thread;
        struct lu_fid *fid;
        struct osd_inode_id *lid;
        int rc;
 
-       if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_DELAY) && cfs_fail_val > 0) {
-               struct l_wait_info lwi;
-
-               lwi = LWI_TIMEOUT(cfs_time_seconds(cfs_fail_val), NULL, NULL);
-               if (likely(lwi.lwi_timeout > 0))
-                       l_wait_event(thread->t_ctl_waitq,
-                               !list_empty(&scrub->os_inconsistent_items) ||
-                               !thread_is_running(thread),
-                               &lwi);
-       }
+       if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_DELAY) && cfs_fail_val > 0)
+               wait_var_event_timeout(
+                       scrub,
+                       !list_empty(&scrub->os_inconsistent_items) ||
+                       kthread_should_stop(),
+                       cfs_time_seconds(cfs_fail_val));
 
        if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_CRASH)) {
                spin_lock(&scrub->os_lock);
-               thread_set_flags(thread, SVC_STOPPING);
+               scrub->os_running = 0;
                spin_unlock(&scrub->os_lock);
                return SCRUB_NEXT_CRASH;
        }
@@ -797,7 +797,7 @@ static int osd_scrub_next(struct osd_thread_info *info, struct osd_device *dev,
        if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_FATAL))
                return SCRUB_NEXT_FATAL;
 
-       if (unlikely(!thread_is_running(thread)))
+       if (kthread_should_stop())
                return SCRUB_NEXT_EXIT;
 
        if (!list_empty(&scrub->os_inconsistent_items)) {
@@ -807,10 +807,10 @@ static int osd_scrub_next(struct osd_thread_info *info, struct osd_device *dev,
 
                        oii = list_entry(scrub->os_inconsistent_items.next,
                                struct osd_inconsistent_item, oii_list);
-                       spin_unlock(&scrub->os_lock);
 
                        *oic = &oii->oii_cache;
                        scrub->os_in_prior = 1;
+                       spin_unlock(&scrub->os_lock);
 
                        return 0;
                }
@@ -838,10 +838,9 @@ static int osd_preload_next(struct osd_thread_info *info,
 {
        struct osd_otable_cache *ooc = &dev->od_otable_it->ooi_cache;
        struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
-       struct ptlrpc_thread *thread = &scrub->os_thread;
        int rc;
 
-       if (thread_is_running(thread) &&
+       if (scrub->os_running &&
            ooc->ooc_pos_preload >= scrub->os_pos_current)
                return SCRUB_NEXT_EXIT;
 
@@ -862,7 +861,7 @@ osd_scrub_wakeup(struct lustre_scrub *scrub, struct osd_otable_it *it)
        spin_lock(&scrub->os_lock);
        if (osd_scrub_has_window(scrub, &it->ooi_cache) ||
            !list_empty(&scrub->os_inconsistent_items) ||
-           it->ooi_waiting || !thread_is_running(&scrub->os_thread))
+           it->ooi_waiting || kthread_should_stop())
                scrub->os_waiting = 0;
        else
                scrub->os_waiting = 1;
@@ -875,10 +874,8 @@ static int osd_scrub_exec(struct osd_thread_info *info, struct osd_device *dev,
                          struct osd_iit_param *param,
                          struct osd_idmap_cache *oic, bool *noslot, int rc)
 {
-       struct l_wait_info lwi = { 0 };
        struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
        struct scrub_file *sf = &scrub->os_file;
-       struct ptlrpc_thread *thread = &scrub->os_thread;
        struct osd_otable_it *it = dev->od_otable_it;
        struct osd_otable_cache *ooc = it ? &it->ooi_cache : NULL;
 
@@ -895,7 +892,9 @@ static int osd_scrub_exec(struct osd_thread_info *info, struct osd_device *dev,
 
        rc = osd_scrub_check_update(info, dev, oic, rc);
        if (rc != 0) {
+               spin_lock(&scrub->os_lock);
                scrub->os_in_prior = 0;
+               spin_unlock(&scrub->os_lock);
                return rc;
        }
 
@@ -908,7 +907,9 @@ static int osd_scrub_exec(struct osd_thread_info *info, struct osd_device *dev,
        }
 
        if (scrub->os_in_prior) {
+               spin_lock(&scrub->os_lock);
                scrub->os_in_prior = 0;
+               spin_unlock(&scrub->os_lock);
                return 0;
        }
 
@@ -917,7 +918,7 @@ wait:
            ooc->ooc_pos_preload < scrub->os_pos_current) {
                spin_lock(&scrub->os_lock);
                it->ooi_waiting = 0;
-               wake_up_all(&thread->t_ctl_waitq);
+               wake_up_var(scrub);
                spin_unlock(&scrub->os_lock);
        }
 
@@ -929,9 +930,8 @@ wait:
                return 0;
        }
 
-       if (it != NULL)
-               l_wait_event(thread->t_ctl_waitq, osd_scrub_wakeup(scrub, it),
-                            &lwi);
+       if (it)
+               wait_var_event(scrub, osd_scrub_wakeup(scrub, it));
 
        if (!ooc || osd_scrub_has_window(scrub, ooc))
                *noslot = false;
@@ -961,7 +961,6 @@ static void osd_scrub_join(const struct lu_env *env, struct osd_device *dev,
                           __u32 flags, bool inconsistent)
 {
        struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
-       struct ptlrpc_thread *thread = &scrub->os_thread;
        struct scrub_file    *sf     = &scrub->os_file;
        int                   rc;
        ENTRY;
@@ -969,6 +968,7 @@ static void osd_scrub_join(const struct lu_env *env, struct osd_device *dev,
        LASSERT(!(flags & SS_AUTO_PARTIAL));
 
        down_write(&scrub->os_rwsem);
+       spin_lock(&scrub->os_lock);
        scrub->os_in_join = 1;
        if (flags & SS_SET_FAILOUT)
                sf->sf_param |= SP_FAILOUT;
@@ -981,8 +981,8 @@ static void osd_scrub_join(const struct lu_env *env, struct osd_device *dev,
                sf->sf_param &= ~SP_DRYRUN;
 
        if (flags & SS_RESET) {
-               scrub_file_reset(scrub, LDISKFS_SB(osd_sb(dev))->s_es->s_uuid,
-                       inconsistent ? SF_INCONSISTENT : 0);
+               scrub_file_reset(scrub, dev->od_uuid,
+                                inconsistent ? SF_INCONSISTENT : 0);
                sf->sf_status = SS_SCANNING;
        }
 
@@ -995,6 +995,7 @@ static void osd_scrub_join(const struct lu_env *env, struct osd_device *dev,
                sf->sf_flags |= SF_AUTO;
                scrub->os_full_speed = 1;
        }
+       spin_unlock(&scrub->os_lock);
 
        scrub->os_new_checked = 0;
        if (sf->sf_pos_last_checkpoint != 0)
@@ -1015,7 +1016,7 @@ static void osd_scrub_join(const struct lu_env *env, struct osd_device *dev,
        scrub->os_in_join = 0;
        scrub->os_full_scrub = 0;
        spin_unlock(&scrub->os_lock);
-       wake_up_all(&thread->t_ctl_waitq);
+       wake_up_var(scrub);
        up_write(&scrub->os_rwsem);
 
        CDEBUG(D_LFSCK, "%s: joined in the OI scrub with flag %u: rc = %d\n",
@@ -1028,14 +1029,12 @@ static int osd_inode_iteration(struct osd_thread_info *info,
                               struct osd_device *dev, __u32 max, bool preload)
 {
        struct lustre_scrub *scrub  = &dev->od_scrub.os_scrub;
-       struct ptlrpc_thread *thread = &scrub->os_thread;
        struct scrub_file *sf = &scrub->os_file;
        osd_iit_next_policy next;
        osd_iit_exec_policy exec;
        __u64 *pos;
        __u64 *count;
        struct osd_iit_param *param;
-       struct l_wait_info lwi = { 0 };
        __u32 limit;
        int rc;
        bool noslot = true;
@@ -1078,7 +1077,7 @@ static int osd_inode_iteration(struct osd_thread_info *info,
                        if (rc == 0) {
                                __u64 used = ksfs->f_files - ksfs->f_ffree;
 
-                               do_div(used, sf->sf_items_updated_prior);
+                               used = div64_u64(used, sf->sf_items_updated_prior);
                                /* If we hit too much inconsistent OI
                                 * mappings during the partial scan,
                                 * then scan the device completely. */
@@ -1098,16 +1097,16 @@ wait:
                        sf->sf_flags &= ~(SF_RECREATED | SF_INCONSISTENT |
                                          SF_UPGRADE | SF_AUTO);
                        sf->sf_status = SS_COMPLETED;
-                       l_wait_event(thread->t_ctl_waitq,
-                                    !thread_is_running(thread) ||
-                                    !scrub->os_partial_scan ||
-                                    scrub->os_in_join ||
-                                    !list_empty(&scrub->os_inconsistent_items),
-                                    &lwi);
+                       wait_var_event(
+                               scrub,
+                               kthread_should_stop() ||
+                               !scrub->os_partial_scan ||
+                               scrub->os_in_join ||
+                               !list_empty(&scrub->os_inconsistent_items));
                        sf->sf_flags = saved_flags;
                        sf->sf_status = SS_SCANNING;
 
-                       if (unlikely(!thread_is_running(thread)))
+                       if (kthread_should_stop())
                                RETURN(0);
 
                        if (!scrub->os_partial_scan || scrub->os_in_join)
@@ -1125,11 +1124,11 @@ wait:
 
 full:
        if (!preload) {
-               l_wait_event(thread->t_ctl_waitq,
-                            !thread_is_running(thread) || !scrub->os_in_join,
-                            &lwi);
+               wait_var_event(scrub,
+                              kthread_should_stop() ||
+                              !scrub->os_in_join);
 
-               if (unlikely(!thread_is_running(thread)))
+               if (kthread_should_stop())
                        RETURN(0);
        }
 
@@ -1250,7 +1249,7 @@ static int osd_otable_it_preload(const struct lu_env *env,
        if (scrub->os_waiting && osd_scrub_has_window(scrub, ooc)) {
                spin_lock(&scrub->os_lock);
                scrub->os_waiting = 0;
-               wake_up_all(&scrub->os_thread.t_ctl_waitq);
+               wake_up_var(scrub);
                spin_unlock(&scrub->os_lock);
        }
 
@@ -1262,7 +1261,6 @@ static int osd_scrub_main(void *args)
        struct lu_env env;
        struct osd_device *dev = (struct osd_device *)args;
        struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
-       struct ptlrpc_thread *thread = &scrub->os_thread;
        int rc;
        ENTRY;
 
@@ -1281,14 +1279,12 @@ static int osd_scrub_main(void *args)
        }
 
        if (!scrub->os_full_speed && !scrub->os_partial_scan) {
-               struct l_wait_info lwi = { 0 };
                struct osd_otable_it *it = dev->od_otable_it;
                struct osd_otable_cache *ooc = &it->ooi_cache;
 
-               l_wait_event(thread->t_ctl_waitq,
-                            it->ooi_user_ready || !thread_is_running(thread),
-                            &lwi);
-               if (unlikely(!thread_is_running(thread)))
+               wait_var_event(scrub,
+                              it->ooi_user_ready || kthread_should_stop());
+               if (kthread_should_stop())
                        GOTO(post, rc = 0);
 
                scrub->os_pos_current = ooc->ooc_pos_preload;
@@ -1301,7 +1297,7 @@ static int osd_scrub_main(void *args)
        rc = osd_inode_iteration(osd_oti_get(&env), dev, ~0U, false);
        if (unlikely(rc == SCRUB_IT_CRASH)) {
                spin_lock(&scrub->os_lock);
-               thread_set_flags(&scrub->os_thread, SVC_STOPPING);
+               scrub->os_running = 0;
                spin_unlock(&scrub->os_lock);
                GOTO(out, rc = -EINVAL);
        }
@@ -1326,9 +1322,12 @@ out:
 
 noenv:
        spin_lock(&scrub->os_lock);
-       thread_set_flags(thread, SVC_STOPPED);
-       wake_up_all(&thread->t_ctl_waitq);
+       scrub->os_running = 0;
        spin_unlock(&scrub->os_lock);
+       if (xchg(&scrub->os_task, NULL) == NULL)
+               /* scrub_stop() is waiting, we need to synchronize */
+               wait_var_event(scrub, kthread_should_stop());
+       wake_up_var(scrub);
        return rc;
 }
 
@@ -1418,8 +1417,8 @@ static const struct osd_lf_map osd_lf_maps[] = {
 
        /* PENDING */
        {
-               .olm_name       = "PENDING",
-               .olm_namelen    = sizeof("PENDING") - 1,
+               .olm_name       = MDT_ORPHAN_DIR,
+               .olm_namelen    = sizeof(MDT_ORPHAN_DIR) - 1,
        },
 
        /* ROOT */
@@ -1671,6 +1670,19 @@ static const struct osd_lf_map osd_lf_maps[] = {
                .olm_name       = LUSTRE_NODEMAP_NAME,
        },
 
+       /* index_backup */
+       {
+               .olm_name       = INDEX_BACKUP_DIR,
+               .olm_fid        = {
+                       .f_seq  = FID_SEQ_LOCAL_FILE,
+                       .f_oid  = INDEX_BACKUP_OID,
+               },
+               .olm_flags      = OLF_SCAN_SUBITEMS | OLF_NOT_BACKUP,
+               .olm_namelen    = sizeof(INDEX_BACKUP_DIR) - 1,
+               .olm_scandir    = osd_ios_general_scan,
+               .olm_filldir    = osd_ios_varfid_fill,
+       },
+
        {
                .olm_name       = NULL
        }
@@ -1711,42 +1723,14 @@ struct osd_ios_item {
 };
 
 struct osd_ios_filldir_buf {
-#ifdef HAVE_DIR_CONTEXT
        /* please keep it as first member */
        struct dir_context       ctx;
-#endif
        struct osd_thread_info  *oifb_info;
        struct osd_device       *oifb_dev;
        struct dentry           *oifb_dentry;
        int                      oifb_items;
 };
 
-static inline struct dentry *
-osd_ios_lookup_one_len(const char *name, struct dentry *parent, int namelen)
-{
-       struct dentry *dentry;
-
-       dentry = ll_lookup_one_len(name, parent, namelen);
-       if (IS_ERR(dentry)) {
-               int rc = PTR_ERR(dentry);
-
-               if (rc != -ENOENT)
-                       CERROR("Fail to find %.*s in %.*s (%lu/%u): rc = %d\n",
-                              namelen, name, parent->d_name.len,
-                              parent->d_name.name, parent->d_inode->i_ino,
-                              parent->d_inode->i_generation, rc);
-
-               return dentry;
-       }
-
-       if (dentry->d_inode == NULL) {
-               dput(dentry);
-               return ERR_PTR(-ENOENT);
-       }
-
-       return dentry;
-}
-
 static int
 osd_ios_new_item(struct osd_device *dev, struct dentry *dentry,
                 scandir_t scandir, filldir_t filldir)
@@ -1767,6 +1751,119 @@ osd_ios_new_item(struct osd_device *dev, struct dentry *dentry,
        RETURN(0);
 }
 
+static bool osd_index_need_recreate(const struct lu_env *env,
+                                   struct osd_device *dev, struct inode *inode)
+{
+       struct osd_directory *iam = &osd_oti_get(env)->oti_iam;
+       struct iam_container *bag = &iam->od_container;
+       int rc;
+       ENTRY;
+
+       rc = iam_container_init(bag, &iam->od_descr, inode);
+       if (rc)
+               RETURN(true);
+
+       rc = iam_container_setup(bag);
+       iam_container_fini(bag);
+       if (rc)
+               RETURN(true);
+
+       RETURN(false);
+}
+
+static void osd_ios_index_register(const struct lu_env *env,
+                                  struct osd_device *osd,
+                                  const struct lu_fid *fid,
+                                  struct inode *inode)
+{
+       struct osd_directory *iam = &osd_oti_get(env)->oti_iam;
+       struct iam_container *bag = &iam->od_container;
+       struct super_block *sb = osd_sb(osd);
+       struct iam_descr *descr;
+       __u32 keysize = 0;
+       __u32 recsize = 0;
+       int rc;
+       ENTRY;
+
+       /* Index must be a regular file. */
+       if (!S_ISREG(inode->i_mode))
+               RETURN_EXIT;
+
+       /* Index's size must be block aligned. */
+       if (inode->i_size < sb->s_blocksize ||
+           (inode->i_size & (sb->s_blocksize - 1)) != 0)
+               RETURN_EXIT;
+
+       iam_container_init(bag, &iam->od_descr, inode);
+       rc = iam_container_setup(bag);
+       if (rc)
+               GOTO(fini, rc = 1);
+
+       descr = bag->ic_descr;
+       /* May be regular file with IAM_LFIX_ROOT_MAGIC matched
+        * coincidentally, or corrupted index object, skip it. */
+       if (descr->id_ptr_size != 4)
+               GOTO(fini, rc = 1);
+
+       keysize = descr->id_key_size;
+       recsize = descr->id_rec_size;
+       rc = osd_index_register(osd, fid, keysize, recsize);
+
+       GOTO(fini, rc);
+
+fini:
+       iam_container_fini(bag);
+       if (!rc)
+               CDEBUG(D_LFSCK, "%s: index object "DFID" (%u/%u) registered\n",
+                      osd_name(osd), PFID(fid), keysize, recsize);
+}
+
+static void osd_index_restore(const struct lu_env *env, struct osd_device *dev,
+                             struct lustre_index_restore_unit *liru,
+                             void *buf, int bufsize)
+{
+       struct osd_thread_info *info = osd_oti_get(env);
+       struct osd_inode_id *id = &info->oti_id;
+       struct lu_fid *tgt_fid = &liru->liru_cfid;
+       struct inode *bak_inode = NULL;
+       struct ldiskfs_dir_entry_2 *de = NULL;
+       struct buffer_head *bh = NULL;
+       struct dentry *dentry;
+       char *name = buf;
+       struct lu_fid bak_fid;
+       int rc;
+       ENTRY;
+
+       lustre_fid2lbx(name, tgt_fid, bufsize);
+       dentry = osd_child_dentry_by_inode(env, dev->od_index_backup_inode,
+                                          name, strlen(name));
+       bh = osd_ldiskfs_find_entry(dev->od_index_backup_inode,
+                                   &dentry->d_name, &de, NULL, NULL);
+       if (IS_ERR(bh))
+               GOTO(log, rc = PTR_ERR(bh));
+
+       osd_id_gen(id, le32_to_cpu(de->inode), OSD_OII_NOGEN);
+       brelse(bh);
+       bak_inode = osd_iget_fid(info, dev, id, &bak_fid);
+       if (IS_ERR(bak_inode))
+               GOTO(log, rc = PTR_ERR(bak_inode));
+
+       iput(bak_inode);
+       /* The OI mapping for index may be invalid, since it will be
+        * re-created, not update the OI mapping, just cache it in RAM. */
+       osd_id_gen(id, liru->liru_clid, OSD_OII_NOGEN);
+       osd_add_oi_cache(info, dev, id, tgt_fid);
+       rc = lustre_index_restore(env, &dev->od_dt_dev, &liru->liru_pfid,
+                                 tgt_fid, &bak_fid, liru->liru_name,
+                                 &dev->od_index_backup_list, &dev->od_lock,
+                                 buf, bufsize);
+       GOTO(log, rc);
+
+log:
+       CDEBUG(D_WARNING, "%s: restore index '%s' with "DFID": rc = %d\n",
+              osd_name(dev), liru->liru_name, PFID(tgt_fid), rc);
+}
+
 /**
  * osd_ios_scan_one() - check/fix LMA FID and OI entry for one inode
  *
@@ -1776,7 +1873,9 @@ osd_ios_new_item(struct osd_device *dev, struct dentry *dentry,
  */
 static int
 osd_ios_scan_one(struct osd_thread_info *info, struct osd_device *dev,
-                struct inode *inode, const struct lu_fid *fid, int flags)
+                struct inode *parent, struct inode *inode,
+                const struct lu_fid *fid, const char *name,
+                int namelen, int flags)
 {
        struct lustre_mdt_attrs *lma    = &info->oti_ost_attrs.loa_lma;
        struct osd_inode_id     *id     = &info->oti_id;
@@ -1787,6 +1886,12 @@ osd_ios_scan_one(struct osd_thread_info *info, struct osd_device *dev,
        int                      rc;
        ENTRY;
 
+       if (!inode) {
+               CDEBUG(D_INODE, "%s: child '%.*s' lacks inode: rc = -2\n",
+                      osd_name(dev), namelen, name);
+               RETURN(-ENOENT);
+       }
+
        rc = osd_get_lma(info, inode, &info->oti_obj_dentry,
                         &info->oti_ost_attrs);
        if (rc != 0 && rc != -ENODATA) {
@@ -1820,9 +1925,32 @@ osd_ios_scan_one(struct osd_thread_info *info, struct osd_device *dev,
                        RETURN(0);
 
                tfid = lma->lma_self_fid;
+               if (lma->lma_compat & LMAC_IDX_BACKUP &&
+                   osd_index_need_recreate(info->oti_env, dev, inode)) {
+                       struct lu_fid *pfid = &info->oti_fid3;
+
+                       if (parent == osd_sb(dev)->s_root->d_inode) {
+                               lu_local_obj_fid(pfid, OSD_FS_ROOT_OID);
+                       } else {
+                               rc = osd_scrub_get_fid(info, dev, parent, pfid,
+                                                      false);
+                               if (rc)
+                                       RETURN(rc);
+                       }
+
+                       rc = lustre_liru_new(&dev->od_index_restore_list, pfid,
+                                       &tfid, inode->i_ino, name, namelen);
+
+                       RETURN(rc);
+               }
+
+               if (!(flags & OLF_NOT_BACKUP))
+                       osd_ios_index_register(info->oti_env, dev, &tfid,
+                                              inode);
        }
 
-       rc = osd_oi_lookup(info, dev, &tfid, id2, 0);
+       /* Since this called from iterate_dir() the inode lock will be taken */
+       rc = osd_oi_lookup(info, dev, &tfid, id2, OI_LOCKED);
        if (rc != 0) {
                if (rc != -ENOENT)
                        RETURN(rc);
@@ -1839,8 +1967,7 @@ osd_ios_scan_one(struct osd_thread_info *info, struct osd_device *dev,
                RETURN(0);
 
        if (!(sf->sf_flags & SF_INCONSISTENT)) {
-               scrub_file_reset(scrub, LDISKFS_SB(osd_sb(dev))->s_es->s_uuid,
-                                SF_INCONSISTENT);
+               scrub_file_reset(scrub, dev->od_uuid, SF_INCONSISTENT);
                rc = scrub_file_store(info->oti_env, scrub);
                if (rc != 0)
                        RETURN(rc);
@@ -1856,7 +1983,7 @@ osd_ios_scan_one(struct osd_thread_info *info, struct osd_device *dev,
 
 /**
  * It scans the /lost+found, and for the OST-object (with filter_fid
- * or filter_fid_old), move them back to its proper /O/<seq>/d<x>.
+ * or filter_fid_18_23), move them back to its proper /O/<seq>/d<x>.
  */
 #ifdef HAVE_FILLDIR_USE_CTX
 static int osd_ios_lf_fill(struct dir_context *buf,
@@ -1886,11 +2013,17 @@ static int osd_ios_lf_fill(void *buf,
                RETURN(0);
 
        scrub->os_lf_scanned++;
-       child = osd_ios_lookup_one_len(name, parent, namelen);
+       child = osd_lookup_one_len(dev, name, parent, namelen);
        if (IS_ERR(child)) {
+               rc = PTR_ERR(child);
                CDEBUG(D_LFSCK, "%s: cannot lookup child '%.*s': rc = %d\n",
-                     osd_name(dev), namelen, name, (int)PTR_ERR(child));
-               RETURN(0);
+                     osd_name(dev), namelen, name, rc);
+               RETURN(rc);
+       } else if (!child->d_inode) {
+               dput(child);
+               CDEBUG(D_INODE, "%s: child '%.*s' lacks inode\n",
+                      osd_name(dev), namelen, name);
+               RETURN(-ENOENT);
        }
 
        inode = child->d_inode;
@@ -1955,12 +2088,13 @@ static int osd_ios_varfid_fill(void *buf,
        if (name[0] == '.')
                RETURN(0);
 
-       child = osd_ios_lookup_one_len(name, fill_buf->oifb_dentry, namelen);
+       child = osd_lookup_one_len(dev, name, fill_buf->oifb_dentry, namelen);
        if (IS_ERR(child))
                RETURN(PTR_ERR(child));
 
-       rc = osd_ios_scan_one(fill_buf->oifb_info, dev, child->d_inode,
-                             NULL, 0);
+       rc = osd_ios_scan_one(fill_buf->oifb_info, dev,
+                             fill_buf->oifb_dentry->d_inode, child->d_inode,
+                             NULL, name, namelen, 0);
        if (rc == 0 && S_ISDIR(child->d_inode->i_mode))
                rc = osd_ios_new_item(dev, child, osd_ios_general_scan,
                                      osd_ios_varfid_fill);
@@ -2002,12 +2136,13 @@ static int osd_ios_dl_fill(void *buf,
        if (map->olm_name == NULL)
                RETURN(0);
 
-       child = osd_ios_lookup_one_len(name, fill_buf->oifb_dentry, namelen);
+       child = osd_lookup_one_len(dev, name, fill_buf->oifb_dentry, namelen);
        if (IS_ERR(child))
                RETURN(PTR_ERR(child));
 
-       rc = osd_ios_scan_one(fill_buf->oifb_info, dev, child->d_inode,
-                             &map->olm_fid, map->olm_flags);
+       rc = osd_ios_scan_one(fill_buf->oifb_info, dev,
+                             fill_buf->oifb_dentry->d_inode, child->d_inode,
+                             &map->olm_fid, name, namelen, map->olm_flags);
        dput(child);
 
        RETURN(rc);
@@ -2023,6 +2158,7 @@ static int osd_ios_uld_fill(void *buf,
 {
        struct osd_ios_filldir_buf *fill_buf =
                (struct osd_ios_filldir_buf *)buf;
+       struct osd_device *dev = fill_buf->oifb_dev;
        struct dentry              *child;
        struct lu_fid               tfid;
        int                         rc       = 0;
@@ -2034,7 +2170,7 @@ static int osd_ios_uld_fill(void *buf,
        if (name[0] != '[')
                RETURN(0);
 
-       child = osd_ios_lookup_one_len(name, fill_buf->oifb_dentry, namelen);
+       child = osd_lookup_one_len(dev, name, fill_buf->oifb_dentry, namelen);
        if (IS_ERR(child))
                RETURN(PTR_ERR(child));
 
@@ -2042,7 +2178,8 @@ static int osd_ios_uld_fill(void *buf,
        sscanf(&name[1], SFID, RFID(&tfid));
        if (fid_is_sane(&tfid))
                rc = osd_ios_scan_one(fill_buf->oifb_info, fill_buf->oifb_dev,
-                                     child->d_inode, &tfid, 0);
+                                     fill_buf->oifb_dentry->d_inode,
+                                     child->d_inode, &tfid, name, namelen, 0);
        else
                rc = -EIO;
        dput(child);
@@ -2083,16 +2220,20 @@ static int osd_ios_root_fill(void *buf,
        if (map->olm_name == NULL)
                RETURN(0);
 
-       child = osd_ios_lookup_one_len(name, fill_buf->oifb_dentry, namelen);
+       child = osd_lookup_one_len(dev, name, fill_buf->oifb_dentry, namelen);
        if (IS_ERR(child))
                RETURN(PTR_ERR(child));
+       else if (!child->d_inode)
+               GOTO(out_put, rc = -ENOENT);
 
        if (!(map->olm_flags & OLF_NO_OI))
-               rc = osd_ios_scan_one(fill_buf->oifb_info, dev, child->d_inode,
-                                     &map->olm_fid, map->olm_flags);
+               rc = osd_ios_scan_one(fill_buf->oifb_info, dev,
+                               fill_buf->oifb_dentry->d_inode, child->d_inode,
+                               &map->olm_fid, name, namelen, map->olm_flags);
        if (rc == 0 && map->olm_flags & OLF_SCAN_SUBITEMS)
                rc = osd_ios_new_item(dev, child, map->olm_scandir,
                                      map->olm_filldir);
+out_put:
        dput(child);
 
        RETURN(rc);
@@ -2102,41 +2243,31 @@ static int
 osd_ios_general_scan(struct osd_thread_info *info, struct osd_device *dev,
                     struct dentry *dentry, filldir_t filldir)
 {
-       struct osd_ios_filldir_buf    buf   = {
-#ifdef HAVE_DIR_CONTEXT
-                                               .ctx.actor = filldir,
-#endif
-                                               .oifb_info = info,
-                                               .oifb_dev = dev,
-                                               .oifb_dentry = dentry };
-       struct file                  *filp  = &info->oti_file;
-       struct inode                 *inode = dentry->d_inode;
-       const struct file_operations *fops  = inode->i_fop;
-       int                           rc;
+       struct osd_ios_filldir_buf buf = {
+               .ctx.actor = filldir,
+               .oifb_info = info,
+               .oifb_dev = dev,
+               .oifb_dentry = dentry
+       };
+       struct file *filp;
+       struct inode *inode = dentry->d_inode;
+       int rc;
+
        ENTRY;
 
        LASSERT(filldir != NULL);
 
-       filp->f_pos = 0;
-       filp->f_path.dentry = dentry;
-       filp->f_mode = FMODE_64BITHASH;
-       filp->f_mapping = inode->i_mapping;
-       filp->f_op = fops;
-       filp->private_data = NULL;
-       set_file_inode(filp, inode);
+       filp = osd_quasi_file_by_dentry(info->oti_env, dentry);
+       rc = osd_security_file_alloc(filp);
+       if (rc)
+               RETURN(rc);
 
        do {
                buf.oifb_items = 0;
-#ifdef HAVE_DIR_CONTEXT
-               buf.ctx.pos = filp->f_pos;
-               rc = fops->iterate(filp, &buf.ctx);
-               filp->f_pos = buf.ctx.pos;
-#else
-               rc = fops->readdir(filp, &buf, filldir);
-#endif
+               rc = iterate_dir(filp, &buf.ctx);
        } while (rc >= 0 && buf.oifb_items > 0 &&
                 filp->f_pos != LDISKFS_HTREE_EOF_64BIT);
-       fops->release(inode, filp);
+       inode->i_fop->release(inode, filp);
 
        RETURN(rc);
 }
@@ -2163,55 +2294,65 @@ osd_ios_ROOT_scan(struct osd_thread_info *info, struct osd_device *dev,
         *      FID directly, instead, the OI scrub will scan the OI structure
         *      and try to re-generate the LMA from the OI mapping. But if the
         *      OI mapping crashed or lost also, then we have to give up under
-        *      double failure cases. */
+        *      double failure cases.
+        */
+       spin_lock(&scrub->os_lock);
        scrub->os_convert_igif = 1;
-       child = osd_ios_lookup_one_len(dot_lustre_name, dentry,
-                                      strlen(dot_lustre_name));
+       spin_unlock(&scrub->os_lock);
+       child = osd_lookup_one_len_unlocked(dev, dot_lustre_name, dentry,
+                                           strlen(dot_lustre_name));
        if (IS_ERR(child)) {
-               rc = PTR_ERR(child);
-               if (rc == -ENOENT) {
-                       /* It is 1.8 MDT device. */
-                       if (!(sf->sf_flags & SF_UPGRADE)) {
-                               scrub_file_reset(scrub,
-                                       LDISKFS_SB(osd_sb(dev))->s_es->s_uuid,
-                                       SF_UPGRADE);
-                               sf->sf_internal_flags &= ~SIF_NO_HANDLE_OLD_FID;
-                               rc = scrub_file_store(info->oti_env, scrub);
-                       } else {
-                               rc = 0;
-                       }
+               if (PTR_ERR(child) != -ENOENT)
+                       RETURN(PTR_ERR(child));
+               goto out_scrub;
+       }
+
+       /* For lustre-2.x (x <= 3), the ".lustre" has NO FID-in-LMA,
+        * so the client will get IGIF for the ".lustre" object when
+        * the MDT restart.
+        *
+        * From the OI scrub view, when the MDT upgrade to Lustre-2.4,
+        * it does not know whether there are some old clients cached
+        * the ".lustre" IGIF during the upgrading. Two choices:
+        *
+        * 1) Generate IGIF-in-LMA and IGIF-in-OI for the ".lustre".
+        *    It will allow the old connected clients to access the
+        *    ".lustre" with cached IGIF. But it will cause others
+        *    on the MDT failed to check "fid_is_dot_lustre()".
+        *
+        * 2) Use fixed FID {FID_SEQ_DOT_LUSTRE, FID_OID_DOT_LUSTRE, 0}
+        *    for ".lustre" in spite of whether there are some clients
+        *    cached the ".lustre" IGIF or not. It enables the check
+        *    "fid_is_dot_lustre()" on the MDT, although it will cause
+        *    that the old connected clients cannot access the ".lustre"
+        *    with the cached IGIF.
+        *
+        * Usually, it is rare case for the old connected clients
+        * to access the ".lustre" with cached IGIF. So we prefer
+        * to the solution 2).
+        */
+       inode_lock(dentry->d_inode);
+       rc = osd_ios_scan_one(info, dev, dentry->d_inode,
+                             child->d_inode, &LU_DOT_LUSTRE_FID,
+                             dot_lustre_name,
+                             strlen(dot_lustre_name), 0);
+       inode_unlock(dentry->d_inode);
+       if (rc == -ENOENT) {
+out_scrub:
+               /* It is 1.8 MDT device. */
+               if (!(sf->sf_flags & SF_UPGRADE)) {
+                       scrub_file_reset(scrub, dev->od_uuid,
+                                        SF_UPGRADE);
+                       sf->sf_internal_flags &= ~SIF_NO_HANDLE_OLD_FID;
+                       rc = scrub_file_store(info->oti_env, scrub);
+               } else {
+                       rc = 0;
                }
-       } else {
-               /* For lustre-2.x (x <= 3), the ".lustre" has NO FID-in-LMA,
-                * so the client will get IGIF for the ".lustre" object when
-                * the MDT restart.
-                *
-                * From the OI scrub view, when the MDT upgrade to Lustre-2.4,
-                * it does not know whether there are some old clients cached
-                * the ".lustre" IGIF during the upgrading. Two choices:
-                *
-                * 1) Generate IGIF-in-LMA and IGIF-in-OI for the ".lustre".
-                *    It will allow the old connected clients to access the
-                *    ".lustre" with cached IGIF. But it will cause others
-                *    on the MDT failed to check "fid_is_dot_lustre()".
-                *
-                * 2) Use fixed FID {FID_SEQ_DOT_LUSTRE, FID_OID_DOT_LUSTRE, 0}
-                *    for ".lustre" in spite of whether there are some clients
-                *    cached the ".lustre" IGIF or not. It enables the check
-                *    "fid_is_dot_lustre()" on the MDT, although it will cause
-                *    that the old connected clients cannot access the ".lustre"
-                *    with the cached IGIF.
-                *
-                * Usually, it is rare case for the old connected clients
-                * to access the ".lustre" with cached IGIF. So we prefer
-                * to the solution 2). */
-               rc = osd_ios_scan_one(info, dev, child->d_inode,
-                                     &LU_DOT_LUSTRE_FID, 0);
-               if (rc == 0)
-                       rc = osd_ios_new_item(dev, child, osd_ios_general_scan,
-                                             osd_ios_dl_fill);
-               dput(child);
+       } else if (rc == 0) {
+               rc = osd_ios_new_item(dev, child, osd_ios_general_scan,
+                                     osd_ios_dl_fill);
        }
+       dput(child);
 
        RETURN(rc);
 }
@@ -2233,55 +2374,63 @@ osd_ios_OBJECTS_scan(struct osd_thread_info *info, struct osd_device *dev,
                        RETURN(rc);
        }
 
-       child = osd_ios_lookup_one_len(ADMIN_USR, dentry, strlen(ADMIN_USR));
-       if (!IS_ERR(child)) {
-               rc = osd_ios_scan_one(info, dev, child->d_inode, NULL, 0);
-               dput(child);
-       } else {
+       child = osd_lookup_one_len_unlocked(dev, ADMIN_USR, dentry,
+                                           strlen(ADMIN_USR));
+       if (IS_ERR(child)) {
                rc = PTR_ERR(child);
+       } else {
+               inode_lock(dentry->d_inode);
+               rc = osd_ios_scan_one(info, dev, dentry->d_inode,
+                                     child->d_inode, NULL, ADMIN_USR,
+                                     strlen(ADMIN_USR), 0);
+               inode_unlock(dentry->d_inode);
+               dput(child);
        }
 
        if (rc != 0 && rc != -ENOENT)
-               RETURN(rc);
-
-       child = osd_ios_lookup_one_len(ADMIN_GRP, dentry, strlen(ADMIN_GRP));
-       if (!IS_ERR(child)) {
-               rc = osd_ios_scan_one(info, dev, child->d_inode, NULL, 0);
-               dput(child);
-       } else {
-               rc = PTR_ERR(child);
-       }
+               GOTO(out, rc);
 
-       if (rc == -ENOENT)
-               rc = 0;
+       child = osd_lookup_one_len_unlocked(dev, ADMIN_GRP, dentry,
+                                           strlen(ADMIN_GRP));
+       if (IS_ERR(child))
+               GOTO(out, rc = PTR_ERR(child));
 
-       RETURN(rc);
+       inode_lock(dentry->d_inode);
+       rc = osd_ios_scan_one(info, dev, dentry->d_inode,
+                             child->d_inode, NULL, ADMIN_GRP,
+                             strlen(ADMIN_GRP), 0);
+       inode_unlock(dentry->d_inode);
+       dput(child);
+out:
+       RETURN(rc == -ENOENT ? 0 : rc);
 }
 
-static int osd_initial_OI_scrub(struct osd_thread_info *info,
-                               struct osd_device *dev)
+static void osd_initial_OI_scrub(struct osd_thread_info *info,
+                                struct osd_device *dev)
 {
        struct osd_ios_item     *item    = NULL;
        scandir_t                scandir = osd_ios_general_scan;
        filldir_t                filldir = osd_ios_root_fill;
        struct dentry           *dentry  = osd_sb(dev)->s_root;
        const struct osd_lf_map *map     = osd_lf_maps;
-       int                      rc;
        ENTRY;
 
        /* Lookup IGIF in OI by force for initial OI scrub. */
        dev->od_igif_inoi = 1;
 
        while (1) {
-               rc = scandir(info, dev, dentry, filldir);
+               /* Don't take inode_lock here since scandir() callbacks
+                * can call VFS functions which may manully take the
+                * inode lock itself like iterate_dir(). Since this
+                * is the case it is best to leave the scandir()
+                * callbacks to managing the inode lock.
+                */
+               scandir(info, dev, dentry, filldir);
                if (item != NULL) {
                        dput(item->oii_dentry);
                        OBD_FREE_PTR(item);
                }
 
-               if (rc != 0)
-                       break;
-
                if (list_empty(&dev->od_ios_list))
                        break;
 
@@ -2295,17 +2444,6 @@ static int osd_initial_OI_scrub(struct osd_thread_info *info,
                dentry = item->oii_dentry;
        }
 
-       while (!list_empty(&dev->od_ios_list)) {
-               item = list_entry(dev->od_ios_list.next,
-                                 struct osd_ios_item, oii_list);
-               list_del_init(&item->oii_list);
-               dput(item->oii_dentry);
-               OBD_FREE_PTR(item);
-       }
-
-       if (rc != 0)
-               RETURN(rc);
-
        /* There maybe the case that the object has been removed, but its OI
         * mapping is still in the OI file, such as the "CATALOGS" after MDT
         * file-level backup/restore. So here cleanup the stale OI mappings. */
@@ -2317,19 +2455,45 @@ static int osd_initial_OI_scrub(struct osd_thread_info *info,
                        continue;
                }
 
-               child = osd_ios_lookup_one_len(map->olm_name,
-                                              osd_sb(dev)->s_root,
-                                              map->olm_namelen);
-               if (!IS_ERR(child))
-                       dput(child);
-               else if (PTR_ERR(child) == -ENOENT)
+               child = osd_lookup_one_len_unlocked(dev, map->olm_name,
+                                                   osd_sb(dev)->s_root,
+                                                   map->olm_namelen);
+               if (PTR_ERR(child) == -ENOENT ||
+                   (!IS_ERR(child) && !child->d_inode))
                        osd_scrub_refresh_mapping(info, dev, &map->olm_fid,
                                                  NULL, DTO_INDEX_DELETE,
                                                  true, 0, NULL);
+               if (!IS_ERR(child))
+                       dput(child);
                map++;
        }
 
-       RETURN(0);
+       if (!list_empty(&dev->od_index_restore_list)) {
+               char *buf;
+
+               OBD_ALLOC_LARGE(buf, INDEX_BACKUP_BUFSIZE);
+               if (!buf)
+                       CERROR("%s: not enough RAM for rebuild index\n",
+                              osd_name(dev));
+
+               while (!list_empty(&dev->od_index_restore_list)) {
+                       struct lustre_index_restore_unit *liru;
+
+                       liru = list_entry(dev->od_index_restore_list.next,
+                                         struct lustre_index_restore_unit,
+                                         liru_link);
+                       list_del(&liru->liru_link);
+                       if (buf)
+                               osd_index_restore(info->oti_env, dev, liru,
+                                                 buf, INDEX_BACKUP_BUFSIZE);
+                       OBD_FREE(liru, liru->liru_len);
+               }
+
+               if (buf)
+                       OBD_FREE_LARGE(buf, INDEX_BACKUP_BUFSIZE);
+       }
+
+       EXIT;
 }
 
 char *osd_lf_fid2name(const struct lu_fid *fid)
@@ -2378,13 +2542,15 @@ int osd_scrub_start(const struct lu_env *env, struct osd_device *dev,
        RETURN(rc);
 }
 
-static void osd_scrub_stop(struct osd_device *dev)
+void osd_scrub_stop(struct osd_device *dev)
 {
        struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
 
        /* od_otable_mutex: prevent curcurrent start/stop */
        mutex_lock(&dev->od_otable_mutex);
+       spin_lock(&scrub->os_lock);
        scrub->os_paused = 1;
+       spin_unlock(&scrub->os_lock);
        scrub_stop(scrub);
        mutex_unlock(&dev->od_otable_mutex);
 }
@@ -2400,12 +2566,11 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
        struct lvfs_run_ctxt *ctxt = &dev->od_scrub.os_ctxt;
        struct scrub_file *sf = &scrub->os_file;
        struct super_block *sb = osd_sb(dev);
-       struct ldiskfs_super_block *es = LDISKFS_SB(sb)->s_es;
        struct lvfs_run_ctxt saved;
        struct file *filp;
        struct inode *inode;
        struct lu_fid *fid = &info->oti_fid;
-       struct lu_object_conf conf;
+       struct osd_inode_id *id = &info->oti_id;
        struct dt_object *obj;
        bool dirty = false;
        bool restored = false;
@@ -2416,9 +2581,8 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
        OBD_SET_CTXT_MAGIC(ctxt);
        ctxt->pwdmnt = dev->od_mnt;
        ctxt->pwd = dev->od_mnt->mnt_root;
-       ctxt->fs = get_ds();
+       ctxt->fs = KERNEL_DS;
 
-       init_waitqueue_head(&scrub->os_thread.t_ctl_waitq);
        init_rwsem(&scrub->os_rwsem);
        spin_lock_init(&scrub->os_lock);
        INIT_LIST_HEAD(&scrub->os_inconsistent_items);
@@ -2433,6 +2597,7 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
        }
 
        inode = file_inode(filp);
+       ldiskfs_set_inode_flag(inode, LDISKFS_INODE_JOURNAL_DATA);
        if (!dev->od_dt_dev.dd_rdonly) {
                /* 'What the @fid is' is not imporatant, because the object
                 * has no OI mapping, and only is visible inside the OSD.*/
@@ -2445,22 +2610,24 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
                }
        }
 
-       igrab(inode);
+       osd_id_gen(id, inode->i_ino, inode->i_generation);
+       osd_add_oi_cache(info, dev, id, fid);
        filp_close(filp, NULL);
        pop_ctxt(&saved, ctxt);
 
-       conf.loc_flags = LOC_F_NEW;
-       obj = lu2dt(lu_object_find_slice(env, osd2lu_dev(dev), fid, &conf));
-       if (IS_ERR_OR_NULL(obj)) {
-               iput(inode);
-               RETURN(obj == NULL ? -ENOENT : PTR_ERR(obj));
-       }
+       obj = lu2dt(lu_object_find_slice(env, osd2lu_dev(dev), fid, NULL));
+       if (IS_ERR_OR_NULL(obj))
+               RETURN(obj ? PTR_ERR(obj) : -ENOENT);
 
-       osd_dt_obj(obj)->oo_inode = inode;
+#ifndef HAVE_S_UUID_AS_UUID_T
+       memcpy(dev->od_uuid.b, sb->s_uuid, sizeof(dev->od_uuid));
+#else
+       uuid_copy(&dev->od_uuid, &sb->s_uuid);
+#endif
        scrub->os_obj = obj;
        rc = scrub_file_load(env, scrub);
        if (rc == -ENOENT || rc == -EFAULT) {
-               scrub_file_init(scrub, es->s_uuid);
+               scrub_file_init(scrub, dev->od_uuid);
                /* If the "/O" dir does not exist when mount (indicated by
                 * osd_device::od_maybe_new), neither for the "/OI_scrub",
                 * then it is quite probably that the device is a new one,
@@ -2470,7 +2637,7 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
                 * an old device, it can be found and cleared later.
                 *
                 * For the system with "SIF_NO_HANDLE_OLD_FID", we do not
-                * need to check "filter_fid_old" and to convert it to
+                * need to check "filter_fid_18_23" and to convert it to
                 * "filter_fid" for each object, and all the IGIF should
                 * have their FID mapping in OI files already. */
                if (dev->od_maybe_new && rc == -ENOENT)
@@ -2479,30 +2646,13 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
        } else if (rc < 0) {
                GOTO(cleanup_obj, rc);
        } else {
-               if (memcmp(sf->sf_uuid, es->s_uuid, 16) != 0) {
-                       struct obd_uuid *old_uuid;
-                       struct obd_uuid *new_uuid;
-
-                       OBD_ALLOC_PTR(old_uuid);
-                       OBD_ALLOC_PTR(new_uuid);
-                       if (old_uuid == NULL || new_uuid == NULL) {
-                               CERROR("%s: UUID has been changed, but"
-                                      "failed to allocate RAM for report\n",
-                                      osd_dev2name(dev));
-                       } else {
-                               class_uuid_unparse(sf->sf_uuid, old_uuid);
-                               class_uuid_unparse(es->s_uuid, new_uuid);
-                               CDEBUG(D_LFSCK, "%s: UUID has been changed "
-                                      "from %s to %s\n", osd_dev2name(dev),
-                                      old_uuid->uuid, new_uuid->uuid);
-                       }
-                       scrub_file_reset(scrub, es->s_uuid, SF_INCONSISTENT);
+               if (!uuid_equal(&sf->sf_uuid, &dev->od_uuid)) {
+                       CDEBUG(D_LFSCK,
+                              "%s: UUID has been changed from %pU to %pU\n",
+                              osd_dev2name(dev), &sf->sf_uuid, &dev->od_uuid);
+                       scrub_file_reset(scrub, dev->od_uuid, SF_INCONSISTENT);
                        dirty = true;
                        restored = true;
-                       if (old_uuid != NULL)
-                               OBD_FREE_PTR(old_uuid);
-                       if (new_uuid != NULL)
-                               OBD_FREE_PTR(new_uuid);
                } else if (sf->sf_status == SS_SCANNING) {
                        sf->sf_status = SS_CRASHED;
                        dirty = true;
@@ -2533,11 +2683,8 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
        if (rc < 0)
                GOTO(cleanup_obj, rc);
 
-       if (!dev->od_dt_dev.dd_rdonly) {
-               rc = osd_initial_OI_scrub(info, dev);
-               if (rc)
-                       GOTO(cleanup_oi, rc);
-       }
+       if (!dev->od_dt_dev.dd_rdonly)
+               osd_initial_OI_scrub(info, dev);
 
        if (sf->sf_flags & SF_UPGRADE ||
            !(sf->sf_internal_flags & SIF_NO_HANDLE_OLD_FID ||
@@ -2602,8 +2749,6 @@ void osd_scrub_cleanup(const struct lu_env *env, struct osd_device *dev)
                dt_object_put_nocache(env, scrub->os_obj);
                scrub->os_obj = NULL;
        }
-       if (dev->od_oi_table != NULL)
-               osd_oi_fini(osd_oti_get(env), dev);
 }
 
 /* object table based iteration APIs */
@@ -2702,8 +2847,7 @@ osd_otable_it_wakeup(struct lustre_scrub *scrub, struct osd_otable_it *it)
 {
        spin_lock(&scrub->os_lock);
        if (it->ooi_cache.ooc_pos_preload < scrub->os_pos_current ||
-           scrub->os_waiting ||
-           !thread_is_running(&scrub->os_thread))
+           scrub->os_waiting || !scrub->os_running)
                it->ooi_waiting = 0;
        else
                it->ooi_waiting = 1;
@@ -2714,19 +2858,17 @@ osd_otable_it_wakeup(struct lustre_scrub *scrub, struct osd_otable_it *it)
 
 static int osd_otable_it_next(const struct lu_env *env, struct dt_it *di)
 {
-       struct osd_otable_it    *it     = (struct osd_otable_it *)di;
-       struct osd_device       *dev    = it->ooi_dev;
+       struct osd_otable_it *it = (struct osd_otable_it *)di;
+       struct osd_device *dev = it->ooi_dev;
        struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
-       struct osd_otable_cache *ooc    = &it->ooi_cache;
-       struct ptlrpc_thread    *thread = &scrub->os_thread;
-       struct l_wait_info       lwi    = { 0 };
-       int                      rc;
+       struct osd_otable_cache *ooc = &it->ooi_cache;
+       int rc;
        ENTRY;
 
        LASSERT(it->ooi_user_ready);
 
 again:
-       if (!thread_is_running(thread) && !it->ooi_used_outside)
+       if (!scrub->os_running && !it->ooi_used_outside)
                RETURN(1);
 
        if (ooc->ooc_cached_items > 0) {
@@ -2737,25 +2879,21 @@ again:
        }
 
        if (it->ooi_all_cached) {
-               l_wait_event(thread->t_ctl_waitq,
-                            !thread_is_running(thread),
-                            &lwi);
+               wait_var_event(scrub, !scrub->os_running);
                RETURN(1);
        }
 
        if (scrub->os_waiting && osd_scrub_has_window(scrub, ooc)) {
                spin_lock(&scrub->os_lock);
                scrub->os_waiting = 0;
-               wake_up_all(&scrub->os_thread.t_ctl_waitq);
+               wake_up_var(scrub);
                spin_unlock(&scrub->os_lock);
        }
 
        if (it->ooi_cache.ooc_pos_preload >= scrub->os_pos_current)
-               l_wait_event(thread->t_ctl_waitq,
-                            osd_otable_it_wakeup(scrub, it),
-                            &lwi);
+               wait_var_event(scrub, osd_otable_it_wakeup(scrub, it));
 
-       if (!thread_is_running(thread) && !it->ooi_used_outside)
+       if (!scrub->os_running && !it->ooi_used_outside)
                RETURN(1);
 
        rc = osd_otable_it_preload(env, it);
@@ -2839,7 +2977,7 @@ static int osd_otable_it_load(const struct lu_env *env,
 
        it->ooi_user_ready = 1;
        if (!scrub->os_full_speed)
-               wake_up_all(&scrub->os_thread.t_ctl_waitq);
+               wake_up_var(scrub);
 
        memset(param, 0, sizeof(*param));
        param->sb = osd_sb(dev);
@@ -2888,7 +3026,6 @@ int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic,
        struct osd_inconsistent_item *oii;
        struct osd_scrub *oscrub = &dev->od_scrub;
        struct lustre_scrub *lscrub = &oscrub->os_scrub;
-       struct ptlrpc_thread *thread = &lscrub->os_thread;
        int wakeup = 0;
        ENTRY;
 
@@ -2900,6 +3037,7 @@ int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic,
        oii->oii_cache = *oic;
        oii->oii_insert = insert;
 
+       spin_lock(&lscrub->os_lock);
        if (lscrub->os_partial_scan) {
                __u64 now = ktime_get_real_seconds();
 
@@ -2920,8 +3058,7 @@ int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic,
                        lscrub->os_full_scrub = 1;
        }
 
-       spin_lock(&lscrub->os_lock);
-       if (unlikely(!thread_is_running(thread))) {
+       if (!lscrub->os_running) {
                spin_unlock(&lscrub->os_lock);
                OBD_FREE_PTR(oii);
                RETURN(-EAGAIN);
@@ -2932,8 +3069,8 @@ int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic,
        list_add_tail(&oii->oii_list, &lscrub->os_inconsistent_items);
        spin_unlock(&lscrub->os_lock);
 
-       if (wakeup != 0)
-               wake_up_all(&thread->t_ctl_waitq);
+       if (wakeup)
+               wake_up_var(lscrub);
 
        RETURN(0);
 }