btrfs-progs: qgroup: fix qgroup show sort by multi items
[btrfs-progs-unstable/devel.git] / cmds-device.c
blob4337eb27203748d4c534be095eed1666f6a638c4
1 /*
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.
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <errno.h>
24 #include <sys/stat.h>
25 #include <getopt.h>
27 #include "kerncompat.h"
28 #include "ctree.h"
29 #include "ioctl.h"
30 #include "utils.h"
31 #include "volumes.h"
32 #include "cmds-fi-usage.h"
34 #include "commands.h"
35 #include "help.h"
36 #include "mkfs/common.h"
38 static const char * const device_cmd_group_usage[] = {
39 "btrfs device <command> [<args>]",
40 NULL
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",
48 NULL
51 static int cmd_device_add(int argc, char **argv)
53 char *mntpnt;
54 int i, fdmnt, ret = 0;
55 DIR *dirstream = NULL;
56 int discard = 1;
57 int force = 0;
58 int last_dev;
60 while (1) {
61 int c;
62 static const struct option long_options[] = {
63 { "nodiscard", optional_argument, NULL, 'K'},
64 { "force", no_argument, NULL, 'f'},
65 { NULL, 0, NULL, 0}
68 c = getopt_long(argc, argv, "Kf", long_options, NULL);
69 if (c < 0)
70 break;
71 switch (c) {
72 case 'K':
73 discard = 0;
74 break;
75 case 'f':
76 force = 1;
77 break;
78 default:
79 usage(cmd_device_add_usage);
83 if (check_argc_min(argc - optind, 2))
84 usage(cmd_device_add_usage);
86 last_dev = argc - 1;
87 mntpnt = argv[last_dev];
89 fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
90 if (fdmnt < 0)
91 return 1;
93 for (i = optind; i < last_dev; i++){
94 struct btrfs_ioctl_vol_args ioctl_args;
95 int devfd, res;
96 u64 dev_block_count = 0;
97 char *path;
99 res = test_dev_for_mkfs(argv[i], force);
100 if (res) {
101 ret++;
102 continue;
105 devfd = open(argv[i], O_RDWR);
106 if (devfd < 0) {
107 error("unable to open device '%s'", argv[i]);
108 ret++;
109 continue;
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));
115 close(devfd);
116 if (res) {
117 ret++;
118 goto error_out;
121 path = canonicalize_path(argv[i]);
122 if (!path) {
123 error("could not canonicalize pathname '%s': %s",
124 argv[i], strerror(errno));
125 ret++;
126 goto error_out;
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);
132 if (res < 0) {
133 error("error adding device '%s': %s",
134 path, strerror(errno));
135 ret++;
137 free(path);
140 error_out:
141 close_file_or_dir(fdmnt, dirstream);
142 return !!ret;
145 static int _cmd_device_remove(int argc, char **argv,
146 const char * const *usagestr)
148 char *mntpnt;
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))
155 usage(usagestr);
157 mntpnt = argv[argc - 1];
159 fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
160 if (fdmnt < 0)
161 return 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};
166 int is_devid = 0;
167 int res;
169 if (string_is_numerical(argv[i])) {
170 argv2.devid = arg_strtou64(argv[i]);
171 argv2.flags = BTRFS_DEVICE_SPEC_BY_ID;
172 is_devid = 1;
173 } else if (is_block_device(argv[i]) == 1 ||
174 strcmp(argv[i], "missing") == 0) {
175 strncpy_null(argv2.name, argv[i]);
176 } else {
177 error("not a block device: %s", argv[i]);
178 ret++;
179 continue;
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)) {
194 if (is_devid) {
195 error("device delete by id failed: %s",
196 strerror(errno));
197 ret++;
198 continue;
200 memset(&arg, 0, sizeof(arg));
201 strncpy_null(arg.name, argv[i]);
202 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
205 if (res) {
206 const char *msg;
208 if (res > 0)
209 msg = btrfs_err_str(res);
210 else
211 msg = strerror(errno);
212 if (is_devid) {
213 error("error removing devid %llu: %s",
214 (unsigned long long)argv2.devid, msg);
215 } else {
216 error("error removing device '%s': %s",
217 argv[i], msg);
219 ret++;
223 close_file_or_dir(fdmnt, dirstream);
224 return !!ret;
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",
230 NULL
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",
241 NULL
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)",
253 NULL
256 static int cmd_device_scan(int argc, char **argv)
258 int i;
259 int devstart;
260 int all = 0;
261 int ret = 0;
263 while (1) {
264 int c;
265 static const struct option long_options[] = {
266 { "all-devices", no_argument, NULL, 'd'},
267 { NULL, 0, NULL, 0}
270 c = getopt_long(argc, argv, "d", long_options, NULL);
271 if (c < 0)
272 break;
273 switch (c) {
274 case 'd':
275 all = 1;
276 break;
277 default:
278 usage(cmd_device_scan_usage);
281 devstart = optind;
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);
292 goto out;
295 for( i = devstart ; i < argc ; i++ ){
296 char *path;
298 if (is_block_device(argv[i]) != 1) {
299 error("not a block device: %s", argv[i]);
300 ret = 1;
301 goto out;
303 path = canonicalize_path(argv[i]);
304 if (!path) {
305 error("could not canonicalize path '%s': %s",
306 argv[i], strerror(errno));
307 ret = 1;
308 goto out;
310 printf("Scanning for Btrfs filesystems in '%s'\n", path);
311 if (btrfs_register_one_device(path) != 0) {
312 ret = 1;
313 free(path);
314 goto out;
316 free(path);
319 out:
320 return !!ret;
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",
326 NULL
329 static int cmd_device_ready(int argc, char **argv)
331 struct btrfs_ioctl_vol_args args;
332 int fd;
333 int ret;
334 char *path;
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);
342 if (fd < 0) {
343 perror("failed to open /dev/btrfs-control");
344 return 1;
347 path = canonicalize_path(argv[optind]);
348 if (!path) {
349 error("could not canonicalize pathname '%s': %s",
350 argv[optind], strerror(errno));
351 ret = 1;
352 goto out;
355 if (is_block_device(path) != 1) {
356 error("not a block device: %s", path);
357 ret = 1;
358 goto out;
361 memset(&args, 0, sizeof(args));
362 strncpy_null(args.name, path);
363 ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
364 if (ret < 0) {
365 error("unable to determine if device '%s' is ready for mount: %s",
366 path, strerror(errno));
367 ret = 1;
370 out:
371 free(path);
372 close(fd);
373 return ret;
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",
384 NULL
387 static int cmd_device_stats(int argc, char **argv)
389 char *dev_path;
390 struct btrfs_ioctl_fs_info_args fi_args;
391 struct btrfs_ioctl_dev_info_args *di_args = NULL;
392 int ret;
393 int fdmnt;
394 int i;
395 int err = 0;
396 int check = 0;
397 __u64 flags = 0;
398 DIR *dirstream = NULL;
400 while (1) {
401 int c;
402 static const struct option long_options[] = {
403 {"check", no_argument, NULL, 'c'},
404 {"reset", no_argument, NULL, 'z'},
405 {NULL, 0, NULL, 0}
408 c = getopt_long(argc, argv, "cz", long_options, NULL);
409 if (c < 0)
410 break;
412 switch (c) {
413 case 'c':
414 check = 1;
415 break;
416 case 'z':
417 flags = BTRFS_DEV_STATS_RESET;
418 break;
419 case '?':
420 default:
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);
431 if (fdmnt < 0)
432 return 1;
434 ret = get_fs_info(dev_path, &fi_args, &di_args);
435 if (ret) {
436 error("getting device info for %s failed: %s", dev_path,
437 strerror(-ret));
438 err = 1;
439 goto out;
441 if (!fi_args.num_devices) {
442 error("no devices found");
443 err = 1;
444 goto out;
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;
457 args.flags = flags;
459 if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) {
460 error("device stats ioctl failed on %s: %s",
461 path, strerror(errno));
462 err |= 1;
463 } else {
464 char *canonical_path;
465 int j;
466 static const struct {
467 const char name[32];
468 u64 num;
469 } dev_stats[] = {
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 },
473 { "corruption_errs",
474 BTRFS_DEV_STAT_CORRUPTION_ERRS },
475 { "generation_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");
486 goto out;
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)
495 continue;
496 printf("[%s].%-16s %llu\n", canonical_path,
497 dev_stats[j].name,
498 (unsigned long long)
499 args.values[dev_stats[j].num]);
500 if ((check == 1)
501 && (args.values[dev_stats[j].num] > 0))
502 err |= 64;
505 free(canonical_path);
509 out:
510 free(di_args);
511 close_file_or_dir(fdmnt, dirstream);
513 return err;
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,
520 NULL
523 static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
525 int i;
526 int ret = 0;
527 struct chunk_info *chunkinfo = NULL;
528 struct device_info *devinfo = NULL;
529 int chunkcount = 0;
530 int devcount = 0;
532 ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
533 &devcount);
534 if (ret)
535 goto out;
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,
541 unit_mode);
542 printf("\n");
545 out:
546 free(devinfo);
547 free(chunkinfo);
549 return ret;
552 static int cmd_device_usage(int argc, char **argv)
554 unsigned unit_mode;
555 int ret = 0;
556 int i;
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++) {
566 int fd;
567 DIR *dirstream = NULL;
569 if (i > 1)
570 printf("\n");
572 fd = btrfs_open_dir(argv[i], &dirstream, 1);
573 if (fd < 0) {
574 ret = 1;
575 break;
578 ret = _cmd_device_usage(fd, argv[i], unit_mode);
579 close_file_or_dir(fd, dirstream);
581 if (ret)
582 break;
585 return !!ret;
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,
595 CMD_ALIAS },
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 },
602 NULL_CMD_STRUCT
606 int cmd_device(int argc, char **argv)
608 return handle_command_group(&device_cmd_group, argc, argv);