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-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 const struct option long_options
[] = {
60 { "nodiscard", optional_argument
, NULL
, 'K'},
61 { "force", no_argument
, NULL
, 'f'},
65 c
= getopt_long(argc
, argv
, "Kf", long_options
, NULL
);
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
);
187 msg
= btrfs_err_str(res
);
191 "ERROR: error removing the device '%s' - %s\n",
197 close_file_or_dir(fdmnt
, dirstream
);
201 static const char * const cmd_scan_dev_usage
[] = {
202 "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
203 "Scan devices for a btrfs filesystem",
204 " -d|--all-devices (deprecated)",
208 static int cmd_scan_dev(int argc
, char **argv
)
218 static const struct option long_options
[] = {
219 { "all-devices", no_argument
, NULL
, 'd'},
223 c
= getopt_long(argc
, argv
, "d", long_options
, NULL
);
231 usage(cmd_scan_dev_usage
);
235 if (all
&& check_argc_max(argc
, 2))
236 usage(cmd_scan_dev_usage
);
238 if (all
|| argc
== 1) {
239 printf("Scanning for Btrfs filesystems\n");
240 ret
= btrfs_scan_lblkid();
242 fprintf(stderr
, "ERROR: error %d while scanning\n", ret
);
243 ret
= btrfs_register_all_devices();
245 fprintf(stderr
, "ERROR: error %d while registering\n", ret
);
249 for( i
= devstart
; i
< argc
; i
++ ){
252 if (!is_block_device(argv
[i
])) {
254 "ERROR: %s is not a block device\n", argv
[i
]);
258 path
= canonicalize_path(argv
[i
]);
261 "ERROR: Could not canonicalize path '%s': %s\n",
262 argv
[i
], strerror(errno
));
266 printf("Scanning for Btrfs filesystems in '%s'\n", path
);
267 if (btrfs_register_one_device(path
) != 0) {
279 static const char * const cmd_ready_dev_usage
[] = {
280 "btrfs device ready <device>",
281 "Check device to see if it has all of its devices in cache for mounting",
285 static int cmd_ready_dev(int argc
, char **argv
)
287 struct btrfs_ioctl_vol_args args
;
292 if (check_argc_min(argc
, 2))
293 usage(cmd_ready_dev_usage
);
295 fd
= open("/dev/btrfs-control", O_RDWR
);
297 perror("failed to open /dev/btrfs-control");
301 path
= canonicalize_path(argv
[argc
- 1]);
304 "ERROR: Could not canonicalize pathname '%s': %s\n",
305 argv
[argc
- 1], strerror(errno
));
310 if (!is_block_device(path
)) {
312 "ERROR: %s is not a block device\n", path
);
317 strncpy(args
.name
, path
, BTRFS_PATH_NAME_MAX
);
318 ret
= ioctl(fd
, BTRFS_IOC_DEVICES_READY
, &args
);
320 fprintf(stderr
, "ERROR: unable to determine if the device '%s'"
321 " is ready for mounting - %s\n", path
,
332 static const char * const cmd_dev_stats_usage
[] = {
333 "btrfs device stats [-z] <path>|<device>",
334 "Show current device IO stats. -z to reset stats afterwards.",
338 static int cmd_dev_stats(int argc
, char **argv
)
341 struct btrfs_ioctl_fs_info_args fi_args
;
342 struct btrfs_ioctl_dev_info_args
*di_args
= NULL
;
349 DIR *dirstream
= NULL
;
352 while ((c
= getopt(argc
, argv
, "z")) != -1) {
355 flags
= BTRFS_DEV_STATS_RESET
;
359 usage(cmd_dev_stats_usage
);
363 argc
= argc
- optind
;
364 if (check_argc_exact(argc
, 1))
365 usage(cmd_dev_stats_usage
);
367 dev_path
= argv
[optind
];
369 fdmnt
= open_path_or_dev_mnt(dev_path
, &dirstream
);
374 "ERROR: '%s' is not a mounted btrfs device\n",
377 fprintf(stderr
, "ERROR: can't access '%s': %s\n",
378 dev_path
, strerror(errno
));
382 ret
= get_fs_info(dev_path
, &fi_args
, &di_args
);
384 fprintf(stderr
, "ERROR: getting dev info for devstats failed: "
385 "%s\n", strerror(-ret
));
389 if (!fi_args
.num_devices
) {
390 fprintf(stderr
, "ERROR: no devices found\n");
395 for (i
= 0; i
< fi_args
.num_devices
; i
++) {
396 struct btrfs_ioctl_get_dev_stats args
= {0};
397 __u8 path
[BTRFS_DEVICE_PATH_NAME_MAX
+ 1];
399 strncpy((char *)path
, (char *)di_args
[i
].path
,
400 BTRFS_DEVICE_PATH_NAME_MAX
);
401 path
[BTRFS_DEVICE_PATH_NAME_MAX
] = '\0';
403 args
.devid
= di_args
[i
].devid
;
404 args
.nr_items
= BTRFS_DEV_STAT_VALUES_MAX
;
407 if (ioctl(fdmnt
, BTRFS_IOC_GET_DEV_STATS
, &args
) < 0) {
409 "ERROR: ioctl(BTRFS_IOC_GET_DEV_STATS) on %s failed: %s\n",
410 path
, strerror(errno
));
413 char *canonical_path
;
415 canonical_path
= canonicalize_path((char *)path
);
417 if (args
.nr_items
>= BTRFS_DEV_STAT_WRITE_ERRS
+ 1)
418 printf("[%s].write_io_errs %llu\n",
420 (unsigned long long) args
.values
[
421 BTRFS_DEV_STAT_WRITE_ERRS
]);
422 if (args
.nr_items
>= BTRFS_DEV_STAT_READ_ERRS
+ 1)
423 printf("[%s].read_io_errs %llu\n",
425 (unsigned long long) args
.values
[
426 BTRFS_DEV_STAT_READ_ERRS
]);
427 if (args
.nr_items
>= BTRFS_DEV_STAT_FLUSH_ERRS
+ 1)
428 printf("[%s].flush_io_errs %llu\n",
430 (unsigned long long) args
.values
[
431 BTRFS_DEV_STAT_FLUSH_ERRS
]);
432 if (args
.nr_items
>= BTRFS_DEV_STAT_CORRUPTION_ERRS
+ 1)
433 printf("[%s].corruption_errs %llu\n",
435 (unsigned long long) args
.values
[
436 BTRFS_DEV_STAT_CORRUPTION_ERRS
]);
437 if (args
.nr_items
>= BTRFS_DEV_STAT_GENERATION_ERRS
+ 1)
438 printf("[%s].generation_errs %llu\n",
440 (unsigned long long) args
.values
[
441 BTRFS_DEV_STAT_GENERATION_ERRS
]);
443 free(canonical_path
);
449 close_file_or_dir(fdmnt
, dirstream
);
454 const char * const cmd_device_usage_usage
[] = {
455 "btrfs device usage [options] <path> [<path>..]",
456 "Show detailed information about internal allocations in devices.",
457 "-b|--raw raw numbers in bytes",
458 "-h|--human-readable",
459 " human friendly numbers, base 1024 (default)",
460 "-H human friendly numbers, base 1000",
461 "--iec use 1024 as a base (KiB, MiB, GiB, TiB)",
462 "--si use 1000 as a base (kB, MB, GB, TB)",
463 "-k|--kbytes show sizes in KiB, or kB with --si",
464 "-m|--mbytes show sizes in MiB, or MB with --si",
465 "-g|--gbytes show sizes in GiB, or GB with --si",
466 "-t|--tbytes show sizes in TiB, or TB with --si",
470 static int _cmd_device_usage(int fd
, char *path
, unsigned unit_mode
)
474 struct chunk_info
*chunkinfo
= NULL
;
475 struct device_info
*devinfo
= NULL
;
479 ret
= load_chunk_and_device_info(fd
, &chunkinfo
, &chunkcount
, &devinfo
,
484 for (i
= 0; i
< devcount
; i
++) {
485 printf("%s, ID: %llu\n", devinfo
[i
].path
, devinfo
[i
].devid
);
486 print_device_sizes(fd
, &devinfo
[i
], unit_mode
);
487 print_device_chunks(fd
, &devinfo
[i
], chunkinfo
, chunkcount
,
499 int cmd_device_usage(int argc
, char **argv
)
501 unsigned unit_mode
= UNITS_DEFAULT
;
503 int i
, more_than_one
= 0;
508 static const struct option long_options
[] = {
509 { "raw", no_argument
, NULL
, 'b'},
510 { "kbytes", no_argument
, NULL
, 'k'},
511 { "mbytes", no_argument
, NULL
, 'm'},
512 { "gbytes", no_argument
, NULL
, 'g'},
513 { "tbytes", no_argument
, NULL
, 't'},
514 { "si", no_argument
, NULL
, GETOPT_VAL_SI
},
515 { "iec", no_argument
, NULL
, GETOPT_VAL_IEC
},
516 { "human-readable", no_argument
, NULL
,
517 GETOPT_VAL_HUMAN_READABLE
},
521 c
= getopt_long(argc
, argv
, "bhHkmgt", long_options
, NULL
);
526 unit_mode
= UNITS_RAW
;
529 units_set_base(&unit_mode
, UNITS_KBYTES
);
532 units_set_base(&unit_mode
, UNITS_MBYTES
);
535 units_set_base(&unit_mode
, UNITS_GBYTES
);
538 units_set_base(&unit_mode
, UNITS_TBYTES
);
540 case GETOPT_VAL_HUMAN_READABLE
:
542 unit_mode
= UNITS_HUMAN_BINARY
;
545 unit_mode
= UNITS_HUMAN_DECIMAL
;
548 units_set_mode(&unit_mode
, UNITS_DECIMAL
);
551 units_set_mode(&unit_mode
, UNITS_BINARY
);
554 usage(cmd_device_usage_usage
);
558 if (check_argc_min(argc
- optind
, 1))
559 usage(cmd_device_usage_usage
);
561 for (i
= optind
; i
< argc
; i
++) {
563 DIR *dirstream
= NULL
;
567 fd
= open_file_or_dir(argv
[i
], &dirstream
);
569 fprintf(stderr
, "ERROR: can't access '%s'\n",
575 ret
= _cmd_device_usage(fd
, argv
[i
], unit_mode
);
576 close_file_or_dir(fd
, dirstream
);
586 const struct cmd_group device_cmd_group
= {
587 device_cmd_group_usage
, NULL
, {
588 { "add", cmd_add_dev
, cmd_add_dev_usage
, NULL
, 0 },
589 { "delete", cmd_rm_dev
, cmd_rm_dev_usage
, NULL
, 0 },
590 { "scan", cmd_scan_dev
, cmd_scan_dev_usage
, NULL
, 0 },
591 { "ready", cmd_ready_dev
, cmd_ready_dev_usage
, NULL
, 0 },
592 { "stats", cmd_dev_stats
, cmd_dev_stats_usage
, NULL
, 0 },
593 { "usage", cmd_device_usage
,
594 cmd_device_usage_usage
, NULL
, 0 },
599 int cmd_device(int argc
, char **argv
)
601 return handle_command_group(&device_cmd_group
, argc
, argv
);