Whamcloud - gitweb
LU-8974 osd-ldiskfs: increase supported ldiskfs fs size
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_handler.c
index 2946850..a928e77 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * GPL HEADER END
  */
@@ -27,7 +23,7 @@
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, 2015, Intel Corporation.
+ * Copyright (c) 2011, 2016, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -389,6 +385,7 @@ int osd_get_lma(struct osd_thread_info *info, struct inode *inode,
 struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
                       struct osd_inode_id *id)
 {
+       int rc;
        struct inode *inode = NULL;
 
        /* if we look for an inode withing a running
@@ -418,6 +415,9 @@ struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
                LDISKFS_SB(osd_sb(dev))->s_es->s_volume_name, id->oii_ino);
                iput(inode);
                inode = ERR_PTR(-ENOENT);
+       } else if ((rc = osd_attach_jinode(inode))) {
+               iput(inode);
+               inode = ERR_PTR(rc);
        } else {
                ldiskfs_clear_inode_state(inode, LDISKFS_STATE_LUSTRE_DESTROY);
                if (id->oii_gen == OSD_OII_NOGEN)
@@ -434,7 +434,7 @@ struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
        return inode;
 }
 
-int osd_ldiskfs_add_entry(struct osd_thread_info *info,
+int osd_ldiskfs_add_entry(struct osd_thread_info *info, struct osd_device *osd,
                          handle_t *handle, struct dentry *child,
                          struct inode *inode, struct htree_lock *hlock)
 {
@@ -442,41 +442,40 @@ int osd_ldiskfs_add_entry(struct osd_thread_info *info,
 
        rc = __ldiskfs_add_entry(handle, child, inode, hlock);
        if (rc == -ENOBUFS || rc == -ENOSPC) {
-               char fidbuf[FID_LEN + 1];
-               struct lustre_mdt_attrs lma;
-               struct lu_fid fid = { };
-               char *errstr;
-               struct dentry *p_dentry = child->d_parent;
-
-               rc2 = osd_get_lma(info, p_dentry->d_inode, p_dentry,
-                                &lma);
+               struct lustre_mdt_attrs *lma = &info->oti_mdt_attrs;
+               struct inode *parent = child->d_parent->d_inode;
+               struct lu_fid *fid = NULL;
+
+               rc2 = osd_get_lma(info, parent, child->d_parent, lma);
                if (rc2 == 0) {
-                       fid = lma.lma_self_fid;
-                       snprintf(fidbuf, sizeof(fidbuf), DFID, PFID(&fid));
+                       fid = &lma->lma_self_fid;
                } else if (rc2 == -ENODATA) {
-                       if (unlikely(p_dentry->d_inode ==
-                                    inode->i_sb->s_root->d_inode))
-                               lu_local_obj_fid(&fid, OSD_FS_ROOT_OID);
-                       else if (info->oti_dev && !info->oti_dev->od_is_ost &&
-                                fid_seq_is_mdt0(fid_seq(&fid)))
-                               lu_igif_build(&fid, p_dentry->d_inode->i_ino,
-                                             p_dentry->d_inode->i_generation);
-                       snprintf(fidbuf, sizeof(fidbuf), DFID, PFID(&fid));
-               } else {
-                       snprintf(fidbuf, FID_LEN, "%s", "unknown");
+                       if (unlikely(parent == inode->i_sb->s_root->d_inode)) {
+                               fid = &info->oti_fid3;
+                               lu_local_obj_fid(fid, OSD_FS_ROOT_OID);
+                       } else if (!osd->od_is_ost && osd->od_index == 0) {
+                               fid = &info->oti_fid3;
+                               lu_igif_build(fid, parent->i_ino,
+                                             parent->i_generation);
+                       }
                }
 
-               if (rc == -ENOSPC)
-                       errstr = "has reached";
+               if (fid != NULL)
+                       CWARN("%s: directory (inode: %lu, FID: "DFID") %s "
+                             "maximum entry limit\n",
+                             osd_name(osd), parent->i_ino, PFID(fid),
+                             rc == -ENOSPC ? "has reached" : "is approaching");
                else
-                       errstr = "is approaching";
-               CWARN("%.16s: directory (inode: %lu FID: %s) %s maximum entry limit\n",
-                       LDISKFS_SB(inode->i_sb)->s_es->s_volume_name,
-                       p_dentry->d_inode->i_ino, fidbuf, errstr);
+                       CWARN("%s: directory (inode: %lu, FID: unknown) %s "
+                             "maximum entry limit\n",
+                             osd_name(osd), parent->i_ino,
+                             rc == -ENOSPC ? "has reached" : "is approaching");
+
                /* ignore such error now */
                if (rc == -ENOBUFS)
                        rc = 0;
        }
+
        return rc;
 }
 
@@ -1196,6 +1195,13 @@ found:
            (flags & SS_AUTO_PARTIAL || sf->sf_status == SS_SCANNING))
                osd_check_lmv(info, dev, inode, oic);
 
+       result = osd_attach_jinode(inode);
+       if (result) {
+               obj->oo_inode = NULL;
+               iput(inode);
+               GOTO(out, result);
+       }
+
        if (!ldiskfs_pdo)
                GOTO(out, result = 0);
 
@@ -1460,7 +1466,7 @@ enum {
  */
 static void osd_th_alloced(struct osd_thandle *oth)
 {
-        oth->oth_alloced = cfs_time_current();
+       oth->oth_alloced = ktime_get();
 }
 
 /**
@@ -1468,58 +1474,42 @@ static void osd_th_alloced(struct osd_thandle *oth)
  */
 static void osd_th_started(struct osd_thandle *oth)
 {
-        oth->oth_started = cfs_time_current();
+       oth->oth_started = ktime_get();
 }
 
 /**
- * Helper function to convert time interval to microseconds packed in
- * long int.
+ * Check whether the we deal with this handle for too long.
  */
-static long interval_to_usec(cfs_time_t start, cfs_time_t end)
+static void __osd_th_check_slow(void *oth, struct osd_device *dev,
+                               ktime_t alloced, ktime_t started,
+                               ktime_t closed)
 {
-        struct timeval val;
+       ktime_t now = ktime_get();
 
-        cfs_duration_usec(cfs_time_sub(end, start), &val);
-        return val.tv_sec * 1000000 + val.tv_usec;
-}
+       LASSERT(dev != NULL);
 
-/**
- * Check whether the we deal with this handle for too long.
- */
-static void __osd_th_check_slow(void *oth, struct osd_device *dev,
-                                cfs_time_t alloced, cfs_time_t started,
-                                cfs_time_t closed)
-{
-        cfs_time_t now = cfs_time_current();
-
-        LASSERT(dev != NULL);
-
-        lprocfs_counter_add(dev->od_stats, LPROC_OSD_THANDLE_STARTING,
-                            interval_to_usec(alloced, started));
-        lprocfs_counter_add(dev->od_stats, LPROC_OSD_THANDLE_OPEN,
-                            interval_to_usec(started, closed));
-        lprocfs_counter_add(dev->od_stats, LPROC_OSD_THANDLE_CLOSING,
-                            interval_to_usec(closed, now));
-
-        if (cfs_time_before(cfs_time_add(alloced, cfs_time_seconds(30)), now)) {
-                CWARN("transaction handle %p was open for too long: "
-                      "now "CFS_TIME_T" ,"
-                      "alloced "CFS_TIME_T" ,"
-                      "started "CFS_TIME_T" ,"
-                      "closed "CFS_TIME_T"\n",
+       lprocfs_counter_add(dev->od_stats, LPROC_OSD_THANDLE_STARTING,
+                           ktime_us_delta(started, alloced));
+       lprocfs_counter_add(dev->od_stats, LPROC_OSD_THANDLE_OPEN,
+                           ktime_us_delta(closed, started));
+       lprocfs_counter_add(dev->od_stats, LPROC_OSD_THANDLE_CLOSING,
+                           ktime_us_delta(now, closed));
+
+       if (ktime_before(ktime_add_ns(alloced, 30 * NSEC_PER_SEC), now)) {
+               CWARN("transaction handle %p was open for too long: now %lld, alloced %lld, started %lld, closed %lld\n",
                       oth, now, alloced, started, closed);
                 libcfs_debug_dumpstack(NULL);
         }
 }
 
-#define OSD_CHECK_SLOW_TH(oth, dev, expr)                               \
-{                                                                       \
-        cfs_time_t __closed = cfs_time_current();                       \
-        cfs_time_t __alloced = oth->oth_alloced;                        \
-        cfs_time_t __started = oth->oth_started;                        \
-                                                                        \
-        expr;                                                           \
-        __osd_th_check_slow(oth, dev, __alloced, __started, __closed);  \
+#define OSD_CHECK_SLOW_TH(oth, dev, expr)                              \
+{                                                                      \
+       ktime_t __closed = ktime_get();                                 \
+       ktime_t __alloced = oth->oth_alloced;                           \
+       ktime_t __started = oth->oth_started;                           \
+                                                                       \
+       expr;                                                           \
+       __osd_th_check_slow(oth, dev, __alloced, __started, __closed);  \
 }
 
 #else /* OSD_THANDLE_STATS */
@@ -1809,6 +1799,7 @@ static int osd_trans_stop(const struct lu_env *env, struct dt_device *dt,
        oh->ot_quota_trans = NULL;
 
        if (oh->ot_handle != NULL) {
+               int rc2;
                 handle_t *hdl = oh->ot_handle;
 
                 /*
@@ -1832,10 +1823,12 @@ static int osd_trans_stop(const struct lu_env *env, struct dt_device *dt,
                hdl->h_sync = th->th_sync;
 
                oh->ot_handle = NULL;
-               OSD_CHECK_SLOW_TH(oh, osd, rc = ldiskfs_journal_stop(hdl));
-               if (rc != 0)
+               OSD_CHECK_SLOW_TH(oh, osd, rc2 = ldiskfs_journal_stop(hdl));
+               if (rc2 != 0)
                        CERROR("%s: failed to stop transaction: rc = %d\n",
-                              osd_name(osd), rc);
+                              osd_name(osd), rc2);
+               if (!rc)
+                       rc = rc2;
        } else {
                osd_trans_stop_cb(oh, th->th_result);
                OBD_FREE_PTR(oh);
@@ -1988,7 +1981,7 @@ int osd_statfs(const struct lu_env *env, struct dt_device *d,
 
        statfs_pack(sfs, ksfs);
        if (unlikely(sb->s_flags & MS_RDONLY))
-               sfs->os_state = OS_STATE_READONLY;
+               sfs->os_state |= OS_STATE_READONLY;
        if (LDISKFS_HAS_INCOMPAT_FEATURE(sb,
                                         LDISKFS_FEATURE_INCOMPAT_EXTENTS))
                sfs->os_maxbytes = sb->s_maxbytes;
@@ -2740,22 +2733,22 @@ enum {
 };
 
 static int osd_mkdir(struct osd_thread_info *info, struct osd_object *obj,
-                     struct lu_attr *attr,
-                     struct dt_allocation_hint *hint,
-                     struct dt_object_format *dof,
-                     struct thandle *th)
+                    struct lu_attr *attr,
+                    struct dt_allocation_hint *hint,
+                    struct dt_object_format *dof,
+                    struct thandle *th)
 {
-        int result;
-        struct osd_thandle *oth;
-        __u32 mode = (attr->la_mode & (S_IFMT | S_IRWXUGO | S_ISVTX));
+       int result;
+       struct osd_thandle *oth;
+       __u32 mode = (attr->la_mode & (S_IFMT | S_IRWXUGO | S_ISVTX | S_ISGID));
 
-        LASSERT(S_ISDIR(attr->la_mode));
+       LASSERT(S_ISDIR(attr->la_mode));
 
-        oth = container_of(th, struct osd_thandle, ot_super);
-        LASSERT(oth->ot_handle->h_transaction != NULL);
-        result = osd_mkfile(info, obj, mode, hint, th);
+       oth = container_of(th, struct osd_thandle, ot_super);
+       LASSERT(oth->ot_handle->h_transaction != NULL);
+       result = osd_mkfile(info, obj, mode, hint, th);
 
-        return result;
+       return result;
 }
 
 static int osd_mk_index(struct osd_thread_info *info, struct osd_object *obj,
@@ -3186,10 +3179,10 @@ static int osd_object_destroy(const struct lu_env *env,
                /* it will check/delete the inode from remote parent,
                 * how to optimize it? unlink performance impaction XXX */
                result = osd_delete_from_remote_parent(env, osd, obj, oh);
-               if (result != 0 && result != -ENOENT) {
+               if (result != 0)
                        CERROR("%s: delete inode "DFID": rc = %d\n",
                               osd_name(osd), PFID(fid), result);
-               }
+
                spin_lock(&obj->oo_guard);
                clear_nlink(inode);
                spin_unlock(&obj->oo_guard);
@@ -3380,6 +3373,9 @@ static struct inode *osd_create_local_agent_inode(const struct lu_env *env,
                RETURN(local);
        }
 
+       /* restore i_gid in case S_ISGID is set, we will inherit S_ISGID and set
+        * correct gid on remote file, not agent here */
+       local->i_gid = current_fsgid();
        ldiskfs_set_inode_state(local, LDISKFS_STATE_LUSTRE_NOSCRUB);
        unlock_new_inode(local);
 
@@ -3900,7 +3896,6 @@ static int osd_xattr_set(const struct lu_env *env, struct dt_object *dt,
 
        if (strcmp(name, XATTR_NAME_LMV) == 0) {
                struct lustre_mdt_attrs *lma = &info->oti_mdt_attrs;
-               int                      rc;
 
                rc = osd_get_lma(info, inode, &info->oti_obj_dentry, lma);
                if (rc != 0)
@@ -3914,10 +3909,6 @@ static int osd_xattr_set(const struct lu_env *env, struct dt_object *dt,
                        RETURN(rc);
        }
 
-       if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_LINKEA_OVERFLOW) &&
-           strcmp(name, XATTR_NAME_LINK) == 0)
-               return -ENOSPC;
-
        rc = __osd_xattr_set(info, inode, name, buf->lb_buf, buf->lb_len,
                               fs_flags);
        osd_trans_exec_check(env, handle, OSD_OT_XATTR_SET);
@@ -4328,7 +4319,7 @@ static int osd_index_declare_ea_delete(const struct lu_env *env,
 {
        struct osd_thandle *oh;
        struct inode       *inode;
-       int                 rc;
+       int                 rc, credits;
        ENTRY;
 
        LASSERT(!dt_object_remote(dt));
@@ -4337,10 +4328,14 @@ static int osd_index_declare_ea_delete(const struct lu_env *env,
        oh = container_of0(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
-       /* due to DNE we may need to remove an agent inode */
-       osd_trans_declare_op(env, oh, OSD_OT_DELETE,
-                            osd_dto_credits_noquota[DTO_INDEX_DELETE] +
-                            osd_dto_credits_noquota[DTO_OBJECT_DELETE]);
+       credits = osd_dto_credits_noquota[DTO_INDEX_DELETE];
+       if (key != NULL && unlikely(strcmp((char *)key, dotdot) == 0)) {
+               /* '..' to a remote object has a local representative */
+               credits += osd_dto_credits_noquota[DTO_INDEX_DELETE];
+               /* to reset LMAI_REMOTE_PARENT */
+               credits += 1;
+       }
+       osd_trans_declare_op(env, oh, OSD_OT_DELETE, credits);
 
        inode = osd_dt_obj(dt)->oo_inode;
        if (inode == NULL)
@@ -4486,20 +4481,19 @@ static int osd_index_ea_delete(const struct lu_env *env, struct dt_object *dt,
         * /Agent directory, Check whether it needs to delete
         * from agent directory */
        if (unlikely(strcmp((char *)key, dotdot) == 0)) {
-               rc = osd_delete_from_remote_parent(env, osd_obj2dev(obj), obj,
-                                                  oh);
-               if (rc != 0 && rc != -ENOENT) {
-                       CERROR("%s: delete agent inode "DFID": rc = %d\n",
-                              osd_name(osd), PFID(fid), rc);
-               }
-
-               if (rc == -ENOENT)
-                       rc = 0;
-
-               GOTO(out, rc);
+               int ret;
+
+               ret = osd_delete_from_remote_parent(env, osd_obj2dev(obj),
+                                                   obj, oh);
+               if (ret != 0)
+                       /* Sigh, the entry has been deleted, and
+                        * it is not easy to revert it back, so
+                        * let's keep this error private, and let
+                        * LFSCK fix it. XXX */
+                       CERROR("%s: delete remote parent "DFID": rc = %d\n",
+                              osd_name(osd), PFID(fid), ret);
        }
 out:
-
         LASSERT(osd_invariant(obj));
        osd_trans_exec_check(env, handle, OSD_OT_DELETE);
         RETURN(rc);
@@ -4690,8 +4684,8 @@ static int __osd_ea_add_rec(struct osd_thread_info *info,
        child = osd_child_dentry_get(info->oti_env, pobj, name, strlen(name));
        child->d_fsdata = (void *)ldp;
        ll_vfs_dq_init(pobj->oo_inode);
-       rc = osd_ldiskfs_add_entry(info, oth->ot_handle, child,
-                                  cinode, hlock);
+       rc = osd_ldiskfs_add_entry(info, osd_obj2dev(pobj), oth->ot_handle,
+                                  child, cinode, hlock);
        if (rc == 0 && OBD_FAIL_CHECK(OBD_FAIL_LFSCK_BAD_TYPE)) {
                struct ldiskfs_dir_entry_2      *de;
                struct buffer_head              *bh;
@@ -5038,8 +5032,8 @@ again:
        }
 
        ldata.ld_buf = buf;
-       rc = linkea_init(&ldata);
-       if (rc == 0) {
+       rc = linkea_init_with_rec(&ldata);
+       if (!rc) {
                linkea_first_entry(&ldata);
                linkea_entry_unpack(ldata.ld_lee, &ldata.ld_reclen, NULL, fid);
        }
@@ -5047,6 +5041,48 @@ again:
        RETURN(rc);
 }
 
+static int osd_verify_ent_by_linkea(const struct lu_env *env,
+                                   struct inode *inode,
+                                   const struct lu_fid *pfid,
+                                   const char *name, const int namelen)
+{
+       struct osd_thread_info *oti = osd_oti_get(env);
+       struct lu_buf *buf = &oti->oti_big_buf;
+       struct dentry *dentry = &oti->oti_obj_dentry;
+       struct linkea_data ldata = { NULL };
+       struct lu_name cname = { .ln_name = name,
+                                .ln_namelen = namelen };
+       int rc;
+       ENTRY;
+
+again:
+       rc = __osd_xattr_get(inode, dentry, XATTR_NAME_LINK,
+                            buf->lb_buf, buf->lb_len);
+       if (rc == -ERANGE)
+               rc = __osd_xattr_get(inode, dentry, XATTR_NAME_LINK, NULL, 0);
+
+       if (rc < 0)
+               RETURN(rc);
+
+       if (unlikely(rc == 0))
+               RETURN(-ENODATA);
+
+       if (buf->lb_len < rc) {
+               lu_buf_realloc(buf, rc);
+               if (buf->lb_buf == NULL)
+                       RETURN(-ENOMEM);
+
+               goto again;
+       }
+
+       ldata.ld_buf = buf;
+       rc = linkea_init_with_rec(&ldata);
+       if (!rc)
+               rc = linkea_links_find(&ldata, &cname, pfid);
+
+       RETURN(rc);
+}
+
 /**
  * Calls ->lookup() to find dentry. From dentry get inode and
  * read inode's ea to get fid. This is required for  interoperability
@@ -5912,14 +5948,10 @@ static int osd_it_ea_key_size(const struct lu_env *env, const struct dt_it *di)
         return it->oie_dirent->oied_namelen;
 }
 
-static inline bool
-osd_dot_dotdot_has_space(struct ldiskfs_dir_entry_2 *de, int dot_dotdot)
+static inline bool osd_dotdot_has_space(struct ldiskfs_dir_entry_2 *de)
 {
-       LASSERTF(dot_dotdot == 1 || dot_dotdot == 2,
-                "dot_dotdot = %d\n", dot_dotdot);
-
        if (LDISKFS_DIR_REC_LEN(de) >=
-           __LDISKFS_DIR_REC_LEN(dot_dotdot + 1 + sizeof(struct osd_fid_pack)))
+           __LDISKFS_DIR_REC_LEN(2 + 1 + sizeof(struct osd_fid_pack)))
                return true;
 
        return false;
@@ -5927,10 +5959,10 @@ osd_dot_dotdot_has_space(struct ldiskfs_dir_entry_2 *de, int dot_dotdot)
 
 static inline bool
 osd_dirent_has_space(struct ldiskfs_dir_entry_2 *de, __u16 namelen,
-                    unsigned blocksize, int dot_dotdot)
+                    unsigned blocksize, bool dotdot)
 {
-       if (dot_dotdot > 0)
-               return osd_dot_dotdot_has_space(de, dot_dotdot);
+       if (dotdot)
+               return osd_dotdot_has_space(de);
 
        if (ldiskfs_rec_len_from_disk(de->rec_len, blocksize) >=
            __LDISKFS_DIR_REC_LEN(namelen + 1 + sizeof(struct osd_fid_pack)))
@@ -5940,10 +5972,11 @@ osd_dirent_has_space(struct ldiskfs_dir_entry_2 *de, __u16 namelen,
 }
 
 static int
-osd_dirent_reinsert(const struct lu_env *env, handle_t *jh,
-                   struct dentry *dentry, const struct lu_fid *fid,
-                   struct buffer_head *bh, struct ldiskfs_dir_entry_2 *de,
-                   struct htree_lock *hlock, int dot_dotdot)
+osd_dirent_reinsert(const struct lu_env *env, struct osd_device *dev,
+                   handle_t *jh, struct dentry *dentry,
+                   const struct lu_fid *fid, struct buffer_head *bh,
+                   struct ldiskfs_dir_entry_2 *de, struct htree_lock *hlock,
+                   bool dotdot)
 {
        struct inode                *dir        = dentry->d_parent->d_inode;
        struct inode                *inode      = dentry->d_inode;
@@ -5959,8 +5992,7 @@ 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, namelen, dir->i_sb->s_blocksize,
-                                dot_dotdot)) {
+       if (osd_dirent_has_space(de, namelen, dir->i_sb->s_blocksize, dotdot)) {
                rc = ldiskfs_journal_get_write_access(jh, bh);
                if (rc != 0)
                        RETURN(rc);
@@ -5975,7 +6007,7 @@ osd_dirent_reinsert(const struct lu_env *env, handle_t *jh,
                RETURN(rc);
        }
 
-       LASSERTF(dot_dotdot == 0, "dot_dotdot = %d\n", dot_dotdot);
+       LASSERT(!dotdot);
 
        rc = ldiskfs_delete_entry(jh, dir, de, bh);
        if (rc != 0)
@@ -5985,7 +6017,7 @@ osd_dirent_reinsert(const struct lu_env *env, handle_t *jh,
        osd_get_ldiskfs_dirent_param(ldp, fid);
        dentry->d_fsdata = (void *)ldp;
        ll_vfs_dq_init(dir);
-       rc = osd_ldiskfs_add_entry(info, jh, dentry, inode, hlock);
+       rc = osd_ldiskfs_add_entry(info, dev, jh, dentry, inode, hlock);
        /* It is too bad, we cannot reinsert the name entry back.
         * That means we lose it! */
        if (rc != 0)
@@ -6007,8 +6039,7 @@ osd_dirent_check_repair(const struct lu_env *env, struct osd_object *obj,
        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;
+       const char                 *devname     = osd_name(dev);
        struct osd_it_ea_dirent    *ent         = it->oie_dirent;
        struct inode               *dir         = obj->oo_inode;
        struct htree_lock          *hlock       = NULL;
@@ -6017,25 +6048,37 @@ osd_dirent_check_repair(const struct lu_env *env, struct osd_object *obj,
        struct ldiskfs_dir_entry_2 *de;
        struct dentry              *dentry;
        struct inode               *inode;
+       const struct lu_fid *pfid = lu_object_fid(&obj->oo_dt.do_lu);
        int                         credits;
        int                         rc;
-       int                         dot_dotdot  = 0;
+       bool                        dotdot      = false;
        bool                        dirty       = false;
        ENTRY;
 
+       if (ent->oied_name[0] == '.') {
+               if (ent->oied_namelen == 1)
+                       RETURN(0);
+
+               if (ent->oied_namelen == 2 && ent->oied_name[1] == '.')
+                       dotdot = true;
+       }
+
        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) {
+                       /* Maybe dangling name entry, or
+                        * corrupted directory entry. */
                        *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",
+                       CDEBUG(D_LFSCK, "%s: fail to iget() for dirent "
+                              "check_repair, dir = %lu/%u, name = %.*s, "
+                              "ino = %llu, rc = %d\n",
                               devname, dir->i_ino, dir->i_generation,
-                              ent->oied_namelen, ent->oied_name, rc);
+                              ent->oied_namelen, ent->oied_name,
+                              ent->oied_ino, rc);
                }
 
                RETURN(rc);
@@ -6044,18 +6087,11 @@ osd_dirent_check_repair(const struct lu_env *env, struct osd_object *obj,
        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)
+       if (rc == -ENODATA || !fid_is_sane(&lma->lma_self_fid))
                lma = NULL;
        else if (rc != 0)
                GOTO(out, rc);
 
-       if (ent->oied_name[0] == '.') {
-               if (ent->oied_namelen == 1)
-                       dot_dotdot = 1;
-               else if (ent->oied_namelen == 2 && ent->oied_name[1] == '.')
-                       dot_dotdot = 2;
-       }
-
        /* We need to ensure that the name entry is still valid.
         * Because it may be removed or renamed by other already.
         *
@@ -6078,11 +6114,12 @@ again:
                jh = osd_journal_start_sb(sb, LDISKFS_HT_MISC, credits);
                if (IS_ERR(jh)) {
                        rc = PTR_ERR(jh);
-                       CDEBUG(D_LFSCK, "%.16s: fail to start trans for dirent "
+                       CDEBUG(D_LFSCK, "%s: fail to start trans for dirent "
                               "check_repair, dir = %lu/%u, credits = %d, "
-                              "name = %.*s: rc = %d\n",
+                              "name = %.*s, ino = %llu: rc = %d\n",
                               devname, dir->i_ino, dir->i_generation, credits,
-                              ent->oied_namelen, ent->oied_name, rc);
+                              ent->oied_namelen, ent->oied_name,
+                              ent->oied_ino, rc);
 
                        GOTO(out_inode, rc);
                }
@@ -6108,124 +6145,127 @@ again:
        }
 
        bh = osd_ldiskfs_find_entry(dir, &dentry->d_name, &de, NULL, hlock);
-       /* For dot/dotdot entry, if there is not enough space to hold the
+       if (IS_ERR(bh) || le32_to_cpu(de->inode) != inode->i_ino) {
+               *attr |= LUDA_IGNORE;
+
+               GOTO(out, rc = 0);
+       }
+
+       /* For dotdot entry, if there is not enough space to hold the
         * FID-in-dirent, just keep them there. It only happens when the
         * device upgraded from 1.8 or restored from MDT file-level backup.
-        * For the whole directory, only dot/dotdot entry have no FID-in-dirent
+        * For the whole directory, only dotdot entry have no FID-in-dirent
         * and needs to get FID from LMA when readdir, it will not affect the
         * performance much. */
-       if (IS_ERR(bh) || (le32_to_cpu(de->inode) != inode->i_ino) ||
-           (dot_dotdot != 0 && !osd_dot_dotdot_has_space(de, dot_dotdot))) {
-               *attr |= LUDA_IGNORE;
+       if (dotdot && !osd_dotdot_has_space(de)) {
+               *attr |= LUDA_UNKNOWN;
 
                GOTO(out, rc = 0);
        }
 
        if (lma != NULL) {
+               if (lu_fid_eq(fid, &lma->lma_self_fid))
+                       GOTO(out, rc = 0);
+
                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 ||
-                                    fid_seq(tfid) != FID_SEQ_LOCAL_FILE ||
-                                    fid_oid(tfid) != REMOTE_PARENT_DIR_OID)) {
-                               CDEBUG(D_LFSCK, "%.16s: expect remote agent "
+                       if (likely(dotdot &&
+                                  fid_seq(tfid) == FID_SEQ_LOCAL_FILE &&
+                                  fid_oid(tfid) == REMOTE_PARENT_DIR_OID)) {
+                               /* It must be REMOTE_PARENT_DIR and as the
+                                * 'dotdot' entry of remote directory */
+                               *attr |= LUDA_IGNORE;
+                       } else {
+                               CDEBUG(D_LFSCK, "%s: expect remote agent "
                                       "parent directory, but got %.*s under "
                                       "dir = %lu/%u with the FID "DFID"\n",
                                       devname, ent->oied_namelen,
                                       ent->oied_name, dir->i_ino,
                                       dir->i_generation, PFID(tfid));
 
-                               GOTO(out, rc = -EIO);
+                               *attr |= LUDA_UNKNOWN;
                        }
 
                        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, rc = 0);
-
-                       /* Do not repair under dryrun mode. */
-                       if (*attr & LUDA_VERIFY_DRYRUN) {
-                               *attr |= LUDA_REPAIR;
+       if (!fid_is_zero(fid)) {
+               rc = osd_verify_ent_by_linkea(env, inode, pfid, ent->oied_name,
+                                             ent->oied_namelen);
+               if (rc == -ENOENT ||
+                   (rc == -ENODATA &&
+                    !(dev->od_scrub.os_file.sf_flags & SF_UPGRADE))) {
+                       /* linkEA does not recognize the dirent entry,
+                        * it may because the dirent entry corruption
+                        * and points to other's inode. */
+                       CDEBUG(D_LFSCK, "%s: the target inode does not "
+                              "recognize the dirent, dir = %lu/%u, "
+                              " name = %.*s, ino = %llu, "
+                              DFID": rc = %d\n", devname, dir->i_ino,
+                              dir->i_generation, ent->oied_namelen,
+                              ent->oied_name, ent->oied_ino, PFID(fid), rc);
+                       *attr |= LUDA_UNKNOWN;
 
-                               GOTO(out, rc = 0);
-                       }
+                       GOTO(out, rc = 0);
+               }
 
-                       if (jh == NULL) {
-                               brelse(bh);
-                               dev->od_dirent_journal = 1;
-                               if (hlock != NULL) {
-                                       ldiskfs_htree_unlock(hlock);
-                                       hlock = NULL;
-                               } else {
-                                       up_read(&obj->oo_ext_idx_sem);
-                               }
+               if (rc && rc != -ENODATA) {
+                       CDEBUG(D_LFSCK, "%s: fail to verify FID in the dirent, "
+                              "dir = %lu/%u, name = %.*s, ino = %llu, "
+                              DFID": rc = %d\n", devname, dir->i_ino,
+                              dir->i_generation, ent->oied_namelen,
+                              ent->oied_name, ent->oied_ino, PFID(fid), rc);
+                       *attr |= LUDA_UNKNOWN;
 
-                               goto again;
-                       }
+                       GOTO(out, rc = 0);
+               }
+       }
 
+       if (lma != NULL) {
+               /* linkEA recognizes the dirent entry, the FID-in-LMA is
+                * valid, trusted, in spite of fid_is_sane(fid) or not. */
+               if (*attr & LUDA_VERIFY_DRYRUN) {
                        *fid = lma->lma_self_fid;
-                       dirty = true;
-                       /* Update the FID-in-dirent. */
-                       rc = osd_dirent_reinsert(env, jh, dentry, fid, bh, de,
-                                                hlock, dot_dotdot);
-                       if (rc == 0)
-                               *attr |= LUDA_REPAIR;
-                       else
-                               CDEBUG(D_LFSCK, "%.16s: fail to update FID "
-                                      "in the dirent, dir = %lu/%u, "
-                                      "name = %.*s, "DFID": rc = %d\n",
-                                      devname, dir->i_ino, dir->i_generation,
-                                      ent->oied_namelen, ent->oied_name,
-                                      PFID(fid), rc);
-               } else {
-                       /* Do not repair under dryrun mode. */
-                       if (*attr & LUDA_VERIFY_DRYRUN) {
-                               *fid = lma->lma_self_fid;
-                               *attr |= LUDA_REPAIR;
+                       *attr |= LUDA_REPAIR;
 
-                               GOTO(out, rc = 0);
-                       }
-
-                       if (jh == NULL) {
-                               brelse(bh);
-                               dev->od_dirent_journal = 1;
-                               if (hlock != NULL) {
-                                       ldiskfs_htree_unlock(hlock);
-                                       hlock = NULL;
-                               } else {
-                                       up_read(&obj->oo_ext_idx_sem);
-                               }
+                       GOTO(out, rc = 0);
+               }
 
-                               goto again;
+               if (jh == NULL) {
+                       brelse(bh);
+                       dev->od_dirent_journal = 1;
+                       if (hlock != NULL) {
+                               ldiskfs_htree_unlock(hlock);
+                               hlock = NULL;
+                       } else {
+                               up_read(&obj->oo_ext_idx_sem);
                        }
 
-                       *fid = lma->lma_self_fid;
-                       dirty = true;
-                       /* Append the FID-in-dirent. */
-                       rc = osd_dirent_reinsert(env, jh, dentry, fid, bh, de,
-                                                hlock, dot_dotdot);
-                       if (rc == 0)
-                               *attr |= LUDA_REPAIR;
-                       else
-                               CDEBUG(D_LFSCK, "%.16s: fail to append FID "
-                                      "after the dirent, dir = %lu/%u, "
-                                      "name = %.*s, "DFID": rc = %d\n",
-                                      devname, dir->i_ino, dir->i_generation,
-                                      ent->oied_namelen, ent->oied_name,
-                                      PFID(fid), rc);
+                       goto again;
                }
+
+               *fid = lma->lma_self_fid;
+               dirty = true;
+               /* Update or append the FID-in-dirent. */
+               rc = osd_dirent_reinsert(env, dev, jh, dentry, fid,
+                                        bh, de, hlock, dotdot);
+               if (rc == 0)
+                       *attr |= LUDA_REPAIR;
+               else
+                       CDEBUG(D_LFSCK, "%s: fail to re-insert FID after "
+                              "the dirent, dir = %lu/%u, name = %.*s, "
+                              "ino = %llu, "DFID": rc = %d\n",
+                              devname, dir->i_ino, dir->i_generation,
+                              ent->oied_namelen, ent->oied_name,
+                              ent->oied_ino, PFID(fid), rc);
        } else {
-               /* Do not repair under dryrun mode. */
+               /* lma is NULL, trust the FID-in-dirent if it is valid. */
                if (*attr & LUDA_VERIFY_DRYRUN) {
                        if (fid_is_sane(fid)) {
                                *attr |= LUDA_REPAIR;
-                       } else {
+                       } else if (dev->od_index == 0) {
                                lu_igif_build(fid, inode->i_ino,
                                              inode->i_generation);
                                *attr |= LUDA_UPGRADE;
@@ -6255,27 +6295,29 @@ again:
                        if (rc == 0)
                                *attr |= LUDA_REPAIR;
                        else
-                               CDEBUG(D_LFSCK, "%.16s: fail to set LMA for "
+                               CDEBUG(D_LFSCK, "%s: fail to set LMA for "
                                       "update dirent, dir = %lu/%u, "
-                                      "name = %.*s, "DFID": rc = %d\n",
+                                      "name = %.*s, ino = %llu, "
+                                      DFID": rc = %d\n",
                                       devname, dir->i_ino, dir->i_generation,
                                       ent->oied_namelen, ent->oied_name,
-                                      PFID(fid), rc);
-               } else {
+                                      ent->oied_ino, PFID(fid), rc);
+               } else if (dev->od_index == 0) {
                        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, dentry, fid, bh, de,
-                                                hlock, dot_dotdot);
+                       rc = osd_dirent_reinsert(env, dev, jh, dentry, fid,
+                                                bh, de, hlock, dotdot);
                        if (rc == 0)
                                *attr |= LUDA_UPGRADE;
                        else
-                               CDEBUG(D_LFSCK, "%.16s: fail to append IGIF "
+                               CDEBUG(D_LFSCK, "%s: fail to append IGIF "
                                       "after the dirent, dir = %lu/%u, "
-                                      "name = %.*s, "DFID": rc = %d\n",
+                                      "name = %.*s, ino = %llu, "
+                                      DFID": rc = %d\n",
                                       devname, dir->i_ino, dir->i_generation,
                                       ent->oied_namelen, ent->oied_name,
-                                      PFID(fid), rc);
+                                      ent->oied_ino, PFID(fid), rc);
                }
        }
 
@@ -6347,10 +6389,8 @@ static inline int osd_it_ea_rec(const struct lu_env *env,
                                                     &attr);
                }
 
-               if (!fid_is_sane(fid)) {
-                       attr &= ~LUDA_IGNORE;
+               if (!fid_is_sane(fid))
                        attr |= LUDA_UNKNOWN;
-               }
        } else {
                attr &= ~LU_DIRENT_ATTRS_MASK;
                if (!fid_is_sane(fid)) {
@@ -6682,7 +6722,7 @@ static int osd_mount(const struct lu_env *env,
        struct osd_thread_info  *info = osd_oti_get(env);
        struct lu_fid           *fid = &info->oti_fid;
        struct inode            *inode;
-       int                      rc = 0, force_over_256tb = 0;
+       int                      rc = 0, force_over_512tb = 0;
         ENTRY;
 
        if (o->od_mnt != NULL)
@@ -6706,15 +6746,25 @@ static int osd_mount(const struct lu_env *env,
                RETURN(-EINVAL);
        }
 #endif
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
        if (opts != NULL && strstr(opts, "force_over_128tb") != NULL) {
-               CWARN("force_over_128tb option is depricated."
-                     "Filesystems less then 256TB can be created without any"
-                     "force options. Use force_over_256tb option for"
-                     "filesystems greather then 256TB.\n");
+               CWARN("force_over_128tb option is deprecated. "
+                     "Filesystems less than 512TB can be created without any "
+                     "force options. Use force_over_512tb option for "
+                     "filesystems greater than 512TB.\n");
        }
+#endif
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 1, 53, 0)
+       if (opts != NULL && strstr(opts, "force_over_256tb") != NULL) {
+               CWARN("force_over_256tb option is deprecated. "
+                     "Filesystems less than 512TB can be created without any "
+                     "force options. Use force_over_512tb option for "
+                     "filesystems greater than 512TB.\n");
+       }
+#endif
 
-       if (opts != NULL && strstr(opts, "force_over_256tb") != NULL)
-               force_over_256tb = 1;
+       if (opts != NULL && strstr(opts, "force_over_512tb") != NULL)
+               force_over_512tb = 1;
 
        __page = alloc_page(GFP_KERNEL);
        if (__page == NULL)
@@ -6733,12 +6783,9 @@ static int osd_mount(const struct lu_env *env,
                        "noextents",
                        /* strip out option we processed in osd */
                        "bigendian_extents",
-#if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(3,0,53,0)
-#warning "remove force_over_128 option"
-#else
-                       "force_over_128tb (deprecated)",
-#endif
+                       "force_over_128tb",
                        "force_over_256tb",
+                       "force_over_512tb",
                        NULL
                };
                strcat(options, opts);
@@ -6766,7 +6813,7 @@ static int osd_mount(const struct lu_env *env,
        /* Glom up mount options */
        if (*options != '\0')
                strcat(options, ",");
-       strlcat(options, "no_mbcache", PAGE_SIZE);
+       strlcat(options, "no_mbcache,nodelalloc", PAGE_SIZE);
 
        type = get_fs_type("ldiskfs");
        if (!type) {
@@ -6784,11 +6831,12 @@ static int osd_mount(const struct lu_env *env,
                GOTO(out, rc);
        }
 
-       if (ldiskfs_blocks_count(LDISKFS_SB(osd_sb(o))->s_es) > (64ULL << 30) &&
-           force_over_256tb == 0) {
+       if (ldiskfs_blocks_count(LDISKFS_SB(osd_sb(o))->s_es) <<
+                                osd_sb(o)->s_blocksize_bits > 512ULL << 40 &&
+                                force_over_512tb == 0) {
                CERROR("%s: device %s LDISKFS does not support filesystems "
-                      "greater than 256TB and can cause data corruption. "
-                      "Use \"force_over_256tb\" mount option to override.\n",
+                      "greater than 512TB and can cause data corruption. "
+                      "Use \"force_over_512tb\" mount option to override.\n",
                       name, dev);
                GOTO(out, rc = -EINVAL);
        }