Whamcloud - gitweb
LU-3591 lfsck: repair unmatched MDT-OST objects pairs 19/7519/26
authorFan Yong <fan.yong@intel.com>
Fri, 7 Feb 2014 01:26:49 +0000 (09:26 +0800)
committerOleg Drokin <oleg.drokin@intel.com>
Sat, 22 Feb 2014 18:34:17 +0000 (18:34 +0000)
Sometimes, the MDT-object1 claims that the OST-object1 is one of its
child objects. But the OST-object1 says inconsistent information:

1. It claims invalid parent information, such as empty or bad parent
   FID information.
2. It claims that its parent is the MDT-object2, but the MDT-object2
   does not exist, or
3. The MDT-object2 exists, but it does not recognize the OST-object1.

Under such cases, the MDT-object layout information is trusted over
the OST-object back-pointer because it relates to user visible file
data. The OST-object back-pointer is only used for internal recovery
purposes and is not visible to the user, so does not affect proper
file usage information, nor was kept consistent for Lustre 1.8.x MDT
file-level backup/restore. The LFSCK will update the OST-object to
make it recognize the new parent.

Signed-off-by: Fan Yong <fan.yong@intel.com>
Change-Id: I01e67baf661b0a9e1c3de37a35de86699b07d049
Reviewed-on: http://review.whamcloud.com/7519
Tested-by: Jenkins
Reviewed-by: Alex Zhuravlev <alexey.zhuravlev@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
lustre/include/obd_support.h
lustre/lfsck/lfsck_internal.h
lustre/lfsck/lfsck_layout.c
lustre/ofd/ofd_io.c
lustre/osp/osp_internal.h
lustre/osp/osp_md_object.c
lustre/osp/osp_object.c
lustre/tests/sanity-lfsck.sh

index f47c845..7b636b5 100644 (file)
@@ -502,6 +502,8 @@ int obd_alloc_fail(const void *ptr, const char *name, const char *type,
 #define OBD_FAIL_LFSCK_DELAY4          0x160e
 #define OBD_FAIL_LFSCK_BAD_LMMOI       0x160f
 #define OBD_FAIL_LFSCK_DANGLING        0x1610
 #define OBD_FAIL_LFSCK_DELAY4          0x160e
 #define OBD_FAIL_LFSCK_BAD_LMMOI       0x160f
 #define OBD_FAIL_LFSCK_DANGLING        0x1610
+#define OBD_FAIL_LFSCK_UNMATCHED_PAIR1 0x1611
+#define OBD_FAIL_LFSCK_UNMATCHED_PAIR2 0x1612
 
 #define OBD_FAIL_LFSCK_NOTIFY_NET      0x16f0
 #define OBD_FAIL_LFSCK_QUERY_NET       0x16f1
 
 #define OBD_FAIL_LFSCK_NOTIFY_NET      0x16f0
 #define OBD_FAIL_LFSCK_QUERY_NET       0x16f1
index 8862f83..6aef96f 100644 (file)
@@ -526,6 +526,7 @@ struct lfsck_thread_info {
        struct lu_fid           lti_fid2;
        struct lu_attr          lti_la;
        struct lu_attr          lti_la2;
        struct lu_fid           lti_fid2;
        struct lu_attr          lti_la;
        struct lu_attr          lti_la2;
+       struct lu_attr          lti_la3;
        struct ost_id           lti_oi;
        union {
                struct lustre_mdt_attrs lti_lma;
        struct ost_id           lti_oi;
        union {
                struct lustre_mdt_attrs lti_lma;
index 15e9c05..ea0450d 100644 (file)
@@ -1472,12 +1472,204 @@ unlock1:
        return rc;
 }
 
        return rc;
 }
 
+/* If the OST-object does not recognize the MDT-object as its parent, and
+ * there is no other MDT-object claims as its parent, then just trust the
+ * given MDT-object as its parent. So update the OST-object filter_fid. */
+static int lfsck_layout_repair_unmatched_pair(const struct lu_env *env,
+                                             struct lfsck_component *com,
+                                             struct lfsck_layout_req *llr,
+                                             const struct lu_attr *pla)
+{
+       struct lfsck_thread_info        *info   = lfsck_env_info(env);
+       struct filter_fid               *pfid   = &info->lti_new_pfid;
+       struct lu_attr                  *tla    = &info->lti_la3;
+       struct dt_object                *parent = llr->llr_parent->llo_obj;
+       struct dt_object                *child  = llr->llr_child;
+       struct dt_device                *dev    = lfsck_obj2dt_dev(child);
+       const struct lu_fid             *tfid   = lu_object_fid(&parent->do_lu);
+       struct thandle                  *handle;
+       struct lu_buf                   *buf;
+       struct lustre_handle             lh     = { 0 };
+       int                              rc;
+       ENTRY;
+
+       CDEBUG(D_LFSCK, "Repair unmatched MDT-OST pair for: parent "DFID
+              ", child "DFID", OST-index %u, stripe-index %u, owner %u:%u\n",
+              PFID(lfsck_dto2fid(parent)), PFID(lfsck_dto2fid(child)),
+              llr->llr_ost_idx, llr->llr_lov_idx, pla->la_uid, pla->la_gid);
+
+       rc = lfsck_layout_lock(env, com, parent, &lh,
+                              MDS_INODELOCK_LAYOUT | MDS_INODELOCK_XATTR);
+       if (rc != 0)
+               RETURN(rc);
+
+       handle = dt_trans_create(env, dev);
+       if (IS_ERR(handle))
+               GOTO(unlock1, rc = PTR_ERR(handle));
+
+       pfid->ff_parent.f_seq = cpu_to_le64(tfid->f_seq);
+       pfid->ff_parent.f_oid = cpu_to_le32(tfid->f_oid);
+       /* The ff_parent->f_ver is not the real parent fid->f_ver. Instead,
+        * it is the OST-object index in the parent MDT-object layout. */
+       pfid->ff_parent.f_ver = cpu_to_le32(llr->llr_lov_idx);
+       buf = lfsck_buf_get(env, pfid, sizeof(struct filter_fid));
+
+       rc = dt_declare_xattr_set(env, child, buf, XATTR_NAME_FID, 0, handle);
+       if (rc != 0)
+               GOTO(stop, rc);
+
+       tla->la_valid = LA_UID | LA_GID;
+       tla->la_uid = pla->la_uid;
+       tla->la_gid = pla->la_gid;
+       rc = dt_declare_attr_set(env, child, tla, handle);
+       if (rc != 0)
+               GOTO(stop, rc);
+
+       rc = dt_trans_start(env, dev, handle);
+       if (rc != 0)
+               GOTO(stop, rc);
+
+       dt_write_lock(env, parent, 0);
+       if (unlikely(lu_object_is_dying(parent->do_lu.lo_header)))
+               GOTO(unlock2, rc = 1);
+
+       rc = dt_xattr_set(env, child, buf, XATTR_NAME_FID, 0, handle,
+                         BYPASS_CAPA);
+       if (rc != 0)
+               GOTO(unlock2, rc);
+
+       /* Get the latest parent's owner. */
+       rc = dt_attr_get(env, parent, tla, BYPASS_CAPA);
+       if (rc != 0)
+               GOTO(unlock2, rc);
+
+       tla->la_valid = LA_UID | LA_GID;
+       rc = dt_attr_set(env, child, tla, handle, BYPASS_CAPA);
+
+       GOTO(unlock2, rc);
+
+unlock2:
+       dt_write_unlock(env, parent);
+
+stop:
+       rc = lfsck_layout_trans_stop(env, dev, handle, rc);
+
+unlock1:
+       lfsck_layout_unlock(&lh);
+
+       return rc;
+}
+
+/* Check whether the OST-object correctly back points to the
+ * MDT-object (@parent) via the XATTR_NAME_FID xattr (@pfid). */
+static int lfsck_layout_check_parent(const struct lu_env *env,
+                                    struct lfsck_component *com,
+                                    struct dt_object *parent,
+                                    const struct lu_fid *pfid,
+                                    const struct lu_fid *cfid,
+                                    const struct lu_attr *pla,
+                                    const struct lu_attr *cla,
+                                    struct lfsck_layout_req *llr,
+                                    struct lu_buf *lov_ea, __u32 idx)
+{
+       struct lfsck_thread_info        *info   = lfsck_env_info(env);
+       struct lu_buf                   *buf    = &info->lti_big_buf;
+       struct dt_object                *tobj;
+       struct lov_mds_md_v1            *lmm;
+       struct lov_ost_data_v1          *objs;
+       int                              rc;
+       int                              i;
+       __u32                            magic;
+       __u16                            count;
+       ENTRY;
+
+       if (fid_is_zero(pfid)) {
+               /* client never wrote. */
+               if (cla->la_size == 0 && cla->la_blocks == 0)
+                       RETURN(0);
+
+               RETURN(LLIT_UNMATCHED_PAIR);
+       }
+
+       if (unlikely(!fid_is_sane(pfid)))
+               RETURN(LLIT_UNMATCHED_PAIR);
+
+       if (lu_fid_eq(pfid, lu_object_fid(&parent->do_lu))) {
+               if (llr->llr_lov_idx == idx)
+                       RETURN(0);
+
+               RETURN(LLIT_UNMATCHED_PAIR);
+       }
+
+       tobj = lfsck_object_find(env, com->lc_lfsck, pfid);
+       if (tobj == NULL)
+               RETURN(LLIT_UNMATCHED_PAIR);
+
+       if (IS_ERR(tobj))
+               RETURN(PTR_ERR(tobj));
+
+       if (!dt_object_exists(tobj))
+               GOTO(out, rc = LLIT_UNMATCHED_PAIR);
+
+       /* Load the tobj's layout EA, in spite of it is a local MDT-object or
+        * remote one on another MDT. Then check whether the given OST-object
+        * is in such layout. If yes, it is multiple referenced, otherwise it
+        * is unmatched referenced case. */
+       rc = lfsck_layout_get_lovea(env, tobj, buf, NULL);
+       if (rc == 0)
+               GOTO(out, rc = LLIT_UNMATCHED_PAIR);
+
+       if (rc < 0)
+               GOTO(out, rc);
+
+       lmm = buf->lb_buf;
+       rc = lfsck_layout_verify_header(lmm);
+       if (rc != 0)
+               GOTO(out, rc);
+
+       /* Currently, we only support LOV_MAGIC_V1/LOV_MAGIC_V3 which has
+        * been verified in lfsck_layout_verify_header() already. If some
+        * new magic introduced in the future, then layout LFSCK needs to
+        * be updated also. */
+       magic = le32_to_cpu(lmm->lmm_magic);
+       if (magic == LOV_MAGIC_V1) {
+               objs = &(lmm->lmm_objects[0]);
+       } else {
+               LASSERT(magic == LOV_MAGIC_V3);
+               objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[0];
+       }
+
+       count = le16_to_cpu(lmm->lmm_stripe_count);
+       for (i = 0; i < count; i++, objs++) {
+               struct lu_fid           *tfid   = &info->lti_fid2;
+               struct ost_id           *oi     = &info->lti_oi;
+
+               ostid_le_to_cpu(&objs->l_ost_oi, oi);
+               ostid_to_fid(tfid, oi, le32_to_cpu(objs->l_ost_idx));
+               if (lu_fid_eq(cfid, tfid)) {
+                       *lov_ea = *buf;
+
+                       GOTO(out, rc = LLIT_MULTIPLE_REFERENCED);
+               }
+       }
+
+       GOTO(out, rc = LLIT_UNMATCHED_PAIR);
+
+out:
+       lfsck_object_put(env, tobj);
+
+       return rc;
+}
+
 static int lfsck_layout_assistant_handle_one(const struct lu_env *env,
                                             struct lfsck_component *com,
                                             struct lfsck_layout_req *llr)
 {
        struct lfsck_layout                  *lo     = com->lc_file_ram;
        struct lfsck_thread_info             *info   = lfsck_env_info(env);
 static int lfsck_layout_assistant_handle_one(const struct lu_env *env,
                                             struct lfsck_component *com,
                                             struct lfsck_layout_req *llr)
 {
        struct lfsck_layout                  *lo     = com->lc_file_ram;
        struct lfsck_thread_info             *info   = lfsck_env_info(env);
+       struct filter_fid_old                *pea    = &info->lti_old_pfid;
+       struct lu_fid                        *pfid   = &info->lti_fid;
+       struct lu_buf                        *buf;
        struct dt_object                     *parent = llr->llr_parent->llo_obj;
        struct dt_object                     *child  = llr->llr_child;
        struct lu_attr                       *pla    = &info->lti_la;
        struct dt_object                     *parent = llr->llr_parent->llo_obj;
        struct dt_object                     *child  = llr->llr_child;
        struct lu_attr                       *pla    = &info->lti_la;
@@ -1485,6 +1677,7 @@ static int lfsck_layout_assistant_handle_one(const struct lu_env *env,
        struct lfsck_instance                *lfsck  = com->lc_lfsck;
        struct lfsck_bookmark                *bk     = &lfsck->li_bookmark_ram;
        enum lfsck_layout_inconsistency_type  type   = LLIT_NONE;
        struct lfsck_instance                *lfsck  = com->lc_lfsck;
        struct lfsck_bookmark                *bk     = &lfsck->li_bookmark_ram;
        enum lfsck_layout_inconsistency_type  type   = LLIT_NONE;
+       __u32                                 idx    = 0;
        int                                   rc;
        ENTRY;
 
        int                                   rc;
        ENTRY;
 
@@ -1508,6 +1701,39 @@ static int lfsck_layout_assistant_handle_one(const struct lu_env *env,
        if (rc != 0)
                GOTO(out, rc);
 
        if (rc != 0)
                GOTO(out, rc);
 
+       buf = lfsck_buf_get(env, pea, sizeof(struct filter_fid_old));
+       rc= dt_xattr_get(env, child, buf, XATTR_NAME_FID, BYPASS_CAPA);
+       if (unlikely(rc >= 0 && rc != sizeof(struct filter_fid_old) &&
+                    rc != sizeof(struct filter_fid))) {
+               type = LLIT_UNMATCHED_PAIR;
+               goto repair;
+       }
+
+       if (rc < 0 && rc != -ENODATA)
+               GOTO(out, rc);
+
+       if (rc == -ENODATA) {
+               fid_zero(pfid);
+       } else {
+               fid_le_to_cpu(pfid, &pea->ff_parent);
+               /* OST-object does not save parent FID::f_ver, instead,
+                * the OST-object index in the parent MDT-object layout
+                * EA reuses the pfid->f_ver. */
+               idx = pfid->f_ver;
+               pfid->f_ver = 0;
+       }
+
+       rc = lfsck_layout_check_parent(env, com, parent, pfid,
+                                      lu_object_fid(&child->do_lu),
+                                      pla, cla, llr, buf, idx);
+       if (rc > 0) {
+               type = rc;
+               goto repair;
+       }
+
+       if (rc < 0)
+               GOTO(out, rc);
+
        /* XXX: other inconsistency will be checked in other patches. */
 
 repair:
        /* XXX: other inconsistency will be checked in other patches. */
 
 repair:
@@ -1528,11 +1754,12 @@ repair:
                                LA_ATIME | LA_MTIME | LA_CTIME;
                rc = lfsck_layout_recreate_ostobj(env, com, llr, cla);
                break;
                                LA_ATIME | LA_MTIME | LA_CTIME;
                rc = lfsck_layout_recreate_ostobj(env, com, llr, cla);
                break;
+       case LLIT_UNMATCHED_PAIR:
+               rc = lfsck_layout_repair_unmatched_pair(env, com, llr, pla);
+               break;
 
        /* XXX: other inconsistency will be fixed in other patches. */
 
 
        /* XXX: other inconsistency will be fixed in other patches. */
 
-       case LLIT_UNMATCHED_PAIR:
-               break;
        case LLIT_MULTIPLE_REFERENCED:
                break;
        case LLIT_INCONSISTENT_OWNER:
        case LLIT_MULTIPLE_REFERENCED:
                break;
        case LLIT_INCONSISTENT_OWNER:
@@ -2345,6 +2572,7 @@ static int lfsck_layout_scan_stripes(const struct lu_env *env,
        struct lu_buf                   *buf;
        int                              rc      = 0;
        int                              i;
        struct lu_buf                   *buf;
        int                              rc      = 0;
        int                              i;
+       __u32                            magic;
        __u16                            count;
        __u16                            gen;
        ENTRY;
        __u16                            count;
        __u16                            gen;
        ENTRY;
@@ -2353,10 +2581,17 @@ static int lfsck_layout_scan_stripes(const struct lu_env *env,
                            sizeof(struct filter_fid_old));
        count = le16_to_cpu(lmm->lmm_stripe_count);
        gen = le16_to_cpu(lmm->lmm_layout_gen);
                            sizeof(struct filter_fid_old));
        count = le16_to_cpu(lmm->lmm_stripe_count);
        gen = le16_to_cpu(lmm->lmm_layout_gen);
-       if (le32_to_cpu(lmm->lmm_magic) == LOV_MAGIC_V1)
+       /* Currently, we only support LOV_MAGIC_V1/LOV_MAGIC_V3 which has
+        * been verified in lfsck_layout_verify_header() already. If some
+        * new magic introduced in the future, then layout LFSCK needs to
+        * be updated also. */
+       magic = le32_to_cpu(lmm->lmm_magic);
+       if (magic == LOV_MAGIC_V1) {
                objs = &(lmm->lmm_objects[0]);
                objs = &(lmm->lmm_objects[0]);
-       else
+       } else {
+               LASSERT(magic == LOV_MAGIC_V3);
                objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[0];
                objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[0];
+       }
 
        for (i = 0; i < count; i++, objs++) {
                struct lu_fid           *fid    = &info->lti_fid;
 
        for (i = 0; i < count; i++, objs++) {
                struct lu_fid           *fid    = &info->lti_fid;
index afda149..b524054 100644 (file)
@@ -354,6 +354,12 @@ ofd_write_attr_set(const struct lu_env *env, struct ofd_device *ofd,
        }
 
        if (ff_needed) {
        }
 
        if (ff_needed) {
+               if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_UNMATCHED_PAIR1))
+                       ff->ff_parent.f_oid = cpu_to_le32(1UL << 31);
+               if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_UNMATCHED_PAIR2))
+                       ff->ff_parent.f_oid =
+                       cpu_to_le32(le32_to_cpu(ff->ff_parent.f_oid) - 1);
+
                info->fti_buf.lb_buf = ff;
                info->fti_buf.lb_len = sizeof(*ff);
                rc = dt_declare_xattr_set(env, dt_obj, &info->fti_buf,
                info->fti_buf.lb_buf = ff;
                info->fti_buf.lb_len = sizeof(*ff);
                rc = dt_declare_xattr_set(env, dt_obj, &info->fti_buf,
index d871528..b699f74 100644 (file)
@@ -507,6 +507,11 @@ int osp_md_declare_object_create(const struct lu_env *env,
 int osp_md_object_create(const struct lu_env *env, struct dt_object *dt,
                         struct lu_attr *attr, struct dt_allocation_hint *hint,
                         struct dt_object_format *dof, struct thandle *th);
 int osp_md_object_create(const struct lu_env *env, struct dt_object *dt,
                         struct lu_attr *attr, struct dt_allocation_hint *hint,
                         struct dt_object_format *dof, struct thandle *th);
+int osp_md_declare_attr_set(const struct lu_env *env, struct dt_object *dt,
+                           const struct lu_attr *attr, struct thandle *th);
+int osp_md_attr_set(const struct lu_env *env, struct dt_object *dt,
+                   const struct lu_attr *attr, struct thandle *th,
+                   struct lustre_capa *capa);
 /* osp_precreate.c */
 int osp_init_precreate(struct osp_device *d);
 int osp_precreate_reserve(const struct lu_env *env, struct osp_device *d);
 /* osp_precreate.c */
 int osp_init_precreate(struct osp_device *d);
 int osp_precreate_reserve(const struct lu_env *env, struct osp_device *d);
index 6ef3019..39fcb66 100644 (file)
@@ -144,8 +144,7 @@ int osp_md_object_create(const struct lu_env *env, struct dt_object *dt,
         * if creation reaches here, it means the object has been created
         * successfully */
        dt->do_lu.lo_header->loh_attr |= LOHA_EXISTS | (attr->la_mode & S_IFMT);
         * if creation reaches here, it means the object has been created
         * successfully */
        dt->do_lu.lo_header->loh_attr |= LOHA_EXISTS | (attr->la_mode & S_IFMT);
-       if (S_ISDIR(attr->la_mode))
-               obj->opo_empty = 1;
+       obj->opo_empty = 1;
 
        return 0;
 }
 
        return 0;
 }
@@ -228,10 +227,8 @@ static void osp_md_ah_init(const struct lu_env *env,
        ah->dah_mode = child_mode;
 }
 
        ah->dah_mode = child_mode;
 }
 
-static int osp_md_declare_attr_set(const struct lu_env *env,
-                                  struct dt_object *dt,
-                                  const struct lu_attr *attr,
-                                  struct thandle *th)
+int osp_md_declare_attr_set(const struct lu_env *env, struct dt_object *dt,
+                           const struct lu_attr *attr, struct thandle *th)
 {
        struct osp_thread_info *osi = osp_env_info(env);
        struct update_request  *update;
 {
        struct osp_thread_info *osi = osp_env_info(env);
        struct update_request  *update;
@@ -263,9 +260,9 @@ static int osp_md_declare_attr_set(const struct lu_env *env,
        return rc;
 }
 
        return rc;
 }
 
-static int osp_md_attr_set(const struct lu_env *env, struct dt_object *dt,
-                          const struct lu_attr *attr, struct thandle *th,
-                          struct lustre_capa *capa)
+int osp_md_attr_set(const struct lu_env *env, struct dt_object *dt,
+                   const struct lu_attr *attr, struct thandle *th,
+                   struct lustre_capa *capa)
 {
        CDEBUG(D_INFO, "attr set object "DFID"\n",
               PFID(&dt->do_lu.lo_header->loh_fid));
 {
        CDEBUG(D_INFO, "attr set object "DFID"\n",
               PFID(&dt->do_lu.lo_header->loh_fid));
index c9e1e84..5ffb7e4 100644 (file)
@@ -431,10 +431,16 @@ static int osp_declare_attr_set(const struct lu_env *env, struct dt_object *dt,
        if (!(attr->la_valid & (LA_UID | LA_GID)))
                RETURN(0);
 
        if (!(attr->la_valid & (LA_UID | LA_GID)))
                RETURN(0);
 
-       /*
-        * track all UID/GID changes via llog
-        */
-       rc = osp_sync_declare_add(env, o, MDS_SETATTR64_REC, th);
+       if (!is_remote_trans(th))
+               /*
+                * track all UID/GID changes via llog
+                */
+               rc = osp_sync_declare_add(env, o, MDS_SETATTR64_REC, th);
+       else
+               /* It is for OST-object attr_set directly without updating
+                * local MDT-object attribute. It is usually used by LFSCK. */
+               rc = osp_md_declare_attr_set(env, dt, attr, th);
+
        if (rc != 0 || o->opo_ooa == NULL)
                RETURN(rc);
 
        if (rc != 0 || o->opo_ooa == NULL)
                RETURN(rc);
 
@@ -476,13 +482,17 @@ static int osp_attr_set(const struct lu_env *env, struct dt_object *dt,
                RETURN(0);
        }
 
                RETURN(0);
        }
 
-       /*
-        * once transaction is committed put proper command on
-        * the queue going to our OST
-        */
-       rc = osp_sync_add(env, o, MDS_SETATTR64_REC, th, attr);
-
-       /* XXX: send new uid/gid to OST ASAP? */
+       if (!is_remote_trans(th))
+               /*
+                * once transaction is committed put proper command on
+                * the queue going to our OST
+                */
+               rc = osp_sync_add(env, o, MDS_SETATTR64_REC, th, attr);
+               /* XXX: send new uid/gid to OST ASAP? */
+       else
+               /* It is for OST-object attr_set directly without updating
+                * local MDT-object attribute. It is usually used by LFSCK. */
+               rc = osp_md_attr_set(env, dt, attr, th, capa);
 
        RETURN(rc);
 }
 
        RETURN(rc);
 }
index 1076bfb..2a40d1c 100644 (file)
@@ -42,8 +42,8 @@ check_and_setup_lustre
 [[ $(lustre_version_code $SINGLEMDS) -le $(version_code 2.4.90) ]] &&
        ALWAYS_EXCEPT="$ALWAYS_EXCEPT 2c"
 
 [[ $(lustre_version_code $SINGLEMDS) -le $(version_code 2.4.90) ]] &&
        ALWAYS_EXCEPT="$ALWAYS_EXCEPT 2c"
 
-[[ $(lustre_version_code ost1) -lt $(version_code 2.5.50) ]] &&
-       ALWAYS_EXCEPT="$ALWAYS_EXCEPT 11 12 13 14"
+[[ $(lustre_version_code ost1) -lt $(version_code 2.5.55) ]] &&
+       ALWAYS_EXCEPT="$ALWAYS_EXCEPT 11 12 13 14 15"
 
 build_test_filter
 
 
 build_test_filter
 
@@ -1321,6 +1321,102 @@ test_14() {
 }
 run_test 14 "LFSCK can repair MDT-object with dangling reference"
 
 }
 run_test 14 "LFSCK can repair MDT-object with dangling reference"
 
+test_15a() {
+       echo "#####"
+       echo "If the OST-object referenced by the MDT-object back points"
+       echo "to some non-exist MDT-object, then the LFSCK should repair"
+       echo "the OST-object to back point to the right MDT-object."
+       echo "#####"
+
+       echo "stopall"
+       stopall > /dev/null
+       echo "formatall"
+       formatall > /dev/null
+       echo "setupall"
+       setupall > /dev/null
+
+       mkdir -p $DIR/$tdir
+       $LFS setstripe -c 1 -i 0 $DIR/$tdir
+
+       echo "Inject failure stub to make the OST-object to back point to"
+       echo "non-exist MDT-object."
+       #define OBD_FAIL_LFSCK_UNMATCHED_PAIR1  0x1611
+
+       do_facet ost1 $LCTL set_param fail_loc=0x1611
+       dd if=/dev/zero of=$DIR/$tdir/f0 bs=1M count=1
+       cancel_lru_locks osc
+       sync
+       sleep 2
+       do_facet ost1 $LCTL set_param fail_loc=0
+
+       echo "stopall to cleanup object cache"
+       stopall > /dev/null
+       echo "setupall"
+       setupall > /dev/null
+
+       echo "Trigger layout LFSCK to find out unmatched pairs and fix them"
+       $START_LAYOUT || error "(1) Fail to start LFSCK for layout!"
+
+       wait_update_facet $SINGLEMDS "$LCTL get_param -n \
+               mdd.${MDT_DEV}.lfsck_layout |
+               awk '/^status/ { print \\\$2 }'" "completed" 3 || return 2
+
+       local repaired=$($SHOW_LAYOUT |
+                        awk '/^repaired_unmatched_pair/ { print $2 }')
+       [ $repaired -eq 1 ] ||
+               error "(3) Fail to repair unmatched pair: $repaired"
+}
+run_test 15a "LFSCK can repair unmatched MDT-object/OST-object pairs (1)"
+
+test_15b() {
+       echo "#####"
+       echo "If the OST-object referenced by the MDT-object back points"
+       echo "to other MDT-object that doesn't recognize the OST-object,"
+       echo "then the LFSCK should repair it to back point to the right"
+       echo "MDT-object (the first one)."
+       echo "#####"
+
+       echo "stopall"
+       stopall > /dev/null
+       echo "formatall"
+       formatall > /dev/null
+       echo "setupall"
+       setupall > /dev/null
+
+       mkdir -p $DIR/$tdir
+       $LFS setstripe -c 1 -i 0 $DIR/$tdir
+       touch $DIR/$tdir/guard
+
+       echo "Inject failure stub to make the OST-object to back point to"
+       echo "other MDT-object"
+
+       #define OBD_FAIL_LFSCK_UNMATCHED_PAIR2  0x1612
+       do_facet ost1 $LCTL set_param fail_loc=0x1612
+       dd if=/dev/zero of=$DIR/$tdir/f0 bs=1M count=1
+       cancel_lru_locks osc
+       sync
+       sleep 2
+       do_facet ost1 $LCTL set_param fail_loc=0
+
+       echo "stopall to cleanup object cache"
+       stopall > /dev/null
+       echo "setupall"
+       setupall > /dev/null
+
+       echo "Trigger layout LFSCK to find out unmatched pairs and fix them"
+       $START_LAYOUT || error "(1) Fail to start LFSCK for layout!"
+
+       wait_update_facet $SINGLEMDS "$LCTL get_param -n \
+               mdd.${MDT_DEV}.lfsck_layout |
+               awk '/^status/ { print \\\$2 }'" "completed" 3 || return 2
+
+       local repaired=$($SHOW_LAYOUT |
+                        awk '/^repaired_unmatched_pair/ { print $2 }')
+       [ $repaired -eq 1 ] ||
+               error "(3) Fail to repair unmatched pair: $repaired"
+}
+run_test 15b "LFSCK can repair unmatched MDT-object/OST-object pairs (2)"
+
 $LCTL set_param debug=-lfsck > /dev/null || true
 
 # restore MDS/OST size
 $LCTL set_param debug=-lfsck > /dev/null || true
 
 # restore MDS/OST size