2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License v2 as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 * General Public License for more details.
11 * You should have received a copy of the GNU General Public
12 * License along with this program; if not, write to the
13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 * Boston, MA 021110-1307, USA.
22 #include <sys/ioctl.h>
27 #include "kerncompat.h"
32 #include "cmds-fi-usage.h"
36 static const char * const device_cmd_group_usage[] = {
37 "btrfs device <command> [<args>]",
41 static const char * const cmd_device_add_usage[] = {
42 "btrfs device add [options] <device> [<device>...] <path>",
43 "Add a device to a filesystem",
44 "-K|--nodiscard do not perform whole device TRIM",
45 "-f|--force force overwrite existing filesystem on the disk",
49 static int cmd_device_add(int argc, char **argv)
52 int i, fdmnt, ret = 0;
53 DIR *dirstream = NULL;
60 static const struct option long_options[] = {
61 { "nodiscard", optional_argument, NULL, 'K'},
62 { "force", no_argument, NULL, 'f'},
66 c = getopt_long(argc, argv, "Kf", long_options, NULL);
77 usage(cmd_device_add_usage);
81 if (check_argc_min(argc - optind, 2))
82 usage(cmd_device_add_usage);
85 mntpnt = argv[last_dev];
87 fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
91 for (i = optind; i < last_dev; i++){
92 struct btrfs_ioctl_vol_args ioctl_args;
94 u64 dev_block_count = 0;
97 res = test_dev_for_mkfs(argv[i], force);
103 devfd = open(argv[i], O_RDWR);
105 error("unable to open device '%s'", argv[i]);
110 res = btrfs_prepare_device(devfd, argv[i], &dev_block_count, 0,
111 PREP_DEVICE_ZERO_END | PREP_DEVICE_VERBOSE |
112 (discard ? PREP_DEVICE_DISCARD : 0));
119 path = canonicalize_path(argv[i]);
121 error("could not canonicalize pathname '%s': %s",
122 argv[i], strerror(errno));
127 memset(&ioctl_args, 0, sizeof(ioctl_args));
128 strncpy_null(ioctl_args.name, path);
129 res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
131 error("error adding device '%s': %s",
132 path, strerror(errno));
139 close_file_or_dir(fdmnt, dirstream);
143 static int _cmd_device_remove(int argc, char **argv,
144 const char * const *usagestr)
147 int i, fdmnt, ret = 0;
148 DIR *dirstream = NULL;
150 clean_args_no_options(argc, argv, usagestr);
152 if (check_argc_min(argc - optind, 2))
155 mntpnt = argv[argc - 1];
157 fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
161 for(i = optind; i < argc - 1; i++) {
162 struct btrfs_ioctl_vol_args arg;
163 struct btrfs_ioctl_vol_args_v2 argv2 = {0};
167 if (string_is_numerical(argv[i])) {
168 argv2.devid = arg_strtou64(argv[i]);
169 argv2.flags = BTRFS_DEVICE_SPEC_BY_ID;
171 } else if (is_block_device(argv[i]) == 1 ||
172 strcmp(argv[i], "missing") == 0) {
173 strncpy_null(argv2.name, argv[i]);
175 error("not a block device: %s", argv[i]);
181 * Positive values are from BTRFS_ERROR_DEV_*,
182 * otherwise it's a generic error, one of errnos
184 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV_V2, &argv2);
187 * If BTRFS_IOC_RM_DEV_V2 is not supported we get ENOTTY and if
188 * argv2.flags includes a flag which kernel doesn't understand then
189 * we shall get EOPNOTSUPP
191 if (res < 0 && (errno == ENOTTY || errno == EOPNOTSUPP)) {
193 error("device delete by id failed: %s",
198 memset(&arg, 0, sizeof(arg));
199 strncpy_null(arg.name, argv[i]);
200 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
207 msg = btrfs_err_str(res);
209 msg = strerror(errno);
211 error("error removing devid %llu: %s",
212 (unsigned long long)argv2.devid, msg);
214 error("error removing device '%s': %s",
221 close_file_or_dir(fdmnt, dirstream);
225 static const char * const cmd_device_remove_usage[] = {
226 "btrfs device remove <device>|<devid> [<device>|<devid>...] <path>",
227 "Remove a device from a filesystem",
231 static int cmd_device_remove(int argc, char **argv)
233 return _cmd_device_remove(argc, argv, cmd_device_remove_usage);
236 static const char * const cmd_device_delete_usage[] = {
237 "btrfs device delete <device>|<devid> [<device>|<devid>...] <path>",
238 "Remove a device from a filesystem",
242 static int cmd_device_delete(int argc, char **argv)
244 return _cmd_device_remove(argc, argv, cmd_device_delete_usage);
247 static const char * const cmd_device_scan_usage[] = {
248 "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
249 "Scan devices for a btrfs filesystem",
250 " -d|--all-devices (deprecated)",
254 static int cmd_device_scan(int argc, char **argv)
263 static const struct option long_options[] = {
264 { "all-devices", no_argument, NULL, 'd'},
268 c = getopt_long(argc, argv, "d", long_options, NULL);
276 usage(cmd_device_scan_usage);
281 if (all && check_argc_max(argc - optind, 1))
282 usage(cmd_device_scan_usage);
284 if (all || argc - optind == 0) {
285 printf("Scanning for Btrfs filesystems\n");
286 ret = btrfs_scan_devices();
287 error_on(ret, "error %d while scanning", ret);
288 ret = btrfs_register_all_devices();
289 error_on(ret, "there are %d errors while registering devices", ret);
293 for( i = devstart ; i < argc ; i++ ){
296 if (is_block_device(argv[i]) != 1) {
297 error("not a block device: %s", argv[i]);
301 path = canonicalize_path(argv[i]);
303 error("could not canonicalize path '%s': %s",
304 argv[i], strerror(errno));
308 printf("Scanning for Btrfs filesystems in '%s'\n", path);
309 if (btrfs_register_one_device(path) != 0) {
321 static const char * const cmd_device_ready_usage[] = {
322 "btrfs device ready <device>",
323 "Check device to see if it has all of its devices in cache for mounting",
327 static int cmd_device_ready(int argc, char **argv)
329 struct btrfs_ioctl_vol_args args;
334 clean_args_no_options(argc, argv, cmd_device_ready_usage);
336 if (check_argc_exact(argc - optind, 1))
337 usage(cmd_device_ready_usage);
339 fd = open("/dev/btrfs-control", O_RDWR);
341 perror("failed to open /dev/btrfs-control");
345 path = canonicalize_path(argv[optind]);
347 error("could not canonicalize pathname '%s': %s",
348 argv[optind], strerror(errno));
353 if (is_block_device(path) != 1) {
354 error("not a block device: %s", path);
359 memset(&args, 0, sizeof(args));
360 strncpy_null(args.name, path);
361 ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
363 error("unable to determine if device '%s' is ready for mount: %s",
364 path, strerror(errno));
374 static const char * const cmd_device_stats_usage[] = {
375 "btrfs device stats [options] <path>|<device>",
376 "Show device IO error statistics",
377 "Show device IO error statistics for all devices of the given filesystem",
378 "identified by PATH or DEVICE. The filesystem must be mounted.",
380 "-z|--reset show current stats and reset values to zero",
381 "-s return non-zero if any stat counter is not zero",
385 static int cmd_device_stats(int argc, char **argv)
388 struct btrfs_ioctl_fs_info_args fi_args;
389 struct btrfs_ioctl_dev_info_args *di_args = NULL;
396 DIR *dirstream = NULL;
400 static const struct option long_options[] = {
401 {"reset", no_argument, NULL, 'z'},
405 c = getopt_long(argc, argv, "zs", long_options, NULL);
411 flags = BTRFS_DEV_STATS_RESET;
418 usage(cmd_device_stats_usage);
422 if (check_argc_exact(argc - optind, 1))
423 usage(cmd_device_stats_usage);
425 dev_path = argv[optind];
427 fdmnt = open_path_or_dev_mnt(dev_path, &dirstream, 1);
431 ret = get_fs_info(dev_path, &fi_args, &di_args);
433 error("getting device info for %s failed: %s", dev_path,
438 if (!fi_args.num_devices) {
439 error("no devices found");
444 for (i = 0; i < fi_args.num_devices; i++) {
445 struct btrfs_ioctl_get_dev_stats args = {0};
446 char path[BTRFS_DEVICE_PATH_NAME_MAX + 1];
448 strncpy(path, (char *)di_args[i].path,
449 BTRFS_DEVICE_PATH_NAME_MAX);
450 path[BTRFS_DEVICE_PATH_NAME_MAX] = 0;
452 args.devid = di_args[i].devid;
453 args.nr_items = BTRFS_DEV_STAT_VALUES_MAX;
456 if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) {
457 error("device stats ioctl failed on %s: %s",
458 path, strerror(errno));
461 char *canonical_path;
463 static const struct {
467 { "write_io_errs", BTRFS_DEV_STAT_WRITE_ERRS },
468 { "read_io_errs", BTRFS_DEV_STAT_READ_ERRS },
469 { "flush_io_errs", BTRFS_DEV_STAT_FLUSH_ERRS },
471 BTRFS_DEV_STAT_CORRUPTION_ERRS },
473 BTRFS_DEV_STAT_GENERATION_ERRS },
476 canonical_path = canonicalize_path(path);
478 /* No path when device is missing. */
479 if (!canonical_path) {
480 canonical_path = malloc(32);
481 if (!canonical_path) {
482 error("not enough memory for path buffer");
485 snprintf(canonical_path, 32,
486 "devid:%llu", args.devid);
489 for (j = 0; j < ARRAY_SIZE(dev_stats); j++) {
490 /* We got fewer items than we know */
491 if (args.nr_items < dev_stats[j].num + 1)
493 printf("[%s].%-16s %llu\n", canonical_path,
496 args.values[dev_stats[j].num]);
498 && (args.values[dev_stats[j].num] > 0))
502 free(canonical_path);
508 close_file_or_dir(fdmnt, dirstream);
513 static const char * const cmd_device_usage_usage[] = {
514 "btrfs device usage [options] <path> [<path>..]",
515 "Show detailed information about internal allocations in devices.",
516 HELPINFO_UNITS_SHORT_LONG,
520 static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
524 struct chunk_info *chunkinfo = NULL;
525 struct device_info *devinfo = NULL;
529 ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
534 for (i = 0; i < devcount; i++) {
535 printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid);
536 print_device_sizes(fd, &devinfo[i], unit_mode);
537 print_device_chunks(fd, &devinfo[i], chunkinfo, chunkcount,
549 static int cmd_device_usage(int argc, char **argv)
555 unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
557 clean_args_no_options(argc, argv, cmd_device_usage_usage);
559 if (check_argc_min(argc - optind, 1))
560 usage(cmd_device_usage_usage);
562 for (i = optind; i < argc; i++) {
564 DIR *dirstream = NULL;
569 fd = btrfs_open_dir(argv[i], &dirstream, 1);
575 ret = _cmd_device_usage(fd, argv[i], unit_mode);
576 close_file_or_dir(fd, dirstream);
585 static const char device_cmd_group_info[] =
586 "manage and query devices in the filesystem";
588 const struct cmd_group device_cmd_group = {
589 device_cmd_group_usage, device_cmd_group_info, {
590 { "add", cmd_device_add, cmd_device_add_usage, NULL, 0 },
591 { "delete", cmd_device_delete, cmd_device_delete_usage, NULL,
593 { "remove", cmd_device_remove, cmd_device_remove_usage, NULL, 0 },
594 { "scan", cmd_device_scan, cmd_device_scan_usage, NULL, 0 },
595 { "ready", cmd_device_ready, cmd_device_ready_usage, NULL, 0 },
596 { "stats", cmd_device_stats, cmd_device_stats_usage, NULL, 0 },
597 { "usage", cmd_device_usage,
598 cmd_device_usage_usage, NULL, 0 },
603 int cmd_device(int argc, char **argv)
605 return handle_command_group(&device_cmd_group, argc, argv);