.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 ,
.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
.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
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()
-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
.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() ,
/**
* 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
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().
}
/**
+ * 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
+ * \param[in] flags bitwise-or'd flags to control the behavior
*
* \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 llapi_layout *layout;
+ struct llapi_layout *layout = NULL;
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;
+ }
+
+#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 (lov_xattr_size <= 0) {
errno = EINVAL;
- goto error;
+ goto out_layout;
}
} else {
errno = EOPNOTSUPP;
- goto error;
+ goto out_layout;
}
if (ent_count == 0) {
errno = EINVAL;
- goto error;
+ goto out_layout;
}
v1 = (struct lov_user_md *)lum;
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;
layout->llot_cur_comp = comp;
}
+out:
+ if (lum != lov_xattr)
+ free(lum);
return layout;
-error:
+out_layout:
llapi_layout_free(layout);
- return NULL;
+ layout = NULL;
+ goto out;
}
/**
}
/**
- * 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
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
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;