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"
31 #include "cmds-fi-disk_usage.h"
35 static const char * const device_cmd_group_usage
[] = {
36 "btrfs device <command> [<args>]",
40 static const char * const cmd_add_dev_usage
[] = {
41 "btrfs device add [options] <device> [<device>...] <path>",
42 "Add a device to a filesystem",
43 "-K|--nodiscard do not perform whole device TRIM",
44 "-f|--force force overwrite existing filesystem on the disk",
48 static int cmd_add_dev(int argc
, char **argv
)
51 int i
, fdmnt
, ret
=0, e
;
52 DIR *dirstream
= NULL
;
59 static struct option long_options
[] = {
60 { "nodiscard", optional_argument
, NULL
, 'K'},
61 { "force", no_argument
, NULL
, 'f'},
64 int c
= getopt_long(argc
, argv
, "Kf", long_options
,
76 usage(cmd_add_dev_usage
);
82 if (check_argc_min(argc
, 2))
83 usage(cmd_add_dev_usage
);
85 mntpnt
= argv
[optind
+ argc
- 1];
87 fdmnt
= open_file_or_dir(mntpnt
, &dirstream
);
89 fprintf(stderr
, "ERROR: can't access '%s'\n", mntpnt
);
93 for (i
= optind
; i
< optind
+ argc
- 1; i
++){
94 struct btrfs_ioctl_vol_args ioctl_args
;
96 u64 dev_block_count
= 0;
100 res
= test_dev_for_mkfs(argv
[i
], force
, estr
);
102 fprintf(stderr
, "%s", estr
);
107 devfd
= open(argv
[i
], O_RDWR
);
109 fprintf(stderr
, "ERROR: Unable to open device '%s'\n", argv
[i
]);
114 res
= btrfs_prepare_device(devfd
, argv
[i
], 1, &dev_block_count
,
122 path
= canonicalize_path(argv
[i
]);
125 "ERROR: Could not canonicalize pathname '%s': %s\n",
126 argv
[i
], strerror(errno
));
131 strncpy_null(ioctl_args
.name
, path
);
132 res
= ioctl(fdmnt
, BTRFS_IOC_ADD_DEV
, &ioctl_args
);
135 fprintf(stderr
, "ERROR: error adding the device '%s' - %s\n",
143 close_file_or_dir(fdmnt
, dirstream
);
147 static const char * const cmd_rm_dev_usage
[] = {
148 "btrfs device delete <device> [<device>...] <path>",
149 "Remove a device from a filesystem",
153 static int cmd_rm_dev(int argc
, char **argv
)
156 int i
, fdmnt
, ret
=0, e
;
157 DIR *dirstream
= NULL
;
159 if (check_argc_min(argc
, 3))
160 usage(cmd_rm_dev_usage
);
162 mntpnt
= argv
[argc
- 1];
164 fdmnt
= open_file_or_dir(mntpnt
, &dirstream
);
166 fprintf(stderr
, "ERROR: can't access '%s'\n", mntpnt
);
170 for(i
=1 ; i
< argc
- 1; i
++ ){
171 struct btrfs_ioctl_vol_args arg
;
174 if (!is_block_device(argv
[i
])) {
176 "ERROR: %s is not a block device\n", argv
[i
]);
180 strncpy_null(arg
.name
, argv
[i
]);
181 res
= ioctl(fdmnt
, BTRFS_IOC_RM_DEV
, &arg
);
185 "ERROR: error removing the device '%s' - %s\n",
186 argv
[i
], btrfs_err_str(res
));
188 } else if (res
< 0) {
190 "ERROR: error removing the device '%s' - %s\n",
191 argv
[i
], strerror(e
));
196 close_file_or_dir(fdmnt
, dirstream
);
200 static const char * const cmd_scan_dev_usage
[] = {
201 "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
202 "Scan devices for a btrfs filesystem",
203 " -d|--all-devices (deprecated)",
207 static int cmd_scan_dev(int argc
, char **argv
)
217 static struct option long_options
[] = {
218 { "all-devices", no_argument
, NULL
, 'd'},
221 int c
= getopt_long(argc
, argv
, "d", long_options
,
230 usage(cmd_scan_dev_usage
);
234 if (all
&& check_argc_max(argc
, 2))
235 usage(cmd_scan_dev_usage
);
237 if (all
|| argc
== 1) {
238 printf("Scanning for Btrfs filesystems\n");
239 ret
= btrfs_scan_lblkid();
241 fprintf(stderr
, "ERROR: error %d while scanning\n", ret
);
242 ret
= btrfs_register_all_devices();
244 fprintf(stderr
, "ERROR: error %d while registering\n", ret
);
248 for( i
= devstart
; i
< argc
; i
++ ){
251 if (!is_block_device(argv
[i
])) {
253 "ERROR: %s is not a block device\n", argv
[i
]);
257 path
= canonicalize_path(argv
[i
]);
260 "ERROR: Could not canonicalize path '%s': %s\n",
261 argv
[i
], strerror(errno
));
265 printf("Scanning for Btrfs filesystems in '%s'\n", path
);
266 if (btrfs_register_one_device(path
) != 0) {
278 static const char * const cmd_ready_dev_usage
[] = {
279 "btrfs device ready <device>",
280 "Check device to see if it has all of its devices in cache for mounting",
284 static int cmd_ready_dev(int argc
, char **argv
)
286 struct btrfs_ioctl_vol_args args
;
291 if (check_argc_min(argc
, 2))
292 usage(cmd_ready_dev_usage
);
294 fd
= open("/dev/btrfs-control", O_RDWR
);
296 perror("failed to open /dev/btrfs-control");
300 path
= canonicalize_path(argv
[argc
- 1]);
303 "ERROR: Could not canonicalize pathname '%s': %s\n",
304 argv
[argc
- 1], strerror(errno
));
309 if (!is_block_device(path
)) {
311 "ERROR: %s is not a block device\n", path
);
316 strncpy(args
.name
, path
, BTRFS_PATH_NAME_MAX
);
317 ret
= ioctl(fd
, BTRFS_IOC_DEVICES_READY
, &args
);
319 fprintf(stderr
, "ERROR: unable to determine if the device '%s'"
320 " is ready for mounting - %s\n", path
,
331 static const char * const cmd_dev_stats_usage
[] = {
332 "btrfs device stats [-z] <path>|<device>",
333 "Show current device IO stats. -z to reset stats afterwards.",
337 static int cmd_dev_stats(int argc
, char **argv
)
340 struct btrfs_ioctl_fs_info_args fi_args
;
341 struct btrfs_ioctl_dev_info_args
*di_args
= NULL
;
348 DIR *dirstream
= NULL
;
351 while ((c
= getopt(argc
, argv
, "z")) != -1) {
354 flags
= BTRFS_DEV_STATS_RESET
;
358 usage(cmd_dev_stats_usage
);
362 argc
= argc
- optind
;
363 if (check_argc_exact(argc
, 1))
364 usage(cmd_dev_stats_usage
);
366 dev_path
= argv
[optind
];
368 fdmnt
= open_path_or_dev_mnt(dev_path
, &dirstream
);
373 "ERROR: '%s' is not a mounted btrfs device\n",
376 fprintf(stderr
, "ERROR: can't access '%s': %s\n",
377 dev_path
, strerror(errno
));
381 ret
= get_fs_info(dev_path
, &fi_args
, &di_args
);
383 fprintf(stderr
, "ERROR: getting dev info for devstats failed: "
384 "%s\n", strerror(-ret
));
388 if (!fi_args
.num_devices
) {
389 fprintf(stderr
, "ERROR: no devices found\n");
394 for (i
= 0; i
< fi_args
.num_devices
; i
++) {
395 struct btrfs_ioctl_get_dev_stats args
= {0};
396 __u8 path
[BTRFS_DEVICE_PATH_NAME_MAX
+ 1];
398 strncpy((char *)path
, (char *)di_args
[i
].path
,
399 BTRFS_DEVICE_PATH_NAME_MAX
);
400 path
[BTRFS_DEVICE_PATH_NAME_MAX
] = '\0';
402 args
.devid
= di_args
[i
].devid
;
403 args
.nr_items
= BTRFS_DEV_STAT_VALUES_MAX
;
406 if (ioctl(fdmnt
, BTRFS_IOC_GET_DEV_STATS
, &args
) < 0) {
408 "ERROR: ioctl(BTRFS_IOC_GET_DEV_STATS) on %s failed: %s\n",
409 path
, strerror(errno
));
412 char *canonical_path
;
414 canonical_path
= canonicalize_path((char *)path
);
416 if (args
.nr_items
>= BTRFS_DEV_STAT_WRITE_ERRS
+ 1)
417 printf("[%s].write_io_errs %llu\n",
419 (unsigned long long) args
.values
[
420 BTRFS_DEV_STAT_WRITE_ERRS
]);
421 if (args
.nr_items
>= BTRFS_DEV_STAT_READ_ERRS
+ 1)
422 printf("[%s].read_io_errs %llu\n",
424 (unsigned long long) args
.values
[
425 BTRFS_DEV_STAT_READ_ERRS
]);
426 if (args
.nr_items
>= BTRFS_DEV_STAT_FLUSH_ERRS
+ 1)
427 printf("[%s].flush_io_errs %llu\n",
429 (unsigned long long) args
.values
[
430 BTRFS_DEV_STAT_FLUSH_ERRS
]);
431 if (args
.nr_items
>= BTRFS_DEV_STAT_CORRUPTION_ERRS
+ 1)
432 printf("[%s].corruption_errs %llu\n",
434 (unsigned long long) args
.values
[
435 BTRFS_DEV_STAT_CORRUPTION_ERRS
]);
436 if (args
.nr_items
>= BTRFS_DEV_STAT_GENERATION_ERRS
+ 1)
437 printf("[%s].generation_errs %llu\n",
439 (unsigned long long) args
.values
[
440 BTRFS_DEV_STAT_GENERATION_ERRS
]);
442 free(canonical_path
);
448 close_file_or_dir(fdmnt
, dirstream
);
453 const char * const cmd_device_usage_usage
[] = {
454 "btrfs device usage [-b] <path> [<path>..]",
455 "Show which chunks are in a device.",
457 "-b\tSet byte as unit",
461 static int _cmd_device_usage(int fd
, char *path
, int mode
)
465 struct chunk_info
*chunkinfo
= NULL
;
466 struct device_info
*devinfo
= NULL
;
470 ret
= load_chunk_and_device_info(fd
, &chunkinfo
, &chunkcount
, &devinfo
,
475 for (i
= 0; i
< devcount
; i
++) {
476 printf("%s, ID: %llu\n", devinfo
[i
].path
, devinfo
[i
].devid
);
477 print_device_sizes(fd
, &devinfo
[i
], mode
);
478 print_device_chunks(fd
, &devinfo
[i
], chunkinfo
, chunkcount
,
490 int cmd_device_usage(int argc
, char **argv
)
493 int mode
= UNITS_HUMAN
;
495 int i
, more_than_one
= 0;
499 int c
= getopt(argc
, argv
, "b");
509 usage(cmd_device_usage_usage
);
513 if (check_argc_min(argc
- optind
, 1))
514 usage(cmd_device_usage_usage
);
516 for (i
= optind
; i
< argc
; i
++) {
518 DIR *dirstream
= NULL
;
522 fd
= open_file_or_dir(argv
[i
], &dirstream
);
524 fprintf(stderr
, "ERROR: can't access '%s'\n",
530 ret
= _cmd_device_usage(fd
, argv
[i
], mode
);
531 close_file_or_dir(fd
, dirstream
);
541 const struct cmd_group device_cmd_group
= {
542 device_cmd_group_usage
, NULL
, {
543 { "add", cmd_add_dev
, cmd_add_dev_usage
, NULL
, 0 },
544 { "delete", cmd_rm_dev
, cmd_rm_dev_usage
, NULL
, 0 },
545 { "scan", cmd_scan_dev
, cmd_scan_dev_usage
, NULL
, 0 },
546 { "ready", cmd_ready_dev
, cmd_ready_dev_usage
, NULL
, 0 },
547 { "stats", cmd_dev_stats
, cmd_dev_stats_usage
, NULL
, 0 },
548 { "usage", cmd_device_usage
,
549 cmd_device_usage_usage
, NULL
, 0 },
554 int cmd_device(int argc
, char **argv
)
556 return handle_command_group(&device_cmd_group
, argc
, argv
);