Whamcloud - gitweb
LU-11376 lov: new foreign LOV format 55/33755/37
authorBruno Faccini <bruno.faccini@intel.com>
Wed, 27 Feb 2019 21:59:52 +0000 (16:59 -0500)
committerOleg Drokin <green@whamcloud.com>
Wed, 8 May 2019 05:50:34 +0000 (05:50 +0000)
This patch introduces a new layout/LOV format in order to
allow to specify an arbitrary external reference for a file
in Lustre namespace.
The new LOV format is made of {newmagic, length, type, flags,
string[length]} to be as flexible as possible.
Foreign file can be created by using the open(O_LOV_DELAY_CREATE) +
ioctl(LL_IOC_LOV_SETSTRIPE) operations and it can only be and remain
an empty file until removed.
A new API method llapi_file_create_foreign() has been introduced
and "lfs [[get,set]stripe,find" modified to understand new layout.
The idea behind this is to provide Lustre namespace support and
layout prefetch/caching under layout protection, for user/external
usage.

Code has been added for lfsck to handle foreign files, and
a new sub-test has been added in sanity-lfsck in order to verify
if does not break foreign file and that reverse is also true.

Signed-off-by: Bruno Faccini <bruno.faccini@intel.com>
Change-Id: I5d9c0642fe8e7009c30918bfa946cac7c00c9af8
Reviewed-on: https://review.whamcloud.com/33755
Tested-by: Jenkins
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Patrick Farrell <pfarrell@whamcloud.com>
30 files changed:
lustre/doc/Makefile.am
lustre/doc/lfs-find.1
lustre/doc/lfs-setstripe.1
lustre/doc/llapi_file_create_foreign.3 [new file with mode: 0644]
lustre/include/lustre/lustreapi.h
lustre/include/uapi/linux/lustre/lustre_idl.h
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/lfsck/lfsck_layout.c
lustre/llite/file.c
lustre/llite/llite_internal.h
lustre/llite/xattr.c
lustre/llite/xattr26.c
lustre/lod/lod_internal.h
lustre/lod/lod_lov.c
lustre/lod/lod_object.c
lustre/lod/lod_qos.c
lustre/lov/lov_cl_internal.h
lustre/lov/lov_ea.c
lustre/lov/lov_internal.h
lustre/lov/lov_object.c
lustre/lov/lov_pack.c
lustre/lov/lov_page.c
lustre/tests/Makefile.am
lustre/tests/create_foreign_file.c [new file with mode: 0644]
lustre/tests/parse_foreign_file.c [new file with mode: 0644]
lustre/tests/sanity-lfsck.sh
lustre/tests/sanity.sh
lustre/utils/lfs.c
lustre/utils/liblustreapi.c
lustre/utils/liblustreapi.map

index 11e92bf..b18525c 100644 (file)
@@ -63,6 +63,7 @@ MANFILES =                                    \
        llapi_create_volatile_param.3           \
        llapi_fd2parent.3                       \
        llapi_file_create.3                     \
        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                      \
        llapi_file_get_stripe.3                 \
        llapi_file_open.3                       \
        llapi_group_lock.3                      \
index 4486b92..046d89a 100644 (file)
@@ -12,6 +12,7 @@ lfs-find \- Lustre client utility to list files with specific attributes
       [[\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--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]
 [\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]
@@ -107,7 +108,7 @@ File has specified numeric group ID.
 .BR --group | -G
 File belongs to specified group, numeric group ID allowed.
 .TP
 .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
 File has a layout of the given type, one of:
 .RS 1.2i
 .TP
@@ -121,6 +122,11 @@ HSM-archived files that are not resident in the filesystem.
 Files that have the first data component on an MDT.
 .RE
 .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
 .BR --maxdepth
 Limits find to decend at most \fIn\fR levels of directory tree.
 .TP
@@ -290,6 +296,9 @@ Recursively list all mirrored files that have more than 2 mirrors.
 .TP
 .B $ lfs find ! --mirror-state=ro /mnt/lustre
 Recursively list all out-of-sync mirrored files.
 .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
 .SH BUGS
 The
 .B lfs find
index eaa109a..5bca972 100644 (file)
@@ -23,6 +23,9 @@ lfs setstripe \- set striping pattern of a file or directory default
 .B lfs setstripe --yaml=\fR<\fIyaml_template_file.lyl\fR> <\fIfile\fR>
 .br
 .B lfs setstripe --copy=\fR<\fIsource_template_file\fR> <\fIfile\fR>
 .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
 .SH DESCRIPTION
 The
 .B lfs setstripe
@@ -123,6 +126,18 @@ This is similar to the
 option but avoids the need for the intermediate
 .B .lyl
 file.
 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
 .SH STRIPE_OPTIONS
 The various OST stripe related options are listed and explained below:
 .TP
@@ -231,6 +246,29 @@ or
 .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.
 .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-*
 .SH COMPONENT_OPTIONS
 The various component related options are listed and explained below.  The
 .B --component-*
@@ -436,6 +474,18 @@ file
 which can be created with the
 .B lfs getstripe --yaml
 command.
 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),
 .SH SEE ALSO
 .BR lctl (1),
 .BR lfs (1),
diff --git a/lustre/doc/llapi_file_create_foreign.3 b/lustre/doc/llapi_file_create_foreign.3
new file mode 100644 (file)
index 0000000..be03522
--- /dev/null
@@ -0,0 +1,91 @@
+.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),
index 0e51d25..1f8dae2 100644 (file)
@@ -128,6 +128,8 @@ struct llapi_stripe_param {
 
 int llapi_file_open_param(const char *name, int flags, mode_t mode,
                          const struct llapi_stripe_param *param);
 
 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,
 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,
@@ -263,7 +265,9 @@ struct find_param {
                                 fp_exclude_hash_type:1,
                                 fp_yaml:1,     /* output layout in YAML */
                                 fp_check_blocks:1,
                                 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;
 
        enum llapi_layout_verbose fp_verbose;
        int                      fp_quiet;
@@ -321,6 +325,7 @@ struct find_param {
        unsigned int             fp_depth;
        unsigned int             fp_hash_type;
        unsigned int             fp_time_margin; /* time margin in seconds */
        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);
 };
 
 int llapi_ostlist(char *path, struct find_param *param);
index 73b5cd2..e395e6c 100644 (file)
@@ -1112,6 +1112,7 @@ enum obdo_flags {
 #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_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
 
 /*
  * magic for fully defined striping
index 6229b61..3329aae 100644 (file)
@@ -55,6 +55,7 @@
 # include <limits.h>
 # include <stdbool.h>
 # include <stdio.h> /* snprintf() */
 # 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 */
 # include <string.h>
 # define NEED_QUOTA_DEFS
 /* # include <sys/quota.h> - this causes complaints about caddr_t */
@@ -540,6 +541,7 @@ struct fsxattr {
 /* 0x0BD40BD0 is occupied by LOV_MAGIC_MIGRATE */
 #define LOV_USER_MAGIC_SPECIFIC 0x0BD50BD0     /* for specific OSTs */
 #define LOV_USER_MAGIC_COMP_V1 0x0BD60BD0
 /* 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*/
 
 #define LMV_USER_MAGIC         0x0CD30CD0    /* default lmv magic */
 #define LMV_USER_MAGIC_V0      0x0CD20CD0    /* old default lmv magic*/
@@ -625,6 +627,21 @@ struct lov_user_md_v3 {           /* LOV EA user data (host-endian) */
        struct lov_user_ost_data_v1 lmm_objects[0]; /* per-stripe data */
 } __attribute__((packed));
 
        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;
 struct lu_extent {
        __u64   e_start;
        __u64   e_end;
@@ -782,6 +799,20 @@ enum lmv_hash_type {
 
 extern char *mdt_hash_name[LMV_HASH_TYPE_MAX];
 
 
 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) */
 /* 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) */
index 4f250e0..bc091f4 100644 (file)
@@ -379,8 +379,29 @@ static int lfsck_layout_verify_header_v1v3(struct dt_object *obj,
        return 0;
 }
 
        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,
 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;
 
 {
        int rc = 0;
 
@@ -430,6 +451,10 @@ static int lfsck_layout_verify_header(struct dt_object *obj,
                                        le32_to_cpu(lcme->lcme_offset)), start,
                                        comp_id);
                }
                                        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);
        }
        } else {
                rc = lfsck_layout_verify_header_v1v3(obj, lmm, 1, 0);
        }
@@ -468,7 +493,7 @@ again:
                goto again;
        }
 
                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;
 }
 
        return rc1 ? rc1 : rc;
 }
@@ -2881,7 +2906,7 @@ again:
        }
 
        lmm = buf->lb_buf;
        }
 
        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 the LOV EA crashed, the rebuild it. */
        if (rc1 == -EINVAL) {
index b5b09d9..8d2368b 100644 (file)
@@ -1975,7 +1975,8 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
 
        if (lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V1) &&
            lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V3) &&
 
        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);
 
         /*
                GOTO(out, rc = -EPROTO);
 
         /*
@@ -2014,6 +2015,15 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
                           cpu_to_le32(LOV_MAGIC_COMP_V1)) {
                        lustre_swab_lov_comp_md_v1(
                                        (struct lov_comp_md_v1 *)lmm);
                           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);
                }
        }
 
                }
        }
 
index 99c8ab3..4a59769 100644 (file)
@@ -1025,6 +1025,8 @@ static inline ssize_t ll_lov_user_md_size(const struct lov_user_md *lum)
                                        LOV_USER_MAGIC_SPECIFIC);
        case LOV_USER_MAGIC_COMP_V1:
                return ((struct lov_comp_md_v1 *)lum)->lcm_size;
                                        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;
        }
 
        return -EINVAL;
index 3958dd6..c98a852 100644 (file)
@@ -472,6 +472,7 @@ static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size)
                };
                struct lu_env *env;
                u16 refcheck;
                };
                struct lu_env *env;
                u16 refcheck;
+               u32 magic;
 
                if (!obj)
                        RETURN(-ENODATA);
 
                if (!obj)
                        RETURN(-ENODATA);
@@ -500,7 +501,8 @@ static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size)
                 * recognizing layout gen as stripe offset when the
                 * file is restored. See LU-2809.
                 */
                 * 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;
                        goto out_env;
 
                ((struct lov_mds_md *)buf)->lmm_layout_gen = 0;
index 917ea3f..152eb7f 100644 (file)
@@ -451,6 +451,7 @@ static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size)
                        .cl_buf.lb_len = buf_size,
                };
                __u16 refcheck;
                        .cl_buf.lb_len = buf_size,
                };
                __u16 refcheck;
+               __u32 magic;
 
                if (obj == NULL)
                        RETURN(-ENODATA);
 
                if (obj == NULL)
                        RETURN(-ENODATA);
@@ -477,7 +478,8 @@ static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size)
                 * otherwise it would confuse tar --xattr by
                 * recognizing layout gen as stripe offset when the
                 * file is restored. See LU-2809. */
                 * 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;
                        goto out_env;
 
                ((struct lov_mds_md *)buf)->lmm_layout_gen = 0;
index 83fb539..4304639 100644 (file)
@@ -306,7 +306,8 @@ struct lod_object {
                        struct lod_mirror_entry *ldo_mirrors;
                        __u32           ldo_is_composite:1,
                                        ldo_flr_state:2,
                        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 {
                };
                /* directory stripe (LMV) */
                struct {
@@ -331,10 +332,19 @@ struct lod_object {
                        struct lod_default_striping     *ldo_def_striping;
                };
        };
                        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)                      \
 };
 
 #define lod_foreach_mirror_comp(comp, lo, mirror_idx)                      \
@@ -519,6 +529,9 @@ static inline bool lod_obj_is_striped(struct dt_object *dt)
        if (S_ISDIR(dt->do_lu.lo_header->loh_attr))
                return lo->ldo_dir_stripe_count != 0;
 
        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;
        for (i = 0; i < lo->ldo_comp_cnt; i++) {
                if (lo->ldo_comp_entries[i].llc_stripe == NULL)
                        continue;
@@ -763,6 +776,8 @@ int lod_declare_striped_create(const struct lu_env *env, struct dt_object *dt,
 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_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);
 
 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);
 
index a990505..2197e41 100644 (file)
@@ -945,7 +945,7 @@ int lod_generate_lovea(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;
        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;
 
        int i, rc = 0, offset;
        ENTRY;
 
@@ -960,9 +960,27 @@ int lod_generate_lovea(const struct lu_env *env, struct lod_object *lo,
                mirror_cnt = lo->ldo_mirror_count;
                comp_entries = lo->ldo_comp_entries;
                is_composite = lo->ldo_is_composite;
                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);
        }
 
        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) {
        LASSERT(comp_cnt != 0 && comp_entries != NULL);
 
        if (!is_composite) {
@@ -1237,6 +1255,7 @@ int lod_parse_striping(const struct lu_env *env, struct lod_object *lo,
 {
        struct lov_mds_md_v1    *lmm;
        struct lov_comp_md_v1   *comp_v1 = NULL;
 {
        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;
        struct lov_ost_data_v1  *objs;
        __u32   magic, pattern;
        int     i, j, rc = 0;
@@ -1253,10 +1272,13 @@ int lod_parse_striping(const struct lu_env *env, struct lod_object *lo,
        magic = le32_to_cpu(lmm->lmm_magic);
 
        if (magic != LOV_MAGIC_V1 && magic != LOV_MAGIC_V3 &&
        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);
 
                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;
 
        if (magic == LOV_MAGIC_COMP_V1) {
                comp_v1 = (struct lov_comp_md_v1 *)lmm;
@@ -1268,6 +1290,25 @@ int lod_parse_striping(const struct lu_env *env, struct lod_object *lo,
                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;
                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);
        } else {
                comp_cnt = 1;
                lo->ldo_layout_gen = le16_to_cpu(lmm->lmm_layout_gen);
@@ -1810,15 +1851,47 @@ int lod_verify_striping(struct lod_device *d, struct lod_object *lo,
        int     rc = 0;
        ENTRY;
 
        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;
 
        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);
        }
 
        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 &&
        if (magic != LOV_USER_MAGIC_V1 &&
            magic != LOV_USER_MAGIC_V3 &&
            magic != LOV_USER_MAGIC_SPECIFIC &&
index 0b4a789..9bd60af 100644 (file)
@@ -2578,7 +2578,7 @@ static int lod_comp_md_size(struct lod_object *lo, bool is_dir)
        int magic, size = 0, i;
        struct lod_layout_component *comp_entries;
        __u16 comp_cnt;
        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;
 
        if (is_dir) {
                comp_cnt = lo->ldo_def_striping->lds_def_comp_cnt;
@@ -2589,8 +2589,11 @@ static int lod_comp_md_size(struct lod_object *lo, bool is_dir)
                comp_cnt = lo->ldo_comp_cnt;
                comp_entries = lo->ldo_comp_entries;
                is_composite = lo->ldo_is_composite;
                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(comp_cnt != 0 && comp_entries != NULL);
        if (is_composite) {
@@ -3940,7 +3943,7 @@ static int lod_generate_and_set_lovea(const struct lu_env *env,
 
        LASSERT(lo);
 
 
        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);
                lod_striping_free(env, lo);
                rc = lod_sub_xattr_del(env, next, XATTR_NAME_LOV, th);
                RETURN(rc);
@@ -5256,7 +5259,8 @@ int lod_striped_create(const struct lu_env *env, struct dt_object *dt,
        int     rc = 0, i, j;
        ENTRY;
 
        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) {
 
        mirror_id = 0; /* non-flr file's mirror_id is 0 */
        if (lo->ldo_mirror_count > 1) {
@@ -6819,6 +6823,41 @@ static int lod_object_init(const struct lu_env *env, struct lu_object *lo,
 
 /**
  *
 
 /**
  *
+ * 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
  * Release resources associated with striping.
  *
  * If the object is striped (regular or directory), then release
@@ -6832,7 +6871,10 @@ void lod_striping_free_nolock(const struct lu_env *env, struct lod_object *lo)
        struct lod_layout_component *lod_comp;
        int i, j;
 
        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);
 
                LASSERT(lo->ldo_comp_entries == NULL);
                LASSERT(lo->ldo_dir_stripes_allocated > 0);
 
index 3749b38..934d6bc 100644 (file)
@@ -1835,7 +1835,7 @@ int lod_use_defined_striping(const struct lu_env *env,
        magic = le32_to_cpu(v1->lmm_magic) & ~LOV_MAGIC_DEFINED;
 
        if (magic != LOV_MAGIC_V1 && magic != LOV_MAGIC_V3 &&
        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) {
                GOTO(unlock, rc = -EINVAL);
 
        if (magic == LOV_MAGIC_COMP_V1) {
@@ -1847,6 +1847,32 @@ int lod_use_defined_striping(const struct lu_env *env,
                mo->ldo_flr_state = le16_to_cpu(comp_v1->lcm_flags) &
                                        LCM_FL_FLR_MASK;
                mo->ldo_is_composite = 1;
                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;
        } else {
                mo->ldo_is_composite = 0;
                comp_cnt = 1;
@@ -1951,16 +1977,17 @@ int lod_qos_parse_config(const struct lu_env *env, struct lod_object *lo,
                         const struct lu_buf *buf)
 {
        struct lod_layout_component *lod_comp;
                         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)
        ENTRY;
 
        if (buf == NULL || buf->lb_buf == NULL || buf->lb_len == 0)
@@ -1972,7 +1999,10 @@ int lod_qos_parse_config(const struct lu_env *env, struct lod_object *lo,
                                    def_pool, sizeof(def_pool));
 
        /* free default striping info */
                                    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)
 
        rc = lod_verify_striping(d, lo, buf, false);
        if (rc)
@@ -1981,6 +2011,7 @@ int lod_qos_parse_config(const struct lu_env *env, struct lod_object *lo,
        v3 = buf->lb_buf;
        v1 = buf->lb_buf;
        comp_v1 = buf->lb_buf;
        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)) {
        magic = v1->lmm_magic;
 
        if (unlikely(le32_to_cpu(magic) & LOV_MAGIC_DEFINED)) {
@@ -2016,6 +2047,22 @@ int lod_qos_parse_config(const struct lu_env *env, struct lod_object *lo,
                /* fall trhough */
        case LOV_USER_MAGIC_COMP_V1:
                break;
                /* 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);
        default:
                CERROR("%s: unrecognized magic %X\n",
                       lod2obd(d)->obd_name, magic);
index b28ff35..179e450 100644 (file)
@@ -122,6 +122,7 @@ enum lov_layout_type {
        LLT_EMPTY,      /** empty file without body (mknod + truncate) */
        LLT_RELEASED,   /** file with no objects (data in HSM) */
        LLT_COMP,       /** support composite layout */
        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
 };
 
        LLT_NR
 };
 
@@ -134,6 +135,8 @@ static inline char *llt2str(enum lov_layout_type llt)
                return "RELEASED";
        case LLT_COMP:
                return "COMPOSITE";
                return "RELEASED";
        case LLT_COMP:
                return "COMPOSITE";
+       case LLT_FOREIGN:
+               return "FOREIGN";
        case LLT_NR:
                LBUG();
        }
        case LLT_NR:
                LBUG();
        }
@@ -623,9 +626,12 @@ int   lov_page_init_empty (const struct lu_env *env, struct cl_object *obj,
                           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);
                           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 *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);
 struct lu_object *lovsub_object_alloc(const struct lu_env *env,
                                       const struct lu_object_header *hdr,
                                       struct lu_device *dev);
index b44cbd1..49673c5 100644 (file)
@@ -132,10 +132,16 @@ void lsm_free(struct lov_stripe_md *lsm)
        unsigned int i;
        size_t lsm_size;
 
        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);
 }
 
        OBD_FREE(lsm, lsm_size);
 }
 
@@ -510,16 +516,64 @@ const struct lsm_operations lsm_comp_md_v1_ops = {
        .lsm_unpackmd         = lsm_unpackmd_comp_md_v1,
 };
 
        .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;
 
 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);
 
               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];
 
        for (i = 0; i < lsm->lsm_entry_count; i++) {
                struct lov_stripe_md_entry *lse = lsm->lsm_entries[i];
 
index 05bfc12..33aa806 100644 (file)
@@ -75,9 +75,14 @@ struct lov_stripe_md {
        spinlock_t      lsm_lock;
        pid_t           lsm_lock_owner; /* debugging */
 
        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 ost_id   lsm_oi;
        u32             lsm_magic;
        u32             lsm_layout_gen;
@@ -88,6 +93,8 @@ struct lov_stripe_md {
        struct lov_stripe_md_entry *lsm_entries[];
 };
 
        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;
 static inline bool lsme_inited(const struct lov_stripe_md_entry *lsme)
 {
        return lsme->lsme_flags & LCME_FL_INIT;
@@ -113,6 +120,9 @@ static inline size_t lov_comp_md_size(const struct lov_stripe_md *lsm)
                return lov_mds_md_size(lsm->lsm_entries[0]->lsme_stripe_count,
                                       lsm->lsm_entries[0]->lsme_magic);
 
                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);
        LASSERT(lsm->lsm_magic == LOV_MAGIC_COMP_V1);
 
        size = sizeof(struct lov_comp_md_v1);
@@ -164,6 +174,7 @@ struct lsm_operations {
 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_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) {
 static inline const struct lsm_operations *lsm_op_find(int magic)
 {
        switch (magic) {
@@ -173,6 +184,8 @@ static inline const struct lsm_operations *lsm_op_find(int magic)
                return &lsm_v3_ops;
        case LOV_MAGIC_COMP_V1:
                return &lsm_comp_md_v1_ops;
                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;
        default:
                CERROR("unrecognized lsm_magic %08x\n", magic);
                return NULL;
index 200f943..884f744 100644 (file)
@@ -811,10 +811,25 @@ static int lov_init_released(const struct lu_env *env,
        return 0;
 }
 
        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)
 {
 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;
 
        lov_layout_wait(env, lov);
        return 0;
@@ -936,6 +951,23 @@ static int lov_print_released(const struct lu_env *env, void *cookie,
        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).
 /**
  * Implements cl_object_operations::coo_attr_get() method for an object
  * without stripes (LLT_EMPTY layout type).
@@ -1034,6 +1066,16 @@ const static struct lov_layout_operations lov_dispatch[] = {
                .llo_io_init   = lov_io_init_composite,
                .llo_getattr   = lov_attr_get_composite,
        },
                .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,
+       },
 };
 
 /**
 };
 
 /**
@@ -1065,6 +1107,9 @@ static enum lov_layout_type lov_type(struct lov_stripe_md *lsm)
            lsm->lsm_magic == LOV_MAGIC_COMP_V1)
                return LLT_COMP;
 
            lsm->lsm_magic == LOV_MAGIC_COMP_V1)
                return LLT_COMP;
 
+       if (lsm->lsm_magic == LOV_MAGIC_FOREIGN)
+               return LLT_FOREIGN;
+
        return LLT_EMPTY;
 }
 
        return LLT_EMPTY;
 }
 
@@ -2136,6 +2181,8 @@ int lov_read_and_clear_async_rc(struct cl_object *clob)
                }
                case LLT_RELEASED:
                case LLT_EMPTY:
                }
                case LLT_RELEASED:
                case LLT_EMPTY:
+                       /* fall through */
+               case LLT_FOREIGN:
                        break;
                default:
                        LBUG();
                        break;
                default:
                        LBUG();
index 3fe19fe..23ffe6c 100644 (file)
@@ -183,6 +183,28 @@ ssize_t lov_lsm_pack_v1v3(const struct lov_stripe_md *lsm, void *buf,
        RETURN(lmm_size);
 }
 
        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)
 {
 ssize_t lov_lsm_pack(const struct lov_stripe_md *lsm, void *buf,
                     size_t buf_size)
 {
@@ -200,6 +222,9 @@ ssize_t lov_lsm_pack(const struct lov_stripe_md *lsm, void *buf,
        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_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);
        lmm_size = lov_comp_md_size(lsm);
        if (buf_size == 0)
                RETURN(lmm_size);
@@ -362,6 +387,7 @@ int lov_getstripe(const struct lu_env *env, struct lov_object *obj,
 {
        /* we use lov_user_md_v3 because it is larger than lov_user_md_v1 */
        struct lov_mds_md *lmmk, *lmm;
 {
        /* 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;
        struct lov_user_md_v1 lum;
        size_t lmmk_size;
        ssize_t lmm_size, lum_size = 0;
@@ -371,7 +397,8 @@ int lov_getstripe(const struct lu_env *env, struct lov_object *obj,
        ENTRY;
 
        if (lsm->lsm_magic != LOV_MAGIC_V1 && lsm->lsm_magic != LOV_MAGIC_V3 &&
        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);
                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);
@@ -405,6 +432,12 @@ int lov_getstripe(const struct lu_env *env, struct lov_object *obj,
                } 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_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);
                }
        }
 
                }
        }
 
@@ -412,8 +445,9 @@ int lov_getstripe(const struct lu_env *env, struct lov_object *obj,
         * Legacy appication passes limited buffer, we need to figure out
         * the user buffer size by the passed in lmm_stripe_count.
         */
         * 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)
 
        if (lum.lmm_magic == LOV_USER_MAGIC_V1 ||
            lum.lmm_magic == LOV_USER_MAGIC_V3)
index 34fbc66..cea48a1 100644 (file)
@@ -148,6 +148,13 @@ int lov_page_init_empty(const struct lu_env *env, struct cl_object *obj,
        RETURN(0);
 }
 
        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);
 bool lov_page_is_empty(const struct cl_page *page)
 {
        const struct cl_page_slice *slice = cl_page_at(page, &lov_device_type);
index 1b36587..5d4b23e 100644 (file)
@@ -75,6 +75,7 @@ THETESTS += listxattr_size_check check_fhandle_syscalls badarea_io
 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 += 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
 
 if TESTS
 if MPITESTS
diff --git a/lustre/tests/create_foreign_file.c b/lustre/tests/create_foreign_file.c
new file mode 100644 (file)
index 0000000..e270135
--- /dev/null
@@ -0,0 +1,89 @@
+#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;
+}
diff --git a/lustre/tests/parse_foreign_file.c b/lustre/tests/parse_foreign_file.c
new file mode 100644 (file)
index 0000000..5b2cddd
--- /dev/null
@@ -0,0 +1,100 @@
+#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;
+}
index 3058f44..27bbb01 100644 (file)
@@ -5574,6 +5574,92 @@ test_37()
 }
 run_test 37 "LFSCK must skip a ORPHAN"
 
 }
 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}
 
 # restore MDS/OST size
 MDSSIZE=${SAVED_MDSSIZE}
index d78ded2..4befadb 100755 (executable)
@@ -2405,6 +2405,101 @@ test_27I() {
 }
 run_test 27I "check that root dir striping does not break parent dir one"
 
 }
 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
 # createtest also checks that device nodes are created and
 # then visible correctly (#2091)
 test_28() { # bug 2091
index d2413ff..b897626 100644 (file)
@@ -321,6 +321,7 @@ command_t cmdlist[] = {
         "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")
         "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"
         "                 <directory|filename>\n"
         " or\n"
         "To add component(s) to an existing composite file:\n"
@@ -340,7 +341,11 @@ command_t cmdlist[] = {
         "\tcomp_id:     Unique component ID to delete\n"
         "\tcomp_flags:  'init' indicating all instantiated components\n"
         "\t             '^init' indicating all uninstantiated components\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"
        {"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"
@@ -398,6 +403,7 @@ command_t cmdlist[] = {
         "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
         "     [[!] --projid <projid>]\n"
         "     [[!] --layout|-L released,raid0,mdt]\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"
         "     [[!] --component-count [+-]<comp_cnt>]\n"
         "     [[!] --component-start [+-]N[kMGTPE]]\n"
         "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
@@ -631,6 +637,20 @@ static int check_hashtype(const char *hashtype)
        return 0;
 }
 
        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";
 
 
 static const char *error_loc = "syserror";
 
@@ -2559,11 +2579,13 @@ enum {
        LFS_COMP_ADD_OPT,
        LFS_COMP_NO_VERIFY_OPT,
        LFS_PROJID_OPT,
        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_MIRROR_ID_OPT,
        LFS_MIRROR_STATE_OPT,
        LFS_LAYOUT_COPY,
        LFS_MIRROR_INDEX_OPT,
+       LFS_LAYOUT_FOREIGN_OPT,
+       LFS_MODE_OPT,
 };
 
 /* functions */
 };
 
 /* functions */
@@ -2585,6 +2607,7 @@ static int lfs_setstripe_internal(int argc, char **argv,
        unsigned long long               size_units = 1;
        bool                             migrate_mode = false;
        bool                             migrate_mdt_mode = false;
        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                             migration_block = false;
        __u64                            migration_flags = 0;
        __u32                            tgts[LOV_MAX_STRIPE_COUNT] = { 0 };
@@ -2605,6 +2628,12 @@ static int lfs_setstripe_internal(int argc, char **argv,
        bool from_yaml = false;
        bool from_copy = false;
        char *template = NULL;
        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 }, */
 
        struct option long_opts[] = {
 /* find { .val = '0',  .name = "null",         .has_arg = no_argument }, */
@@ -2631,10 +2660,14 @@ static int lfs_setstripe_internal(int argc, char **argv,
                                                .has_arg = no_argument},
        { .val = LFS_COMP_NO_VERIFY_OPT,
                        .name = "no-verify",    .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},
                        .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_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},
        { .val = LFS_LAYOUT_COPY,
                        .name = "copy",         .has_arg = required_argument},
        { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
@@ -2683,6 +2716,7 @@ static int lfs_setstripe_internal(int argc, char **argv,
 /* find        { .val = 'U',   .name = "user",         .has_arg = required_argument }*/
        /* --verbose is only valid in migrate mode */
        { .val = 'v',   .name = "verbose",      .has_arg = no_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 } };
 
        { .val = 'y',   .name = "yaml",         .has_arg = required_argument },
        { .name = NULL } };
 
@@ -2690,12 +2724,13 @@ static int lfs_setstripe_internal(int argc, char **argv,
 
        migrate_mode = (opc == SO_MIGRATE);
        mirror_mode = (opc == SO_MIRROR_CREATE || opc == SO_MIRROR_EXTEND);
 
        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,
 
        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. */
                switch (c) {
                case 0:
                        /* Long options. */
@@ -2740,8 +2775,20 @@ static int lfs_setstripe_internal(int argc, char **argv,
                                goto usage_error;
                        }
                        break;
                                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",
 
                        if (!mirror_mode || !last_mirror) {
                                fprintf(stderr, "error: %s: --flags must be specified with --mirror-count|-N option\n",
@@ -2750,11 +2797,11 @@ static int lfs_setstripe_internal(int argc, char **argv,
                        }
 
                        result = comp_str2flags(optarg, &last_mirror->m_flags,
                        }
 
                        result = comp_str2flags(optarg, &last_mirror->m_flags,
-                                               &flags);
+                                               &neg_flags);
                        if (result != 0)
                                goto usage_error;
 
                        if (result != 0)
                                goto usage_error;
 
-                       if (flags) {
+                       if (neg_flags) {
                                fprintf(stderr, "%s: inverted flags are not supported\n",
                                        progname);
                                result = -EINVAL;
                                fprintf(stderr, "%s: inverted flags are not supported\n",
                                        progname);
                                result = -EINVAL;
@@ -2769,6 +2816,37 @@ static int lfs_setstripe_internal(int argc, char **argv,
                        }
                        break;
                }
                        }
                        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;
                case LFS_LAYOUT_COPY:
                        from_copy = true;
                        template = optarg;
@@ -3050,6 +3128,9 @@ static int lfs_setstripe_internal(int argc, char **argv,
                        migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
                        migration_flags = MIGRATION_VERBOSE;
                        break;
                        migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
                        migration_flags = MIGRATION_VERBOSE;
                        break;
+               case 'x':
+                       xattr = optarg;
+                       break;
                case 'y':
                        from_yaml = true;
                        template = optarg;
                case 'y':
                        from_yaml = true;
                        template = optarg;
@@ -3069,6 +3150,29 @@ static int lfs_setstripe_internal(int argc, char **argv,
                goto usage_error;
        }
 
                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",
        if (mirror_mode && mirror_count == 0) {
                fprintf(stderr,
                        "error: %s: --mirror-count|-N option is required\n",
@@ -3364,7 +3468,14 @@ static int lfs_setstripe_internal(int argc, char **argv,
                                              NULL);
                } else if (layout != NULL) {
                        result = lfs_component_create(fname, O_CREAT | O_WRONLY,
                                              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;
                        if (result >= 0) {
                                close(result);
                                result = 0;
@@ -3372,7 +3483,7 @@ static int lfs_setstripe_internal(int argc, char **argv,
                } else {
                        result = llapi_file_open_param(fname,
                                                       O_CREAT | O_WRONLY,
                } else {
                        result = llapi_file_open_param(fname,
                                                       O_CREAT | O_WRONLY,
-                                                      0666, param);
+                                                      mode, param);
                        if (result >= 0) {
                                close(result);
                                result = 0;
                        if (result >= 0) {
                                close(result);
                                result = 0;
@@ -3386,6 +3497,9 @@ static int lfs_setstripe_internal(int argc, char **argv,
                }
        }
 
                }
        }
 
+       if (mode_opt != NULL && previous_umask != 0)
+               umask(previous_umask);
+
        free(param);
        free(migrate_mdt_param.fp_lmv_md);
        llapi_layout_free(layout);
        free(param);
        free(migrate_mdt_param.fp_lmv_md);
        llapi_layout_free(layout);
@@ -3572,6 +3686,8 @@ static int lfs_find(int argc, char **argv)
                                                .has_arg = required_argument },
        { .val = LFS_MIRROR_STATE_OPT,
                        .name = "mirror-state", .has_arg = required_argument },
                                                .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 },
        { .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 },
@@ -3780,6 +3896,30 @@ static int lfs_find(int argc, char **argv)
                                param.fp_mirror_state = state;
                        }
                        break;
                                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;
                 case 'c':
                         if (optarg[0] == '+') {
                                param.fp_stripe_count_sign = -1;
index c5098fd..7063285 100644 (file)
@@ -86,6 +86,14 @@ char *mdt_hash_name[] = { "none",
                          LMV_HASH_NAME_ALL_CHARS,
                          LMV_HASH_NAME_FNV_1A_64 };
 
                          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 */
 void llapi_msg_set_level(int level)
 {
         /* ensure level is in the good range */
@@ -798,6 +806,76 @@ int llapi_file_open(const char *name, int flags, int mode,
                                     stripe_pattern, NULL);
 }
 
                                     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)
 {
 int llapi_file_create(const char *name, unsigned long long stripe_size,
                       int stripe_offset, int stripe_count, int stripe_pattern)
 {
@@ -3519,6 +3597,53 @@ static void lov_dump_plain_user_lmm(struct find_param *param, char *path,
        }
 }
 
        }
 }
 
+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 *)&param->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)
 {
 static void llapi_lov_dump_user_lmm(struct find_param *param, char *path,
                                    enum lov_dump_flags flags)
 {
@@ -3540,6 +3665,9 @@ static void llapi_lov_dump_user_lmm(struct find_param *param, char *path,
        case LOV_USER_MAGIC_SPECIFIC:
                lov_dump_plain_user_lmm(param, path, flags);
                break;
        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];
        case LMV_MAGIC_V1:
        case LMV_USER_MAGIC: {
                char pool_name[LOV_MAXPOOLNAME + 1];
@@ -3707,6 +3835,10 @@ static int check_obd_match(struct find_param *param)
        if (!S_ISREG(st->st_mode))
                return 0;
 
        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) {
        /* Only those files should be accepted, which have a
         * stripe on the specified OST. */
        if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
@@ -3789,6 +3921,9 @@ static int find_check_stripe_size(struct find_param *param)
        struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
        int ret, i, count = 1;
 
        struct lov_user_md_v1 *v1 = &param->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;
        if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
                comp_v1 = (struct lov_comp_md_v1 *)v1;
                count = comp_v1->lcm_entry_count;
@@ -3818,6 +3953,9 @@ static __u32 find_get_stripe_count(struct find_param *param)
        int i, count = 1;
        __u32 stripe_count = 0;
 
        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 (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
                comp_v1 = (struct lov_comp_md_v1 *)v1;
                count = comp_v1->lcm_entry_count;
@@ -3850,6 +3988,10 @@ static int find_check_layout(struct find_param *param)
                if (comp_v1)
                        v1 = lov_comp_entry(comp_v1, i);
 
                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;
 
                if (v1->lmm_pattern == LOV_PATTERN_INVALID)
                        continue;
 
@@ -3870,6 +4012,29 @@ static int find_check_layout(struct find_param *param)
        return -1;
 }
 
        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 *)&param->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;
 static int find_check_pool(struct find_param *param)
 {
        struct lov_comp_md_v1 *comp_v1 = NULL;
@@ -3890,6 +4055,9 @@ static int find_check_pool(struct find_param *param)
                if (comp_v1 != NULL)
                        v1 = lov_comp_entry(comp_v1, i);
 
                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) &&
                if (((v1->lmm_magic == LOV_USER_MAGIC_V1) &&
                     (param->fp_poolname[0] == '\0')) ||
                    ((v1->lmm_magic == LOV_USER_MAGIC_V3) &&
@@ -3917,6 +4085,9 @@ static int find_check_comp_options(struct find_param *param)
        struct lov_comp_md_entry_v1 *entry;
        int i, ret = 0;
 
        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 {
        if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
                comp_v1 = (struct lov_comp_md_v1 *)v1;
        } else {
@@ -4025,7 +4196,7 @@ static bool find_check_lmm_info(struct find_param *param)
               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_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;
 }
               param->fp_check_mirror_state ||
               param->fp_check_projid;
 }
@@ -4201,6 +4372,12 @@ static int cb_find_init(char *path, DIR *parent, DIR **dirp,
                 }
         }
 
                 }
         }
 
+       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)
        if (param->fp_check_stripe_size) {
                decision = find_check_stripe_size(param);
                if (decision == -1)
index 45b8927..bdb832a 100644 (file)
@@ -6,6 +6,7 @@
        liblustreapi_initialized;
        l_ioctl;
        mdt_hash_name;
        liblustreapi_initialized;
        l_ioctl;
        mdt_hash_name;
+       lov_foreign_type;
        Parser_*;
        register_ioc_*;
     local:
        Parser_*;
        register_ioc_*;
     local: