Whamcloud - gitweb
LU-11974 llapi: improve llapi_layout_get_by_xattr(3) API 76/34276/8
authorLi Xi <lixi@ddn.com>
Tue, 19 Feb 2019 02:33:20 +0000 (10:33 +0800)
committerOleg Drokin <green@whamcloud.com>
Fri, 8 Mar 2019 21:48:55 +0000 (21:48 +0000)
llapi_layout_get_by_xattr() assumes that the lum has already
been properly swapped by llapi_layout_swab_lov_user_md().
However, llapi_layout_swab_lov_user_md() function is not
exported, so external tool won't be able to use it.

Instead of exporting a lot of APIs, this patch include the
swab functions into llapi_layout_get_by_xattr() and add an
argument flags to the API.

Change-Id: I9fbf0f0ba66660d2f382fb20b03f069c1a7afad5
Signed-off-by: Li Xi <lixi@ddn.com>
Reviewed-on: https://review.whamcloud.com/34276
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Jian Yu <yujian@whamcloud.com>
Tested-by: Jenkins
Tested-by: Maloo <maloo@whamcloud.com>
lustre/doc/llapi_layout_get_by_fd.3
lustre/include/lustre/lustreapi.h
lustre/utils/liblustreapi_layout.c

index bb4451e..dfd0500 100644 (file)
@@ -6,8 +6,6 @@ obtain the layout of a Lustre file
 .nf
 .B #include <lustre/lustreapi.h>
 .PP
 .nf
 .B #include <lustre/lustreapi.h>
 .PP
-.BI "struct llapi_layout *llapi_layout_get_by_xattr(const void *"lov_xattr ",
-.BI "                                               ssize_t " lov_xattr_size );
 .BI "struct llapi_layout *llapi_layout_get_by_fd(int "fd ", uint32_t " flags );
 .PP
 .BI "struct llapi_layout *llapi_layout_get_by_fid(const char *"lustre_path ,
 .BI "struct llapi_layout *llapi_layout_get_by_fd(int "fd ", uint32_t " flags );
 .PP
 .BI "struct llapi_layout *llapi_layout_get_by_fid(const char *"lustre_path ,
@@ -16,6 +14,10 @@ obtain the layout of a Lustre file
 .PP
 .BI "struct llapi_layout *llapi_layout_get_by_path(const char *"path ,
 .BI "                                              uint32_t " flags );
 .PP
 .BI "struct llapi_layout *llapi_layout_get_by_path(const char *"path ,
 .BI "                                              uint32_t " flags );
+.PP
+.BI "struct llapi_layout *llapi_layout_get_by_xattr(void *"lov_xattr ,
+.BI "                                               ssize_t " lov_xattr_size ,
+.BI "                                               uint32_t " xattr_flags );
 .fi
 .SH DESCRIPTION
 .PP
 .fi
 .SH DESCRIPTION
 .PP
@@ -46,7 +48,10 @@ For
 .BR llapi_layout_get_by_xattr() ,
 .I lov_xattr
 is a Lustre layout extended attribute (LOV EA) from a file or directory in
 .BR llapi_layout_get_by_xattr() ,
 .I lov_xattr
 is a Lustre layout extended attribute (LOV EA) from a file or directory in
-a Lustre filesystem.
+a Lustre filesystem. The
+.I lov_xattr
+should be the raw xattr without being byte-swapped, since this function will
+swap it properly.
 .PP
 For
 .BR llapi_layout_get_by_fd() ,
 .PP
 For
 .BR llapi_layout_get_by_fd() ,
@@ -76,13 +81,17 @@ argument that names a file or directory in a Lustre filesystem.
 .PP
 Zero or more flags may be bitwise-or'd together in
 .I flags
 .PP
 Zero or more flags may be bitwise-or'd together in
 .I flags
+or
+.I xattr_flags
 to control how a layout is retrieved.  Currently
 .B llapi_layout_get_by_path()
 accepts only one flag, and
 .B llapi_layout_get_by_fd()
 and
 .B llapi_layout_get_by_fid()
 to control how a layout is retrieved.  Currently
 .B llapi_layout_get_by_path()
 accepts only one flag, and
 .B llapi_layout_get_by_fd()
 and
 .B llapi_layout_get_by_fid()
-do not accept any flags. The list of flags is as follows:
+do not accept any flags. The list of flags that can be used in
+.I flags
+is as follows:
 .TP 5
 .SM LAYOUT_GET_EXPECTED
 Unspecified attribute values are replaced by the literal default values
 .TP 5
 .SM LAYOUT_GET_EXPECTED
 Unspecified attribute values are replaced by the literal default values
@@ -117,6 +126,29 @@ since stripe size is unspecified, while
 .B llapi_layout_get_by_path(D, LAYOUT_GET_EXPECTED)
 reports the literal value 1048576.  Both forms report a stripe count
 of 2, since that attribute is specified.
 .B llapi_layout_get_by_path(D, LAYOUT_GET_EXPECTED)
 reports the literal value 1048576.  Both forms report a stripe count
 of 2, since that attribute is specified.
+.PP
+The list of flags that can be used in
+.I xattr_flags
+is as follows:
+.TP 5
+.SM LLAPI_LXF_CHECK
+If the
+.B LLAPI_LXF_CHECK
+flag is set, this function will check whether the objects count in lum
+is consistent with the stripe count in lum. This check only apply to
+regular file, so
+.B LLAPI_LXF_CHECK
+flag should be cleared if the xattr belongs to a directory.
+.TP
+.SM LLAPI_LXF_COPY
+If the
+.B LLAPI_LXF_COPY
+flag is set, this function will use a temporary buffer for byte swapping
+when necessary, leaving
+.I lov_xattr
+untouched. Otherwise, the byte swapping will be done to the
+.I lov_xattr
+buffer directly.
 .SH RETURN VALUES
 .LP
 .BR llapi_layout_get_by_fd() ,
 .SH RETURN VALUES
 .LP
 .BR llapi_layout_get_by_fd() ,
index 7a29c13..d2a3608 100644 (file)
@@ -565,8 +565,8 @@ struct llapi_layout *llapi_layout_get_by_fd(int fd, uint32_t flags);
 
 /**
  * Return a pointer to a newly-allocated opaque data type containing the
 
 /**
  * Return a pointer to a newly-allocated opaque data type containing the
- * layout for the file associated with Lustre file identifier string
- * \a fidstr.  The string \a path must name a path within the
+ * layout for the file associated with Lustre file identifier
+ * \a fid.  The string \a path must name a path within the
  * filesystem that contains the file being looked up, such as the
  * filesystem root.  The returned pointer should be freed with
  * llapi_layout_free() when it is no longer needed.  Failure is
  * filesystem that contains the file being looked up, such as the
  * filesystem root.  The returned pointer should be freed with
  * llapi_layout_free() when it is no longer needed.  Failure is
@@ -577,6 +577,32 @@ struct llapi_layout *llapi_layout_get_by_fid(const char *path,
                                             const struct lu_fid *fid,
                                             uint32_t flags);
 
                                             const struct lu_fid *fid,
                                             uint32_t flags);
 
+enum llapi_layout_xattr_flags {
+       LLAPI_LXF_CHECK = 0x0001,
+       LLAPI_LXF_COPY  = 0x0002,
+};
+
+/**
+ * Return a pointer to a newly-allocated opaque data type containing the
+ * layout for the file associated with extended attribute \a lov_xattr.  The
+ * length of the extended attribute is \a lov_xattr_size. The \a lov_xattr
+ * should be raw xattr without being swapped, since this function will swap it
+ * properly. Thus, \a lov_xattr will be modified during the process. If the
+ * \a LLAPI_LXF_CHECK flag of \a flags is set, this function will check whether
+ * the objects count in lum is consistent with the stripe count in lum. This
+ * check only apply to regular file, so \a LLAPI_LXF_CHECK flag should be
+ * cleared if the xattr belongs to a directory. If the \a LLAPI_LXF_COPY flag
+ * of \a flags is set, this function will use a temporary buffer for byte
+ * swapping when necessary, leaving \a lov_xattr untouched. Otherwise, the byte
+ * swapping will be done to the \a lov_xattr buffer directly.  The returned
+ * pointer should be freed with llapi_layout_free() when it is no longer
+ * needed.  Failure is  * indicated with a NULL return value and an appropriate
+ * error code stored in errno.
+ */
+struct llapi_layout *llapi_layout_get_by_xattr(void *lov_xattr,
+                                              ssize_t lov_xattr_size,
+                                              uint32_t flags);
+
 /**
  * Allocate a new layout. Use this when creating a new file with
  * llapi_layout_file_create().
 /**
  * Allocate a new layout. Use this when creating a new file with
  * llapi_layout_file_create().
index 591946e..b967356 100644 (file)
@@ -357,29 +357,134 @@ struct llapi_layout *llapi_layout_alloc(void)
 }
 
 /**
 }
 
 /**
+ * Check if the given \a lum_size is large enough to hold the required
+ * fields in \a lum.
+ *
+ * \param[in] lum      the struct lov_user_md to check
+ * \param[in] lum_size the number of bytes in \a lum
+ *
+ * \retval true                the \a lum_size is too small
+ * \retval false       the \a lum_size is large enough
+ */
+static bool llapi_layout_lum_truncated(struct lov_user_md *lum, size_t lum_size)
+{
+       uint32_t magic;
+
+       if (lum_size < sizeof(lum->lmm_magic))
+               return true;
+
+       if (lum->lmm_magic == LOV_MAGIC_V1 ||
+           lum->lmm_magic == __swab32(LOV_MAGIC_V1))
+               magic = LOV_MAGIC_V1;
+       else if (lum->lmm_magic == LOV_MAGIC_V3 ||
+                lum->lmm_magic == __swab32(LOV_MAGIC_V3))
+               magic = LOV_MAGIC_V3;
+       else if (lum->lmm_magic == LOV_MAGIC_COMP_V1 ||
+                lum->lmm_magic == __swab32(LOV_MAGIC_COMP_V1))
+               magic = LOV_MAGIC_COMP_V1;
+       else
+               return true;
+
+       if (magic == LOV_MAGIC_V1 || magic == LOV_MAGIC_V3)
+               return lum_size < lov_user_md_size(0, magic);
+       else
+               return lum_size < sizeof(struct lov_comp_md_v1);
+}
+
+/* Verify if the objects count in lum is consistent with the
+ * stripe count in lum. It applies to regular file only. */
+static bool llapi_layout_lum_valid(struct lov_user_md *lum, int lum_size)
+{
+       struct lov_comp_md_v1 *comp_v1 = NULL;
+       int i, ent_count, obj_count;
+
+       if (lum->lmm_magic == LOV_MAGIC_COMP_V1) {
+               comp_v1 = (struct lov_comp_md_v1 *)lum;
+               ent_count = comp_v1->lcm_entry_count;
+       } else if (lum->lmm_magic == LOV_MAGIC_V1 ||
+                  lum->lmm_magic == LOV_MAGIC_V3) {
+               ent_count = 1;
+       } else {
+               return false;
+       }
+
+       for (i = 0; i < ent_count; i++) {
+               if (comp_v1) {
+                       lum = (struct lov_user_md *)((char *)comp_v1 +
+                               comp_v1->lcm_entries[i].lcme_offset);
+                       lum_size = comp_v1->lcm_entries[i].lcme_size;
+               }
+               obj_count = llapi_layout_objects_in_lum(lum, lum_size);
+
+               if (comp_v1) {
+                       if (!(comp_v1->lcm_entries[i].lcme_flags &
+                                LCME_FL_INIT) && obj_count != 0)
+                               return false;
+               } else if (obj_count != lum->lmm_stripe_count) {
+                       return false;
+               }
+       }
+       return true;
+}
+
+/**
  * Convert the data from a lov_user_md to a newly allocated llapi_layout.
  * The caller is responsible for freeing the returned pointer.
  *
  * \param[in] lov_xattr                LOV user metadata xattr to copy data from
  * \param[in] lov_xattr_size   size the lov_xattr_size passed in
  * Convert the data from a lov_user_md to a newly allocated llapi_layout.
  * The caller is responsible for freeing the returned pointer.
  *
  * \param[in] lov_xattr                LOV user metadata xattr to copy data from
  * \param[in] lov_xattr_size   size the lov_xattr_size passed in
+ * \param[in] flags            bitwise-or'd flags to control the behavior
  *
  * \retval             valid llapi_layout pointer on success
  * \retval             NULL if memory allocation fails
  */
  *
  * \retval             valid llapi_layout pointer on success
  * \retval             NULL if memory allocation fails
  */
-struct llapi_layout *llapi_layout_get_by_xattr(const void *lov_xattr,
-                                              ssize_t lov_xattr_size)
+struct llapi_layout *llapi_layout_get_by_xattr(void *lov_xattr,
+                                              ssize_t lov_xattr_size,
+                                              uint32_t flags)
 {
 {
-       const struct lov_user_md *lum = lov_xattr;
+       struct lov_user_md *lum = lov_xattr;
        struct lov_comp_md_v1 *comp_v1 = NULL;
        struct lov_comp_md_entry_v1 *ent;
        struct lov_user_md *v1;
        struct lov_comp_md_v1 *comp_v1 = NULL;
        struct lov_comp_md_entry_v1 *ent;
        struct lov_user_md *v1;
-       struct llapi_layout *layout;
+       struct llapi_layout *layout = NULL;
        struct llapi_layout_comp *comp;
        int i, ent_count = 0, obj_count;
 
        struct llapi_layout_comp *comp;
        int i, ent_count = 0, obj_count;
 
-       layout = __llapi_layout_alloc();
-       if (layout == NULL)
+       if (lov_xattr == NULL || lov_xattr_size <= 0) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       /* Return an error if we got back a partial layout. */
+       if (llapi_layout_lum_truncated(lov_xattr, lov_xattr_size)) {
+               errno = ERANGE;
                return NULL;
                return NULL;
+       }
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+       if (flags & LLAPI_LXF_COPY) {
+               lum = malloc(lov_xattr_size);
+               if (lum == NULL) {
+                       errno = ENOMEM;
+                       return NULL;
+               }
+               memcpy(lum, lov_xattr, lov_xattr_size);
+       }
+#endif
+
+       llapi_layout_swab_lov_user_md(lum, lov_xattr_size);
+
+       if ((flags & LLAPI_LXF_CHECK) &&
+           !llapi_layout_lum_valid(lum, lov_xattr_size)) {
+               errno = EBADSLT;
+               goto out;
+       }
+
+       layout = __llapi_layout_alloc();
+       if (layout == NULL) {
+               errno = ENOMEM;
+               goto out;
+       }
 
        if (lum->lmm_magic == LOV_MAGIC_COMP_V1) {
                comp_v1 = (struct lov_comp_md_v1 *)lum;
 
        if (lum->lmm_magic == LOV_MAGIC_COMP_V1) {
                comp_v1 = (struct lov_comp_md_v1 *)lum;
@@ -396,16 +501,16 @@ struct llapi_layout *llapi_layout_get_by_xattr(const void *lov_xattr,
 
                if (lov_xattr_size <= 0) {
                        errno = EINVAL;
 
                if (lov_xattr_size <= 0) {
                        errno = EINVAL;
-                       goto error;
+                       goto out_layout;
                }
        } else {
                errno = EOPNOTSUPP;
                }
        } else {
                errno = EOPNOTSUPP;
-               goto error;
+               goto out_layout;
        }
 
        if (ent_count == 0) {
                errno = EINVAL;
        }
 
        if (ent_count == 0) {
                errno = EINVAL;
-               goto error;
+               goto out_layout;
        }
 
        v1 = (struct lov_user_md *)lum;
        }
 
        v1 = (struct lov_user_md *)lum;
@@ -422,7 +527,7 @@ struct llapi_layout *llapi_layout_get_by_xattr(const void *lov_xattr,
                obj_count = llapi_layout_objects_in_lum(v1, lov_xattr_size);
                comp = __llapi_comp_alloc(obj_count);
                if (comp == NULL)
                obj_count = llapi_layout_objects_in_lum(v1, lov_xattr_size);
                comp = __llapi_comp_alloc(obj_count);
                if (comp == NULL)
-                       goto error;
+                       goto out_layout;
 
                if (ent != NULL) {
                        comp->llc_extent.e_start = ent->lcme_extent.e_start;
 
                if (ent != NULL) {
                        comp->llc_extent.e_start = ent->lcme_extent.e_start;
@@ -485,10 +590,14 @@ struct llapi_layout *llapi_layout_get_by_xattr(const void *lov_xattr,
                layout->llot_cur_comp = comp;
        }
 
                layout->llot_cur_comp = comp;
        }
 
+out:
+       if (lum != lov_xattr)
+               free(lum);
        return layout;
        return layout;
-error:
+out_layout:
        llapi_layout_free(layout);
        llapi_layout_free(layout);
-       return NULL;
+       layout = NULL;
+       goto out;
 }
 
 /**
 }
 
 /**
@@ -764,77 +873,6 @@ static bool is_any_specified(const struct llapi_layout *layout)
 }
 
 /**
 }
 
 /**
- * Check if the given \a lum_size is large enough to hold the required
- * fields in \a lum.
- *
- * \param[in] lum      the struct lov_user_md to check
- * \param[in] lum_size the number of bytes in \a lum
- *
- * \retval true                the \a lum_size is too small
- * \retval false       the \a lum_size is large enough
- */
-static bool llapi_layout_lum_truncated(struct lov_user_md *lum, size_t lum_size)
-{
-       uint32_t magic;
-
-       if (lum_size < sizeof(lum->lmm_magic))
-               return true;
-
-       if (lum->lmm_magic == LOV_MAGIC_V1 ||
-           lum->lmm_magic == __swab32(LOV_MAGIC_V1))
-               magic = LOV_MAGIC_V1;
-       else if (lum->lmm_magic == LOV_MAGIC_V3 ||
-                lum->lmm_magic == __swab32(LOV_MAGIC_V3))
-               magic = LOV_MAGIC_V3;
-       else if (lum->lmm_magic == LOV_MAGIC_COMP_V1 ||
-                lum->lmm_magic == __swab32(LOV_MAGIC_COMP_V1))
-               magic = LOV_MAGIC_COMP_V1;
-       else
-               return true;
-
-       if (magic == LOV_MAGIC_V1 || magic == LOV_MAGIC_V3)
-               return lum_size < lov_user_md_size(0, magic);
-       else
-               return lum_size < sizeof(struct lov_comp_md_v1);
-}
-
-/* Verify if the objects count in lum is consistent with the
- * stripe count in lum. It applies to regular file only. */
-static bool llapi_layout_lum_valid(struct lov_user_md *lum, int lum_size)
-{
-       struct lov_comp_md_v1 *comp_v1 = NULL;
-       int i, ent_count, obj_count;
-
-       if (lum->lmm_magic == LOV_MAGIC_COMP_V1) {
-               comp_v1 = (struct lov_comp_md_v1 *)lum;
-               ent_count = comp_v1->lcm_entry_count;
-       } else if (lum->lmm_magic == LOV_MAGIC_V1 ||
-                  lum->lmm_magic == LOV_MAGIC_V3) {
-               ent_count = 1;
-       } else {
-               return false;
-       }
-
-       for (i = 0; i < ent_count; i++) {
-               if (comp_v1) {
-                       lum = (struct lov_user_md *)((char *)comp_v1 +
-                               comp_v1->lcm_entries[i].lcme_offset);
-                       lum_size = comp_v1->lcm_entries[i].lcme_size;
-               }
-               obj_count = llapi_layout_objects_in_lum(lum, lum_size);
-
-               if (comp_v1) {
-                       if (!(comp_v1->lcm_entries[i].lcme_flags &
-                                LCME_FL_INIT) && obj_count != 0)
-                               return false;
-               } else if (obj_count != lum->lmm_stripe_count) {
-                       return false;
-               }
-       }
-       return true;
-}
-
-/**
  * Get the striping layout for the file referenced by file descriptor \a fd.
  *
  * If the filesystem does not support the "lustre." xattr namespace, the
  * Get the striping layout for the file referenced by file descriptor \a fd.
  *
  * If the filesystem does not support the "lustre." xattr namespace, the
@@ -873,14 +911,6 @@ struct llapi_layout *llapi_layout_get_by_fd(int fd, uint32_t flags)
                goto out;
        }
 
                goto out;
        }
 
-       /* Return an error if we got back a partial layout. */
-       if (llapi_layout_lum_truncated(lum, bytes_read)) {
-               errno = EINTR;
-               goto out;
-       }
-
-       llapi_layout_swab_lov_user_md(lum, bytes_read);
-
        /* Directories may have a positive non-zero lum->lmm_stripe_count
         * yet have an empty lum->lmm_objects array. For non-directories the
         * amount of data returned from the kernel must be consistent
        /* Directories may have a positive non-zero lum->lmm_stripe_count
         * yet have an empty lum->lmm_objects array. For non-directories the
         * amount of data returned from the kernel must be consistent
@@ -888,12 +918,8 @@ struct llapi_layout *llapi_layout_get_by_fd(int fd, uint32_t flags)
        if (fstat(fd, &st) < 0)
                goto out;
 
        if (fstat(fd, &st) < 0)
                goto out;
 
-       if (!S_ISDIR(st.st_mode) && !llapi_layout_lum_valid(lum, bytes_read)) {
-               errno = EINTR;
-               goto out;
-       }
-
-       layout = llapi_layout_get_by_xattr(lum, bytes_read);
+       layout = llapi_layout_get_by_xattr(lum, bytes_read,
+               S_ISDIR(st.st_mode) ? 0 : LLAPI_LXF_CHECK);
 out:
        free(lum);
        return layout;
 out:
        free(lum);
        return layout;