]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Refactoring for device specific commands
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 12 Mar 2017 14:53:43 +0000 (06:53 -0800)
committerKent Overstreet <kent.overstreet@gmail.com>
Sun, 12 Mar 2017 14:53:43 +0000 (06:53 -0800)
17 files changed:
.bcache_revision
bcache.c
cmd_device.c
cmd_format.c
cmds.h
include/linux/bcache-ioctl.h
libbcache/alloc.c
libbcache/btree_update.c
libbcache/buckets.c
libbcache/buckets.h
libbcache/buckets_types.h
libbcache/chardev.c
libbcache/extents.c
libbcache/notify.c
libbcache/super.c
libbcache/super.h
libbcache/sysfs.c

index ca2be28b5871f293311e62b1356d5145a1f26c0f..434bc959e01fedbf319fc956e3d1d5edcfa6c7d2 100644 (file)
@@ -1 +1 @@
-BCACHE_REVISION=5548432e689033ee93f0835b41571f8ec8b7bc48
+BCACHE_REVISION=3ea79179e3101fb50de8730a809d00d189f05be5
index b3c8e468502cbb441516dcc195b7937465371d63..1074210e2a4d80dce2c529814bea8b88aeb5a8e6 100644 (file)
--- a/bcache.c
+++ b/bcache.c
@@ -28,56 +28,113 @@ static void usage(void)
        puts("bcache - tool for managing bcache volumes/filesystems\n"
             "usage: bcache <command> [<args>]\n"
             "\n"
-            "Commands for formatting, startup and shutdown:\n"
-            "  format         Format a new filesystem\n"
-            "  unlock         Unlock an encrypted filesystem prior to running/mounting\n"
-            "  assemble       Assemble an existing multi device filesystem\n"
-            "  incremental    Incrementally assemble an existing multi device filesystem\n"
-            "  run            Start a partially assembled filesystem\n"
-            "  stop           Stop a running filesystem\n"
+            "Superblock commands:\n"
+            "  format           Format a new filesystem\n"
+            "  show-super       Dump superblock information to stdout\n"
             "\n"
+            "Repair:\n"
+            "  bcache fsck      Check an existing filesystem for errors\n"
+            "\n"
+            "Startup/shutdown, assembly of multi device filesystems:\n"
+            "  unlock           Unlock an encrypted filesystem prior to running/mounting\n"
+            "  assemble         Assemble an existing multi device filesystem\n"
+            "  incremental      Incrementally assemble an existing multi device filesystem\n"
+            "  run              Start a partially assembled filesystem\n"
+            "  stop             Stop a running filesystem\n"
+
             "Commands for managing a running filesystem:\n"
-            "  fs_show        Show various information about a filesystem\n"
-            "  fs_set         Modify filesystem options\n"
+            "  fs show          Show various information about a filesystem\n"
+            "  fs set           Modify filesystem options\n"
             "\n"
-            "Commands for managing a specific device in a filesystem:\n"
-            "  device_show    Show information about a formatted device\n"
-            "  device_add     Add a device to an existing (running) filesystem\n"
-            "  device_fail    Mark a device as failed\n"
-            "  device_remove  Remove a device from an existing (running) filesystem\n"
+            "Commands for managing devices within a running filesystem:\n"
+            "  device add       Add a new device to an existing filesystem\n"
+            "  device remove    Remove a device from an existing filesystem\n"
+            "  device online    Readd an existing member to a filesystem\n"
+            "  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"
             "\n"
-            "Repair:\n"
-            "  bcache fsck    Check an existing filesystem for errors\n"
+            "Migrate:\n"
+            "  migrate          Migrate an existing filesystem to bcachefs, in place\n"
+            "  migrate-superblock\n"
+            "                   Add default superblock, after bcache migrate\n"
             "\n"
             "Debug:\n"
-            "  bcache dump    Dump filesystem metadata to a qcow2 image\n"
-            "  bcache list    List filesystem metadata in textual form\n"
-            "\n"
-            "Migrate:\n"
-            "  bcache migrate Migrate an existing filesystem to bcachefs, in place\n"
-            "  bcache migrate_superblock\n"
-            "                 Add default superblock, after bcache migrate\n");
+            "These commands work on offline, unmounted filesystems\n"
+            "  dump             Dump filesystem metadata to a qcow2 image\n"
+            "  list             List filesystem metadata in textual form\n");
 }
 
-int main(int argc, char *argv[])
-{
-       char *cmd;
-
-       setvbuf(stdout, NULL, _IOLBF, 0);
+static char *full_cmd;
 
-       if (argc < 2) {
+static char *pop_cmd(int *argc, char *argv[])
+{
+       if (*argc < 2) {
                printf("%s: missing command\n", argv[0]);
                usage();
                exit(EXIT_FAILURE);
        }
 
-       cmd = argv[1];
+       char *cmd = argv[1];
+       memmove(&argv[1], &argv[2], *argc * sizeof(argv[0]));
+       (*argc)--;
+
+       full_cmd = mprintf("%s %s", full_cmd, cmd);
+       return cmd;
+}
+
+static int fs_cmds(int argc, char *argv[])
+{
+       char *cmd = pop_cmd(&argc, argv);
+
+       if (!strcmp(cmd, "show"))
+               return cmd_fs_show(argc, argv);
+       if (!strcmp(cmd, "set"))
+               return cmd_fs_set(argc, argv);
 
-       memmove(&argv[1], &argv[2], argc * sizeof(argv[0]));
-       argc--;
+       usage();
+       return 0;
+}
+
+static int device_cmds(int argc, char *argv[])
+{
+       char *cmd = pop_cmd(&argc, argv);
+
+       if (!strcmp(cmd, "add"))
+               return cmd_device_add(argc, argv);
+       if (!strcmp(cmd, "remove"))
+               return cmd_device_remove(argc, argv);
+       if (!strcmp(cmd, "online"))
+               return cmd_device_online(argc, argv);
+       if (!strcmp(cmd, "offline"))
+               return cmd_device_offline(argc, argv);
+       if (!strcmp(cmd, "evacuate"))
+               return cmd_device_offline(argc, argv);
+       if (!strcmp(cmd, "set-state"))
+               return cmd_device_set_state(argc, argv);
+
+       usage();
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       full_cmd = argv[0];
+
+       setvbuf(stdout, NULL, _IOLBF, 0);
+
+       char *cmd = pop_cmd(&argc, argv);
 
        if (!strcmp(cmd, "format"))
                return cmd_format(argc, argv);
+       if (!strcmp(cmd, "show-super"))
+               return cmd_show_super(argc, argv);
+
+       if (!strcmp(cmd, "fsck"))
+               return cmd_fsck(argc, argv);
+
+       if (!strcmp(cmd, "unlock"))
+               return cmd_unlock(argc, argv);
        if (!strcmp(cmd, "assemble"))
                return cmd_assemble(argc, argv);
        if (!strcmp(cmd, "incremental"))
@@ -87,36 +144,22 @@ int main(int argc, char *argv[])
        if (!strcmp(cmd, "stop"))
                return cmd_stop(argc, argv);
 
-       if (!strcmp(cmd, "fs_show"))
-               return cmd_fs_show(argc, argv);
-       if (!strcmp(cmd, "fs_set"))
-               return cmd_fs_set(argc, argv);
+       if (!strcmp(cmd, "fs"))
+               return fs_cmds(argc, argv);
 
-       if (!strcmp(cmd, "device_show"))
-               return cmd_device_show(argc, argv);
-       if (!strcmp(cmd, "device_add"))
-               return cmd_device_add(argc, argv);
-       if (!strcmp(cmd, "device_fail"))
-               return cmd_device_fail(argc, argv);
-       if (!strcmp(cmd, "device_remove"))
-               return cmd_device_remove(argc, argv);
+       if (!strcmp(cmd, "device"))
+               return device_cmds(argc, argv);
 
-       if (!strcmp(cmd, "fsck"))
-               return cmd_fsck(argc, argv);
-
-       if (!strcmp(cmd, "unlock"))
-               return cmd_unlock(argc, argv);
+       if (!strcmp(cmd, "migrate"))
+               return cmd_migrate(argc, argv);
+       if (!strcmp(cmd, "migrate-superblock"))
+               return cmd_migrate_superblock(argc, argv);
 
        if (!strcmp(cmd, "dump"))
                return cmd_dump(argc, argv);
        if (!strcmp(cmd, "list"))
                return cmd_list(argc, argv);
 
-       if (!strcmp(cmd, "migrate"))
-               return cmd_migrate(argc, argv);
-       if (!strcmp(cmd, "migrate_superblock"))
-               return cmd_migrate_superblock(argc, argv);
-
        usage();
        return 0;
 }
index 32f4492b5a52c87b1840ccec2a2f99a6f5a04828..d898733bbd53d4d008eadfc7b81e5893fe5238bc 100644 (file)
@@ -15,6 +15,7 @@
 #include "cmds.h"
 #include "libbcache.h"
 #include "linux/bcache-ioctl.h"
+#include "opts.h"
 #include "tools-util.h"
 
 /* This code belongs under show_fs */
@@ -164,23 +165,17 @@ int cmd_device_show(int argc, char *argv[])
 }
 #endif
 
-int cmd_device_show(int argc, char *argv[])
+static void disk_ioctl(const char *fs, const char *dev, int cmd, int flags)
 {
-       struct bch_sb *sb;
-
-       if (argc != 2)
-               die("please supply a single device");
-
-       sb = bcache_super_read(argv[1]);
-       bcache_super_print(sb, HUMAN_READABLE);
+       struct bch_ioctl_disk i = { .flags = flags, .dev = (__u64) dev, };
 
-       return 0;
+       xioctl(bcache_fs_open(fs).ioctl_fd, cmd, &i);
 }
 
 static void device_add_usage(void)
 {
-       puts("bcache device_add - add a device to an existing filesystem\n"
-            "Usage: bcache device_add [OPTION]... filesystem device\n"
+       puts("bcache device add - add a device to an existing filesystem\n"
+            "Usage: bcache device add [OPTION]... filesystem device\n"
             "\n"
             "Options:\n"
             "      --fs_size=size          Size of filesystem on device\n"
@@ -193,24 +188,23 @@ static void device_add_usage(void)
             "Report bugs to <linux-bcache@vger.kernel.org>");
 }
 
-static const struct option device_add_opts[] = {
-       { "fs_size",            required_argument,      NULL, 'S' },
-       { "bucket",             required_argument,      NULL, 'B' },
-       { "discard",            no_argument,            NULL, 'D' },
-       { "tier",               required_argument,      NULL, 't' },
-       { "force",              no_argument,            NULL, 'f' },
-       { NULL }
-};
-
 int cmd_device_add(int argc, char *argv[])
 {
+       static const struct option longopts[] = {
+               { "fs_size",            required_argument,      NULL, 'S' },
+               { "bucket",             required_argument,      NULL, 'B' },
+               { "discard",            no_argument,            NULL, 'D' },
+               { "tier",               required_argument,      NULL, 't' },
+               { "force",              no_argument,            NULL, 'f' },
+               { NULL }
+       };
        struct format_opts format_opts = format_opts_default();
        struct dev_opts dev_opts = { 0 };
        bool force = false;
        int opt;
 
        while ((opt = getopt_long(argc, argv, "t:fh",
-                                 device_add_opts, NULL)) != -1)
+                                 longopts, NULL)) != -1)
                switch (opt) {
                case 'S':
                        if (bch_strtoull_h(optarg, &dev_opts.size))
@@ -256,19 +250,16 @@ int cmd_device_add(int argc, char *argv[])
        fsync(dev_opts.fd);
        close(dev_opts.fd);
 
-       struct bch_ioctl_disk_add ia = {
-               .dev = (__u64) dev_opts.path,
-       };
-
-       xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &ia);
+       struct bch_ioctl_disk i = { .dev = (__u64) dev_opts.path, };
 
+       xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &i);
        return 0;
 }
 
-static void device_fail_usage(void)
+static void device_remove_usage(void)
 {
-       puts("bcache device_fail - mark a device as failed\n"
-            "Usage: bcache device_fail filesystem [devices]\n"
+       puts("bcache device_remove - remove a device from a filesystem\n"
+            "Usage: bcache device remove filesystem device\n"
             "\n"
             "Options:\n"
             "  -f, --force                 Force removal, even if some data\n"
@@ -280,104 +271,175 @@ static void device_fail_usage(void)
        exit(EXIT_SUCCESS);
 }
 
-int cmd_device_fail(int argc, char *argv[])
+int cmd_device_remove(int argc, char *argv[])
 {
        static const struct option longopts[] = {
-               { "force-degraded",             0, NULL, 'f' },
-               //{ "force-data-lost",          0, NULL, 'F' },
-               //{ "force-metadata-lost",      0, NULL, 'F' },
-               { "help",                       0, NULL, 'h' },
+               { "force",              0, NULL, 'f' },
+               { "force-metadata",     0, NULL, 'F' },
+               { "help",               0, NULL, 'h' },
                { NULL }
        };
-       int opt, force_degraded = 0, force_data = 0, force_metadata = 0;
+       int opt, flags = 0;
 
        while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
                switch (opt) {
                case 'f':
-                       force_degraded = 1;
+                       flags |= BCH_FORCE_IF_DATA_LOST;
+                       break;
+               case 'F':
+                       flags |= BCH_FORCE_IF_METADATA_LOST;
                        break;
                case 'h':
-                       device_fail_usage();
+                       device_remove_usage();
                }
 
-       if (argc - optind < 2)
-               die("Please supply a filesystem and at least one device to fail");
+       if (argc - optind != 2)
+               die("Please supply a filesystem and at least one device to remove");
 
-       struct bcache_handle fs = bcache_fs_open(argv[optind]);
+       disk_ioctl(argv[optind], argv[optind + 1],
+                  BCH_IOCTL_DISK_REMOVE, flags);
+       return 0;
+}
+
+static void device_online_usage(void)
+{
+       puts("bcache device online - readd a device to a running filesystem\n"
+            "Usage: bcache device online [OPTION]... filesystem device\n"
+            "\n"
+            "Options:\n"
+            "  -h, --help                  Display this help and exit\n"
+            "\n"
+            "Report bugs to <linux-bcache@vger.kernel.org>");
+}
 
-       for (unsigned i = optind + 1; i < argc; i++) {
-               struct bch_ioctl_disk_set_state ir = {
-                       .dev            = (__u64) argv[i],
-                       .new_state      = BCH_MEMBER_STATE_FAILED,
-               };
+int cmd_device_online(int argc, char *argv[])
+{
+       int opt;
 
-               if (force_degraded)
-                       ir.flags |= BCH_FORCE_IF_DEGRADED;
-               if (force_data)
-                       ir.flags |= BCH_FORCE_IF_DATA_LOST;
-               if (force_metadata)
-                       ir.flags |= BCH_FORCE_IF_METADATA_LOST;
+       while ((opt = getopt(argc, argv, "h")) != -1)
+               switch (opt) {
+               case 'h':
+                       device_online_usage();
+                       exit(EXIT_SUCCESS);
+               }
 
-               xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &ir);
-       }
+       if (argc - optind != 2)
+               die("Please supply a filesystem and a device");
 
+       disk_ioctl(argv[optind], argv[optind + 1], BCH_IOCTL_DISK_ONLINE, 0);
        return 0;
 }
 
-static void device_remove_usage(void)
+static void device_offline_usage(void)
 {
-       puts("bcache device_remove - remove one or more devices from a filesystem\n"
-            "Usage: bcache device_remove filesystem [devices]\n"
+       puts("bcache device offline - take a device offline, without removing it\n"
+            "Usage: bcache device offline [OPTION]... filesystem device\n"
             "\n"
             "Options:\n"
-            "  -f, --force                 Force removal, even if some data\n"
-            "                              couldn't be migrated\n"
-            "      --force-metadata        Force removal, even if some metadata\n"
-            "                              couldn't be migrated\n"
+            "  -f, --force                 Force, if data redundancy will be degraded\n"
+            "  -h, --help                  Display this help and exit\n"
+            "\n"
+            "Report bugs to <linux-bcache@vger.kernel.org>");
+}
+
+int cmd_device_offline(int argc, char *argv[])
+{
+       static const struct option longopts[] = {
+               { "force",              0, NULL, 'f' },
+               { NULL }
+       };
+       int opt, flags = 0;
+
+       while ((opt = getopt_long(argc, argv, "fh",
+                                 longopts, NULL)) != -1)
+               switch (opt) {
+               case 'f':
+                       flags |= BCH_FORCE_IF_DEGRADED;
+                       break;
+               case 'h':
+                       device_offline_usage();
+                       exit(EXIT_SUCCESS);
+               }
+
+       if (argc - optind != 2)
+               die("Please supply a filesystem and a device");
+
+       disk_ioctl(argv[optind], argv[optind + 1],
+                  BCH_IOCTL_DISK_OFFLINE, flags);
+       return 0;
+}
+
+static void device_evacuate_usage(void)
+{
+       puts("bcache device evacuate - move data off of a given device\n"
+            "Usage: bcache device evacuate [OPTION]... filesystem device\n"
+            "\n"
+            "Options:\n"
+            "  -h, --help                  Display this help and exit\n"
+            "\n"
+            "Report bugs to <linux-bcache@vger.kernel.org>");
+}
+
+int cmd_device_evacuate(int argc, char *argv[])
+{
+       int opt;
+
+       while ((opt = getopt(argc, argv, "h")) != -1)
+               switch (opt) {
+               case 'h':
+                       device_evacuate_usage();
+                       exit(EXIT_SUCCESS);
+               }
+
+       if (argc - optind != 2)
+               die("Please supply a filesystem and a device");
+
+       disk_ioctl(argv[optind], argv[optind + 1], BCH_IOCTL_DISK_EVACUATE, 0);
+       return 0;
+}
+
+static void device_set_state_usage(void)
+{
+       puts("bcache device set-state\n"
+            "Usage: bcache device set-state filesystem device new-state\n"
+            "\n"
+            "Options:\n"
+            "  -f, --force                 Force, if data redundancy will be degraded\n"
             "  -h, --help                  display this help and exit\n"
             "Report bugs to <linux-bcache@vger.kernel.org>");
        exit(EXIT_SUCCESS);
 }
 
-int cmd_device_remove(int argc, char *argv[])
+int cmd_device_set_state(int argc, char *argv[])
 {
        static const struct option longopts[] = {
-               { "force",              0, NULL, 'f' },
-               { "force-metadata",     0, NULL, 'F' },
-               { "help",               0, NULL, 'h' },
+               { "force",                      0, NULL, 'f' },
+               { "help",                       0, NULL, 'h' },
                { NULL }
        };
-       int opt, force_data = 0, force_metadata = 0;
+       int opt, flags = 0;
 
        while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
                switch (opt) {
                case 'f':
-                       force_data = 1;
-                       break;
-               case 'F':
-                       force_metadata = 1;
+                       flags |= BCH_FORCE_IF_DEGRADED;
                        break;
                case 'h':
-                       device_remove_usage();
+                       device_set_state_usage();
                }
 
-       if (argc - optind < 2)
-               die("Please supply a filesystem and at least one device to remove");
+       if (argc - optind != 3)
+               die("Please supply a filesystem, device and state");
 
        struct bcache_handle fs = bcache_fs_open(argv[optind]);
 
-       for (unsigned i = optind + 1; i < argc; i++) {
-               struct bch_ioctl_disk_remove ir = {
-                       .dev = (__u64) argv[i],
-               };
-
-               if (force_data)
-                       ir.flags |= BCH_FORCE_IF_DATA_LOST;
-               if (force_metadata)
-                       ir.flags |= BCH_FORCE_IF_METADATA_LOST;
-
-               xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_REMOVE, &ir);
-       }
+       struct bch_ioctl_disk_set_state i = {
+               .flags          = flags,
+               .dev            = (__u64) argv[optind + 1],
+               .new_state      = read_string_list_or_die(argv[optind + 2],
+                                               bch_dev_state, "device state"),
+       };
 
+       xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &i);
        return 0;
 }
index 3ef862f7b3f13290de8c5a28722d55d8580f8540..45764a10e259e3b402476c0092484726bc908e19 100644 (file)
@@ -268,3 +268,15 @@ int cmd_format(int argc, char *argv[])
 
        return 0;
 }
+
+int cmd_show_super(int argc, char *argv[])
+{
+       struct bch_sb *sb;
+
+       if (argc != 2)
+               die("please supply a single device");
+
+       sb = bcache_super_read(argv[1]);
+       bcache_super_print(sb, HUMAN_READABLE);
+       return 0;
+}
diff --git a/cmds.h b/cmds.h
index 401f295c9aa7bc766250e2e65956fc8b6c8b3009..7e4712a5b3e06db445eadb8415f4cd631308931c 100644 (file)
--- a/cmds.h
+++ b/cmds.h
@@ -10,6 +10,7 @@
 #include "tools-util.h"
 
 int cmd_format(int argc, char *argv[]);
+int cmd_show_super(int argc, char *argv[]);
 
 int cmd_unlock(int argc, char *argv[]);
 int cmd_assemble(int argc, char *argv[]);
@@ -20,10 +21,12 @@ int cmd_stop(int argc, char *argv[]);
 int cmd_fs_show(int argc, char *argv[]);
 int cmd_fs_set(int argc, char *argv[]);
 
-int cmd_device_show(int argc, char *argv[]);
 int cmd_device_add(int argc, char *argv[]);
-int cmd_device_fail(int argc, char *argv[]);
 int cmd_device_remove(int argc, char *argv[]);
+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_fsck(int argc, char *argv[]);
 
index 7a0513cd2e119d0cd432d0f03bfa25da93786d05..2d07666c97ce24ba5a31aac3088d267cbd12959a 100644 (file)
@@ -8,8 +8,6 @@
 extern "C" {
 #endif
 
-/* global control dev: */
-
 #define BCH_FORCE_IF_DATA_LOST         (1 << 0)
 #define BCH_FORCE_IF_METADATA_LOST     (1 << 1)
 #define BCH_FORCE_IF_DATA_DEGRADED     (1 << 2)
@@ -19,24 +17,12 @@ extern "C" {
        (BCH_FORCE_IF_DATA_DEGRADED|            \
         BCH_FORCE_IF_METADATA_DEGRADED)
 
-#define BCH_IOCTL_ASSEMBLE     _IOW('r', 1, struct bch_ioctl_assemble)
-#define BCH_IOCTL_INCREMENTAL  _IOW('r', 1, struct bch_ioctl_incremental)
-
-/* cache set control dev: */
+#define BCH_BY_UUID                    (1 << 4)
 
-#define BCH_IOCTL_RUN          _IO('r', 2)
-#define BCH_IOCTL_STOP         _IO('r', 3)
-
-#define BCH_IOCTL_DISK_ADD     _IOW('r', 4, struct bch_ioctl_disk_add)
-#define BCH_IOCTL_DISK_REMOVE  _IOW('r', 5, struct bch_ioctl_disk_remove)
-#define BCH_IOCTL_DISK_SET_STATE _IOW('r', 6, struct bch_ioctl_disk_set_state)
-
-#define BCH_IOCTL_DISK_REMOVE_BY_UUID                                  \
-       _IOW('r', 5, struct bch_ioctl_disk_remove_by_uuid)
-#define BCH_IOCTL_DISK_FAIL_BY_UUID                                    \
-       _IOW('r', 6, struct bch_ioctl_disk_fail_by_uuid)
+/* global control dev: */
 
-#define BCH_IOCTL_QUERY_UUID   _IOR('r', 6, struct bch_ioctl_query_uuid)
+#define BCH_IOCTL_ASSEMBLE     _IOW(0xbc, 1, struct bch_ioctl_assemble)
+#define BCH_IOCTL_INCREMENTAL  _IOW(0xbc, 2, struct bch_ioctl_incremental)
 
 struct bch_ioctl_assemble {
        __u32                   flags;
@@ -51,13 +37,29 @@ struct bch_ioctl_incremental {
        __u64                   dev;
 };
 
-struct bch_ioctl_disk_add {
+/* filesystem ioctls: */
+
+#define BCH_IOCTL_QUERY_UUID   _IOR(0xbc,      1,  struct bch_ioctl_query_uuid)
+#define BCH_IOCTL_START                _IOW(0xbc,      2,  struct bch_ioctl_start)
+#define BCH_IOCTL_STOP         _IO(0xbc,       3)
+#define BCH_IOCTL_DISK_ADD     _IOW(0xbc,      4,  struct bch_ioctl_disk)
+#define BCH_IOCTL_DISK_REMOVE  _IOW(0xbc,      5,  struct bch_ioctl_disk)
+#define BCH_IOCTL_DISK_ONLINE  _IOW(0xbc,      6,  struct bch_ioctl_disk)
+#define BCH_IOCTL_DISK_OFFLINE _IOW(0xbc,      7,  struct bch_ioctl_disk)
+#define BCH_IOCTL_DISK_SET_STATE _IOW(0xbc,    8,  struct bch_ioctl_disk_set_state)
+#define BCH_IOCTL_DISK_EVACUATE        _IOW(0xbc,      9,  struct bch_ioctl_disk)
+#define BCH_IOCTL_DATA         _IOW(0xbc,      10, struct bch_ioctl_data)
+
+struct bch_ioctl_query_uuid {
+       uuid_le                 uuid;
+};
+
+struct bch_ioctl_start {
        __u32                   flags;
        __u32                   pad;
-       __u64                   dev;
 };
 
-struct bch_ioctl_disk_remove {
+struct bch_ioctl_disk {
        __u32                   flags;
        __u32                   pad;
        __u64                   dev;
@@ -70,20 +72,21 @@ struct bch_ioctl_disk_set_state {
        __u64                   dev;
 };
 
-struct bch_ioctl_disk_remove_by_uuid {
-       __u32                   flags;
-       __u32                   pad;
-       uuid_le                 dev;
-};
+#define BCH_REWRITE_INCREASE_REPLICAS  (1 << 0)
+#define BCH_REWRITE_DECREASE_REPLICAS  (1 << 1)
 
-struct bch_ioctl_disk_fail_by_uuid {
+#define BCH_REWRITE_RECOMPRESS         (1 << 0)
+#define BCH_REWRITE_DECREASE_REPLICAS  (1 << 1)
+
+struct bch_ioctl_data {
        __u32                   flags;
        __u32                   pad;
-       uuid_le                 dev;
-};
 
-struct bch_ioctl_query_uuid {
-       uuid_le                 uuid;
+       __u64                   start_inode;
+       __u64                   start_offset;
+
+       __u64                   end_inode;
+       __u64                   end_offset;
 };
 
 #ifdef __cplusplus
index 2392c68841661dd4e69fae0bf9c48856d329f363..2f892914f9e33ac9b779136adda629998a2c9623 100644 (file)
@@ -154,11 +154,10 @@ static void pd_controllers_update(struct work_struct *work)
                        s64 fragmented = ((stats.buckets_dirty +
                                           stats.buckets_cached) <<
                                          bucket_bits) -
-                               ((stats.sectors_dirty +
-                                 stats.sectors_cached) << 9);
+                               ((stats.sectors[S_DIRTY] +
+                                 stats.sectors[S_CACHED] ) << 9);
 
-                       if (fragmented < 0)
-                               fragmented = 0;
+                       fragmented = max(0LL, fragmented);
 
                        bch_pd_controller_update(&ca->moving_gc_pd,
                                                 free, fragmented, -1);
index 8db7034faaee9232775677f71e28d6e6243b82b7..751a51c2c34898d46587b9d33a75230d604df375 100644 (file)
@@ -385,7 +385,7 @@ static void bch_btree_set_root_inmem(struct bch_fs *c, struct btree *b,
                        bch_btree_node_free_index(c, NULL, old->btree_id,
                                                  bkey_i_to_s_c(&old->key),
                                                  &stats);
-               bch_fs_stats_apply(c, &stats, &btree_reserve->disk_res,
+               bch_fs_usage_apply(c, &stats, &btree_reserve->disk_res,
                                   gc_pos_btree_root(b->btree_id));
        }
 
@@ -655,7 +655,7 @@ static void bch_insert_fixup_btree_ptr(struct btree_iter *iter,
                                          bkey_disassemble(b, k, &tmp),
                                          &stats);
 
-       bch_fs_stats_apply(c, &stats, disk_res, gc_pos_btree_node(b));
+       bch_fs_usage_apply(c, &stats, disk_res, gc_pos_btree_node(b));
 
        bch_btree_bset_insert_key(iter, b, node_iter, insert);
        set_btree_node_dirty(b);
index b1b96d581e9e33c8dfce1cb420244089292699c7..a28d493035882ebb05a900b9f7d64249518f909f 100644 (file)
@@ -204,7 +204,21 @@ static inline int is_cached_bucket(struct bucket_mark m)
                !m.dirty_sectors && !!m.cached_sectors;
 }
 
-void bch_fs_stats_apply(struct bch_fs *c,
+static inline enum s_alloc bucket_type(struct bucket_mark m)
+{
+       return is_meta_bucket(m) ? S_META : S_DIRTY;
+}
+
+static bool bucket_became_unavailable(struct bch_fs *c,
+                                     struct bucket_mark old,
+                                     struct bucket_mark new)
+{
+       return is_available_bucket(old) &&
+              !is_available_bucket(new) &&
+              c && c->gc_pos.phase == GC_PHASE_DONE;
+}
+
+void bch_fs_usage_apply(struct bch_fs *c,
                        struct bch_fs_usage *stats,
                        struct disk_reservation *disk_res,
                        struct gc_pos gc_pos)
@@ -241,62 +255,43 @@ void bch_fs_stats_apply(struct bch_fs *c,
        memset(stats, 0, sizeof(*stats));
 }
 
-static bool bucket_became_unavailable(struct bch_fs *c,
-                                     struct bucket_mark old,
-                                     struct bucket_mark new)
+static void bch_fs_usage_update(struct bch_fs_usage *fs_usage,
+                               struct bucket_mark old, struct bucket_mark new)
 {
-       return is_available_bucket(old) &&
-              !is_available_bucket(new) &&
-              c && c->gc_pos.phase == GC_PHASE_DONE;
+       fs_usage->s[S_COMPRESSED][S_CACHED] +=
+               (int) new.cached_sectors - (int) old.cached_sectors;
+       fs_usage->s[S_COMPRESSED][bucket_type(old)] -=
+               old.dirty_sectors;
+       fs_usage->s[S_COMPRESSED][bucket_type(new)] +=
+               new.dirty_sectors;
 }
 
-static void bch_usage_update(struct bch_dev *ca,
-                            struct bucket_mark old, struct bucket_mark new,
-                            struct bch_fs_usage *bch_alloc_stats)
+static void bch_dev_usage_update(struct bch_dev *ca,
+                                struct bucket_mark old, struct bucket_mark new)
 {
        struct bch_fs *c = ca->fs;
-       struct bch_dev_usage *cache_stats;
+       struct bch_dev_usage *dev_usage;
 
        bch_fs_inconsistent_on(old.data_type && new.data_type &&
                        old.data_type != new.data_type, c,
                        "different types of metadata in same bucket: %u, %u",
                        old.data_type, new.data_type);
 
-       if (bch_alloc_stats) {
-               bch_alloc_stats->s[S_COMPRESSED][S_CACHED] +=
-                       (int) new.cached_sectors - (int) old.cached_sectors;
-
-               bch_alloc_stats->s[S_COMPRESSED]
-                       [is_meta_bucket(old) ? S_META : S_DIRTY] -=
-                       old.dirty_sectors;
-
-               bch_alloc_stats->s[S_COMPRESSED]
-                       [is_meta_bucket(new) ? S_META : S_DIRTY] +=
-                       new.dirty_sectors;
-       }
-
        preempt_disable();
-       cache_stats = this_cpu_ptr(ca->usage_percpu);
+       dev_usage = this_cpu_ptr(ca->usage_percpu);
 
-       cache_stats->sectors_cached +=
+       dev_usage->sectors[S_CACHED] +=
                (int) new.cached_sectors - (int) old.cached_sectors;
 
-       if (is_meta_bucket(old))
-               cache_stats->sectors_meta -= old.dirty_sectors;
-       else
-               cache_stats->sectors_dirty -= old.dirty_sectors;
+       dev_usage->sectors[bucket_type(old)] -= old.dirty_sectors;
+       dev_usage->sectors[bucket_type(new)] += new.dirty_sectors;
 
-       if (is_meta_bucket(new))
-               cache_stats->sectors_meta += new.dirty_sectors;
-       else
-               cache_stats->sectors_dirty += new.dirty_sectors;
-
-       cache_stats->buckets_alloc +=
+       dev_usage->buckets_alloc +=
                (int) new.owned_by_allocator - (int) old.owned_by_allocator;
 
-       cache_stats->buckets_meta += is_meta_bucket(new) - is_meta_bucket(old);
-       cache_stats->buckets_cached += is_cached_bucket(new) - is_cached_bucket(old);
-       cache_stats->buckets_dirty += is_dirty_bucket(new) - is_dirty_bucket(old);
+       dev_usage->buckets_meta += is_meta_bucket(new) - is_meta_bucket(old);
+       dev_usage->buckets_cached += is_cached_bucket(new) - is_cached_bucket(old);
+       dev_usage->buckets_dirty += is_dirty_bucket(new) - is_dirty_bucket(old);
        preempt_enable();
 
        if (!is_available_bucket(old) && is_available_bucket(new))
@@ -305,10 +300,9 @@ static void bch_usage_update(struct bch_dev *ca,
 
 #define bucket_data_cmpxchg(ca, g, new, expr)                  \
 ({                                                             \
-       struct bch_fs_usage _stats = { 0 };             \
        struct bucket_mark _old = bucket_cmpxchg(g, new, expr); \
                                                                \
-       bch_usage_update(ca, _old, new, &_stats);               \
+       bch_dev_usage_update(ca, _old, new);                    \
        _old;                                                   \
 })
 
@@ -317,7 +311,7 @@ void bch_invalidate_bucket(struct bch_dev *ca, struct bucket *g)
        struct bch_fs_usage stats = { 0 };
        struct bucket_mark old, new;
 
-       old = bucket_cmpxchg(g, new, ({
+       old = bucket_data_cmpxchg(ca, g, new, ({
                new.owned_by_allocator  = 1;
                new.had_metadata        = 0;
                new.data_type           = 0;
@@ -327,23 +321,8 @@ void bch_invalidate_bucket(struct bch_dev *ca, struct bucket *g)
                new.gen++;
        }));
 
-       bch_usage_update(ca, old, new, &stats);
-
-       BUG_ON(old.dirty_sectors);
-
-       /*
-        * Ick:
-        *
-        * Only stats.sectors_cached should be nonzero: this is important
-        * because in this path we modify bch_alloc_stats based on how the
-        * bucket_mark was modified, and the sector counts in bucket_mark are
-        * subject to (saturating) overflow - and if they did overflow, the
-        * bch_fs_usage stats will now be off. We can tolerate this for
-        * sectors_cached, but not anything else:
-        */
-       stats.s[S_COMPRESSED][S_CACHED] = 0;
-       stats.s[S_UNCOMPRESSED][S_CACHED] = 0;
-       BUG_ON(!bch_is_zero(&stats, sizeof(stats)));
+       /* XXX: we're not actually updating fs usage's cached sectors... */
+       bch_fs_usage_update(&stats, old, new);
 
        if (!old.owned_by_allocator && old.cached_sectors)
                trace_bcache_invalidate(ca, g - ca->buckets,
@@ -452,7 +431,6 @@ static void bch_mark_pointer(struct bch_fs *c,
        unsigned saturated;
        struct bch_dev *ca = c->devs[ptr->dev];
        struct bucket *g = ca->buckets + PTR_BUCKET_NR(ca, ptr);
-       u64 v;
        unsigned old_sectors, new_sectors;
        int disk_sectors, compressed_sectors;
 
@@ -476,9 +454,7 @@ static void bch_mark_pointer(struct bch_fs *c,
                goto out;
        }
 
-       v = READ_ONCE(g->_mark.counter);
-       do {
-               new.counter = old.counter = v;
+       old = bucket_data_cmpxchg(ca, g, new, ({
                saturated = 0;
 
                /*
@@ -523,11 +499,7 @@ static void bch_mark_pointer(struct bch_fs *c,
                }
 
                new.had_metadata |= is_meta_bucket(new);
-       } while ((v = cmpxchg(&g->_mark.counter,
-                             old.counter,
-                             new.counter)) != old.counter);
-
-       bch_usage_update(ca, old, new, NULL);
+       }));
 
        BUG_ON(!may_make_unavailable &&
               bucket_became_unavailable(c, old, new));
index 9a00d38a682aa67a469a1f31196ec09eefeb3007..81355576f33aafe0acb8b59ccd419b8dd17dddd6 100644 (file)
@@ -183,7 +183,7 @@ static inline u64 dev_buckets_free(struct bch_dev *ca)
 
 struct bch_fs_usage __bch_fs_usage_read(struct bch_fs *);
 struct bch_fs_usage bch_fs_usage_read(struct bch_fs *);
-void bch_fs_stats_apply(struct bch_fs *, struct bch_fs_usage *,
+void bch_fs_usage_apply(struct bch_fs *, struct bch_fs_usage *,
                        struct disk_reservation *, struct gc_pos);
 
 static inline u64 __bch_fs_sectors_used(struct bch_fs *c)
index 1856db93d6394dbd7c3312d1739be9cb6190d093..ca187099ee4185ec02933f695d4866806566aff4 100644 (file)
@@ -65,15 +65,10 @@ struct bucket {
        };
 };
 
-struct bch_dev_usage {
-       u64                     buckets_dirty;
-       u64                     buckets_cached;
-       u64                     buckets_meta;
-       u64                     buckets_alloc;
-
-       u64                     sectors_dirty;
-       u64                     sectors_cached;
-       u64                     sectors_meta;
+enum s_compressed {
+       S_COMPRESSED,
+       S_UNCOMPRESSED,
+       S_COMPRESSED_NR,
 };
 
 enum s_alloc {
@@ -83,10 +78,13 @@ enum s_alloc {
        S_ALLOC_NR,
 };
 
-enum s_compressed {
-       S_COMPRESSED,
-       S_UNCOMPRESSED,
-       S_COMPRESSED_NR,
+struct bch_dev_usage {
+       u64                     buckets_dirty;
+       u64                     buckets_cached;
+       u64                     buckets_meta;
+       u64                     buckets_alloc;
+
+       u64                     sectors[S_ALLOC_NR];
 };
 
 struct bch_fs_usage {
index d98a3ee17bfc93dca081eb45d9e71fbbcf0b9e7f..c764a9d0121fd49868b5b0fc3650a49c19c86cb3 100644 (file)
@@ -24,6 +24,9 @@ static long bch_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg)
        if (copy_from_user(&arg, user_arg, sizeof(arg)))
                return -EFAULT;
 
+       if (arg.flags || arg.pad)
+               return -EINVAL;
+
        user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL);
        if (!devs)
                return -ENOMEM;
@@ -69,6 +72,9 @@ static long bch_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg)
        if (copy_from_user(&arg, user_arg, sizeof(arg)))
                return -EFAULT;
 
+       if (arg.flags || arg.pad)
+               return -EINVAL;
+
        path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
        if (!path)
                return -ENOMEM;
@@ -96,30 +102,31 @@ static long bch_global_ioctl(unsigned cmd, void __user *arg)
        }
 }
 
-static long bch_ioctl_stop(struct bch_fs *c)
+static long bch_ioctl_query_uuid(struct bch_fs *c,
+                       struct bch_ioctl_query_uuid __user *user_arg)
 {
-       bch_fs_stop_async(c);
-       return 0;
+       return copy_to_user(&user_arg->uuid,
+                           &c->sb.user_uuid,
+                           sizeof(c->sb.user_uuid));
 }
 
-static long bch_ioctl_disk_add(struct bch_fs *c,
-                              struct bch_ioctl_disk_add __user *user_arg)
+static long bch_ioctl_start(struct bch_fs *c, struct bch_ioctl_start __user *user_arg)
 {
-       struct bch_ioctl_disk_add arg;
-       char *path;
-       int ret;
+       struct bch_ioctl_start arg;
 
        if (copy_from_user(&arg, user_arg, sizeof(arg)))
                return -EFAULT;
 
-       path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
-       if (!path)
-               return -ENOMEM;
+       if (arg.flags || arg.pad)
+               return -EINVAL;
 
-       ret = bch_dev_add(c, path);
-       kfree(path);
+       return bch_fs_start(c) ? -EIO : 0;
+}
 
-       return ret;
+static long bch_ioctl_stop(struct bch_fs *c)
+{
+       bch_fs_stop(c);
+       return 0;
 }
 
 /* returns with ref on ca->ref */
@@ -150,29 +157,49 @@ found:
        return ca;
 }
 
-static long bch_ioctl_disk_remove(struct bch_fs *c,
-                                 struct bch_ioctl_disk_remove __user *user_arg)
+#if 0
+static struct bch_member *bch_uuid_lookup(struct bch_fs *c, uuid_le uuid)
 {
-       struct bch_ioctl_disk_remove arg;
-       struct bch_dev *ca;
+       struct bch_sb_field_members *mi = bch_sb_get_members(c->disk_sb);
+       unsigned i;
+
+       lockdep_assert_held(&c->sb_lock);
+
+       for (i = 0; i < c->disk_sb->nr_devices; i++)
+               if (!memcmp(&mi->members[i].uuid, &uuid, sizeof(uuid)))
+                       return &mi->members[i];
+
+       return NULL;
+}
+#endif
+
+static long bch_ioctl_disk_add(struct bch_fs *c,
+                              struct bch_ioctl_disk __user *user_arg)
+{
+       struct bch_ioctl_disk arg;
+       char *path;
        int ret;
 
        if (copy_from_user(&arg, user_arg, sizeof(arg)))
                return -EFAULT;
 
-       ca = bch_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
-       if (IS_ERR(ca))
-               return PTR_ERR(ca);
+       if (arg.flags || arg.pad)
+               return -EINVAL;
 
-       ret = bch_dev_remove(c, ca, arg.flags);
+       path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
+       if (!path)
+               return -ENOMEM;
+
+       ret = bch_dev_add(c, path);
+       kfree(path);
 
        return ret;
 }
 
-static long bch_ioctl_disk_set_state(struct bch_fs *c,
-                                    struct bch_ioctl_disk_set_state __user *user_arg)
+static long bch_ioctl_disk_remove(struct bch_fs *c,
+                                 struct bch_ioctl_disk __user *user_arg)
 {
-       struct bch_ioctl_disk_set_state arg;
+       struct bch_ioctl_disk arg;
        struct bch_dev *ca;
        int ret;
 
@@ -183,75 +210,94 @@ static long bch_ioctl_disk_set_state(struct bch_fs *c,
        if (IS_ERR(ca))
                return PTR_ERR(ca);
 
-       ret = bch_dev_set_state(c, ca, arg.new_state, arg.flags);
+       ret = bch_dev_remove(c, ca, arg.flags);
 
        percpu_ref_put(&ca->ref);
        return ret;
 }
 
-static struct bch_member *bch_uuid_lookup(struct bch_fs *c, uuid_le uuid)
+static long bch_ioctl_disk_online(struct bch_fs *c,
+                                 struct bch_ioctl_disk __user *user_arg)
 {
-       struct bch_sb_field_members *mi = bch_sb_get_members(c->disk_sb);
-       unsigned i;
+       struct bch_ioctl_disk arg;
+       char *path;
+       int ret;
 
-       lockdep_assert_held(&c->sb_lock);
+       if (copy_from_user(&arg, user_arg, sizeof(arg)))
+               return -EFAULT;
 
-       for (i = 0; i < c->disk_sb->nr_devices; i++)
-               if (!memcmp(&mi->members[i].uuid, &uuid, sizeof(uuid)))
-                       return &mi->members[i];
+       if (arg.flags || arg.pad)
+               return -EINVAL;
 
-       return NULL;
+       path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
+       if (!path)
+               return -ENOMEM;
+
+       ret = bch_dev_online(c, path);
+       kfree(path);
+       return ret;
 }
 
-static long bch_ioctl_disk_remove_by_uuid(struct bch_fs *c,
-                       struct bch_ioctl_disk_remove_by_uuid __user *user_arg)
+static long bch_ioctl_disk_offline(struct bch_fs *c,
+                                  struct bch_ioctl_disk __user *user_arg)
 {
-       struct bch_ioctl_disk_fail_by_uuid arg;
-       struct bch_member *m;
-       int ret = -ENOENT;
+       struct bch_ioctl_disk arg;
+       struct bch_dev *ca;
+       int ret;
 
        if (copy_from_user(&arg, user_arg, sizeof(arg)))
                return -EFAULT;
 
-       mutex_lock(&c->sb_lock);
-       if ((m = bch_uuid_lookup(c, arg.dev))) {
-               /* XXX: */
-               SET_BCH_MEMBER_STATE(m, BCH_MEMBER_STATE_FAILED);
-               bch_write_super(c);
-               ret = 0;
-       }
-       mutex_unlock(&c->sb_lock);
+       if (arg.pad)
+               return -EINVAL;
 
+       ca = bch_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
+       if (IS_ERR(ca))
+               return PTR_ERR(ca);
+
+       ret = bch_dev_offline(c, ca, arg.flags);
+       percpu_ref_put(&ca->ref);
        return ret;
 }
 
-static long bch_ioctl_disk_fail_by_uuid(struct bch_fs *c,
-                       struct bch_ioctl_disk_fail_by_uuid __user *user_arg)
+static long bch_ioctl_disk_set_state(struct bch_fs *c,
+                                    struct bch_ioctl_disk_set_state __user *user_arg)
 {
-       struct bch_ioctl_disk_fail_by_uuid arg;
-       struct bch_member *m;
-       int ret = -ENOENT;
+       struct bch_ioctl_disk_set_state arg;
+       struct bch_dev *ca;
+       int ret;
 
        if (copy_from_user(&arg, user_arg, sizeof(arg)))
                return -EFAULT;
 
-       mutex_lock(&c->sb_lock);
-       if ((m = bch_uuid_lookup(c, arg.dev))) {
-               SET_BCH_MEMBER_STATE(m, BCH_MEMBER_STATE_FAILED);
-               bch_write_super(c);
-               ret = 0;
-       }
-       mutex_unlock(&c->sb_lock);
+       ca = bch_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
+       if (IS_ERR(ca))
+               return PTR_ERR(ca);
 
+       ret = bch_dev_set_state(c, ca, arg.new_state, arg.flags);
+
+       percpu_ref_put(&ca->ref);
        return ret;
 }
 
-static long bch_ioctl_query_uuid(struct bch_fs *c,
-                       struct bch_ioctl_query_uuid __user *user_arg)
+static long bch_ioctl_disk_evacuate(struct bch_fs *c,
+                                   struct bch_ioctl_disk __user *user_arg)
 {
-       return copy_to_user(&user_arg->uuid,
-                           &c->sb.user_uuid,
-                           sizeof(c->sb.user_uuid));
+       struct bch_ioctl_disk arg;
+       struct bch_dev *ca;
+       int ret;
+
+       if (copy_from_user(&arg, user_arg, sizeof(arg)))
+               return -EFAULT;
+
+       ca = bch_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
+       if (IS_ERR(ca))
+               return PTR_ERR(ca);
+
+       ret = bch_dev_migrate(c, ca);
+
+       percpu_ref_put(&ca->ref);
+       return ret;
 }
 
 long bch_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
@@ -267,8 +313,8 @@ long bch_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
 
        /* ioctls that do require admin cap: */
        switch (cmd) {
-       case BCH_IOCTL_RUN:
-               return -ENOTTY;
+       case BCH_IOCTL_START:
+               return bch_ioctl_start(c, arg);
        case BCH_IOCTL_STOP:
                return bch_ioctl_stop(c);
 
@@ -276,13 +322,14 @@ long bch_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
                return bch_ioctl_disk_add(c, arg);
        case BCH_IOCTL_DISK_REMOVE:
                return bch_ioctl_disk_remove(c, arg);
+       case BCH_IOCTL_DISK_ONLINE:
+               return bch_ioctl_disk_online(c, arg);
+       case BCH_IOCTL_DISK_OFFLINE:
+               return bch_ioctl_disk_offline(c, arg);
        case BCH_IOCTL_DISK_SET_STATE:
                return bch_ioctl_disk_set_state(c, arg);
-
-       case BCH_IOCTL_DISK_REMOVE_BY_UUID:
-               return bch_ioctl_disk_remove_by_uuid(c, arg);
-       case BCH_IOCTL_DISK_FAIL_BY_UUID:
-               return bch_ioctl_disk_fail_by_uuid(c, arg);
+       case BCH_IOCTL_DISK_EVACUATE:
+               return bch_ioctl_disk_evacuate(c, arg);
 
        default:
                return -ENOTTY;
index c1bf47b6989ab72b382769e622e75e9f5cfaa5f7..76b55f64813d8acafe73e4d9286454ed96dfe2a0 100644 (file)
@@ -931,7 +931,7 @@ struct extent_insert_state {
        struct btree_insert             *trans;
        struct btree_insert_entry       *insert;
        struct bpos                     committed;
-       struct bch_fs_usage     stats;
+       struct bch_fs_usage             stats;
 
        /* for deleting: */
        struct bkey_i                   whiteout;
@@ -1554,7 +1554,7 @@ next:
 stop:
        extent_insert_committed(s);
 
-       bch_fs_stats_apply(c, &s->stats, s->trans->disk_res,
+       bch_fs_usage_apply(c, &s->stats, s->trans->disk_res,
                           gc_pos_btree_node(b));
 
        EBUG_ON(bkey_cmp(iter->pos, s->committed));
@@ -1716,7 +1716,7 @@ stop:
                                     bkey_start_offset(&insert->k->k),
                                     insert->k->k.size);
 
-       bch_fs_stats_apply(c, &s.stats, trans->disk_res,
+       bch_fs_usage_apply(c, &s.stats, trans->disk_res,
                           gc_pos_btree_node(b));
 
        EBUG_ON(bkey_cmp(iter->pos, bkey_start_pos(&insert->k->k)));
index 1d5f626fcf5d77db1fde0eaa97278d874dd47428..b06a87499b2db7b0a9fff871981bfda010f4ef54 100644 (file)
@@ -94,33 +94,6 @@ void bch_notify_dev_added(struct bch_dev *ca)
        notify_put(c);
 }
 
-void bch_notify_dev_removing(struct bch_dev *ca)
-{
-       struct bch_fs *c = ca->fs;
-
-       notify_get_cache(ca);
-       notify_var(c, "STATE=removing");
-       notify_put(c);
-}
-
-void bch_notify_dev_remove_failed(struct bch_dev *ca)
-{
-       struct bch_fs *c = ca->fs;
-
-       notify_get_cache(ca);
-       notify_var(c, "STATE=remove_failed");
-       notify_put(c);
-}
-
-void bch_notify_dev_removed(struct bch_dev *ca)
-{
-       struct bch_fs *c = ca->fs;
-
-       notify_get_cache(ca);
-       notify_var(c, "STATE=removed");
-       notify_put(c);
-}
-
 void bch_notify_dev_error(struct bch_dev *ca, bool fatal)
 {
        struct bch_fs *c = ca->fs;
index bb4a7dc3612fc412e19f1b61db414393f876dbf3..1e272af2b59e46cb3d3549c786d06c9dbc53c62a 100644 (file)
@@ -1069,7 +1069,7 @@ static void bch_dev_io_ref_release(struct percpu_ref *ref)
        complete(&ca->offline_complete);
 }
 
-static void bch_dev_offline(struct bch_dev *ca)
+static void __bch_dev_offline(struct bch_dev *ca)
 {
        struct bch_fs *c = ca->fs;
 
@@ -1244,7 +1244,7 @@ err:
        return -ENOMEM;
 }
 
-static int bch_dev_online(struct bch_fs *c, struct bcache_superblock *sb)
+static int __bch_dev_online(struct bch_fs *c, struct bcache_superblock *sb)
 {
        struct bch_dev *ca;
        int ret;
@@ -1534,7 +1534,7 @@ static int __bch_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
 
        bch_journal_meta(&c->journal);
 
-       bch_dev_offline(ca);
+       __bch_dev_offline(ca);
        bch_dev_stop(ca);
        bch_dev_free(ca);
 
@@ -1644,7 +1644,7 @@ have_slot:
                goto err_unlock;
        }
 
-       if (bch_dev_online(c, &sb)) {
+       if (__bch_dev_online(c, &sb)) {
                err = "bch_dev_online() error";
                ret = -ENOMEM;
                goto err_unlock;
@@ -1677,6 +1677,88 @@ err:
        return ret ?: -EINVAL;
 }
 
+int bch_dev_online(struct bch_fs *c, const char *path)
+{
+       struct bcache_superblock sb = { 0 };
+       const char *err;
+
+       mutex_lock(&c->state_lock);
+
+       err = bch_read_super(&sb, bch_opts_empty(), path);
+       if (err)
+               goto err;
+
+       err = bch_dev_in_fs(c->disk_sb, sb.sb);
+       if (err)
+               goto err;
+
+       mutex_lock(&c->sb_lock);
+       if (__bch_dev_online(c, &sb)) {
+               mutex_unlock(&c->sb_lock);
+               goto err;
+       }
+       mutex_unlock(&c->sb_lock);
+
+       mutex_unlock(&c->state_lock);
+       return 0;
+err:
+       mutex_unlock(&c->state_lock);
+       bch_free_super(&sb);
+       bch_err(c, "error bringing %s online: %s", path, err);
+       return -EINVAL;
+}
+
+int bch_dev_offline(struct bch_fs *c, struct bch_dev *ca, int flags)
+{
+       mutex_lock(&c->state_lock);
+
+       if (!bch_dev_state_allowed(c, ca, BCH_MEMBER_STATE_FAILED, flags)) {
+               bch_err(ca, "Cannot offline required disk");
+               mutex_unlock(&c->state_lock);
+               return -EINVAL;
+       }
+
+       __bch_dev_read_only(c, ca);
+       __bch_dev_offline(ca);
+
+       mutex_unlock(&c->state_lock);
+       return 0;
+}
+
+int bch_dev_migrate(struct bch_fs *c, struct bch_dev *ca)
+{
+       int ret;
+
+       mutex_lock(&c->state_lock);
+
+       if (ca->mi.state == BCH_MEMBER_STATE_RW) {
+               bch_err(ca, "Cannot migrate data off RW device");
+               mutex_unlock(&c->state_lock);
+               return -EINVAL;
+       }
+
+       mutex_unlock(&c->state_lock);
+
+       ret = bch_move_data_off_device(ca);
+       if (ret) {
+               bch_err(ca, "Error migrating data: %i", ret);
+               return ret;
+       }
+
+       ret = bch_move_metadata_off_device(ca);
+       if (ret) {
+               bch_err(ca, "Error migrating metadata: %i", ret);
+               return ret;
+       }
+
+       if (ca->mi.has_data || ca->mi.has_metadata) {
+               bch_err(ca, "Migrate error: data still present");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /* Filesystem open: */
 
 const char *bch_fs_open(char * const *devices, unsigned nr_devices,
@@ -1731,7 +1813,7 @@ const char *bch_fs_open(char * const *devices, unsigned nr_devices,
        err = "bch_dev_online() error";
        mutex_lock(&c->sb_lock);
        for (i = 0; i < nr_devices; i++)
-               if (bch_dev_online(c, &sb[i])) {
+               if (__bch_dev_online(c, &sb[i])) {
                        mutex_unlock(&c->sb_lock);
                        goto err;
                }
@@ -1803,7 +1885,7 @@ static const char *__bch_fs_open_incremental(struct bcache_superblock *sb,
        err = "bch_dev_online() error";
 
        mutex_lock(&c->sb_lock);
-       if (bch_dev_online(c, sb)) {
+       if (__bch_dev_online(c, sb)) {
                mutex_unlock(&c->sb_lock);
                goto err;
        }
index 7999b74e38c8ac77dd77df854241becc4457ec38..79da390e601a1a2bd45c59c158ddb393469b87ce 100644 (file)
@@ -105,6 +105,9 @@ int bch_dev_set_state(struct bch_fs *, struct bch_dev *,
 int bch_dev_fail(struct bch_dev *, int);
 int bch_dev_remove(struct bch_fs *, struct bch_dev *, int);
 int bch_dev_add(struct bch_fs *, const char *);
+int bch_dev_online(struct bch_fs *, const char *);
+int bch_dev_offline(struct bch_fs *, struct bch_dev *, int);
+int bch_dev_migrate(struct bch_fs *, struct bch_dev *);
 
 void bch_fs_detach(struct bch_fs *);
 
index c96ad33616fad9a346172003835996b3359f1739..3536ec0c1c1110b6a615bf22d4dcf01e64cba313 100644 (file)
@@ -1174,11 +1174,11 @@ SHOW(bch_dev)
        sysfs_print(io_errors,
                    atomic_read(&ca->io_errors) >> IO_ERROR_SHIFT);
 
-       sysfs_hprint(dirty_data,        stats.sectors_dirty << 9);
-       sysfs_print(dirty_bytes,        stats.sectors_dirty << 9);
+       sysfs_hprint(dirty_data,        stats.sectors[S_DIRTY] << 9);
+       sysfs_print(dirty_bytes,        stats.sectors[S_DIRTY] << 9);
        sysfs_print(dirty_buckets,      stats.buckets_dirty);
-       sysfs_hprint(cached_data,       stats.sectors_cached << 9);
-       sysfs_print(cached_bytes,       stats.sectors_cached << 9);
+       sysfs_hprint(cached_data,       stats.sectors[S_CACHED] << 9);
+       sysfs_print(cached_bytes,       stats.sectors[S_CACHED] << 9);
        sysfs_print(cached_buckets,     stats.buckets_cached);
        sysfs_print(meta_buckets,       stats.buckets_meta);
        sysfs_print(alloc_buckets,      stats.buckets_alloc);