X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=cmds-device.c;h=86459d1b956430585c5649986dbd346a16cb6409;hb=5a87a95115a0f992ef4d3ef9ad480d8cf3bb27ec;hp=8e69b885937a643d81f9651979ff83b3468817a3;hpb=ec1fc69d3945f67684a2c15969dfb309ed967168;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/cmds-device.c b/cmds-device.c index 8e69b88..86459d1 100644 --- a/cmds-device.c +++ b/cmds-device.c @@ -32,6 +32,8 @@ #include "cmds-fi-usage.h" #include "commands.h" +#include "help.h" +#include "mkfs/common.h" static const char * const device_cmd_group_usage[] = { "btrfs device []", @@ -49,10 +51,11 @@ static const char * const cmd_device_add_usage[] = { static int cmd_device_add(int argc, char **argv) { char *mntpnt; - int i, fdmnt, ret=0, e; + int i, fdmnt, ret = 0; DIR *dirstream = NULL; int discard = 1; int force = 0; + int last_dev; while (1) { int c; @@ -77,24 +80,20 @@ static int cmd_device_add(int argc, char **argv) } } - argc = argc - optind; - - if (check_argc_min(argc, 2)) + if (check_argc_min(argc - optind, 2)) usage(cmd_device_add_usage); - mntpnt = argv[optind + argc - 1]; + last_dev = argc - 1; + mntpnt = argv[last_dev]; - fdmnt = open_file_or_dir(mntpnt, &dirstream); - if (fdmnt < 0) { - fprintf(stderr, "ERROR: can't access '%s'\n", mntpnt); + fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1); + if (fdmnt < 0) return 1; - } - for (i = optind; i < optind + argc - 1; i++){ + for (i = optind; i < last_dev; i++){ struct btrfs_ioctl_vol_args ioctl_args; int devfd, res; u64 dev_block_count = 0; - int mixed = 0; char *path; res = test_dev_for_mkfs(argv[i], force); @@ -105,13 +104,14 @@ static int cmd_device_add(int argc, char **argv) devfd = open(argv[i], O_RDWR); if (devfd < 0) { - fprintf(stderr, "ERROR: Unable to open device '%s'\n", argv[i]); + error("unable to open device '%s'", argv[i]); ret++; continue; } - res = btrfs_prepare_device(devfd, argv[i], 1, &dev_block_count, - 0, &mixed, discard); + res = btrfs_prepare_device(devfd, argv[i], &dev_block_count, 0, + PREP_DEVICE_ZERO_END | PREP_DEVICE_VERBOSE | + (discard ? PREP_DEVICE_DISCARD : 0)); close(devfd); if (res) { ret++; @@ -120,9 +120,8 @@ static int cmd_device_add(int argc, char **argv) path = canonicalize_path(argv[i]); if (!path) { - fprintf(stderr, - "ERROR: Could not canonicalize pathname '%s': %s\n", - argv[i], strerror(errno)); + error("could not canonicalize pathname '%s': %m", + argv[i]); ret++; goto error_out; } @@ -130,10 +129,8 @@ static int cmd_device_add(int argc, char **argv) memset(&ioctl_args, 0, sizeof(ioctl_args)); strncpy_null(ioctl_args.name, path); res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args); - e = errno; if (res < 0) { - fprintf(stderr, "ERROR: error adding the device '%s' - %s\n", - path, strerror(e)); + error("error adding device '%s': %m", path); ret++; } free(path); @@ -141,7 +138,6 @@ static int cmd_device_add(int argc, char **argv) error_out: close_file_or_dir(fdmnt, dirstream); - btrfs_close_all_devices(); return !!ret; } @@ -149,44 +145,75 @@ static int _cmd_device_remove(int argc, char **argv, const char * const *usagestr) { char *mntpnt; - int i, fdmnt, ret=0, e; + int i, fdmnt, ret = 0; DIR *dirstream = NULL; - if (check_argc_min(argc, 3)) + clean_args_no_options(argc, argv, usagestr); + + if (check_argc_min(argc - optind, 2)) usage(usagestr); mntpnt = argv[argc - 1]; - fdmnt = open_file_or_dir(mntpnt, &dirstream); - if (fdmnt < 0) { - fprintf(stderr, "ERROR: can't access '%s'\n", mntpnt); + fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1); + if (fdmnt < 0) return 1; - } - for(i=1 ; i < argc - 1; i++ ){ + for(i = optind; i < argc - 1; i++) { struct btrfs_ioctl_vol_args arg; + struct btrfs_ioctl_vol_args_v2 argv2 = {0}; + int is_devid = 0; int res; - if (!is_block_device(argv[i])) { - fprintf(stderr, - "ERROR: %s is not a block device\n", argv[i]); + if (string_is_numerical(argv[i])) { + argv2.devid = arg_strtou64(argv[i]); + argv2.flags = BTRFS_DEVICE_SPEC_BY_ID; + is_devid = 1; + } else if (is_block_device(argv[i]) == 1 || + strcmp(argv[i], "missing") == 0) { + strncpy_null(argv2.name, argv[i]); + } else { + error("not a block device: %s", argv[i]); ret++; continue; } - memset(&arg, 0, sizeof(arg)); - strncpy_null(arg.name, argv[i]); - res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); - e = errno; + + /* + * Positive values are from BTRFS_ERROR_DEV_*, + * otherwise it's a generic error, one of errnos + */ + res = ioctl(fdmnt, BTRFS_IOC_RM_DEV_V2, &argv2); + + /* + * If BTRFS_IOC_RM_DEV_V2 is not supported we get ENOTTY and if + * argv2.flags includes a flag which kernel doesn't understand then + * we shall get EOPNOTSUPP + */ + if (res < 0 && (errno == ENOTTY || errno == EOPNOTSUPP)) { + if (is_devid) { + error("device delete by id failed: %m"); + ret++; + continue; + } + memset(&arg, 0, sizeof(arg)); + strncpy_null(arg.name, argv[i]); + res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); + } + if (res) { const char *msg; if (res > 0) msg = btrfs_err_str(res); else - msg = strerror(e); - fprintf(stderr, - "ERROR: error removing the device '%s' - %s\n", - argv[i], msg); + msg = strerror(errno); + if (is_devid) { + error("error removing devid %llu: %s", + (unsigned long long)argv2.devid, msg); + } else { + error("error removing device '%s': %s", + argv[i], msg); + } ret++; } } @@ -195,9 +222,16 @@ static int _cmd_device_remove(int argc, char **argv, return !!ret; } +#define COMMON_USAGE_REMOVE_DELETE \ + "If 'missing' is specified for , the first device that is", \ + "described by the filesystem metadata, but not present at the mount", \ + "time will be removed. (only in degraded mode)" + static const char * const cmd_device_remove_usage[] = { - "btrfs device remove [...] ", + "btrfs device remove | [|...] ", "Remove a device from a filesystem", + "", + COMMON_USAGE_REMOVE_DELETE, NULL }; @@ -207,8 +241,10 @@ static int cmd_device_remove(int argc, char **argv) } static const char * const cmd_device_delete_usage[] = { - "btrfs device delete [...] ", - "Remove a device from a filesystem", + "btrfs device delete | [|...] ", + "Remove a device from a filesystem (alias of \"btrfs device remove\")", + "", + COMMON_USAGE_REMOVE_DELETE, NULL }; @@ -227,11 +263,10 @@ static const char * const cmd_device_scan_usage[] = { static int cmd_device_scan(int argc, char **argv) { int i; - int devstart = 1; + int devstart; int all = 0; int ret = 0; - optind = 1; while (1) { int c; static const struct option long_options[] = { @@ -250,35 +285,31 @@ static int cmd_device_scan(int argc, char **argv) usage(cmd_device_scan_usage); } } + devstart = optind; - if (all && check_argc_max(argc, 2)) + if (all && check_argc_max(argc - optind, 1)) usage(cmd_device_scan_usage); - if (all || argc == 1) { + if (all || argc - optind == 0) { printf("Scanning for Btrfs filesystems\n"); - ret = btrfs_scan_lblkid(); - if (ret) - fprintf(stderr, "ERROR: error %d while scanning\n", ret); + ret = btrfs_scan_devices(); + error_on(ret, "error %d while scanning", ret); ret = btrfs_register_all_devices(); - if (ret) - fprintf(stderr, "ERROR: error %d while registering\n", ret); + error_on(ret, "there are %d errors while registering devices", ret); goto out; } for( i = devstart ; i < argc ; i++ ){ char *path; - if (!is_block_device(argv[i])) { - fprintf(stderr, - "ERROR: %s is not a block device\n", argv[i]); + if (is_block_device(argv[i]) != 1) { + error("not a block device: %s", argv[i]); ret = 1; goto out; } path = canonicalize_path(argv[i]); if (!path) { - fprintf(stderr, - "ERROR: Could not canonicalize path '%s': %s\n", - argv[i], strerror(errno)); + error("could not canonicalize path '%s': %m", argv[i]); ret = 1; goto out; } @@ -292,7 +323,6 @@ static int cmd_device_scan(int argc, char **argv) } out: - btrfs_close_all_devices(); return !!ret; } @@ -309,7 +339,9 @@ static int cmd_device_ready(int argc, char **argv) int ret; char *path; - if (check_argc_min(argc, 2)) + clean_args_no_options(argc, argv, cmd_device_ready_usage); + + if (check_argc_exact(argc - optind, 1)) usage(cmd_device_ready_usage); fd = open("/dev/btrfs-control", O_RDWR); @@ -318,18 +350,16 @@ static int cmd_device_ready(int argc, char **argv) return 1; } - path = canonicalize_path(argv[argc - 1]); + path = canonicalize_path(argv[optind]); if (!path) { - fprintf(stderr, - "ERROR: Could not canonicalize pathname '%s': %s\n", - argv[argc - 1], strerror(errno)); + error("could not canonicalize pathname '%s': %m", + argv[optind]); ret = 1; goto out; } - if (!is_block_device(path)) { - fprintf(stderr, - "ERROR: %s is not a block device\n", path); + if (is_block_device(path) != 1) { + error("not a block device: %s", path); ret = 1; goto out; } @@ -338,9 +368,8 @@ static int cmd_device_ready(int argc, char **argv) strncpy_null(args.name, path); ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args); if (ret < 0) { - fprintf(stderr, "ERROR: unable to determine if the device '%s'" - " is ready for mounting - %s\n", path, - strerror(errno)); + error("unable to determine if device '%s' is ready for mount: %m", + path); ret = 1; } @@ -351,10 +380,13 @@ out: } static const char * const cmd_device_stats_usage[] = { - "btrfs device stats [-z] |", - "Show current device IO stats.", + "btrfs device stats [options] |", + "Show device IO error statistics", + "Show device IO error statistics for all devices of the given filesystem", + "identified by PATH or DEVICE. The filesystem must be mounted.", "", - "-z show current stats and reset values to zero", + "-c|--check return non-zero if any stat counter is not zero", + "-z|--reset show current stats and reset values to zero", NULL }; @@ -366,14 +398,27 @@ static int cmd_device_stats(int argc, char **argv) int ret; int fdmnt; int i; - int c; int err = 0; + int check = 0; __u64 flags = 0; DIR *dirstream = NULL; - optind = 1; - while ((c = getopt(argc, argv, "z")) != -1) { + while (1) { + int c; + static const struct option long_options[] = { + {"check", no_argument, NULL, 'c'}, + {"reset", no_argument, NULL, 'z'}, + {NULL, 0, NULL, 0} + }; + + c = getopt_long(argc, argv, "cz", long_options, NULL); + if (c < 0) + break; + switch (c) { + case 'c': + check = 1; + break; case 'z': flags = BTRFS_DEV_STATS_RESET; break; @@ -383,85 +428,85 @@ static int cmd_device_stats(int argc, char **argv) } } - argc = argc - optind; - if (check_argc_exact(argc, 1)) + if (check_argc_exact(argc - optind, 1)) usage(cmd_device_stats_usage); dev_path = argv[optind]; - fdmnt = open_path_or_dev_mnt(dev_path, &dirstream); - - if (fdmnt < 0) { - if (errno == EINVAL) - fprintf(stderr, - "ERROR: '%s' is not a mounted btrfs device\n", - dev_path); - else - fprintf(stderr, "ERROR: can't access '%s': %s\n", - dev_path, strerror(errno)); + fdmnt = open_path_or_dev_mnt(dev_path, &dirstream, 1); + if (fdmnt < 0) return 1; - } ret = get_fs_info(dev_path, &fi_args, &di_args); if (ret) { - fprintf(stderr, "ERROR: getting dev info for devstats failed: " - "%s\n", strerror(-ret)); + error("getting device info for %s failed: %s", dev_path, + strerror(-ret)); err = 1; goto out; } if (!fi_args.num_devices) { - fprintf(stderr, "ERROR: no devices found\n"); + error("no devices found"); err = 1; goto out; } for (i = 0; i < fi_args.num_devices; i++) { struct btrfs_ioctl_get_dev_stats args = {0}; - __u8 path[BTRFS_DEVICE_PATH_NAME_MAX + 1]; + char path[BTRFS_DEVICE_PATH_NAME_MAX + 1]; - strncpy((char *)path, (char *)di_args[i].path, + strncpy(path, (char *)di_args[i].path, BTRFS_DEVICE_PATH_NAME_MAX); - path[BTRFS_DEVICE_PATH_NAME_MAX] = '\0'; + path[BTRFS_DEVICE_PATH_NAME_MAX] = 0; args.devid = di_args[i].devid; args.nr_items = BTRFS_DEV_STAT_VALUES_MAX; args.flags = flags; if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) { - fprintf(stderr, - "ERROR: ioctl(BTRFS_IOC_GET_DEV_STATS) on %s failed: %s\n", - path, strerror(errno)); - err = 1; + error("device stats ioctl failed on %s: %m", + path); + err |= 1; } else { char *canonical_path; - - canonical_path = canonicalize_path((char *)path); - - if (args.nr_items >= BTRFS_DEV_STAT_WRITE_ERRS + 1) - printf("[%s].write_io_errs %llu\n", - canonical_path, - (unsigned long long) args.values[ - BTRFS_DEV_STAT_WRITE_ERRS]); - if (args.nr_items >= BTRFS_DEV_STAT_READ_ERRS + 1) - printf("[%s].read_io_errs %llu\n", - canonical_path, - (unsigned long long) args.values[ - BTRFS_DEV_STAT_READ_ERRS]); - if (args.nr_items >= BTRFS_DEV_STAT_FLUSH_ERRS + 1) - printf("[%s].flush_io_errs %llu\n", - canonical_path, - (unsigned long long) args.values[ - BTRFS_DEV_STAT_FLUSH_ERRS]); - if (args.nr_items >= BTRFS_DEV_STAT_CORRUPTION_ERRS + 1) - printf("[%s].corruption_errs %llu\n", - canonical_path, - (unsigned long long) args.values[ - BTRFS_DEV_STAT_CORRUPTION_ERRS]); - if (args.nr_items >= BTRFS_DEV_STAT_GENERATION_ERRS + 1) - printf("[%s].generation_errs %llu\n", - canonical_path, - (unsigned long long) args.values[ - BTRFS_DEV_STAT_GENERATION_ERRS]); + int j; + static const struct { + const char name[32]; + u64 num; + } dev_stats[] = { + { "write_io_errs", BTRFS_DEV_STAT_WRITE_ERRS }, + { "read_io_errs", BTRFS_DEV_STAT_READ_ERRS }, + { "flush_io_errs", BTRFS_DEV_STAT_FLUSH_ERRS }, + { "corruption_errs", + BTRFS_DEV_STAT_CORRUPTION_ERRS }, + { "generation_errs", + BTRFS_DEV_STAT_GENERATION_ERRS }, + }; + + canonical_path = canonicalize_path(path); + + /* No path when device is missing. */ + if (!canonical_path) { + canonical_path = malloc(32); + if (!canonical_path) { + error("not enough memory for path buffer"); + goto out; + } + snprintf(canonical_path, 32, + "devid:%llu", args.devid); + } + + for (j = 0; j < ARRAY_SIZE(dev_stats); j++) { + /* We got fewer items than we know */ + if (args.nr_items < dev_stats[j].num + 1) + continue; + printf("[%s].%-16s %llu\n", canonical_path, + dev_stats[j].name, + (unsigned long long) + args.values[dev_stats[j].num]); + if ((check == 1) + && (args.values[dev_stats[j].num] > 0)) + err |= 64; + } free(canonical_path); } @@ -470,24 +515,14 @@ static int cmd_device_stats(int argc, char **argv) out: free(di_args); close_file_or_dir(fdmnt, dirstream); - btrfs_close_all_devices(); return err; } -const char * const cmd_device_usage_usage[] = { +static const char * const cmd_device_usage_usage[] = { "btrfs device usage [options] [..]", "Show detailed information about internal allocations in devices.", - "-b|--raw raw numbers in bytes", - "-h|--human-readable", - " human friendly numbers, base 1024 (default)", - "-H human friendly numbers, base 1000", - "--iec use 1024 as a base (KiB, MiB, GiB, TiB)", - "--si use 1000 as a base (kB, MB, GB, TB)", - "-k|--kbytes show sizes in KiB, or kB with --si", - "-m|--mbytes show sizes in MiB, or MB with --si", - "-g|--gbytes show sizes in GiB, or GB with --si", - "-t|--tbytes show sizes in TiB, or TB with --si", + HELPINFO_UNITS_SHORT_LONG, NULL }; @@ -507,8 +542,8 @@ static int _cmd_device_usage(int fd, char *path, unsigned unit_mode) for (i = 0; i < devcount; i++) { printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid); - print_device_sizes(fd, &devinfo[i], unit_mode); - print_device_chunks(fd, &devinfo[i], chunkinfo, chunkcount, + print_device_sizes(&devinfo[i], unit_mode); + print_device_chunks(&devinfo[i], chunkinfo, chunkcount, unit_mode); printf("\n"); } @@ -520,90 +555,39 @@ out: return ret; } -int cmd_device_usage(int argc, char **argv) +static int cmd_device_usage(int argc, char **argv) { - unsigned unit_mode = UNITS_DEFAULT; + unsigned unit_mode; int ret = 0; - int i, more_than_one = 0; + int i; - optind = 1; - while (1) { - int c; - static const struct option long_options[] = { - { "raw", no_argument, NULL, 'b'}, - { "kbytes", no_argument, NULL, 'k'}, - { "mbytes", no_argument, NULL, 'm'}, - { "gbytes", no_argument, NULL, 'g'}, - { "tbytes", no_argument, NULL, 't'}, - { "si", no_argument, NULL, GETOPT_VAL_SI}, - { "iec", no_argument, NULL, GETOPT_VAL_IEC}, - { "human-readable", no_argument, NULL, - GETOPT_VAL_HUMAN_READABLE}, - { NULL, 0, NULL, 0 } - }; + unit_mode = get_unit_mode_from_arg(&argc, argv, 1); - c = getopt_long(argc, argv, "bhHkmgt", long_options, NULL); - if (c < 0) - break; - switch (c) { - case 'b': - unit_mode = UNITS_RAW; - break; - case 'k': - units_set_base(&unit_mode, UNITS_KBYTES); - break; - case 'm': - units_set_base(&unit_mode, UNITS_MBYTES); - break; - case 'g': - units_set_base(&unit_mode, UNITS_GBYTES); - break; - case 't': - units_set_base(&unit_mode, UNITS_TBYTES); - break; - case GETOPT_VAL_HUMAN_READABLE: - case 'h': - unit_mode = UNITS_HUMAN_BINARY; - break; - case 'H': - unit_mode = UNITS_HUMAN_DECIMAL; - break; - case GETOPT_VAL_SI: - units_set_mode(&unit_mode, UNITS_DECIMAL); - break; - case GETOPT_VAL_IEC: - units_set_mode(&unit_mode, UNITS_BINARY); - break; - default: - usage(cmd_device_usage_usage); - } - } + clean_args_no_options(argc, argv, cmd_device_usage_usage); if (check_argc_min(argc - optind, 1)) usage(cmd_device_usage_usage); - for (i = optind; i < argc ; i++) { + for (i = optind; i < argc; i++) { int fd; - DIR *dirstream = NULL; - if (more_than_one) + DIR *dirstream = NULL; + + if (i > 1) printf("\n"); - fd = open_file_or_dir(argv[i], &dirstream); + fd = btrfs_open_dir(argv[i], &dirstream, 1); if (fd < 0) { - fprintf(stderr, "ERROR: can't access '%s'\n", - argv[1]); ret = 1; - goto out; + break; } ret = _cmd_device_usage(fd, argv[i], unit_mode); close_file_or_dir(fd, dirstream); if (ret) - goto out; - more_than_one = 1; + break; } -out: + return !!ret; }