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 static const char * const cmd_device_remove_usage
[] = {
228 "btrfs device remove <device>|<devid> [<device>|<devid>...] <path>",
229 "Remove a device from a filesystem",
233 static int cmd_device_remove(int argc
, char **argv
)
235 return _cmd_device_remove(argc
, argv
, cmd_device_remove_usage
);
238 static const char * const cmd_device_delete_usage
[] = {
239 "btrfs device delete <device>|<devid> [<device>|<devid>...] <path>",
240 "Remove a device from a filesystem",
244 static int cmd_device_delete(int argc
, char **argv
)
246 return _cmd_device_remove(argc
, argv
, cmd_device_delete_usage
);
249 static const char * const cmd_device_scan_usage
[] = {
250 "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
251 "Scan devices for a btrfs filesystem",
252 " -d|--all-devices (deprecated)",
256 static int cmd_device_scan(int argc
, char **argv
)
265 static const struct option long_options
[] = {
266 { "all-devices", no_argument
, NULL
, 'd'},
270 c
= getopt_long(argc
, argv
, "d", long_options
, NULL
);
278 usage(cmd_device_scan_usage
);
283 if (all
&& check_argc_max(argc
- optind
, 1))
284 usage(cmd_device_scan_usage
);
286 if (all
|| argc
- optind
== 0) {
287 printf("Scanning for Btrfs filesystems\n");
288 ret
= btrfs_scan_devices();
289 error_on(ret
, "error %d while scanning", ret
);
290 ret
= btrfs_register_all_devices();
291 error_on(ret
, "there are %d errors while registering devices", ret
);
295 for( i
= devstart
; i
< argc
; i
++ ){
298 if (is_block_device(argv
[i
]) != 1) {
299 error("not a block device: %s", argv
[i
]);
303 path
= canonicalize_path(argv
[i
]);
305 error("could not canonicalize path '%s': %s",
306 argv
[i
], strerror(errno
));
310 printf("Scanning for Btrfs filesystems in '%s'\n", path
);
311 if (btrfs_register_one_device(path
) != 0) {
323 static const char * const cmd_device_ready_usage
[] = {
324 "btrfs device ready <device>",
325 "Check device to see if it has all of its devices in cache for mounting",
329 static int cmd_device_ready(int argc
, char **argv
)
331 struct btrfs_ioctl_vol_args args
;
336 clean_args_no_options(argc
, argv
, cmd_device_ready_usage
);
338 if (check_argc_exact(argc
- optind
, 1))
339 usage(cmd_device_ready_usage
);
341 fd
= open("/dev/btrfs-control", O_RDWR
);
343 perror("failed to open /dev/btrfs-control");
347 path
= canonicalize_path(argv
[optind
]);
349 error("could not canonicalize pathname '%s': %s",
350 argv
[optind
], strerror(errno
));
355 if (is_block_device(path
) != 1) {
356 error("not a block device: %s", path
);
361 memset(&args
, 0, sizeof(args
));
362 strncpy_null(args
.name
, path
);
363 ret
= ioctl(fd
, BTRFS_IOC_DEVICES_READY
, &args
);
365 error("unable to determine if device '%s' is ready for mount: %s",
366 path
, strerror(errno
));
376 static const char * const cmd_device_stats_usage
[] = {
377 "btrfs device stats [options] <path>|<device>",
378 "Show device IO error statistics",
379 "Show device IO error statistics for all devices of the given filesystem",
380 "identified by PATH or DEVICE. The filesystem must be mounted.",
382 "-c|--check return non-zero if any stat counter is not zero",
383 "-z|--reset show current stats and reset values to zero",
387 static int cmd_device_stats(int argc
, char **argv
)
390 struct btrfs_ioctl_fs_info_args fi_args
;
391 struct btrfs_ioctl_dev_info_args
*di_args
= NULL
;
398 DIR *dirstream
= NULL
;
402 static const struct option long_options
[] = {
403 {"check", no_argument
, NULL
, 'c'},
404 {"reset", no_argument
, NULL
, 'z'},
408 c
= getopt_long(argc
, argv
, "cz", long_options
, NULL
);
417 flags
= BTRFS_DEV_STATS_RESET
;
421 usage(cmd_device_stats_usage
);
425 if (check_argc_exact(argc
- optind
, 1))
426 usage(cmd_device_stats_usage
);
428 dev_path
= argv
[optind
];
430 fdmnt
= open_path_or_dev_mnt(dev_path
, &dirstream
, 1);
434 ret
= get_fs_info(dev_path
, &fi_args
, &di_args
);
436 error("getting device info for %s failed: %s", dev_path
,
441 if (!fi_args
.num_devices
) {
442 error("no devices found");
447 for (i
= 0; i
< fi_args
.num_devices
; i
++) {
448 struct btrfs_ioctl_get_dev_stats args
= {0};
449 char path
[BTRFS_DEVICE_PATH_NAME_MAX
+ 1];
451 strncpy(path
, (char *)di_args
[i
].path
,
452 BTRFS_DEVICE_PATH_NAME_MAX
);
453 path
[BTRFS_DEVICE_PATH_NAME_MAX
] = 0;
455 args
.devid
= di_args
[i
].devid
;
456 args
.nr_items
= BTRFS_DEV_STAT_VALUES_MAX
;
459 if (ioctl(fdmnt
, BTRFS_IOC_GET_DEV_STATS
, &args
) < 0) {
460 error("device stats ioctl failed on %s: %s",
461 path
, strerror(errno
));
464 char *canonical_path
;
466 static const struct {
470 { "write_io_errs", BTRFS_DEV_STAT_WRITE_ERRS
},
471 { "read_io_errs", BTRFS_DEV_STAT_READ_ERRS
},
472 { "flush_io_errs", BTRFS_DEV_STAT_FLUSH_ERRS
},
474 BTRFS_DEV_STAT_CORRUPTION_ERRS
},
476 BTRFS_DEV_STAT_GENERATION_ERRS
},
479 canonical_path
= canonicalize_path(path
);
481 /* No path when device is missing. */
482 if (!canonical_path
) {
483 canonical_path
= malloc(32);
484 if (!canonical_path
) {
485 error("not enough memory for path buffer");
488 snprintf(canonical_path
, 32,
489 "devid:%llu", args
.devid
);
492 for (j
= 0; j
< ARRAY_SIZE(dev_stats
); j
++) {
493 /* We got fewer items than we know */
494 if (args
.nr_items
< dev_stats
[j
].num
+ 1)
496 printf("[%s].%-16s %llu\n", canonical_path
,
499 args
.values
[dev_stats
[j
].num
]);
501 && (args
.values
[dev_stats
[j
].num
] > 0))
505 free(canonical_path
);
511 close_file_or_dir(fdmnt
, dirstream
);
516 static const char * const cmd_device_usage_usage
[] = {
517 "btrfs device usage [options] <path> [<path>..]",
518 "Show detailed information about internal allocations in devices.",
519 HELPINFO_UNITS_SHORT_LONG
,
523 static int _cmd_device_usage(int fd
, char *path
, unsigned unit_mode
)
527 struct chunk_info
*chunkinfo
= NULL
;
528 struct device_info
*devinfo
= NULL
;
532 ret
= load_chunk_and_device_info(fd
, &chunkinfo
, &chunkcount
, &devinfo
,
537 for (i
= 0; i
< devcount
; i
++) {
538 printf("%s, ID: %llu\n", devinfo
[i
].path
, devinfo
[i
].devid
);
539 print_device_sizes(&devinfo
[i
], unit_mode
);
540 print_device_chunks(&devinfo
[i
], chunkinfo
, chunkcount
,
552 static int cmd_device_usage(int argc
, char **argv
)
558 unit_mode
= get_unit_mode_from_arg(&argc
, argv
, 1);
560 clean_args_no_options(argc
, argv
, cmd_device_usage_usage
);
562 if (check_argc_min(argc
- optind
, 1))
563 usage(cmd_device_usage_usage
);
565 for (i
= optind
; i
< argc
; i
++) {
567 DIR *dirstream
= NULL
;
572 fd
= btrfs_open_dir(argv
[i
], &dirstream
, 1);
578 ret
= _cmd_device_usage(fd
, argv
[i
], unit_mode
);
579 close_file_or_dir(fd
, dirstream
);
588 static const char device_cmd_group_info
[] =
589 "manage and query devices in the filesystem";
591 const struct cmd_group device_cmd_group
= {
592 device_cmd_group_usage
, device_cmd_group_info
, {
593 { "add", cmd_device_add
, cmd_device_add_usage
, NULL
, 0 },
594 { "delete", cmd_device_delete
, cmd_device_delete_usage
, NULL
,
596 { "remove", cmd_device_remove
, cmd_device_remove_usage
, NULL
, 0 },
597 { "scan", cmd_device_scan
, cmd_device_scan_usage
, NULL
, 0 },
598 { "ready", cmd_device_ready
, cmd_device_ready_usage
, NULL
, 0 },
599 { "stats", cmd_device_stats
, cmd_device_stats_usage
, NULL
, 0 },
600 { "usage", cmd_device_usage
,
601 cmd_device_usage_usage
, NULL
, 0 },
606 int cmd_device(int argc
, char **argv
)
608 return handle_command_group(&device_cmd_group
, argc
, argv
);