btrfs-progs: Refactor block sizes users in cmds-check.c
[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 #include "help.h"
36 #include "mkfs/common.h"
37
38 static const char * const device_cmd_group_usage[] = {
39         "btrfs device <command> [<args>]",
40         NULL
41 };
42
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
49 };
50
51 static int cmd_device_add(int argc, char **argv)
52 {
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;
59
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}
66                 };
67
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);
80                 }
81         }
82
83         if (check_argc_min(argc - optind, 2))
84                 usage(cmd_device_add_usage);
85
86         last_dev = argc - 1;
87         mntpnt = argv[last_dev];
88
89         fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
90         if (fdmnt < 0)
91                 return 1;
92
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;
98
99                 res = test_dev_for_mkfs(argv[i], force);
100                 if (res) {
101                         ret++;
102                         continue;
103                 }
104
105                 devfd = open(argv[i], O_RDWR);
106                 if (devfd < 0) {
107                         error("unable to open device '%s'", argv[i]);
108                         ret++;
109                         continue;
110                 }
111
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;
119                 }
120
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;
127                 }
128
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++;
136                 }
137                 free(path);
138         }
139
140 error_out:
141         close_file_or_dir(fdmnt, dirstream);
142         return !!ret;
143 }
144
145 static int _cmd_device_remove(int argc, char **argv,
146                 const char * const *usagestr)
147 {
148         char    *mntpnt;
149         int i, fdmnt, ret = 0;
150         DIR     *dirstream = NULL;
151
152         clean_args_no_options(argc, argv, usagestr);
153
154         if (check_argc_min(argc - optind, 2))
155                 usage(usagestr);
156
157         mntpnt = argv[argc - 1];
158
159         fdmnt = btrfs_open_dir(mntpnt, &dirstream, 1);
160         if (fdmnt < 0)
161                 return 1;
162
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;
168
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;
180                 }
181
182                 /*
183                  * Positive values are from BTRFS_ERROR_DEV_*,
184                  * otherwise it's a generic error, one of errnos
185                  */
186                 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV_V2, &argv2);
187
188                 /*
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
192                  */
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;
199                         }
200                         memset(&arg, 0, sizeof(arg));
201                         strncpy_null(arg.name, argv[i]);
202                         res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
203                 }
204
205                 if (res) {
206                         const char *msg;
207
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);
218                         }
219                         ret++;
220                 }
221         }
222
223         close_file_or_dir(fdmnt, dirstream);
224         return !!ret;
225 }
226
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
231 };
232
233 static int cmd_device_remove(int argc, char **argv)
234 {
235         return _cmd_device_remove(argc, argv, cmd_device_remove_usage);
236 }
237
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
242 };
243
244 static int cmd_device_delete(int argc, char **argv)
245 {
246         return _cmd_device_remove(argc, argv, cmd_device_delete_usage);
247 }
248
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
254 };
255
256 static int cmd_device_scan(int argc, char **argv)
257 {
258         int i;
259         int devstart;
260         int all = 0;
261         int ret = 0;
262
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}
268                 };
269
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);
279                 }
280         }
281         devstart = optind;
282
283         if (all && check_argc_max(argc - optind, 1))
284                 usage(cmd_device_scan_usage);
285
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;
293         }
294
295         for( i = devstart ; i < argc ; i++ ){
296                 char *path;
297
298                 if (is_block_device(argv[i]) != 1) {
299                         error("not a block device: %s", argv[i]);
300                         ret = 1;
301                         goto out;
302                 }
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;
309                 }
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;
315                 }
316                 free(path);
317         }
318
319 out:
320         return !!ret;
321 }
322
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
327 };
328
329 static int cmd_device_ready(int argc, char **argv)
330 {
331         struct  btrfs_ioctl_vol_args args;
332         int     fd;
333         int     ret;
334         char    *path;
335
336         clean_args_no_options(argc, argv, cmd_device_ready_usage);
337
338         if (check_argc_exact(argc - optind, 1))
339                 usage(cmd_device_ready_usage);
340
341         fd = open("/dev/btrfs-control", O_RDWR);
342         if (fd < 0) {
343                 perror("failed to open /dev/btrfs-control");
344                 return 1;
345         }
346
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;
353         }
354
355         if (is_block_device(path) != 1) {
356                 error("not a block device: %s", path);
357                 ret = 1;
358                 goto out;
359         }
360
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;
368         }
369
370 out:
371         free(path);
372         close(fd);
373         return ret;
374 }
375
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.",
381         "",
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
385 };
386
387 static int cmd_device_stats(int argc, char **argv)
388 {
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;
399
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}
406                 };
407
408                 c = getopt_long(argc, argv, "cz", long_options, NULL);
409                 if (c < 0)
410                         break;
411
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);
422                 }
423         }
424
425         if (check_argc_exact(argc - optind, 1))
426                 usage(cmd_device_stats_usage);
427
428         dev_path = argv[optind];
429
430         fdmnt = open_path_or_dev_mnt(dev_path, &dirstream, 1);
431         if (fdmnt < 0)
432                 return 1;
433
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;
440         }
441         if (!fi_args.num_devices) {
442                 error("no devices found");
443                 err = 1;
444                 goto out;
445         }
446
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];
450
451                 strncpy(path, (char *)di_args[i].path,
452                         BTRFS_DEVICE_PATH_NAME_MAX);
453                 path[BTRFS_DEVICE_PATH_NAME_MAX] = 0;
454
455                 args.devid = di_args[i].devid;
456                 args.nr_items = BTRFS_DEV_STAT_VALUES_MAX;
457                 args.flags = flags;
458
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 },
477                         };
478
479                         canonical_path = canonicalize_path(path);
480
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;
487                                 }
488                                 snprintf(canonical_path, 32,
489                                          "devid:%llu", args.devid);
490                         }
491
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;
503                         }
504
505                         free(canonical_path);
506                 }
507         }
508
509 out:
510         free(di_args);
511         close_file_or_dir(fdmnt, dirstream);
512
513         return err;
514 }
515
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
521 };
522
523 static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
524 {
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;
531
532         ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
533                         &devcount);
534         if (ret)
535                 goto out;
536
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");
543         }
544
545 out:
546         free(devinfo);
547         free(chunkinfo);
548
549         return ret;
550 }
551
552 static int cmd_device_usage(int argc, char **argv)
553 {
554         unsigned unit_mode;
555         int ret = 0;
556         int i;
557
558         unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
559
560         clean_args_no_options(argc, argv, cmd_device_usage_usage);
561
562         if (check_argc_min(argc - optind, 1))
563                 usage(cmd_device_usage_usage);
564
565         for (i = optind; i < argc; i++) {
566                 int fd;
567                 DIR *dirstream = NULL;
568
569                 if (i > 1)
570                         printf("\n");
571
572                 fd = btrfs_open_dir(argv[i], &dirstream, 1);
573                 if (fd < 0) {
574                         ret = 1;
575                         break;
576                 }
577
578                 ret = _cmd_device_usage(fd, argv[i], unit_mode);
579                 close_file_or_dir(fd, dirstream);
580
581                 if (ret)
582                         break;
583         }
584
585         return !!ret;
586 }
587
588 static const char device_cmd_group_info[] =
589 "manage and query devices in the filesystem";
590
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
603         }
604 };
605
606 int cmd_device(int argc, char **argv)
607 {
608         return handle_command_group(&device_cmd_group, argc, argv);
609 }