Whamcloud - gitweb
LU-2858 mdt: check .lustre before reint operation.
authorwangdi <di.wang@whamcloud.com>
Sat, 14 Dec 2013 07:41:11 +0000 (23:41 -0800)
committerOleg Drokin <oleg.drokin@intel.com>
Sat, 9 Mar 2013 01:08:35 +0000 (20:08 -0500)
1. Check .lustre in MDT layer to make sure any attempt to change
.lustre will return EPERMT.

2. send parent fid for remote open, so mdt can check whether it
will create lov object for the fid under OBF.

3. add a few test cases in sanity 154(OBF checking) to check .lustre
and remote fid

Signed-off-by: wang di <di.wang@intel.com>
Change-Id: Ia708856e026a959ca30b06fdd3acd907e5d1b913
Reviewed-on: http://review.whamcloud.com/5555
Tested-by: Hudson
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: John Hammond <johnlockwoodhammond@gmail.com>
lustre/include/lustre_fid.h
lustre/lmv/lmv_intent.c
lustre/mdt/mdt_internal.h
lustre/mdt/mdt_open.c
lustre/mdt/mdt_reint.c
lustre/tests/sanity.sh

index 1af9af0..59be208 100644 (file)
@@ -264,6 +264,12 @@ static inline int fid_is_dot_lustre(const struct lu_fid *fid)
                        fid_oid(fid) == FID_OID_DOT_LUSTRE);
 }
 
+static inline int fid_is_obf(const struct lu_fid *fid)
+{
+       return unlikely(fid_seq(fid) == FID_SEQ_DOT_LUSTRE &&
+                       fid_oid(fid) == FID_OID_DOT_LUSTRE_OBF);
+}
+
 static inline int fid_is_otable_it(const struct lu_fid *fid)
 {
        return unlikely(fid_seq(fid) == FID_SEQ_LOCAL_FILE &&
index 207f0d9..387dd9d 100644 (file)
 #include <lprocfs_status.h>
 #include "lmv_internal.h"
 
-int lmv_intent_remote(struct obd_export *exp, void *lmm,
-                      int lmmsize, struct lookup_intent *it,
-                      int flags, struct ptlrpc_request **reqp,
-                      ldlm_blocking_callback cb_blocking,
-                     __u64 extra_lock_flags)
+static int lmv_intent_remote(struct obd_export *exp, void *lmm,
+                            int lmmsize, struct lookup_intent *it,
+                            const struct lu_fid *parent_fid, int flags,
+                            struct ptlrpc_request **reqp,
+                            ldlm_blocking_callback cb_blocking,
+                            __u64 extra_lock_flags)
 {
        struct obd_device       *obd = exp->exp_obd;
        struct lmv_obd          *lmv = &obd->u.lmv;
@@ -109,8 +110,11 @@ int lmv_intent_remote(struct obd_export *exp, void *lmm,
                GOTO(out, rc = -ENOMEM);
 
        op_data->op_fid1 = body->fid1;
-       op_data->op_bias = MDS_CROSS_REF;
+       /* Sent the parent FID to the remote MDT */
+       if (parent_fid != NULL)
+               op_data->op_fid2 = *parent_fid;
 
+       op_data->op_bias = MDS_CROSS_REF;
        CDEBUG(D_INODE, "REMOTE_INTENT with fid="DFID" -> mds #%d\n",
               PFID(&body->fid1), tgt->ltd_idx);
 
@@ -208,8 +212,8 @@ int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
         * Okay, MDS has returned success. Probably name has been resolved in
         * remote inode.
         */
-       rc = lmv_intent_remote(exp, lmm, lmmsize, it, flags, reqp,
-                              cb_blocking, extra_lock_flags);
+       rc = lmv_intent_remote(exp, lmm, lmmsize, it, &op_data->op_fid1, flags,
+                              reqp, cb_blocking, extra_lock_flags);
        if (rc != 0) {
                LASSERT(rc < 0);
                /*
@@ -276,7 +280,7 @@ int lmv_intent_lookup(struct obd_export *exp, struct md_op_data *op_data,
        if (likely(!(body->valid & OBD_MD_MDS)))
                RETURN(0);
 
-       rc = lmv_intent_remote(exp, lmm, lmmsize, it, flags, reqp,
+       rc = lmv_intent_remote(exp, lmm, lmmsize, it, NULL, flags, reqp,
                               cb_blocking, extra_lock_flags);
 
        RETURN(rc);
index 664940c..a0c047f 100644 (file)
@@ -599,11 +599,6 @@ static inline const struct lu_fid *mdt_object_fid(const struct mdt_object *o)
         return lu_object_fid(&o->mot_obj.mo_lu);
 }
 
-static inline int mdt_object_obf(const struct mdt_object *o)
-{
-        return lu_fid_eq(mdt_object_fid(o), &LU_OBF_FID);
-}
-
 static inline struct lu_site *mdt_lu_site(const struct mdt_device *mdt)
 {
         return mdt->mdt_md_dev.md_lu_dev.ld_site;
index 6c2483f..46dc11e 100644 (file)
@@ -108,29 +108,34 @@ void mdt_mfd_free(struct mdt_file_data *mfd)
 static int mdt_create_data(struct mdt_thread_info *info,
                            struct mdt_object *p, struct mdt_object *o)
 {
-        struct md_op_spec     *spec = &info->mti_spec;
-        struct md_attr        *ma   = &info->mti_attr;
-        int                    rc   = 0;
-        ENTRY;
+       struct md_op_spec     *spec = &info->mti_spec;
+       struct md_attr        *ma   = &info->mti_attr;
+       int                    rc   = 0;
+       ENTRY;
 
-        if (!md_should_create(spec->sp_cr_flags))
-                RETURN(0);
+       if (!md_should_create(spec->sp_cr_flags))
+               RETURN(0);
 
-        ma->ma_need = MA_INODE | MA_LOV;
-        ma->ma_valid = 0;
+       ma->ma_need = MA_INODE | MA_LOV;
+       ma->ma_valid = 0;
        mutex_lock(&o->mot_lov_mutex);
-        if (!(o->mot_flags & MOF_LOV_CREATED)) {
-                rc = mdo_create_data(info->mti_env,
-                                     p ? mdt_object_child(p) : NULL,
-                                     mdt_object_child(o), spec, ma);
+       if (!(o->mot_flags & MOF_LOV_CREATED)) {
+               if (p != NULL && (fid_is_obf(mdt_object_fid(p)) ||
+                                 fid_is_dot_lustre(mdt_object_fid(p))))
+                       GOTO(unlock, rc = -EPERM);
+
+               rc = mdo_create_data(info->mti_env,
+                                    p ? mdt_object_child(p) : NULL,
+                                    mdt_object_child(o), spec, ma);
                if (rc == 0)
                        rc = mdt_attr_get_complex(info, o, ma);
 
-                if (rc == 0 && ma->ma_valid & MA_LOV)
-                        o->mot_flags |= MOF_LOV_CREATED;
-        }
+               if (rc == 0 && ma->ma_valid & MA_LOV)
+                       o->mot_flags |= MOF_LOV_CREATED;
+       }
+unlock:
        mutex_unlock(&o->mot_lov_mutex);
-        RETURN(rc);
+       RETURN(rc);
 }
 
 static int mdt_ioepoch_opened(struct mdt_object *mo)
@@ -1339,9 +1344,10 @@ int mdt_pin(struct mdt_thread_info* info)
 }
 
 /* Cross-ref request. Currently it can only be a pure open (w/o create) */
-int mdt_cross_open(struct mdt_thread_info* info,
-                   const struct lu_fid *fid,
-                   struct ldlm_reply *rep, __u32 flags)
+static int mdt_cross_open(struct mdt_thread_info *info,
+                         const struct lu_fid *parent_fid,
+                         const struct lu_fid *fid,
+                         struct ldlm_reply *rep, __u32 flags)
 {
         struct md_attr    *ma = &info->mti_attr;
         struct mdt_object *o;
@@ -1371,9 +1377,17 @@ int mdt_cross_open(struct mdt_thread_info* info,
 
                        mdt_set_capainfo(info, 0, fid, BYPASS_CAPA);
                        rc = mdt_attr_get_complex(info, o, ma);
-                       if (rc == 0)
-                               rc = mdt_finish_open(info, NULL, o, flags, 0,
-                                                    rep);
+                       if (rc != 0)
+                               GOTO(out, rc);
+
+                       /* Do not create lov object if the fid is opened
+                        * under OBF */
+                       if (S_ISREG(ma->ma_attr.la_mode) &&
+                           !(ma->ma_valid & MA_LOV) && (flags & FMODE_WRITE) &&
+                           fid_is_obf(parent_fid))
+                               GOTO(out, rc = -EPERM);
+
+                       rc = mdt_finish_open(info, NULL, o, flags, 0, rep);
                } else {
                        /*
                         * Something is wrong here. lookup was positive but
@@ -1447,8 +1461,8 @@ int mdt_reint_open(struct mdt_thread_info *info, struct mdt_lock_handle *lhc)
                mdt_set_disposition(info, ldlm_rep,
                            (DISP_IT_EXECD | DISP_LOOKUP_EXECD |
                             DISP_LOOKUP_POS));
-               result = mdt_cross_open(info, rr->rr_fid1, ldlm_rep,
-                                       create_flags);
+               result = mdt_cross_open(info, rr->rr_fid2, rr->rr_fid1,
+                                       ldlm_rep, create_flags);
                GOTO(out, result);
        } else if (req_is_replay(req) ||
            (req->rq_export->exp_libclient && create_flags & MDS_OPEN_HAS_EA)) {
@@ -1549,8 +1563,9 @@ int mdt_reint_open(struct mdt_thread_info *info, struct mdt_lock_handle *lhc)
 
         mdt_set_capainfo(info, 1, child_fid, BYPASS_CAPA);
         if (result == -ENOENT) {
-                if (mdt_object_obf(parent))
-                        GOTO(out_child, result = -EPERM);
+               /* Create under OBF and .lustre is not permitted */
+               if (fid_is_obf(rr->rr_fid1) || fid_is_dot_lustre(rr->rr_fid1))
+                       GOTO(out_child, result = -EPERM);
 
                 /* save versions in reply */
                 mdt_version_get_save(info, parent, 0);
index f16da5d..6bb72b1 100644 (file)
@@ -92,7 +92,7 @@ static void mdt_obj_version_get(struct mdt_thread_info *info,
 {
         LASSERT(o);
        if (mdt_object_exists(o) && !mdt_object_remote(o) &&
-           !mdt_object_obf(o))
+           !fid_is_obf(mdt_object_fid(o)))
                 *version = dt_version_get(info->mti_env, mdt_obj2dt(o));
         else
                 *version = ENOENT_VERSION;
@@ -268,7 +268,10 @@ static int mdt_md_create(struct mdt_thread_info *info)
         DEBUG_REQ(D_INODE, mdt_info_req(info), "Create  (%s->"DFID") in "DFID,
                   rr->rr_name, PFID(rr->rr_fid2), PFID(rr->rr_fid1));
 
-        repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
+       if (fid_is_obf(rr->rr_fid1) || fid_is_dot_lustre(rr->rr_fid1))
+               RETURN(-EPERM);
+
+       repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
 
         lh = &info->mti_lh[MDT_LH_PARENT];
         mdt_lock_pdo_init(lh, LCK_PW, rr->rr_name, rr->rr_namelen);
@@ -278,9 +281,6 @@ static int mdt_md_create(struct mdt_thread_info *info)
         if (IS_ERR(parent))
                 RETURN(PTR_ERR(parent));
 
-        if (mdt_object_obf(parent))
-                GOTO(out_put_parent, rc = -EPERM);
-
         rc = mdt_version_get_check_save(info, parent, 0);
         if (rc)
                 GOTO(out_put_parent, rc);
@@ -495,14 +495,14 @@ static int mdt_reint_setattr(struct mdt_thread_info *info,
         if (info->mti_dlm_req)
                 ldlm_request_cancel(req, info->mti_dlm_req, 0);
 
-        repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
+       if (fid_is_obf(rr->rr_fid1) || fid_is_dot_lustre(rr->rr_fid1))
+               RETURN(-EPERM);
+
+       repbody = req_capsule_server_get(info->mti_pill, &RMF_MDT_BODY);
         mo = mdt_object_find(info->mti_env, info->mti_mdt, rr->rr_fid1);
         if (IS_ERR(mo))
                 GOTO(out, rc = PTR_ERR(mo));
 
-       if (mdt_object_obf(mo))
-               GOTO(out_put, rc = -EPERM);
-
         /* start a log jounal handle if needed */
         if (!(mdt_conn_flags(info) & OBD_CONNECT_SOM)) {
                 if ((ma->ma_attr.la_valid & LA_SIZE) ||
@@ -687,6 +687,8 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
         if (OBD_FAIL_CHECK(OBD_FAIL_MDS_REINT_UNLINK))
                 RETURN(err_serious(-ENOENT));
 
+       if (fid_is_obf(rr->rr_fid1) || fid_is_dot_lustre(rr->rr_fid1))
+               RETURN(-EPERM);
         /*
         * step 1: Found the parent.
          */
@@ -696,9 +698,6 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
                GOTO(out, rc);
        }
 
-       if (mdt_object_obf(mp))
-               GOTO(put_parent, rc = -EPERM);
-
        parent_lh = &info->mti_lh[MDT_LH_PARENT];
        lname = mdt_name(info->mti_env, (char *)rr->rr_name, rr->rr_namelen);
        if (mdt_object_remote(mp)) {
@@ -729,6 +728,9 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
        if (rc != 0)
                GOTO(unlock_parent, rc);
 
+       if (fid_is_obf(child_fid) || fid_is_dot_lustre(child_fid))
+               GOTO(unlock_parent, rc = -EPERM);
+
         mdt_reint_init_ma(info, ma);
 
        /* We will lock the child regardless it is local or remote. No harm. */
@@ -745,7 +747,7 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
                        CDEBUG(D_INFO, "%s: name %s can not find "DFID"\n",
                               mdt2obd_dev(info->mti_mdt)->obd_name,
                               (char *)rr->rr_name, PFID(mdt_object_fid(mc)));
-                       GOTO(unlock_parent, rc = -ENOENT);
+                       GOTO(put_child, rc = -ENOENT);
                }
                CDEBUG(D_INFO, "%s: name %s: "DFID" is another MDT\n",
                       mdt2obd_dev(info->mti_mdt)->obd_name,
@@ -753,7 +755,7 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
 
                if (!mdt_is_dne_client(req->rq_export))
                        /* Return -EIO for old client */
-                       GOTO(unlock_parent, rc = -EIO);
+                       GOTO(put_child, rc = -EIO);
 
                if (info->mti_spec.sp_rm_entry) {
                        struct lu_ucred *uc  = mdt_ucred(info);
@@ -763,7 +765,7 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
                                       "permitted for administrator: rc = %d\n",
                                        mdt2obd_dev(info->mti_mdt)->obd_name,
                                        -EPERM);
-                               GOTO(unlock_parent, rc = -EPERM);
+                               GOTO(put_child, rc = -EPERM);
                        }
 
                        ma->ma_need = MA_INODE;
@@ -771,8 +773,7 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
                        mdt_set_capainfo(info, 1, child_fid, BYPASS_CAPA);
                        rc = mdo_unlink(info->mti_env, mdt_object_child(mp),
                                        NULL, lname, ma);
-                       mdt_object_put(info->mti_env, mc);
-                       GOTO(unlock_parent, rc);
+                       GOTO(put_child, rc);
                }
                /* Revoke the LOOKUP lock of the remote object granted by
                 * this MDT. Since the unlink will happen on another MDT,
@@ -785,21 +786,18 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
                LASSERT(repbody != NULL);
                repbody->fid1 = *mdt_object_fid(mc);
                repbody->valid |= (OBD_MD_FLID | OBD_MD_MDS);
-               mdt_object_unlock_put(info, mc, child_lh, rc);
-               GOTO(unlock_parent, rc = -EREMOTE);
+               GOTO(unlock_child, rc = -EREMOTE);
        } else if (info->mti_spec.sp_rm_entry) {
                CERROR("%s: lfs rmdir should not be used on local dir %s\n",
                       mdt2obd_dev(info->mti_mdt)->obd_name,
                       (char *)rr->rr_name);
-               mdt_object_put(info->mti_env, mc);
-               GOTO(unlock_parent, rc = -EPERM);
+               GOTO(put_child, rc = -EPERM);
        }
 
         rc = mdt_object_lock(info, mc, child_lh, MDS_INODELOCK_FULL,
                              MDT_CROSS_LOCK);
        if (rc != 0) {
-               mdt_object_put(info->mti_env, mc);
-               GOTO(unlock_parent, rc);
+               GOTO(put_child, rc);
        }
 
         mdt_fail_write(info->mti_env, info->mti_mdt->mdt_bottom,
@@ -840,8 +838,10 @@ static int mdt_reint_unlink(struct mdt_thread_info *info,
         }
 
         EXIT;
-
-        mdt_object_unlock_put(info, mc, child_lh, rc);
+unlock_child:
+       mdt_object_unlock(info, mc, child_lh, rc);
+put_child:
+       mdt_object_put(info->mti_env, mc);
 unlock_parent:
        mdt_object_unlock(info, mp, parent_lh, rc);
 put_parent:
@@ -882,6 +882,10 @@ static int mdt_reint_link(struct mdt_thread_info *info,
         if (lu_fid_eq(rr->rr_fid1, rr->rr_fid2))
                 RETURN(-EPERM);
 
+       if (fid_is_obf(rr->rr_fid1) || fid_is_dot_lustre(rr->rr_fid1) ||
+           fid_is_obf(rr->rr_fid2) || fid_is_dot_lustre(rr->rr_fid2))
+               RETURN(-EPERM);
+
         /* step 1: find & lock the target parent dir */
         lhp = &info->mti_lh[MDT_LH_PARENT];
         mdt_lock_pdo_init(lhp, LCK_PW, rr->rr_name,
@@ -891,9 +895,6 @@ static int mdt_reint_link(struct mdt_thread_info *info,
         if (IS_ERR(mp))
                 RETURN(PTR_ERR(mp));
 
-        if (mdt_object_obf(mp))
-                GOTO(out_unlock_parent, rc = -EPERM);
-
         rc = mdt_version_get_check_save(info, mp, 0);
         if (rc)
                 GOTO(out_unlock_parent, rc);
@@ -1098,6 +1099,10 @@ static int mdt_reint_rename(struct mdt_thread_info *info,
                   PFID(rr->rr_fid1), rr->rr_name,
                   PFID(rr->rr_fid2), rr->rr_tgt);
 
+       if (fid_is_obf(rr->rr_fid1) || fid_is_dot_lustre(rr->rr_fid1) ||
+           fid_is_obf(rr->rr_fid2) || fid_is_dot_lustre(rr->rr_fid2))
+               RETURN(-EPERM);
+
        rc = mdt_rename_lock(info, &rename_lh);
        if (rc) {
                CERROR("Can't lock FS for rename, rc %d\n", rc);
@@ -1115,9 +1120,6 @@ static int mdt_reint_rename(struct mdt_thread_info *info,
         if (IS_ERR(msrcdir))
                 GOTO(out_rename_lock, rc = PTR_ERR(msrcdir));
 
-        if (mdt_object_obf(msrcdir))
-                GOTO(out_unlock_source, rc = -EPERM);
-
         rc = mdt_version_get_check_save(info, msrcdir, 0);
         if (rc)
                 GOTO(out_unlock_source, rc);
@@ -1142,9 +1144,6 @@ static int mdt_reint_rename(struct mdt_thread_info *info,
                 if (IS_ERR(mtgtdir))
                         GOTO(out_unlock_source, rc = PTR_ERR(mtgtdir));
 
-                if (mdt_object_obf(mtgtdir))
-                        GOTO(out_put_target, rc = -EPERM);
-
                 /* check early, the real version will be saved after locking */
                 rc = mdt_version_get_check(info, mtgtdir, 1);
                 if (rc)
@@ -1182,6 +1181,9 @@ static int mdt_reint_rename(struct mdt_thread_info *info,
         if (lu_fid_eq(old_fid, rr->rr_fid1) || lu_fid_eq(old_fid, rr->rr_fid2))
                 GOTO(out_unlock_target, rc = -EINVAL);
 
+       if (fid_is_obf(old_fid) || fid_is_dot_lustre(old_fid))
+               GOTO(out_unlock_target, rc = -EPERM);
+
        mold = mdt_object_find(info->mti_env, info->mti_mdt, old_fid);
        if (IS_ERR(mold))
                GOTO(out_unlock_target, rc = PTR_ERR(mold));
@@ -1192,11 +1194,6 @@ static int mdt_reint_rename(struct mdt_thread_info *info,
                GOTO(out_unlock_target, rc = -EXDEV);
        }
 
-       if (mdt_object_obf(mold)) {
-               mdt_object_put(info->mti_env, mold);
-               GOTO(out_unlock_target, rc = -EPERM);
-       }
-
         lh_oldp = &info->mti_lh[MDT_LH_OLD];
         mdt_lock_reg_init(lh_oldp, LCK_EX);
         rc = mdt_object_lock(info, mold, lh_oldp, MDS_INODELOCK_LOOKUP,
@@ -1226,16 +1223,14 @@ static int mdt_reint_rename(struct mdt_thread_info *info,
                     lu_fid_eq(new_fid, rr->rr_fid2))
                         GOTO(out_unlock_old, rc = -EINVAL);
 
+               if (fid_is_obf(new_fid) || fid_is_dot_lustre(new_fid))
+                       GOTO(out_unlock_old, rc = -EPERM);
+
                 mdt_lock_reg_init(lh_newp, LCK_EX);
                 mnew = mdt_object_find(info->mti_env, info->mti_mdt, new_fid);
                 if (IS_ERR(mnew))
                         GOTO(out_unlock_old, rc = PTR_ERR(mnew));
 
-               if (mdt_object_obf(mnew)) {
-                       mdt_object_put(info->mti_env, mnew);
-                       GOTO(out_unlock_old, rc = -EPERM);
-               }
-
                if (mdt_object_remote(mnew)) {
                        mdt_object_put(info->mti_env, mnew);
                        CDEBUG(D_INFO, "src child "DFID" is on another MDT\n",
index 940e64c..21ba77b 100644 (file)
@@ -8473,18 +8473,10 @@ test_153() {
 }
 run_test 153 "test if fdatasync does not crash ======================="
 
-test_154() {
-       [ $PARALLEL == "yes" ] && skip "skip parallel run" && return
-       [[ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.2.51) ]] ||
-               { skip "Need MDS version at least 2.2.51"; return 0; }
-
-       cp /etc/hosts $DIR/$tfile
-
-       fid=$($LFS path2fid $DIR/$tfile)
-       rc=$?
-       [ $rc -ne 0 ] && error "error: could not get fid for $DIR/$tfile."
-
-       ffid=$DIR/.lustre/fid/$fid
+dot_lustre_fid_permission_check() {
+       local fid=$1
+       local ffid=$MOUNT/.lustre/fid/$fid
+       local test_dir=$2
 
        echo "stat fid $fid"
        stat $ffid > /dev/null || error "stat $ffid failed."
@@ -8497,14 +8489,16 @@ test_154() {
        echo "append write to fid $fid"
        cat /etc/hosts >> $ffid || error "append write $ffid failed."
        echo "rename fid $fid"
-       mv $ffid $DIR/$tfile.1 && error "rename $ffid to $tfile.1 should fail."
-       touch $DIR/$tfile.1
-       mv $DIR/$tfile.1 $ffid && error "rename $tfile.1 to $ffid should fail."
-       rm -f $DIR/$tfile.1
+       mv $ffid $test_dir/$tfile.1 &&
+               error "rename $ffid to $tfile.1 should fail."
+       touch $test_dir/$tfile.1
+       mv $test_dir/$tfile.1 $ffid &&
+               error "rename $tfile.1 to $ffid should fail."
+       rm -f $test_dir/$tfile.1
        echo "truncate fid $fid"
        $TRUNCATE $ffid 777 || error "truncate $ffid failed."
        echo "link fid $fid"
-       ln -f $ffid $DIR/tfile.lnk || error "link $ffid failed."
+       ln -f $ffid $test_dir/tfile.lnk || error "link $ffid failed."
        if [ -n $(lctl get_param -n mdc.*-mdc-*.connect_flags | grep acl) ]; then
                echo "setfacl fid $fid"
                setfacl -R -m u:bin:rwx $ffid || error "setfacl $ffid failed."
@@ -8512,80 +8506,136 @@ test_154() {
                getfacl $ffid >/dev/null || error "getfacl $ffid failed."
        fi
        echo "unlink fid $fid"
-       unlink $DIR/.lustre/fid/$fid && error "unlink $ffid should fail."
+       unlink $MOUNT/.lustre/fid/$fid && error "unlink $ffid should fail."
        echo "mknod fid $fid"
        mknod $ffid c 1 3 && error "mknod $ffid should fail."
 
        fid=[0xf00000400:0x1:0x0]
-       ffid=$DIR/.lustre/fid/$fid
+       ffid=$MOUNT/.lustre/fid/$fid
 
        echo "stat non-exist fid $fid"
        stat $ffid > /dev/null && error "stat non-exist $ffid should fail."
        echo "write to non-exist fid $fid"
        cat /etc/hosts > $ffid && error "write non-exist $ffid should fail."
        echo "link new fid $fid"
-       ln $DIR/$tfile $ffid && error "link $ffid should fail."
+       ln $test_dir/$tfile $ffid && error "link $ffid should fail."
 
-       test_mkdir -p $DIR/$tdir
-       touch $DIR/$tdir/$tfile
-       fid=$($LFS path2fid $DIR/$tdir)
+       mkdir -p $test_dir/$tdir
+       touch $test_dir/$tdir/$tfile
+       fid=$($LFS path2fid $test_dir/$tdir)
        rc=$?
-       [ $rc -ne 0 ] && error "error: could not get fid for $DIR/$tfile."
+       [ $rc -ne 0 ] &&
+               error "error: could not get fid for $test_dir/$dir/$tfile."
 
-       ffid=$DIR/.lustre/fid/$fid
+       ffid=$MOUNT/.lustre/fid/$fid
 
        echo "ls $fid"
        ls $ffid > /dev/null || error "ls $ffid failed."
        echo "touch $fid/$tfile.1"
        touch $ffid/$tfile.1 || error "touch $ffid/$tfile.1 failed."
 
-       echo "touch $DIR/.lustre/fid/$tfile"
-       touch $DIR/.lustre/fid/$tfile && \
-               error "touch $DIR/.lustre/fid/$tfile should fail."
+       echo "touch $MOUNT/.lustre/fid/$tfile"
+       touch $MOUNT/.lustre/fid/$tfile && \
+               error "touch $MOUNT/.lustre/fid/$tfile should fail."
 
-       echo "setxattr to $DIR/.lustre/fid"
-       setfattr -n trusted.name1 -v value1 $DIR/.lustre/fid &&
+       echo "setxattr to $MOUNT/.lustre/fid"
+       setfattr -n trusted.name1 -v value1 $MOUNT/.lustre/fid &&
                error "setxattr should fail."
 
-       echo "listxattr for $DIR/.lustre/fid"
-       getfattr -d -m "^trusted" $DIR/.lustre/fid &&
+       echo "listxattr for $MOUNT/.lustre/fid"
+       getfattr -d -m "^trusted" $MOUNT/.lustre/fid &&
                error "listxattr should fail."
 
-       echo "delxattr from $DIR/.lustre/fid"
-       setfattr -x trusted.name1 $DIR/.lustre/fid &&
+       echo "delxattr from $MOUNT/.lustre/fid"
+       setfattr -x trusted.name1 $MOUNT/.lustre/fid &&
                error "delxattr should fail."
 
-       echo "touch invalid fid: $DIR/.lustre/fid/[0x200000400:0x2:0x3]"
-       touch $DIR/.lustre/fid/[0x200000400:0x2:0x3] &&
+       echo "touch invalid fid: $MOUNT/.lustre/fid/[0x200000400:0x2:0x3]"
+       touch $MOUNT/.lustre/fid/[0x200000400:0x2:0x3] &&
                error "touch invalid fid should fail."
 
-       echo "touch non-normal fid: $DIR/.lustre/fid/[0x1:0x2:0x0]"
-       touch $DIR/.lustre/fid/[0x1:0x2:0x0] &&
+       echo "touch non-normal fid: $MOUNT/.lustre/fid/[0x1:0x2:0x0]"
+       touch $MOUNT/.lustre/fid/[0x1:0x2:0x0] &&
                error "touch non-normal fid should fail."
 
-       echo "rename $tdir to $DIR/.lustre/fid"
-       mrename $DIR/$tdir $DIR/.lustre/fid &&
-               error "rename to $DIR/.lustre/fid should fail."
+       echo "rename $tdir to $MOUNT/.lustre/fid"
+       mrename $test_dir/$tdir $MOUNT/.lustre/fid &&
+               error "rename to $MOUNT/.lustre/fid should fail."
 
        echo "rename .lustre to itself"
-       fid=$($LFS path2fid $DIR)
-       mrename $DIR/.lustre $DIR/.lustre/fid/$fid/.lustre &&
+       fid=$($LFS path2fid $MOUNT)
+       mrename $MOUNT/.lustre $MOUNT/.lustre/fid/$fid/.lustre &&
                error "rename .lustre to itself should fail."
 
-       $OPENFILE -f O_LOV_DELAY_CREATE:O_CREAT $DIR/$tfile-2
-       fid=$($LFS path2fid $DIR/$tfile-2)
-       echo "cp /etc/passwd $DIR/.lustre/fid/$fid"
-       cp /etc/passwd $DIR/.lustre/fid/$fid &&
+       $OPENFILE -f O_LOV_DELAY_CREATE:O_CREAT $test_dir/$tfile-2
+       fid=$($LFS path2fid $test_dir/$tfile-2)
+       echo "cp /etc/passwd $MOUNT/.lustre/fid/$fid"
+       cp /etc/passwd $MOUNT/.lustre/fid/$fid &&
                error "create lov data thru .lustre should fail."
-       echo "cp /etc/passwd $DIR/$tfile-2"
-       cp /etc/passwd $DIR/$tfile-2 || error "copy to $DIR/$tfile-2 failed."
-       echo "diff /etc/passwd $DIR/.lustre/fid/$fid"
-       diff /etc/passwd $DIR/.lustre/fid/$fid ||
-               error "diff /etc/passwd $DIR/.lustre/fid/$fid failed."
+       echo "cp /etc/passwd $test_dir/$tfile-2"
+       cp /etc/passwd $test_dir/$tfile-2 ||
+               error "copy to $test_dir/$tfile-2 failed."
+       echo "diff /etc/passwd $MOUNT/.lustre/fid/$fid"
+       diff /etc/passwd $MOUNT/.lustre/fid/$fid ||
+               error "diff /etc/passwd $MOUNT/.lustre/fid/$fid failed."
+
+       rm -rf $test_dir/tfile.lnk
+       rm -rf $test_dir/$tfile-2
+}
+
+test_154a() {
+       [ $PARALLEL == "yes" ] && skip "skip parallel run" && return
+       [[ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.2.51) ]] ||
+               { skip "Need MDS version at least 2.2.51"; return 0; }
+
+       cp /etc/hosts $DIR/$tfile
+
+       fid=$($LFS path2fid $DIR/$tfile)
+       rc=$?
+       [ $rc -ne 0 ] && error "error: could not get fid for $DIR/$tfile."
 
-       echo "Open-by-FID succeeded"
+       dot_lustre_fid_permission_check "$fid" $DIR ||
+               error "dot lustre permission check $fid failed"
+
+       rm -rf $MOUNT/.lustre && error ".lustre is not allowed to be unlinked"
+       chmod 777 $MOUNT/.lustre && error ".lustre is not allowed to be chmod"
+
+       touch $MOUNT/.lustre/file &&
+               error "creation is not allowed under .lustre"
+
+       mkdir $MOUNT/.lustre/dir &&
+               error "mkdir is not allowed under .lustre"
+
+       rm -rf $DIR/$tfile
+}
+run_test 154a "Open-by-FID"
+
+test_154b() {
+       [ $PARALLEL == "yes" ] && skip "skip parallel run" && return
+       [[ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.2.51) ]] ||
+               { skip "Need MDS version at least 2.2.51"; return 0; }
+
+       [ $MDSCOUNT -lt 2 ] && skip "needs >= 2 MDTs" && return
+
+       local remote_dir=$DIR/$tdir/remote_dir
+       local MDTIDX=1
+       local rc=0
+
+       mkdir -p $DIR/$tdir
+       $LFS mkdir -i $MDTIDX $remote_dir ||
+               error "create remote directory failed"
+
+       cp /etc/hosts $remote_dir/$tfile
+
+       fid=$($LFS path2fid $remote_dir/$tfile)
+       rc=$?
+       [ $rc -ne 0 ] && error "error: could not get fid for $remote_dir/$tfile"
+
+       dot_lustre_fid_permission_check "$fid" $remote_dir ||
+               error "dot lustre permission check $fid failed"
+       rm -rf $DIR/$tdir
 }
-run_test 154 "Open-by-FID"
+run_test 154b "Open-by-FID for remote directory"
 
 test_155_small_load() {
     local temp=$TMP/$tfile