+ default:
+ fprintf(stderr, "%s %s: unrecognized option '%s'\n",
+ progname, argv[0], argv[optind - 1]);
+ goto usage_error;
+ }
+ }
+
+ fname = argv[optind];
+
+ if (optind == argc) {
+ fprintf(stderr, "%s %s: FILE must be specified\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (mirror_mode && mirror_count == 0) {
+ fprintf(stderr,
+ "error: %s: --mirror-count|-N option is required\n",
+ progname);
+ result = -EINVAL;
+ goto error;
+ }
+
+ if (mirror_mode) {
+ if (lsa.lsa_comp_end == 0)
+ lsa.lsa_comp_end = LUSTRE_EOF;
+ }
+
+ if (lsa.lsa_comp_end != 0) {
+ result = comp_args_to_layout(lpp, &lsa, true);
+ if (result)
+ goto error;
+ }
+
+ if (mirror_flags & MF_NO_VERIFY) {
+ if (opc != SO_MIRROR_EXTEND) {
+ fprintf(stderr,
+ "error: %s: --no-verify is valid only for lfs mirror extend command\n",
+ progname);
+ result = -EINVAL;
+ goto error;
+ } else if (!has_m_file) {
+ fprintf(stderr,
+ "error: %s: --no-verify must be specified with -f <victim_file> option\n",
+ progname);
+ result = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
+ * altered by user space tool, so we don't need to support the
+ * --component-set for this moment. */
+ if (comp_set && !comp_id) {
+ fprintf(stderr, "%s %s: --component-set doesn't have component-id set\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if ((delete + comp_set + comp_del + comp_add) > 1) {
+ fprintf(stderr,
+ "%s %s: options --component-set, --component-del, --component-add and -d are mutually exclusive\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
+ lsa.lsa_comp_flags != 0 || layout != NULL)) {
+ fprintf(stderr,
+ "%s %s: option -d is mutually exclusive with -s, -c, -o, -p, -I, -F and -E options\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if ((comp_set || comp_del) &&
+ (setstripe_args_specified(&lsa) || layout != NULL)) {
+ fprintf(stderr,
+ "%s %s: options --component-del and --component-set are mutually exclusive when used with -c, -E, -o, -p, or -s\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
+ fprintf(stderr,
+ "%s %s: options -I and -F are mutually exclusive when used with --component-del\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (comp_add || comp_del) {
+ struct stat st;
+
+ result = lstat(fname, &st);
+ if (result == 0 && S_ISDIR(st.st_mode)) {
+ fprintf(stderr,
+ "%s setstripe: cannot use --component-add or --component-del for directory\n",
+ progname);
+ goto usage_error;
+ }
+
+ if (mirror_mode) {
+ fprintf(stderr, "error: %s: can't use --component-add "
+ "or --component-del for mirror operation\n",
+ progname);
+ goto usage_error;
+ }
+ }
+
+ if (comp_add) {
+ if (layout == NULL) {
+ fprintf(stderr,
+ "%s %s: option -E must be specified with --component-add\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ result = adjust_first_extent(fname, layout);
+ if (result == -ENODATA)
+ comp_add = 0;
+ else if (result != 0)
+ goto error;
+ }
+
+ if (from_yaml && from_copy) {
+ fprintf(stderr,
+ "%s: can't specify --yaml and --copy together\n",
+ progname);
+ goto error;
+ }
+
+ if ((from_yaml || from_copy) &&
+ (setstripe_args_specified(&lsa) || layout != NULL)) {
+ fprintf(stderr, "error: %s: can't specify --yaml with "
+ "-c, -S, -i, -o, -p or -E options.\n",
+ argv[0]);
+ goto error;
+ }
+
+ if (mdt_idx_arg != NULL && optind > 3) {
+ fprintf(stderr,
+ "%s %s: option -m cannot be used with other options\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
+ fprintf(stderr,
+ "%s %s: options --non-block and --block are mutually exclusive\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (!comp_del && !comp_set && comp_id != 0) {
+ fprintf(stderr,
+ "%s %s: option -I can only be used with --component-del\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+
+ if (mdt_idx_arg != NULL) {
+ /* initialize migrate mdt parameters */
+ migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr, "%s %s: invalid MDT index '%s'\n",
+ progname, argv[0], mdt_idx_arg);
+ goto usage_error;
+ }
+ migrate_mdt_param.fp_migrate = 1;
+ } else if (layout == NULL) {
+ /* initialize stripe parameters */
+ param = calloc(1, offsetof(typeof(*param),
+ lsp_osts[lsa.lsa_nr_tgts]));
+ if (param == NULL) {
+ fprintf(stderr,
+ "%s %s: cannot allocate memory for parameters: %s\n",
+ progname, argv[0], strerror(ENOMEM));
+ result = -ENOMEM;
+ goto error;
+ }
+
+ if (lsa.lsa_stripe_size != LLAPI_LAYOUT_DEFAULT)
+ param->lsp_stripe_size = lsa.lsa_stripe_size;
+ if (lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT) {
+ if (lsa.lsa_stripe_count == LLAPI_LAYOUT_WIDE)
+ param->lsp_stripe_count = -1;
+ else
+ param->lsp_stripe_count = lsa.lsa_stripe_count;
+ }
+ if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
+ param->lsp_stripe_offset = -1;
+ else
+ param->lsp_stripe_offset = lsa.lsa_stripe_off;
+ param->lsp_pool = lsa.lsa_pool_name;
+ param->lsp_is_specific = false;
+ if (lsa.lsa_nr_tgts > 0) {
+ if (lsa.lsa_stripe_count > 0 &&
+ lsa.lsa_stripe_count != LLAPI_LAYOUT_DEFAULT &&
+ lsa.lsa_stripe_count != LLAPI_LAYOUT_WIDE &&
+ lsa.lsa_nr_tgts != lsa.lsa_stripe_count) {
+ fprintf(stderr, "error: %s: stripe count %lld "
+ "doesn't match the number of OSTs: %d\n"
+ , argv[0], lsa.lsa_stripe_count,
+ lsa.lsa_nr_tgts);
+ free(param);
+ goto usage_error;
+ }
+
+ param->lsp_is_specific = true;
+ param->lsp_stripe_count = lsa.lsa_nr_tgts;
+ memcpy(param->lsp_osts, osts,
+ sizeof(*osts) * lsa.lsa_nr_tgts);
+ }
+ }
+
+ if (from_yaml) {
+ /* generate a layout from a YAML template */
+ result = lfs_comp_create_from_yaml(template, &layout,
+ &lsa, osts);
+ if (result) {
+ fprintf(stderr, "error: %s: can't create composite "
+ "layout from template file %s\n",
+ argv[0], template);
+ goto error;
+ }
+ } else if (from_copy) {
+ layout = llapi_layout_get_by_path(template, 0);
+ if (layout == NULL) {
+ fprintf(stderr,
+ "%s: can't create composite layout from file %s.\n",
+ progname, template);
+ goto error;
+ }
+ }
+
+ for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
+ if (mdt_idx_arg != NULL) {
+ result = llapi_migrate_mdt(fname, &migrate_mdt_param);
+ } else if (migrate_mode) {
+ result = lfs_migrate(fname, migration_flags, param,
+ layout);
+ } else if (comp_set != 0) {
+ result = lfs_component_set(fname, comp_id,
+ lsa.lsa_comp_flags,
+ lsa.lsa_comp_neg_flags);
+ } else if (comp_del != 0) {
+ result = lfs_component_del(fname, comp_id,
+ lsa.lsa_comp_flags,
+ lsa.lsa_comp_neg_flags);
+ } else if (comp_add != 0) {
+ result = lfs_component_add(fname, layout);
+ } else if (opc == SO_MIRROR_CREATE) {
+ result = mirror_create(fname, mirror_list);
+ } else if (opc == SO_MIRROR_EXTEND) {
+ result = mirror_extend(fname, mirror_list,
+ mirror_flags);
+ } else if (opc == SO_MIRROR_SPLIT) {
+ if (mirror_id == 0) {
+ fprintf(stderr,
+ "%s %s: no mirror id is specified\n",
+ progname, argv[0]);
+ goto usage_error;
+ }
+ result = mirror_split(fname, mirror_id, mirror_flags,
+ has_m_file ? mirror_list->m_file :
+ NULL);
+ } else if (layout != NULL) {
+ result = lfs_component_create(fname, O_CREAT | O_WRONLY,
+ 0666, layout);
+ if (result >= 0) {
+ close(result);
+ result = 0;
+ }
+ } else {
+ result = llapi_file_open_param(fname,
+ O_CREAT | O_WRONLY,
+ 0666, param);
+ if (result >= 0) {
+ close(result);
+ result = 0;
+ }
+ }
+ if (result) {
+ /* Save the first error encountered. */
+ if (result2 == 0)
+ result2 = result;
+ continue;
+ }
+ }
+
+ free(param);
+ llapi_layout_free(layout);
+ lfs_mirror_list_free(mirror_list);
+ return result2;
+usage_error:
+ result = CMD_HELP;
+error:
+ llapi_layout_free(layout);
+ lfs_mirror_list_free(mirror_list);
+ return result;
+}
+
+static int lfs_poollist(int argc, char **argv)
+{
+ if (argc != 2)
+ return CMD_HELP;
+
+ return llapi_poollist(argv[1]);
+}
+
+static int set_time(time_t *time, time_t *set, char *str)
+{
+ time_t t;
+ int res = 0;
+
+ if (str[0] == '+')
+ res = 1;
+ else if (str[0] == '-')
+ res = -1;
+
+ if (res)
+ str++;
+
+ t = strtol(str, NULL, 0);
+ if (*time < t * 24 * 60 * 60) {
+ if (res)
+ str--;
+ fprintf(stderr, "Wrong time '%s' is specified.\n", str);
+ return INT_MAX;
+ }
+
+ *set = *time - t * 24 * 60 * 60;
+ return res;
+}
+static int name2uid(unsigned int *id, const char *name)
+{
+ struct passwd *passwd;
+
+ passwd = getpwnam(name);
+ if (passwd == NULL)
+ return -ENOENT;
+ *id = passwd->pw_uid;
+
+ return 0;
+}
+
+static int name2gid(unsigned int *id, const char *name)
+{
+ struct group *group;
+
+ group = getgrnam(name);
+ if (group == NULL)
+ return -ENOENT;
+ *id = group->gr_gid;
+
+ return 0;
+}
+
+static inline int name2projid(unsigned int *id, const char *name)
+{
+ return -ENOTSUP;
+}
+
+static int uid2name(char **name, unsigned int id)
+{
+ struct passwd *passwd;
+
+ passwd = getpwuid(id);
+ if (passwd == NULL)
+ return -ENOENT;
+ *name = passwd->pw_name;
+
+ return 0;
+}
+
+static inline int gid2name(char **name, unsigned int id)
+{
+ struct group *group;
+
+ group = getgrgid(id);
+ if (group == NULL)
+ return -ENOENT;
+ *name = group->gr_name;
+
+ return 0;
+}
+
+static int name2layout(__u32 *layout, char *name)
+{
+ char *ptr, *layout_name;
+
+ *layout = 0;
+ for (ptr = name; ; ptr = NULL) {
+ layout_name = strtok(ptr, ",");
+ if (layout_name == NULL)
+ break;
+ if (strcmp(layout_name, "released") == 0)
+ *layout |= LOV_PATTERN_F_RELEASED;
+ else if (strcmp(layout_name, "raid0") == 0)
+ *layout |= LOV_PATTERN_RAID0;
+ else if (strcmp(layout_name, "mdt") == 0)
+ *layout |= LOV_PATTERN_MDT;
+ else
+ return -1;
+ }
+ return 0;
+}
+
+static int lfs_find(int argc, char **argv)
+{
+ int c, rc;
+ int ret = 0;
+ time_t t;
+ struct find_param param = {
+ .fp_max_depth = -1,
+ .fp_quiet = 1,
+ };
+ struct option long_opts[] = {
+ { .val = 'A', .name = "atime", .has_arg = required_argument },
+ { .val = 'b', .name = "blocks", .has_arg = required_argument },
+ { .val = LFS_COMP_COUNT_OPT,
+ .name = "comp-count", .has_arg = required_argument },
+ { .val = LFS_COMP_COUNT_OPT,
+ .name = "component-count",
+ .has_arg = required_argument },
+ { .val = LFS_COMP_FLAGS_OPT,
+ .name = "comp-flags", .has_arg = required_argument },
+ { .val = LFS_COMP_FLAGS_OPT,
+ .name = "component-flags",
+ .has_arg = required_argument },
+ { .val = LFS_COMP_START_OPT,
+ .name = "comp-start", .has_arg = required_argument },
+ { .val = LFS_COMP_START_OPT,
+ .name = "component-start",
+ .has_arg = required_argument },
+ { .val = LFS_MIRROR_STATE_OPT,
+ .name = "mirror-state", .has_arg = required_argument },
+ { .val = 'c', .name = "stripe-count", .has_arg = required_argument },
+ { .val = 'c', .name = "stripe_count", .has_arg = required_argument },
+ { .val = 'C', .name = "ctime", .has_arg = required_argument },
+/* getstripe { .val = 'd', .name = "directory", .has_arg = no_argument }, */
+ { .val = 'D', .name = "maxdepth", .has_arg = required_argument },
+ { .val = 'E', .name = "comp-end", .has_arg = required_argument },
+ { .val = 'E', .name = "component-end",
+ .has_arg = required_argument },
+/* find { .val = 'F', .name = "fid", .has_arg = no_argument }, */
+ { .val = 'g', .name = "gid", .has_arg = required_argument },
+ { .val = 'G', .name = "group", .has_arg = required_argument },
+ { .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
+ { .val = 'i', .name = "stripe-index", .has_arg = required_argument },
+ { .val = 'i', .name = "stripe_index", .has_arg = required_argument },
+/* getstripe { .val = 'I', .name = "comp-id", .has_arg = required_argument }*/
+ { .val = 'L', .name = "layout", .has_arg = required_argument },
+ { .val = 'm', .name = "mdt", .has_arg = required_argument },
+ { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
+ { .val = 'm', .name = "mdt_index", .has_arg = required_argument },
+ { .val = 'M', .name = "mtime", .has_arg = required_argument },
+ { .val = 'n', .name = "name", .has_arg = required_argument },
+ { .val = 'N', .name = "mirror-count", .has_arg = required_argument },
+/* find { .val = 'o' .name = "or", .has_arg = no_argument }, like find(1) */
+ { .val = 'O', .name = "obd", .has_arg = required_argument },
+ { .val = 'O', .name = "ost", .has_arg = required_argument },
+ /* no short option for pool yet, can be 'p' after 2.18 */
+ { .val = LFS_POOL_OPT,
+ .name = "pool", .has_arg = required_argument },
+ { .val = '0', .name = "print0", .has_arg = no_argument },
+ { .val = 'P', .name = "print", .has_arg = no_argument },
+ { .val = LFS_PROJID_OPT,
+ .name = "projid", .has_arg = required_argument },
+/* getstripe { .val = 'q', .name = "quiet", .has_arg = no_argument }, */
+/* getstripe { .val = 'r', .name = "recursive", .has_arg = no_argument }, */
+/* getstripe { .val = 'R', .name = "raw", .has_arg = no_argument }, */
+ { .val = 's', .name = "size", .has_arg = required_argument },
+ { .val = 'S', .name = "stripe-size", .has_arg = required_argument },
+ { .val = 'S', .name = "stripe_size", .has_arg = required_argument },
+ { .val = 't', .name = "type", .has_arg = required_argument },
+ { .val = 'T', .name = "mdt-count", .has_arg = required_argument },
+ { .val = 'u', .name = "uid", .has_arg = required_argument },
+ { .val = 'U', .name = "user", .has_arg = required_argument },
+/* getstripe { .val = 'v', .name = "verbose", .has_arg = no_argument }, */
+/* getstripe { .val = 'y', .name = "yaml", .has_arg = no_argument }, */
+ { .name = NULL } };
+ int pathstart = -1;
+ int pathend = -1;
+ int neg_opt = 0;
+ time_t *xtime;
+ int *xsign;
+ int isoption;
+ char *endptr;
+
+ time(&t);
+
+ /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
+ while ((c = getopt_long_only(argc, argv,
+ "-0A:b:c:C:D:E:g:G:H:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:v",
+ long_opts, NULL)) >= 0) {
+ xtime = NULL;
+ xsign = NULL;
+ if (neg_opt)
+ --neg_opt;
+ /* '!' is part of option */
+ /* when getopt_long_only() finds a string which is not
+ * an option nor a known option argument it returns 1
+ * in that case if we already have found pathstart and pathend
+ * (i.e. we have the list of pathnames),
+ * the only supported value is "!"
+ */
+ isoption = (c != 1) || (strcmp(optarg, "!") == 0);
+ if (!isoption && pathend != -1) {
+ fprintf(stderr, "err: %s: filename|dirname must either "
+ "precede options or follow options\n",
+ argv[0]);
+ ret = CMD_HELP;
+ goto err;
+ }
+ if (!isoption && pathstart == -1)
+ pathstart = optind - 1;
+ if (isoption && pathstart != -1 && pathend == -1)
+ pathend = optind - 2;
+ switch (c) {
+ case 0:
+ /* Long options. */
+ break;
+ case 1:
+ /* unknown; opt is "!" or path component,
+ * checking done above.
+ */
+ if (strcmp(optarg, "!") == 0)
+ neg_opt = 2;
+ break;
+ case 'A':
+ xtime = ¶m.fp_atime;
+ xsign = ¶m.fp_asign;
+ param.fp_exclude_atime = !!neg_opt;
+ /* no break, this falls through to 'C' for ctime */
+ case 'C':
+ if (c == 'C') {
+ xtime = ¶m.fp_ctime;
+ xsign = ¶m.fp_csign;
+ param.fp_exclude_ctime = !!neg_opt;
+ }
+ /* no break, this falls through to 'M' for mtime */
+ case 'M':
+ if (c == 'M') {
+ xtime = ¶m.fp_mtime;
+ xsign = ¶m.fp_msign;
+ param.fp_exclude_mtime = !!neg_opt;
+ }
+ rc = set_time(&t, xtime, optarg);
+ if (rc == INT_MAX) {
+ ret = -1;
+ goto err;
+ }
+ if (rc)
+ *xsign = rc;
+ break;
+ case 'b':
+ if (optarg[0] == '+') {
+ param.fp_blocks_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_blocks_sign = 1;
+ optarg++;
+ }
+
+ param.fp_blocks_units = 1024;
+ ret = llapi_parse_size(optarg, ¶m.fp_blocks,
+ ¶m.fp_blocks_units, 0);
+ if (ret) {
+ fprintf(stderr, "error: bad blocks '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_blocks = 1;
+ param.fp_exclude_blocks = !!neg_opt;
+ break;
+ case LFS_COMP_COUNT_OPT:
+ if (optarg[0] == '+') {
+ param.fp_comp_count_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_comp_count_sign = 1;
+ optarg++;
+ }
+
+ param.fp_comp_count = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "error: bad component count "
+ "'%s'\n", optarg);
+ goto err;
+ }
+ param.fp_check_comp_count = 1;
+ param.fp_exclude_comp_count = !!neg_opt;
+ break;
+ case LFS_COMP_FLAGS_OPT:
+ rc = comp_str2flags(optarg, ¶m.fp_comp_flags,
+ ¶m.fp_comp_neg_flags);
+ if (rc) {
+ fprintf(stderr, "error: bad component flags "
+ "'%s'\n", optarg);
+ goto err;
+ }
+ param.fp_check_comp_flags = 1;
+ if (neg_opt) {
+ __u32 flags = param.fp_comp_neg_flags;
+ param.fp_comp_neg_flags = param.fp_comp_flags;
+ param.fp_comp_flags = flags;
+ }
+ break;
+ case LFS_COMP_START_OPT:
+ if (optarg[0] == '+') {
+ param.fp_comp_start_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_comp_start_sign = 1;
+ optarg++;
+ }
+
+ rc = llapi_parse_size(optarg, ¶m.fp_comp_start,
+ ¶m.fp_comp_start_units, 0);
+ if (rc) {
+ fprintf(stderr, "error: bad component start "
+ "'%s'\n", optarg);
+ goto err;
+ }
+ param.fp_check_comp_start = 1;
+ param.fp_exclude_comp_start = !!neg_opt;
+ break;
+ case LFS_MIRROR_STATE_OPT:
+ rc = mirror_str2state(optarg, ¶m.fp_mirror_state,
+ ¶m.fp_mirror_neg_state);
+ if (rc) {
+ fprintf(stderr,
+ "error: bad mirrored file state '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_mirror_state = 1;
+ if (neg_opt) {
+ __u16 state = param.fp_mirror_neg_state;
+ param.fp_mirror_neg_state =
+ param.fp_mirror_state;
+ param.fp_mirror_state = state;
+ }
+ break;
+ case 'c':
+ if (optarg[0] == '+') {
+ param.fp_stripe_count_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_stripe_count_sign = 1;
+ optarg++;
+ }
+
+ param.fp_stripe_count = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,"error: bad stripe_count '%s'\n",
+ optarg);
+ ret = -1;
+ goto err;
+ }
+ param.fp_check_stripe_count = 1;
+ param.fp_exclude_stripe_count = !!neg_opt;
+ break;
+ case 'D':
+ param.fp_max_depth = strtol(optarg, 0, 0);
+ break;
+ case 'E':
+ if (optarg[0] == '+') {
+ param.fp_comp_end_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_comp_end_sign = 1;
+ optarg++;
+ }
+
+ if (arg_is_eof(optarg)) {
+ param.fp_comp_end = LUSTRE_EOF;
+ param.fp_comp_end_units = 1;
+ rc = 0;
+ } else {
+ rc = llapi_parse_size(optarg,
+ ¶m.fp_comp_end,
+ ¶m.fp_comp_end_units, 0);
+ }
+ if (rc) {
+ fprintf(stderr, "error: bad component end "
+ "'%s'\n", optarg);
+ goto err;
+ }
+ param.fp_check_comp_end = 1;
+ param.fp_exclude_comp_end = !!neg_opt;
+ break;
+ case 'g':
+ case 'G':
+ rc = name2gid(¶m.fp_gid, optarg);
+ if (rc) {
+ param.fp_gid = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "Group/GID: %s cannot "
+ "be found.\n", optarg);
+ ret = -1;
+ goto err;
+ }
+ }
+ param.fp_exclude_gid = !!neg_opt;
+ param.fp_check_gid = 1;
+ break;
+ case 'H':
+ param.fp_hash_type = check_hashtype(optarg);
+ if (param.fp_hash_type == 0) {
+ fprintf(stderr, "error: bad hash_type '%s'\n",
+ optarg);
+ ret = -1;
+ goto err;
+ }
+ param.fp_check_hash_type = 1;
+ param.fp_exclude_hash_type = !!neg_opt;
+ break;
+ case 'L':
+ ret = name2layout(¶m.fp_layout, optarg);
+ if (ret)
+ goto err;
+ param.fp_exclude_layout = !!neg_opt;
+ param.fp_check_layout = 1;
+ break;
+ case 'u':
+ case 'U':
+ rc = name2uid(¶m.fp_uid, optarg);
+ if (rc) {
+ param.fp_uid = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "User/UID: %s cannot "
+ "be found.\n", optarg);
+ ret = -1;
+ goto err;
+ }
+ }
+ param.fp_exclude_uid = !!neg_opt;
+ param.fp_check_uid = 1;
+ break;
+ case 'n':
+ param.fp_pattern = (char *)optarg;
+ param.fp_exclude_pattern = !!neg_opt;
+ break;
+ case 'N':
+ if (optarg[0] == '+') {
+ param.fp_mirror_count_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_mirror_count_sign = 1;
+ optarg++;
+ }
+
+ param.fp_mirror_count = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "error: bad mirror count '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_mirror_count = 1;
+ param.fp_exclude_mirror_count = !!neg_opt;
+ break;
+ case 'm':
+ case 'i':
+ case 'O': {
+ char *buf, *token, *next, *p;
+ int len = 1;
+ void *tmp;
+
+ buf = strdup(optarg);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ param.fp_exclude_obd = !!neg_opt;
+
+ token = buf;
+ while (token && *token) {
+ token = strchr(token, ',');
+ if (token) {
+ len++;
+ token++;
+ }
+ }
+ if (c == 'm') {
+ param.fp_exclude_mdt = !!neg_opt;
+ param.fp_num_alloc_mdts += len;
+ tmp = realloc(param.fp_mdt_uuid,
+ param.fp_num_alloc_mdts *
+ sizeof(*param.fp_mdt_uuid));
+ if (tmp == NULL) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ param.fp_mdt_uuid = tmp;
+ } else {
+ param.fp_exclude_obd = !!neg_opt;
+ param.fp_num_alloc_obds += len;
+ tmp = realloc(param.fp_obd_uuid,
+ param.fp_num_alloc_obds *
+ sizeof(*param.fp_obd_uuid));
+ if (tmp == NULL) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ param.fp_obd_uuid = tmp;
+ }
+ for (token = buf; token && *token; token = next) {
+ struct obd_uuid *puuid;
+ if (c == 'm') {
+ puuid =
+ ¶m.fp_mdt_uuid[param.fp_num_mdts++];
+ } else {
+ puuid =
+ ¶m.fp_obd_uuid[param.fp_num_obds++];
+ }
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+
+ if (strlen(token) > sizeof(puuid->uuid) - 1) {
+ ret = -E2BIG;
+ goto err_free;
+ }
+
+ strncpy(puuid->uuid, token,
+ sizeof(puuid->uuid));
+ }
+err_free:
+ if (buf)
+ free(buf);
+ break;
+ }
+#if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 18, 53, 0)
+ case 'p':
+#endif
+ case LFS_POOL_OPT:
+ if (strlen(optarg) > LOV_MAXPOOLNAME) {
+ fprintf(stderr,
+ "Pool name %s is too long (max %d)\n",
+ optarg, LOV_MAXPOOLNAME);
+ ret = -1;
+ goto err;
+ }
+ /*
+ * We do check for empty pool because empty pool
+ * is used to find V1 LOV attributes
+ */
+ strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
+ param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
+ param.fp_exclude_pool = !!neg_opt;
+ param.fp_check_pool = 1;
+ break;
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 14, 53, 0)
+ case 'p': /* want this for --pool, to match getstripe/find */
+ fprintf(stderr,
+ "warning: -p deprecated, use --print0 or -0\n");
+#endif
+ case '0':
+ param.fp_zero_end = 1;
+ break;
+ case 'P': /* we always print, this option is a no-op */
+ break;
+ case LFS_PROJID_OPT:
+ rc = name2projid(¶m.fp_projid, optarg);
+ if (rc) {
+ param.fp_projid = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr,
+ "Invalid project ID: %s",
+ optarg);
+ ret = -1;
+ goto err;
+ }
+ }
+ param.fp_exclude_projid = !!neg_opt;
+ param.fp_check_projid = 1;
+ break;
+ case 's':
+ if (optarg[0] == '+') {
+ param.fp_size_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_size_sign = 1;
+ optarg++;
+ }
+
+ ret = llapi_parse_size(optarg, ¶m.fp_size,
+ ¶m.fp_size_units, 0);
+ if (ret) {
+ fprintf(stderr, "error: bad file size '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_size = 1;
+ param.fp_exclude_size = !!neg_opt;
+ break;
+ case 'S':
+ if (optarg[0] == '+') {
+ param.fp_stripe_size_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_stripe_size_sign = 1;
+ optarg++;
+ }
+
+ ret = llapi_parse_size(optarg, ¶m.fp_stripe_size,
+ ¶m.fp_stripe_size_units, 0);
+ if (ret) {
+ fprintf(stderr, "error: bad stripe_size '%s'\n",
+ optarg);
+ goto err;
+ }
+ param.fp_check_stripe_size = 1;
+ param.fp_exclude_stripe_size = !!neg_opt;
+ break;
+ case 't':
+ param.fp_exclude_type = !!neg_opt;
+ switch (optarg[0]) {
+ case 'b':
+ param.fp_type = S_IFBLK;
+ break;
+ case 'c':
+ param.fp_type = S_IFCHR;
+ break;
+ case 'd':
+ param.fp_type = S_IFDIR;
+ break;
+ case 'f':
+ param.fp_type = S_IFREG;
+ break;
+ case 'l':
+ param.fp_type = S_IFLNK;
+ break;
+ case 'p':
+ param.fp_type = S_IFIFO;
+ break;
+ case 's':
+ param.fp_type = S_IFSOCK;
+ break;
+ default:
+ fprintf(stderr, "error: %s: bad type '%s'\n",
+ argv[0], optarg);
+ ret = CMD_HELP;
+ goto err;
+ };
+ break;
+ case 'T':
+ if (optarg[0] == '+') {
+ param.fp_mdt_count_sign = -1;
+ optarg++;
+ } else if (optarg[0] == '-') {
+ param.fp_mdt_count_sign = 1;
+ optarg++;
+ }
+
+ param.fp_mdt_count = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "error: bad mdt_count '%s'\n",
+ optarg);
+ ret = -1;
+ goto err;
+ }
+ param.fp_check_mdt_count = 1;
+ param.fp_exclude_mdt_count = !!neg_opt;
+ break;
+ default:
+ ret = CMD_HELP;
+ goto err;
+ };
+ }
+
+ if (pathstart == -1) {
+ fprintf(stderr, "error: %s: no filename|pathname\n",
+ argv[0]);
+ ret = CMD_HELP;
+ goto err;
+ } else if (pathend == -1) {
+ /* no options */
+ pathend = argc;
+ }
+
+ do {
+ rc = llapi_find(argv[pathstart], ¶m);
+ if (rc != 0 && ret == 0)
+ ret = rc;
+ } while (++pathstart < pathend);
+
+ if (ret)
+ fprintf(stderr, "error: %s failed for %s.\n",
+ argv[0], argv[optind - 1]);
+err:
+ if (param.fp_obd_uuid && param.fp_num_alloc_obds)
+ free(param.fp_obd_uuid);
+
+ if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
+ free(param.fp_mdt_uuid);
+
+ return ret;
+}
+
+static int lfs_getstripe_internal(int argc, char **argv,
+ struct find_param *param)
+{
+ struct option long_opts[] = {
+/* find { .val = 'A', .name = "atime", .has_arg = required_argument }*/
+/* find { .val = 'b', .name = "blocks", .has_arg = required_argument }*/
+ { .val = LFS_COMP_COUNT_OPT,
+ .name = "comp-count", .has_arg = no_argument },
+ { .val = LFS_COMP_COUNT_OPT,
+ .name = "component-count", .has_arg = no_argument },
+ { .val = LFS_COMP_FLAGS_OPT,
+ .name = "comp-flags", .has_arg = optional_argument },
+ { .val = LFS_COMP_FLAGS_OPT,
+ .name = "component-flags", .has_arg = optional_argument },
+ { .val = LFS_COMP_START_OPT,
+ .name = "comp-start", .has_arg = optional_argument },
+ { .val = LFS_COMP_START_OPT,
+ .name = "component-start", .has_arg = optional_argument },
+ { .val = 'c', .name = "stripe-count", .has_arg = no_argument },
+ { .val = 'c', .name = "stripe_count", .has_arg = no_argument },
+/* find { .val = 'C', .name = "ctime", .has_arg = required_argument }*/
+ { .val = 'd', .name = "directory", .has_arg = no_argument },
+ { .val = 'D', .name = "default", .has_arg = no_argument },
+ { .val = 'E', .name = "comp-end", .has_arg = optional_argument },
+ { .val = 'E', .name = "component-end", .has_arg = optional_argument },
+ { .val = 'F', .name = "fid", .has_arg = no_argument },
+ { .val = 'g', .name = "generation", .has_arg = no_argument },
+/* find { .val = 'G', .name = "group", .has_arg = required_argument }*/
+/* dirstripe { .val = 'H', .name = "mdt-hash", .has_arg = required_argument }*/
+ { .val = 'i', .name = "stripe-index", .has_arg = no_argument },
+ { .val = 'i', .name = "stripe_index", .has_arg = no_argument },
+ { .val = 'I', .name = "comp-id", .has_arg = optional_argument },
+ { .val = 'I', .name = "component-id", .has_arg = optional_argument },
+ { .val = 'L', .name = "layout", .has_arg = no_argument },
+ { .val = 'm', .name = "mdt", .has_arg = no_argument },
+ { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
+ { .val = 'm', .name = "mdt_index", .has_arg = no_argument },
+/* find { .val = 'M', .name = "mtime", .has_arg = required_argument }*/
+/* find { .val = 'n', .name = "name", .has_arg = required_argument }*/
+ { .val = 'O', .name = "obd", .has_arg = required_argument },
+ { .val = 'O', .name = "ost", .has_arg = required_argument },
+ { .val = 'p', .name = "pool", .has_arg = no_argument },
+/* find { .val = 'P', .name = "print", .has_arg = no_argument }, */
+ { .val = 'q', .name = "quiet", .has_arg = no_argument },
+ { .val = 'r', .name = "recursive", .has_arg = no_argument },
+ { .val = 'R', .name = "raw", .has_arg = no_argument },
+ { .val = 'S', .name = "stripe-size", .has_arg = no_argument },
+ { .val = 'S', .name = "stripe_size", .has_arg = no_argument },
+/* find { .val = 't', .name = "type", .has_arg = required_argument }*/
+/* dirstripe { .val = 'T', .name = "mdt-count", .has_arg = required_argument }*/
+/* find { .val = 'u', .name = "uid", .has_arg = required_argument }*/
+/* find { .val = 'U', .name = "user", .has_arg = required_argument }*/
+ { .val = 'v', .name = "verbose", .has_arg = no_argument },
+ { .val = 'y', .name = "yaml", .has_arg = no_argument },
+ { .name = NULL } };
+ int c, rc;
+ char *end, *tmp;
+
+ while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
+ long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'c':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_COUNT;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case LFS_COMP_COUNT_OPT:
+ param->fp_verbose |= VERBOSE_COMP_COUNT;
+ param->fp_max_depth = 0;
+ break;
+ case LFS_COMP_FLAGS_OPT:
+ if (optarg != NULL) {
+ rc = comp_str2flags(optarg,
+ ¶m->fp_comp_flags,
+ ¶m->fp_comp_neg_flags);
+ if (rc != 0) {
+ fprintf(stderr, "error: %s bad "
+ "component flags '%s'.\n",
+ argv[0], optarg);
+ return CMD_HELP;
+ }
+ param->fp_check_comp_flags = 1;
+ } else {
+ param->fp_verbose |= VERBOSE_COMP_FLAGS;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case LFS_COMP_START_OPT:
+ if (optarg != NULL) {
+ tmp = optarg;
+ if (tmp[0] == '+') {
+ param->fp_comp_start_sign = -1;
+ tmp++;
+ } else if (tmp[0] == '-') {
+ param->fp_comp_start_sign = 1;
+ tmp++;
+ }
+ rc = llapi_parse_size(tmp,
+ ¶m->fp_comp_start,
+ ¶m->fp_comp_start_units, 0);
+ if (rc != 0) {
+ fprintf(stderr, "error: %s bad "
+ "component start '%s'.\n",
+ argv[0], tmp);
+ return CMD_HELP;
+ } else {
+ param->fp_check_comp_start = 1;
+ }
+ } else {
+ param->fp_verbose |= VERBOSE_COMP_START;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'd':
+ param->fp_max_depth = 0;
+ break;
+ case 'D':
+ param->fp_get_default_lmv = 1;
+ break;
+ case 'E':
+ if (optarg != NULL) {
+ tmp = optarg;
+ if (tmp[0] == '+') {
+ param->fp_comp_end_sign = -1;
+ tmp++;
+ } else if (tmp[0] == '-') {
+ param->fp_comp_end_sign = 1;
+ tmp++;
+ }
+
+ if (arg_is_eof(tmp)) {
+ param->fp_comp_end = LUSTRE_EOF;
+ param->fp_comp_end_units = 1;
+ rc = 0;
+ } else {
+ rc = llapi_parse_size(tmp,
+ ¶m->fp_comp_end,
+ ¶m->fp_comp_end_units, 0);
+ }
+ if (rc != 0) {
+ fprintf(stderr, "error: %s bad "
+ "component end '%s'.\n",
+ argv[0], tmp);
+ return CMD_HELP;
+ }
+ param->fp_check_comp_end = 1;
+ } else {
+ param->fp_verbose |= VERBOSE_COMP_END;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'F':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_DFID;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'g':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_GENERATION;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'i':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_OFFSET;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'I':
+ if (optarg != NULL) {
+ param->fp_comp_id = strtoul(optarg, &end, 0);
+ if (*end != '\0' || param->fp_comp_id == 0 ||
+ param->fp_comp_id > LCME_ID_MAX) {
+ fprintf(stderr, "error: %s bad "
+ "component id '%s'\n",
+ argv[0], optarg);
+ return CMD_HELP;
+ } else {
+ param->fp_check_comp_id = 1;
+ }
+ } else {
+ param->fp_max_depth = 0;
+ param->fp_verbose |= VERBOSE_COMP_ID;
+ }
+ break;
+ case 'L':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_LAYOUT;
+ param->fp_max_depth = 0;
+ }
+ break;
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ case 'M':
+ fprintf(stderr, "warning: '-M' deprecated"
+ ", use '--mdt-index' or '-m' instead\n");
+#endif
+ case 'm':
+ if (!(param->fp_verbose & VERBOSE_DETAIL))
+ param->fp_max_depth = 0;
+ param->fp_verbose |= VERBOSE_MDTINDEX;
+ break;
+ case 'O':
+ if (param->fp_obd_uuid) {
+ fprintf(stderr,
+ "error: %s: only one obduuid allowed",
+ argv[0]);
+ return CMD_HELP;
+ }
+ param->fp_obd_uuid = (struct obd_uuid *)optarg;
+ break;
+ case 'p':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_POOL;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'q':
+ param->fp_quiet++;
+ break;
+ case 'r':
+ param->fp_recursive = 1;
+ break;
+ case 'R':
+ param->fp_raw = 1;
+ break;
+ case 'S':
+ if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+ param->fp_verbose |= VERBOSE_SIZE;
+ param->fp_max_depth = 0;
+ }
+ break;
+ case 'v':
+ param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
+ break;
+ case 'y':
+ param->fp_yaml = 1;
+ break;
+ default:
+ return CMD_HELP;
+ }
+ }
+
+ if (optind >= argc)
+ return CMD_HELP;
+
+ if (param->fp_recursive)
+ param->fp_max_depth = -1;
+ else if (param->fp_verbose & VERBOSE_DETAIL)
+ param->fp_max_depth = 1;
+
+ if (!param->fp_verbose)
+ param->fp_verbose = VERBOSE_DEFAULT;
+ if (param->fp_quiet)
+ param->fp_verbose = VERBOSE_OBJID;
+
+ do {
+ rc = llapi_getstripe(argv[optind], param);
+ } while (++optind < argc && !rc);
+
+ if (rc)
+ fprintf(stderr, "error: %s failed for %s.\n",
+ argv[0], argv[optind - 1]);
+ return rc;
+}
+
+static int lfs_tgts(int argc, char **argv)
+{
+ char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
+ struct find_param param;
+ int index = 0, rc=0;
+
+ if (argc > 2)
+ return CMD_HELP;
+
+ if (argc == 2 && !realpath(argv[1], path)) {
+ rc = -errno;
+ fprintf(stderr, "error: invalid path '%s': %s\n",
+ argv[1], strerror(-rc));
+ return rc;
+ }
+
+ while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
+ /* Check if we have a mount point */
+ if (mntdir[0] == '\0')
+ continue;
+
+ memset(¶m, 0, sizeof(param));
+ if (!strcmp(argv[0], "mdts"))
+ param.fp_get_lmv = 1;
+
+ rc = llapi_ostlist(mntdir, ¶m);
+ if (rc) {
+ fprintf(stderr, "error: %s: failed on %s\n",
+ argv[0], mntdir);
+ }
+ if (path[0] != '\0')
+ break;
+ memset(mntdir, 0, PATH_MAX);
+ }
+
+ return rc;
+}
+
+static int lfs_getstripe(int argc, char **argv)
+{
+ struct find_param param = { 0 };
+
+ param.fp_max_depth = 1;
+ return lfs_getstripe_internal(argc, argv, ¶m);
+}
+
+/* functions */
+static int lfs_getdirstripe(int argc, char **argv)
+{
+ struct find_param param = { 0 };
+ struct option long_opts[] = {
+ { .val = 'c', .name = "mdt-count", .has_arg = no_argument },
+ { .val = 'D', .name = "default", .has_arg = no_argument },
+ { .val = 'H', .name = "mdt-hash", .has_arg = no_argument },
+ { .val = 'i', .name = "mdt-index", .has_arg = no_argument },
+ { .val = 'm', .name = "mdt-index", .has_arg = no_argument },
+ { .val = 'O', .name = "obd", .has_arg = required_argument },
+ { .val = 'r', .name = "recursive", .has_arg = no_argument },
+ { .val = 'T', .name = "mdt-count", .has_arg = no_argument },
+ { .val = 'y', .name = "yaml", .has_arg = no_argument },
+ { .name = NULL } };
+ int c, rc;
+
+ param.fp_get_lmv = 1;
+
+ while ((c = getopt_long(argc, argv,
+ "cDHimO:rtTy", long_opts, NULL)) != -1)
+ {
+ switch (c) {
+ case 'c':
+ case 'T':
+ param.fp_verbose |= VERBOSE_COUNT;
+ break;
+ case 'D':
+ param.fp_get_default_lmv = 1;
+ break;
+ case 'i':
+ case 'm':
+ param.fp_verbose |= VERBOSE_OFFSET;
+ break;
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
+ case 't':
+ fprintf(stderr, "warning: '-t' deprecated, "
+ "use '--mdt-hash' or '-H' instead\n");
+#endif
+ case 'H':
+ param.fp_verbose |= VERBOSE_HASH_TYPE;
+ break;
+ case 'O':
+ if (param.fp_obd_uuid) {
+ fprintf(stderr,
+ "error: %s: only one obduuid allowed",
+ argv[0]);
+ return CMD_HELP;
+ }
+ param.fp_obd_uuid = (struct obd_uuid *)optarg;
+ break;
+ case 'r':
+ param.fp_recursive = 1;
+ break;
+ case 'y':
+ param.fp_yaml = 1;
+ break;
+ default:
+ return CMD_HELP;
+ }
+ }
+
+ if (optind >= argc)
+ return CMD_HELP;
+
+ if (param.fp_recursive)
+ param.fp_max_depth = -1;
+
+ if (!param.fp_verbose)
+ param.fp_verbose = VERBOSE_DEFAULT;
+
+ do {
+ rc = llapi_getstripe(argv[optind], ¶m);
+ } while (++optind < argc && !rc);
+
+ if (rc)
+ fprintf(stderr, "error: %s failed for %s.\n",
+ argv[0], argv[optind - 1]);
+ return rc;
+}
+
+enum mntdf_flags {
+ MNTDF_INODES = 0x0001,
+ MNTDF_COOKED = 0x0002,
+ MNTDF_LAZY = 0x0004,
+ MNTDF_VERBOSE = 0x0008,
+ MNTDF_SHOW = 0x0010,
+};
+
+#define COOK(value) \
+({ \
+ int radix = 0; \
+ while (value > 1024) { \
+ value /= 1024; \
+ radix++; \
+ } \
+ radix; \
+})
+#define UUF "%-20s"
+#define CSF "%11s"
+#define CDF "%11llu"
+#define HDF "%8.1f%c"
+#define RSF "%4s"
+#define RDF "%3d%%"
+
+static inline int obd_statfs_ratio(const struct obd_statfs *st)
+{
+ double avail, used, ratio = 0;
+
+ avail = st->os_bavail;
+ used = st->os_blocks - st->os_bfree;
+ if (avail + used > 0)
+ ratio = used / (used + avail) * 100 + 0.5;
+
+ return (int)ratio;
+}
+
+static int showdf(char *mntdir, struct obd_statfs *stat,
+ char *uuid, enum mntdf_flags flags,
+ char *type, int index, int rc)
+{
+ long long avail, used, total;
+ int ratio = 0;
+ char *suffix = "KMGTPEZY";
+ /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
+ char tbuf[3 * sizeof(__u64)];
+ char ubuf[3 * sizeof(__u64)];
+ char abuf[3 * sizeof(__u64)];
+ char rbuf[3 * sizeof(__u64)];
+
+ if (!uuid || !stat)
+ return -EINVAL;
+
+ switch (rc) {
+ case 0:
+ if (flags & MNTDF_INODES) {
+ avail = stat->os_ffree;
+ used = stat->os_files - stat->os_ffree;
+ total = stat->os_files;
+ } else {
+ int shift = flags & MNTDF_COOKED ? 0 : 10;
+
+ avail = (stat->os_bavail * stat->os_bsize) >> shift;
+ used = ((stat->os_blocks - stat->os_bfree) *
+ stat->os_bsize) >> shift;
+ total = (stat->os_blocks * stat->os_bsize) >> shift;
+ }
+
+ ratio = obd_statfs_ratio(stat);
+
+ if (flags & MNTDF_COOKED) {
+ int i;
+ double cook_val;
+
+ cook_val = (double)total;
+ i = COOK(cook_val);
+ if (i > 0)
+ snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
+ suffix[i - 1]);
+ else
+ snprintf(tbuf, sizeof(tbuf), CDF, total);
+
+ cook_val = (double)used;
+ i = COOK(cook_val);
+ if (i > 0)
+ snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
+ suffix[i - 1]);
+ else
+ snprintf(ubuf, sizeof(ubuf), CDF, used);
+
+ cook_val = (double)avail;
+ i = COOK(cook_val);
+ if (i > 0)
+ snprintf(abuf, sizeof(abuf), HDF, cook_val,
+ suffix[i - 1]);
+ else
+ snprintf(abuf, sizeof(abuf), CDF, avail);
+ } else {
+ snprintf(tbuf, sizeof(tbuf), CDF, total);
+ snprintf(ubuf, sizeof(tbuf), CDF, used);
+ snprintf(abuf, sizeof(tbuf), CDF, avail);
+ }
+
+ sprintf(rbuf, RDF, ratio);
+ printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
+ uuid, tbuf, ubuf, abuf, rbuf, mntdir);
+ if (type)
+ printf("[%s:%d]", type, index);
+
+ if (stat->os_state) {
+ /*
+ * Each character represents the matching
+ * OS_STATE_* bit.
+ */
+ const char state_names[] = "DRSI";
+ __u32 state;
+ __u32 i;
+
+ printf(" ");
+ for (i = 0, state = stat->os_state;
+ state && i < sizeof(state_names); i++) {
+ if (!(state & (1 << i)))
+ continue;
+ printf("%c", state_names[i]);
+ state ^= 1 << i;
+ }
+ }
+
+ printf("\n");
+ break;
+ case -ENODATA:
+ printf(UUF": inactive device\n", uuid);
+ break;
+ default:
+ printf(UUF": %s\n", uuid, strerror(-rc));
+ break;
+ }
+
+ return 0;
+}
+
+struct ll_stat_type {
+ int st_op;
+ char *st_name;
+};
+
+#define LL_STATFS_MAX LOV_MAX_STRIPE_COUNT
+
+struct ll_statfs_data {
+ int sd_index;
+ struct obd_statfs sd_st;
+};
+
+struct ll_statfs_buf {
+ int sb_count;
+ struct ll_statfs_data sb_buf[LL_STATFS_MAX];
+};
+
+static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
+ int ops, struct ll_statfs_buf *lsb)
+{
+ struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
+ struct obd_uuid uuid_buf;
+ char *poolname = NULL;
+ struct ll_stat_type types[] = {
+ { .st_op = LL_STATFS_LMV, .st_name = "MDT" },
+ { .st_op = LL_STATFS_LOV, .st_name = "OST" },
+ { .st_name = NULL } };
+ struct ll_stat_type *tp;
+ __u64 ost_ffree = 0;
+ __u32 index;
+ __u32 type;
+ int fd;
+ int rc = 0;
+ int rc2;
+
+ if (pool) {
+ poolname = strchr(pool, '.');
+ if (poolname != NULL) {
+ if (strncmp(fsname, pool, strlen(fsname))) {
+ fprintf(stderr, "filesystem name incorrect\n");
+ return -ENODEV;
+ }
+ poolname++;
+ } else
+ poolname = pool;
+ }
+
+ fd = open(mntdir, O_RDONLY);
+ if (fd < 0) {
+ rc = -errno;
+ fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
+ strerror(errno));
+ return rc;
+ }
+
+ if (flags & MNTDF_SHOW) {
+ if (flags & MNTDF_INODES)
+ printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
+ "UUID", "Inodes", "IUsed", "IFree",
+ "IUse%", "Mounted on");
+ else
+ printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
+ "UUID",
+ flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
+ "Used", "Available", "Use%", "Mounted on");
+ }
+
+ for (tp = types; tp->st_name != NULL; tp++) {
+ if (!(tp->st_op & ops))
+ continue;
+
+ for (index = 0; ; index++) {
+ memset(&stat_buf, 0, sizeof(struct obd_statfs));
+ memset(&uuid_buf, 0, sizeof(struct obd_uuid));
+ type = flags & MNTDF_LAZY ?
+ tp->st_op | LL_STATFS_NODELAY : tp->st_op;
+ rc2 = llapi_obd_fstatfs(fd, type, index,
+ &stat_buf, &uuid_buf);
+ if (rc2 == -ENODEV)
+ break;
+ if (rc2 == -EAGAIN)
+ continue;
+ if (rc2 == -ENODATA) { /* Inactive device, OK. */
+ if (!(flags & MNTDF_VERBOSE))
+ continue;
+ } else if (rc2 < 0 && rc == 0) {
+ rc = rc2;