Whamcloud - gitweb
LU-13527 utils: allow OST FID lookup via lfs fid2path 88/58988/11
authorKeguang Xu <squalfof@gmail.com>
Sun, 27 Apr 2025 07:32:00 +0000 (15:32 +0800)
committerOleg Drokin <green@whamcloud.com>
Tue, 27 May 2025 04:06:15 +0000 (04:06 +0000)
We support reverse name lookup of OST FID in addition
to MDT FID via "lfs fid2path",
- we use fld_client_lookup() to tell whether it's OST FID
or MDT FID
- for OST FID, we communicate with the OST that contains
the underlying object with the given FID, retrieve its parent
FID, i.e., the MDT FID, then continue with the MDT FID logic
- for MDT FID, previous logic was kept

NB: The ost_index obtained from fld_client_lookup() is passed
down to the lower layer via u.gf_root_fid, which was initially
taken as a non-functional field in OST context.

Signed-off-by: Keguang Xu <squalfof@gmail.com>
Change-Id: Icdf5cd7bb4693d5fef0b48f83464ca80aab81d1d
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/58988
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Lai Siyao <lai.siyao@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
lustre/fld/fld_request.c
lustre/include/lustre_fld.h
lustre/llite/file.c
lustre/lmv/lmv_fld.c
lustre/lov/lov_obd.c
lustre/lov/lov_object.c
lustre/ofd/ofd_dev.c
lustre/osc/osc_request.c
lustre/tests/sanity.sh

index 047732d..d1793bc 100644 (file)
@@ -418,41 +418,42 @@ out_req:
        return rc;
 }
 
-int fld_client_lookup(struct lu_client_fld *fld, u64 seq, u32 *mds,
-                     u32 flags, const struct lu_env *env)
+int fld_client_lookup(struct lu_client_fld *fld, u64 seq, u32 flags,
+                     const struct lu_env *env, struct lu_seq_range *res)
 {
-       struct lu_seq_range res = { 0 };
        struct lu_fld_target *target;
        struct lu_fld_target *origin;
        int rc;
 
        ENTRY;
 
-       rc = fld_cache_lookup(fld->lcf_cache, seq, &res);
-       if (rc == 0) {
-               *mds = res.lsr_index;
+       LASSERT(fld != NULL);
+       LASSERT(res != NULL);
+
+       rc = fld_cache_lookup(fld->lcf_cache, seq, res);
+       if (rc == 0)
                RETURN(0);
-       }
 
        /* Can not find it in the cache */
        target = fld_client_get_target(fld, seq);
        LASSERT(target != NULL);
        origin = target;
+
 again:
        CDEBUG(D_INFO, "%s: Lookup fld entry (seq: %#llx) on target %s (idx %llu)\n",
               fld->lcf_name, seq, fld_target_name(target), target->ft_idx);
 
-       res.lsr_start = seq;
-       fld_range_set_type(&res, flags);
+       res->lsr_start = seq;
+       fld_range_set_type(res, flags);
 
 #ifdef HAVE_SERVER_SUPPORT
        if (target->ft_srv) {
                LASSERT(env != NULL);
-               rc = fld_server_lookup(env, target->ft_srv, seq, &res);
+               rc = fld_server_lookup(env, target->ft_srv, seq, res);
        } else
 #endif /* HAVE_SERVER_SUPPORT */
        {
-               rc = fld_client_rpc(target->ft_exp, &res, FLD_QUERY, NULL);
+               rc = fld_client_rpc(target->ft_exp, res, FLD_QUERY, NULL);
        }
 
        if (rc == -ESHUTDOWN) {
@@ -479,10 +480,8 @@ again:
                if (target != origin)
                        goto again;
        }
-       if (rc == 0) {
-               *mds = res.lsr_index;
-               fld_cache_insert(fld->lcf_cache, &res);
-       }
+       if (rc == 0)
+               fld_cache_insert(fld->lcf_cache, res);
 
        RETURN(rc);
 }
index a0aa9e4..9e97d35 100644 (file)
@@ -140,8 +140,8 @@ void fld_client_fini(struct lu_client_fld *fld);
 
 void fld_client_flush(struct lu_client_fld *fld);
 
-int fld_client_lookup(struct lu_client_fld *fld, u64 seq, u32 *mds,
-                     __u32 flags, const struct lu_env *env);
+int fld_client_lookup(struct lu_client_fld *fld, u64 seq, u32 flags,
+                     const struct lu_env *env, struct lu_seq_range *res);
 
 int fld_client_create(struct lu_client_fld *fld, struct lu_seq_range *range,
                      const struct lu_env *env);
index 8e01c17..ca31e33 100644 (file)
@@ -3488,12 +3488,56 @@ lookup:
        return rc;
 }
 
+/**
+ * The FID provided could be either an MDT FID or an OST FID, both need to
+ * be handled here.
+ * 1. query from fldb-server the actual type of this FID
+ * 2a. if it's an OST-FID, try OSC_IOCONTROL(FID2PATH) with given FID, which
+ * should return the corresponding parent FID, i.e. the MDT FID
+ * 2b. otherwise it's a MDT FID already, continue to step 3
+ * 3. take the MDT FID calling MDC_IOCONTROL(FID2PATH)
+ */
 int __ll_fid2path(struct inode *inode, struct getinfo_fid2path *gfout,
                  size_t outsize, __u32 pathlen_orig)
 {
        struct obd_export *exp = ll_i2mdexp(inode);
+       struct obd_device *md_exp = ll_i2sbi(inode)->ll_md_exp->exp_obd;
+       struct lmv_obd *lmv = &md_exp->u.lmv;
+       struct lu_seq_range res = {0};
        int rc;
 
+       rc = fld_client_lookup(&lmv->lmv_fld, fid_seq(&gfout->gf_fid),
+                              LU_SEQ_RANGE_ANY, NULL, &res);
+       if (rc) {
+               CDEBUG(D_IOCTL,
+                      "%s: Error looking for target idx. Seq %#llx: rc=%d\n",
+                      md_exp->obd_name, fid_seq(&gfout->gf_fid), rc);
+               RETURN(rc);
+       }
+
+       /* Call osc_iocontrol */
+       if (res.lsr_flags == LU_SEQ_RANGE_OST) {
+               __u64 gf_recno = gfout->gf_recno;
+               __u32 gf_linkno = gfout->gf_linkno;
+               struct obd_export *dt_exp = ll_i2dtexp(inode);
+
+               /* Pass 'ost_idx' down to the lower layer via u.gf_root_fid,
+                * which is a non-functional field in the OST context
+                */
+               gfout->gf_u.gf_root_fid->f_oid = res.lsr_index;
+
+               rc = obd_iocontrol(OBD_IOC_FID2PATH, dt_exp, outsize, gfout,
+                                  NULL);
+               if (rc) {
+                       CDEBUG(D_IOCTL,
+                              "%s: Err on FID2PATH(OST), Seq %#llx: rc=%d\n",
+                              md_exp->obd_name, fid_seq(&gfout->gf_fid), rc);
+                       RETURN(rc);
+               }
+               gfout->gf_recno = gf_recno;
+               gfout->gf_linkno = gf_linkno;
+       }
+
        /* Append root FID after gfout to let MDT know the root FID so that
         * it can lookup the correct path, this is mainly for fileset.
         * old server without fileset mount support will ignore this.
index 171ab8a..aef4e8c 100644 (file)
 int lmv_fld_lookup(struct lmv_obd *lmv, const struct lu_fid *fid, u32 *mds)
 {
        struct obd_device *obd = lmv2obd_dev(lmv);
+       struct lu_seq_range res = {0};
        int rc;
 
        ENTRY;
 
-       /*
-        * FIXME: Currently ZFS still use local seq for ROOT unfortunately, and
-        * this fid_is_local check should be removed once LU-2240 is fixed
-        */
-       if (!fid_is_sane(fid) || !(fid_seq_in_fldb(fid_seq(fid)) ||
-                                  fid_seq_is_local_file(fid_seq(fid)))) {
+       if (!fid_is_sane(fid) || !fid_seq_in_fldb(fid_seq(fid))) {
                rc = -EINVAL;
                CERROR("%s: invalid FID "DFID": rc = %d\n", obd->obd_name,
                       PFID(fid), rc);
                RETURN(rc);
        }
 
-       rc = fld_client_lookup(&lmv->lmv_fld, fid_seq(fid), mds,
-                              LU_SEQ_RANGE_MDT, NULL);
+       rc = fld_client_lookup(&lmv->lmv_fld, fid_seq(fid), LU_SEQ_RANGE_MDT,
+                              NULL, &res);
        if (rc) {
                CERROR("%s: Error while looking for mds number. Seq %#llx: rc = %d\n",
                       obd->obd_name, fid_seq(fid), rc);
                RETURN(rc);
        }
 
+       *mds = res.lsr_index;
        CDEBUG(D_INODE, "FLD lookup got mds #%x for fid="DFID"\n",
               *mds, PFID(fid));
 
index b147198..acf8265 100644 (file)
@@ -909,6 +909,42 @@ out_rqset:
        RETURN(rc);
 }
 
+/**
+ * lov_fid2path() - retrieve corresponding MDT FID from given OST FID
+ * @karg: pointer to struct getinfo_fid2path{}, carrying the OST FID
+ *        as the input, and the MDT FID as the output
+ *
+ * Note: the OST index is retrieved from upper layer's u.gf_root_fid
+ */
+static int lov_fid2path(struct lov_obd *lov, int len, void *karg,
+                       void __user *uarg)
+{
+       struct lov_tgt_desc *tgt = NULL;
+       struct getinfo_fid2path *gf;
+       u32 ost_idx;
+       int rc;
+
+       gf = karg;
+       ost_idx = gf->gf_u.gf_root_fid->f_oid;
+       if (!fid_is_sane(&gf->gf_fid))
+               RETURN(-EINVAL);
+
+       tgt = lov_tgt(lov, ost_idx);
+       if (!tgt) {
+               CDEBUG(D_IOCTL, DFID" retrieve tgt failed, idx:%u\n",
+                      PFID(&gf->gf_fid), ost_idx);
+               RETURN(-EIO);
+       }
+
+       rc = obd_iocontrol(OBD_IOC_FID2PATH, tgt->ltd_exp, len, gf, uarg);
+       if (rc)
+               CDEBUG(D_IOCTL, "%s: err consult "DFID" on OST: rc=%d\n",
+                      tgt->ltd_exp->exp_obd->obd_name,
+                      PFID(&gf->gf_fid), rc);
+
+       RETURN(rc);
+}
+
 static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                         void *karg, void __user *uarg)
 {
@@ -1043,6 +1079,10 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                OBD_FREE_PTR(oqctl);
                break;
        }
+       case OBD_IOC_FID2PATH: {
+               rc = lov_fid2path(lov, len, karg, uarg);
+               break;
+       }
        default: {
                int set = 0;
 
index f147099..b80d20b 100644 (file)
@@ -426,13 +426,14 @@ static int lov_attr_get_dom(const struct lu_env *env, struct lov_object *lov,
 static int lov_fld_lookup(struct lov_device *ld, const struct lu_fid *fid,
                          __u32 *nr)
 {
+       struct lu_seq_range res = {0};
        __u32 mds_idx;
        int i, rc;
 
        ENTRY;
 
        rc = fld_client_lookup(&ld->ld_lmv->u.lmv.lmv_fld, fid_seq(fid),
-                              &mds_idx, LU_SEQ_RANGE_MDT, NULL);
+                              LU_SEQ_RANGE_MDT, NULL, &res);
        if (rc) {
                CERROR("%s: error while looking for mds number. Seq %#llx"
                       ", err = %d\n", lu_dev_name(cl2lu_dev(&ld->ld_cl)),
@@ -440,6 +441,7 @@ static int lov_fld_lookup(struct lov_device *ld, const struct lu_fid *fid,
                RETURN(rc);
        }
 
+       mds_idx = res.lsr_index;
        CDEBUG(D_INODE, "FLD lookup got mds #%x for fid="DFID"\n",
               mds_idx, PFID(fid));
 
index cd114d1..4f975ec 100644 (file)
@@ -57,6 +57,8 @@
 #include <lustre_quota.h>
 #include <lustre_nodemap.h>
 #include <lustre_log.h>
+#include <llog_swab.h>
+#include <lustre_swab.h>
 #include <linux/falloc.h>
 
 #include "ofd_internal.h"
@@ -990,6 +992,82 @@ static int lock_zero_regions(const struct lu_env *env,
        RETURN(rc);
 }
 
+/**
+ * ofd_fid2path() - load parent FID.
+ * @info: Per-thread common data shared by ost level handlers.
+ * @fp:   User-provided struct for arguments and to store MDT-FID information.
+ *
+ * Part of the OST layer implementation of lfs fid2path.
+ *
+ * Return: 0 Lookup successful,
+ *         negative errno if there was a problem
+ */
+static int ofd_fid2path(struct ofd_thread_info *info,
+                       struct getinfo_fid2path *fp)
+{
+       struct ofd_device *ofd = ofd_exp(info->fti_exp);
+       struct ofd_object *fo = NULL;
+       int rc;
+
+       ENTRY;
+
+       if (!fid_is_sane(&fp->gf_fid))
+               RETURN(-EINVAL);
+
+       if (!fid_is_namespace_visible(&fp->gf_fid)) {
+               CDEBUG(D_IOCTL,
+                      "%s: "DFID" is invalid, f_seq should be >= %#llx, or f_oid != 0, or f_ver == 0\n",
+                      ofd_name(ofd), PFID(&fp->gf_fid),
+                      (__u64)FID_SEQ_NORMAL);
+               RETURN(-EINVAL);
+       }
+
+       fo = ofd_object_find(info->fti_env, ofd, &fp->gf_fid);
+       if (IS_ERR_OR_NULL(fo)) {
+               rc = IS_ERR(fo) ? PTR_ERR(fo) : -ENOENT;
+               CDEBUG(D_IOCTL, "%s: cannot find "DFID": rc=%d\n",
+                       ofd_name(ofd), PFID(&fp->gf_fid), rc);
+               RETURN(rc);
+       }
+       if (!ofd_object_exists(fo))
+               GOTO(out, rc = -ENOENT);
+
+       rc = ofd_object_ff_load(info->fti_env, fo, false);
+       if (rc) {
+               CDEBUG(D_IOCTL, "%s: ff_load failed for "DFID": rc=%d\n",
+                       ofd_name(ofd), PFID(&fp->gf_fid), rc);
+               GOTO(out, rc);
+       }
+
+       fp->gf_fid = fo->ofo_ff.ff_parent;
+       fp->gf_fid.f_ver = 0;
+
+out:
+       if (fo)
+               ofd_object_put(info->fti_env, fo);
+
+       RETURN(rc);
+}
+
+static int ofd_rpc_fid2path(struct tgt_session_info *tsi,
+                           struct ofd_thread_info *info,
+                           void *key, int keylen,
+                           void *val, int vallen)
+{
+       struct getinfo_fid2path *fpout, *fpin;
+       int rc = 0;
+
+       fpin = key + round_up(sizeof(KEY_FID2PATH), 8);
+       fpout = val;
+
+       if (req_capsule_req_need_swab(tsi->tsi_pill))
+               lustre_swab_fid2path(fpin);
+
+       memcpy(fpout, fpin, sizeof(*fpin));
+
+       rc = ofd_fid2path(info, fpout);
+       RETURN(rc);
+}
 
 /**
  * OFD request handler for OST_GET_INFO RPC.
@@ -998,6 +1076,7 @@ static int lock_zero_regions(const struct lu_env *env,
  * - KEY_LAST_ID (obsolete)
  * - KEY_FIEMAP
  * - KEY_LAST_FID
+ * - KEY_FID2PATH
  *
  * This function reads needed data from storage and fills reply with it.
  *
@@ -1126,6 +1205,35 @@ static int ofd_get_info_hdl(struct tgt_session_info *tsi)
                       PFID(fid));
 out_put:
                ofd_seq_put(tsi->tsi_env, oseq);
+       } else if (KEY_IS(KEY_FID2PATH)) {
+               __u32 *vallen;
+               void *valout;
+
+               req_capsule_extend(tsi->tsi_pill, &RQF_MDS_FID2PATH);
+               vallen = req_capsule_client_get(tsi->tsi_pill,
+                                               &RMF_GETINFO_VALLEN);
+               if (!vallen) {
+                       CDEBUG(D_IOCTL,
+                              "%s: cannot get RMF_GETINFO_VALLEN buffer\n",
+                              tgt_name(tsi->tsi_tgt));
+                       RETURN(err_serious(-EPROTO));
+               }
+
+               req_capsule_set_size(tsi->tsi_pill, &RMF_GETINFO_VAL,
+                                    RCL_SERVER, *vallen);
+               rc = req_capsule_server_pack(tsi->tsi_pill);
+               if (rc)
+                       RETURN(err_serious(rc));
+
+               valout = req_capsule_server_get(tsi->tsi_pill,
+                                               &RMF_GETINFO_VAL);
+               if (!valout) {
+                       CDEBUG(D_IOCTL,
+                              "%s: cannot get get-info RPC out buffer\n",
+                              tgt_name(tsi->tsi_tgt));
+                       RETURN(-ENOMEM);
+               }
+               rc = ofd_rpc_fid2path(tsi, fti, key, keylen, valout, *vallen);
        } else {
                CERROR("%s: not supported key %s\n", tgt_name(tsi->tsi_tgt),
                       (char *)key);
index 736cc7c..4957c74 100644 (file)
@@ -26,6 +26,7 @@
 #include <lustre_net.h>
 #include <lustre_obdo.h>
 #include <lustre_osc.h>
+#include <lustre_swab.h>
 #include <obd.h>
 #include <obd_cksum.h>
 #include <obd_class.h>
@@ -3463,6 +3464,42 @@ out:
        return rc;
 }
 
+static int osc_ioc_fid2path(struct obd_export *exp,
+                           struct getinfo_fid2path *gf)
+{
+       __u32 keylen, vallen;
+       void *key;
+       int rc;
+
+       if (!fid_is_sane(&gf->gf_fid))
+               RETURN(-EINVAL);
+
+       /* Key is KEY_FID2PATH + getinfo_fid2path description */
+       keylen = round_up(sizeof(KEY_FID2PATH), 8) + sizeof(*gf);
+       OBD_ALLOC(key, keylen);
+       if (key == NULL)
+               RETURN(-ENOMEM);
+
+       memcpy(key, KEY_FID2PATH, sizeof(KEY_FID2PATH));
+       memcpy(key + round_up(sizeof(KEY_FID2PATH), 8), gf, sizeof(*gf));
+
+       /* Val is struct getinfo_fid2path result */
+       vallen = sizeof(*gf);
+
+       rc = obd_get_info(NULL, exp, keylen, key, &vallen, gf);
+       if (rc != 0)
+               GOTO(out, rc);
+
+       if (vallen < sizeof(*gf))
+               GOTO(out, rc = -EPROTO);
+       if (vallen > sizeof(*gf))
+               GOTO(out, rc = -EOVERFLOW);
+
+out:
+       OBD_FREE(key, keylen);
+       return rc;
+}
+
 static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                         void *karg, void __user *uarg)
 {
@@ -3493,6 +3530,9 @@ static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                if (rc > 0)
                        rc = 0;
                break;
+       case OBD_IOC_FID2PATH:
+               rc = osc_ioc_fid2path(exp, karg);
+               break;
        case OBD_IOC_GETATTR:
                if (unlikely(karg == NULL)) {
                        OBD_IOC_ERROR(obd->obd_name, cmd, "karg=NULL",
@@ -3525,6 +3565,58 @@ static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
        return rc;
 }
 
+static int osc_get_info(const struct lu_env *env, struct obd_export *exp,
+                       __u32 keylen, void *key, __u32 *vallen, void *val)
+{
+       struct obd_import *imp = class_exp2cliimp(exp);
+       struct ptlrpc_request *req;
+       int rc = -EINVAL;
+       char *tmp;
+
+       ENTRY;
+       req = ptlrpc_request_alloc(imp, &RQF_MDS_FID2PATH);
+       if (req == NULL)
+               RETURN(-ENOMEM);
+
+       req_capsule_set_size(&req->rq_pill, &RMF_GETINFO_KEY, RCL_CLIENT,
+                            keylen);
+       req_capsule_set_size(&req->rq_pill, &RMF_GETINFO_VALLEN,
+                            RCL_CLIENT, sizeof(*vallen));
+
+       rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GET_INFO);
+       if (rc != 0) {
+               ptlrpc_request_free(req);
+               RETURN(rc);
+       }
+
+       tmp = req_capsule_client_get(&req->rq_pill, &RMF_GETINFO_KEY);
+       memcpy(tmp, key, keylen);
+       tmp = req_capsule_client_get(&req->rq_pill, &RMF_GETINFO_VALLEN);
+       memcpy(tmp, vallen, sizeof(*vallen));
+
+       req_capsule_set_size(&req->rq_pill, &RMF_GETINFO_VAL,
+                            RCL_SERVER, *vallen);
+       ptlrpc_request_set_replen(req);
+
+       /* if server failed to resolve FID, and OI scrub not able to fix it, it
+        * will return -EINPROGRESS, ptlrpc_queue_wait() will keep retrying,
+        * set request interruptible to avoid deadlock.
+        */
+       if (KEY_IS(KEY_FID2PATH))
+               req->rq_allow_intr = 1;
+
+       rc = ptlrpc_queue_wait(req);
+       if (rc == 0) {
+               tmp = req_capsule_server_get(&req->rq_pill, &RMF_GETINFO_VAL);
+               memcpy(val, tmp, *vallen);
+               if (req_capsule_rep_need_swab(&req->rq_pill))
+                       lustre_swab_fid2path(val);
+       }
+       ptlrpc_req_put(req);
+
+       RETURN(rc);
+}
+
 int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
                       u32 keylen, void *key, u32 vallen, void *val,
                       struct ptlrpc_request_set *set)
@@ -4080,6 +4172,7 @@ static const struct obd_ops osc_obd_ops = {
        .o_getattr              = osc_getattr,
        .o_setattr              = osc_setattr,
        .o_iocontrol            = osc_iocontrol,
+       .o_get_info             = osc_get_info,
        .o_set_info_async       = osc_set_info_async,
        .o_import_event         = osc_import_event,
        .o_quotactl             = osc_quotactl,
index d62afb5..73d7354 100755 (executable)
@@ -18729,6 +18729,32 @@ test_154B() {
 }
 run_test 154B "verify the ll_decode_linkea tool"
 
+test_154C() {
+       (( $MDS1_VERSION >= $(version_code 2.16.54) )) ||
+               skip "need MDS1 version >= 2.16.54 for OST FID lookup"
+       (( $OSTCOUNT >= 2 )) || skip_env "needs >= 2 OSTs"
+
+       local tf=$DIR/$tfile
+       $LFS setstripe -c2 -i0 -S1M $tf
+       dd if=/dev/zero of=$tf bs=1M count=8
+
+       stack_trap "rm -rf $tf; wait_delete_completed"
+
+       local stripe_info=$($LFS getstripe $tf)
+       # for each OST object, execute fid2path
+       while read -r lfid ofid; do
+               # keep only valid lines to parse
+               [[ "$lfid" == "l_fid:" ]] || continue
+
+               found=$($LFS fid2path "$MOUNT" "$ofid")
+               echo "ost_fid=$ofid with outpath=$found"
+               [[ -n "$found" ]] ||
+                       error "fid2path failed on $ofid"
+               [[ "$found" == "$tf" ]] || error "fid2path $found != $tf"
+       done < <($LFS getstripe -y $tf)
+}
+run_test 154C "lfs fid2path on OST FID"
+
 test_154a() {
        [ $PARALLEL == "yes" ] && skip "skip parallel run"
        [ -n "$FILESET" ] && skip "SKIP due to FILESET set"