llapi_create_volatile_param.3 \
llapi_fd2parent.3 \
llapi_file_create.3 \
+ llapi_file_create_foreign.3 \
llapi_file_get_stripe.3 \
llapi_file_open.3 \
llapi_group_lock.3 \
[[\fB!\fR] \fB--component-start|\fB--comp-start\fR [\fB+-\fR]\fIn\fR[\fBKMGTPE\fR]]
[[\fB!\fR] \fB--gid\fR|\fB-g\fR|\fB--group\fR|\fB-G\fR <\fIgname\fR>|<\fIgid\fR>]
[[\fB!\fR] \fB--layout\fR|\fB-L mdt\fR,\fBraid0\fR,\fBreleased\fR]
+ [[\fB!\fR] \fB--foreign\fR [<\fItype\fR>]]
[\fB--maxdepth\fR|\fB-D\fI n\fR]
[[\fB!\fR] \fB--mdt\fR|\fB--mdt-index\fR|\fB-m\fR <\fIuuid\fR|\fIindex\fR,...>]
[[\fB!\fR] \fB--mdt-count\fR|\fB-T\fR [\fB+-\fR]\fIn\fR]
.BR --group | -G
File belongs to specified group, numeric group ID allowed.
.TP
-.BR --layout
+.BR --layout | -L
File has a layout of the given type, one of:
.RS 1.2i
.TP
Files that have the first data component on an MDT.
.RE
.TP
+.BR --foreign[=<type>]
+File is foreign (non-Lustre layout) and is of type if specified.
+Presently only none or daos are defined types.
+.RE
+.TP
.BR --maxdepth
Limits find to decend at most \fIn\fR levels of directory tree.
.TP
.TP
.B $ lfs find ! --mirror-state=ro /mnt/lustre
Recursively list all out-of-sync mirrored files.
+.TP
+.B $ lfs find ! --foreign=daos /mnt/lustre
+Recursively list all but foreign files of daos type.
.SH BUGS
The
.B lfs find
.B lfs setstripe --yaml=\fR<\fIyaml_template_file.lyl\fR> <\fIfile\fR>
.br
.B lfs setstripe --copy=\fR<\fIsource_template_file\fR> <\fIfile\fR>
+.br
+.B lfs setstripe --foreign[=\fR<\fIforeign_type\fR>\fB] \
+[--flags=\fR<\fIhex\fR>\fB] --xattr=\fR<\fIlayout_string\fR> <\fIfile\fR>
.SH DESCRIPTION
The
.B lfs setstripe
option but avoids the need for the intermediate
.B .lyl
file.
+.TP
+.B lfs setstripe --foreign[=\fR<\fIforeign_type\fR>\fB] \
+[--flags=\fR<\fIhex\fR>\fB] --xattr=\fR<\fIlayout_string\fR> <\fIfile\fR>
+.br
+Create a new
+.I file
+with a foreign/non-lustre layout of type
+.I foreign_type \fR(\fBnone\fR, \fBdaos\fR, ...)
+with flags
+.I hex
+and a free-format layout value of
+.I layout_string.
.SH STRIPE_OPTIONS
The various OST stripe related options are listed and explained below:
.TP
.BR pool_name=none
(since Lustre 2.11) to force a component to inherit the pool from the parent
or root directory instead of the previous component.
+.TP
+.B --foreign \fR[<\fIforeign_type\fR>]
+file layout is non-lustre/free-format and of type <
+.IR foreign_type
+>, if specified (see also
+.IR --xattr
+and
+.IR --flags
+options).
+Current known types are
+.BR none
+and
+.BR daos
+, default is
+.BR none
+.
+.B -x\fR, \fB--xattr \fR<\fIlayout_string\fR>
+Mandatory non-lustre/free-format layout/LOV EA content for
+.I foreign
+file.
+.TP
+.B -F\fR, \fB--flags \fR<\fIhex\fR>
+Optional bitmap of flags for foreign type.
.SH COMPONENT_OPTIONS
The various component related options are listed and explained below. The
.B --component-*
which can be created with the
.B lfs getstripe --yaml
command.
+.TP
+.B lfs setstripe --foreign=daos --flags=0xda08 \
+ --xattr=PUUID:CUUID /mnt/lustre/file1
+This creates foreign
+.BR file1
+of type
+.BR daos
+with non-lustre/free-format
+.BR PUUID:CUUID
+layout/LOV EA and flags
+.BR 0xda08
+.
.SH SEE ALSO
.BR lctl (1),
.BR lfs (1),
--- /dev/null
+.TH lustreapi 3 "2009 Jul 10" The Lustre user application interface library
+.SH NAME
+llapi_file_create_foreign \- create a file with foreign layout on a Lustre filesystem
+.SH SYNOPSIS
+.nf
+.B #include <sys/types.h>
+.B #include <sys/stat.h>
+.B #include <fcntl.h>
+.B #include <lustre/lustreapi.h>
+.sp
+.BI "int llapi_file_create_foreign(const char *" name ", mode_t " mode ","
+.BI " __u32 " type ", __u32 " flags ", char *" foreign_lov );
+.sp
+.fi
+.SH DESCRIPTION
+.LP
+.B llapi_file_create_foreign(\|)
+creates a file with
+.I foreign_lov
+free format layout and
+.I mode
+and
+.I name
+on a Lustre filesystem, followed by file close.
+.TP 15
+.I mode
+specifies the permission bits.
+Refer to
+.BR open(2)
+man page for a detailed description.
+.TP 15
+.I type
+specifies a type of foreign layout.
+.TP 15
+.I flags
+specifies any flags for foreign layout.
+.TP 15
+.I foreign_lov
+free-format string to be set as file layout/LOV EA.
+.SH RETURN VALUES
+.LP
+.B llapi_file_create_foreign(\|)
+return:
+.TP
+>=0
+on success, for
+.B llapi_file_open
+the return value is a file descriptor.
+.TP
+<0
+on failure, the absolute value is an error code.
+.SH ERRORS
+.TP 15
+.SM EEXIST
+.I name
+already exists.
+.TP
+.SM ENOTTY
+.I name
+may not point to a Lustre filesystem.
+.SH "EXAMPLE"
+.nf
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <lustre/lustreapi.h>
+int main(int argc, char *argv[])
+{
+ int rc;
+
+ if (argc != 2)
+ return -1;
+
+ rc = llapi_file_create_foreign(argv[1], 0600, LOV_FOREIGN_TYPE_DAOS,
+ 0xda08, "PUUID@CUUID");
+ if (rc < 0) {
+ fprintf(stderr, "file creation has failed, %s\\n", strerror(-rc));
+ return -1;
+ }
+ printf("foreign file %s has been created with 'PUUID@CUUID' layout!\\n",
+ argv[1]);
+ return 0;
+}
+.fi
+.SH "SEE ALSO"
+.BR llapi_file_open (3)
+.BR lustre (7),
+.BR lustreapi (7)
+.BR open (2),
int llapi_file_open_param(const char *name, int flags, mode_t mode,
const struct llapi_stripe_param *param);
+int llapi_file_create_foreign(const char *name, mode_t mode, __u32 type,
+ __u32 flags, char *foreign_lov);
int llapi_file_create(const char *name, unsigned long long stripe_size,
int stripe_offset, int stripe_count, int stripe_pattern);
int llapi_file_open(const char *name, int flags, int mode,
fp_exclude_hash_type:1,
fp_yaml:1, /* output layout in YAML */
fp_check_blocks:1,
- fp_exclude_blocks:1;
+ fp_exclude_blocks:1,
+ fp_check_foreign:1,
+ fp_exclude_foreign:1;
enum llapi_layout_verbose fp_verbose;
int fp_quiet;
unsigned int fp_depth;
unsigned int fp_hash_type;
unsigned int fp_time_margin; /* time margin in seconds */
+ __u32 fp_foreign_type;
};
int llapi_ostlist(char *path, struct find_param *param);
#define LOV_MAGIC_SPECIFIC (0x0BD50000 | LOV_MAGIC_MAGIC)
#define LOV_MAGIC LOV_MAGIC_V1
#define LOV_MAGIC_COMP_V1 (0x0BD60000 | LOV_MAGIC_MAGIC)
+#define LOV_MAGIC_FOREIGN (0x0BD70000 | LOV_MAGIC_MAGIC)
/*
* magic for fully defined striping
# include <limits.h>
# include <stdbool.h>
# include <stdio.h> /* snprintf() */
+# include <stdint.h>
# include <string.h>
# define NEED_QUOTA_DEFS
/* # include <sys/quota.h> - this causes complaints about caddr_t */
/* 0x0BD40BD0 is occupied by LOV_MAGIC_MIGRATE */
#define LOV_USER_MAGIC_SPECIFIC 0x0BD50BD0 /* for specific OSTs */
#define LOV_USER_MAGIC_COMP_V1 0x0BD60BD0
+#define LOV_USER_MAGIC_FOREIGN 0x0BD70BD0
#define LMV_USER_MAGIC 0x0CD30CD0 /* default lmv magic */
#define LMV_USER_MAGIC_V0 0x0CD20CD0 /* old default lmv magic*/
struct lov_user_ost_data_v1 lmm_objects[0]; /* per-stripe data */
} __attribute__((packed));
+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_flags; /* flags, type specific */
+ char lfm_value[];
+};
+
+#define foreign_size(lfm) (((struct lov_foreign_md *)lfm)->lfm_length + \
+ offsetof(struct lov_foreign_md, lfm_value))
+
+#define foreign_size_le(lfm) \
+ (le32_to_cpu(((struct lov_foreign_md *)lfm)->lfm_length) + \
+ offsetof(struct lov_foreign_md, lfm_value))
+
struct lu_extent {
__u64 e_start;
__u64 e_end;
extern char *mdt_hash_name[LMV_HASH_TYPE_MAX];
+/**
+ * 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[];
+
/* Got this according to how get LOV_MAX_STRIPE_COUNT, see above,
* (max buffer size - lmv+rpc header) / sizeof(struct lmv_user_mds_data) */
#define LMV_MAX_STRIPE_COUNT 2000 /* ((12 * 4096 - 256) / 24) */
return 0;
}
+static int lfsck_layout_verify_header_foreign(struct dt_object *obj,
+ struct lov_foreign_md *lfm,
+ size_t len)
+{
+ /* magic has been verified already */
+ __u32 value_len = le32_to_cpu(lfm->lfm_length);
+ /* type and flags are not checked for instance */
+
+ CDEBUG(D_INFO, "foreign LOV EA, magic %x, len %u, type %x, flags %x, for file "DFID"\n",
+ le32_to_cpu(lfm->lfm_magic), value_len,
+ le32_to_cpu(lfm->lfm_type), le32_to_cpu(lfm->lfm_flags),
+ PFID(lfsck_dto2fid(obj)));
+
+ if (len != value_len + offsetof(typeof(*lfm), lfm_value))
+ CDEBUG(D_LFSCK, "foreign LOV EA internal size %u does not match EA full size %zu for file "DFID"\n",
+ value_len, len, PFID(lfsck_dto2fid(obj)));
+
+ /* nothing to repair */
+ return -ENODATA;
+}
+
static int lfsck_layout_verify_header(struct dt_object *obj,
- struct lov_mds_md_v1 *lmm)
+ struct lov_mds_md_v1 *lmm, size_t len)
{
int rc = 0;
le32_to_cpu(lcme->lcme_offset)), start,
comp_id);
}
+ } else if (le32_to_cpu(lmm->lmm_magic) == LOV_MAGIC_FOREIGN) {
+ rc = lfsck_layout_verify_header_foreign(obj,
+ (struct lov_foreign_md *)lmm,
+ len);
} else {
rc = lfsck_layout_verify_header_v1v3(obj, lmm, 1, 0);
}
goto again;
}
- rc1 = lfsck_layout_verify_header(obj, buf->lb_buf);
+ rc1 = lfsck_layout_verify_header(obj, buf->lb_buf, rc);
return rc1 ? rc1 : rc;
}
}
lmm = buf->lb_buf;
- rc1 = lfsck_layout_verify_header(parent, lmm);
+ rc1 = lfsck_layout_verify_header(parent, lmm, lovea_size);
/* If the LOV EA crashed, the rebuild it. */
if (rc1 == -EINVAL) {
if (lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V1) &&
lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V3) &&
- lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_COMP_V1))
+ lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_COMP_V1) &&
+ lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_FOREIGN))
GOTO(out, rc = -EPROTO);
/*
cpu_to_le32(LOV_MAGIC_COMP_V1)) {
lustre_swab_lov_comp_md_v1(
(struct lov_comp_md_v1 *)lmm);
+ } else if (lmm->lmm_magic ==
+ cpu_to_le32(LOV_MAGIC_FOREIGN)) {
+ struct lov_foreign_md *lfm;
+
+ lfm = (struct lov_foreign_md *)lmm;
+ __swab32s(&lfm->lfm_magic);
+ __swab32s(&lfm->lfm_length);
+ __swab32s(&lfm->lfm_type);
+ __swab32s(&lfm->lfm_flags);
}
}
LOV_USER_MAGIC_SPECIFIC);
case LOV_USER_MAGIC_COMP_V1:
return ((struct lov_comp_md_v1 *)lum)->lcm_size;
+ case LOV_USER_MAGIC_FOREIGN:
+ return foreign_size(lum);
}
return -EINVAL;
};
struct lu_env *env;
u16 refcheck;
+ u32 magic;
if (!obj)
RETURN(-ENODATA);
* recognizing layout gen as stripe offset when the
* file is restored. See LU-2809.
*/
- if (((struct lov_mds_md *)buf)->lmm_magic == LOV_MAGIC_COMP_V1)
+ magic = ((struct lov_mds_md *)buf)->lmm_magic;
+ if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_FOREIGN)
goto out_env;
((struct lov_mds_md *)buf)->lmm_layout_gen = 0;
.cl_buf.lb_len = buf_size,
};
__u16 refcheck;
+ __u32 magic;
if (obj == NULL)
RETURN(-ENODATA);
* otherwise it would confuse tar --xattr by
* recognizing layout gen as stripe offset when the
* file is restored. See LU-2809. */
- if (((struct lov_mds_md *)buf)->lmm_magic == LOV_MAGIC_COMP_V1)
+ magic = ((struct lov_mds_md *)buf)->lmm_magic;
+ if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_FOREIGN)
goto out_env;
((struct lov_mds_md *)buf)->lmm_layout_gen = 0;
struct lod_mirror_entry *ldo_mirrors;
__u32 ldo_is_composite:1,
ldo_flr_state:2,
- ldo_comp_cached:1;
+ ldo_comp_cached:1,
+ ldo_is_foreign:1;
};
/* directory stripe (LMV) */
struct {
struct lod_default_striping *ldo_def_striping;
};
};
- /* file stripe (LOV) */
- struct lod_layout_component *ldo_comp_entries;
- /* slave stripes of striped directory (LMV) */
- struct dt_object **ldo_stripe;
+ union {
+ struct {
+ /* foreign/raw format LOV */
+ char *ldo_foreign_lov;
+ size_t ldo_foreign_lov_size;
+ };
+ struct {
+ /* file stripe (LOV) */
+ struct lod_layout_component *ldo_comp_entries;
+ /* slave stripes of striped directory (LMV) */
+ struct dt_object **ldo_stripe;
+ };
+ };
};
#define lod_foreach_mirror_comp(comp, lo, mirror_idx) \
if (S_ISDIR(dt->do_lu.lo_header->loh_attr))
return lo->ldo_dir_stripe_count != 0;
+ if (lo->ldo_is_foreign)
+ return false;
+
for (i = 0; i < lo->ldo_comp_cnt; i++) {
if (lo->ldo_comp_entries[i].llc_stripe == NULL)
continue;
int lod_striped_create(const struct lu_env *env, struct dt_object *dt,
struct lu_attr *attr, struct dt_object_format *dof,
struct thandle *th);
+int lod_alloc_foreign_lov(struct lod_object *lo, size_t size);
+void lod_free_foreign_lov(struct lod_object *lo);
void lod_striping_free_nolock(const struct lu_env *env, struct lod_object *lo);
void lod_striping_free(const struct lu_env *env, struct lod_object *lo);
struct lov_comp_md_v1 *lcm;
struct lod_layout_component *comp_entries;
__u16 comp_cnt, mirror_cnt;
- bool is_composite;
+ bool is_composite, is_foreign = false;
int i, rc = 0, offset;
ENTRY;
mirror_cnt = lo->ldo_mirror_count;
comp_entries = lo->ldo_comp_entries;
is_composite = lo->ldo_is_composite;
+ is_foreign = lo->ldo_is_foreign;
}
LASSERT(lmm_size != NULL);
+
+ if (is_foreign) {
+ struct lov_foreign_md *lfm;
+
+ lfm = (struct lov_foreign_md *)lmm;
+ memcpy(lfm, lo->ldo_foreign_lov, lo->ldo_foreign_lov_size);
+ /* need to store little-endian */
+ if (cpu_to_le32(LOV_MAGIC_FOREIGN) != LOV_MAGIC_FOREIGN) {
+ __swab32s(&lfm->lfm_magic);
+ __swab32s(&lfm->lfm_length);
+ __swab32s(&lfm->lfm_type);
+ __swab32s(&lfm->lfm_flags);
+ }
+ *lmm_size = lo->ldo_foreign_lov_size;
+ RETURN(0);
+ }
+
LASSERT(comp_cnt != 0 && comp_entries != NULL);
if (!is_composite) {
{
struct lov_mds_md_v1 *lmm;
struct lov_comp_md_v1 *comp_v1 = NULL;
+ struct lov_foreign_md *foreign = NULL;
struct lov_ost_data_v1 *objs;
__u32 magic, pattern;
int i, j, rc = 0;
magic = le32_to_cpu(lmm->lmm_magic);
if (magic != LOV_MAGIC_V1 && magic != LOV_MAGIC_V3 &&
- magic != LOV_MAGIC_COMP_V1)
+ magic != LOV_MAGIC_COMP_V1 && magic != LOV_MAGIC_FOREIGN)
GOTO(out, rc = -EINVAL);
- lod_free_comp_entries(lo);
+ if (lo->ldo_is_foreign)
+ lod_free_foreign_lov(lo);
+ else
+ lod_free_comp_entries(lo);
if (magic == LOV_MAGIC_COMP_V1) {
comp_v1 = (struct lov_comp_md_v1 *)lmm;
lo->ldo_flr_state = le16_to_cpu(comp_v1->lcm_flags) &
LCM_FL_FLR_MASK;
mirror_cnt = le16_to_cpu(comp_v1->lcm_mirror_count) + 1;
+ } else if (magic == LOV_MAGIC_FOREIGN) {
+ size_t length;
+
+ foreign = (struct lov_foreign_md *)buf->lb_buf;
+ length = offsetof(typeof(*foreign), lfm_value);
+ if (buf->lb_len < length ||
+ buf->lb_len < (length + le32_to_cpu(foreign->lfm_length))) {
+ CDEBUG(D_LAYOUT,
+ "buf len %zu too small for lov_foreign_md\n",
+ buf->lb_len);
+ GOTO(out, rc = -EINVAL);
+ }
+
+ /* just cache foreign LOV EA raw */
+ rc = lod_alloc_foreign_lov(lo, length);
+ if (rc)
+ GOTO(out, rc);
+ memcpy(lo->ldo_foreign_lov, buf->lb_buf, length);
+ GOTO(out, rc);
} else {
comp_cnt = 1;
lo->ldo_layout_gen = le16_to_cpu(lmm->lmm_layout_gen);
int rc = 0;
ENTRY;
+ if (buf->lb_len < sizeof(lum->lmm_magic)) {
+ CDEBUG(D_LAYOUT, "invalid buf len %zu\n", buf->lb_len);
+ RETURN(-EINVAL);
+ }
+
lum = buf->lb_buf;
+ magic = le32_to_cpu(lum->lmm_magic) & ~LOV_MAGIC_DEFINED;
+ /* treat foreign LOV EA/object case first
+ * XXX is it expected to try setting again a foreign?
+ * XXX should we care about different current vs new layouts ?
+ */
+ if (unlikely(magic == LOV_USER_MAGIC_FOREIGN)) {
+ struct lov_foreign_md *lfm = buf->lb_buf;
+
+ if (buf->lb_len < offsetof(typeof(*lfm), lfm_value)) {
+ CDEBUG(D_LAYOUT,
+ "buf len %zu < min lov_foreign_md size (%zu)\n",
+ buf->lb_len, offsetof(typeof(*lfm),
+ lfm_value));
+ RETURN(-EINVAL);
+ }
+
+ if (foreign_size_le(lfm) > buf->lb_len) {
+ CDEBUG(D_LAYOUT,
+ "buf len %zu < this lov_foreign_md size (%zu)\n",
+ buf->lb_len, foreign_size_le(lfm));
+ RETURN(-EINVAL);
+ }
+ /* Don't do anything with foreign layouts */
+ RETURN(0);
+ }
+
+ /* normal LOV/layout cases */
+
if (buf->lb_len < sizeof(*lum)) {
CDEBUG(D_LAYOUT, "buf len %zu too small for lov_user_md\n",
buf->lb_len);
RETURN(-EINVAL);
}
- magic = le32_to_cpu(lum->lmm_magic) & ~LOV_MAGIC_DEFINED;
if (magic != LOV_USER_MAGIC_V1 &&
magic != LOV_USER_MAGIC_V3 &&
magic != LOV_USER_MAGIC_SPECIFIC &&
int magic, size = 0, i;
struct lod_layout_component *comp_entries;
__u16 comp_cnt;
- bool is_composite;
+ bool is_composite, is_foreign = false;
if (is_dir) {
comp_cnt = lo->ldo_def_striping->lds_def_comp_cnt;
comp_cnt = lo->ldo_comp_cnt;
comp_entries = lo->ldo_comp_entries;
is_composite = lo->ldo_is_composite;
+ is_foreign = lo->ldo_is_foreign;
}
+ if (is_foreign)
+ return lo->ldo_foreign_lov_size;
LASSERT(comp_cnt != 0 && comp_entries != NULL);
if (is_composite) {
LASSERT(lo);
- if (lo->ldo_comp_cnt == 0) {
+ if (lo->ldo_comp_cnt == 0 && !lo->ldo_is_foreign) {
lod_striping_free(env, lo);
rc = lod_sub_xattr_del(env, next, XATTR_NAME_LOV, th);
RETURN(rc);
int rc = 0, i, j;
ENTRY;
- LASSERT(lo->ldo_comp_cnt != 0 && lo->ldo_comp_entries != NULL);
+ LASSERT((lo->ldo_comp_cnt != 0 && lo->ldo_comp_entries != NULL) ||
+ lo->ldo_is_foreign);
mirror_id = 0; /* non-flr file's mirror_id is 0 */
if (lo->ldo_mirror_count > 1) {
/**
*
+ * Alloc cached foreign LOV
+ *
+ * \param[in] lo object
+ * \param[in] size size of foreign LOV
+ *
+ * \retval 0 on success
+ * \retval negative if failed
+ */
+int lod_alloc_foreign_lov(struct lod_object *lo, size_t size)
+{
+ OBD_ALLOC_LARGE(lo->ldo_foreign_lov, size);
+ if (lo->ldo_foreign_lov == NULL)
+ return -ENOMEM;
+ lo->ldo_foreign_lov_size = size;
+ lo->ldo_is_foreign = 1;
+ return 0;
+}
+
+/**
+ *
+ * Free cached foreign LOV
+ *
+ * \param[in] lo object
+ */
+void lod_free_foreign_lov(struct lod_object *lo)
+{
+ if (lo->ldo_foreign_lov != NULL)
+ OBD_FREE_LARGE(lo->ldo_foreign_lov, lo->ldo_foreign_lov_size);
+ lo->ldo_foreign_lov = NULL;
+ lo->ldo_foreign_lov_size = 0;
+ lo->ldo_is_foreign = 0;
+}
+
+/**
+ *
* Release resources associated with striping.
*
* If the object is striped (regular or directory), then release
struct lod_layout_component *lod_comp;
int i, j;
- if (lo->ldo_stripe != NULL) {
+ if (unlikely(lo->ldo_is_foreign)) {
+ lod_free_foreign_lov(lo);
+ lo->ldo_comp_cached = 0;
+ } else if (lo->ldo_stripe != NULL) {
LASSERT(lo->ldo_comp_entries == NULL);
LASSERT(lo->ldo_dir_stripes_allocated > 0);
magic = le32_to_cpu(v1->lmm_magic) & ~LOV_MAGIC_DEFINED;
if (magic != LOV_MAGIC_V1 && magic != LOV_MAGIC_V3 &&
- magic != LOV_MAGIC_COMP_V1)
+ magic != LOV_MAGIC_COMP_V1 && magic != LOV_MAGIC_FOREIGN)
GOTO(unlock, rc = -EINVAL);
if (magic == LOV_MAGIC_COMP_V1) {
mo->ldo_flr_state = le16_to_cpu(comp_v1->lcm_flags) &
LCM_FL_FLR_MASK;
mo->ldo_is_composite = 1;
+ } else if (magic == LOV_MAGIC_FOREIGN) {
+ struct lov_foreign_md *foreign;
+ size_t length;
+
+ if (buf->lb_len < offsetof(typeof(*foreign), lfm_value)) {
+ CDEBUG(D_LAYOUT,
+ "buf len %zu < min lov_foreign_md size (%zu)\n",
+ buf->lb_len,
+ offsetof(typeof(*foreign), lfm_value));
+ GOTO(out, rc = -EINVAL);
+ }
+ foreign = (struct lov_foreign_md *)buf->lb_buf;
+ length = foreign_size_le(foreign);
+ if (buf->lb_len < length) {
+ CDEBUG(D_LAYOUT,
+ "buf len %zu < this lov_foreign_md size (%zu)\n",
+ buf->lb_len, length);
+ GOTO(out, rc = -EINVAL);
+ }
+
+ /* just cache foreign LOV EA raw */
+ rc = lod_alloc_foreign_lov(mo, length);
+ if (rc)
+ GOTO(out, rc);
+ memcpy(mo->ldo_foreign_lov, buf->lb_buf, length);
+ GOTO(out, rc);
} else {
mo->ldo_is_composite = 0;
comp_cnt = 1;
const struct lu_buf *buf)
{
struct lod_layout_component *lod_comp;
- struct lod_device *d = lu2lod_dev(lod2lu_obj(lo)->lo_dev);
- struct lov_desc *desc = &d->lod_desc;
- struct lov_user_md_v1 *v1 = NULL;
- struct lov_user_md_v3 *v3 = NULL;
- struct lov_comp_md_v1 *comp_v1 = NULL;
- char def_pool[LOV_MAXPOOLNAME + 1];
- __u32 magic;
- __u16 comp_cnt;
- __u16 mirror_cnt;
- int i, rc;
+ struct lod_device *d = lu2lod_dev(lod2lu_obj(lo)->lo_dev);
+ struct lov_desc *desc = &d->lod_desc;
+ struct lov_user_md_v1 *v1 = NULL;
+ struct lov_user_md_v3 *v3 = NULL;
+ struct lov_comp_md_v1 *comp_v1 = NULL;
+ struct lov_foreign_md *lfm = NULL;
+ char def_pool[LOV_MAXPOOLNAME + 1];
+ __u32 magic;
+ __u16 comp_cnt;
+ __u16 mirror_cnt;
+ int i, rc;
ENTRY;
if (buf == NULL || buf->lb_buf == NULL || buf->lb_len == 0)
def_pool, sizeof(def_pool));
/* free default striping info */
- lod_free_comp_entries(lo);
+ if (lo->ldo_is_foreign)
+ lod_free_foreign_lov(lo);
+ else
+ lod_free_comp_entries(lo);
rc = lod_verify_striping(d, lo, buf, false);
if (rc)
v3 = buf->lb_buf;
v1 = buf->lb_buf;
comp_v1 = buf->lb_buf;
+ /* {lmm,lfm}_magic position/length work for all LOV formats */
magic = v1->lmm_magic;
if (unlikely(le32_to_cpu(magic) & LOV_MAGIC_DEFINED)) {
/* fall trhough */
case LOV_USER_MAGIC_COMP_V1:
break;
+ case __swab32(LOV_USER_MAGIC_FOREIGN):
+ lfm = buf->lb_buf;
+ __swab32s(&lfm->lfm_magic);
+ __swab32s(&lfm->lfm_length);
+ __swab32s(&lfm->lfm_type);
+ __swab32s(&lfm->lfm_flags);
+ magic = lfm->lfm_magic;
+ /* fall through */
+ case LOV_USER_MAGIC_FOREIGN:
+ if (!lfm)
+ lfm = buf->lb_buf;
+ rc = lod_alloc_foreign_lov(lo, foreign_size(lfm));
+ if (rc)
+ RETURN(rc);
+ memcpy(lo->ldo_foreign_lov, buf->lb_buf, foreign_size(lfm));
+ RETURN(0);
default:
CERROR("%s: unrecognized magic %X\n",
lod2obd(d)->obd_name, magic);
LLT_EMPTY, /** empty file without body (mknod + truncate) */
LLT_RELEASED, /** file with no objects (data in HSM) */
LLT_COMP, /** support composite layout */
+ LLT_FOREIGN, /** foreign layout */
LLT_NR
};
return "RELEASED";
case LLT_COMP:
return "COMPOSITE";
+ case LLT_FOREIGN:
+ return "FOREIGN";
case LLT_NR:
LBUG();
}
struct cl_page *page, pgoff_t index);
int lov_page_init_composite(const struct lu_env *env, struct cl_object *obj,
struct cl_page *page, pgoff_t index);
+int lov_page_init_foreign(const struct lu_env *env, struct cl_object *obj,
+ struct cl_page *page, pgoff_t index);
struct lu_object *lov_object_alloc (const struct lu_env *env,
const struct lu_object_header *hdr,
struct lu_device *dev);
+
struct lu_object *lovsub_object_alloc(const struct lu_env *env,
const struct lu_object_header *hdr,
struct lu_device *dev);
unsigned int i;
size_t lsm_size;
- for (i = 0; i < entry_count; i++)
- lsme_free(lsm->lsm_entries[i]);
+ if (lsm->lsm_magic == LOV_MAGIC_FOREIGN) {
+ OBD_FREE_LARGE(lsm_foreign(lsm), lsm->lsm_foreign_size);
+ } else {
+ for (i = 0; i < entry_count; i++)
+ lsme_free(lsm->lsm_entries[i]);
+ }
- lsm_size = offsetof(typeof(*lsm), lsm_entries[entry_count]);
+ lsm_size = lsm->lsm_magic == LOV_MAGIC_FOREIGN ?
+ offsetof(typeof(*lsm), lsm_entries[1]) :
+ offsetof(typeof(*lsm), lsm_entries[entry_count]);
OBD_FREE(lsm, lsm_size);
}
.lsm_unpackmd = lsm_unpackmd_comp_md_v1,
};
+static struct
+lov_stripe_md *lsm_unpackmd_foreign(struct lov_obd *lov, void *buf,
+ size_t buf_size)
+{
+ struct lov_foreign_md *lfm = buf;
+ struct lov_stripe_md *lsm;
+ size_t lsm_size;
+ struct lov_stripe_md_entry *lsme;
+
+ lsm_size = offsetof(typeof(*lsm), lsm_entries[1]);
+ OBD_ALLOC(lsm, lsm_size);
+ if (lsm == NULL)
+ RETURN(ERR_PTR(-ENOMEM));
+
+ atomic_set(&lsm->lsm_refc, 1);
+ spin_lock_init(&lsm->lsm_lock);
+ lsm->lsm_magic = le32_to_cpu(lfm->lfm_magic);
+ lsm->lsm_foreign_size = foreign_size_le(lfm);
+
+ /* alloc for full foreign EA including format fields */
+ OBD_ALLOC_LARGE(lsme, lsm->lsm_foreign_size);
+ if (lsme == NULL) {
+ OBD_FREE(lsm, lsm_size);
+ RETURN(ERR_PTR(-ENOMEM));
+ }
+
+ /* copy full foreign EA including format fields */
+ memcpy(lsme, buf, lsm->lsm_foreign_size);
+
+ lsm_foreign(lsm) = lsme;
+
+ return lsm;
+}
+
+const struct lsm_operations lsm_foreign_ops = {
+ .lsm_unpackmd = lsm_unpackmd_foreign,
+};
+
void dump_lsm(unsigned int level, const struct lov_stripe_md *lsm)
{
int i, j;
- CDEBUG(level, "lsm %p, objid "DOSTID", maxbytes %#llx, magic 0x%08X, "
- "refc: %d, entry: %u, layout_gen %u\n",
+ CDEBUG_LIMIT(level,
+ "lsm %p, objid "DOSTID", maxbytes %#llx, magic 0x%08X, refc: %d, entry: %u, layout_gen %u\n",
lsm, POSTID(&lsm->lsm_oi), lsm->lsm_maxbytes, lsm->lsm_magic,
atomic_read(&lsm->lsm_refc), lsm->lsm_entry_count,
lsm->lsm_layout_gen);
+ if (lsm->lsm_magic == LOV_MAGIC_FOREIGN) {
+ struct lov_foreign_md *lfm = (void *)lsm_foreign(lsm);
+
+ CDEBUG_LIMIT(level,
+ "foreign LOV EA, magic %x, length %u, type %x, flags %x, value '%.*s'\n",
+ lfm->lfm_magic, lfm->lfm_length, lfm->lfm_type,
+ lfm->lfm_flags, lfm->lfm_length, lfm->lfm_value);
+ return;
+ }
+
for (i = 0; i < lsm->lsm_entry_count; i++) {
struct lov_stripe_md_entry *lse = lsm->lsm_entries[i];
spinlock_t lsm_lock;
pid_t lsm_lock_owner; /* debugging */
- /* maximum possible file size, might change as OSTs status changes,
- * e.g. disconnected, deactivated */
- loff_t lsm_maxbytes;
+ union {
+ /* maximum possible file size, might change as OSTs status
+ * changes, e.g. disconnected, deactivated
+ */
+ loff_t lsm_maxbytes;
+ /* size of full foreign LOV */
+ size_t lsm_foreign_size;
+ };
struct ost_id lsm_oi;
u32 lsm_magic;
u32 lsm_layout_gen;
struct lov_stripe_md_entry *lsm_entries[];
};
+#define lsm_foreign(lsm) (lsm->lsm_entries[0])
+
static inline bool lsme_inited(const struct lov_stripe_md_entry *lsme)
{
return lsme->lsme_flags & LCME_FL_INIT;
return lov_mds_md_size(lsm->lsm_entries[0]->lsme_stripe_count,
lsm->lsm_entries[0]->lsme_magic);
+ if (lsm->lsm_magic == LOV_MAGIC_FOREIGN)
+ return lsm->lsm_foreign_size;
+
LASSERT(lsm->lsm_magic == LOV_MAGIC_COMP_V1);
size = sizeof(struct lov_comp_md_v1);
extern const struct lsm_operations lsm_v1_ops;
extern const struct lsm_operations lsm_v3_ops;
extern const struct lsm_operations lsm_comp_md_v1_ops;
+extern const struct lsm_operations lsm_foreign_ops;
static inline const struct lsm_operations *lsm_op_find(int magic)
{
switch (magic) {
return &lsm_v3_ops;
case LOV_MAGIC_COMP_V1:
return &lsm_comp_md_v1_ops;
+ case LOV_MAGIC_FOREIGN:
+ return &lsm_foreign_ops;
default:
CERROR("unrecognized lsm_magic %08x\n", magic);
return NULL;
return 0;
}
+static int lov_init_foreign(const struct lu_env *env,
+ struct lov_device *dev, struct lov_object *lov,
+ struct lov_stripe_md *lsm,
+ const struct cl_object_conf *conf,
+ union lov_layout_state *state)
+{
+ LASSERT(lsm != NULL);
+ LASSERT(lov->lo_type == LLT_FOREIGN);
+ LASSERT(lov->lo_lsm == NULL);
+
+ lov->lo_lsm = lsm_addref(lsm);
+ return 0;
+}
+
static int lov_delete_empty(const struct lu_env *env, struct lov_object *lov,
union lov_layout_state *state)
{
- LASSERT(lov->lo_type == LLT_EMPTY || lov->lo_type == LLT_RELEASED);
+ LASSERT(lov->lo_type == LLT_EMPTY || lov->lo_type == LLT_RELEASED ||
+ lov->lo_type == LLT_FOREIGN);
lov_layout_wait(env, lov);
return 0;
return 0;
}
+static int lov_print_foreign(const struct lu_env *env, void *cookie,
+ lu_printer_t p, const struct lu_object *o)
+{
+ struct lov_object *lov = lu2lov(o);
+ struct lov_stripe_md *lsm = lov->lo_lsm;
+
+ (*p)(env, cookie,
+ "foreign: %s, lsm{%p 0x%08X %d %u}:\n",
+ lov->lo_layout_invalid ? "invalid" : "valid", lsm,
+ lsm->lsm_magic, atomic_read(&lsm->lsm_refc),
+ lsm->lsm_layout_gen);
+ (*p)(env, cookie,
+ "raw_ea_content '%.*s'\n",
+ (int)lsm->lsm_foreign_size, (char *)lsm_foreign(lsm));
+ return 0;
+}
+
/**
* Implements cl_object_operations::coo_attr_get() method for an object
* without stripes (LLT_EMPTY layout type).
.llo_io_init = lov_io_init_composite,
.llo_getattr = lov_attr_get_composite,
},
+ [LLT_FOREIGN] = {
+ .llo_init = lov_init_foreign,
+ .llo_delete = lov_delete_empty,
+ .llo_fini = lov_fini_released,
+ .llo_print = lov_print_foreign,
+ .llo_page_init = lov_page_init_foreign,
+ .llo_lock_init = lov_lock_init_empty,
+ .llo_io_init = lov_io_init_empty,
+ .llo_getattr = lov_attr_get_empty,
+ },
};
/**
lsm->lsm_magic == LOV_MAGIC_COMP_V1)
return LLT_COMP;
+ if (lsm->lsm_magic == LOV_MAGIC_FOREIGN)
+ return LLT_FOREIGN;
+
return LLT_EMPTY;
}
}
case LLT_RELEASED:
case LLT_EMPTY:
+ /* fall through */
+ case LLT_FOREIGN:
break;
default:
LBUG();
RETURN(lmm_size);
}
+ssize_t lov_lsm_pack_foreign(const struct lov_stripe_md *lsm, void *buf,
+ size_t buf_size)
+{
+ struct lov_foreign_md *lfm = buf;
+ size_t lfm_size;
+
+ lfm_size = lsm->lsm_foreign_size;
+
+ if (buf_size == 0)
+ RETURN(lfm_size);
+
+ if (buf_size < lfm_size)
+ RETURN(-ERANGE);
+
+ /* full foreign LOV is already avail in its cache
+ * no need to translate format fields to little-endian
+ */
+ memcpy(lfm, lsm_foreign(lsm), lsm->lsm_foreign_size);
+
+ RETURN(lfm_size);
+}
+
ssize_t lov_lsm_pack(const struct lov_stripe_md *lsm, void *buf,
size_t buf_size)
{
if (lsm->lsm_magic == LOV_MAGIC_V1 || lsm->lsm_magic == LOV_MAGIC_V3)
return lov_lsm_pack_v1v3(lsm, buf, buf_size);
+ if (lsm->lsm_magic == LOV_MAGIC_FOREIGN)
+ return lov_lsm_pack_foreign(lsm, buf, buf_size);
+
lmm_size = lov_comp_md_size(lsm);
if (buf_size == 0)
RETURN(lmm_size);
{
/* we use lov_user_md_v3 because it is larger than lov_user_md_v1 */
struct lov_mds_md *lmmk, *lmm;
+ struct lov_foreign_md *lfm;
struct lov_user_md_v1 lum;
size_t lmmk_size;
ssize_t lmm_size, lum_size = 0;
ENTRY;
if (lsm->lsm_magic != LOV_MAGIC_V1 && lsm->lsm_magic != LOV_MAGIC_V3 &&
- lsm->lsm_magic != LOV_MAGIC_COMP_V1) {
+ lsm->lsm_magic != LOV_MAGIC_COMP_V1 &&
+ lsm->lsm_magic != LOV_MAGIC_FOREIGN) {
CERROR("bad LSM MAGIC: 0x%08X != 0x%08X nor 0x%08X\n",
lsm->lsm_magic, LOV_MAGIC_V1, LOV_MAGIC_V3);
GOTO(out, rc = -EIO);
} else if (lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_COMP_V1)) {
lustre_swab_lov_comp_md_v1(
(struct lov_comp_md_v1 *)lmmk);
+ } else if (lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_FOREIGN)) {
+ lfm = (struct lov_foreign_md *)lmmk;
+ __swab32s(&lfm->lfm_magic);
+ __swab32s(&lfm->lfm_length);
+ __swab32s(&lfm->lfm_type);
+ __swab32s(&lfm->lfm_flags);
}
}
* Legacy appication passes limited buffer, we need to figure out
* the user buffer size by the passed in lmm_stripe_count.
*/
- if (copy_from_user(&lum, lump, sizeof(struct lov_user_md_v1)))
- GOTO(out_free, rc = -EFAULT);
+ if (lsm->lsm_magic != LOV_MAGIC_FOREIGN)
+ if (copy_from_user(&lum, lump, sizeof(struct lov_user_md_v1)))
+ GOTO(out_free, rc = -EFAULT);
if (lum.lmm_magic == LOV_USER_MAGIC_V1 ||
lum.lmm_magic == LOV_USER_MAGIC_V3)
RETURN(0);
}
+int lov_page_init_foreign(const struct lu_env *env, struct cl_object *obj,
+ struct cl_page *page, pgoff_t index)
+{
+ CDEBUG(D_PAGE, DFID" has no data\n", PFID(lu_object_fid(&obj->co_lu)));
+ RETURN(-ENODATA);
+}
+
bool lov_page_is_empty(const struct cl_page *page)
{
const struct cl_page_slice *slice = cl_page_at(page, &lov_device_type);
THETESTS += llapi_layout_test orphan_linkea_check llapi_hsm_test
THETESTS += group_lock_test llapi_fid_test sendfile_grouplock mmap_cat
THETESTS += swap_lock_test lockahead_test mirror_io mmap_mknod_test
+THETESTS += create_foreign_file parse_foreign_file
if TESTS
if MPITESTS
--- /dev/null
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/xattr.h>
+#include <sys/file.h>
+
+#include <lustre/lustreapi.h>
+
+int main(int argc, char **argv)
+{
+ int c, fd;
+ char *fname = "FILE";
+ char *xval = "UUID@UUID";
+ size_t len;
+ struct lov_foreign_md *lfm;
+ char *end;
+ __u32 type = LOV_FOREIGN_TYPE_DAOS, flags = 0xda08;
+
+ while ((c = getopt(argc, argv, "f:x:t:F:")) != -1) {
+ switch (c) {
+ case 'f':
+ fname = optarg;
+ break;
+ case 'x':
+ xval = optarg;
+ break;
+ case 't':
+ type = strtoul(optarg, &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr,
+ "%s: invalid type '%s'\n", argv[0],
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'F':
+ flags = strtoul(optarg, &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr,
+ "%s: invalid flags '%s'\n", argv[0],
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'h':
+ fprintf(stderr,
+ "Usage: %s -f <filename> -x <LOV EA content>\n",
+ argv[0]);
+ break;
+ }
+ }
+
+ len = strlen(xval);
+ if (len > XATTR_SIZE_MAX || len <= 0) {
+ fprintf(stderr,
+ "invalid LOV EA length %zu > XATTR_SIZE_MAX (%u)\n",
+ len, XATTR_SIZE_MAX);
+ exit(1);
+ }
+
+ fd = open(fname, O_WRONLY|O_CREAT|O_LOV_DELAY_CREATE, 0644);
+ if (fd == -1) {
+ perror("open()");
+ exit(1);
+ }
+
+ lfm = malloc(len + offsetof(struct lov_foreign_md, lfm_value));
+ if (lfm == NULL) {
+ perror("malloc()");
+ exit(1);
+ }
+
+ lfm->lfm_magic = LOV_USER_MAGIC_FOREIGN;
+ lfm->lfm_length = len;
+ lfm->lfm_type = type;
+ lfm->lfm_flags = flags;
+ memcpy(lfm->lfm_value, xval, len);
+
+ if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, lfm) != 0) {
+ perror("ioctl(LL_IOC_LOV_SETSTRIPE)");
+ exit(1);
+ }
+
+ close(fd);
+ return 0;
+}
--- /dev/null
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/xattr.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <byteswap.h>
+
+#include <lustre/lustreapi.h>
+
+int main(int argc, char **argv)
+{
+ int c, i;
+ char *fname = "FILE";
+ size_t len, len2;
+ struct lov_foreign_md *lfm;
+
+ while ((c = getopt(argc, argv, "f:")) != -1) {
+ switch (c) {
+ case 'f':
+ fname = optarg;
+ break;
+ case 'h':
+ fprintf(stderr, "Usage: %s -f <filename>\n", argv[0]);
+ break;
+ }
+ }
+
+ len = getxattr(fname, "lustre.lov", NULL, 0);
+ if (len == -1) {
+ perror("getxattr()");
+ exit(1);
+ }
+ if (len > XATTR_SIZE_MAX || len <= 0) {
+ fprintf(stderr,
+ "invalid LOV EA length %zu > XATTR_SIZE_MAX (%u)\n",
+ len, XATTR_SIZE_MAX);
+ exit(1);
+ }
+
+ lfm = malloc(len);
+ if (lfm == NULL) {
+ perror("malloc()");
+ exit(1);
+ }
+
+ len2 = getxattr(fname, "lustre.lov", lfm, len);
+ if (len2 == -1) {
+ perror("getxattr()");
+ exit(1);
+ }
+
+ if (len != len2)
+ fprintf(stderr,
+ "trusted.lov xattr size changed, before=%zu now=%zu\n",
+ len, len2);
+
+ if (len2 < offsetof(struct lov_foreign_md, lfm_value)) {
+ fprintf(stderr, "trusted.lov size=%zu too small\n", len2);
+ fprintf(stderr, "printing its content in hex anyway:\n");
+ for (i = 0; i < len2; i++)
+ fprintf(stderr, "%02x", *((char *)lfm + i));
+ exit(1);
+ }
+
+
+ if (lfm->lfm_magic != LOV_USER_MAGIC_FOREIGN) {
+ if (lfm->lfm_magic == bswap_32(LOV_USER_MAGIC_FOREIGN))
+ fprintf(stderr, "magic is swapped\n");
+ else
+ fprintf(stderr, "wrong magic=(0x%x)\n", lfm->lfm_magic);
+ }
+
+ if (lfm->lfm_length != len2 - offsetof(typeof(*lfm), lfm_value)) {
+ if (bswap_32(lfm->lfm_length) == len2 - offsetof(typeof(*lfm),
+ lfm_value))
+ fprintf(stderr, "length is swapped\n");
+ else
+ fprintf(stderr,
+ "wrong internal length=%u vs xattr size=%zu\n",
+ lfm->lfm_length, len2);
+ }
+
+ fprintf(stdout, "lov_xattr_size: %zu\n", len2);
+ fprintf(stdout, "lov_foreign_magic: 0x%08X\n", lfm->lfm_magic);
+ fprintf(stdout, "lov_foreign_size: %u\n", lfm->lfm_length);
+ fprintf(stdout, "lov_foreign_type: %u\n", lfm->lfm_type);
+ fprintf(stdout, "lov_foreign_flags: 0x%08X\n", lfm->lfm_flags);
+ fprintf(stdout, "lov_foreign_value: 0x");
+ for (i = 0; i < len2 - offsetof(typeof(*lfm), lfm_value); i++)
+ fprintf(stdout, "%02x", lfm->lfm_value[i]);
+
+ fprintf(stdout, "\n");
+
+ return 0;
+}
}
run_test 37 "LFSCK must skip a ORPHAN"
+test_38()
+{
+ [[ $MDS1_VERSION -le $(version_code 2.12.51) ]] &&
+ skip "Need MDS version newer than 2.12.51"
+
+ test_mkdir $DIR/$tdir
+ local uuid1=$(cat /proc/sys/kernel/random/uuid)
+ local uuid2=$(cat /proc/sys/kernel/random/uuid)
+
+ # create foreign file
+ $LFS setstripe --foreign=daos --flags 0xda05 \
+ -x "${uuid1}@${uuid2}" $DIR/$tdir/$tfile ||
+ error "$DIR/$tdir/$tfile: create failed"
+
+ $LFS getstripe -v $DIR/$tdir/$tfile |
+ grep "lfm_magic:.*0x0BD70BD0" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign magic"
+ # lfm_length is LOV EA size - sizeof(lfm_magic) - sizeof(lfm_length)
+ $LFS getstripe -v $DIR/$tdir/$tfile | grep "lfm_length:.*73" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign size"
+ $LFS getstripe -v $DIR/$tdir/$tfile | grep "lfm_type:.*daos" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign type"
+ $LFS getstripe -v $DIR/$tdir/$tfile |
+ grep "lfm_flags:.*0x0000DA05" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign flags"
+ $LFS getstripe $DIR/$tdir/$tfile |
+ grep "lfm_value:.*${uuid1}@${uuid2}" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign value"
+
+ # modify striping should fail
+ $LFS setstripe -c 2 $DIR/$tdir/$tfile &&
+ error "$DIR/$tdir/$tfile: setstripe should fail"
+
+ $START_NAMESPACE -r -A || error "Fail to start LFSCK for namespace"
+
+ wait_all_targets_blocked namespace completed 1
+
+ # check that "global" namespace_repaired == 0 !!!
+ local repaired=$(do_facet mds1 \
+ "$LCTL lfsck_query -t all -M ${FSNAME}-MDT0000 |
+ awk '/^namespace_repaired/ { print \\\$2 }'")
+ [ $repaired -eq 0 ] ||
+ error "(2) Expect no namespace repair, but got: $repaired"
+
+ $START_LAYOUT -A -r || error "Fail to start LFSCK for layout"
+
+ wait_all_targets_blocked layout completed 2
+
+ # check that "global" layout_repaired == 0 !!!
+ local repaired=$(do_facet mds1 \
+ "$LCTL lfsck_query -t all -M ${FSNAME}-MDT0000 |
+ awk '/^layout_repaired/ { print \\\$2 }'")
+ [ $repaired -eq 0 ] ||
+ error "(2) Expect no layout repair, but got: $repaired"
+
+ echo "post-lfsck checks of foreign file"
+
+ $LFS getstripe -v $DIR/$tdir/$tfile |
+ grep "lfm_magic:.*0x0BD70BD0" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign magic"
+ # lfm_length is LOV EA size - sizeof(lfm_magic) - sizeof(lfm_length)
+ $LFS getstripe -v $DIR/$tdir/$tfile | grep "lfm_length:.*73" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign size"
+ $LFS getstripe -v $DIR/$tdir/$tfile | grep "lfm_type:.*daos" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign type"
+ $LFS getstripe -v $DIR/$tdir/$tfile |
+ grep "lfm_flags:.*0x0000DA05" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign flags"
+ $LFS getstripe $DIR/$tdir/$tfile |
+ grep "lfm_value:.*${uuid1}@${uuid2}" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign value"
+
+ # modify striping should fail
+ $LFS setstripe -c 2 $DIR/$tdir/$tfile &&
+ error "$DIR/$tdir/$tfile: setstripe should fail"
+
+ # R/W should fail
+ cat $DIR/$tdir/$tfile && "$DIR/$tdir/$tfile: read should fail"
+ cat /etc/passwd > $DIR/$tdir/$tfile &&
+ error "$DIR/$tdir/$tfile: write should fail"
+
+ #remove foreign file
+ rm $DIR/$tdir/$tfile ||
+ error "$DIR/$tdir/$tfile: remove of foreign file has failed"
+}
+run_test 38 "LFSCK does not break foreign file and reverse is also true"
# restore MDS/OST size
MDSSIZE=${SAVED_MDSSIZE}
}
run_test 27I "check that root dir striping does not break parent dir one"
+test_27J() {
+ [[ $(lustre_version_code $SINGLEMDS) -le $(version_code 2.12.51) ]] &&
+ skip "Need MDS version newer than 2.12.51"
+
+ test_mkdir $DIR/$tdir
+ local uuid1=$(cat /proc/sys/kernel/random/uuid)
+ local uuid2=$(cat /proc/sys/kernel/random/uuid)
+
+ # create foreign file (raw way)
+ create_foreign_file -f $DIR/$tdir/$tfile -x "${uuid1}@${uuid2}" \
+ -t 1 -F 0xda08 || error "create_foreign_file failed"
+
+ # verify foreign file (raw way)
+ parse_foreign_file -f $DIR/$tdir/$tfile |
+ grep "lov_foreign_magic: 0x0BD70BD0" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign magic"
+ parse_foreign_file -f $DIR/$tdir/$tfile | grep "lov_xattr_size: 89" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign size"
+ parse_foreign_file -f $DIR/$tdir/$tfile |
+ grep "lov_foreign_size: 73" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign size"
+ parse_foreign_file -f $DIR/$tdir/$tfile |
+ grep "lov_foreign_type: 1" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign type"
+ parse_foreign_file -f $DIR/$tdir/$tfile |
+ grep "lov_foreign_flags: 0x0000DA08" ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign flags"
+ local lov=$(parse_foreign_file -f $DIR/$tdir/$tfile |
+ grep "lov_foreign_value: 0x" |
+ sed -e 's/lov_foreign_value: 0x//')
+ local lov2=$(echo -n "${uuid1}@${uuid2}" | od -A n -t x1 -w160)
+ [[ $lov = ${lov2// /} ]] ||
+ error "$DIR/$tdir/$tfile: invalid LOV EA foreign value"
+
+ # create foreign file (lfs + API)
+ $LFS setstripe --foreign=daos --flags 0xda08 \
+ -x "${uuid1}@${uuid2}" $DIR/$tdir/${tfile}2 ||
+ error "$DIR/$tdir/${tfile}2: create failed"
+
+ $LFS getstripe -v $DIR/$tdir/${tfile}2 |
+ grep "lfm_magic:.*0x0BD70BD0" ||
+ error "$DIR/$tdir/${tfile}2: invalid LOV EA foreign magic"
+ # lfm_length is LOV EA size - sizeof(lfm_magic) - sizeof(lfm_length)
+ $LFS getstripe -v $DIR/$tdir/${tfile}2 | grep "lfm_length:.*73" ||
+ error "$DIR/$tdir/${tfile}2: invalid LOV EA foreign size"
+ $LFS getstripe -v $DIR/$tdir/${tfile}2 | grep "lfm_type:.*daos" ||
+ error "$DIR/$tdir/${tfile}2: invalid LOV EA foreign type"
+ $LFS getstripe -v $DIR/$tdir/${tfile}2 |
+ grep "lfm_flags:.*0x0000DA08" ||
+ error "$DIR/$tdir/${tfile}2: invalid LOV EA foreign flags"
+ $LFS getstripe -v $DIR/$tdir/${tfile}2 |
+ grep "lfm_value:.*${uuid1}@${uuid2}" ||
+ error "$DIR/$tdir/${tfile}2: invalid LOV EA foreign value"
+
+ # modify striping should fail
+ $LFS setstripe -c 2 $DIR/$tdir/$tfile &&
+ error "$DIR/$tdir/$tfile: setstripe should fail"
+ $LFS setstripe -c 2 $DIR/$tdir/${tfile}2 &&
+ error "$DIR/$tdir/${tfile}2: setstripe should fail"
+
+ # R/W should fail
+ cat $DIR/$tdir/$tfile && error "$DIR/$tdir/$tfile: read should fail"
+ cat $DIR/$tdir/${tfile}2 &&
+ error "$DIR/$tdir/${tfile}2: read should fail"
+ cat /etc/passwd > $DIR/$tdir/$tfile &&
+ error "$DIR/$tdir/$tfile: write should fail"
+ cat /etc/passwd > $DIR/$tdir/${tfile}2 &&
+ error "$DIR/$tdir/${tfile}2: write should fail"
+
+ # chmod should work
+ chmod 222 $DIR/$tdir/$tfile ||
+ error "$DIR/$tdir/$tfile: chmod failed"
+ chmod 222 $DIR/$tdir/${tfile}2 ||
+ error "$DIR/$tdir/${tfile}2: chmod failed"
+
+ # chown should work
+ chown $RUNAS_ID:$RUNAS_GID $DIR/$tdir/$tfile ||
+ error "$DIR/$tdir/$tfile: chown failed"
+ chown $RUNAS_ID:$RUNAS_GID $DIR/$tdir/${tfile}2 ||
+ error "$DIR/$tdir/${tfile}2: chown failed"
+
+ # rename should work
+ mv $DIR/$tdir/$tfile $DIR/$tdir/${tfile}.new ||
+ error "$DIR/$tdir/$tfile: rename of foreign file has failed"
+ mv $DIR/$tdir/${tfile}2 $DIR/$tdir/${tfile}2.new ||
+ error "$DIR/$tdir/${tfile}2: rename of foreign file has failed"
+
+ #remove foreign file
+ rm $DIR/$tdir/${tfile}.new ||
+ error "$DIR/$tdir/${tfile}.new: remove of foreign file has failed"
+ rm $DIR/$tdir/${tfile}2.new ||
+ error "$DIR/$tdir/${tfile}2.new: remove of foreign file has failed"
+}
+run_test 27J "basic ops on file with foreign LOV"
+
# createtest also checks that device nodes are created and
# then visible correctly (#2091)
test_28() { # bug 2091
"To create a file with specified striping/composite layout, or\n"
"create/replace the default layout on an existing directory:\n"
SSM_CMD_COMMON("setstripe")
+ " [--mode <mode>]\n"
" <directory|filename>\n"
" or\n"
"To add component(s) to an existing composite file:\n"
"\tcomp_id: Unique component ID to delete\n"
"\tcomp_flags: 'init' indicating all instantiated components\n"
"\t '^init' indicating all uninstantiated components\n"
- "\t-I and -F cannot be specified at the same time\n"},
+ "\t-I and -F cannot be specified at the same time\n"
+ "To create a file with a foreign (free format) layout:\n"
+ "usage: setstripe --foreign[=<foreign_type>]\n"
+ " --xattr|-x <layout_string> [--flags <hex>]\n"
+ " [--mode <mode>] <filename>\n"},
{"getstripe", lfs_getstripe, 0,
"To list the layout pattern for a given file or files in a\n"
"directory or recursively for all files in a directory tree.\n"
" [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
" [[!] --projid <projid>]\n"
" [[!] --layout|-L released,raid0,mdt]\n"
+ " [[!] --foreign[=<foreign_type>]]\n"
" [[!] --component-count [+-]<comp_cnt>]\n"
" [[!] --component-start [+-]N[kMGTPE]]\n"
" [[!] --component-end|-E [+-]N[kMGTPE]]\n"
return 0;
}
+static uint32_t lov_check_foreign_type_name(const char *foreign_type_name)
+{
+ uint32_t i;
+
+ for (i = 0; i < LOV_FOREIGN_TYPE_UNKNOWN; i++) {
+ if (lov_foreign_type[i].lft_name == NULL)
+ break;
+ if (strcmp(foreign_type_name,
+ lov_foreign_type[i].lft_name) == 0)
+ return lov_foreign_type[i].lft_type;
+ }
+
+ return LOV_FOREIGN_TYPE_UNKNOWN;
+}
static const char *error_loc = "syserror";
LFS_COMP_ADD_OPT,
LFS_COMP_NO_VERIFY_OPT,
LFS_PROJID_OPT,
- LFS_MIRROR_FLAGS_OPT,
+ LFS_LAYOUT_FLAGS_OPT, /* used for mirror and foreign flags */
LFS_MIRROR_ID_OPT,
LFS_MIRROR_STATE_OPT,
LFS_LAYOUT_COPY,
LFS_MIRROR_INDEX_OPT,
+ LFS_LAYOUT_FOREIGN_OPT,
+ LFS_MODE_OPT,
};
/* functions */
unsigned long long size_units = 1;
bool migrate_mode = false;
bool migrate_mdt_mode = false;
+ bool setstripe_mode = false;
bool migration_block = false;
__u64 migration_flags = 0;
__u32 tgts[LOV_MAX_STRIPE_COUNT] = { 0 };
bool from_yaml = false;
bool from_copy = false;
char *template = NULL;
+ bool foreign_mode = false;
+ char *xattr = NULL;
+ uint32_t type = LOV_FOREIGN_TYPE_NONE, flags = 0;
+ char *mode_opt = NULL;
+ mode_t previous_umask = 0;
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
struct option long_opts[] = {
/* find { .val = '0', .name = "null", .has_arg = no_argument }, */
.has_arg = no_argument},
{ .val = LFS_COMP_NO_VERIFY_OPT,
.name = "no-verify", .has_arg = no_argument},
- { .val = LFS_MIRROR_FLAGS_OPT,
+ { .val = LFS_LAYOUT_FLAGS_OPT,
.name = "flags", .has_arg = required_argument},
+ { .val = LFS_LAYOUT_FOREIGN_OPT,
+ .name = "foreign", .has_arg = optional_argument},
{ .val = LFS_MIRROR_ID_OPT,
.name = "mirror-id", .has_arg = required_argument},
+ { .val = LFS_MODE_OPT,
+ .name = "mode", .has_arg = required_argument},
{ .val = LFS_LAYOUT_COPY,
.name = "copy", .has_arg = required_argument},
{ .val = 'c', .name = "stripe-count", .has_arg = required_argument},
/* find { .val = 'U', .name = "user", .has_arg = required_argument }*/
/* --verbose is only valid in migrate mode */
{ .val = 'v', .name = "verbose", .has_arg = no_argument},
+ { .val = 'x', .name = "xattr", .has_arg = required_argument },
{ .val = 'y', .name = "yaml", .has_arg = required_argument },
{ .name = NULL } };
migrate_mode = (opc == SO_MIGRATE);
mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
+ setstripe_mode = (opc == SO_SETSTRIPE);
snprintf(cmd, sizeof(cmd), "%s %s", progname, argv[0]);
progname = cmd;
while ((c = getopt_long(argc, argv,
- "bc:dDE:f:H:i:I:m:N::no:p:L:s:S:vy:", long_opts,
- NULL)) >= 0) {
+ "bc:dDE:f:H:i:I:m:N::no:p:L:s:S:vx:y:",
+ long_opts, NULL)) >= 0) {
switch (c) {
case 0:
/* Long options. */
goto usage_error;
}
break;
- case LFS_MIRROR_FLAGS_OPT: {
- __u32 flags;
+ case LFS_LAYOUT_FLAGS_OPT: {
+ uint32_t neg_flags;
+
+ /* check for numeric flags (foreign and mirror cases) */
+ if (setstripe_mode && !mirror_mode && !last_mirror) {
+ flags = strtoul(optarg, &end, 16);
+ if (*end != '\0') {
+ fprintf(stderr,
+ "%s %s: bad flags '%s'\n",
+ progname, argv[0], optarg);
+ return CMD_HELP;
+ }
+ break;
+ }
if (!mirror_mode || !last_mirror) {
fprintf(stderr, "error: %s: --flags must be specified with --mirror-count|-N option\n",
}
result = comp_str2flags(optarg, &last_mirror->m_flags,
- &flags);
+ &neg_flags);
if (result != 0)
goto usage_error;
- if (flags) {
+ if (neg_flags) {
fprintf(stderr, "%s: inverted flags are not supported\n",
progname);
result = -EINVAL;
}
break;
}
+ case LFS_LAYOUT_FOREIGN_OPT:
+ if (optarg != NULL) {
+ /* check pure numeric */
+ type = strtoul(optarg, &end, 0);
+ if (*end) {
+ /* check name */
+ type = lov_check_foreign_type_name(optarg);
+ if (type == LOV_FOREIGN_TYPE_UNKNOWN) {
+ fprintf(stderr,
+ "%s %s: unrecognized foreign type '%s'\n",
+ progname, argv[0],
+ optarg);
+ return CMD_HELP;
+ }
+ }
+ }
+ foreign_mode = true;
+ break;
+ case LFS_MODE_OPT:
+ mode_opt = optarg;
+ if (mode_opt != NULL) {
+ mode = strtoul(mode_opt, &end, 8);
+ if (*end != '\0') {
+ fprintf(stderr,
+ "%s %s: bad MODE '%s'\n",
+ progname, argv[0], mode_opt);
+ return CMD_HELP;
+ }
+ previous_umask = umask(0);
+ }
+ break;
case LFS_LAYOUT_COPY:
from_copy = true;
template = optarg;
migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
migration_flags = MIGRATION_VERBOSE;
break;
+ case 'x':
+ xattr = optarg;
+ break;
case 'y':
from_yaml = true;
template = optarg;
goto usage_error;
}
+ if (xattr && !foreign_mode) {
+ /* only print a warning as this is harmless and will be ignored
+ */
+ fprintf(stderr,
+ "%s %s: xattr has been specified for non-foreign layout\n",
+ progname, argv[0]);
+ } else if (foreign_mode && !xattr) {
+ fprintf(stderr,
+ "%s %s: xattr must be provided in foreign mode\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (foreign_mode && (!setstripe_mode || comp_add | comp_del ||
+ comp_set || comp_id || delete || from_copy ||
+ setstripe_args_specified(&lsa) || lsa.lsa_nr_tgts ||
+ lsa.lsa_tgts)) {
+ fprintf(stderr,
+ "%s %s: only --xattr/--flags/--mode options are valid with --foreign\n",
+ progname, argv[0]);
+ return CMD_HELP;
+ }
+
if (mirror_mode && mirror_count == 0) {
fprintf(stderr,
"error: %s: --mirror-count|-N option is required\n",
NULL);
} else if (layout != NULL) {
result = lfs_component_create(fname, O_CREAT | O_WRONLY,
- 0666, layout);
+ mode, layout);
+ if (result >= 0) {
+ close(result);
+ result = 0;
+ }
+ } else if (foreign_mode) {
+ result = llapi_file_create_foreign(fname, mode, type,
+ flags, xattr);
if (result >= 0) {
close(result);
result = 0;
} else {
result = llapi_file_open_param(fname,
O_CREAT | O_WRONLY,
- 0666, param);
+ mode, param);
if (result >= 0) {
close(result);
result = 0;
}
}
+ if (mode_opt != NULL && previous_umask != 0)
+ umask(previous_umask);
+
free(param);
free(migrate_mdt_param.fp_lmv_md);
llapi_layout_free(layout);
.has_arg = required_argument },
{ .val = LFS_MIRROR_STATE_OPT,
.name = "mirror-state", .has_arg = required_argument },
+ { .val = LFS_LAYOUT_FOREIGN_OPT,
+ .name = "foreign", .has_arg = optional_argument},
{ .val = 'c', .name = "stripe-count", .has_arg = required_argument },
{ .val = 'c', .name = "stripe_count", .has_arg = required_argument },
{ .val = 'C', .name = "ctime", .has_arg = required_argument },
param.fp_mirror_state = state;
}
break;
+ case LFS_LAYOUT_FOREIGN_OPT: {
+ /* all types by default */
+ uint32_t type = LOV_FOREIGN_TYPE_UNKNOWN;
+
+ if (optarg != NULL) {
+ /* check pure numeric */
+ type = strtoul(optarg, &endptr, 0);
+ if (*endptr) {
+ /* check name */
+ type = lov_check_foreign_type_name(optarg);
+ if (type == LOV_FOREIGN_TYPE_UNKNOWN) {
+ fprintf(stderr,
+ "%s %s: unrecognized foreign type '%s'\n",
+ progname, argv[0],
+ optarg);
+ return CMD_HELP;
+ }
+ }
+ }
+ param.fp_foreign_type = type;
+ param.fp_check_foreign = 1;
+ param.fp_exclude_foreign = !!neg_opt;
+ break;
+ }
case 'c':
if (optarg[0] == '+') {
param.fp_stripe_count_sign = -1;
LMV_HASH_NAME_ALL_CHARS,
LMV_HASH_NAME_FNV_1A_64 };
+struct lustre_foreign_type lov_foreign_type[] = {
+ {.lft_type = LOV_FOREIGN_TYPE_NONE, .lft_name = "none"},
+ {.lft_type = LOV_FOREIGN_TYPE_DAOS, .lft_name = "daos"},
+ /* must be the last element */
+ {.lft_type = LOV_FOREIGN_TYPE_UNKNOWN, .lft_name = NULL}
+ /* array max dimension must be <= UINT32_MAX */
+};
+
void llapi_msg_set_level(int level)
{
/* ensure level is in the good range */
stripe_pattern, NULL);
}
+int llapi_file_create_foreign(const char *name, mode_t mode, __u32 type,
+ __u32 flags, char *foreign_lov)
+{
+ size_t len;
+ struct lov_foreign_md *lfm;
+ int fd, rc;
+
+ if (foreign_lov == NULL) {
+ llapi_error(LLAPI_MSG_ERROR, -EINVAL,
+ "foreign LOV EA content must be provided");
+ return -EINVAL;
+ }
+
+ len = strlen(foreign_lov);
+ if (len > XATTR_SIZE_MAX - offsetof(struct lov_foreign_md, lfm_value) ||
+ len <= 0) {
+ llapi_error(LLAPI_MSG_ERROR, -EINVAL,
+ "foreign LOV EA size %zu (must be 0 < len < %zu)",
+ len, XATTR_SIZE_MAX -
+ offsetof(struct lov_foreign_md, lfm_value));
+ return -EINVAL;
+ }
+
+ lfm = malloc(len + offsetof(struct lov_foreign_md, lfm_value));
+ if (lfm == NULL) {
+ llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
+ "failed to allocate lov_foreign_md");
+ return -ENOMEM;
+ }
+
+ fd = open(name, O_WRONLY|O_CREAT|O_LOV_DELAY_CREATE, mode);
+ if (fd == -1) {
+ perror("open()");
+ rc = -errno;
+ goto out_free;
+ }
+
+ lfm->lfm_magic = LOV_USER_MAGIC_FOREIGN;
+ lfm->lfm_length = len;
+ lfm->lfm_type = type;
+ lfm->lfm_flags = flags;
+ memcpy(lfm->lfm_value, foreign_lov, len);
+
+ if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, lfm) != 0) {
+ char *errmsg = "stripe already set";
+ char fsname[MAX_OBD_NAME + 1] = { 0 };
+
+ rc = -errno;
+ if (errno != EEXIST && errno != EALREADY)
+ errmsg = strerror(errno);
+
+ llapi_err_noerrno(LLAPI_MSG_ERROR,
+ "setstripe error for '%s': %s", name, errmsg);
+
+ /* Make sure we are on a Lustre file system */
+ if (rc == -ENOTTY && llapi_search_fsname(name, fsname))
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "'%s' is not on a Lustre filesystem",
+ name);
+
+ close(fd);
+ fd = rc;
+ }
+
+out_free:
+ free(lfm);
+
+ return fd;
+}
+
int llapi_file_create(const char *name, unsigned long long stripe_size,
int stripe_offset, int stripe_count, int stripe_pattern)
{
}
}
+static uint32_t lov_check_foreign_type(uint32_t foreign_type)
+{
+ uint32_t i;
+
+ for (i = 0; i < LOV_FOREIGN_TYPE_UNKNOWN; i++) {
+ if (lov_foreign_type[i].lft_name == NULL)
+ break;
+ if (foreign_type == lov_foreign_type[i].lft_type)
+ return i;
+ }
+
+ return LOV_FOREIGN_TYPE_UNKNOWN;
+}
+
+static void lov_dump_foreign_lmm(struct find_param *param, char *path,
+ enum lov_dump_flags flags)
+{
+ struct lov_foreign_md *lfm = (void *)¶m->fp_lmd->lmd_lmm;
+ bool yaml = flags & LDF_YAML;
+
+ if (!yaml && param->fp_depth && path)
+ llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
+
+ if (param->fp_verbose & VERBOSE_DETAIL) {
+ uint32_t type = lov_check_foreign_type(lfm->lfm_type);
+
+ llapi_printf(LLAPI_MSG_NORMAL, "lfm_magic: 0x%08X\n",
+ lfm->lfm_magic);
+ llapi_printf(LLAPI_MSG_NORMAL, "lfm_length: %u\n",
+ lfm->lfm_length);
+ llapi_printf(LLAPI_MSG_NORMAL, "lfm_type: 0x%08X",
+ lfm->lfm_type);
+ if (type < LOV_FOREIGN_TYPE_UNKNOWN)
+ llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
+ lov_foreign_type[type].lft_name);
+ else
+ llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
+
+ llapi_printf(LLAPI_MSG_NORMAL, "lfm_flags: 0x%08X\n",
+ lfm->lfm_flags);
+ }
+
+ llapi_printf(LLAPI_MSG_NORMAL, "lfm_value: '%.*s'\n",
+ lfm->lfm_length, lfm->lfm_value);
+ llapi_printf(LLAPI_MSG_NORMAL, "\n");
+}
+
static void llapi_lov_dump_user_lmm(struct find_param *param, char *path,
enum lov_dump_flags flags)
{
case LOV_USER_MAGIC_SPECIFIC:
lov_dump_plain_user_lmm(param, path, flags);
break;
+ case LOV_USER_MAGIC_FOREIGN:
+ lov_dump_foreign_lmm(param, path, flags);
+ break;
case LMV_MAGIC_V1:
case LMV_USER_MAGIC: {
char pool_name[LOV_MAXPOOLNAME + 1];
if (!S_ISREG(st->st_mode))
return 0;
+ /* exclude foreign */
+ if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
+ return param->fp_exclude_obd;
+
/* Only those files should be accepted, which have a
* stripe on the specified OST. */
if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm;
int ret, i, count = 1;
+ if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
+ return param->fp_exclude_stripe_size ? 1 : -1;
+
if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
comp_v1 = (struct lov_comp_md_v1 *)v1;
count = comp_v1->lcm_entry_count;
int i, count = 1;
__u32 stripe_count = 0;
+ if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
+ return 0;
+
if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
comp_v1 = (struct lov_comp_md_v1 *)v1;
count = comp_v1->lcm_entry_count;
if (comp_v1)
v1 = lov_comp_entry(comp_v1, i);
+ /* foreign file have a special magic but no pattern field */
+ if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
+ continue;
+
if (v1->lmm_pattern == LOV_PATTERN_INVALID)
continue;
return -1;
}
+/* if no type specified, check/exclude all foreign
+ * if type specified, check all foreign&type and exclude !foreign + foreign&type
+ */
+static int find_check_foreign(struct find_param *param)
+{
+ if (S_ISREG(param->fp_lmd->lmd_st.st_mode)) {
+ struct lov_foreign_md *lfm;
+
+ lfm = (void *)¶m->fp_lmd->lmd_lmm;
+ if (lfm->lfm_magic != LOV_USER_MAGIC_FOREIGN) {
+ if (param->fp_foreign_type == LOV_FOREIGN_TYPE_UNKNOWN)
+ return param->fp_exclude_foreign ? 1 : -1;
+ return -1;
+ } else {
+ if (param->fp_foreign_type == LOV_FOREIGN_TYPE_UNKNOWN ||
+ lfm->lfm_type == param->fp_foreign_type)
+ return param->fp_exclude_foreign ? -1 : 1;
+ return param->fp_exclude_foreign ? 1 : -1;
+ }
+ }
+ return -1;
+}
+
static int find_check_pool(struct find_param *param)
{
struct lov_comp_md_v1 *comp_v1 = NULL;
if (comp_v1 != NULL)
v1 = lov_comp_entry(comp_v1, i);
+ if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
+ continue;
+
if (((v1->lmm_magic == LOV_USER_MAGIC_V1) &&
(param->fp_poolname[0] == '\0')) ||
((v1->lmm_magic == LOV_USER_MAGIC_V3) &&
struct lov_comp_md_entry_v1 *entry;
int i, ret = 0;
+ if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
+ return -1;
+
if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
comp_v1 = (struct lov_comp_md_v1 *)v1;
} else {
param->fp_check_stripe_size || param->fp_check_layout ||
param->fp_check_comp_count || param->fp_check_comp_end ||
param->fp_check_comp_start || param->fp_check_comp_flags ||
- param->fp_check_mirror_count ||
+ param->fp_check_mirror_count || param->fp_check_foreign ||
param->fp_check_mirror_state ||
param->fp_check_projid;
}
}
}
+ if (param->fp_check_foreign) {
+ decision = find_check_foreign(param);
+ if (decision == -1)
+ goto decided;
+ }
+
if (param->fp_check_stripe_size) {
decision = find_check_stripe_size(param);
if (decision == -1)
liblustreapi_initialized;
l_ioctl;
mdt_hash_name;
+ lov_foreign_type;
Parser_*;
register_ioc_*;
local: