X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=cmds-device.c;h=86459d1b956430585c5649986dbd346a16cb6409;hb=f5dd778f5299088f89d380ce922a84d77a98b9d6;hp=bea1a06cb44055d322d5e51b4d4be37249464953;hpb=56480048e4f9f3e79f835b531a4b03d7fe94100b;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/cmds-device.c b/cmds-device.c index bea1a06..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,7 +51,7 @@ 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; @@ -102,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, 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++; @@ -117,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; } @@ -127,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); @@ -145,10 +145,12 @@ 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]; @@ -157,30 +159,61 @@ static int _cmd_device_remove(int argc, char **argv, 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]) != 1 && strcmp(argv[i], "missing")) { - 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++; } } @@ -189,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 }; @@ -201,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 }; @@ -221,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[] = { @@ -244,18 +285,17 @@ 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; } @@ -263,16 +303,13 @@ static int cmd_device_scan(int argc, char **argv) char *path; if (is_block_device(argv[i]) != 1) { - fprintf(stderr, - "ERROR: %s is not a block device\n", argv[i]); + 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; } @@ -302,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); @@ -311,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) != 1) { - fprintf(stderr, - "ERROR: %s is not a block device\n", path); + error("not a block device: %s", path); ret = 1; goto out; } @@ -331,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; } @@ -344,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 }; @@ -359,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; @@ -376,8 +428,7 @@ 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]; @@ -388,64 +439,74 @@ static int cmd_device_stats(int argc, char **argv) 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); } @@ -481,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"); } @@ -498,35 +559,35 @@ static int cmd_device_usage(int argc, char **argv) { unsigned unit_mode; int ret = 0; - int more_than_one = 0; int i; unit_mode = get_unit_mode_from_arg(&argc, argv, 1); - if (check_argc_min(argc, 2) || argv[1][0] == '-') + clean_args_no_options(argc, argv, cmd_device_usage_usage); + + if (check_argc_min(argc - optind, 1)) usage(cmd_device_usage_usage); - for (i = 1; i < argc; i++) { + for (i = optind; i < argc; i++) { int fd; DIR *dirstream = NULL; - if (more_than_one) + if (i > 1) printf("\n"); fd = btrfs_open_dir(argv[i], &dirstream, 1); if (fd < 0) { 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; }