btrfs-progs: remove unused argument from print_device_chunks
[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                         {"reset", no_argument, NULL, 'z'},
404                         {NULL, 0, NULL, 0}
405                 };
406
407                 c = getopt_long(argc, argv, "cz", long_options, NULL);
408                 if (c < 0)
409                         break;
410
411                 switch (c) {
412                 case 'c':
413                         check = 1;
414                         break;
415                 case 'z':
416                         flags = BTRFS_DEV_STATS_RESET;
417                         break;
418                 case '?':
419                 default:
420                         usage(cmd_device_stats_usage);
421                 }
422         }
423
424         if (check_argc_exact(argc - optind, 1))
425                 usage(cmd_device_stats_usage);
426
427         dev_path = argv[optind];
428
429         fdmnt = open_path_or_dev_mnt(dev_path, &dirstream, 1);
430         if (fdmnt < 0)
431                 return 1;
432
433         ret = get_fs_info(dev_path, &fi_args, &di_args);
434         if (ret) {
435                 error("getting device info for %s failed: %s", dev_path,
436                         strerror(-ret));
437                 err = 1;
438                 goto out;
439         }
440         if (!fi_args.num_devices) {
441                 error("no devices found");
442                 err = 1;
443                 goto out;
444         }
445
446         for (i = 0; i < fi_args.num_devices; i++) {
447                 struct btrfs_ioctl_get_dev_stats args = {0};
448                 char path[BTRFS_DEVICE_PATH_NAME_MAX + 1];
449
450                 strncpy(path, (char *)di_args[i].path,
451                         BTRFS_DEVICE_PATH_NAME_MAX);
452                 path[BTRFS_DEVICE_PATH_NAME_MAX] = 0;
453
454                 args.devid = di_args[i].devid;
455                 args.nr_items = BTRFS_DEV_STAT_VALUES_MAX;
456                 args.flags = flags;
457
458                 if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) {
459                         error("device stats ioctl failed on %s: %s",
460                               path, strerror(errno));
461                         err |= 1;
462                 } else {
463                         char *canonical_path;
464                         int j;
465                         static const struct {
466                                 const char name[32];
467                                 u64 num;
468                         } dev_stats[] = {
469                                 { "write_io_errs", BTRFS_DEV_STAT_WRITE_ERRS },
470                                 { "read_io_errs", BTRFS_DEV_STAT_READ_ERRS },
471                                 { "flush_io_errs", BTRFS_DEV_STAT_FLUSH_ERRS },
472                                 { "corruption_errs",
473                                         BTRFS_DEV_STAT_CORRUPTION_ERRS },
474                                 { "generation_errs",
475                                         BTRFS_DEV_STAT_GENERATION_ERRS },
476                         };
477
478                         canonical_path = canonicalize_path(path);
479
480                         /* No path when device is missing. */
481                         if (!canonical_path) {
482                                 canonical_path = malloc(32);
483                                 if (!canonical_path) {
484                                         error("not enough memory for path buffer");
485                                         goto out;
486                                 }
487                                 snprintf(canonical_path, 32,
488                                          "devid:%llu", args.devid);
489                         }
490
491                         for (j = 0; j < ARRAY_SIZE(dev_stats); j++) {
492                                 /* We got fewer items than we know */
493                                 if (args.nr_items < dev_stats[j].num + 1)
494                                         continue;
495                                 printf("[%s].%-16s %llu\n", canonical_path,
496                                         dev_stats[j].name,
497                                         (unsigned long long)
498                                          args.values[dev_stats[j].num]);
499                                 if ((check == 1)
500                                     && (args.values[dev_stats[j].num] > 0))
501                                         err |= 64;
502                         }
503
504                         free(canonical_path);
505                 }
506         }
507
508 out:
509         free(di_args);
510         close_file_or_dir(fdmnt, dirstream);
511
512         return err;
513 }
514
515 static const char * const cmd_device_usage_usage[] = {
516         "btrfs device usage [options] <path> [<path>..]",
517         "Show detailed information about internal allocations in devices.",
518         HELPINFO_UNITS_SHORT_LONG,
519         NULL
520 };
521
522 static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
523 {
524         int i;
525         int ret = 0;
526         struct chunk_info *chunkinfo = NULL;
527         struct device_info *devinfo = NULL;
528         int chunkcount = 0;
529         int devcount = 0;
530
531         ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
532                         &devcount);
533         if (ret)
534                 goto out;
535
536         for (i = 0; i < devcount; i++) {
537                 printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid);
538                 print_device_sizes(&devinfo[i], unit_mode);
539                 print_device_chunks(&devinfo[i], chunkinfo, chunkcount,
540                                 unit_mode);
541                 printf("\n");
542         }
543
544 out:
545         free(devinfo);
546         free(chunkinfo);
547
548         return ret;
549 }
550
551 static int cmd_device_usage(int argc, char **argv)
552 {
553         unsigned unit_mode;
554         int ret = 0;
555         int i;
556
557         unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
558
559         clean_args_no_options(argc, argv, cmd_device_usage_usage);
560
561         if (check_argc_min(argc - optind, 1))
562                 usage(cmd_device_usage_usage);
563
564         for (i = optind; i < argc; i++) {
565                 int fd;
566                 DIR *dirstream = NULL;
567
568                 if (i > 1)
569                         printf("\n");
570
571                 fd = btrfs_open_dir(argv[i], &dirstream, 1);
572                 if (fd < 0) {
573                         ret = 1;
574                         break;
575                 }
576
577                 ret = _cmd_device_usage(fd, argv[i], unit_mode);
578                 close_file_or_dir(fd, dirstream);
579
580                 if (ret)
581                         break;
582         }
583
584         return !!ret;
585 }
586
587 static const char device_cmd_group_info[] =
588 "manage and query devices in the filesystem";
589
590 const struct cmd_group device_cmd_group = {
591         device_cmd_group_usage, device_cmd_group_info, {
592                 { "add", cmd_device_add, cmd_device_add_usage, NULL, 0 },
593                 { "delete", cmd_device_delete, cmd_device_delete_usage, NULL,
594                         CMD_ALIAS },
595                 { "remove", cmd_device_remove, cmd_device_remove_usage, NULL, 0 },
596                 { "scan", cmd_device_scan, cmd_device_scan_usage, NULL, 0 },
597                 { "ready", cmd_device_ready, cmd_device_ready_usage, NULL, 0 },
598                 { "stats", cmd_device_stats, cmd_device_stats_usage, NULL, 0 },
599                 { "usage", cmd_device_usage,
600                         cmd_device_usage_usage, NULL, 0 },
601                 NULL_CMD_STRUCT
602         }
603 };
604
605 int cmd_device(int argc, char **argv)
606 {
607         return handle_command_group(&device_cmd_group, argc, argv);
608 }