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) {
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);
}
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);
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.
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));
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)
{
OBD_FREE_PTR(oqctl);
break;
}
+ case OBD_IOC_FID2PATH: {
+ rc = lov_fid2path(lov, len, karg, uarg);
+ break;
+ }
default: {
int set = 0;
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)),
RETURN(rc);
}
+ mds_idx = res.lsr_index;
CDEBUG(D_INODE, "FLD lookup got mds #%x for fid="DFID"\n",
mds_idx, PFID(fid));
#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"
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.
* - KEY_LAST_ID (obsolete)
* - KEY_FIEMAP
* - KEY_LAST_FID
+ * - KEY_FID2PATH
*
* This function reads needed data from storage and fills reply with it.
*
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);
#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>
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)
{
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",
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)
.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,
}
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"