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
;
63 static const struct option long_options
[] = {
64 { "nodiscard", optional_argument
, NULL
, 'K'},
65 { "force", no_argument
, NULL
, 'f'},
69 c
= getopt_long(argc
, argv
, "Kf", long_options
, NULL
);
80 usage(cmd_device_add_usage
);
84 if (check_argc_min(argc
- optind
, 2))
85 usage(cmd_device_add_usage
);
88 mntpnt
= argv
[last_dev
];
90 fdmnt
= btrfs_open_dir(mntpnt
, &dirstream
, 1);
94 for (i
= optind
; i
< last_dev
; i
++){
95 struct btrfs_ioctl_vol_args ioctl_args
;
97 u64 dev_block_count
= 0;
100 res
= test_dev_for_mkfs(argv
[i
], force
);
106 devfd
= open(argv
[i
], O_RDWR
);
108 error("unable to open device '%s'", argv
[i
]);
113 res
= btrfs_prepare_device(devfd
, argv
[i
], &dev_block_count
, 0,
114 PREP_DEVICE_ZERO_END
| PREP_DEVICE_VERBOSE
|
115 (discard
? PREP_DEVICE_DISCARD
: 0));
122 path
= canonicalize_path(argv
[i
]);
124 error("could not canonicalize pathname '%s': %m",
130 memset(&ioctl_args
, 0, sizeof(ioctl_args
));
131 strncpy_null(ioctl_args
.name
, path
);
132 res
= ioctl(fdmnt
, BTRFS_IOC_ADD_DEV
, &ioctl_args
);
134 error("error adding device '%s': %m", path
);
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: %m");
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 #define COMMON_USAGE_REMOVE_DELETE \
227 "If 'missing' is specified for <device>, the first device that is", \
228 "described by the filesystem metadata, but not present at the mount", \
229 "time will be removed. (only in degraded mode)"
231 static const char * const cmd_device_remove_usage
[] = {
232 "btrfs device remove <device>|<devid> [<device>|<devid>...] <path>",
233 "Remove a device from a filesystem",
235 COMMON_USAGE_REMOVE_DELETE
,
239 static int cmd_device_remove(int argc
, char **argv
)
241 return _cmd_device_remove(argc
, argv
, cmd_device_remove_usage
);
244 static const char * const cmd_device_delete_usage
[] = {
245 "btrfs device delete <device>|<devid> [<device>|<devid>...] <path>",
246 "Remove a device from a filesystem (alias of \"btrfs device remove\")",
248 COMMON_USAGE_REMOVE_DELETE
,
252 static int cmd_device_delete(int argc
, char **argv
)
254 return _cmd_device_remove(argc
, argv
, cmd_device_delete_usage
);
257 static const char * const cmd_device_scan_usage
[] = {
258 "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
259 "Scan devices for a btrfs filesystem",
260 " -d|--all-devices (deprecated)",
264 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': %m", argv
[i
]);
318 printf("Scanning for Btrfs filesystems in '%s'\n", path
);
319 if (btrfs_register_one_device(path
) != 0) {
331 static const char * const cmd_device_ready_usage
[] = {
332 "btrfs device ready <device>",
333 "Check device to see if it has all of its devices in cache for mounting",
337 static int cmd_device_ready(int argc
, char **argv
)
339 struct btrfs_ioctl_vol_args args
;
344 clean_args_no_options(argc
, argv
, cmd_device_ready_usage
);
346 if (check_argc_exact(argc
- optind
, 1))
347 usage(cmd_device_ready_usage
);
349 fd
= open("/dev/btrfs-control", O_RDWR
);
351 perror("failed to open /dev/btrfs-control");
355 path
= canonicalize_path(argv
[optind
]);
357 error("could not canonicalize pathname '%s': %m",
363 if (is_block_device(path
) != 1) {
364 error("not a block device: %s", path
);
369 memset(&args
, 0, sizeof(args
));
370 strncpy_null(args
.name
, path
);
371 ret
= ioctl(fd
, BTRFS_IOC_DEVICES_READY
, &args
);
373 error("unable to determine if device '%s' is ready for mount: %m",
384 static const char * const cmd_device_stats_usage
[] = {
385 "btrfs device stats [options] <path>|<device>",
386 "Show device IO error statistics",
387 "Show device IO error statistics for all devices of the given filesystem",
388 "identified by PATH or DEVICE. The filesystem must be mounted.",
390 "-c|--check return non-zero if any stat counter is not zero",
391 "-z|--reset show current stats and reset values to zero",
395 static int cmd_device_stats(int argc
, char **argv
)
398 struct btrfs_ioctl_fs_info_args fi_args
;
399 struct btrfs_ioctl_dev_info_args
*di_args
= NULL
;
406 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: %m",
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
, const 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
);