]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_device.c
New data rereplicate command
[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 "libbcachefs/bcachefs_ioctl.h"
16 #include "libbcachefs/super-io.h"
17 #include "cmds.h"
18 #include "libbcachefs.h"
19 #include "libbcachefs/opts.h"
20 #include "tools-util.h"
21
22 static void device_add_usage(void)
23 {
24         puts("bcachefs device add - add a device to an existing filesystem\n"
25              "Usage: bcachefs device add [OPTION]... filesystem device\n"
26              "\n"
27              "Options:\n"
28              "      --fs_size=size          Size of filesystem on device\n"
29              "      --bucket=size           Bucket size\n"
30              "      --discard               Enable discards\n"
31              "  -t, --tier=#                Higher tier (e.g. 1) indicates slower devices\n"
32              "  -f, --force                 Use device even if it appears to already be formatted\n"
33              "  -h, --help                  Display this help and exit\n"
34              "\n"
35              "Report bugs to <linux-bcache@vger.kernel.org>");
36 }
37
38 int cmd_device_add(int argc, char *argv[])
39 {
40         static const struct option longopts[] = {
41                 { "fs_size",            required_argument,      NULL, 'S' },
42                 { "bucket",             required_argument,      NULL, 'B' },
43                 { "discard",            no_argument,            NULL, 'D' },
44                 { "tier",               required_argument,      NULL, 't' },
45                 { "force",              no_argument,            NULL, 'f' },
46                 { NULL }
47         };
48         struct format_opts format_opts  = format_opts_default();
49         struct dev_opts dev_opts        = dev_opts_default();
50         bool force = false;
51         int opt;
52
53         while ((opt = getopt_long(argc, argv, "t:fh",
54                                   longopts, NULL)) != -1)
55                 switch (opt) {
56                 case 'S':
57                         if (bch2_strtoull_h(optarg, &dev_opts.size))
58                                 die("invalid filesystem size");
59
60                         dev_opts.size >>= 9;
61                         break;
62                 case 'B':
63                         dev_opts.bucket_size =
64                                 hatoi_validate(optarg, "bucket size");
65                         break;
66                 case 'D':
67                         dev_opts.discard = true;
68                         break;
69                 case 't':
70                         if (kstrtouint(optarg, 10, &dev_opts.tier) ||
71                             dev_opts.tier >= BCH_TIER_MAX)
72                                 die("invalid tier");
73                         break;
74                 case 'f':
75                         force = true;
76                         break;
77                 case 'h':
78                         device_add_usage();
79                         exit(EXIT_SUCCESS);
80                 }
81         args_shift(optind);
82
83         char *fs_path = arg_pop();
84         if (!fs_path)
85                 die("Please supply a filesystem");
86
87         char *dev_path = arg_pop();
88         if (!dev_path)
89                 die("Please supply a device");
90
91         if (argc)
92                 die("too many arguments");
93
94         struct bchfs_handle fs = bcache_fs_open(fs_path);
95
96         dev_opts.path = dev_path;
97         dev_opts.fd = open_for_format(dev_opts.path, force);
98
99         format_opts.block_size  =
100                 read_file_u64(fs.sysfs_fd, "block_size") >> 9;
101         format_opts.btree_node_size =
102                 read_file_u64(fs.sysfs_fd, "btree_node_size") >> 9;
103
104         struct bch_sb *sb = bch2_format(format_opts, &dev_opts, 1);
105         free(sb);
106         fsync(dev_opts.fd);
107         close(dev_opts.fd);
108
109         bchu_disk_add(fs, dev_opts.path);
110         return 0;
111 }
112
113 static void device_remove_usage(void)
114 {
115         puts("bcachefs device_remove - remove a device from a filesystem\n"
116              "Usage: bcachefs device remove device\n"
117              "\n"
118              "Options:\n"
119              "  -f, --force                 Force removal, even if some data\n"
120              "                              couldn't be migrated\n"
121              "      --force-metadata        Force removal, even if some metadata\n"
122              "                              couldn't be migrated\n"
123              "  -h, --help                  display this help and exit\n"
124              "Report bugs to <linux-bcache@vger.kernel.org>");
125         exit(EXIT_SUCCESS);
126 }
127
128 int cmd_device_remove(int argc, char *argv[])
129 {
130         static const struct option longopts[] = {
131                 { "force",              0, NULL, 'f' },
132                 { "force-metadata",     0, NULL, 'F' },
133                 { "help",               0, NULL, 'h' },
134                 { NULL }
135         };
136         int opt, flags = BCH_FORCE_IF_DEGRADED;
137
138         while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
139                 switch (opt) {
140                 case 'f':
141                         flags |= BCH_FORCE_IF_DATA_LOST;
142                         break;
143                 case 'F':
144                         flags |= BCH_FORCE_IF_METADATA_LOST;
145                         break;
146                 case 'h':
147                         device_remove_usage();
148                 }
149         args_shift(optind);
150
151         char *dev = arg_pop();
152         if (!dev)
153                 die("Please supply a device to remove");
154
155         if (argc)
156                 die("too many arguments");
157
158         unsigned dev_idx;
159         struct bchfs_handle fs = bchu_fs_open_by_dev(dev, &dev_idx);
160         bchu_disk_remove(fs, dev_idx, flags);
161         return 0;
162 }
163
164 static void device_online_usage(void)
165 {
166         puts("bcachefs device online - readd a device to a running filesystem\n"
167              "Usage: bcachefs device online [OPTION]... device\n"
168              "\n"
169              "Options:\n"
170              "  -h, --help                  Display this help and exit\n"
171              "\n"
172              "Report bugs to <linux-bcache@vger.kernel.org>");
173 }
174
175 int cmd_device_online(int argc, char *argv[])
176 {
177         int opt;
178
179         while ((opt = getopt(argc, argv, "h")) != -1)
180                 switch (opt) {
181                 case 'h':
182                         device_online_usage();
183                         exit(EXIT_SUCCESS);
184                 }
185         args_shift(optind);
186
187         char *dev = arg_pop();
188         if (!dev)
189                 die("Please supply a device");
190
191         if (argc)
192                 die("too many arguments");
193
194         unsigned dev_idx;
195         struct bchfs_handle fs = bchu_fs_open_by_dev(dev, &dev_idx);
196         bchu_disk_online(fs, dev);
197         return 0;
198 }
199
200 static void device_offline_usage(void)
201 {
202         puts("bcachefs device offline - take a device offline, without removing it\n"
203              "Usage: bcachefs device offline [OPTION]... device\n"
204              "\n"
205              "Options:\n"
206              "  -f, --force                 Force, if data redundancy will be degraded\n"
207              "  -h, --help                  Display this help and exit\n"
208              "\n"
209              "Report bugs to <linux-bcache@vger.kernel.org>");
210 }
211
212 int cmd_device_offline(int argc, char *argv[])
213 {
214         static const struct option longopts[] = {
215                 { "force",              0, NULL, 'f' },
216                 { NULL }
217         };
218         int opt, flags = 0;
219
220         while ((opt = getopt_long(argc, argv, "fh",
221                                   longopts, NULL)) != -1)
222                 switch (opt) {
223                 case 'f':
224                         flags |= BCH_FORCE_IF_DEGRADED;
225                         break;
226                 case 'h':
227                         device_offline_usage();
228                         exit(EXIT_SUCCESS);
229                 }
230         args_shift(optind);
231
232         char *dev = arg_pop();
233         if (!dev)
234                 die("Please supply a device");
235
236         if (argc)
237                 die("too many arguments");
238
239         unsigned dev_idx;
240         struct bchfs_handle fs = bchu_fs_open_by_dev(dev, &dev_idx);
241         bchu_disk_offline(fs, dev_idx, flags);
242         return 0;
243 }
244
245 static void device_evacuate_usage(void)
246 {
247         puts("bcachefs device evacuate - move data off of a given device\n"
248              "Usage: bcachefs device evacuate [OPTION]... device\n"
249              "\n"
250              "Options:\n"
251              "  -h, --help                  Display this help and exit\n"
252              "\n"
253              "Report bugs to <linux-bcache@vger.kernel.org>");
254 }
255
256 int cmd_device_evacuate(int argc, char *argv[])
257 {
258         int opt;
259
260         while ((opt = getopt(argc, argv, "h")) != -1)
261                 switch (opt) {
262                 case 'h':
263                         device_evacuate_usage();
264                         exit(EXIT_SUCCESS);
265                 }
266         args_shift(optind);
267
268         char *dev_path = arg_pop();
269         if (!dev_path)
270                 die("Please supply a device");
271
272         if (argc)
273                 die("too many arguments");
274
275         unsigned dev_idx;
276         struct bchfs_handle fs = bchu_fs_open_by_dev(dev_path, &dev_idx);
277
278         return bchu_data(fs, (struct bch_ioctl_data) {
279                 .op             = BCH_DATA_OP_MIGRATE,
280                 .start          = POS_MIN,
281                 .end            = POS_MAX,
282                 .migrate.dev    = dev_idx,
283         });
284 }
285
286 static void device_set_state_usage(void)
287 {
288         puts("bcachefs device set-state\n"
289              "Usage: bcachefs device set-state device new-state\n"
290              "\n"
291              "Options:\n"
292              "  -f, --force                 Force, if data redundancy will be degraded\n"
293              "  -h, --help                  display this help and exit\n"
294              "Report bugs to <linux-bcache@vger.kernel.org>");
295         exit(EXIT_SUCCESS);
296 }
297
298 int cmd_device_set_state(int argc, char *argv[])
299 {
300         static const struct option longopts[] = {
301                 { "force",                      0, NULL, 'f' },
302                 { "help",                       0, NULL, 'h' },
303                 { NULL }
304         };
305         int opt, flags = 0;
306
307         while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
308                 switch (opt) {
309                 case 'f':
310                         flags |= BCH_FORCE_IF_DEGRADED;
311                         break;
312                 case 'h':
313                         device_set_state_usage();
314                 }
315         args_shift(optind);
316
317         char *dev_path = arg_pop();
318         if (!dev_path)
319                 die("Please supply a device");
320
321         char *new_state_str = arg_pop();
322         if (!new_state_str)
323                 die("Please supply a device state");
324
325         unsigned new_state = read_string_list_or_die(new_state_str,
326                                         bch2_dev_state, "device state");
327
328         unsigned dev_idx;
329         struct bchfs_handle fs = bchu_fs_open_by_dev(dev_path, &dev_idx);
330
331         bchu_disk_set_state(fs, dev_idx, new_state, flags);
332         return 0;
333 }
334
335 static void device_resize_usage(void)
336 {
337         puts("bcachefs device resize \n"
338              "Usage: bcachefs device resize device [ size ]\n"
339              "\n"
340              "Options:\n"
341              "  -h, --help                  display this help and exit\n"
342              "Report bugs to <linux-bcache@vger.kernel.org>");
343         exit(EXIT_SUCCESS);
344 }
345
346 int cmd_device_resize(int argc, char *argv[])
347 {
348         static const struct option longopts[] = {
349                 { "help",                       0, NULL, 'h' },
350                 { NULL }
351         };
352         u64 size;
353         int opt;
354
355         while ((opt = getopt_long(argc, argv, "h", longopts, NULL)) != -1)
356                 switch (opt) {
357                 case 'h':
358                         device_resize_usage();
359                 }
360         args_shift(optind);
361
362         char *dev = arg_pop();
363         if (!dev)
364                 die("Please supply a device to resize");
365
366         int dev_fd = xopen(dev, O_RDONLY);
367
368         char *size_arg = arg_pop();
369         if (!size_arg)
370                 size = get_size(dev, dev_fd);
371         else if (bch2_strtoull_h(size_arg, &size))
372                 die("invalid size");
373
374         size >>= 9;
375
376         if (argc)
377                 die("Too many arguments");
378
379         struct stat dev_stat = xfstat(dev_fd);
380
381         char *mount = dev_to_mount(dev);
382         if (mount) {
383                 if (!S_ISBLK(dev_stat.st_mode))
384                         die("%s is mounted but isn't a block device?!", dev);
385
386                 printf("Doing online resize of %s\n", dev);
387
388                 struct bchfs_handle fs = bcache_fs_open(mount);
389
390                 unsigned idx = bchu_disk_get_idx(fs, dev_stat.st_rdev);
391
392                 struct bch_sb *sb = bchu_read_super(fs, -1);
393                 if (idx >= sb->nr_devices)
394                         die("error reading superblock: dev idx >= sb->nr_devices");
395
396                 struct bch_sb_field_members *mi = bch2_sb_get_members(sb);
397                 if (!mi)
398                         die("error reading superblock: no member info");
399
400                 /* could also just read this out of sysfs... meh */
401                 struct bch_member *m = mi->members + idx;
402
403                 u64 nbuckets = size / le16_to_cpu(m->bucket_size);
404
405                 printf("resizing %s to %llu buckets\n", dev, nbuckets);
406                 bchu_disk_resize(fs, idx, nbuckets);
407         } else {
408                 printf("Doing offline resize of %s\n", dev);
409
410                 struct bch_fs *c = bch2_fs_open(&dev, 1, bch2_opts_empty());
411                 if (IS_ERR(c))
412                         die("error opening %s: %s", dev, strerror(-PTR_ERR(c)));
413
414                 struct bch_dev *ca, *resize = NULL;
415                 unsigned i;
416
417                 for_each_online_member(ca, c, i) {
418                         if (resize)
419                                 die("confused: more than one online device?");
420                         resize = ca;
421                         percpu_ref_get(&resize->io_ref);
422                 }
423
424                 u64 nbuckets = size / le16_to_cpu(resize->mi.bucket_size);
425
426                 printf("resizing %s to %llu buckets\n", dev, nbuckets);
427                 int ret = bch2_dev_resize(c, resize, nbuckets);
428                 if (ret)
429                         fprintf(stderr, "resize error: %s\n", strerror(-ret));
430
431                 percpu_ref_put(&resize->io_ref);
432                 bch2_fs_stop(c);
433         }
434         return 0;
435 }