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': %m",
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': %m", path
);
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: %m");
198 memset(&arg
, 0, sizeof(arg
));
199 strncpy_null(arg
.name
, argv
[i
]);
200 res
= ioctl(fdmnt
, BTRFS_IOC_RM_DEV
, &arg
);
207 msg
= btrfs_err_str(res
);
209 msg
= strerror(errno
);
211 error("error removing devid %llu: %s",
212 (unsigned long long)argv2
.devid
, msg
);
214 error("error removing device '%s': %s",
221 close_file_or_dir(fdmnt
, dirstream
);
225 #define COMMON_USAGE_REMOVE_DELETE \
226 "If 'missing' is specified for <device>, the first device that is", \
227 "described by the filesystem metadata, but not present at the mount", \
228 "time will be removed. (only in degraded mode)"
230 static const char * const cmd_device_remove_usage
[] = {
231 "btrfs device remove <device>|<devid> [<device>|<devid>...] <path>",
232 "Remove a device from a filesystem",
234 COMMON_USAGE_REMOVE_DELETE
,
238 static int cmd_device_remove(int argc
, char **argv
)
240 return _cmd_device_remove(argc
, argv
, cmd_device_remove_usage
);
243 static const char * const cmd_device_delete_usage
[] = {
244 "btrfs device delete <device>|<devid> [<device>|<devid>...] <path>",
245 "Remove a device from a filesystem (alias of \"btrfs device remove\")",
247 COMMON_USAGE_REMOVE_DELETE
,
251 static int cmd_device_delete(int argc
, char **argv
)
253 return _cmd_device_remove(argc
, argv
, cmd_device_delete_usage
);
256 static const char * const cmd_device_scan_usage
[] = {
257 "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
258 "Scan devices for a btrfs filesystem",
259 " -d|--all-devices (deprecated)",
263 static int cmd_device_scan(int argc
, char **argv
)
272 static const struct option long_options
[] = {
273 { "all-devices", no_argument
, NULL
, 'd'},
277 c
= getopt_long(argc
, argv
, "d", long_options
, NULL
);
285 usage(cmd_device_scan_usage
);
290 if (all
&& check_argc_max(argc
- optind
, 1))
291 usage(cmd_device_scan_usage
);
293 if (all
|| argc
- optind
== 0) {
294 printf("Scanning for Btrfs filesystems\n");
295 ret
= btrfs_scan_devices();
296 error_on(ret
, "error %d while scanning", ret
);
297 ret
= btrfs_register_all_devices();
298 error_on(ret
, "there are %d errors while registering devices", ret
);
302 for( i
= devstart
; i
< argc
; i
++ ){
305 if (is_block_device(argv
[i
]) != 1) {
306 error("not a block device: %s", argv
[i
]);
310 path
= canonicalize_path(argv
[i
]);
312 error("could not canonicalize path '%s': %m", argv
[i
]);
316 printf("Scanning for Btrfs filesystems in '%s'\n", path
);
317 if (btrfs_register_one_device(path
) != 0) {
329 static const char * const cmd_device_ready_usage
[] = {
330 "btrfs device ready <device>",
331 "Check device to see if it has all of its devices in cache for mounting",
335 static int cmd_device_ready(int argc
, char **argv
)
337 struct btrfs_ioctl_vol_args args
;
342 clean_args_no_options(argc
, argv
, cmd_device_ready_usage
);
344 if (check_argc_exact(argc
- optind
, 1))
345 usage(cmd_device_ready_usage
);
347 fd
= open("/dev/btrfs-control", O_RDWR
);
349 perror("failed to open /dev/btrfs-control");
353 path
= canonicalize_path(argv
[optind
]);
355 error("could not canonicalize pathname '%s': %m",
361 if (is_block_device(path
) != 1) {
362 error("not a block device: %s", path
);
367 memset(&args
, 0, sizeof(args
));
368 strncpy_null(args
.name
, path
);
369 ret
= ioctl(fd
, BTRFS_IOC_DEVICES_READY
, &args
);
371 error("unable to determine if device '%s' is ready for mount: %m",
382 static const char * const cmd_device_stats_usage
[] = {
383 "btrfs device stats [options] <path>|<device>",
384 "Show device IO error statistics",
385 "Show device IO error statistics for all devices of the given filesystem",
386 "identified by PATH or DEVICE. The filesystem must be mounted.",
388 "-c|--check return non-zero if any stat counter is not zero",
389 "-z|--reset show current stats and reset values to zero",
393 static int cmd_device_stats(int argc
, char **argv
)
396 struct btrfs_ioctl_fs_info_args fi_args
;
397 struct btrfs_ioctl_dev_info_args
*di_args
= NULL
;
404 DIR *dirstream
= NULL
;
408 static const struct option long_options
[] = {
409 {"check", no_argument
, NULL
, 'c'},
410 {"reset", no_argument
, NULL
, 'z'},
414 c
= getopt_long(argc
, argv
, "cz", long_options
, NULL
);
423 flags
= BTRFS_DEV_STATS_RESET
;
427 usage(cmd_device_stats_usage
);
431 if (check_argc_exact(argc
- optind
, 1))
432 usage(cmd_device_stats_usage
);
434 dev_path
= argv
[optind
];
436 fdmnt
= open_path_or_dev_mnt(dev_path
, &dirstream
, 1);
440 ret
= get_fs_info(dev_path
, &fi_args
, &di_args
);
442 error("getting device info for %s failed: %s", dev_path
,
447 if (!fi_args
.num_devices
) {
448 error("no devices found");
453 for (i
= 0; i
< fi_args
.num_devices
; i
++) {
454 struct btrfs_ioctl_get_dev_stats args
= {0};
455 char path
[BTRFS_DEVICE_PATH_NAME_MAX
+ 1];
457 strncpy(path
, (char *)di_args
[i
].path
,
458 BTRFS_DEVICE_PATH_NAME_MAX
);
459 path
[BTRFS_DEVICE_PATH_NAME_MAX
] = 0;
461 args
.devid
= di_args
[i
].devid
;
462 args
.nr_items
= BTRFS_DEV_STAT_VALUES_MAX
;
465 if (ioctl(fdmnt
, BTRFS_IOC_GET_DEV_STATS
, &args
) < 0) {
466 error("device stats ioctl failed on %s: %m",
470 char *canonical_path
;
472 static const struct {
476 { "write_io_errs", BTRFS_DEV_STAT_WRITE_ERRS
},
477 { "read_io_errs", BTRFS_DEV_STAT_READ_ERRS
},
478 { "flush_io_errs", BTRFS_DEV_STAT_FLUSH_ERRS
},
480 BTRFS_DEV_STAT_CORRUPTION_ERRS
},
482 BTRFS_DEV_STAT_GENERATION_ERRS
},
485 canonical_path
= canonicalize_path(path
);
487 /* No path when device is missing. */
488 if (!canonical_path
) {
489 canonical_path
= malloc(32);
490 if (!canonical_path
) {
491 error("not enough memory for path buffer");
494 snprintf(canonical_path
, 32,
495 "devid:%llu", args
.devid
);
498 for (j
= 0; j
< ARRAY_SIZE(dev_stats
); j
++) {
499 /* We got fewer items than we know */
500 if (args
.nr_items
< dev_stats
[j
].num
+ 1)
502 printf("[%s].%-16s %llu\n", canonical_path
,
505 args
.values
[dev_stats
[j
].num
]);
507 && (args
.values
[dev_stats
[j
].num
] > 0))
511 free(canonical_path
);
517 close_file_or_dir(fdmnt
, dirstream
);
522 static const char * const cmd_device_usage_usage
[] = {
523 "btrfs device usage [options] <path> [<path>..]",
524 "Show detailed information about internal allocations in devices.",
525 HELPINFO_UNITS_SHORT_LONG
,
529 static int _cmd_device_usage(int fd
, char *path
, unsigned unit_mode
)
533 struct chunk_info
*chunkinfo
= NULL
;
534 struct device_info
*devinfo
= NULL
;
538 ret
= load_chunk_and_device_info(fd
, &chunkinfo
, &chunkcount
, &devinfo
,
543 for (i
= 0; i
< devcount
; i
++) {
544 printf("%s, ID: %llu\n", devinfo
[i
].path
, devinfo
[i
].devid
);
545 print_device_sizes(&devinfo
[i
], unit_mode
);
546 print_device_chunks(&devinfo
[i
], chunkinfo
, chunkcount
,
558 static int cmd_device_usage(int argc
, char **argv
)
564 unit_mode
= get_unit_mode_from_arg(&argc
, argv
, 1);
566 clean_args_no_options(argc
, argv
, cmd_device_usage_usage
);
568 if (check_argc_min(argc
- optind
, 1))
569 usage(cmd_device_usage_usage
);
571 for (i
= optind
; i
< argc
; i
++) {
573 DIR *dirstream
= NULL
;
578 fd
= btrfs_open_dir(argv
[i
], &dirstream
, 1);
584 ret
= _cmd_device_usage(fd
, argv
[i
], unit_mode
);
585 close_file_or_dir(fd
, dirstream
);
594 static const char device_cmd_group_info
[] =
595 "manage and query devices in the filesystem";
597 const struct cmd_group device_cmd_group
= {
598 device_cmd_group_usage
, device_cmd_group_info
, {
599 { "add", cmd_device_add
, cmd_device_add_usage
, NULL
, 0 },
600 { "delete", cmd_device_delete
, cmd_device_delete_usage
, NULL
,
602 { "remove", cmd_device_remove
, cmd_device_remove_usage
, NULL
, 0 },
603 { "scan", cmd_device_scan
, cmd_device_scan_usage
, NULL
, 0 },
604 { "ready", cmd_device_ready
, cmd_device_ready_usage
, NULL
, 0 },
605 { "stats", cmd_device_stats
, cmd_device_stats_usage
, NULL
, 0 },
606 { "usage", cmd_device_usage
,
607 cmd_device_usage_usage
, NULL
, 0 },
612 int cmd_device(int argc
, char **argv
)
614 return handle_command_group(&device_cmd_group
, argc
, argv
);