]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Resizing
authorKent Overstreet <kent.overstreet@gmail.com>
Thu, 28 Dec 2017 06:01:16 +0000 (01:01 -0500)
committerKent Overstreet <kent.overstreet@gmail.com>
Thu, 28 Dec 2017 07:55:08 +0000 (02:55 -0500)
bcachefs.c
cmd_assemble.c
cmd_device.c
cmd_fs.c
cmd_run.c
cmds.h
libbcachefs.c
libbcachefs.h
tools-util.c
tools-util.h

index 795334118e645ab9faf7b4fbf25541e775d4ef25..8408c29735e66b30ef8f92c1280207efaad67bbe 100644 (file)
@@ -51,6 +51,7 @@ static void usage(void)
             "  device offline       Take a device offline, without removing it\n"
             "  device evacuate      Migrate data off of a specific device\n"
             "  device set-state     Mark a device as failed\n"
+            "  device resize        Resize filesystem on a device\n"
             "\n"
             "Encryption:\n"
             "  unlock               Unlock an encrypted filesystem prior to running/mounting\n"
@@ -112,6 +113,8 @@ static int device_cmds(int argc, char *argv[])
                return cmd_device_offline(argc, argv);
        if (!strcmp(cmd, "set-state"))
                return cmd_device_set_state(argc, argv);
+       if (!strcmp(cmd, "resize"))
+               return cmd_device_resize(argc, argv);
 
        usage();
        return 0;
index 5fbabdd95998c4101d5390eebd6af920394389ca..b2a832e6cd61a30f6d05948123a67b09ed3858a0 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "libbcachefs/bcachefs_ioctl.h"
 #include "cmds.h"
+#include "libbcachefs.h"
 
 int cmd_assemble(int argc, char *argv[])
 {
index f2d751c593c9e4fb053da3e00069d11558be3df6..f8e0cfbfb75494bb18254034e9dabbb323d97019 100644 (file)
@@ -13,6 +13,7 @@
 #include <unistd.h>
 
 #include "libbcachefs/bcachefs_ioctl.h"
+#include "libbcachefs/super-io.h"
 #include "cmds.h"
 #include "libbcachefs.h"
 #include "libbcachefs/opts.h"
@@ -99,7 +100,7 @@ int cmd_device_show(int argc, char *argv[])
        if (argc != 2)
                die("Please supply a single device");
 
-       struct bcache_handle fs = bcache_fs_open(argv[1]);
+       struct bchfs_handle fs = bcache_fs_open(argv[1]);
        struct dirent *entry;
 
        struct bcache_dev devices[256];
@@ -240,7 +241,7 @@ int cmd_device_add(int argc, char *argv[])
        if (argc - optind != 2)
                die("Please supply a filesystem and a device to add");
 
-       struct bcache_handle fs = bcache_fs_open(argv[optind]);
+       struct bchfs_handle fs = bcache_fs_open(argv[optind]);
 
        dev_opts.path = argv[optind + 1];
        dev_opts.fd = open_for_format(dev_opts.path, force);
@@ -255,9 +256,7 @@ int cmd_device_add(int argc, char *argv[])
        fsync(dev_opts.fd);
        close(dev_opts.fd);
 
-       struct bch_ioctl_disk i = { .dev = (__u64) dev_opts.path, };
-
-       xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &i);
+       bchu_disk_add(fs, dev_opts.path);
        return 0;
 }
 
@@ -436,20 +435,113 @@ int cmd_device_set_state(int argc, char *argv[])
        if (argc - optind != 3)
                die("Please supply a filesystem, device and state");
 
-       struct bcache_handle fs = bcache_fs_open(argv[optind]);
+       struct bchfs_handle fs = bcache_fs_open(argv[optind]);
+
+       bchu_disk_set_state(fs, argv[optind + 1],
+                           read_string_list_or_die(argv[optind + 2],
+                                       bch2_dev_state, "device state"),
+                           flags);
+       return 0;
+}
+
+static void device_resize_usage(void)
+{
+       puts("bcachefs device resize \n"
+            "Usage: bcachefs device resize device [ size ]\n"
+            "\n"
+            "Options:\n"
+            "  -h, --help                  display this help and exit\n"
+            "Report bugs to <linux-bcache@vger.kernel.org>");
+       exit(EXIT_SUCCESS);
+}
 
-       struct bch_ioctl_disk_set_state i = {
-               .flags          = flags,
-               .new_state      = read_string_list_or_die(argv[optind + 2],
-                                               bch2_dev_state, "device state"),
+int cmd_device_resize(int argc, char *argv[])
+{
+       static const struct option longopts[] = {
+               { "help",                       0, NULL, 'h' },
+               { NULL }
        };
+       u64 size;
+       int opt;
 
-       const char *dev = argv[optind + 1];
-       if (!kstrtoull(dev, 10, &i.dev))
-               i.flags |= BCH_BY_INDEX;
-       else
-               i.dev = (u64) dev;
+       while ((opt = getopt_long(argc, argv, "h", longopts, NULL)) != -1)
+               switch (opt) {
+               case 'h':
+                       device_resize_usage();
+               }
+
+       if (argc < optind + 1)
+               die("Please supply a device to resize");
+
+       char *dev = argv[optind];
+       int dev_fd = xopen(dev, O_RDONLY);
+
+       if (argc == optind + 1)
+               size = get_size(dev, dev_fd);
+       else if (bch2_strtoull_h(argv[optind + 1], &size))
+               die("invalid size");
+
+       size >>= 9;
+
+       if (argc > optind + 2)
+               die("Too many arguments");
+
+       struct stat dev_stat = xfstat(dev_fd);
+
+       char *mount = dev_to_mount(dev);
+       if (mount) {
+               if (!S_ISBLK(dev_stat.st_mode))
+                       die("%s is mounted but isn't a block device?!", dev);
+
+               printf("Doing online resize of %s\n", dev);
+
+               struct bchfs_handle fs = bcache_fs_open(mount);
+
+               unsigned idx = bchu_disk_get_idx(fs, dev_stat.st_rdev);
+
+               struct bch_sb *sb = bchu_read_super(fs, -1);
+               if (idx >= sb->nr_devices)
+                       die("error reading superblock: dev idx >= sb->nr_devices");
 
-       xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &i);
+               struct bch_sb_field_members *mi = bch2_sb_get_members(sb);
+               if (!mi)
+                       die("error reading superblock: no member info");
+
+               /* could also just read this out of sysfs... meh */
+               struct bch_member *m = mi->members + idx;
+
+               u64 nbuckets = size / le16_to_cpu(m->bucket_size);
+
+               printf("resizing %s to %llu buckets\n", dev, nbuckets);
+               bchu_disk_resize(fs, idx, nbuckets);
+       } else {
+               printf("Doing offline resize of %s\n", dev);
+
+               struct bch_fs *c = NULL;
+               struct bch_opts opts = bch2_opts_empty();
+               const char *err = bch2_fs_open(&dev, 1, opts, &c);
+               if (err)
+                       die("error opening %s: %s", argv[optind], err);
+
+               struct bch_dev *ca, *resize = NULL;
+               unsigned i;
+
+               for_each_online_member(ca, c, i) {
+                       if (resize)
+                               die("confused: more than one online device?");
+                       resize = ca;
+                       percpu_ref_get(&resize->io_ref);
+               }
+
+               u64 nbuckets = size / le16_to_cpu(resize->mi.bucket_size);
+
+               printf("resizing %s to %llu buckets\n", dev, nbuckets);
+               int ret = bch2_dev_resize(c, resize, nbuckets);
+               if (ret)
+                       fprintf(stderr, "resize error: %s\n", strerror(-ret));
+
+               percpu_ref_put(&resize->io_ref);
+               bch2_fs_stop(c);
+       }
        return 0;
 }
index 65ee539e703820e88882aa74595f3bd04af3f774..3f64161f70a530a6e4469dabdadd01becd48fd24 100644 (file)
--- a/cmd_fs.c
+++ b/cmd_fs.c
@@ -8,6 +8,7 @@
 #include "libbcachefs/opts.h"
 
 #include "cmds.h"
+#include "libbcachefs.h"
 
 static inline int printf_pad(unsigned pad, const char * fmt, ...)
 {
@@ -26,21 +27,11 @@ static inline int printf_pad(unsigned pad, const char * fmt, ...)
 
 static void print_fs_usage(const char *path, enum units units)
 {
-       unsigned i, j, nr_devices = 4;
-       struct bcache_handle fs = bcache_fs_open(path);
-       struct bch_ioctl_usage *u = NULL;
+       unsigned i, j;
        char uuid[40];
 
-       while (1) {
-               u = xrealloc(u, sizeof(*u) + sizeof(u->devs[0]) * nr_devices);
-               u->nr_devices = nr_devices;
-
-               if (!ioctl(fs.ioctl_fd, BCH_IOCTL_USAGE, u))
-                       break;
-               if (errno != ENOSPC)
-                       die("BCH_IOCTL_USAGE error: %m");
-               nr_devices *= 2;
-       }
+       struct bchfs_handle fs = bcache_fs_open(path);
+       struct bch_ioctl_usage *u = bchu_usage(fs);
 
        uuid_unparse(fs.uuid.b, uuid);
        printf("Filesystem %s:\n", uuid);
index bbb37e5dc10d67ba53d83f5055943ec896933b38..673d519ab8ebfe5d663d52d9e6e22981dce83d75 100644 (file)
--- a/cmd_run.c
+++ b/cmd_run.c
@@ -13,6 +13,7 @@
 
 #include "libbcachefs/bcachefs_ioctl.h"
 #include "cmds.h"
+#include "libbcachefs.h"
 
 int cmd_run(int argc, char *argv[])
 {
@@ -24,7 +25,7 @@ int cmd_stop(int argc, char *argv[])
        if (argc != 2)
                die("Please supply a filesystem");
 
-       struct bcache_handle fs = bcache_fs_open(argv[1]);
+       struct bchfs_handle fs = bcache_fs_open(argv[1]);
        xioctl(fs.ioctl_fd, BCH_IOCTL_STOP);
        return 0;
 }
diff --git a/cmds.h b/cmds.h
index 1c07e0729ca13c9afb66f06831580310ee3ee9a3..e28a5045de44758f71744cf86cdacca600c997dc 100644 (file)
--- a/cmds.h
+++ b/cmds.h
@@ -25,6 +25,7 @@ int cmd_device_online(int argc, char *argv[]);
 int cmd_device_offline(int argc, char *argv[]);
 int cmd_device_evacuate(int argc, char *argv[]);
 int cmd_device_set_state(int argc, char *argv[]);
+int cmd_device_resize(int argc, char *argv[]);
 
 int cmd_unlock(int argc, char *argv[]);
 int cmd_set_passphrase(int argc, char *argv[]);
index 351eb31e6009692febd51ad6d51b483ecbdd6b87..afbc8d7afa596796c225c179bfd695fa4e874146 100644 (file)
@@ -455,3 +455,57 @@ void bch2_super_print(struct bch_sb *sb, int units)
                       BCH_MEMBER_DISCARD(m));
        }
 }
+
+/* ioctl interface: */
+
+/* Global control device: */
+int bcachectl_open(void)
+{
+       return xopen("/dev/bcachefs-ctl", O_RDWR);
+}
+
+/* Filesystem handles (ioctl, sysfs dir): */
+
+#define SYSFS_BASE "/sys/fs/bcachefs/"
+
+void bcache_fs_close(struct bchfs_handle fs)
+{
+       close(fs.ioctl_fd);
+       close(fs.sysfs_fd);
+}
+
+struct bchfs_handle bcache_fs_open(const char *path)
+{
+       struct bchfs_handle ret;
+
+       if (!uuid_parse(path, ret.uuid.b)) {
+               /* It's a UUID, look it up in sysfs: */
+               char *sysfs = mprintf("%s%s", SYSFS_BASE, path);
+               ret.sysfs_fd = xopen(sysfs, O_RDONLY);
+
+               char *minor = read_file_str(ret.sysfs_fd, "minor");
+               char *ctl = mprintf("/dev/bcachefs%s-ctl", minor);
+               ret.ioctl_fd = xopen(ctl, O_RDWR);
+
+               free(sysfs);
+               free(minor);
+               free(ctl);
+       } else {
+               /* It's a path: */
+               ret.ioctl_fd = xopen(path, O_RDONLY);
+
+               struct bch_ioctl_query_uuid uuid;
+               xioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid);
+
+               ret.uuid = uuid.uuid;
+
+               char uuid_str[40];
+               uuid_unparse(uuid.uuid.b, uuid_str);
+
+               char *sysfs = mprintf("%s%s", SYSFS_BASE, uuid_str);
+               ret.sysfs_fd = xopen(sysfs, O_RDONLY);
+               free(sysfs);
+       }
+
+       return ret;
+}
index 836cb7a9c9244d24213a15be70b38f7bb5bfcd6e..97f4b2d8346088b4eaa19da88f82f56497db89df 100644 (file)
@@ -5,6 +5,7 @@
 #include <stdbool.h>
 
 #include "libbcachefs/bcachefs_format.h"
+#include "libbcachefs/bcachefs_ioctl.h"
 #include "tools-util.h"
 #include "libbcachefs/vstructs.h"
 
@@ -76,4 +77,103 @@ struct bch_sb *__bch2_super_read(int, u64);
 
 void bch2_super_print(struct bch_sb *, int);
 
+/* ioctl interface: */
+
+int bcachectl_open(void);
+
+struct bchfs_handle {
+       uuid_le uuid;
+       int     ioctl_fd;
+       int     sysfs_fd;
+};
+
+void bcache_fs_close(struct bchfs_handle);
+struct bchfs_handle bcache_fs_open(const char *);
+
+static inline void bchu_disk_add(struct bchfs_handle fs, char *dev)
+{
+       struct bch_ioctl_disk i = { .dev = (__u64) dev, };
+
+       xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &i);
+}
+
+static inline void bchu_disk_set_state(struct bchfs_handle fs, const char *dev,
+                                      unsigned new_state, unsigned flags)
+{
+       struct bch_ioctl_disk_set_state i = {
+               .flags          = flags,
+               .new_state      = new_state,
+       };
+
+       if (!kstrtoull(dev, 10, &i.dev))
+               i.flags |= BCH_BY_INDEX;
+       else
+               i.dev = (u64) dev;
+
+       xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &i);
+}
+
+static inline struct bch_ioctl_usage *bchu_usage(struct bchfs_handle fs)
+{
+       struct bch_ioctl_usage *u = NULL;
+       unsigned nr_devices = 4;
+
+       while (1) {
+               u = xrealloc(u, sizeof(*u) + sizeof(u->devs[0]) * nr_devices);
+               u->nr_devices = nr_devices;
+
+               if (!ioctl(fs.ioctl_fd, BCH_IOCTL_USAGE, u))
+                       return u;
+
+               if (errno != ENOSPC)
+                       die("BCH_IOCTL_USAGE error: %m");
+               nr_devices *= 2;
+       }
+}
+
+static inline struct bch_sb *bchu_read_super(struct bchfs_handle fs, unsigned idx)
+{
+       size_t size = 4096;
+       struct bch_sb *sb = NULL;
+
+       while (1) {
+               sb = xrealloc(sb, size);
+               struct bch_ioctl_read_super i = {
+                       .size   = size,
+                       .sb     = (u64) sb,
+               };
+
+               if (idx != -1) {
+                       i.flags |= BCH_READ_DEV|BCH_BY_INDEX;
+                       i.dev = idx;
+               }
+
+               if (!ioctl(fs.ioctl_fd, BCH_IOCTL_READ_SUPER, &i))
+                       return sb;
+               if (errno != ERANGE)
+                       die("BCH_IOCTL_READ_SUPER error: %m");
+               size *= 2;
+       }
+}
+
+static inline unsigned bchu_disk_get_idx(struct bchfs_handle fs, dev_t dev)
+{
+       struct bch_ioctl_disk_get_idx i = { .dev = dev };
+
+       return xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_GET_IDX, &i);
+}
+
+static inline void bchu_disk_resize(struct bchfs_handle fs,
+                                   unsigned idx,
+                                   u64 nbuckets)
+{
+       struct bch_ioctl_disk_resize i = {
+               .flags  = BCH_BY_INDEX,
+               .dev    = idx,
+               .nbuckets = nbuckets,
+       };
+
+       xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_RESIZE, &i);
+}
+
 #endif /* _LIBBCACHE_H */
index 70f5558b2dfa1e5342eaa16d06fa9f436cbba8d4..d545049552ced523a80c20e8d86262a1b48f0320 100644 (file)
@@ -262,58 +262,6 @@ int open_for_format(const char *dev, bool force)
        return fd;
 }
 
-/* Global control device: */
-int bcachectl_open(void)
-{
-       return xopen("/dev/bcachefs-ctl", O_RDWR);
-}
-
-/* Filesystem handles (ioctl, sysfs dir): */
-
-#define SYSFS_BASE "/sys/fs/bcachefs/"
-
-void bcache_fs_close(struct bcache_handle fs)
-{
-       close(fs.ioctl_fd);
-       close(fs.sysfs_fd);
-}
-
-struct bcache_handle bcache_fs_open(const char *path)
-{
-       struct bcache_handle ret;
-
-       if (!uuid_parse(path, ret.uuid.b)) {
-               /* It's a UUID, look it up in sysfs: */
-               char *sysfs = mprintf("%s%s", SYSFS_BASE, path);
-               ret.sysfs_fd = xopen(sysfs, O_RDONLY);
-
-               char *minor = read_file_str(ret.sysfs_fd, "minor");
-               char *ctl = mprintf("/dev/bcachefs%s-ctl", minor);
-               ret.ioctl_fd = xopen(ctl, O_RDWR);
-
-               free(sysfs);
-               free(minor);
-               free(ctl);
-       } else {
-               /* It's a path: */
-               ret.ioctl_fd = xopen(path, O_RDONLY);
-
-               struct bch_ioctl_query_uuid uuid;
-               xioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid);
-
-               ret.uuid = uuid.uuid;
-
-               char uuid_str[40];
-               uuid_unparse(uuid.uuid.b, uuid_str);
-
-               char *sysfs = mprintf("%s%s", SYSFS_BASE, uuid_str);
-               ret.sysfs_fd = xopen(sysfs, O_RDONLY);
-               free(sysfs);
-       }
-
-       return ret;
-}
-
 bool ask_yn(void)
 {
        const char *short_yes = "yY";
@@ -586,9 +534,9 @@ u32 crc32c(u32 crc, const void *buf, size_t size)
 
 #endif /* HAVE_WORKING_IFUNC */
 
-char *dev_to_path(dev_t dev)
+char *dev_to_name(dev_t dev)
 {
-       char *line = NULL, *name = NULL, *path = NULL;
+       char *line = NULL, *name = NULL;
        size_t n = 0;
 
        FILE *f = fopen("/proc/partitions", "r");
@@ -602,17 +550,58 @@ char *dev_to_path(dev_t dev)
                name = realloc(name, n + 1);
 
                if (sscanf(line, " %u %u %llu %s", &ma, &mi, &sectors, name) == 4 &&
-                   ma == major(dev) && mi == minor(dev)) {
-                       path = mprintf("/dev/%s", name);
-                       break;
-               }
-
+                   ma == major(dev) && mi == minor(dev))
+                       goto found;
        }
 
+       free(name);
+       name = NULL;
+found:
        fclose(f);
        free(line);
+       return name;
+}
+
+char *dev_to_path(dev_t dev)
+{
+       char *name = dev_to_name(dev);
+       if (!name)
+               return NULL;
+
+       char *path = mprintf("/dev/%s", name);
+
        free(name);
        return path;
 }
 
+char *dev_to_mount(char *dev)
+{
+       char *line = NULL, *ret = NULL;
+       size_t n = 0;
+
+       FILE *f = fopen("/proc/mounts", "r");
+       if (!f)
+               die("error opening /proc/mounts: %m");
+
+       while (getline(&line, &n, f) != -1) {
+               char *d, *p = line;
+               char *devs = strsep(&p, " ");
+               char *mount = strsep(&p, " ");
+
+               if (!devs || !mount)
+                       continue;
+
+               p = devs;
+               while ((d = strsep(&p, ":")))
+                       if (!strcmp(d, dev)) {
+                               ret = strdup(mount);
+                               goto found;
+                       }
+       }
+found:
+       fclose(f);
+       free(line);
+       return ret;
+}
+
 #endif
index 649ea9bb0075f283e200d88f360aec376ecc6b8c..dcca376b8e4a80925514eda482d6e1c0041d20df 100644 (file)
@@ -5,6 +5,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -39,10 +40,12 @@ struct stat xfstat(int);
 #define xopen(...)     xopenat(AT_FDCWD, __VA_ARGS__)
 
 #define xioctl(_fd, _nr, ...)                                          \
-do {                                                                   \
-       if (ioctl((_fd), (_nr), ##__VA_ARGS__))                         \
+({                                                                     \
+       int _ret = ioctl((_fd), (_nr), ##__VA_ARGS__);                  \
+       if (_ret < 0)                                                   \
                die(#_nr " ioctl error: %m");                           \
-} while (0)
+       _ret;                                                           \
+})
 
 enum units {
        BYTES,
@@ -68,17 +71,6 @@ u64 get_size(const char *, int);
 unsigned get_blocksize(const char *, int);
 int open_for_format(const char *, bool);
 
-int bcachectl_open(void);
-
-struct bcache_handle {
-       uuid_le uuid;
-       int     ioctl_fd;
-       int     sysfs_fd;
-};
-
-void bcache_fs_close(struct bcache_handle);
-struct bcache_handle bcache_fs_open(const char *);
-
 bool ask_yn(void);
 
 struct range {
@@ -155,6 +147,8 @@ unsigned hatoi_validate(const char *, const char *);
 
 u32 crc32c(u32, const void *, size_t);
 
+char *dev_to_name(dev_t);
 char *dev_to_path(dev_t);
+char *dev_to_mount(char *);
 
 #endif /* _TOOLS_UTIL_H */