]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_device.c
cmd_list improvements; use %m
[bcachefs-tools-debian] / cmd_device.c
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <getopt.h>
4 #include <libgen.h>
5 #include <stdbool.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/ioctl.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14
15 #include "bcachefs_ioctl.h"
16 #include "cmds.h"
17 #include "libbcachefs.h"
18 #include "opts.h"
19 #include "tools-util.h"
20
21 /* This code belongs under show_fs */
22 #if 0
23
24 struct bcache_dev {
25         unsigned        nr;
26         const char      *name;
27
28         unsigned        has_metadata;
29         unsigned        has_data;
30         const char      *state;
31         unsigned        tier;
32
33         u64             bucket_size;
34         u64             first_bucket;
35         u64             nbuckets;
36
37         /* XXX: dirty != used, it doesn't count metadata */
38         u64             bytes_dirty;
39 };
40
41 static struct bcache_dev fill_dev(const char *dev_name, unsigned nr, int dir)
42 {
43         return (struct bcache_dev) {
44                 .nr             = nr,
45                 .name           = dev_name,
46
47                 .has_metadata   = read_file_u64(dir, "has_metadata"),
48                 .has_data       = read_file_u64(dir, "has_data"),
49                 .state          = read_file_str(dir, "state"),
50                 .tier           = read_file_u64(dir, "tier"),
51
52                 .bucket_size    = read_file_u64(dir, "bucket_size_bytes"),
53                 .first_bucket   = read_file_u64(dir, "first_bucket"),
54                 .nbuckets       = read_file_u64(dir, "nbuckets"),
55                 .bytes_dirty    = read_file_u64(dir, "dirty_bytes"),
56         };
57 }
58
59 static void show_dev(struct bcache_dev *dev)
60 {
61         u64 capacity = (dev->nbuckets - dev->first_bucket) *
62                 dev->bucket_size;
63         /*
64          * XXX: show fragmentation information, cached/dirty information
65          */
66
67         printf("Device %u (/dev/%s):\n"
68                "    Has metadata:\t%u\n"
69                "    Has dirty data:\t%u\n"
70                "    State:\t\t%s\n"
71                "    Tier:\t\t%u\n"
72                "    Size:\t\t%llu\n"
73                "    Used:\t\t%llu\n"
74                "    Free:\t\t%llu\n"
75                "    Use%%:\t\t%llu\n",
76                dev->nr, dev->name,
77                dev->has_metadata,
78                dev->has_data,
79                dev->state,
80                dev->tier,
81                capacity,
82                dev->bytes_dirty,
83                capacity - dev->bytes_dirty,
84                (dev->bytes_dirty * 100) / capacity);
85 }
86
87 int cmd_device_show(int argc, char *argv[])
88 {
89         int human_readable = 0;
90         NihOption opts[] = {
91         //      { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
92
93                 { 'h',  "human-readable",               N_("print sizes in powers of 1024 (e.g., 1023M)"),
94                         NULL, NULL,     &human_readable,        NULL},
95                 NIH_OPTION_LAST
96         };
97         char **args = bch_nih_init(argc, argv, opts);
98
99         if (argc != 2)
100                 die("Please supply a single device");
101
102         struct bcache_handle fs = bcache_fs_open(argv[1]);
103         struct dirent *entry;
104
105         struct bcache_dev devices[256];
106         unsigned i, j, nr_devices = 0, nr_active_tiers = 0;
107
108         unsigned tiers[BCH_TIER_MAX]; /* number of devices in each tier */
109         memset(tiers, 0, sizeof(tiers));
110
111         while ((entry = readdir(fs.sysfs))) {
112                 unsigned nr;
113                 int pos = 0;
114
115                 sscanf(entry->d_name, "cache%u%n", &nr, &pos);
116                 if (pos != strlen(entry->d_name))
117                         continue;
118
119                 char link[PATH_MAX];
120                 if (readlinkat(dirfd(fs.sysfs), entry->d_name,
121                                link, sizeof(link)) < 0)
122                         die("readlink error: %m\n");
123
124                 char *dev_name = basename(dirname(link));
125
126                 int fd = xopenat(dirfd(fs.sysfs), entry->d_name, O_RDONLY);
127
128                 devices[nr_devices] = fill_dev(strdup(dev_name), nr, fd);
129                 tiers[devices[nr_devices].tier]++;
130                 nr_devices++;
131
132                 close(fd);
133         }
134
135         for (i = 0; i < BCH_TIER_MAX; i++)
136                 if (tiers[i])
137                         nr_active_tiers++;
138
139         /* Print out devices sorted by tier: */
140         bool first = true;
141
142         for (i = 0; i < BCH_TIER_MAX; i++) {
143                 if (!tiers[i])
144                         continue;
145
146                 if (nr_active_tiers > 1) {
147                         if (!first)
148                                 printf("\n");
149                         first = false;
150                         printf("Tier %u:\n\n", i);
151                 }
152
153                 for (j = 0; j < nr_devices; j++) {
154                         if (devices[j].tier != i)
155                                 continue;
156
157                         if (!first)
158                                 printf("\n");
159                         first = false;
160                         show_dev(&devices[j]);
161                 }
162         }
163
164         return 0;
165 }
166 #endif
167
168 static void disk_ioctl(const char *fs, const char *dev, int cmd, int flags)
169 {
170         struct bch_ioctl_disk i = { .flags = flags, };
171
172         if (!kstrtoull(dev, 10, &i.dev))
173                 i.flags |= BCH_BY_INDEX;
174         else
175                 i.dev = (u64) dev;
176
177         xioctl(bcache_fs_open(fs).ioctl_fd, cmd, &i);
178 }
179
180 static void device_add_usage(void)
181 {
182         puts("bcachefs device add - add a device to an existing filesystem\n"
183              "Usage: bcachefs device add [OPTION]... filesystem device\n"
184              "\n"
185              "Options:\n"
186              "      --fs_size=size          Size of filesystem on device\n"
187              "      --bucket=size           Bucket size\n"
188              "      --discard               Enable discards\n"
189              "  -t, --tier=#                Higher tier (e.g. 1) indicates slower devices\n"
190              "  -f, --force                 Use device even if it appears to already be formatted\n"
191              "  -h, --help                  Display this help and exit\n"
192              "\n"
193              "Report bugs to <linux-bcache@vger.kernel.org>");
194 }
195
196 int cmd_device_add(int argc, char *argv[])
197 {
198         static const struct option longopts[] = {
199                 { "fs_size",            required_argument,      NULL, 'S' },
200                 { "bucket",             required_argument,      NULL, 'B' },
201                 { "discard",            no_argument,            NULL, 'D' },
202                 { "tier",               required_argument,      NULL, 't' },
203                 { "force",              no_argument,            NULL, 'f' },
204                 { NULL }
205         };
206         struct format_opts format_opts = format_opts_default();
207         struct dev_opts dev_opts = { 0 };
208         bool force = false;
209         int opt;
210
211         while ((opt = getopt_long(argc, argv, "t:fh",
212                                   longopts, NULL)) != -1)
213                 switch (opt) {
214                 case 'S':
215                         if (bch2_strtoull_h(optarg, &dev_opts.size))
216                                 die("invalid filesystem size");
217
218                         dev_opts.size >>= 9;
219                         break;
220                 case 'B':
221                         dev_opts.bucket_size =
222                                 hatoi_validate(optarg, "bucket size");
223                         break;
224                 case 'D':
225                         dev_opts.discard = true;
226                         break;
227                 case 't':
228                         if (kstrtouint(optarg, 10, &dev_opts.tier) ||
229                             dev_opts.tier >= BCH_TIER_MAX)
230                                 die("invalid tier");
231                         break;
232                 case 'f':
233                         force = true;
234                         break;
235                 case 'h':
236                         device_add_usage();
237                         exit(EXIT_SUCCESS);
238                 }
239
240         if (argc - optind != 2)
241                 die("Please supply a filesystem and a device to add");
242
243         struct bcache_handle fs = bcache_fs_open(argv[optind]);
244
245         dev_opts.path = argv[optind + 1];
246         dev_opts.fd = open_for_format(dev_opts.path, force);
247
248         format_opts.block_size  =
249                 read_file_u64(fs.sysfs_fd, "block_size_bytes") >> 9;
250         format_opts.btree_node_size =
251                 read_file_u64(fs.sysfs_fd, "btree_node_size_bytes") >> 9;
252
253         struct bch_sb *sb = bch2_format(format_opts, &dev_opts, 1);
254         free(sb);
255         fsync(dev_opts.fd);
256         close(dev_opts.fd);
257
258         struct bch_ioctl_disk i = { .dev = (__u64) dev_opts.path, };
259
260         xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &i);
261         return 0;
262 }
263
264 static void device_remove_usage(void)
265 {
266         puts("bcachefs device_remove - remove a device from a filesystem\n"
267              "Usage: bcachefs device remove filesystem device\n"
268              "\n"
269              "Options:\n"
270              "  -f, --force                 Force removal, even if some data\n"
271              "                              couldn't be migrated\n"
272              "      --force-metadata        Force removal, even if some metadata\n"
273              "                              couldn't be migrated\n"
274              "  -h, --help                  display this help and exit\n"
275              "Report bugs to <linux-bcache@vger.kernel.org>");
276         exit(EXIT_SUCCESS);
277 }
278
279 int cmd_device_remove(int argc, char *argv[])
280 {
281         static const struct option longopts[] = {
282                 { "force",              0, NULL, 'f' },
283                 { "force-metadata",     0, NULL, 'F' },
284                 { "help",               0, NULL, 'h' },
285                 { NULL }
286         };
287         int opt, flags = 0;
288
289         while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
290                 switch (opt) {
291                 case 'f':
292                         flags |= BCH_FORCE_IF_DATA_LOST;
293                         break;
294                 case 'F':
295                         flags |= BCH_FORCE_IF_METADATA_LOST;
296                         break;
297                 case 'h':
298                         device_remove_usage();
299                 }
300
301         if (argc - optind != 2)
302                 die("Please supply a filesystem and at least one device to remove");
303
304         disk_ioctl(argv[optind], argv[optind + 1],
305                    BCH_IOCTL_DISK_REMOVE, flags);
306         return 0;
307 }
308
309 static void device_online_usage(void)
310 {
311         puts("bcachefs device online - readd a device to a running filesystem\n"
312              "Usage: bcachefs device online [OPTION]... filesystem device\n"
313              "\n"
314              "Options:\n"
315              "  -h, --help                  Display this help and exit\n"
316              "\n"
317              "Report bugs to <linux-bcache@vger.kernel.org>");
318 }
319
320 int cmd_device_online(int argc, char *argv[])
321 {
322         int opt;
323
324         while ((opt = getopt(argc, argv, "h")) != -1)
325                 switch (opt) {
326                 case 'h':
327                         device_online_usage();
328                         exit(EXIT_SUCCESS);
329                 }
330
331         if (argc - optind != 2)
332                 die("Please supply a filesystem and a device");
333
334         disk_ioctl(argv[optind], argv[optind + 1], BCH_IOCTL_DISK_ONLINE, 0);
335         return 0;
336 }
337
338 static void device_offline_usage(void)
339 {
340         puts("bcachefs device offline - take a device offline, without removing it\n"
341              "Usage: bcachefs device offline [OPTION]... filesystem device\n"
342              "\n"
343              "Options:\n"
344              "  -f, --force                 Force, if data redundancy will be degraded\n"
345              "  -h, --help                  Display this help and exit\n"
346              "\n"
347              "Report bugs to <linux-bcache@vger.kernel.org>");
348 }
349
350 int cmd_device_offline(int argc, char *argv[])
351 {
352         static const struct option longopts[] = {
353                 { "force",              0, NULL, 'f' },
354                 { NULL }
355         };
356         int opt, flags = 0;
357
358         while ((opt = getopt_long(argc, argv, "fh",
359                                   longopts, NULL)) != -1)
360                 switch (opt) {
361                 case 'f':
362                         flags |= BCH_FORCE_IF_DEGRADED;
363                         break;
364                 case 'h':
365                         device_offline_usage();
366                         exit(EXIT_SUCCESS);
367                 }
368
369         if (argc - optind != 2)
370                 die("Please supply a filesystem and a device");
371
372         disk_ioctl(argv[optind], argv[optind + 1],
373                    BCH_IOCTL_DISK_OFFLINE, flags);
374         return 0;
375 }
376
377 static void device_evacuate_usage(void)
378 {
379         puts("bcachefs device evacuate - move data off of a given device\n"
380              "Usage: bcachefs device evacuate [OPTION]... filesystem device\n"
381              "\n"
382              "Options:\n"
383              "  -h, --help                  Display this help and exit\n"
384              "\n"
385              "Report bugs to <linux-bcache@vger.kernel.org>");
386 }
387
388 int cmd_device_evacuate(int argc, char *argv[])
389 {
390         int opt;
391
392         while ((opt = getopt(argc, argv, "h")) != -1)
393                 switch (opt) {
394                 case 'h':
395                         device_evacuate_usage();
396                         exit(EXIT_SUCCESS);
397                 }
398
399         if (argc - optind != 2)
400                 die("Please supply a filesystem and a device");
401
402         disk_ioctl(argv[optind], argv[optind + 1], BCH_IOCTL_DISK_EVACUATE, 0);
403         return 0;
404 }
405
406 static void device_set_state_usage(void)
407 {
408         puts("bcachefs device set-state\n"
409              "Usage: bcachefs device set-state filesystem device new-state\n"
410              "\n"
411              "Options:\n"
412              "  -f, --force                 Force, if data redundancy will be degraded\n"
413              "  -h, --help                  display this help and exit\n"
414              "Report bugs to <linux-bcache@vger.kernel.org>");
415         exit(EXIT_SUCCESS);
416 }
417
418 int cmd_device_set_state(int argc, char *argv[])
419 {
420         static const struct option longopts[] = {
421                 { "force",                      0, NULL, 'f' },
422                 { "help",                       0, NULL, 'h' },
423                 { NULL }
424         };
425         int opt, flags = 0;
426
427         while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
428                 switch (opt) {
429                 case 'f':
430                         flags |= BCH_FORCE_IF_DEGRADED;
431                         break;
432                 case 'h':
433                         device_set_state_usage();
434                 }
435
436         if (argc - optind != 3)
437                 die("Please supply a filesystem, device and state");
438
439         struct bcache_handle fs = bcache_fs_open(argv[optind]);
440
441         struct bch_ioctl_disk_set_state i = {
442                 .flags          = flags,
443                 .new_state      = read_string_list_or_die(argv[optind + 2],
444                                                 bch2_dev_state, "device state"),
445         };
446
447         const char *dev = argv[optind + 1];
448         if (!kstrtoull(dev, 10, &i.dev))
449                 i.flags |= BCH_BY_INDEX;
450         else
451                 i.dev = (u64) dev;
452
453         xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &i);
454         return 0;
455 }