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"
37 static const char * const device_cmd_group_usage[] = {
38 "btrfs device <command> [<args>]",
42 static const char * const cmd_device_add_usage[] = {
43 "btrfs device add [options] <device> [<device>...] <path>",
44 "Add a device to a filesystem",
45 "-K|--nodiscard do not perform whole device TRIM",
46 "-f|--force force overwrite existing filesystem on the disk",
50 static int cmd_device_add(int argc, char **argv)
53 int i, fdmnt, ret = 0;
54 DIR *dirstream = NULL;
61 static const struct option long_options[] = {
62 { "nodiscard", optional_argument, NULL, 'K'},
63 { "force", no_argument, NULL, 'f'},
67 c = getopt_long(argc, argv, "Kf", long_options, NULL);
78 usage(cmd_device_add_usage);
82 if (check_argc_min(argc - optind, 2))
83 usage(cmd_device_add_usage);
86 mntpnt = argv[last_dev];
88 fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
92 for (i = optind; i < last_dev; i++){
93 struct btrfs_ioctl_vol_args ioctl_args;
95 u64 dev_block_count = 0;
98 res = test_dev_for_mkfs(argv[i], force);
104 devfd = open(argv[i], O_RDWR);
106 error("unable to open device '%s'", argv[i]);
111 res = btrfs_prepare_device(devfd, argv[i], &dev_block_count, 0,
112 PREP_DEVICE_ZERO_END | PREP_DEVICE_VERBOSE |
113 (discard ? PREP_DEVICE_DISCARD : 0));
120 path = canonicalize_path(argv[i]);
122 error("could not canonicalize pathname '%s': %s",
123 argv[i], strerror(errno));
128 memset(&ioctl_args, 0, sizeof(ioctl_args));
129 strncpy_null(ioctl_args.name, path);
130 res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
132 error("error adding device '%s': %s",
133 path, strerror(errno));
140 close_file_or_dir(fdmnt, dirstream);
144 static int _cmd_device_remove(int argc, char **argv,
145 const char * const *usagestr)
148 int i, fdmnt, ret = 0;
149 DIR *dirstream = NULL;
151 clean_args_no_options(argc, argv, usagestr);
153 if (check_argc_min(argc - optind, 2))
156 mntpnt = argv[argc - 1];
158 fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
162 for(i = optind; i < argc - 1; i++) {
163 struct btrfs_ioctl_vol_args arg;
164 struct btrfs_ioctl_vol_args_v2 argv2 = {0};
168 if (string_is_numerical(argv[i])) {
169 argv2.devid = arg_strtou64(argv[i]);
170 argv2.flags = BTRFS_DEVICE_SPEC_BY_ID;
172 } else if (is_block_device(argv[i]) == 1 ||
173 strcmp(argv[i], "missing") == 0) {
174 strncpy_null(argv2.name, argv[i]);
176 error("not a block device: %s", argv[i]);
182 * Positive values are from BTRFS_ERROR_DEV_*,
183 * otherwise it's a generic error, one of errnos
185 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV_V2, &argv2);
188 * If BTRFS_IOC_RM_DEV_V2 is not supported we get ENOTTY and if
189 * argv2.flags includes a flag which kernel doesn't understand then
190 * we shall get EOPNOTSUPP
192 if (res < 0 && (errno == ENOTTY || errno == EOPNOTSUPP)) {
194 error("device delete by id failed: %s",
199 memset(&arg, 0, sizeof(arg));
200 strncpy_null(arg.name, argv[i]);
201 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
208 msg = btrfs_err_str(res);
210 msg = strerror(errno);
212 error("error removing devid %llu: %s",
213 (unsigned long long)argv2.devid, msg);
215 error("error removing device '%s': %s",
222 close_file_or_dir(fdmnt, dirstream);
226 static const char * const cmd_device_remove_usage[] = {
227 "btrfs device remove <device>|<devid> [<device>|<devid>...] <path>",
228 "Remove a device from a filesystem",
232 static int cmd_device_remove(int argc, char **argv)
234 return _cmd_device_remove(argc, argv, cmd_device_remove_usage);
237 static const char * const cmd_device_delete_usage[] = {
238 "btrfs device delete <device>|<devid> [<device>|<devid>...] <path>",
239 "Remove a device from a filesystem",
243 static int cmd_device_delete(int argc, char **argv)
245 return _cmd_device_remove(argc, argv, cmd_device_delete_usage);
248 static const char * const cmd_device_scan_usage[] = {
249 "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
250 "Scan devices for a btrfs filesystem",
251 " -d|--all-devices (deprecated)",
255 static int cmd_device_scan(int argc, char **argv)
264 static const struct option long_options[] = {
265 { "all-devices", no_argument, NULL, 'd'},
269 c = getopt_long(argc, argv, "d", long_options, NULL);
277 usage(cmd_device_scan_usage);
282 if (all && check_argc_max(argc - optind, 1))
283 usage(cmd_device_scan_usage);
285 if (all || argc - optind == 0) {
286 printf("Scanning for Btrfs filesystems\n");
287 ret = btrfs_scan_devices();
288 error_on(ret, "error %d while scanning", ret);
289 ret = btrfs_register_all_devices();
290 error_on(ret, "there are %d errors while registering devices", ret);
294 for( i = devstart ; i < argc ; i++ ){
297 if (is_block_device(argv[i]) != 1) {
298 error("not a block device: %s", argv[i]);
302 path = canonicalize_path(argv[i]);
304 error("could not canonicalize path '%s': %s",
305 argv[i], strerror(errno));
309 printf("Scanning for Btrfs filesystems in '%s'\n", path);
310 if (btrfs_register_one_device(path) != 0) {
322 static const char * const cmd_device_ready_usage[] = {
323 "btrfs device ready <device>",
324 "Check device to see if it has all of its devices in cache for mounting",
328 static int cmd_device_ready(int argc, char **argv)
330 struct btrfs_ioctl_vol_args args;
335 clean_args_no_options(argc, argv, cmd_device_ready_usage);
337 if (check_argc_exact(argc - optind, 1))
338 usage(cmd_device_ready_usage);
340 fd = open("/dev/btrfs-control", O_RDWR);
342 perror("failed to open /dev/btrfs-control");
346 path = canonicalize_path(argv[optind]);
348 error("could not canonicalize pathname '%s': %s",
349 argv[optind], strerror(errno));
354 if (is_block_device(path) != 1) {
355 error("not a block device: %s", path);
360 memset(&args, 0, sizeof(args));
361 strncpy_null(args.name, path);
362 ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
364 error("unable to determine if device '%s' is ready for mount: %s",
365 path, strerror(errno));
375 static const char * const cmd_device_stats_usage[] = {
376 "btrfs device stats [options] <path>|<device>",
377 "Show device IO error statistics",
378 "Show device IO error statistics for all devices of the given filesystem",
379 "identified by PATH or DEVICE. The filesystem must be mounted.",
381 "-c|--check return non-zero if any stat counter is not zero",
382 "-z|--reset show current stats and reset values to zero",
386 static int cmd_device_stats(int argc, char **argv)
389 struct btrfs_ioctl_fs_info_args fi_args;
390 struct btrfs_ioctl_dev_info_args *di_args = NULL;
397 DIR *dirstream = NULL;
401 static const struct option long_options[] = {
402 {"reset", no_argument, NULL, 'z'},
406 c = getopt_long(argc, argv, "cz", long_options, NULL);
415 flags = BTRFS_DEV_STATS_RESET;
419 usage(cmd_device_stats_usage);
423 if (check_argc_exact(argc - optind, 1))
424 usage(cmd_device_stats_usage);
426 dev_path = argv[optind];
428 fdmnt = open_path_or_dev_mnt(dev_path, &dirstream, 1);
432 ret = get_fs_info(dev_path, &fi_args, &di_args);
434 error("getting device info for %s failed: %s", dev_path,
439 if (!fi_args.num_devices) {
440 error("no devices found");
445 for (i = 0; i < fi_args.num_devices; i++) {
446 struct btrfs_ioctl_get_dev_stats args = {0};
447 char path[BTRFS_DEVICE_PATH_NAME_MAX + 1];
449 strncpy(path, (char *)di_args[i].path,
450 BTRFS_DEVICE_PATH_NAME_MAX);
451 path[BTRFS_DEVICE_PATH_NAME_MAX] = 0;
453 args.devid = di_args[i].devid;
454 args.nr_items = BTRFS_DEV_STAT_VALUES_MAX;
457 if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) {
458 error("device stats ioctl failed on %s: %s",
459 path, strerror(errno));
462 char *canonical_path;
464 static const struct {
468 { "write_io_errs", BTRFS_DEV_STAT_WRITE_ERRS },
469 { "read_io_errs", BTRFS_DEV_STAT_READ_ERRS },
470 { "flush_io_errs", BTRFS_DEV_STAT_FLUSH_ERRS },
472 BTRFS_DEV_STAT_CORRUPTION_ERRS },
474 BTRFS_DEV_STAT_GENERATION_ERRS },
477 canonical_path = canonicalize_path(path);
479 /* No path when device is missing. */
480 if (!canonical_path) {
481 canonical_path = malloc(32);
482 if (!canonical_path) {
483 error("not enough memory for path buffer");
486 snprintf(canonical_path, 32,
487 "devid:%llu", args.devid);
490 for (j = 0; j < ARRAY_SIZE(dev_stats); j++) {
491 /* We got fewer items than we know */
492 if (args.nr_items < dev_stats[j].num + 1)
494 printf("[%s].%-16s %llu\n", canonical_path,
497 args.values[dev_stats[j].num]);
499 && (args.values[dev_stats[j].num] > 0))
503 free(canonical_path);
509 close_file_or_dir(fdmnt, dirstream);
514 static const char * const cmd_device_usage_usage[] = {
515 "btrfs device usage [options] <path> [<path>..]",
516 "Show detailed information about internal allocations in devices.",
517 HELPINFO_UNITS_SHORT_LONG,
521 static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
525 struct chunk_info *chunkinfo = NULL;
526 struct device_info *devinfo = NULL;
530 ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
535 for (i = 0; i < devcount; i++) {
536 printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid);
537 print_device_sizes(fd, &devinfo[i], unit_mode);
538 print_device_chunks(fd, &devinfo[i], chunkinfo, chunkcount,
550 static int cmd_device_usage(int argc, char **argv)
556 unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
558 clean_args_no_options(argc, argv, cmd_device_usage_usage);
560 if (check_argc_min(argc - optind, 1))
561 usage(cmd_device_usage_usage);
563 for (i = optind; i < argc; i++) {
565 DIR *dirstream = NULL;
570 fd = btrfs_open_dir(argv[i], &dirstream, 1);
576 ret = _cmd_device_usage(fd, argv[i], unit_mode);
577 close_file_or_dir(fd, dirstream);
586 static const char device_cmd_group_info[] =
587 "manage and query devices in the filesystem";
589 const struct cmd_group device_cmd_group = {
590 device_cmd_group_usage, device_cmd_group_info, {
591 { "add", cmd_device_add, cmd_device_add_usage, NULL, 0 },
592 { "delete", cmd_device_delete, cmd_device_delete_usage, NULL,
594 { "remove", cmd_device_remove, cmd_device_remove_usage, NULL, 0 },
595 { "scan", cmd_device_scan, cmd_device_scan_usage, NULL, 0 },
596 { "ready", cmd_device_ready, cmd_device_ready_usage, NULL, 0 },
597 { "stats", cmd_device_stats, cmd_device_stats_usage, NULL, 0 },
598 { "usage", cmd_device_usage,
599 cmd_device_usage_usage, NULL, 0 },
604 int cmd_device(int argc, char **argv)
606 return handle_command_group(&device_cmd_group, argc, argv);