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 #include "mkfs/common.h"
38 static const char * const device_cmd_group_usage[] = {
39 "btrfs device <command> [<args>]",
43 static const char * const cmd_device_add_usage[] = {
44 "btrfs device add [options] <device> [<device>...] <path>",
45 "Add a device to a filesystem",
46 "-K|--nodiscard do not perform whole device TRIM",
47 "-f|--force force overwrite existing filesystem on the disk",
51 static int cmd_device_add(int argc, char **argv)
54 int i, fdmnt, ret = 0;
55 DIR *dirstream = NULL;
62 static const struct option long_options[] = {
63 { "nodiscard", optional_argument, NULL, 'K'},
64 { "force", no_argument, NULL, 'f'},
68 c = getopt_long(argc, argv, "Kf", long_options, NULL);
79 usage(cmd_device_add_usage);
83 if (check_argc_min(argc - optind, 2))
84 usage(cmd_device_add_usage);
87 mntpnt = argv[last_dev];
89 fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
93 for (i = optind; i < last_dev; i++){
94 struct btrfs_ioctl_vol_args ioctl_args;
96 u64 dev_block_count = 0;
99 res = test_dev_for_mkfs(argv[i], force);
105 devfd = open(argv[i], O_RDWR);
107 error("unable to open device '%s'", argv[i]);
112 res = btrfs_prepare_device(devfd, argv[i], &dev_block_count, 0,
113 PREP_DEVICE_ZERO_END | PREP_DEVICE_VERBOSE |
114 (discard ? PREP_DEVICE_DISCARD : 0));
121 path = canonicalize_path(argv[i]);
123 error("could not canonicalize pathname '%s': %s",
124 argv[i], strerror(errno));
129 memset(&ioctl_args, 0, sizeof(ioctl_args));
130 strncpy_null(ioctl_args.name, path);
131 res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
133 error("error adding device '%s': %s",
134 path, strerror(errno));
141 close_file_or_dir(fdmnt, dirstream);
145 static int _cmd_device_remove(int argc, char **argv,
146 const char * const *usagestr)
149 int i, fdmnt, ret = 0;
150 DIR *dirstream = NULL;
152 clean_args_no_options(argc, argv, usagestr);
154 if (check_argc_min(argc - optind, 2))
157 mntpnt = argv[argc - 1];
159 fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
163 for(i = optind; i < argc - 1; i++) {
164 struct btrfs_ioctl_vol_args arg;
165 struct btrfs_ioctl_vol_args_v2 argv2 = {0};
169 if (string_is_numerical(argv[i])) {
170 argv2.devid = arg_strtou64(argv[i]);
171 argv2.flags = BTRFS_DEVICE_SPEC_BY_ID;
173 } else if (is_block_device(argv[i]) == 1 ||
174 strcmp(argv[i], "missing") == 0) {
175 strncpy_null(argv2.name, argv[i]);
177 error("not a block device: %s", argv[i]);
183 * Positive values are from BTRFS_ERROR_DEV_*,
184 * otherwise it's a generic error, one of errnos
186 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV_V2, &argv2);
189 * If BTRFS_IOC_RM_DEV_V2 is not supported we get ENOTTY and if
190 * argv2.flags includes a flag which kernel doesn't understand then
191 * we shall get EOPNOTSUPP
193 if (res < 0 && (errno == ENOTTY || errno == EOPNOTSUPP)) {
195 error("device delete by id failed: %s",
200 memset(&arg, 0, sizeof(arg));
201 strncpy_null(arg.name, argv[i]);
202 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
209 msg = btrfs_err_str(res);
211 msg = strerror(errno);
213 error("error removing devid %llu: %s",
214 (unsigned long long)argv2.devid, msg);
216 error("error removing device '%s': %s",
223 close_file_or_dir(fdmnt, dirstream);
227 #define COMMON_USAGE_REMOVE_DELETE \
228 "If 'missing' is specified for <device>, the first device that is", \
229 "described by the filesystem metadata, but not present at the mount", \
230 "time will be removed. (only in degraded mode)"
232 static const char * const cmd_device_remove_usage[] = {
233 "btrfs device remove <device>|<devid> [<device>|<devid>...] <path>",
234 "Remove a device from a filesystem",
236 COMMON_USAGE_REMOVE_DELETE,
240 static int cmd_device_remove(int argc, char **argv)
242 return _cmd_device_remove(argc, argv, cmd_device_remove_usage);
245 static const char * const cmd_device_delete_usage[] = {
246 "btrfs device delete <device>|<devid> [<device>|<devid>...] <path>",
247 "Remove a device from a filesystem (alias of \"btrfs device remove\")",
249 COMMON_USAGE_REMOVE_DELETE,
253 static int cmd_device_delete(int argc, char **argv)
255 return _cmd_device_remove(argc, argv, cmd_device_delete_usage);
258 static const char * const cmd_device_scan_usage[] = {
259 "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
260 "Scan devices for a btrfs filesystem",
261 " -d|--all-devices (deprecated)",
265 static int cmd_device_scan(int argc, char **argv)
274 static const struct option long_options[] = {
275 { "all-devices", no_argument, NULL, 'd'},
279 c = getopt_long(argc, argv, "d", long_options, NULL);
287 usage(cmd_device_scan_usage);
292 if (all && check_argc_max(argc - optind, 1))
293 usage(cmd_device_scan_usage);
295 if (all || argc - optind == 0) {
296 printf("Scanning for Btrfs filesystems\n");
297 ret = btrfs_scan_devices();
298 error_on(ret, "error %d while scanning", ret);
299 ret = btrfs_register_all_devices();
300 error_on(ret, "there are %d errors while registering devices", ret);
304 for( i = devstart ; i < argc ; i++ ){
307 if (is_block_device(argv[i]) != 1) {
308 error("not a block device: %s", argv[i]);
312 path = canonicalize_path(argv[i]);
314 error("could not canonicalize path '%s': %s",
315 argv[i], strerror(errno));
319 printf("Scanning for Btrfs filesystems in '%s'\n", path);
320 if (btrfs_register_one_device(path) != 0) {
332 static const char * const cmd_device_ready_usage[] = {
333 "btrfs device ready <device>",
334 "Check device to see if it has all of its devices in cache for mounting",
338 static int cmd_device_ready(int argc, char **argv)
340 struct btrfs_ioctl_vol_args args;
345 clean_args_no_options(argc, argv, cmd_device_ready_usage);
347 if (check_argc_exact(argc - optind, 1))
348 usage(cmd_device_ready_usage);
350 fd = open("/dev/btrfs-control", O_RDWR);
352 perror("failed to open /dev/btrfs-control");
356 path = canonicalize_path(argv[optind]);
358 error("could not canonicalize pathname '%s': %s",
359 argv[optind], strerror(errno));
364 if (is_block_device(path) != 1) {
365 error("not a block device: %s", path);
370 memset(&args, 0, sizeof(args));
371 strncpy_null(args.name, path);
372 ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
374 error("unable to determine if device '%s' is ready for mount: %s",
375 path, strerror(errno));
385 static const char * const cmd_device_stats_usage[] = {
386 "btrfs device stats [options] <path>|<device>",
387 "Show device IO error statistics",
388 "Show device IO error statistics for all devices of the given filesystem",
389 "identified by PATH or DEVICE. The filesystem must be mounted.",
391 "-c|--check return non-zero if any stat counter is not zero",
392 "-z|--reset show current stats and reset values to zero",
396 static int cmd_device_stats(int argc, char **argv)
399 struct btrfs_ioctl_fs_info_args fi_args;
400 struct btrfs_ioctl_dev_info_args *di_args = NULL;
407 DIR *dirstream = NULL;
411 static const struct option long_options[] = {
412 {"check", no_argument, NULL, 'c'},
413 {"reset", no_argument, NULL, 'z'},
417 c = getopt_long(argc, argv, "cz", long_options, NULL);
426 flags = BTRFS_DEV_STATS_RESET;
430 usage(cmd_device_stats_usage);
434 if (check_argc_exact(argc - optind, 1))
435 usage(cmd_device_stats_usage);
437 dev_path = argv[optind];
439 fdmnt = open_path_or_dev_mnt(dev_path, &dirstream, 1);
443 ret = get_fs_info(dev_path, &fi_args, &di_args);
445 error("getting device info for %s failed: %s", dev_path,
450 if (!fi_args.num_devices) {
451 error("no devices found");
456 for (i = 0; i < fi_args.num_devices; i++) {
457 struct btrfs_ioctl_get_dev_stats args = {0};
458 char path[BTRFS_DEVICE_PATH_NAME_MAX + 1];
460 strncpy(path, (char *)di_args[i].path,
461 BTRFS_DEVICE_PATH_NAME_MAX);
462 path[BTRFS_DEVICE_PATH_NAME_MAX] = 0;
464 args.devid = di_args[i].devid;
465 args.nr_items = BTRFS_DEV_STAT_VALUES_MAX;
468 if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) {
469 error("device stats ioctl failed on %s: %s",
470 path, strerror(errno));
473 char *canonical_path;
475 static const struct {
479 { "write_io_errs", BTRFS_DEV_STAT_WRITE_ERRS },
480 { "read_io_errs", BTRFS_DEV_STAT_READ_ERRS },
481 { "flush_io_errs", BTRFS_DEV_STAT_FLUSH_ERRS },
483 BTRFS_DEV_STAT_CORRUPTION_ERRS },
485 BTRFS_DEV_STAT_GENERATION_ERRS },
488 canonical_path = canonicalize_path(path);
490 /* No path when device is missing. */
491 if (!canonical_path) {
492 canonical_path = malloc(32);
493 if (!canonical_path) {
494 error("not enough memory for path buffer");
497 snprintf(canonical_path, 32,
498 "devid:%llu", args.devid);
501 for (j = 0; j < ARRAY_SIZE(dev_stats); j++) {
502 /* We got fewer items than we know */
503 if (args.nr_items < dev_stats[j].num + 1)
505 printf("[%s].%-16s %llu\n", canonical_path,
508 args.values[dev_stats[j].num]);
510 && (args.values[dev_stats[j].num] > 0))
514 free(canonical_path);
520 close_file_or_dir(fdmnt, dirstream);
525 static const char * const cmd_device_usage_usage[] = {
526 "btrfs device usage [options] <path> [<path>..]",
527 "Show detailed information about internal allocations in devices.",
528 HELPINFO_UNITS_SHORT_LONG,
532 static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
536 struct chunk_info *chunkinfo = NULL;
537 struct device_info *devinfo = NULL;
541 ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
546 for (i = 0; i < devcount; i++) {
547 printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid);
548 print_device_sizes(&devinfo[i], unit_mode);
549 print_device_chunks(&devinfo[i], chunkinfo, chunkcount,
561 static int cmd_device_usage(int argc, char **argv)
567 unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
569 clean_args_no_options(argc, argv, cmd_device_usage_usage);
571 if (check_argc_min(argc - optind, 1))
572 usage(cmd_device_usage_usage);
574 for (i = optind; i < argc; i++) {
576 DIR *dirstream = NULL;
581 fd = btrfs_open_dir(argv[i], &dirstream, 1);
587 ret = _cmd_device_usage(fd, argv[i], unit_mode);
588 close_file_or_dir(fd, dirstream);
597 static const char device_cmd_group_info[] =
598 "manage and query devices in the filesystem";
600 const struct cmd_group device_cmd_group = {
601 device_cmd_group_usage, device_cmd_group_info, {
602 { "add", cmd_device_add, cmd_device_add_usage, NULL, 0 },
603 { "delete", cmd_device_delete, cmd_device_delete_usage, NULL,
605 { "remove", cmd_device_remove, cmd_device_remove_usage, NULL, 0 },
606 { "scan", cmd_device_scan, cmd_device_scan_usage, NULL, 0 },
607 { "ready", cmd_device_ready, cmd_device_ready_usage, NULL, 0 },
608 { "stats", cmd_device_stats, cmd_device_stats_usage, NULL, 0 },
609 { "usage", cmd_device_usage,
610 cmd_device_usage_usage, NULL, 0 },
615 int cmd_device(int argc, char **argv)
617 return handle_command_group(&device_cmd_group, argc, argv);