packaging: Enable LTO and set visibility to hidden
[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': %m",
124                                 argv[i]);
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': %m", path);
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: %m");
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 #define COMMON_USAGE_REMOVE_DELETE                                      \
226         "If 'missing' is specified for <device>, the first device that is",     \
227         "described by the filesystem metadata, but not present at the mount",   \
228         "time will be removed. (only in degraded mode)"
229
230 static const char * const cmd_device_remove_usage[] = {
231         "btrfs device remove <device>|<devid> [<device>|<devid>...] <path>",
232         "Remove a device from a filesystem",
233         "",
234         COMMON_USAGE_REMOVE_DELETE,
235         NULL
236 };
237
238 static int cmd_device_remove(int argc, char **argv)
239 {
240         return _cmd_device_remove(argc, argv, cmd_device_remove_usage);
241 }
242
243 static const char * const cmd_device_delete_usage[] = {
244         "btrfs device delete <device>|<devid> [<device>|<devid>...] <path>",
245         "Remove a device from a filesystem (alias of \"btrfs device remove\")",
246         "",
247         COMMON_USAGE_REMOVE_DELETE,
248         NULL
249 };
250
251 static int cmd_device_delete(int argc, char **argv)
252 {
253         return _cmd_device_remove(argc, argv, cmd_device_delete_usage);
254 }
255
256 static const char * const cmd_device_scan_usage[] = {
257         "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
258         "Scan devices for a btrfs filesystem",
259         " -d|--all-devices (deprecated)",
260         NULL
261 };
262
263 static int cmd_device_scan(int argc, char **argv)
264 {
265         int i;
266         int devstart;
267         int all = 0;
268         int ret = 0;
269
270         while (1) {
271                 int c;
272                 static const struct option long_options[] = {
273                         { "all-devices", no_argument, NULL, 'd'},
274                         { NULL, 0, NULL, 0}
275                 };
276
277                 c = getopt_long(argc, argv, "d", long_options, NULL);
278                 if (c < 0)
279                         break;
280                 switch (c) {
281                 case 'd':
282                         all = 1;
283                         break;
284                 default:
285                         usage(cmd_device_scan_usage);
286                 }
287         }
288         devstart = optind;
289
290         if (all && check_argc_max(argc - optind, 1))
291                 usage(cmd_device_scan_usage);
292
293         if (all || argc - optind == 0) {
294                 printf("Scanning for Btrfs filesystems\n");
295                 ret = btrfs_scan_devices();
296                 error_on(ret, "error %d while scanning", ret);
297                 ret = btrfs_register_all_devices();
298                 error_on(ret, "there are %d errors while registering devices", ret);
299                 goto out;
300         }
301
302         for( i = devstart ; i < argc ; i++ ){
303                 char *path;
304
305                 if (is_block_device(argv[i]) != 1) {
306                         error("not a block device: %s", argv[i]);
307                         ret = 1;
308                         goto out;
309                 }
310                 path = canonicalize_path(argv[i]);
311                 if (!path) {
312                         error("could not canonicalize path '%s': %m", argv[i]);
313                         ret = 1;
314                         goto out;
315                 }
316                 printf("Scanning for Btrfs filesystems in '%s'\n", path);
317                 if (btrfs_register_one_device(path) != 0) {
318                         ret = 1;
319                         free(path);
320                         goto out;
321                 }
322                 free(path);
323         }
324
325 out:
326         return !!ret;
327 }
328
329 static const char * const cmd_device_ready_usage[] = {
330         "btrfs device ready <device>",
331         "Check device to see if it has all of its devices in cache for mounting",
332         NULL
333 };
334
335 static int cmd_device_ready(int argc, char **argv)
336 {
337         struct  btrfs_ioctl_vol_args args;
338         int     fd;
339         int     ret;
340         char    *path;
341
342         clean_args_no_options(argc, argv, cmd_device_ready_usage);
343
344         if (check_argc_exact(argc - optind, 1))
345                 usage(cmd_device_ready_usage);
346
347         fd = open("/dev/btrfs-control", O_RDWR);
348         if (fd < 0) {
349                 perror("failed to open /dev/btrfs-control");
350                 return 1;
351         }
352
353         path = canonicalize_path(argv[optind]);
354         if (!path) {
355                 error("could not canonicalize pathname '%s': %m",
356                         argv[optind]);
357                 ret = 1;
358                 goto out;
359         }
360
361         if (is_block_device(path) != 1) {
362                 error("not a block device: %s", path);
363                 ret = 1;
364                 goto out;
365         }
366
367         memset(&args, 0, sizeof(args));
368         strncpy_null(args.name, path);
369         ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
370         if (ret < 0) {
371                 error("unable to determine if device '%s' is ready for mount: %m",
372                         path);
373                 ret = 1;
374         }
375
376 out:
377         free(path);
378         close(fd);
379         return ret;
380 }
381
382 static const char * const cmd_device_stats_usage[] = {
383         "btrfs device stats [options] <path>|<device>",
384         "Show device IO error statistics",
385         "Show device IO error statistics for all devices of the given filesystem",
386         "identified by PATH or DEVICE. The filesystem must be mounted.",
387         "",
388         "-c|--check             return non-zero if any stat counter is not zero",
389         "-z|--reset             show current stats and reset values to zero",
390         NULL
391 };
392
393 static int cmd_device_stats(int argc, char **argv)
394 {
395         char *dev_path;
396         struct btrfs_ioctl_fs_info_args fi_args;
397         struct btrfs_ioctl_dev_info_args *di_args = NULL;
398         int ret;
399         int fdmnt;
400         int i;
401         int err = 0;
402         int check = 0;
403         __u64 flags = 0;
404         DIR *dirstream = NULL;
405
406         while (1) {
407                 int c;
408                 static const struct option long_options[] = {
409                         {"check", no_argument, NULL, 'c'},
410                         {"reset", no_argument, NULL, 'z'},
411                         {NULL, 0, NULL, 0}
412                 };
413
414                 c = getopt_long(argc, argv, "cz", long_options, NULL);
415                 if (c < 0)
416                         break;
417
418                 switch (c) {
419                 case 'c':
420                         check = 1;
421                         break;
422                 case 'z':
423                         flags = BTRFS_DEV_STATS_RESET;
424                         break;
425                 case '?':
426                 default:
427                         usage(cmd_device_stats_usage);
428                 }
429         }
430
431         if (check_argc_exact(argc - optind, 1))
432                 usage(cmd_device_stats_usage);
433
434         dev_path = argv[optind];
435
436         fdmnt = open_path_or_dev_mnt(dev_path, &dirstream, 1);
437         if (fdmnt < 0)
438                 return 1;
439
440         ret = get_fs_info(dev_path, &fi_args, &di_args);
441         if (ret) {
442                 error("getting device info for %s failed: %s", dev_path,
443                         strerror(-ret));
444                 err = 1;
445                 goto out;
446         }
447         if (!fi_args.num_devices) {
448                 error("no devices found");
449                 err = 1;
450                 goto out;
451         }
452
453         for (i = 0; i < fi_args.num_devices; i++) {
454                 struct btrfs_ioctl_get_dev_stats args = {0};
455                 char path[BTRFS_DEVICE_PATH_NAME_MAX + 1];
456
457                 strncpy(path, (char *)di_args[i].path,
458                         BTRFS_DEVICE_PATH_NAME_MAX);
459                 path[BTRFS_DEVICE_PATH_NAME_MAX] = 0;
460
461                 args.devid = di_args[i].devid;
462                 args.nr_items = BTRFS_DEV_STAT_VALUES_MAX;
463                 args.flags = flags;
464
465                 if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) {
466                         error("device stats ioctl failed on %s: %m",
467                               path);
468                         err |= 1;
469                 } else {
470                         char *canonical_path;
471                         int j;
472                         static const struct {
473                                 const char name[32];
474                                 u64 num;
475                         } dev_stats[] = {
476                                 { "write_io_errs", BTRFS_DEV_STAT_WRITE_ERRS },
477                                 { "read_io_errs", BTRFS_DEV_STAT_READ_ERRS },
478                                 { "flush_io_errs", BTRFS_DEV_STAT_FLUSH_ERRS },
479                                 { "corruption_errs",
480                                         BTRFS_DEV_STAT_CORRUPTION_ERRS },
481                                 { "generation_errs",
482                                         BTRFS_DEV_STAT_GENERATION_ERRS },
483                         };
484
485                         canonical_path = canonicalize_path(path);
486
487                         /* No path when device is missing. */
488                         if (!canonical_path) {
489                                 canonical_path = malloc(32);
490                                 if (!canonical_path) {
491                                         error("not enough memory for path buffer");
492                                         goto out;
493                                 }
494                                 snprintf(canonical_path, 32,
495                                          "devid:%llu", args.devid);
496                         }
497
498                         for (j = 0; j < ARRAY_SIZE(dev_stats); j++) {
499                                 /* We got fewer items than we know */
500                                 if (args.nr_items < dev_stats[j].num + 1)
501                                         continue;
502                                 printf("[%s].%-16s %llu\n", canonical_path,
503                                         dev_stats[j].name,
504                                         (unsigned long long)
505                                          args.values[dev_stats[j].num]);
506                                 if ((check == 1)
507                                     && (args.values[dev_stats[j].num] > 0))
508                                         err |= 64;
509                         }
510
511                         free(canonical_path);
512                 }
513         }
514
515 out:
516         free(di_args);
517         close_file_or_dir(fdmnt, dirstream);
518
519         return err;
520 }
521
522 static const char * const cmd_device_usage_usage[] = {
523         "btrfs device usage [options] <path> [<path>..]",
524         "Show detailed information about internal allocations in devices.",
525         HELPINFO_UNITS_SHORT_LONG,
526         NULL
527 };
528
529 static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
530 {
531         int i;
532         int ret = 0;
533         struct chunk_info *chunkinfo = NULL;
534         struct device_info *devinfo = NULL;
535         int chunkcount = 0;
536         int devcount = 0;
537
538         ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
539                         &devcount);
540         if (ret)
541                 goto out;
542
543         for (i = 0; i < devcount; i++) {
544                 printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid);
545                 print_device_sizes(&devinfo[i], unit_mode);
546                 print_device_chunks(&devinfo[i], chunkinfo, chunkcount,
547                                 unit_mode);
548                 printf("\n");
549         }
550
551 out:
552         free(devinfo);
553         free(chunkinfo);
554
555         return ret;
556 }
557
558 static int cmd_device_usage(int argc, char **argv)
559 {
560         unsigned unit_mode;
561         int ret = 0;
562         int i;
563
564         unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
565
566         clean_args_no_options(argc, argv, cmd_device_usage_usage);
567
568         if (check_argc_min(argc - optind, 1))
569                 usage(cmd_device_usage_usage);
570
571         for (i = optind; i < argc; i++) {
572                 int fd;
573                 DIR *dirstream = NULL;
574
575                 if (i > 1)
576                         printf("\n");
577
578                 fd = btrfs_open_dir(argv[i], &dirstream, 1);
579                 if (fd < 0) {
580                         ret = 1;
581                         break;
582                 }
583
584                 ret = _cmd_device_usage(fd, argv[i], unit_mode);
585                 close_file_or_dir(fd, dirstream);
586
587                 if (ret)
588                         break;
589         }
590
591         return !!ret;
592 }
593
594 static const char device_cmd_group_info[] =
595 "manage and query devices in the filesystem";
596
597 const struct cmd_group device_cmd_group = {
598         device_cmd_group_usage, device_cmd_group_info, {
599                 { "add", cmd_device_add, cmd_device_add_usage, NULL, 0 },
600                 { "delete", cmd_device_delete, cmd_device_delete_usage, NULL,
601                         CMD_ALIAS },
602                 { "remove", cmd_device_remove, cmd_device_remove_usage, NULL, 0 },
603                 { "scan", cmd_device_scan, cmd_device_scan_usage, NULL, 0 },
604                 { "ready", cmd_device_ready, cmd_device_ready_usage, NULL, 0 },
605                 { "stats", cmd_device_stats, cmd_device_stats_usage, NULL, 0 },
606                 { "usage", cmd_device_usage,
607                         cmd_device_usage_usage, NULL, 0 },
608                 NULL_CMD_STRUCT
609         }
610 };
611
612 int cmd_device(int argc, char **argv)
613 {
614         return handle_command_group(&device_cmd_group, argc, argv);
615 }