From 6669e463d7eb7eb1768ba5927d96447724ff525f Mon Sep 17 00:00:00 2001 From: Li Xi Date: Tue, 19 Feb 2019 10:33:20 +0800 Subject: [PATCH] LU-11974 llapi: improve llapi_layout_get_by_xattr(3) API 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. Lustre-change: https://review.whamcloud.com/34276 Lustre-commit: 89e43812da871bb560f3c50a0c36713ea7788e0a Change-Id: I9fbf0f0ba66660d2f382fb20b03f069c1a7afad5 Signed-off-by: Li Xi Reviewed-by: Andreas Dilger Reviewed-by: Jian Yu Signed-off-by: Minh Diep Reviewed-on: https://review.whamcloud.com/34463 Reviewed-by: Wang Shilong Tested-by: Jenkins Tested-by: Maloo --- lustre/doc/llapi_layout_get_by_fd.3 | 40 ++++++- lustre/include/lustre/lustreapi.h | 30 ++++- lustre/utils/liblustreapi_layout.c | 220 ++++++++++++++++++++---------------- 3 files changed, 187 insertions(+), 103 deletions(-) diff --git a/lustre/doc/llapi_layout_get_by_fd.3 b/lustre/doc/llapi_layout_get_by_fd.3 index bb4451e..dfd0500 100644 --- a/lustre/doc/llapi_layout_get_by_fd.3 +++ b/lustre/doc/llapi_layout_get_by_fd.3 @@ -6,8 +6,6 @@ obtain the layout of a Lustre file .nf .B #include .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 , @@ -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_xattr(void *"lov_xattr , +.BI " ssize_t " lov_xattr_size , +.BI " uint32_t " xattr_flags ); .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 -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() , @@ -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 +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 @@ -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. +.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() , diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index 7a29c13..d2a3608 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -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 - * 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 @@ -577,6 +577,32 @@ struct llapi_layout *llapi_layout_get_by_fid(const char *path, 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(). diff --git a/lustre/utils/liblustreapi_layout.c b/lustre/utils/liblustreapi_layout.c index f84b3b3..c5a268a 100644 --- a/lustre/utils/liblustreapi_layout.c +++ b/lustre/utils/liblustreapi_layout.c @@ -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 + * \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; @@ -396,16 +501,16 @@ struct llapi_layout *llapi_layout_get_by_xattr(const void *lov_xattr, 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; @@ -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) - goto error; + goto out_layout; 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; } +out: + if (lum != lov_xattr) + free(lum); return layout; -error: +out_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 @@ -873,14 +911,6 @@ struct llapi_layout *llapi_layout_get_by_fd(int fd, uint32_t flags) 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 @@ -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 (!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; -- 1.8.3.1