btrfs-progs: dev stats: update option name for checking non-zero status
[platform/upstream/btrfs-progs.git] / cmds-device.c
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.
5  *
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.
10  *
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.
15  */
16
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>
26
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"
33
34 #include "commands.h"
35
36 static const char * const device_cmd_group_usage[] = {
37         "btrfs device <command> [<args>]",
38         NULL
39 };
40
41 static const char * const cmd_device_add_usage[] = {
42         "btrfs device add [options] <device> [<device>...] <path>",
43         "Add a device to a filesystem",
44         "-K|--nodiscard    do not perform whole device TRIM",
45         "-f|--force        force overwrite existing filesystem on the disk",
46         NULL
47 };
48
49 static int cmd_device_add(int argc, char **argv)
50 {
51         char    *mntpnt;
52         int i, fdmnt, ret = 0;
53         DIR     *dirstream = NULL;
54         int discard = 1;
55         int force = 0;
56         int last_dev;
57
58         while (1) {
59                 int c;
60                 static const struct option long_options[] = {
61                         { "nodiscard", optional_argument, NULL, 'K'},
62                         { "force", no_argument, NULL, 'f'},
63                         { NULL, 0, NULL, 0}
64                 };
65
66                 c = getopt_long(argc, argv, "Kf", long_options, NULL);
67                 if (c < 0)
68                         break;
69                 switch (c) {
70                 case 'K':
71                         discard = 0;
72                         break;
73                 case 'f':
74                         force = 1;
75                         break;
76                 default:
77                         usage(cmd_device_add_usage);
78                 }
79         }
80
81         if (check_argc_min(argc - optind, 2))
82                 usage(cmd_device_add_usage);
83
84         last_dev = argc - 1;
85         mntpnt = argv[last_dev];
86
87         fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
88         if (fdmnt < 0)
89                 return 1;
90
91         for (i = optind; i < last_dev; i++){
92                 struct btrfs_ioctl_vol_args ioctl_args;
93                 int     devfd, res;
94                 u64 dev_block_count = 0;
95                 char *path;
96
97                 res = test_dev_for_mkfs(argv[i], force);
98                 if (res) {
99                         ret++;
100                         continue;
101                 }
102
103                 devfd = open(argv[i], O_RDWR);
104                 if (devfd < 0) {
105                         error("unable to open device '%s'", argv[i]);
106                         ret++;
107                         continue;
108                 }
109
110                 res = btrfs_prepare_device(devfd, argv[i], &dev_block_count, 0,
111                                 PREP_DEVICE_ZERO_END | PREP_DEVICE_VERBOSE |
112                                 (discard ? PREP_DEVICE_DISCARD : 0));
113                 close(devfd);
114                 if (res) {
115                         ret++;
116                         goto error_out;
117                 }
118
119                 path = canonicalize_path(argv[i]);
120                 if (!path) {
121                         error("could not canonicalize pathname '%s': %s",
122                                 argv[i], strerror(errno));
123                         ret++;
124                         goto error_out;
125                 }
126
127                 memset(&ioctl_args, 0, sizeof(ioctl_args));
128                 strncpy_null(ioctl_args.name, path);
129                 res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
130                 if (res < 0) {
131                         error("error adding device '%s': %s",
132                                 path, strerror(errno));
133                         ret++;
134                 }
135                 free(path);
136         }
137
138 error_out:
139         close_file_or_dir(fdmnt, dirstream);
140         return !!ret;
141 }
142
143 static int _cmd_device_remove(int argc, char **argv,
144                 const char * const *usagestr)
145 {
146         char    *mntpnt;
147         int i, fdmnt, ret = 0;
148         DIR     *dirstream = NULL;
149
150         clean_args_no_options(argc, argv, usagestr);
151
152         if (check_argc_min(argc - optind, 2))
153                 usage(usagestr);
154
155         mntpnt = argv[argc - 1];
156
157         fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
158         if (fdmnt < 0)
159                 return 1;
160
161         for(i = optind; i < argc - 1; i++) {
162                 struct  btrfs_ioctl_vol_args arg;
163                 struct btrfs_ioctl_vol_args_v2 argv2 = {0};
164                 int is_devid = 0;
165                 int     res;
166
167                 if (string_is_numerical(argv[i])) {
168                         argv2.devid = arg_strtou64(argv[i]);
169                         argv2.flags = BTRFS_DEVICE_SPEC_BY_ID;
170                         is_devid = 1;
171                 } else if (is_block_device(argv[i]) == 1 ||
172                                 strcmp(argv[i], "missing") == 0) {
173                         strncpy_null(argv2.name, argv[i]);
174                 } else {
175                         error("not a block device: %s", argv[i]);
176                         ret++;
177                         continue;
178                 }
179
180                 /*
181                  * Positive values are from BTRFS_ERROR_DEV_*,
182                  * otherwise it's a generic error, one of errnos
183                  */
184                 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV_V2, &argv2);
185
186                 /*
187                  * If BTRFS_IOC_RM_DEV_V2 is not supported we get ENOTTY and if
188                  * argv2.flags includes a flag which kernel doesn't understand then
189                  * we shall get EOPNOTSUPP
190                  */
191                 if (res < 0 && (errno == ENOTTY || errno == EOPNOTSUPP)) {
192                         if (is_devid) {
193                                 error("device delete by id failed: %s",
194                                                         strerror(errno));
195                                 ret++;
196                                 continue;
197                         }
198                         memset(&arg, 0, sizeof(arg));
199                         strncpy_null(arg.name, argv[i]);
200                         res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
201                 }
202
203                 if (res) {
204                         const char *msg;
205
206                         if (res > 0)
207                                 msg = btrfs_err_str(res);
208                         else
209                                 msg = strerror(errno);
210                         if (is_devid) {
211                                 error("error removing devid %llu: %s",
212                                         (unsigned long long)argv2.devid, msg);
213                         } else {
214                                 error("error removing device '%s': %s",
215                                         argv[i], msg);
216                         }
217                         ret++;
218                 }
219         }
220
221         close_file_or_dir(fdmnt, dirstream);
222         return !!ret;
223 }
224
225 static const char * const cmd_device_remove_usage[] = {
226         "btrfs device remove <device>|<devid> [<device>|<devid>...] <path>",
227         "Remove a device from a filesystem",
228         NULL
229 };
230
231 static int cmd_device_remove(int argc, char **argv)
232 {
233         return _cmd_device_remove(argc, argv, cmd_device_remove_usage);
234 }
235
236 static const char * const cmd_device_delete_usage[] = {
237         "btrfs device delete <device>|<devid> [<device>|<devid>...] <path>",
238         "Remove a device from a filesystem",
239         NULL
240 };
241
242 static int cmd_device_delete(int argc, char **argv)
243 {
244         return _cmd_device_remove(argc, argv, cmd_device_delete_usage);
245 }
246
247 static const char * const cmd_device_scan_usage[] = {
248         "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
249         "Scan devices for a btrfs filesystem",
250         " -d|--all-devices (deprecated)",
251         NULL
252 };
253
254 static int cmd_device_scan(int argc, char **argv)
255 {
256         int i;
257         int devstart;
258         int all = 0;
259         int ret = 0;
260
261         while (1) {
262                 int c;
263                 static const struct option long_options[] = {
264                         { "all-devices", no_argument, NULL, 'd'},
265                         { NULL, 0, NULL, 0}
266                 };
267
268                 c = getopt_long(argc, argv, "d", long_options, NULL);
269                 if (c < 0)
270                         break;
271                 switch (c) {
272                 case 'd':
273                         all = 1;
274                         break;
275                 default:
276                         usage(cmd_device_scan_usage);
277                 }
278         }
279         devstart = optind;
280
281         if (all && check_argc_max(argc - optind, 1))
282                 usage(cmd_device_scan_usage);
283
284         if (all || argc - optind == 0) {
285                 printf("Scanning for Btrfs filesystems\n");
286                 ret = btrfs_scan_devices();
287                 error_on(ret, "error %d while scanning", ret);
288                 ret = btrfs_register_all_devices();
289                 error_on(ret, "there are %d errors while registering devices", ret);
290                 goto out;
291         }
292
293         for( i = devstart ; i < argc ; i++ ){
294                 char *path;
295
296                 if (is_block_device(argv[i]) != 1) {
297                         error("not a block device: %s", argv[i]);
298                         ret = 1;
299                         goto out;
300                 }
301                 path = canonicalize_path(argv[i]);
302                 if (!path) {
303                         error("could not canonicalize path '%s': %s",
304                                 argv[i], strerror(errno));
305                         ret = 1;
306                         goto out;
307                 }
308                 printf("Scanning for Btrfs filesystems in '%s'\n", path);
309                 if (btrfs_register_one_device(path) != 0) {
310                         ret = 1;
311                         free(path);
312                         goto out;
313                 }
314                 free(path);
315         }
316
317 out:
318         return !!ret;
319 }
320
321 static const char * const cmd_device_ready_usage[] = {
322         "btrfs device ready <device>",
323         "Check device to see if it has all of its devices in cache for mounting",
324         NULL
325 };
326
327 static int cmd_device_ready(int argc, char **argv)
328 {
329         struct  btrfs_ioctl_vol_args args;
330         int     fd;
331         int     ret;
332         char    *path;
333
334         clean_args_no_options(argc, argv, cmd_device_ready_usage);
335
336         if (check_argc_exact(argc - optind, 1))
337                 usage(cmd_device_ready_usage);
338
339         fd = open("/dev/btrfs-control", O_RDWR);
340         if (fd < 0) {
341                 perror("failed to open /dev/btrfs-control");
342                 return 1;
343         }
344
345         path = canonicalize_path(argv[optind]);
346         if (!path) {
347                 error("could not canonicalize pathname '%s': %s",
348                         argv[optind], strerror(errno));
349                 ret = 1;
350                 goto out;
351         }
352
353         if (is_block_device(path) != 1) {
354                 error("not a block device: %s", path);
355                 ret = 1;
356                 goto out;
357         }
358
359         memset(&args, 0, sizeof(args));
360         strncpy_null(args.name, path);
361         ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
362         if (ret < 0) {
363                 error("unable to determine if device '%s' is ready for mount: %s",
364                         path, strerror(errno));
365                 ret = 1;
366         }
367
368 out:
369         free(path);
370         close(fd);
371         return ret;
372 }
373
374 static const char * const cmd_device_stats_usage[] = {
375         "btrfs device stats [options] <path>|<device>",
376         "Show device IO error statistics",
377         "Show device IO error statistics for all devices of the given filesystem",
378         "identified by PATH or DEVICE. The filesystem must be mounted.",
379         "",
380         "-c|--check             return non-zero if any stat counter is not zero",
381         "-z|--reset             show current stats and reset values to zero",
382         NULL
383 };
384
385 static int cmd_device_stats(int argc, char **argv)
386 {
387         char *dev_path;
388         struct btrfs_ioctl_fs_info_args fi_args;
389         struct btrfs_ioctl_dev_info_args *di_args = NULL;
390         int ret;
391         int fdmnt;
392         int i;
393         int err = 0;
394         int check = 0;
395         __u64 flags = 0;
396         DIR *dirstream = NULL;
397
398         while (1) {
399                 int c;
400                 static const struct option long_options[] = {
401                         {"reset", no_argument, NULL, 'z'},
402                         {NULL, 0, NULL, 0}
403                 };
404
405                 c = getopt_long(argc, argv, "cz", long_options, NULL);
406                 if (c < 0)
407                         break;
408
409                 switch (c) {
410                 case 'c':
411                         check = 1;
412                         break;
413                 case 'z':
414                         flags = BTRFS_DEV_STATS_RESET;
415                         break;
416                 case '?':
417                 default:
418                         usage(cmd_device_stats_usage);
419                 }
420         }
421
422         if (check_argc_exact(argc - optind, 1))
423                 usage(cmd_device_stats_usage);
424
425         dev_path = argv[optind];
426
427         fdmnt = open_path_or_dev_mnt(dev_path, &dirstream, 1);
428         if (fdmnt < 0)
429                 return 1;
430
431         ret = get_fs_info(dev_path, &fi_args, &di_args);
432         if (ret) {
433                 error("getting device info for %s failed: %s", dev_path,
434                         strerror(-ret));
435                 err = 1;
436                 goto out;
437         }
438         if (!fi_args.num_devices) {
439                 error("no devices found");
440                 err = 1;
441                 goto out;
442         }
443
444         for (i = 0; i < fi_args.num_devices; i++) {
445                 struct btrfs_ioctl_get_dev_stats args = {0};
446                 char path[BTRFS_DEVICE_PATH_NAME_MAX + 1];
447
448                 strncpy(path, (char *)di_args[i].path,
449                         BTRFS_DEVICE_PATH_NAME_MAX);
450                 path[BTRFS_DEVICE_PATH_NAME_MAX] = 0;
451
452                 args.devid = di_args[i].devid;
453                 args.nr_items = BTRFS_DEV_STAT_VALUES_MAX;
454                 args.flags = flags;
455
456                 if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) {
457                         error("device stats ioctl failed on %s: %s",
458                               path, strerror(errno));
459                         err |= 1;
460                 } else {
461                         char *canonical_path;
462                         int j;
463                         static const struct {
464                                 const char name[32];
465                                 u64 num;
466                         } dev_stats[] = {
467                                 { "write_io_errs", BTRFS_DEV_STAT_WRITE_ERRS },
468                                 { "read_io_errs", BTRFS_DEV_STAT_READ_ERRS },
469                                 { "flush_io_errs", BTRFS_DEV_STAT_FLUSH_ERRS },
470                                 { "corruption_errs",
471                                         BTRFS_DEV_STAT_CORRUPTION_ERRS },
472                                 { "generation_errs",
473                                         BTRFS_DEV_STAT_GENERATION_ERRS },
474                         };
475
476                         canonical_path = canonicalize_path(path);
477
478                         /* No path when device is missing. */
479                         if (!canonical_path) {
480                                 canonical_path = malloc(32);
481                                 if (!canonical_path) {
482                                         error("not enough memory for path buffer");
483                                         goto out;
484                                 }
485                                 snprintf(canonical_path, 32,
486                                          "devid:%llu", args.devid);
487                         }
488
489                         for (j = 0; j < ARRAY_SIZE(dev_stats); j++) {
490                                 /* We got fewer items than we know */
491                                 if (args.nr_items < dev_stats[j].num + 1)
492                                         continue;
493                                 printf("[%s].%-16s %llu\n", canonical_path,
494                                         dev_stats[j].name,
495                                         (unsigned long long)
496                                          args.values[dev_stats[j].num]);
497                                 if ((check == 1)
498                                     && (args.values[dev_stats[j].num] > 0))
499                                         err |= 64;
500                         }
501
502                         free(canonical_path);
503                 }
504         }
505
506 out:
507         free(di_args);
508         close_file_or_dir(fdmnt, dirstream);
509
510         return err;
511 }
512
513 static const char * const cmd_device_usage_usage[] = {
514         "btrfs device usage [options] <path> [<path>..]",
515         "Show detailed information about internal allocations in devices.",
516         HELPINFO_UNITS_SHORT_LONG,
517         NULL
518 };
519
520 static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
521 {
522         int i;
523         int ret = 0;
524         struct chunk_info *chunkinfo = NULL;
525         struct device_info *devinfo = NULL;
526         int chunkcount = 0;
527         int devcount = 0;
528
529         ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
530                         &devcount);
531         if (ret)
532                 goto out;
533
534         for (i = 0; i < devcount; i++) {
535                 printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid);
536                 print_device_sizes(fd, &devinfo[i], unit_mode);
537                 print_device_chunks(fd, &devinfo[i], chunkinfo, chunkcount,
538                                 unit_mode);
539                 printf("\n");
540         }
541
542 out:
543         free(devinfo);
544         free(chunkinfo);
545
546         return ret;
547 }
548
549 static int cmd_device_usage(int argc, char **argv)
550 {
551         unsigned unit_mode;
552         int ret = 0;
553         int i;
554
555         unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
556
557         clean_args_no_options(argc, argv, cmd_device_usage_usage);
558
559         if (check_argc_min(argc - optind, 1))
560                 usage(cmd_device_usage_usage);
561
562         for (i = optind; i < argc; i++) {
563                 int fd;
564                 DIR *dirstream = NULL;
565
566                 if (i > 1)
567                         printf("\n");
568
569                 fd = btrfs_open_dir(argv[i], &dirstream, 1);
570                 if (fd < 0) {
571                         ret = 1;
572                         break;
573                 }
574
575                 ret = _cmd_device_usage(fd, argv[i], unit_mode);
576                 close_file_or_dir(fd, dirstream);
577
578                 if (ret)
579                         break;
580         }
581
582         return !!ret;
583 }
584
585 static const char device_cmd_group_info[] =
586 "manage and query devices in the filesystem";
587
588 const struct cmd_group device_cmd_group = {
589         device_cmd_group_usage, device_cmd_group_info, {
590                 { "add", cmd_device_add, cmd_device_add_usage, NULL, 0 },
591                 { "delete", cmd_device_delete, cmd_device_delete_usage, NULL,
592                         CMD_ALIAS },
593                 { "remove", cmd_device_remove, cmd_device_remove_usage, NULL, 0 },
594                 { "scan", cmd_device_scan, cmd_device_scan_usage, NULL, 0 },
595                 { "ready", cmd_device_ready, cmd_device_ready_usage, NULL, 0 },
596                 { "stats", cmd_device_stats, cmd_device_stats_usage, NULL, 0 },
597                 { "usage", cmd_device_usage,
598                         cmd_device_usage_usage, NULL, 0 },
599                 NULL_CMD_STRUCT
600         }
601 };
602
603 int cmd_device(int argc, char **argv)
604 {
605         return handle_command_group(&device_cmd_group, argc, argv);
606 }