+ /* Extent sanity checks */
+ /* Must set previous component extent before adding another */
+ if (prev && prev->llc_extent.e_start == 0 &&
+ prev->llc_extent.e_end == 0) {
+ args->lsa_rc = LSE_SET_COMP_START;
+ goto out_err;
+ }
+
+ if (!args->lsa_incomplete) {
+ /* Components followed by extension space (extendable
+ * components) must be zero length before initialization.
+ * (Except for first comp, which will be initialized on
+ * creation). */
+ if (next && (next->llc_flags & LCME_FL_EXTENSION) &&
+ !first_comp && !(comp->llc_flags & LCME_FL_INIT) &&
+ comp->llc_extent.e_start != comp->llc_extent.e_end) {
+ args->lsa_rc = LSE_NOT_ZERO_LENGTH_EXTENDABLE;
+ goto out_err;
+ }
+
+ /* End must come after end of previous comp */
+ if (prev && comp->llc_extent.e_end < prev->llc_extent.e_end) {
+ args->lsa_rc = LSE_END_NOT_GREATER;
+ goto out_err;
+ }
+
+ /* Components not followed by ext space must have length > 0. */
+ if (comp->llc_extent.e_start == comp->llc_extent.e_end &&
+ (next == NULL || !(next->llc_flags & LCME_FL_EXTENSION))) {
+ args->lsa_rc = LSE_ZERO_LENGTH_NORMAL;
+ goto out_err;
+ }
+
+ /* The component end must be aligned by the stripe size */
+ if ((comp->llc_flags & LCME_FL_EXTENSION) &&
+ (prev->llc_stripe_size != LLAPI_LAYOUT_DEFAULT)) {
+ if (comp->llc_extent.e_end != LUSTRE_EOF &&
+ comp->llc_extent.e_end % prev->llc_stripe_size) {
+ args->lsa_rc = LSE_ALIGN_END;
+ goto out_err;
+ }
+ if ((comp->llc_stripe_size * SEL_UNIT_SIZE) %
+ prev->llc_stripe_size) {
+ args->lsa_rc = LSE_ALIGN_EXT;
+ goto out_err;
+ }
+ } else if (!(comp->llc_flags & LCME_FL_EXTENSION) &&
+ (comp->llc_stripe_size != LLAPI_LAYOUT_DEFAULT)) {
+ if (comp->llc_extent.e_end != LUSTRE_EOF &&
+ comp->llc_extent.e_end !=
+ comp->llc_extent.e_start &&
+ comp->llc_extent.e_end % comp->llc_stripe_size) {
+ args->lsa_rc = LSE_ALIGN_END;
+ goto out_err;
+ }
+ }
+ }
+
+ /* Components must have start == prev->end */
+ if (prev && comp->llc_extent.e_start != 0 &&
+ comp->llc_extent.e_start != prev->llc_extent.e_end) {
+ args->lsa_rc = LSE_NOT_ADJACENT_PREV;
+ goto out_err;
+ }
+
+ /* Components must have start <= end */
+ if (comp->llc_extent.e_start > comp->llc_extent.e_end) {
+ args->lsa_rc = LSE_START_GT_END;
+ goto out_err;
+ }
+
+ if (args->lsa_fsname[0] != '\0') {
+ int i, rc = 0;
+
+ if (comp->llc_pattern & LLAPI_LAYOUT_SPECIFIC) {
+ assert(comp->llc_stripe_count <=
+ comp->llc_objects_count);
+
+ for (i = 0; i < comp->llc_stripe_count && rc == 0; i++){
+ if (comp->llc_objects[i].l_ost_idx ==
+ LLAPI_LAYOUT_IDX_MAX) {
+ args->lsa_rc = -1;
+ goto out_err;
+ }
+ rc = llapi_layout_search_ost(
+ comp->llc_objects[i].l_ost_idx,
+ comp->llc_pool_name, args->lsa_fsname);
+ }
+ } else if (comp->llc_stripe_offset != LLAPI_LAYOUT_DEFAULT) {
+ rc = llapi_layout_search_ost(
+ comp->llc_stripe_offset,
+ comp->llc_pool_name, args->lsa_fsname);
+ }
+ if (rc) {
+ args->lsa_rc = LSE_UNKNOWN_OST;
+ goto out_err;
+ }
+ }
+
+ return LLAPI_LAYOUT_ITER_CONT;
+
+out_err:
+ errno = errno ? errno : EINVAL;
+ return LLAPI_LAYOUT_ITER_STOP;
+}
+
+/* Print explanation of layout error */
+void llapi_layout_sanity_perror(int error)
+{
+ if (error >= LSE_LAST || error < 0) {
+ fprintf(stdout, "Invalid layout, unrecognized error: %d\n",
+ error);
+ } else {
+ fprintf(stdout, "Invalid layout: %s\n",
+ llapi_layout_strerror[error]);
+ }
+}
+
+/* Walk a layout and enforce sanity checks that apply to > 1 component
+ *
+ * The core idea here is that of sanity checking individual tokens vs semantic
+ * checking.
+ * We cannot check everything at the individual component level ('token'),
+ * instead we must check whether or not the full layout has a valid meaning.
+ *
+ * An example of a component level check is "is stripe size valid?". That is
+ * handled when setting stripe size.
+ *
+ * An example of a layout level check is "are the extents of these components
+ * valid when adjacent to one another", or "can we set these flags on adjacent
+ * components"?
+ *
+ * \param[in] layout component layout list.
+ * \param[in] fname file the layout to be checked for
+ * \param[in] incomplete if layout is complete or not - some checks can
+ * only be done on complete layouts.
+ * \param[in] flr set when this is called from FLR mirror create
+ *
+ * \retval 0, success, positive: various errors, see
+ * llapi_layout_sanity_perror, -1, failure
+ */
+int llapi_layout_sanity(struct llapi_layout *layout,
+ const char *fname,
+ bool incomplete,
+ bool flr)
+{
+ struct llapi_layout_sanity_args args = { { 0 } };
+ struct llapi_layout_comp *curr;
+ int rc = 0;
+
+ if (!layout)
+ return 0;
+
+ curr = layout->llot_cur_comp;
+ if (!curr)
+ return 0;
+
+ /* Make sure we are on a Lustre file system */
+ if (fname) {
+ rc = llapi_search_fsname(fname, args.lsa_fsname);
+ if (rc) {
+ llapi_error(LLAPI_MSG_ERROR, rc,
+ "'%s' is not on a Lustre filesystem",
+ fname);
+ return rc;
+ }
+ }
+
+ /* Set up args */
+ args.lsa_rc = 0;
+ args.lsa_flr = flr;
+ args.lsa_incomplete = incomplete;
+
+ /* When we modify an existing layout, this tells us if it's FLR */
+ if (mirror_id_of(curr->llc_id) > 0)
+ args.lsa_flr = true;
+
+ errno = 0;
+ rc = llapi_layout_comp_iterate(layout,
+ llapi_layout_sanity_cb,
+ &args);
+ if (errno == ENOENT)
+ errno = 0;
+
+ if (rc != LLAPI_LAYOUT_ITER_CONT)
+ rc = args.lsa_rc;
+
+ layout->llot_cur_comp = curr;
+
+ return rc;
+}
+
+int llapi_layout_dom_size(struct llapi_layout *layout, uint64_t *size)
+{
+ uint64_t pattern, start;
+ int rc;
+
+ if (!layout || !llapi_layout_is_composite(layout)) {
+ *size = 0;
+ return 0;
+ }
+
+ rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
+ if (rc)
+ return -errno;
+
+ rc = llapi_layout_pattern_get(layout, &pattern);
+ if (rc)
+ return -errno;
+
+ if (pattern != LOV_PATTERN_MDT && pattern != LLAPI_LAYOUT_MDT) {
+ *size = 0;
+ return 0;
+ }
+
+ rc = llapi_layout_comp_extent_get(layout, &start, size);
+ if (rc)
+ return -errno;
+ if (start)
+ return -ERANGE;
+ return 0;
+}
+
+int lov_comp_md_size(struct lov_comp_md_v1 *lcm)
+{
+ if (lcm->lcm_magic == LOV_MAGIC_V1 || lcm->lcm_magic == LOV_MAGIC_V3) {
+ struct lov_user_md *lum = (void *)lcm;
+
+ return lov_user_md_size(lum->lmm_stripe_count, lum->lmm_magic);
+ }
+
+ if (lcm->lcm_magic == LOV_MAGIC_FOREIGN) {
+ struct lov_foreign_md *lfm = (void *)lcm;
+
+ return lfm->lfm_length;
+ }
+
+ if (lcm->lcm_magic != LOV_MAGIC_COMP_V1)
+ return -EOPNOTSUPP;
+
+ return lcm->lcm_size;
+}
+
+int llapi_get_lum_file_fd(int dir_fd, const char *fname, __u64 *valid,
+ lstatx_t *statx, struct lov_user_md *lum,
+ size_t lumsize)
+{
+ struct lov_user_mds_data *lmd;
+ char buf[65536 + offsetof(typeof(*lmd), lmd_lmm)];
+ int parent_fd = -1;
+ int rc;
+
+ if (lum && lumsize < sizeof(*lum))
+ return -EINVAL;
+
+ /* If a file name is provided, it is relative to the parent directory */
+ if (fname) {
+ parent_fd = dir_fd;
+ dir_fd = -1;
+ }
+
+ lmd = (struct lov_user_mds_data *)buf;
+ rc = get_lmd_info_fd(fname, parent_fd, dir_fd, buf, sizeof(buf),
+ GET_LMD_INFO);
+ if (rc)
+ return rc;
+
+ if (valid)
+ *valid = lmd->lmd_flags;
+
+ if (statx)
+ memcpy(statx, &lmd->lmd_stx, sizeof(*statx));
+
+ if (lum) {
+ if (lmd->lmd_lmmsize > lumsize)
+ return -EOVERFLOW;
+ memcpy(lum, &lmd->lmd_lmm, lmd->lmd_lmmsize);
+ }
+
+ return 0;
+}
+
+int llapi_get_lum_dir_fd(int dir_fd, __u64 *valid, lstatx_t *statx,
+ struct lov_user_md *lum, size_t lumsize)
+{
+ return llapi_get_lum_file_fd(dir_fd, NULL, valid, statx, lum, lumsize);
+}
+
+int llapi_get_lum_file(const char *path, __u64 *valid, lstatx_t *statx,
+ struct lov_user_md *lum, size_t lumsize)
+{
+ char parent[PATH_MAX];
+ const char *fname;
+ char *tmp;
+ int offset;
+ int dir_fd;
+ int rc;
+
+ tmp = strrchr(path, '/');
+ if (!tmp) {
+ strncpy(parent, ".", sizeof(parent) - 1);
+ offset = -1;
+ } else {
+ strncpy(parent, path, tmp - path);
+ offset = tmp - path - 1;
+ parent[tmp - path] = 0;
+ }
+
+ fname = path;
+ if (offset >= 0)
+ fname += offset + 2;
+
+ dir_fd = open(parent, O_RDONLY);
+ if (dir_fd < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", path);
+ return rc;
+ }
+
+ rc = llapi_get_lum_file_fd(dir_fd, fname, valid, statx, lum, lumsize);
+ close(dir_fd);
+ return rc;
+}
+
+int llapi_get_lum_dir(const char *path, __u64 *valid, lstatx_t *statx,
+ struct lov_user_md *lum, size_t lumsize)
+{
+ int dir_fd;
+ int rc;
+
+ dir_fd = open(path, O_RDONLY);
+ if (dir_fd < 0) {
+ rc = -errno;
+ llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", path);
+ return rc;
+ }
+
+ rc = llapi_get_lum_dir_fd(dir_fd, valid, statx, lum, lumsize);
+ close(dir_fd);
+ return rc;