Whamcloud - gitweb
LU-812 ldiskfs: super_operations->dirty_inode now takes a flag
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_handler.c
index b322eeb..e1bc36f 100644 (file)
@@ -53,8 +53,6 @@
 #include <linux/fs.h>
 /* XATTR_{REPLACE,CREATE} */
 #include <linux/xattr.h>
-/* simple_mkdir() */
-#include <lvfs.h>
 
 /*
  * struct OBD_{ALLOC,FREE}*()
@@ -370,13 +368,13 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj,
         * unexpected reason, we should be able to detect it later by calling
         * do_create->osd_oi_insert()
         */
-       if (conf != NULL && (conf->loc_flags & LOC_F_NEW) != 0)
+       if (conf != NULL && conf->loc_flags & LOC_F_NEW)
                GOTO(out, result = 0);
 
        /* Search order: 3. OI files. */
        result = osd_oi_lookup(info, dev, fid, id, true);
        if (result == -ENOENT) {
-               if (!fid_is_norm(fid) ||
+               if (!fid_is_norm(fid) || fid_is_on_ost(info, dev, fid) ||
                    !ldiskfs_test_bit(osd_oi_fid2idx(dev,fid),
                                      sf->sf_oi_bitmap))
                        GOTO(out, result = 0);
@@ -623,12 +621,8 @@ static int osd_param_is_not_sane(const struct osd_device *dev,
 /*
  * Concurrency: shouldn't matter.
  */
-#ifdef HAVE_LDISKFS_JOURNAL_CALLBACK_ADD
 static void osd_trans_commit_cb(struct super_block *sb,
-                                struct journal_callback *jcb, int error)
-#else
-static void osd_trans_commit_cb(struct journal_callback *jcb, int error)
-#endif
+                                struct ldiskfs_journal_cb_entry *jcb, int error)
 {
         struct osd_thandle *oh = container_of0(jcb, struct osd_thandle, ot_jcb);
         struct thandle     *th  = &oh->ot_super;
@@ -825,7 +819,7 @@ static int osd_trans_stop(const struct lu_env *env, struct thandle *th)
                  * notice we don't do this in osd_trans_start()
                  * as underlying transaction can change during truncate
                  */
-                osd_journal_callback_set(hdl, osd_trans_commit_cb,
+                ldiskfs_journal_callback_add(hdl, osd_trans_commit_cb,
                                          &oh->ot_jcb);
 
                 LASSERT(oti->oti_txns == 1);
@@ -1079,14 +1073,31 @@ static int osd_commit_async(const struct lu_env *env,
 
 static int osd_ro(const struct lu_env *env, struct dt_device *d)
 {
-        struct super_block *sb = osd_sb(osd_dt_dev(d));
-        int rc;
-        ENTRY;
+       struct super_block *sb = osd_sb(osd_dt_dev(d));
+       struct block_device *dev = sb->s_bdev;
+#ifdef HAVE_DEV_SET_RDONLY
+       struct block_device *jdev = LDISKFS_SB(sb)->journal_bdev;
+       int rc = 0;
+#else
+       int rc = -EOPNOTSUPP;
+#endif
+       ENTRY;
 
+#ifdef HAVE_DEV_SET_RDONLY
        CERROR("*** setting %s read-only ***\n", osd_dt_dev(d)->od_svname);
 
-        rc = __lvfs_set_rdonly(sb->s_bdev, LDISKFS_SB(sb)->journal_bdev);
-        RETURN(rc);
+       if (jdev && (jdev != dev)) {
+               CDEBUG(D_IOCTL | D_HA, "set journal dev %lx rdonly\n",
+                      (long)jdev);
+               dev_set_rdonly(jdev);
+       }
+       CDEBUG(D_IOCTL | D_HA, "set dev %lx rdonly\n", (long)dev);
+       dev_set_rdonly(dev);
+#else
+       CERROR("%s: %lx CANNOT BE SET READONLY: rc = %d\n",
+              osd_dt_dev(d)->od_svname, (long)dev, rc);
+#endif
+       RETURN(rc);
 }
 
 /*
@@ -1363,7 +1374,8 @@ static void osd_inode_getattr(const struct lu_env *env,
 {
         attr->la_valid      |= LA_ATIME | LA_MTIME | LA_CTIME | LA_MODE |
                                LA_SIZE | LA_BLOCKS | LA_UID | LA_GID |
-                               LA_FLAGS | LA_NLINK | LA_RDEV | LA_BLKSIZE;
+                               LA_FLAGS | LA_NLINK | LA_RDEV | LA_BLKSIZE |
+                              LA_TYPE;
 
         attr->la_atime      = LTIME_S(inode->i_atime);
         attr->la_mtime      = LTIME_S(inode->i_mtime);
@@ -1387,7 +1399,7 @@ static int osd_attr_get(const struct lu_env *env,
 {
         struct osd_object *obj = osd_dt_obj(dt);
 
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LINVRNT(osd_invariant(obj));
 
         if (osd_object_auth(env, dt, capa, CAPA_OPC_META_READ))
@@ -1620,7 +1632,7 @@ static int osd_attr_set(const struct lu_env *env,
         int rc;
 
         LASSERT(handle != NULL);
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(osd_invariant(obj));
 
         if (osd_object_auth(env, dt, capa, CAPA_OPC_META_WRITE))
@@ -1628,6 +1640,31 @@ static int osd_attr_set(const struct lu_env *env,
 
        osd_trans_exec_op(env, handle, OSD_OT_ATTR_SET);
 
+       if (OBD_FAIL_CHECK(OBD_FAIL_OSD_FID_MAPPING)) {
+               struct osd_thread_info  *oti  = osd_oti_get(env);
+               const struct lu_fid     *fid0 = lu_object_fid(&dt->do_lu);
+               struct lu_fid           *fid1 = &oti->oti_fid;
+               struct osd_inode_id     *id   = &oti->oti_id;
+               struct iam_path_descr   *ipd;
+               struct iam_container    *bag;
+               struct osd_thandle      *oh;
+               int                      rc;
+
+               fid_cpu_to_be(fid1, fid0);
+               memset(id, 1, sizeof(*id));
+               bag = &osd_fid2oi(osd_dev(dt->do_lu.lo_dev),
+                                 fid0)->oi_dir.od_container;
+               ipd = osd_idx_ipd_get(env, bag);
+               if (unlikely(ipd == NULL))
+                       RETURN(-ENOMEM);
+
+               oh = container_of0(handle, struct osd_thandle, ot_super);
+               rc = iam_update(oh->ot_handle, bag, (const struct iam_key *)fid1,
+                               (const struct iam_rec *)id, ipd);
+               osd_ipd_put(env, bag, ipd);
+               return(rc > 0 ? 0 : rc);
+       }
+
         inode = obj->oo_inode;
        ll_vfs_dq_init(inode);
 
@@ -1640,7 +1677,7 @@ static int osd_attr_set(const struct lu_env *env,
        spin_unlock(&obj->oo_guard);
 
         if (!rc)
-                inode->i_sb->s_op->dirty_inode(inode);
+               ll_dirty_inode(inode, I_DIRTY_DATASYNC);
         return rc;
 }
 
@@ -1892,7 +1929,7 @@ static void osd_attr_init(struct osd_thread_info *info, struct osd_object *obj,
                  * enabled on ldiskfs (lquota takes care of it).
                  */
                 LASSERTF(result == 0, "%d", result);
-                inode->i_sb->s_op->dirty_inode(inode);
+               ll_dirty_inode(inode, I_DIRTY_DATASYNC);
         }
 
         attr->la_valid = valid;
@@ -1910,6 +1947,11 @@ static int __osd_object_create(struct osd_thread_info *info,
                                struct thandle *th)
 {
        int     result;
+       __u32   umask;
+
+       /* we drop umask so that permissions we pass are not affected */
+       umask = current->fs->umask;
+       current->fs->umask = 0;
 
        result = osd_create_type_f(dof->dof_type)(info, obj, attr, hint, dof,
                                                  th);
@@ -1921,7 +1963,10 @@ static int __osd_object_create(struct osd_thread_info *info,
                        unlock_new_inode(obj->oo_inode);
         }
 
-        return result;
+       /* restore previous umask value */
+       current->fs->umask = umask;
+
+       return result;
 }
 
 /**
@@ -1948,19 +1993,13 @@ int osd_fld_lookup(const struct lu_env *env, struct osd_device *osd,
        struct seq_server_site  *ss = osd_seq_site(osd);
        int                     rc;
 
-       if (fid_is_igif(fid)) {
-               range->lsr_flags = LU_SEQ_RANGE_MDT;
-               range->lsr_index = 0;
-               return 0;
-       }
-
        if (fid_is_idif(fid)) {
                range->lsr_flags = LU_SEQ_RANGE_OST;
                range->lsr_index = fid_idif_ost_idx(fid);
                return 0;
        }
 
-       if (!fid_is_norm(fid)) {
+       if (!fid_seq_in_fldb(fid_seq(fid))) {
                range->lsr_flags = LU_SEQ_RANGE_MDT;
                if (ss != NULL)
                        /* FIXME: If ss is NULL, it suppose not get lsr_index
@@ -1979,7 +2018,9 @@ int osd_fld_lookup(const struct lu_env *env, struct osd_device *osd,
        return rc;
 }
 
-
+/*
+ * Concurrency: no external locking is necessary.
+ */
 static int osd_declare_object_create(const struct lu_env *env,
                                     struct dt_object *dt,
                                     struct lu_attr *attr,
@@ -1999,16 +2040,13 @@ static int osd_declare_object_create(const struct lu_env *env,
 
        osd_trans_declare_op(env, oh, OSD_OT_CREATE,
                             osd_dto_credits_noquota[DTO_OBJECT_CREATE]);
-       /* XXX: So far, only normal fid needs be inserted into the oi,
-        *      things could be changed later. Revise following code then. */
-       if (fid_is_norm(lu_object_fid(&dt->do_lu)) &&
-           !fid_is_on_ost(osd_oti_get(env), osd_dt_dev(handle->th_dev),
-                          lu_object_fid(&dt->do_lu))) {
+       if (!fid_is_on_ost(osd_oti_get(env), osd_dt_dev(handle->th_dev),
+                          lu_object_fid(&dt->do_lu)))
                /* Reuse idle OI block may cause additional one OI block
                 * to be changed. */
                osd_trans_declare_op(env, oh, OSD_OT_INSERT,
                                osd_dto_credits_noquota[DTO_INDEX_INSERT] + 1);
-       }
+
        /* If this is directory, then we expect . and .. to be inserted as
         * well. The one directory block always needs to be created for the
         * directory, so we could use DTO_WRITE_BASE here (GDT, block bitmap,
@@ -2055,7 +2093,7 @@ static int osd_object_create(const struct lu_env *env, struct dt_object *dt,
         ENTRY;
 
         LINVRNT(osd_invariant(obj));
-        LASSERT(!dt_object_exists(dt));
+       LASSERT(!dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(osd_write_locked(env, obj));
         LASSERT(th != NULL);
 
@@ -2071,7 +2109,9 @@ static int osd_object_create(const struct lu_env *env, struct dt_object *dt,
         if (result == 0)
                 result = __osd_oi_insert(env, obj, fid, th);
 
-        LASSERT(ergo(result == 0, dt_object_exists(dt)));
+       LASSERT(ergo(result == 0,
+                    dt_object_exists(dt) && !dt_object_remote(dt)));
+
         LASSERT(osd_invariant(obj));
         RETURN(result);
 }
@@ -2097,13 +2137,10 @@ static int osd_declare_object_destroy(const struct lu_env *env,
 
        osd_trans_declare_op(env, oh, OSD_OT_DELETE,
                             osd_dto_credits_noquota[DTO_OBJECT_DELETE]);
-       /* XXX: So far, only normal fid needs to be inserted into the OI,
-        *      so only normal fid needs to be removed from the OI also.
-        * Recycle idle OI leaf may cause additional three OI blocks
+       /* Recycle idle OI leaf may cause additional three OI blocks
         * to be changed. */
        osd_trans_declare_op(env, oh, OSD_OT_DESTROY,
-                            fid_is_norm(lu_object_fid(&dt->do_lu)) ?
-                            osd_dto_credits_noquota[DTO_INDEX_DELETE] + 3 : 0);
+                            osd_dto_credits_noquota[DTO_INDEX_DELETE] + 3);
 
        /* one less inode */
        rc = osd_declare_inode_qid(env, inode->i_uid, inode->i_gid, -1, oh,
@@ -2144,7 +2181,7 @@ static int osd_object_destroy(const struct lu_env *env,
                /* it will check/delete the agent inode for every dir
                 * destory, how to optimize it? unlink performance
                 * impaction XXX */
-               result = osd_delete_agent_inode(env, osd, obj, oh);
+               result = osd_delete_from_agent(env, osd, obj, oh);
                if (result != 0 && result != -ENOENT) {
                        CERROR("%s: delete agent inode "DFID": rc = %d\n",
                               osd_name(osd), PFID(fid), result);
@@ -2152,7 +2189,7 @@ static int osd_object_destroy(const struct lu_env *env,
                spin_lock(&obj->oo_guard);
                clear_nlink(inode);
                spin_unlock(&obj->oo_guard);
-               inode->i_sb->s_op->dirty_inode(inode);
+               ll_dirty_inode(inode, I_DIRTY_DATASYNC);
        }
 
        osd_trans_exec_op(env, th, OSD_OT_DESTROY);
@@ -2196,6 +2233,12 @@ int osd_ea_fid_set(struct osd_thread_info *info, struct inode *inode,
        struct lustre_mdt_attrs *lma = &info->oti_mdt_attrs;
        int                      rc;
 
+       if (OBD_FAIL_CHECK(OBD_FAIL_FID_INLMA))
+               return 0;
+
+       if (OBD_FAIL_CHECK(OBD_FAIL_FID_IGIF) && fid_is_client_visible(fid))
+               return 0;
+
        lustre_lma_init(lma, fid);
        lustre_lma_swab(lma);
 
@@ -2218,10 +2261,7 @@ int osd_ea_fid_set(struct osd_thread_info *info, struct inode *inode,
 void osd_get_ldiskfs_dirent_param(struct ldiskfs_dentry_param *param,
                                  const struct dt_rec *fid)
 {
-       /* XXX: replace the check with "!fid_is_client_mdt_visible()"
-        *      when FID in OI file introduced for local object. */
-       if (!fid_is_norm((const struct lu_fid *)fid) &&
-           !fid_is_igif((const struct lu_fid *)fid)) {
+       if (!fid_is_client_mdt_visible((const struct lu_fid *)fid)) {
                param->edp_magic = 0;
                return;
        }
@@ -2232,8 +2272,7 @@ void osd_get_ldiskfs_dirent_param(struct ldiskfs_dentry_param *param,
 }
 
 /**
- * Try to read the fid from inode ea into dt_rec, if return value
- * i.e. rc is +ve, then we got fid, otherwise we will have to form igif
+ * Try to read the fid from inode ea into dt_rec.
  *
  * \param fid object fid.
  *
@@ -2294,15 +2333,9 @@ static struct inode *osd_create_remote_inode(const struct lu_env *env,
        oh = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle->h_transaction != NULL);
 
-#ifdef HAVE_QUOTA_SUPPORT
-       osd_push_ctxt(info->oti_env, save);
-#endif
        /* FIXME: Insert index api needs to know the mode of
         * the remote object. Just use S_IFDIR for now */
        local = ldiskfs_create_inode(oh->ot_handle, pobj->oo_inode, S_IFDIR);
-#ifdef HAVE_QUOTA_SUPPORT
-       osd_pop_ctxt(info->oti_env, save);
-#endif
        if (IS_ERR(local)) {
                CERROR("%s: create local error %d\n", osd_name(osd),
                       (int)PTR_ERR(local));
@@ -2373,7 +2406,7 @@ static int osd_object_ea_create(const struct lu_env *env, struct dt_object *dt,
         ENTRY;
 
         LASSERT(osd_invariant(obj));
-        LASSERT(!dt_object_exists(dt));
+       LASSERT(!dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(osd_write_locked(env, obj));
         LASSERT(th != NULL);
 
@@ -2386,16 +2419,16 @@ static int osd_object_ea_create(const struct lu_env *env, struct dt_object *dt,
        osd_trans_declare_rb(env, th, OSD_OT_REF_ADD);
 
         result = __osd_object_create(info, obj, attr, hint, dof, th);
-        /* objects under osd root shld have igif fid, so dont add fid EA */
-       /* For ost object, the fid will be stored during first write */
-       if (result == 0 && fid_seq(fid) >= FID_SEQ_NORMAL &&
-           !fid_is_on_ost(info, osd_dt_dev(th->th_dev), fid))
+       if ((result == 0) &&
+           (fid_is_last_id(fid) ||
+            !fid_is_on_ost(info, osd_dt_dev(th->th_dev), fid)))
                result = osd_ea_fid_set(info, obj->oo_inode, fid);
 
         if (result == 0)
                 result = __osd_oi_insert(env, obj, fid, th);
 
-        LASSERT(ergo(result == 0, dt_object_exists(dt)));
+       LASSERT(ergo(result == 0,
+                    dt_object_exists(dt) && !dt_object_remote(dt)));
         LINVRNT(osd_invariant(obj));
         RETURN(result);
 }
@@ -2428,7 +2461,7 @@ static int osd_object_ref_add(const struct lu_env *env,
         struct inode      *inode = obj->oo_inode;
 
         LINVRNT(osd_invariant(obj));
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(osd_write_locked(env, obj));
         LASSERT(th != NULL);
 
@@ -2457,7 +2490,7 @@ static int osd_object_ref_add(const struct lu_env *env,
        }
        LASSERT(inode->i_nlink <= LDISKFS_LINK_MAX);
        spin_unlock(&obj->oo_guard);
-       inode->i_sb->s_op->dirty_inode(inode);
+       ll_dirty_inode(inode, I_DIRTY_DATASYNC);
        LINVRNT(osd_invariant(obj));
 
        return 0;
@@ -2469,7 +2502,7 @@ static int osd_declare_object_ref_del(const struct lu_env *env,
 {
         struct osd_thandle *oh;
 
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(handle != NULL);
 
         oh = container_of0(handle, struct osd_thandle, ot_super);
@@ -2491,7 +2524,7 @@ static int osd_object_ref_del(const struct lu_env *env, struct dt_object *dt,
         struct inode      *inode = obj->oo_inode;
 
         LINVRNT(osd_invariant(obj));
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(osd_write_locked(env, obj));
         LASSERT(th != NULL);
 
@@ -2506,7 +2539,7 @@ static int osd_object_ref_del(const struct lu_env *env, struct dt_object *dt,
        if (S_ISDIR(inode->i_mode) && inode->i_nlink == 0)
                set_nlink(inode, 1);
        spin_unlock(&obj->oo_guard);
-       inode->i_sb->s_op->dirty_inode(inode);
+       ll_dirty_inode(inode, I_DIRTY_DATASYNC);
        LINVRNT(osd_invariant(obj));
 
        return 0;
@@ -2547,7 +2580,7 @@ static int osd_xattr_get(const struct lu_env *env, struct dt_object *dt,
                 return sizeof(dt_obj_version_t);
         }
 
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(inode->i_op != NULL && inode->i_op->getxattr != NULL);
 
         if (osd_object_auth(env, dt, capa, CAPA_OPC_META_READ))
@@ -2592,7 +2625,7 @@ static void osd_object_version_set(const struct lu_env *env,
         LDISKFS_I(inode)->i_fs_version = *new_version;
         /** Version is set after all inode operations are finished,
          *  so we should mark it dirty here */
-        inode->i_sb->s_op->dirty_inode(inode);
+       ll_dirty_inode(inode, I_DIRTY_DATASYNC);
 }
 
 /*
@@ -2606,6 +2639,7 @@ static int osd_xattr_set(const struct lu_env *env, struct dt_object *dt,
        struct inode           *inode    = obj->oo_inode;
        struct osd_thread_info *info     = osd_oti_get(env);
        int                     fs_flags = 0;
+       ENTRY;
 
         LASSERT(handle != NULL);
 
@@ -2643,7 +2677,7 @@ static int osd_xattr_list(const struct lu_env *env, struct dt_object *dt,
         struct osd_thread_info *info   = osd_oti_get(env);
         struct dentry          *dentry = &info->oti_obj_dentry;
 
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(inode->i_op != NULL && inode->i_op->listxattr != NULL);
         LASSERT(osd_read_locked(env, obj) || osd_write_locked(env, obj));
 
@@ -2660,7 +2694,7 @@ static int osd_declare_xattr_del(const struct lu_env *env,
 {
         struct osd_thandle *oh;
 
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(handle != NULL);
 
         oh = container_of0(handle, struct osd_thandle, ot_super);
@@ -2685,7 +2719,7 @@ static int osd_xattr_del(const struct lu_env *env, struct dt_object *dt,
         struct dentry          *dentry = &info->oti_obj_dentry;
         int                     rc;
 
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(inode->i_op != NULL && inode->i_op->removexattr != NULL);
         LASSERT(handle != NULL);
 
@@ -2719,7 +2753,7 @@ static struct obd_capa *osd_capa_get(const struct lu_env *env,
         if (!dev->od_fl_capa)
                 RETURN(ERR_PTR(-ENOENT));
 
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LINVRNT(osd_invariant(obj));
 
         /* renewal sanity check */
@@ -2802,9 +2836,13 @@ static int osd_object_sync(const struct lu_env *env, struct dt_object *dt)
        file->f_dentry = dentry;
        file->f_mapping = inode->i_mapping;
        file->f_op = inode->i_fop;
+#ifndef HAVE_FILE_FSYNC_4ARGS
        mutex_lock(&inode->i_mutex);
-       rc = file->f_op->fsync(file, dentry, 0);
+#endif
+       rc = do_fsync(file, 0);
+#ifndef HAVE_FILE_FSYNC_4ARGS
        mutex_unlock(&inode->i_mutex);
+#endif
        RETURN(rc);
 }
 
@@ -2884,14 +2922,13 @@ static int osd_index_try(const struct lu_env *env, struct dt_object *dt,
        struct osd_object       *obj = osd_dt_obj(dt);
 
         LINVRNT(osd_invariant(obj));
-        LASSERT(dt_object_exists(dt));
 
         if (osd_object_is_root(obj)) {
                 dt->do_index_ops = &osd_index_ea_ops;
                 result = 0;
        } else if (feat == &dt_directory_features) {
                 dt->do_index_ops = &osd_index_ea_ops;
-                if (S_ISDIR(obj->oo_inode->i_mode))
+               if (obj->oo_inode != NULL && S_ISDIR(obj->oo_inode->i_mode))
                         result = 0;
                 else
                         result = -ENOTDIR;
@@ -2944,7 +2981,8 @@ static int osd_index_try(const struct lu_env *env, struct dt_object *dt,
         }
         LINVRNT(osd_invariant(obj));
 
-       if (is_quota_glb_feat(feat))
+       if (result == 0 && is_quota_glb_feat(feat) &&
+           fid_seq(lu_object_fid(&dt->do_lu)) == FID_SEQ_QUOTA_GLB)
                result = osd_quota_migration(env, dt, feat);
 
         return result;
@@ -3071,7 +3109,7 @@ static int osd_index_iam_delete(const struct lu_env *env, struct dt_object *dt,
         ENTRY;
 
         LINVRNT(osd_invariant(obj));
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(bag->ic_object == obj->oo_inode);
         LASSERT(handle != NULL);
 
@@ -3110,7 +3148,7 @@ static int osd_index_declare_ea_delete(const struct lu_env *env,
        int                 rc;
        ENTRY;
 
-       LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
        LASSERT(handle != NULL);
 
        oh = container_of0(handle, struct osd_thandle, ot_super);
@@ -3137,7 +3175,7 @@ static inline int osd_get_fid_from_dentry(struct ldiskfs_dir_entry_2 *de,
                 rec = (struct osd_fid_pack *) (de->name + de->name_len + 1);
                 rc = osd_fid_unpack((struct lu_fid *)fid, rec);
         }
-        RETURN(rc);
+       return rc;
 }
 
 static int osd_remote_fid(const struct lu_env *env, struct osd_device *osd,
@@ -3148,7 +3186,8 @@ static int osd_remote_fid(const struct lu_env *env, struct osd_device *osd,
        int                     rc;
        ENTRY;
 
-       if ((!fid_is_norm(fid) && !fid_is_igif(fid)) || ss == NULL)
+       /* Those FID seqs, which are not in FLDB, must be local seq */
+       if (unlikely(!fid_seq_in_fldb(fid_seq(fid)) || ss == NULL))
                RETURN(0);
 
        rc = osd_fld_lookup(env, osd, fid, range);
@@ -3189,7 +3228,7 @@ static int osd_index_ea_delete(const struct lu_env *env, struct dt_object *dt,
         ENTRY;
 
         LINVRNT(osd_invariant(obj));
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(handle != NULL);
 
        osd_trans_exec_op(env, handle, OSD_OT_DELETE);
@@ -3229,6 +3268,12 @@ static int osd_index_ea_delete(const struct lu_env *env, struct dt_object *dt,
        if (rc != 0)
                GOTO(out, rc);
 
+       /* For inode on the remote MDT, .. will point to
+        * /Agent directory. So do not try to lookup/delete
+        * remote inode for .. */
+       if (strcmp((char *)key, dotdot) == 0)
+               GOTO(out, rc = 0);
+
        LASSERT(de != NULL);
        rc = osd_get_fid_from_dentry(de, (struct dt_rec *)fid);
        if (rc == 0 && osd_remote_fid(env, osd, fid)) {
@@ -3274,7 +3319,7 @@ static int osd_index_iam_lookup(const struct lu_env *env, struct dt_object *dt,
         ENTRY;
 
         LASSERT(osd_invariant(obj));
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(bag->ic_object == obj->oo_inode);
 
         if (osd_object_auth(env, dt, capa, CAPA_OPC_INDEX_LOOKUP))
@@ -3326,7 +3371,6 @@ static int osd_index_declare_iam_insert(const struct lu_env *env,
 {
         struct osd_thandle *oh;
 
-        LASSERT(dt_object_exists(dt));
         LASSERT(handle != NULL);
 
         oh = container_of0(handle, struct osd_thandle, ot_super);
@@ -3365,7 +3409,7 @@ static int osd_index_iam_insert(const struct lu_env *env, struct dt_object *dt,
         ENTRY;
 
         LINVRNT(osd_invariant(obj));
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(bag->ic_object == obj->oo_inode);
         LASSERT(th != NULL);
 
@@ -3527,8 +3571,18 @@ static int osd_ea_add_rec(const struct lu_env *env, struct osd_object *pobj,
                        down_write(&pobj->oo_ext_idx_sem);
                 }
 
-                rc = __osd_ea_add_rec(info, pobj, cinode, name, fid,
-                                      hlock, th);
+               if (OBD_FAIL_CHECK(OBD_FAIL_FID_INDIR)) {
+                       struct lu_fid *tfid = &info->oti_fid;
+
+                       *tfid = *(const struct lu_fid *)fid;
+                       tfid->f_ver = ~0;
+                       rc = __osd_ea_add_rec(info, pobj, cinode, name,
+                                             (const struct dt_rec *)tfid,
+                                             hlock, th);
+               } else {
+                       rc = __osd_ea_add_rec(info, pobj, cinode, name, fid,
+                                             hlock, th);
+               }
         }
         if (hlock != NULL)
                 ldiskfs_htree_unlock(hlock);
@@ -3587,6 +3641,31 @@ again:
        EXIT;
 }
 
+static int osd_fail_fid_lookup(struct osd_thread_info *oti,
+                              struct osd_device *dev,
+                              struct osd_idmap_cache *oic,
+                              struct lu_fid *fid, __u32 ino)
+{
+       struct lustre_mdt_attrs *lma   = &oti->oti_mdt_attrs;
+       struct inode            *inode;
+       int                      rc;
+
+       osd_id_gen(&oic->oic_lid, ino, OSD_OII_NOGEN);
+       inode = osd_iget(oti, dev, &oic->oic_lid);
+       if (IS_ERR(inode)) {
+               fid_zero(&oic->oic_fid);
+               return PTR_ERR(inode);
+       }
+
+       rc = osd_get_lma(oti, inode, &oti->oti_obj_dentry, lma);
+       iput(inode);
+       if (rc != 0)
+               fid_zero(&oic->oic_fid);
+       else
+               *fid = oic->oic_fid = lma->lma_self_fid;
+       return rc;
+}
+
 /**
  * Calls ->lookup() to find dentry. From dentry get inode and
  * read inode's ea to get fid. This is required for  interoperability
@@ -3631,6 +3710,12 @@ static int osd_ea_lookup_rec(const struct lu_env *env, struct osd_object *obj,
                struct scrub_file *sf = &scrub->os_file;
 
                ino = le32_to_cpu(de->inode);
+               if (OBD_FAIL_CHECK(OBD_FAIL_FID_LOOKUP)) {
+                       brelse(bh);
+                       rc = osd_fail_fid_lookup(oti, dev, oic, fid, ino);
+                       GOTO(out, rc);
+               }
+
                rc = osd_get_fid_from_dentry(de, rec);
 
                /* done with de, release bh */
@@ -3647,7 +3732,8 @@ static int osd_ea_lookup_rec(const struct lu_env *env, struct osd_object *obj,
                oic->oic_lid = *id;
                oic->oic_fid = *fid;
                if ((scrub->os_pos_current <= ino) &&
-                   (sf->sf_flags & SF_INCONSISTENT ||
+                   ((sf->sf_flags & SF_INCONSISTENT) ||
+                    (sf->sf_flags & SF_UPGRADE && fid_is_igif(fid)) ||
                     ldiskfs_test_bit(osd_oi_fid2idx(dev, fid),
                                      sf->sf_oi_bitmap)))
                        osd_consistency_check(oti, dev, oic);
@@ -3744,7 +3830,7 @@ static int osd_index_declare_ea_insert(const struct lu_env *env,
        int                     rc;
        ENTRY;
 
-       LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
        LASSERT(handle != NULL);
 
        oh = container_of0(handle, struct osd_thandle, ot_super);
@@ -3778,11 +3864,8 @@ static int osd_index_declare_ea_insert(const struct lu_env *env,
        if (rc <= 0)
                RETURN(rc);
 
-#ifdef OSD_DECLARE_OP
-#define OSD_OT_CREATE create
-#define OSD_OT_INSERT insert
-#define osd_trans_declare_op(env, oh, op, cred) OSD_DECLARE_OP(oh, op, cred)
-#endif
+       rc = 0;
+
        osd_trans_declare_op(env, oh, OSD_OT_CREATE,
                             osd_dto_credits_noquota[DTO_OBJECT_CREATE]);
        osd_trans_declare_op(env, oh, OSD_OT_INSERT,
@@ -3821,7 +3904,7 @@ static int osd_index_ea_insert(const struct lu_env *env, struct dt_object *dt,
        ENTRY;
 
         LASSERT(osd_invariant(obj));
-        LASSERT(dt_object_exists(dt));
+       LASSERT(dt_object_exists(dt) && !dt_object_remote(dt));
         LASSERT(th != NULL);
 
        osd_trans_exec_op(env, th, OSD_OT_INSERT);
@@ -3847,7 +3930,7 @@ static int osd_index_ea_insert(const struct lu_env *env, struct dt_object *dt,
                        /* If parent on remote MDT, we need put this object
                         * under AGENT */
                        oh = container_of(th, typeof(*oh), ot_super);
-                       rc = osd_create_agent_inode(env, osd, obj, oh);
+                       rc = osd_add_to_agent(env, osd, obj, oh);
                        if (rc != 0) {
                                CERROR("%s: add agent "DFID" error: rc = %d\n",
                                       osd_name(osd),
@@ -4022,44 +4105,42 @@ static int osd_it_iam_key_size(const struct lu_env *env, const struct dt_it *di)
         return iam_it_key_size(&it->oi_it);
 }
 
-static inline void osd_it_append_attrs(struct lu_dirent *ent, __u32 attr,
-                                       int len, __u16 type)
+static inline void
+osd_it_append_attrs(struct lu_dirent *ent, int len, __u16 type)
 {
-        struct luda_type *lt;
-        const unsigned    align = sizeof(struct luda_type) - 1;
-
-        /* check if file type is required */
-        if (attr & LUDA_TYPE) {
-                        len = (len + align) & ~align;
+       /* check if file type is required */
+       if (ent->lde_attrs & LUDA_TYPE) {
+               struct luda_type *lt;
+               int align = sizeof(*lt) - 1;
 
-                        lt = (void *) ent->lde_name + len;
-                        lt->lt_type = cpu_to_le16(CFS_DTTOIF(type));
-                        ent->lde_attrs |= LUDA_TYPE;
-        }
+               len = (len + align) & ~align;
+               lt = (struct luda_type *)(ent->lde_name + len);
+               lt->lt_type = cpu_to_le16(DTTOIF(type));
+       }
 
-        ent->lde_attrs = cpu_to_le32(ent->lde_attrs);
+       ent->lde_attrs = cpu_to_le32(ent->lde_attrs);
 }
 
 /**
  * build lu direct from backend fs dirent.
  */
 
-static inline void osd_it_pack_dirent(struct lu_dirent *ent,
-                                      struct lu_fid *fid, __u64 offset,
-                                      char *name, __u16 namelen,
-                                      __u16 type, __u32 attr)
+static inline void
+osd_it_pack_dirent(struct lu_dirent *ent, struct lu_fid *fid, __u64 offset,
+                  char *name, __u16 namelen, __u16 type, __u32 attr)
 {
-        fid_cpu_to_le(&ent->lde_fid, fid);
-        ent->lde_attrs = LUDA_FID;
+       ent->lde_attrs = attr | LUDA_FID;
+       fid_cpu_to_le(&ent->lde_fid, fid);
 
-        ent->lde_hash = cpu_to_le64(offset);
-        ent->lde_reclen = cpu_to_le16(lu_dirent_calc_size(namelen, attr));
+       ent->lde_hash = cpu_to_le64(offset);
+       ent->lde_reclen = cpu_to_le16(lu_dirent_calc_size(namelen, attr));
 
-        strncpy(ent->lde_name, name, namelen);
-        ent->lde_namelen = cpu_to_le16(namelen);
+       strncpy(ent->lde_name, name, namelen);
+       ent->lde_name[namelen] = '\0';
+       ent->lde_namelen = cpu_to_le16(namelen);
 
-        /* append lustre attributes */
-        osd_it_append_attrs(ent, attr, namelen, type);
+       /* append lustre attributes */
+       osd_it_append_attrs(ent, namelen, type);
 }
 
 /**
@@ -4427,10 +4508,337 @@ static int osd_it_ea_key_size(const struct lu_env *env, const struct dt_it *di)
         return it->oie_dirent->oied_namelen;
 }
 
+static int
+osd_dirent_update(handle_t *jh, struct super_block *sb,
+                 struct osd_it_ea_dirent *ent, struct lu_fid *fid,
+                 struct buffer_head *bh, struct ldiskfs_dir_entry_2 *de)
+{
+       struct osd_fid_pack *rec;
+       int                  rc;
+       ENTRY;
+
+       LASSERT(de->file_type & LDISKFS_DIRENT_LUFID);
+       LASSERT(de->rec_len >= de->name_len + sizeof(struct osd_fid_pack));
+
+       rc = ldiskfs_journal_get_write_access(jh, bh);
+       if (rc != 0) {
+               CERROR("%.16s: fail to write access for update dirent: "
+                      "name = %.*s, rc = %d\n",
+                      LDISKFS_SB(sb)->s_es->s_volume_name,
+                      ent->oied_namelen, ent->oied_name, rc);
+               RETURN(rc);
+       }
+
+       rec = (struct osd_fid_pack *)(de->name + de->name_len + 1);
+       fid_cpu_to_be((struct lu_fid *)rec->fp_area, fid);
+       rc = ldiskfs_journal_dirty_metadata(jh, bh);
+       if (rc != 0)
+               CERROR("%.16s: fail to dirty metadata for update dirent: "
+                      "name = %.*s, rc = %d\n",
+                      LDISKFS_SB(sb)->s_es->s_volume_name,
+                      ent->oied_namelen, ent->oied_name, rc);
+
+       RETURN(rc);
+}
+
+static inline int
+osd_dirent_has_space(__u16 reclen, __u16 namelen, unsigned blocksize)
+{
+       if (ldiskfs_rec_len_from_disk(reclen, blocksize) >=
+           __LDISKFS_DIR_REC_LEN(namelen + 1 + sizeof(struct osd_fid_pack)))
+               return 1;
+       else
+               return 0;
+}
+
+static int
+osd_dirent_reinsert(const struct lu_env *env, handle_t *jh,
+                   struct inode *dir, struct inode *inode,
+                   struct osd_it_ea_dirent *ent, struct lu_fid *fid,
+                   struct buffer_head *bh, struct ldiskfs_dir_entry_2 *de,
+                   struct htree_lock *hlock)
+{
+       struct dentry               *dentry;
+       struct osd_fid_pack         *rec;
+       struct ldiskfs_dentry_param *ldp;
+       int                          rc;
+       ENTRY;
+
+       if (!LDISKFS_HAS_INCOMPAT_FEATURE(inode->i_sb,
+                                         LDISKFS_FEATURE_INCOMPAT_DIRDATA))
+               RETURN(0);
+
+       /* There is enough space to hold the FID-in-dirent. */
+       if (osd_dirent_has_space(de->rec_len, ent->oied_namelen,
+                                dir->i_sb->s_blocksize)) {
+               rc = ldiskfs_journal_get_write_access(jh, bh);
+               if (rc != 0) {
+                       CERROR("%.16s: fail to write access for reinsert "
+                              "dirent: name = %.*s, rc = %d\n",
+                              LDISKFS_SB(inode->i_sb)->s_es->s_volume_name,
+                              ent->oied_namelen, ent->oied_name, rc);
+                       RETURN(rc);
+               }
+
+               de->name[de->name_len] = 0;
+               rec = (struct osd_fid_pack *)(de->name + de->name_len + 1);
+               rec->fp_len = sizeof(struct lu_fid) + 1;
+               fid_cpu_to_be((struct lu_fid *)rec->fp_area, fid);
+               de->file_type |= LDISKFS_DIRENT_LUFID;
+
+               rc = ldiskfs_journal_dirty_metadata(jh, bh);
+               if (rc != 0)
+                       CERROR("%.16s: fail to dirty metadata for reinsert "
+                              "dirent: name = %.*s, rc = %d\n",
+                              LDISKFS_SB(inode->i_sb)->s_es->s_volume_name,
+                              ent->oied_namelen, ent->oied_name, rc);
+
+               RETURN(rc);
+       }
+
+       rc = ldiskfs_delete_entry(jh, dir, de, bh);
+       if (rc != 0) {
+               CERROR("%.16s: fail to delete entry for reinsert dirent: "
+                      "name = %.*s, rc = %d\n",
+                      LDISKFS_SB(inode->i_sb)->s_es->s_volume_name,
+                      ent->oied_namelen, ent->oied_name, rc);
+               RETURN(rc);
+       }
+
+       dentry = osd_child_dentry_by_inode(env, dir, ent->oied_name,
+                                          ent->oied_namelen);
+       ldp = (struct ldiskfs_dentry_param *)osd_oti_get(env)->oti_ldp;
+       osd_get_ldiskfs_dirent_param(ldp, (const struct dt_rec *)fid);
+       dentry->d_fsdata = (void *)ldp;
+       ll_vfs_dq_init(dir);
+       rc = osd_ldiskfs_add_entry(jh, dentry, inode, hlock);
+       /* It is too bad, we cannot reinsert the name entry back.
+        * That means we lose it! */
+       if (rc != 0)
+               CERROR("%.16s: fail to insert entry for reinsert dirent: "
+                      "name = %.*s, rc = %d\n",
+                      LDISKFS_SB(inode->i_sb)->s_es->s_volume_name,
+                      ent->oied_namelen, ent->oied_name, rc);
+
+       RETURN(rc);
+}
+
+static int
+osd_dirent_check_repair(const struct lu_env *env, struct osd_object *obj,
+                       struct osd_it_ea *it, struct lu_fid *fid,
+                       struct osd_inode_id *id, __u32 *attr)
+{
+       struct osd_thread_info     *info        = osd_oti_get(env);
+       struct lustre_mdt_attrs    *lma         = &info->oti_mdt_attrs;
+       struct osd_device          *dev         = osd_obj2dev(obj);
+       struct super_block         *sb          = osd_sb(dev);
+       const char                 *devname     =
+                                       LDISKFS_SB(sb)->s_es->s_volume_name;
+       struct osd_it_ea_dirent    *ent         = it->oie_dirent;
+       struct inode               *dir         = obj->oo_inode;
+       struct htree_lock          *hlock       = NULL;
+       struct buffer_head         *bh          = NULL;
+       handle_t                   *jh          = NULL;
+       struct ldiskfs_dir_entry_2 *de;
+       struct dentry              *dentry;
+       struct inode               *inode;
+       int                         credits;
+       int                         rc;
+       bool                        dirty       = false;
+       bool                        is_dotdot   = false;
+       ENTRY;
+
+       if (ent->oied_name[0] == '.') {
+               /* Skip dot entry, even if it has stale FID-in-dirent, because
+                * we do not use such FID-in-dirent anymore, it is harmless. */
+               if (ent->oied_namelen == 1)
+                       RETURN(0);
+
+               if (ent->oied_namelen == 2 && ent->oied_name[1] == '.')
+                       is_dotdot = true;
+       }
+
+       dentry = osd_child_dentry_get(env, obj, ent->oied_name,
+                                     ent->oied_namelen);
+
+       /* We need to ensure that the name entry is still valid.
+        * Because it may be removed or renamed by other already.
+        *
+        * The unlink or rename operation will start journal before PDO lock,
+        * so to avoid deadlock, here we need to start journal handle before
+        * related PDO lock also. But because we do not know whether there
+        * will be something to be repaired before PDO lock, we just start
+        * journal without conditions.
+        *
+        * We may need to remove the name entry firstly, then insert back.
+        * One credit is for user quota file update.
+        * One credit is for group quota file update.
+        * Two credits are for dirty inode. */
+       credits = osd_dto_credits_noquota[DTO_INDEX_DELETE] +
+                 osd_dto_credits_noquota[DTO_INDEX_INSERT] + 1 + 1 + 2;
+
+again:
+       if (dev->od_dirent_journal) {
+               jh = ldiskfs_journal_start_sb(sb, credits);
+               if (IS_ERR(jh)) {
+                       rc = PTR_ERR(jh);
+                       CERROR("%.16s: fail to start trans for dirent "
+                              "check_repair: credits %d, name %.*s, rc %d\n",
+                              devname, credits, ent->oied_namelen,
+                              ent->oied_name, rc);
+                       RETURN(rc);
+               }
+       }
+
+       if (obj->oo_hl_head != NULL) {
+               hlock = osd_oti_get(env)->oti_hlock;
+               ldiskfs_htree_lock(hlock, obj->oo_hl_head, dir,
+                                  LDISKFS_HLOCK_DEL);
+       } else {
+               down_write(&obj->oo_ext_idx_sem);
+       }
+
+       bh = osd_ldiskfs_find_entry(dir, dentry, &de, hlock);
+       /* For dotdot entry, if there is not enough space to hold FID-in-dirent,
+        * just keep it there. It only happens when the device upgraded from 1.8
+        * or restored from MDT file-level backup. For the whole directory, only
+        * dotdot entry has no FID-in-dirent and needs to get FID from LMA when
+        * readdir, it will not affect the performance much. */
+       if ((bh == NULL) || (le32_to_cpu(de->inode) != ent->oied_ino) ||
+           (is_dotdot && !osd_dirent_has_space(de->rec_len,
+                                               ent->oied_namelen,
+                                               sb->s_blocksize))) {
+               *attr |= LUDA_IGNORE;
+               GOTO(out_journal, rc = 0);
+       }
+
+       osd_id_gen(id, ent->oied_ino, OSD_OII_NOGEN);
+       inode = osd_iget(info, dev, id);
+       if (IS_ERR(inode)) {
+               rc = PTR_ERR(inode);
+               if (rc == -ENOENT || rc == -ESTALE) {
+                       *attr |= LUDA_IGNORE;
+                       rc = 0;
+               }
+
+               GOTO(out_journal, rc);
+       }
+
+       rc = osd_get_lma(info, inode, &info->oti_obj_dentry, lma);
+       if (rc == 0) {
+               if (fid_is_sane(fid)) {
+                       /* FID-in-dirent is valid. */
+                       if (lu_fid_eq(fid, &lma->lma_self_fid))
+                               GOTO(out_inode, rc = 0);
+
+                       /* Do not repair under dryrun mode. */
+                       if (*attr & LUDA_VERIFY_DRYRUN) {
+                               *attr |= LUDA_REPAIR;
+                               GOTO(out_inode, rc = 0);
+                       }
+
+                       if (!dev->od_dirent_journal) {
+                               iput(inode);
+                               brelse(bh);
+                               if (hlock != NULL)
+                                       ldiskfs_htree_unlock(hlock);
+                               else
+                                       up_write(&obj->oo_ext_idx_sem);
+                               dev->od_dirent_journal = 1;
+                               goto again;
+                       }
+
+                       *fid = lma->lma_self_fid;
+                       dirty = true;
+                       /* Update the FID-in-dirent. */
+                       rc = osd_dirent_update(jh, sb, ent, fid, bh, de);
+                       if (rc == 0)
+                               *attr |= LUDA_REPAIR;
+               } else {
+                       /* Do not repair under dryrun mode. */
+                       if (*attr & LUDA_VERIFY_DRYRUN) {
+                               *attr |= LUDA_REPAIR;
+                               GOTO(out_inode, rc = 0);
+                       }
+
+                       if (!dev->od_dirent_journal) {
+                               iput(inode);
+                               brelse(bh);
+                               if (hlock != NULL)
+                                       ldiskfs_htree_unlock(hlock);
+                               else
+                                       up_write(&obj->oo_ext_idx_sem);
+                               dev->od_dirent_journal = 1;
+                               goto again;
+                       }
+
+                       *fid = lma->lma_self_fid;
+                       dirty = true;
+                       /* Append the FID-in-dirent. */
+                       rc = osd_dirent_reinsert(env, jh, dir, inode, ent,
+                                                fid, bh, de, hlock);
+                       if (rc == 0)
+                               *attr |= LUDA_REPAIR;
+               }
+       } else if (rc == -ENODATA) {
+               /* Do not repair under dryrun mode. */
+               if (*attr & LUDA_VERIFY_DRYRUN) {
+                       if (fid_is_sane(fid))
+                               *attr |= LUDA_REPAIR;
+                       else
+                               *attr |= LUDA_UPGRADE;
+                       GOTO(out_inode, rc = 0);
+               }
+
+               if (!dev->od_dirent_journal) {
+                       iput(inode);
+                       brelse(bh);
+                       if (hlock != NULL)
+                               ldiskfs_htree_unlock(hlock);
+                       else
+                               up_write(&obj->oo_ext_idx_sem);
+                       dev->od_dirent_journal = 1;
+                       goto again;
+               }
+
+               dirty = true;
+               if (unlikely(fid_is_sane(fid))) {
+                       /* FID-in-dirent exists, but FID-in-LMA is lost.
+                        * Trust the FID-in-dirent, and add FID-in-LMA. */
+                       rc = osd_ea_fid_set(info, inode, fid);
+                       if (rc == 0)
+                               *attr |= LUDA_REPAIR;
+               } else {
+                       lu_igif_build(fid, inode->i_ino, inode->i_generation);
+                       /* It is probably IGIF object. Only aappend the
+                        * FID-in-dirent. OI scrub will process FID-in-LMA. */
+                       rc = osd_dirent_reinsert(env, jh, dir, inode, ent,
+                                                fid, bh, de, hlock);
+                       if (rc == 0)
+                               *attr |= LUDA_UPGRADE;
+               }
+       }
+
+       GOTO(out_inode, rc);
+
+out_inode:
+       iput(inode);
+
+out_journal:
+       brelse(bh);
+       if (hlock != NULL)
+               ldiskfs_htree_unlock(hlock);
+       else
+               up_write(&obj->oo_ext_idx_sem);
+       if (jh != NULL)
+               ldiskfs_journal_stop(jh);
+       if (rc >= 0 && !dirty)
+               dev->od_dirent_journal = 0;
+       return rc;
+}
 
 /**
- * Returns the value (i.e. fid/igif) at current position from iterator's
- * in memory structure.
+ * Returns the value at current position from iterator's in memory structure.
  *
  * \param di struct osd_it_ea, iterator's in memory structure
  * \param attr attr requested for dirent.
@@ -4457,16 +4865,31 @@ static inline int osd_it_ea_rec(const struct lu_env *env,
        int                     rc    = 0;
        ENTRY;
 
-       if (!fid_is_sane(fid)) {
-               rc = osd_ea_fid_get(env, obj, ino, fid, id);
-               if (rc != 0) {
-                       fid_zero(&oic->oic_fid);
-                       RETURN(rc);
+       if (attr & LUDA_VERIFY) {
+               attr |= LUDA_TYPE;
+               if (unlikely(ino == osd_sb(dev)->s_root->d_inode->i_ino)) {
+                       attr |= LUDA_IGNORE;
+                       rc = 0;
+                       goto pack;
                }
+
+               rc = osd_dirent_check_repair(env, obj, it, fid, id, &attr);
        } else {
-               osd_id_gen(id, ino, OSD_OII_NOGEN);
+               attr &= ~LU_DIRENT_ATTRS_MASK;
+               if (!fid_is_sane(fid)) {
+                       if (OBD_FAIL_CHECK(OBD_FAIL_FID_LOOKUP))
+                               RETURN(-ENOENT);
+
+                       rc = osd_ea_fid_get(env, obj, ino, fid, id);
+               } else {
+                       osd_id_gen(id, ino, OSD_OII_NOGEN);
+               }
        }
 
+       if (rc < 0)
+               RETURN(rc);
+
+pack:
        osd_it_pack_dirent(lde, fid, it->oie_dirent->oied_off,
                           it->oie_dirent->oied_name,
                           it->oie_dirent->oied_namelen,
@@ -4475,10 +4898,15 @@ static inline int osd_it_ea_rec(const struct lu_env *env,
        if (osd_remote_fid(env, dev, fid))
                RETURN(0);
 
-       oic->oic_lid = *id;
-       oic->oic_fid = *fid;
-       if ((scrub->os_pos_current <= ino) &&
-           (sf->sf_flags & SF_INCONSISTENT ||
+       if (likely(!(attr & LUDA_IGNORE))) {
+               oic->oic_lid = *id;
+               oic->oic_fid = *fid;
+       }
+
+       if (!(attr & LUDA_VERIFY) &&
+           (scrub->os_pos_current <= ino) &&
+           ((sf->sf_flags & SF_INCONSISTENT) ||
+            (sf->sf_flags & SF_UPGRADE && fid_is_igif(fid)) ||
             ldiskfs_test_bit(osd_oi_fid2idx(dev, fid), sf->sf_oi_bitmap)))
                osd_consistency_check(oti, dev, oic);
 
@@ -4610,12 +5038,14 @@ static void *osd_key_init(const struct lu_context *ctx,
 static void osd_key_fini(const struct lu_context *ctx,
                          struct lu_context_key *key, void* data)
 {
-        struct osd_thread_info *info = data;
+       struct osd_thread_info *info = data;
 
-        if (info->oti_hlock != NULL)
-                ldiskfs_htree_lock_free(info->oti_hlock);
-        OBD_FREE(info->oti_it_ea_buf, OSD_IT_EA_BUFSIZE);
-        OBD_FREE_PTR(info);
+       if (info->oti_hlock != NULL)
+               ldiskfs_htree_lock_free(info->oti_hlock);
+       OBD_FREE(info->oti_it_ea_buf, OSD_IT_EA_BUFSIZE);
+       lu_buf_free(&info->oti_iobuf.dr_pg_buf);
+       lu_buf_free(&info->oti_iobuf.dr_bl_buf);
+       OBD_FREE_PTR(info);
 }
 
 static void osd_key_exit(const struct lu_context *ctx,
@@ -4644,7 +5074,9 @@ static int osd_device_init(const struct lu_env *env, struct lu_device *d,
 {
        struct osd_device *osd = osd_dev(d);
 
-       strncpy(osd->od_svname, name, MAX_OBD_NAME);
+       if (strlcpy(osd->od_svname, name, sizeof(osd->od_svname))
+           >= sizeof(osd->od_svname))
+               return -E2BIG;
        return osd_procfs_init(osd, name);
 }
 
@@ -4734,13 +5166,15 @@ static int osd_mount(const struct lu_env *env,
                GOTO(out, rc);
        }
 
-       if (lvfs_check_rdonly(o->od_mnt->mnt_sb->s_bdev)) {
+#ifdef HAVE_DEV_SET_RDONLY
+       if (dev_check_rdonly(o->od_mnt->mnt_sb->s_bdev)) {
                CERROR("%s: underlying device %s is marked as read-only. "
                       "Setup failed\n", name, dev);
                mntput(o->od_mnt);
                o->od_mnt = NULL;
                GOTO(out, rc = -EROFS);
        }
+#endif
 
        if (!LDISKFS_HAS_COMPAT_FEATURE(o->od_mnt->mnt_sb,
            LDISKFS_FEATURE_COMPAT_HAS_JOURNAL)) {
@@ -4798,6 +5232,7 @@ static int osd_device_init0(const struct lu_env *env,
        struct lu_device        *l = osd2lu_dev(o);
        struct osd_thread_info *info;
        int                     rc;
+       int                     cplen = 0;
 
        /* if the module was re-loaded, env can loose its keys */
        rc = lu_env_refill((struct lu_env *) env);
@@ -4831,8 +5266,12 @@ static int osd_device_init0(const struct lu_env *env,
        if (rc < 0)
                GOTO(out_mnt, rc);
 
-       strncpy(o->od_svname, lustre_cfg_string(cfg, 4),
-                       sizeof(o->od_svname) - 1);
+       cplen = strlcpy(o->od_svname, lustre_cfg_string(cfg, 4),
+                       sizeof(o->od_svname));
+       if (cplen >= sizeof(o->od_svname)) {
+               rc = -E2BIG;
+               GOTO(out_mnt, rc);
+       }
 
        rc = osd_obj_map_init(o);
        if (rc != 0)