Whamcloud - gitweb
LU-6895 lfsck: not destroy directory when fix FID-in-dirent
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_handler.c
index 214bce7..d6c2f86 100644 (file)
@@ -311,6 +311,130 @@ osd_iget_fid(struct osd_thread_info *info, struct osd_device *dev,
        return inode;
 }
 
+static struct inode *osd_iget_check(struct osd_thread_info *info,
+                                   struct osd_device *dev,
+                                   const struct lu_fid *fid,
+                                   struct osd_inode_id *id,
+                                   bool cached)
+{
+       struct inode    *inode;
+       int              rc     = 0;
+       ENTRY;
+
+       /* The cached OI mapping is trustable. If we cannot locate the inode
+        * via the cached OI mapping, then return the failure to the caller
+        * directly without further OI checking. */
+
+       inode = ldiskfs_iget(osd_sb(dev), id->oii_ino);
+       if (IS_ERR(inode)) {
+               rc = PTR_ERR(inode);
+               if (cached || (rc != -ENOENT && rc != -ESTALE)) {
+                       CDEBUG(D_INODE, "no inode: ino = %u, rc = %d\n",
+                              id->oii_ino, rc);
+
+                       GOTO(put, rc);
+               }
+
+               goto check_oi;
+       }
+
+       if (is_bad_inode(inode)) {
+               rc = -ENOENT;
+               if (cached) {
+                       CDEBUG(D_INODE, "bad inode: ino = %u\n", id->oii_ino);
+
+                       GOTO(put, rc);
+               }
+
+               goto check_oi;
+       }
+
+       if (id->oii_gen != OSD_OII_NOGEN &&
+           inode->i_generation != id->oii_gen) {
+               rc = -ESTALE;
+               if (cached) {
+                       CDEBUG(D_INODE, "unmatched inode: ino = %u, "
+                              "oii_gen = %u, i_generation = %u\n",
+                              id->oii_ino, id->oii_gen, inode->i_generation);
+
+                       GOTO(put, rc);
+               }
+
+               goto check_oi;
+       }
+
+       if (inode->i_nlink == 0) {
+               rc = -ENOENT;
+               if (cached) {
+                       CDEBUG(D_INODE, "stale inode: ino = %u\n", id->oii_ino);
+
+                       GOTO(put, rc);
+               }
+
+               goto check_oi;
+       }
+
+check_oi:
+       if (rc != 0) {
+               LASSERTF(rc == -ESTALE || rc == -ENOENT, "rc = %d\n", rc);
+
+               rc = osd_oi_lookup(info, dev, fid, id, OI_CHECK_FLD);
+               /* XXX: There are four possible cases:
+                *      1. rc = 0.
+                *         Backup/restore caused the OI invalid.
+                *      2. rc = 0.
+                *         Someone unlinked the object but NOT removed
+                *         the OI mapping, such as mount target device
+                *         as ldiskfs, and modify something directly.
+                *      3. rc = -ENOENT.
+                *         Someone just removed the object between the
+                *         former oi_lookup and the iget. It is normal.
+                *      4. Other failure cases.
+                *
+                *      Generally, when the device is mounted, it will
+                *      auto check whether the system is restored from
+                *      file-level backup or not. We trust such detect
+                *      to distinguish the 1st case from the 2nd case. */
+               if (rc == 0) {
+                       if (!IS_ERR(inode) && inode->i_generation != 0 &&
+                           inode->i_generation == id->oii_gen)
+                               /* "id->oii_gen != OSD_OII_NOGEN" is for
+                                * "@cached == false" case. */
+                               rc = -ENOENT;
+                       else
+                               rc = -EREMCHG;
+               } else {
+                       /* If the OI mapping was in OI file before the
+                        * osd_iget_check(), but now, it is disappear,
+                        * then it must be removed by race. That is a
+                        * normal race case. */
+               }
+       } else {
+               if (id->oii_gen == OSD_OII_NOGEN)
+                       osd_id_gen(id, inode->i_ino, inode->i_generation);
+
+               /* Do not update file c/mtime in ldiskfs.
+                * NB: we don't have any lock to protect this because we don't
+                * have reference on osd_object now, but contention with
+                * another lookup + attr_set can't happen in the tiny window
+                * between if (...) and set S_NOCMTIME. */
+               if (!(inode->i_flags & S_NOCMTIME))
+                       inode->i_flags |= S_NOCMTIME;
+       }
+
+       GOTO(put, rc);
+
+put:
+       if (rc != 0) {
+               if (!IS_ERR(inode))
+                       iput(inode);
+
+               inode = ERR_PTR(rc);
+       }
+
+       return inode;
+}
+
 /**
  * \retval +v: new filter_fid, does not contain self-fid
  * \retval 0:  filter_fid_old, contains self-fid
@@ -395,9 +519,6 @@ static int osd_check_lma(const struct lu_env *env, struct osd_object *obj)
                }
        }
 
-       if (unlikely(rc == -ENODATA))
-               RETURN(0);
-
        if (rc < 0)
                RETURN(rc);
 
@@ -460,8 +581,7 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj,
        struct scrub_file      *sf;
        int                     result;
        int                     saved  = 0;
-       bool                    in_oi  = false;
-       bool                    in_cache = false;
+       bool                    cached  = true;
        bool                    triggered = false;
        ENTRY;
 
@@ -491,7 +611,6 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj,
        if (lu_fid_eq(fid, &oic->oic_fid) &&
            likely(oic->oic_dev == dev)) {
                id = &oic->oic_lid;
-               in_cache = true;
                goto iget;
        }
 
@@ -503,10 +622,12 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj,
                        goto iget;
        }
 
+       cached = false;
        /* Search order: 3. OI files. */
        result = osd_oi_lookup(info, dev, fid, id, OI_CHECK_FLD);
        if (result == -ENOENT) {
                if (!(fid_is_norm(fid) || fid_is_igif(fid)) ||
+                   fid_is_on_ost(info, dev, fid, OI_CHECK_FLD) ||
                    !ldiskfs_test_bit(osd_oi_fid2idx(dev,fid),
                                      sf->sf_oi_bitmap))
                        GOTO(out, result = 0);
@@ -517,81 +638,64 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj,
        if (result != 0)
                GOTO(out, result);
 
-       in_oi = true;
-
 iget:
-       inode = osd_iget(info, dev, id);
+       inode = osd_iget_check(info, dev, fid, id, cached);
        if (IS_ERR(inode)) {
                result = PTR_ERR(inode);
-               if (result != -ENOENT && result != -ESTALE)
-                       GOTO(out, result);
+               if (result == -ENOENT || result == -ESTALE)
+                       GOTO(out, result = -ENOENT);
 
-               if (in_cache)
-                       fid_zero(&oic->oic_fid);
-
-               result = osd_oi_lookup(info, dev, fid, id, OI_CHECK_FLD);
-               if (result != 0)
-                       GOTO(out, result = (result == -ENOENT ? 0 : result));
-
-               /* The OI mapping is there, but the inode is NOT there.
-                * Two possible cases for that:
-                *
-                * 1) Backup/restore caused the OI invalid.
-                * 2) Someone unlinked the object but NOT removed
-                *    the OI mapping, such as mount target device
-                *    as ldiskfs, and modify something directly.
-                *
-                * Generally, when the device is mounted, it will
-                * auto check whether the system is restored from
-                * file-level backup or not. We trust such detect
-                * to distinguish the 1st case from the 2nd case. */
-               if (!(scrub->os_file.sf_flags & SF_INCONSISTENT))
-                       GOTO(out, result = 0);
+               if (result == -EREMCHG) {
 
 trigger:
-               if (unlikely(triggered))
-                       GOTO(out, result = saved);
-
-               triggered = true;
-               if (thread_is_running(&scrub->os_thread)) {
-                       result = -EINPROGRESS;
-               } else if (!dev->od_noscrub) {
-                       /* Since we do not know the right OI mapping, we have
-                        * to trigger OI scrub to scan the whole device. */
-                       result = osd_scrub_start(dev, SS_AUTO_FULL |
-                               SS_CLEAR_DRYRUN | SS_CLEAR_FAILOUT);
-                       CDEBUG(D_LFSCK | D_CONSOLE, "%.16s: trigger OI "
-                              "scrub by RPC for "DFID", rc = %d [1]\n",
-                              osd_name(dev), PFID(fid), result);
-                       if (result == 0 || result == -EALREADY)
+                       if (unlikely(triggered))
+                               GOTO(out, result = saved);
+
+                       triggered = true;
+                       if (thread_is_running(&scrub->os_thread)) {
                                result = -EINPROGRESS;
-                       else
-                               result = -EREMCHG;
-               }
+                       } else if (!dev->od_noscrub) {
+                               result = osd_scrub_start(dev, SS_AUTO_FULL |
+                                       SS_CLEAR_DRYRUN | SS_CLEAR_FAILOUT);
+                               LCONSOLE_WARN("%.16s: trigger OI scrub by RPC "
+                                             "for "DFID", rc = %d [1]\n",
+                                             osd_name(dev), PFID(fid), result);
+                               if (result == 0 || result == -EALREADY)
+                                       result = -EINPROGRESS;
+                               else
+                                       result = -EREMCHG;
+                       }
 
-               /* We still have chance to get the valid inode: for the
-                * object which is referenced by remote name entry, the
-                * object on the local MDT will be linked under the dir
-                * of "/REMOTE_PARENT_DIR" with its FID string as name.
-                *
-                * We do not know whether the object for the given FID
-                * is referenced by some remote name entry or not, and
-                * especially for DNE II, a multiple-linked object may
-                * have many name entries reside on many MDTs.
-                *
-                * To simplify the operation, OSD will not distinguish
-                * more, just lookup "/REMOTE_PARENT_DIR". Usually, it
-                * only happened for the RPC from other MDT during the
-                * OI scrub, or for the client side RPC with FID only,
-                * such as FID to path, or from old connected client. */
-               saved = result;
-               result = osd_lookup_in_remote_parent(info, dev, fid, id);
-               if (result == 0) {
-                       in_oi = false;
-                       goto iget;
+                       if (fid_is_on_ost(info, dev, fid, OI_CHECK_FLD))
+                               GOTO(out, result);
+
+                       /* We still have chance to get the valid inode: for the
+                        * object which is referenced by remote name entry, the
+                        * object on the local MDT will be linked under the dir
+                        * of "/REMOTE_PARENT_DIR" with its FID string as name.
+                        *
+                        * We do not know whether the object for the given FID
+                        * is referenced by some remote name entry or not, and
+                        * especially for DNE II, a multiple-linked object may
+                        * have many name entries reside on many MDTs.
+                        *
+                        * To simplify the operation, OSD will not distinguish
+                        * more, just lookup "/REMOTE_PARENT_DIR". Usually, it
+                        * only happened for the RPC from other MDT during the
+                        * OI scrub, or for the client side RPC with FID only,
+                        * such as FID to path, or from old connected client. */
+                       saved = result;
+                       result = osd_lookup_in_remote_parent(info, dev,
+                                                            fid, id);
+                       if (result == 0) {
+                               cached = true;
+                               goto iget;
+                       }
+
+                       result = saved;
                }
 
-               GOTO(out, result = saved);
+               GOTO(out, result);
        }
 
        obj->oo_inode = inode;
@@ -599,34 +703,66 @@ trigger:
 
        result = osd_check_lma(env, obj);
        if (result != 0) {
+               if (result == -ENODATA) {
+                       if (cached) {
+                               result = osd_oi_lookup(info, dev, fid, id,
+                                                      OI_CHECK_FLD);
+                               if (result != 0) {
+                                       /* result == -ENOENT means that the OI
+                                        * mapping has been removed by race,
+                                        * the target inode belongs to other
+                                        * object.
+                                        *
+                                        * Others error also can be returned
+                                        * directly. */
+                                       iput(inode);
+                                       obj->oo_inode = NULL;
+                                       GOTO(out, result);
+                               } else {
+                                       /* result == 0 means the cached OI
+                                        * mapping is still in the OI file,
+                                        * the target the inode is valid. */
+                               }
+                       } else {
+                               /* The current OI mapping is from the OI file,
+                                * since the inode has been found via
+                                * osd_iget_check(), no need recheck OI. */
+                       }
+
+                       goto found;
+               }
+
                iput(inode);
                obj->oo_inode = NULL;
-
                if (result != -EREMCHG)
                        GOTO(out, result);
 
-               if (in_cache)
-                       fid_zero(&oic->oic_fid);
-
-               result = osd_oi_lookup(info, dev, fid, id, OI_CHECK_FLD);
-               if (result == 0)
-                       goto trigger;
-
-               if (result != -ENOENT)
-                       GOTO(out, result);
+               if (cached) {
+                       result = osd_oi_lookup(info, dev, fid, id,
+                                              OI_CHECK_FLD);
+                       /* result == -ENOENT means the cached OI mapping
+                        * has been removed from the OI file by race,
+                        * above target inode belongs to other object.
+                        *
+                        * Others error also can be returned directly. */
+                       if (result != 0)
+                               GOTO(out, result);
 
-               if (!in_oi && (fid_is_norm(fid) || fid_is_igif(fid)) &&
-                   ldiskfs_test_bit(osd_oi_fid2idx(dev, fid),
-                                    sf->sf_oi_bitmap))
-                       goto trigger;
+                       /* result == 0, goto trigger */
+               } else {
+                       /* The current OI mapping is from the OI file,
+                        * since the inode has been found via
+                        * osd_iget_check(), no need recheck OI. */
+               }
 
-               GOTO(out, result = 0);
+               goto trigger;
        }
 
+found:
        obj->oo_compat_dot_created = 1;
        obj->oo_compat_dotdot_created = 1;
 
-        if (!S_ISDIR(inode->i_mode) || !ldiskfs_pdo) /* done */
+       if (!S_ISDIR(inode->i_mode) || !ldiskfs_pdo) /* done */
                GOTO(out, result = 0);
 
        LASSERT(obj->oo_hl_head == NULL);
@@ -639,6 +775,9 @@ trigger:
        GOTO(out, result = 0);
 
 out:
+       if (result != 0 && cached)
+               fid_zero(&oic->oic_fid);
+
        LINVRNT(osd_invariant(obj));
        return result;
 }
@@ -4993,62 +5132,44 @@ 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)
+static inline bool
+osd_dot_dotdot_has_space(struct ldiskfs_dir_entry_2 *de, int dot_dotdot)
 {
-       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)
-               RETURN(rc);
+       LASSERTF(dot_dotdot == 1 || dot_dotdot == 2,
+                "dot_dotdot = %d\n", dot_dotdot);
 
-       rec = (struct osd_fid_pack *)(de->name + de->name_len + 1);
-       fid_cpu_to_be((struct lu_fid *)rec->fp_area, fid);
-       rc = ldiskfs_handle_dirty_metadata(jh, NULL, bh);
+       if (LDISKFS_DIR_REC_LEN(de) >=
+           __LDISKFS_DIR_REC_LEN(dot_dotdot + 1 + sizeof(struct osd_fid_pack)))
+               return true;
 
-       RETURN(rc);
+       return false;
 }
 
-static inline int
-osd_dirent_has_space(__u16 reclen, __u16 namelen, unsigned blocksize)
+static inline bool
+osd_dirent_has_space(struct ldiskfs_dir_entry_2 *de, __u16 namelen,
+                    unsigned blocksize, int dot_dotdot)
 {
-       if (ldiskfs_rec_len_from_disk(reclen, blocksize) >=
-           __LDISKFS_DIR_REC_LEN(namelen + 1 + sizeof(struct osd_fid_pack)))
-               return 1;
-       else
-               return 0;
-}
+       if (dot_dotdot > 0)
+               return osd_dot_dotdot_has_space(de, dot_dotdot);
 
-static inline int
-osd_dot_dotdot_has_space(struct ldiskfs_dir_entry_2 *de, int dot_dotdot)
-{
-       LASSERTF(dot_dotdot == 1 || dot_dotdot == 2,
-                "dot_dotdot = %d\n", dot_dotdot);
+       if (ldiskfs_rec_len_from_disk(de->rec_len, blocksize) >=
+           __LDISKFS_DIR_REC_LEN(namelen + 1 + sizeof(struct osd_fid_pack)))
+               return true;
 
-       if (LDISKFS_DIR_REC_LEN(de) >=
-           __LDISKFS_DIR_REC_LEN(dot_dotdot + 1 + sizeof(struct osd_fid_pack)))
-               return 1;
-       else
-               return 0;
+       return false;
 }
 
 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 dentry *dentry, const struct lu_fid *fid,
                    struct buffer_head *bh, struct ldiskfs_dir_entry_2 *de,
-                   struct htree_lock *hlock)
+                   struct htree_lock *hlock, int dot_dotdot)
 {
-       struct dentry               *dentry;
+       struct inode                *dir        = dentry->d_parent->d_inode;
+       struct inode                *inode      = dentry->d_inode;
        struct osd_fid_pack         *rec;
        struct ldiskfs_dentry_param *ldp;
+       int                          namelen    = dentry->d_name.len;
        int                          rc;
        ENTRY;
 
@@ -5057,29 +5178,28 @@ osd_dirent_reinsert(const struct lu_env *env, handle_t *jh,
                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)) {
+       if (osd_dirent_has_space(de, namelen, dir->i_sb->s_blocksize,
+                                dot_dotdot)) {
                rc = ldiskfs_journal_get_write_access(jh, bh);
                if (rc != 0)
                        RETURN(rc);
 
-               de->name[de->name_len] = 0;
-               rec = (struct osd_fid_pack *)(de->name + de->name_len + 1);
+               de->name[namelen] = 0;
+               rec = (struct osd_fid_pack *)(de->name + namelen + 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_handle_dirty_metadata(jh, NULL, bh);
 
                RETURN(rc);
        }
 
+       LASSERTF(dot_dotdot == 0, "dot_dotdot = %d\n", dot_dotdot);
+
        rc = ldiskfs_delete_entry(jh, dir, de, bh);
        if (rc != 0)
                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, fid);
        dentry->d_fsdata = (void *)ldp;
@@ -5091,8 +5211,8 @@ osd_dirent_reinsert(const struct lu_env *env, handle_t *jh,
                CDEBUG(D_LFSCK, "%.16s: fail to reinsert the dirent, "
                       "dir = %lu/%u, name = %.*s, "DFID": rc = %d\n",
                       LDISKFS_SB(inode->i_sb)->s_es->s_volume_name,
-                      dir->i_ino, dir->i_generation,
-                      ent->oied_namelen, ent->oied_name, PFID(fid), rc);
+                      dir->i_ino, dir->i_generation, namelen,
+                      dentry->d_name.name, PFID(fid), rc);
 
        RETURN(rc);
 }
@@ -5122,6 +5242,32 @@ osd_dirent_check_repair(const struct lu_env *env, struct osd_object *obj,
        bool                        dirty       = false;
        ENTRY;
 
+       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_UNKNOWN;
+                       rc = 0;
+               } else {
+                       CDEBUG(D_LFSCK, "%.16s: fail to iget for dirent "
+                              "check_repair, dir = %lu/%u, name = %.*s: "
+                              "rc = %d\n",
+                              devname, dir->i_ino, dir->i_generation,
+                              ent->oied_namelen, ent->oied_name, rc);
+               }
+
+               RETURN(rc);
+       }
+
+       dentry = osd_child_dentry_by_inode(env, dir, ent->oied_name,
+                                          ent->oied_namelen);
+       rc = osd_get_lma(info, inode, dentry, lma);
+       if (rc == -ENODATA)
+               lma = NULL;
+       else if (rc != 0)
+               GOTO(out, rc);
+
        if (ent->oied_name[0] == '.') {
                if (ent->oied_namelen == 1)
                        dot_dotdot = 1;
@@ -5129,9 +5275,6 @@ osd_dirent_check_repair(const struct lu_env *env, struct osd_object *obj,
                        dot_dotdot = 2;
        }
 
-       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.
         *
@@ -5148,8 +5291,9 @@ osd_dirent_check_repair(const struct lu_env *env, struct osd_object *obj,
        credits = osd_dto_credits_noquota[DTO_INDEX_DELETE] +
                  osd_dto_credits_noquota[DTO_INDEX_INSERT] + 1 + 1 + 2;
 
-again:
        if (dev->od_dirent_journal != 0) {
+
+again:
                jh = osd_journal_start_sb(sb, LDISKFS_HT_MISC, credits);
                if (IS_ERR(jh)) {
                        rc = PTR_ERR(jh);
@@ -5158,7 +5302,8 @@ again:
                               "name = %.*s: rc = %d\n",
                               devname, dir->i_ino, dir->i_generation, credits,
                               ent->oied_namelen, ent->oied_name, rc);
-                       RETURN(rc);
+
+                       GOTO(out_inode, rc);
                }
 
                if (obj->oo_hl_head != NULL) {
@@ -5188,35 +5333,18 @@ again:
         * For the whole directory, only dot/dotdot entry have 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) ||
+       if ((bh == NULL) || (le32_to_cpu(de->inode) != inode->i_ino) ||
            (dot_dotdot != 0 && !osd_dot_dotdot_has_space(de, dot_dotdot))) {
                *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)
-                       rc = 1;
-               else
-                       CDEBUG(D_LFSCK, "%.16s: fail to iget for dirent "
-                              "check_repair, dir = %lu/%u, name = %.*s: "
-                              "rc = %d\n",
-                              devname, dir->i_ino, dir->i_generation,
-                              ent->oied_namelen, ent->oied_name, rc);
-
-               GOTO(out_journal, rc);
+               GOTO(out, rc = 0);
        }
 
-       rc = osd_get_lma(info, inode, &info->oti_obj_dentry, lma);
-       if (rc == 0) {
+       if (lma != NULL) {
                if (unlikely(lma->lma_compat & LMAC_NOT_IN_OI)) {
                        struct lu_fid *tfid = &lma->lma_self_fid;
 
                        *attr |= LUDA_IGNORE;
-
                        /* It must be REMOTE_PARENT_DIR and as the
                         * dotdot entry of remote directory */
                        if (unlikely(dot_dotdot != 2 ||
@@ -5229,39 +5357,40 @@ again:
                                       ent->oied_name, dir->i_ino,
                                       dir->i_generation, PFID(tfid));
 
-                               rc = -EIO;
+                               GOTO(out, rc = -EIO);
                        }
 
-
-                       GOTO(out_inode, rc);
+                       GOTO(out, 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);
+                               GOTO(out, rc = 0);
 
                        /* Do not repair under dryrun mode. */
                        if (*attr & LUDA_VERIFY_DRYRUN) {
                                *attr |= LUDA_REPAIR;
-                               GOTO(out_inode, rc = 0);
+
+                               GOTO(out, rc = 0);
                        }
 
-                       if (dev->od_dirent_journal == 0) {
-                               iput(inode);
+                       if (jh == NULL) {
                                brelse(bh);
                                if (hlock != NULL)
                                        ldiskfs_htree_unlock(hlock);
                                else
                                        up_read(&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);
+                       rc = osd_dirent_reinsert(env, jh, dentry, fid, bh, de,
+                                                hlock, dot_dotdot);
                        if (rc == 0)
                                *attr |= LUDA_REPAIR;
                        else
@@ -5276,25 +5405,26 @@ again:
                        if (*attr & LUDA_VERIFY_DRYRUN) {
                                *fid = lma->lma_self_fid;
                                *attr |= LUDA_REPAIR;
-                               GOTO(out_inode, rc = 0);
+
+                               GOTO(out, rc = 0);
                        }
 
-                       if (dev->od_dirent_journal == 0) {
-                               iput(inode);
+                       if (jh == NULL) {
                                brelse(bh);
                                if (hlock != NULL)
                                        ldiskfs_htree_unlock(hlock);
                                else
                                        up_read(&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);
+                       rc = osd_dirent_reinsert(env, jh, dentry, fid, bh, de,
+                                                hlock, dot_dotdot);
                        if (rc == 0)
                                *attr |= LUDA_REPAIR;
                        else
@@ -5305,7 +5435,7 @@ again:
                                       ent->oied_namelen, ent->oied_name,
                                       PFID(fid), rc);
                }
-       } else if (rc == -ENODATA) {
+       } else {
                /* Do not repair under dryrun mode. */
                if (*attr & LUDA_VERIFY_DRYRUN) {
                        if (fid_is_sane(fid)) {
@@ -5315,17 +5445,18 @@ again:
                                              inode->i_generation);
                                *attr |= LUDA_UPGRADE;
                        }
-                       GOTO(out_inode, rc = 0);
+
+                       GOTO(out, rc = 0);
                }
 
-               if (dev->od_dirent_journal == 0) {
-                       iput(inode);
+               if (jh == NULL) {
                        brelse(bh);
                        if (hlock != NULL)
                                ldiskfs_htree_unlock(hlock);
                        else
                                up_read(&obj->oo_ext_idx_sem);
                        dev->od_dirent_journal = 1;
+
                        goto again;
                }
 
@@ -5347,8 +5478,8 @@ again:
                        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);
+                       rc = osd_dirent_reinsert(env, jh, dentry, fid, bh, de,
+                                                hlock, dot_dotdot);
                        if (rc == 0)
                                *attr |= LUDA_UPGRADE;
                        else
@@ -5361,12 +5492,9 @@ again:
                }
        }
 
-       GOTO(out_inode, rc);
-
-out_inode:
-       iput(inode);
+       GOTO(out, rc);
 
-out_journal:
+out:
        brelse(bh);
        if (hlock != NULL) {
                ldiskfs_htree_unlock(hlock);
@@ -5376,10 +5504,15 @@ out_journal:
                else
                        up_read(&obj->oo_ext_idx_sem);
        }
+
        if (jh != NULL)
                ldiskfs_journal_stop(jh);
+
+out_inode:
+       iput(inode);
        if (rc >= 0 && !dirty)
                dev->od_dirent_journal = 0;
+
        return rc;
 }
 
@@ -5425,6 +5558,11 @@ static inline int osd_it_ea_rec(const struct lu_env *env,
                        rc = osd_dirent_check_repair(env, obj, it, fid, id,
                                                     &attr);
                }
+
+               if (!fid_is_sane(fid)) {
+                       attr &= ~LUDA_IGNORE;
+                       attr |= LUDA_UNKNOWN;
+               }
        } else {
                attr &= ~LU_DIRENT_ATTRS_MASK;
                if (!fid_is_sane(fid)) {
@@ -5462,7 +5600,7 @@ static inline int osd_it_ea_rec(const struct lu_env *env,
        if (osd_remote_fid(env, dev, fid))
                RETURN(0);
 
-       if (likely(!(attr & LUDA_IGNORE) && rc == 0))
+       if (likely(!(attr & (LUDA_IGNORE | LUDA_UNKNOWN)) && rc == 0))
                osd_add_oi_cache(oti, dev, id, fid);
 
        RETURN(rc > 0 ? 0 : rc);
@@ -6284,7 +6422,7 @@ static void __exit osd_mod_exit(void)
        lu_kmem_fini(ldiskfs_caches);
 }
 
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
 MODULE_DESCRIPTION("Lustre Object Storage Device ("LUSTRE_OSD_LDISKFS_NAME")");
 MODULE_VERSION(LUSTRE_VERSION_STRING);
 MODULE_LICENSE("GPL");