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