- struct option long_opts[] = {
- /* valid only in migrate mode */
- {"block", no_argument, 0, 'b'},
-#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
- /* This formerly implied "stripe-count", but was explicitly
- * made "stripe-count" for consistency with other options,
- * and to separate it from "mdt-count" when DNE arrives. */
- {"count", required_argument, 0, 'c'},
-#endif
- {"stripe-count", required_argument, 0, 'c'},
- {"stripe_count", required_argument, 0, 'c'},
- {"delete", no_argument, 0, 'd'},
-#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
- /* This formerly implied "stripe-index", but was explicitly
- * made "stripe-index" for consistency with other options,
- * and to separate it from "mdt-index" when DNE arrives. */
- {"index", required_argument, 0, 'i'},
-#endif
- {"stripe-index", required_argument, 0, 'i'},
- {"stripe_index", required_argument, 0, 'i'},
-#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
- /* This formerly implied "stripe-index", but was confusing
- * with "file offset" (which will eventually be needed for
- * with different layouts by offset), so deprecate it. */
- {"offset", required_argument, 0, 'o'},
-#endif
- {"pool", required_argument, 0, 'p'},
-#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
- /* This formerly implied "--stripe-size", but was confusing
- * with "lfs find --size|-s", which means "file size", so use
- * the consistent "--stripe-size|-S" for all commands. */
- {"size", required_argument, 0, 's'},
-#endif
- {"stripe-size", required_argument, 0, 'S'},
- {"stripe_size", required_argument, 0, 'S'},
- {0, 0, 0, 0}
+ if (arg == NULL)
+ return -EINVAL;
+
+ end_of_loop = false;
+ while (!end_of_loop) {
+ int start_index;
+ int end_index;
+ int i;
+ char *endptr = NULL;
+
+ rc = -EINVAL;
+
+ ptr = strchrnul(arg, ',');
+
+ end_of_loop = *ptr == '\0';
+ *ptr = '\0';
+
+ start_index = strtol(arg, &endptr, 0);
+ if (endptr == arg) /* no data at all */
+ break;
+ if (*endptr != '-' && *endptr != '\0') /* has invalid data */
+ break;
+ if (start_index < 0)
+ break;
+
+ end_index = start_index;
+ if (*endptr == '-') {
+ end_index = strtol(endptr + 1, &endptr, 0);
+ if (*endptr != '\0')
+ break;
+ if (end_index < start_index)
+ break;
+ }
+
+ for (i = start_index; i <= end_index && slots > 0; i++) {
+ int j;
+
+ /* remove duplicate */
+ for (j = 0; j < offset; j++) {
+ if (osts[j] == i)
+ break;
+ }
+ if (j == offset) { /* no duplicate */
+ osts[nr++] = i;
+ --slots;
+ }
+ }
+ if (slots == 0 && i < end_index)
+ break;
+
+ *ptr = ',';
+ arg = ++ptr;
+ offset = nr;
+ rc = 0;
+ }
+ if (!end_of_loop && ptr != NULL)
+ *ptr = ',';
+
+ return rc < 0 ? rc : nr;
+}
+
+static int verify_pool_name(char *prog_name, char *pool_name)
+{
+ char *ptr;
+
+ if (pool_name == NULL)
+ return 0;
+
+ ptr = strchr(pool_name, '.');
+ if (ptr != NULL && ptr == pool_name) {
+ fprintf(stderr, "error: %s: fsname is empty in pool name '%s'\n",
+ prog_name, pool_name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct lfs_setstripe_args {
+ unsigned long long lsa_comp_end;
+ unsigned long long lsa_stripe_size;
+ int lsa_stripe_count;
+ int lsa_stripe_off;
+ __u32 lsa_comp_flags;
+ int lsa_nr_osts;
+ __u32 *lsa_osts;
+ char *lsa_pool_name;
+};
+
+static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
+{
+ memset(lsa, 0, sizeof(*lsa));
+ lsa->lsa_stripe_off = -1;
+}
+
+static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
+{
+ return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
+ lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
+ lsa->lsa_comp_end != 0);
+}
+
+static int comp_args_to_layout(struct llapi_layout **composite,
+ struct lfs_setstripe_args *lsa)
+{
+ struct llapi_layout *layout = *composite;
+ uint64_t prev_end = 0;
+ int i = 0, rc;
+
+ if (layout == NULL) {
+ layout = llapi_layout_alloc();
+ if (layout == NULL) {
+ fprintf(stderr, "Alloc llapi_layout failed. %s\n",
+ strerror(errno));
+ return -ENOMEM;
+ }
+ *composite = layout;
+ } else {
+ uint64_t start;
+
+ /* Get current component extent, current component
+ * must be the tail component. */
+ rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
+ if (rc) {
+ fprintf(stderr, "Get comp extent failed. %s\n",
+ strerror(errno));
+ return rc;
+ }
+
+ rc = llapi_layout_comp_add(layout);
+ if (rc) {
+ fprintf(stderr, "Add component failed. %s\n",
+ strerror(errno));
+ return rc;
+ }
+ }
+
+ rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
+ if (rc) {
+ fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
+ prev_end, lsa->lsa_comp_end, strerror(errno));
+ return rc;
+ }
+
+ if (lsa->lsa_stripe_size != 0) {
+ rc = llapi_layout_stripe_size_set(layout,
+ lsa->lsa_stripe_size);
+ if (rc) {
+ fprintf(stderr, "Set stripe size %llu failed. %s\n",
+ lsa->lsa_stripe_size, strerror(errno));
+ return rc;
+ }
+ }
+
+ if (lsa->lsa_stripe_count != 0) {
+ rc = llapi_layout_stripe_count_set(layout,
+ lsa->lsa_stripe_count == -1 ?
+ LLAPI_LAYOUT_WIDE :
+ lsa->lsa_stripe_count);
+ if (rc) {
+ fprintf(stderr, "Set stripe count %d failed. %s\n",
+ lsa->lsa_stripe_count, strerror(errno));
+ return rc;
+ }
+ }
+
+ if (lsa->lsa_pool_name != NULL) {
+ rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
+ if (rc) {
+ fprintf(stderr, "Set pool name: %s failed. %s\n",
+ lsa->lsa_pool_name, strerror(errno));
+ return rc;
+ }
+ }
+
+ if (lsa->lsa_nr_osts > 0) {
+ if (lsa->lsa_stripe_count > 0 &&
+ lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
+ fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
+ lsa->lsa_stripe_count, lsa->lsa_nr_osts);
+ return -EINVAL;
+ }
+ for (i = 0; i < lsa->lsa_nr_osts; i++) {
+ rc = llapi_layout_ost_index_set(layout, i,
+ lsa->lsa_osts[i]);
+ if (rc)
+ break;
+ }
+ } else if (lsa->lsa_stripe_off != -1) {
+ rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
+ }
+ if (rc) {
+ fprintf(stderr, "Set ost index %d failed. %s\n",
+ i, strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+/* In 'lfs setstripe --component-add' mode, we need to fetch the extent
+ * end of the last component in the existing file, and adjust the
+ * first extent start of the components to be added accordingly. */
+static int adjust_first_extent(char *fname, struct llapi_layout *layout)
+{
+ struct llapi_layout *head;
+ uint64_t start, end, stripe_size, prev_end = 0;
+ int rc;
+
+ if (layout == NULL)
+ return -EINVAL;
+
+ errno = 0;
+ head = llapi_layout_get_by_path(fname, 0);
+ if (head == NULL) {
+ fprintf(stderr, "Read layout from %s failed. %s\n",
+ fname, strerror(errno));
+ return -EINVAL;
+ } else if (errno == ENODATA) {
+ /* file without LOVEA, this component-add will be turned
+ * into a component-create. */
+ llapi_layout_free(head);
+ return -ENODATA;
+ } else if (!llapi_layout_is_composite(head)) {
+ fprintf(stderr, "'%s' isn't a composite file.\n",
+ fname);
+ llapi_layout_free(head);
+ return -EINVAL;
+ }
+
+ rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
+ if (rc) {
+ fprintf(stderr, "Get prev extent failed. %s\n",
+ strerror(errno));
+ llapi_layout_free(head);
+ return rc;
+ }
+
+ llapi_layout_free(head);
+
+ /* Make sure we use the first component of the layout to be added. */
+ rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
+ if (rc < 0) {
+ fprintf(stderr, "Move component cursor failed. %s\n",
+ strerror(errno));
+ return rc;
+ }
+
+ rc = llapi_layout_comp_extent_get(layout, &start, &end);
+ if (rc) {
+ fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
+ return rc;
+ }
+
+ if (start > prev_end || end <= prev_end) {
+ fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
+ "adjacent with the existing file extent end: %lu\n",
+ start, end, prev_end);
+ return -EINVAL;
+ }
+
+ rc = llapi_layout_stripe_size_get(layout, &stripe_size);
+ if (rc) {
+ fprintf(stderr, "Get stripe size failed. %s\n",
+ strerror(errno));
+ return rc;
+ }
+
+ if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
+ (prev_end & (stripe_size - 1))) {
+ fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
+ stripe_size, prev_end);
+ return -EINVAL;
+ }
+
+ rc = llapi_layout_comp_extent_set(layout, prev_end, end);
+ if (rc) {
+ fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
+ prev_end, end, strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+static inline bool comp_flags_is_neg(__u32 flags)
+{
+ return flags & LCME_FL_NEG;
+}
+
+static inline void comp_flags_set_neg(__u32 *flags)
+{
+ *flags |= LCME_FL_NEG;
+}
+
+static inline void comp_flags_clear_neg(__u32 *flags)
+{
+ *flags &= ~LCME_FL_NEG;
+}
+
+static int comp_str2flags(__u32 *flags, char *string)
+{
+ char *name;
+ __u32 neg_flags = 0;
+
+ if (string == NULL)
+ return -EINVAL;
+
+ *flags = 0;
+ for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
+ bool found = false;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
+ __u32 comp_flag = comp_flags_table[i].cfn_flag;
+ const char *comp_name = comp_flags_table[i].cfn_name;
+
+ if (strcmp(name, comp_name) == 0) {
+ *flags |= comp_flag;
+ found = true;
+ } else if (strncmp(name, "^", 1) == 0 &&
+ strcmp(name + 1, comp_name) == 0) {
+ neg_flags |= comp_flag;
+ found = true;
+ }
+ }
+ if (!found) {
+ llapi_printf(LLAPI_MSG_ERROR, "Component flag "
+ "'%s' is not supported.\n", name);
+ return -EINVAL;
+ }
+ }
+
+ if (*flags == 0 && neg_flags == 0)
+ return -EINVAL;
+ /* don't support mixed flags for now */
+ if (*flags && neg_flags)
+ return -EINVAL;
+
+ if (neg_flags) {
+ *flags = neg_flags;
+ comp_flags_set_neg(flags);
+ }
+
+ return 0;
+}
+
+static inline bool arg_is_eof(char *arg)
+{
+ return !strncmp(arg, "-1", strlen("-1")) ||
+ !strncmp(arg, "EOF", strlen("EOF")) ||
+ !strncmp(arg, "eof", strlen("eof"));
+}
+
+enum {
+ LFS_POOL_OPT = 3,
+ LFS_COMP_COUNT_OPT,
+ LFS_COMP_START_OPT,
+ LFS_COMP_FLAGS_OPT,
+ LFS_COMP_DEL_OPT,
+ LFS_COMP_SET_OPT,
+ LFS_COMP_ADD_OPT,
+ LFS_PROJID_OPT,
+};
+
+/* functions */
+static int lfs_setstripe(int argc, char **argv)
+{
+ struct lfs_setstripe_args lsa;
+ struct llapi_stripe_param *param = NULL;
+ struct find_param migrate_mdt_param = {
+ .fp_max_depth = -1,
+ .fp_mdt_index = -1,