@@ -189,4 +189,11 @@ static inline bool lmv_is_known_hash_type(u32 type)
(type & LMV_HASH_TYPE_MASK) == LMV_HASH_TYPE_ALL_CHARS;
}
+static inline bool lmv_magic_supported(u32 lum_magic)
+{
+ return lum_magic == LMV_USER_MAGIC ||
+ lum_magic == LMV_USER_MAGIC_SPECIFIC ||
+ lum_magic == LMV_MAGIC_FOREIGN;
+}
+
#endif
@@ -929,7 +929,10 @@ struct obd_ops {
struct lustre_md {
struct mdt_body *body;
struct lu_buf layout;
- struct lmv_stripe_md *lmv;
+ union {
+ struct lmv_stripe_md *lmv;
+ struct lmv_foreign_md *lfm;
+ };
#ifdef CONFIG_LUSTRE_FS_POSIX_ACL
struct posix_acl *posix_acl;
#endif
@@ -346,6 +346,14 @@ static int ll_readdir(struct file *filp, struct dir_context *ctx)
rc = PTR_ERR(op_data);
goto out;
}
+
+ /* foreign dirs are browsed out of Lustre */
+ if (unlikely(op_data->op_mea1 &&
+ op_data->op_mea1->lsm_md_magic == LMV_MAGIC_FOREIGN)) {
+ ll_finish_md_op_data(op_data);
+ return -ENODATA;
+ }
+
op_data->op_fid3 = pfid;
ctx->pos = pos;
@@ -421,14 +429,22 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
};
int err;
- if (unlikely(lump->lum_magic != LMV_USER_MAGIC &&
- lump->lum_magic != LMV_USER_MAGIC_SPECIFIC))
+ if (unlikely(!lmv_magic_supported(lump->lum_magic)))
return -EINVAL;
- CDEBUG(D_VFSTRACE,
- "VFS Op:inode=" DFID "(%p) name %s stripe_offset %d, stripe_count: %u\n",
- PFID(ll_inode2fid(parent)), parent, dirname,
- (int)lump->lum_stripe_offset, lump->lum_stripe_count);
+ if (lump->lum_magic != LMV_MAGIC_FOREIGN) {
+ CDEBUG(D_VFSTRACE,
+ "VFS Op:inode=" DFID "(%p) name %s stripe_offset %d, stripe_count: %u\n",
+ PFID(ll_inode2fid(parent)), parent, dirname,
+ (int)lump->lum_stripe_offset, lump->lum_stripe_count);
+ } else {
+ struct lmv_foreign_md *lfm = (struct lmv_foreign_md *)lump;
+
+ CDEBUG(D_VFSTRACE,
+ "VFS Op:inode=" DFID "(%p) name %s foreign, length %u, value '%.*s'\n",
+ PFID(ll_inode2fid(parent)), parent, dirname,
+ lfm->lfm_length, lfm->lfm_length, lfm->lfm_value);
+ }
if (lump->lum_stripe_count > 1 &&
!(exp_connect_flags(sbi->ll_md_exp) & OBD_CONNECT_DIR_STRIPE))
@@ -438,8 +454,7 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
!OBD_FAIL_CHECK(OBD_FAIL_LLITE_NO_CHECK_DEAD))
return -ENOENT;
- if (lump->lum_magic != cpu_to_le32(LMV_USER_MAGIC) &&
- lump->lum_magic != cpu_to_le32(LMV_USER_MAGIC_SPECIFIC))
+ if (unlikely(!lmv_magic_supported(cpu_to_le32(lump->lum_magic))))
lustre_swab_lmv_user_md(lump);
if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
@@ -721,6 +736,17 @@ int ll_dir_getstripe(struct inode *inode, void **plmm, int *plmm_size,
}
}
break;
+ case LMV_MAGIC_FOREIGN: {
+ struct lmv_foreign_md *lfm = (struct lmv_foreign_md *)lmm;
+
+ if (cpu_to_le32(LMV_MAGIC_FOREIGN) != LMV_MAGIC_FOREIGN) {
+ __swab32s(&lfm->lfm_magic);
+ __swab32s(&lfm->lfm_length);
+ __swab32s(&lfm->lfm_type);
+ __swab32s(&lfm->lfm_flags);
+ }
+ break;
+ }
default:
CERROR("unknown magic: %lX\n", (unsigned long)lmm->lmm_magic);
rc = -EPROTO;
@@ -1313,9 +1339,24 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
lum = (struct lmv_user_md *)data->ioc_inlbuf2;
lumlen = data->ioc_inllen2;
- if ((lum->lum_magic != LMV_USER_MAGIC &&
- lum->lum_magic != LMV_USER_MAGIC_SPECIFIC) ||
+ if (!lmv_magic_supported(lum->lum_magic)) {
+ CERROR("%s: wrong lum magic %x : rc = %d\n", filename,
+ lum->lum_magic, -EINVAL);
+ rc = -EINVAL;
+ goto lmv_out_free;
+ }
+
+ if ((lum->lum_magic == LMV_USER_MAGIC ||
+ lum->lum_magic == LMV_USER_MAGIC_SPECIFIC) &&
lumlen < sizeof(*lum)) {
+ CERROR("%s: wrong lum size %d for magic %x : rc = %d\n",
+ filename, lumlen, lum->lum_magic, -EINVAL);
+ rc = -EINVAL;
+ goto lmv_out_free;
+ }
+
+ if (lum->lum_magic == LMV_MAGIC_FOREIGN &&
+ lumlen < sizeof(struct lmv_foreign_md)) {
CERROR("%s: wrong lum magic %x or size %d: rc = %d\n",
filename, lum->lum_magic, lumlen, -EFAULT);
rc = -EINVAL;
@@ -1447,7 +1488,25 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto finish_req;
}
- stripe_count = lmv_mds_md_stripe_count_get(lmm);
+ /* if foreign LMV case, fake stripes number */
+ if (lmm->lmv_magic == LMV_MAGIC_FOREIGN) {
+ struct lmv_foreign_md *lfm;
+
+ lfm = (struct lmv_foreign_md *)lmm;
+ if (lfm->lfm_length < XATTR_SIZE_MAX -
+ offsetof(typeof(*lfm), lfm_value)) {
+ u32 size = lfm->lfm_length +
+ offsetof(typeof(*lfm), lfm_value);
+
+ stripe_count = lmv_foreign_to_md_stripes(size);
+ } else {
+ CERROR("invalid %d foreign size returned\n",
+ lfm->lfm_length);
+ return -EINVAL;
+ }
+ } else {
+ stripe_count = lmv_mds_md_stripe_count_get(lmm);
+ }
if (max_stripe_count < stripe_count) {
lum.lum_stripe_count = stripe_count;
if (copy_to_user(ulmv, &lum, sizeof(lum))) {
@@ -1458,6 +1517,19 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto finish_req;
}
+ /* enough room on user side and foreign case */
+ if (lmm->lmv_magic == LMV_MAGIC_FOREIGN) {
+ struct lmv_foreign_md *lfm;
+ u32 size;
+
+ lfm = (struct lmv_foreign_md *)lmm;
+ size = lfm->lfm_length +
+ offsetof(struct lmv_foreign_md, lfm_value);
+ if (copy_to_user(ulmv, lfm, size))
+ rc = -EFAULT;
+ goto finish_req;
+ }
+
lum_size = lmv_user_md_size(stripe_count,
LMV_USER_MAGIC_SPECIFIC);
tmp = kzalloc(lum_size, GFP_NOFS);
@@ -4249,6 +4249,11 @@ static int ll_merge_md_attr(struct inode *inode)
int rc;
LASSERT(lli->lli_lsm_md);
+
+ /* foreign dir is not striped dir */
+ if (lli->lli_lsm_md->lsm_md_magic == LMV_MAGIC_FOREIGN)
+ return 0;
+
down_read(&lli->lli_lsm_sem);
rc = md_merge_attr(ll_i2mdexp(inode), ll_i2info(inode)->lli_lsm_md,
&attr, ll_md_blocking_ast);
@@ -1329,8 +1329,12 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
/*
* if dir layout mismatch, check whether version is increased, which
* means layout is changed, this happens in dir migration and lfsck.
+ *
+ * foreign LMV should not change.
*/
- if (lli->lli_lsm_md && !lsm_md_eq(lli->lli_lsm_md, lsm)) {
+ if (lli->lli_lsm_md &&
+ lli->lli_lsm_md->lsm_md_magic != LMV_MAGIC_FOREIGN &&
+ !lsm_md_eq(lli->lli_lsm_md, lsm)) {
if (lsm->lsm_md_layout_version <=
lli->lli_lsm_md->lsm_md_layout_version) {
CERROR("%s: " DFID " dir layout mismatch:\n",
@@ -1352,6 +1356,16 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
if (!lli->lli_lsm_md) {
struct cl_attr *attr;
+ if (lsm->lsm_md_magic == LMV_MAGIC_FOREIGN) {
+ /* set md->lmv to NULL, so the following free lustre_md
+ * will not free this lsm
+ */
+ md->lmv = NULL;
+ lli->lli_lsm_md = lsm;
+ up_write(&lli->lli_lsm_sem);
+ return 0;
+ }
+
rc = ll_init_lsm_md(inode, md);
up_write(&lli->lli_lsm_sem);
if (rc)
@@ -2297,7 +2311,7 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
rc = md_get_lustre_md(sbi->ll_md_exp, req, sbi->ll_dt_exp,
sbi->ll_md_exp, &md);
if (rc)
- goto cleanup;
+ goto out;
if (*inode) {
rc = ll_update_inode(*inode, &md);
@@ -2365,8 +2379,8 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
}
out:
+ /* cleanup will be done if necessary */
md_free_lustre_md(sbi->ll_md_exp, &md);
-cleanup:
if (rc != 0 && it && it->it_op & IT_OPEN)
ll_open_cleanup(sb ? sb : (*inode)->i_sb, req);
@@ -276,6 +276,11 @@ static int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
u64 flags = it->it_flags;
int rc;
+ /* do not allow file creation in foreign dir */
+ if ((it->it_op & IT_CREAT) && op_data->op_mea1 &&
+ op_data->op_mea1->lsm_md_magic == LMV_MAGIC_FOREIGN)
+ return -ENODATA;
+
if ((it->it_op & IT_CREAT) && !(flags & MDS_OPEN_BY_FID)) {
/* don't allow create under dir with bad hash */
if (lmv_is_dir_bad_hash(op_data->op_mea1))
@@ -426,6 +431,15 @@ static int lmv_intent_lookup(struct obd_export *exp,
struct mdt_body *body;
int rc;
+ /* foreign dir is not striped */
+ if (op_data->op_mea1 &&
+ op_data->op_mea1->lsm_md_magic == LMV_MAGIC_FOREIGN) {
+ /* only allow getattr/lookup for itself */
+ if (op_data->op_name)
+ return -ENODATA;
+ return 0;
+ }
+
retry:
tgt = lmv_locate_tgt(lmv, op_data, &op_data->op_fid1);
if (IS_ERR(tgt))
@@ -1166,15 +1166,22 @@ static int lmv_placement_policy(struct obd_device *obd,
* 2. Then check if there is default stripe offset.
* 3. Finally choose MDS by name hash if the parent
* is striped directory. (see lmv_locate_tgt()).
+ *
+ * presently explicit MDT location is not supported
+ * for foreign dirs (as it can't be embedded into free
+ * format LMV, like with lum_stripe_offset), so we only
+ * rely on default stripe offset or then name hashing.
*/
if (op_data->op_cli_flags & CLI_SET_MEA && lum &&
+ le32_to_cpu(lum->lum_magic != LMV_MAGIC_FOREIGN) &&
le32_to_cpu(lum->lum_stripe_offset) != (u32)-1) {
*mds = le32_to_cpu(lum->lum_stripe_offset);
} else if (op_data->op_default_stripe_offset != (u32)-1) {
*mds = op_data->op_default_stripe_offset;
op_data->op_mds = *mds;
/* Correct the stripe offset in lum */
- if (lum)
+ if (lum &&
+ le32_to_cpu(lum->lum_magic != LMV_MAGIC_FOREIGN))
lum->lum_stripe_offset = cpu_to_le32(*mds);
} else {
*mds = op_data->op_mds;
@@ -1606,6 +1613,10 @@ struct lmv_tgt_desc*
struct lmv_oinfo *oinfo;
struct lmv_tgt_desc *tgt;
+ /* foreign dir is not striped dir */
+ if (lsm && lsm->lsm_md_magic == LMV_MAGIC_FOREIGN)
+ return ERR_PTR(-ENODATA);
+
/*
* During creating VOLATILE file, it should honor the mdt
* index if the file under striped dir is being restored, see
@@ -2657,6 +2668,10 @@ static int lmv_read_page(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_tgt_desc *tgt;
if (unlikely(lsm)) {
+ /* foreign dir is not striped dir */
+ if (lsm->lsm_md_magic == LMV_MAGIC_FOREIGN)
+ return -ENODATA;
+
return lmv_striped_read_page(exp, op_data, cb_op,
offset, ppage);
}
@@ -2962,6 +2977,16 @@ static int lmv_unpackmd(struct obd_export *exp, struct lmv_stripe_md **lsmp,
/* Free memmd */
if (lsm && !lmm) {
int i;
+ struct lmv_foreign_md *lfm = (struct lmv_foreign_md *)lsm;
+
+ if (lfm->lfm_magic == LMV_MAGIC_FOREIGN) {
+ size_t lfm_size;
+
+ lfm_size = lfm->lfm_length + offsetof(typeof(*lfm),
+ lfm_value[0]);
+ kvfree(lfm);
+ return 0;
+ }
for (i = 0; i < lsm->lsm_md_stripe_count; i++)
iput(lsm->lsm_md_oinfo[i].lmo_root);
@@ -2971,6 +2996,25 @@ static int lmv_unpackmd(struct obd_export *exp, struct lmv_stripe_md **lsmp,
return 0;
}
+ /* foreign lmv case */
+ if (le32_to_cpu(lmm->lmv_magic) == LMV_MAGIC_FOREIGN) {
+ struct lmv_foreign_md *lfm = (struct lmv_foreign_md *)lsm;
+
+ if (!lfm) {
+ lfm = kvzalloc(lmm_size, GFP_NOFS);
+ if (!lfm)
+ return -ENOMEM;
+ *lsmp = (struct lmv_stripe_md *)lfm;
+ }
+ lfm->lfm_magic = le32_to_cpu(lmm->lmv_foreign_md.lfm_magic);
+ lfm->lfm_length = le32_to_cpu(lmm->lmv_foreign_md.lfm_length);
+ lfm->lfm_type = le32_to_cpu(lmm->lmv_foreign_md.lfm_type);
+ lfm->lfm_flags = le32_to_cpu(lmm->lmv_foreign_md.lfm_flags);
+ memcpy(&lfm->lfm_value, &lmm->lmv_foreign_md.lfm_value,
+ lfm->lfm_length);
+ return lmm_size;
+ }
+
if (le32_to_cpu(lmm->lmv_magic) == LMV_MAGIC_STRIPE)
return -EPERM;
@@ -3279,6 +3323,10 @@ static int lmv_merge_attr(struct obd_export *exp,
{
int rc, i;
+ /* foreign dir is not striped dir */
+ if (lsm->lsm_md_magic == LMV_MAGIC_FOREIGN)
+ return 0;
+
rc = lmv_revalidate_slaves(exp, lsm, cb_blocking, 0);
if (rc < 0)
return rc;
@@ -613,11 +613,18 @@ static int mdc_get_lustre_md(struct obd_export *exp,
goto out;
if (rc < (typeof(rc))sizeof(*md->lmv)) {
- CDEBUG(D_INFO,
- "size too small: rc < sizeof(*md->lmv) (%d < %d)\n",
- rc, (int)sizeof(*md->lmv));
- rc = -EPROTO;
- goto out;
+ struct lmv_foreign_md *lfm = md->lfm;
+
+ /* short (< sizeof(struct lmv_stripe_md))
+ * foreign LMV case
+ */
+ if (lfm->lfm_magic != LMV_MAGIC_FOREIGN) {
+ CDEBUG(D_INFO,
+ "size too small: rc < sizeof(*md->lmv) (%d < %d)\n",
+ rc, (int)sizeof(*md->lmv));
+ rc = -EPROTO;
+ goto out;
+ }
}
}
}
@@ -1974,8 +1974,15 @@ void lustre_swab_lmv_user_md_objects(struct lmv_user_mds_data *lmd,
void lustre_swab_lmv_user_md(struct lmv_user_md *lum)
{
- u32 count = lum->lum_stripe_count;
+ u32 count;
+ if (lum->lum_magic == LMV_MAGIC_FOREIGN) {
+ __swab32s(&lum->lum_magic);
+ __swab32s(&((struct lmv_foreign_md *)lum)->lfm_length);
+ return;
+ }
+
+ count = lum->lum_stripe_count;
__swab32s(&lum->lum_magic);
__swab32s(&lum->lum_stripe_count);
__swab32s(&lum->lum_stripe_offset);
@@ -1976,11 +1976,21 @@ struct lmv_mds_md_v1 {
struct lu_fid lmv_stripe_fids[0]; /* FIDs for each stripe */
};
+/* foreign LMV EA */
+struct lmv_foreign_md {
+ __u32 lfm_magic; /* magic number = LMV_MAGIC_FOREIGN */
+ __u32 lfm_length; /* length of lfm_value */
+ __u32 lfm_type; /* type, see LU_FOREIGN_TYPE_ */
+ __u32 lfm_flags; /* flags, type specific */
+ char lfm_value[]; /* free format value */
+};
+
#define LMV_MAGIC_V1 0x0CD20CD0 /* normal stripe lmv magic */
#define LMV_MAGIC LMV_MAGIC_V1
/* #define LMV_USER_MAGIC 0x0CD30CD0 */
#define LMV_MAGIC_STRIPE 0x0CD40CD0 /* magic for dir sub_stripe */
+#define LMV_MAGIC_FOREIGN 0x0CD50CD0 /* magic for lmv foreign */
/*
*Right now only the lower part(0-16bits) of lmv_hash_type is being used,
@@ -2025,6 +2035,7 @@ static inline __u64 lustre_hash_fnv_1a_64(const void *buf, size_t size)
__u32 lmv_magic;
struct lmv_mds_md_v1 lmv_md_v1;
struct lmv_user_md lmv_user_md;
+ struct lmv_foreign_md lmv_foreign_md;
};
static inline ssize_t lmv_mds_md_size(int stripe_count, unsigned int lmm_magic)
@@ -474,7 +474,7 @@ struct lov_user_md_v3 { /* LOV EA user data (host-endian) */
struct lov_foreign_md {
__u32 lfm_magic; /* magic number = LOV_MAGIC_FOREIGN */
__u32 lfm_length; /* length of lfm_value */
- __u32 lfm_type; /* type, see LOV_FOREIGN_TYPE_ */
+ __u32 lfm_type; /* type, see LU_FOREIGN_TYPE_ */
__u32 lfm_flags; /* flags, type specific */
char lfm_value[];
};
@@ -645,19 +645,22 @@ enum lmv_hash_type {
#define LMV_HASH_NAME_ALL_CHARS "all_char"
#define LMV_HASH_NAME_FNV_1A_64 "fnv_1a_64"
-/**
- * LOV foreign types
- **/
-#define LOV_FOREIGN_TYPE_NONE 0
-#define LOV_FOREIGN_TYPE_DAOS 0xda05
-#define LOV_FOREIGN_TYPE_UNKNOWN UINT32_MAX
-
struct lustre_foreign_type {
uint32_t lft_type;
const char *lft_name;
};
-extern struct lustre_foreign_type lov_foreign_type[];
+/**
+ * LOV/LMV foreign types
+ **/
+enum lustre_foreign_types {
+ LU_FOREIGN_TYPE_NONE = 0,
+ LU_FOREIGN_TYPE_DAOS = 0xda05,
+ /* must be the max/last one */
+ LU_FOREIGN_TYPE_UNKNOWN = 0xffffffff,
+};
+
+extern struct lustre_foreign_type lu_foreign_types[];
/*
* Got this according to how get LOV_MAX_STRIPE_COUNT, see above,
@@ -678,6 +681,16 @@ struct lmv_user_md_v1 {
struct lmv_user_mds_data lum_objects[0];
} __packed;
+static inline __u32 lmv_foreign_to_md_stripes(__u32 size)
+{
+ if (size <= sizeof(struct lmv_user_md))
+ return 0;
+
+ size -= sizeof(struct lmv_user_md);
+ return (size + sizeof(struct lmv_user_mds_data) - 1) /
+ sizeof(struct lmv_user_mds_data);
+}
+
static inline int lmv_user_md_size(int stripes, int lmm_magic)
{
int size = sizeof(struct lmv_user_md);