From d252e12accd8b4fdc0e50b539370b203f3894de9 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sun, 12 Mar 2017 06:53:43 -0800 Subject: [PATCH] Refactoring for device specific commands --- .bcache_revision | 2 +- bcache.c | 153 +++++++++++++------- cmd_device.c | 268 +++++++++++++++++++++-------------- cmd_format.c | 12 ++ cmds.h | 7 +- include/linux/bcache-ioctl.h | 69 ++++----- libbcache/alloc.c | 7 +- libbcache/btree_update.c | 4 +- libbcache/buckets.c | 108 ++++++-------- libbcache/buckets.h | 2 +- libbcache/buckets_types.h | 24 ++-- libbcache/chardev.c | 207 ++++++++++++++++----------- libbcache/extents.c | 6 +- libbcache/notify.c | 27 ---- libbcache/super.c | 94 +++++++++++- libbcache/super.h | 3 + libbcache/sysfs.c | 8 +- 17 files changed, 599 insertions(+), 402 deletions(-) diff --git a/.bcache_revision b/.bcache_revision index ca2be28b..434bc959 100644 --- a/.bcache_revision +++ b/.bcache_revision @@ -1 +1 @@ -BCACHE_REVISION=5548432e689033ee93f0835b41571f8ec8b7bc48 +BCACHE_REVISION=3ea79179e3101fb50de8730a809d00d189f05be5 diff --git a/bcache.c b/bcache.c index b3c8e468..1074210e 100644 --- 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 []\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" - "\n" - "Commands for managing a running filesystem:\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" + "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" + " bcache fsck Check an existing filesystem for errors\n" "\n" - "Debug:\n" - " bcache dump Dump filesystem metadata to a qcow2 image\n" - " bcache list List filesystem metadata in textual form\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" + "\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" "Migrate:\n" - " bcache migrate Migrate an existing filesystem to bcachefs, in place\n" - " bcache migrate_superblock\n" - " Add default superblock, after bcache 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" + "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[]) +static char *full_cmd; + +static char *pop_cmd(int *argc, char *argv[]) { - char *cmd; - - setvbuf(stdout, NULL, _IOLBF, 0); - - if (argc < 2) { + 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)--; - 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); + + 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; } diff --git a/cmd_device.c b/cmd_device.c index 32f4492b..d898733b 100644 --- a/cmd_device.c +++ b/cmd_device.c @@ -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; + struct bch_ioctl_disk i = { .flags = flags, .dev = (__u64) dev, }; - if (argc != 2) - die("please supply a single device"); - - sb = bcache_super_read(argv[1]); - bcache_super_print(sb, HUMAN_READABLE); - - 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 "); } -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,78 +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); - - return 0; -} - -static void device_fail_usage(void) -{ - puts("bcache device_fail - mark a device as failed\n" - "Usage: bcache device_fail filesystem [devices]\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" - " -h, --help display this help and exit\n" - "Report bugs to "); - exit(EXIT_SUCCESS); -} - -int cmd_device_fail(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' }, - { NULL } - }; - int opt, force_degraded = 0, force_data = 0, force_metadata = 0; - - while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1) - switch (opt) { - case 'f': - force_degraded = 1; - break; - case 'h': - device_fail_usage(); - } - - if (argc - optind < 2) - die("Please supply a filesystem and at least one device to fail"); - - struct bcache_handle fs = bcache_fs_open(argv[optind]); - - 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, - }; - - 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; - - xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &ir); - } + struct bch_ioctl_disk i = { .dev = (__u64) dev_opts.path, }; + xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &i); return 0; } static void device_remove_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_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" @@ -347,37 +279,167 @@ int cmd_device_remove(int argc, char *argv[]) { "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; + flags |= BCH_FORCE_IF_DATA_LOST; break; case 'F': - force_metadata = 1; + flags |= BCH_FORCE_IF_METADATA_LOST; break; case 'h': device_remove_usage(); } - if (argc - optind < 2) + if (argc - optind != 2) die("Please supply a filesystem and at least one device to remove"); + 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 "); +} + +int cmd_device_online(int argc, char *argv[]) +{ + int opt; + + while ((opt = getopt(argc, argv, "h")) != -1) + switch (opt) { + case 'h': + device_online_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_ONLINE, 0); + return 0; +} + +static void device_offline_usage(void) +{ + 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, if data redundancy will be degraded\n" + " -h, --help Display this help and exit\n" + "\n" + "Report bugs to "); +} + +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 "); +} + +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 "); + exit(EXIT_SUCCESS); +} + +int cmd_device_set_state(int argc, char *argv[]) +{ + static const struct option longopts[] = { + { "force", 0, NULL, 'f' }, + { "help", 0, NULL, 'h' }, + { 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_set_state_usage(); + } + + 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; } diff --git a/cmd_format.c b/cmd_format.c index 3ef862f7..45764a10 100644 --- a/cmd_format.c +++ b/cmd_format.c @@ -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 401f295c..7e4712a5 100644 --- 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[]); diff --git a/include/linux/bcache-ioctl.h b/include/linux/bcache-ioctl.h index 7a0513cd..2d07666c 100644 --- a/include/linux/bcache-ioctl.h +++ b/include/linux/bcache-ioctl.h @@ -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) +#define BCH_BY_UUID (1 << 4) -/* cache set control dev: */ +/* global control dev: */ -#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) - -#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 { - __u32 flags; - __u32 pad; - __u64 dev; +/* 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_disk_remove { +struct bch_ioctl_start { + __u32 flags; + __u32 pad; +}; + +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 { +#define BCH_REWRITE_INCREASE_REPLICAS (1 << 0) +#define BCH_REWRITE_DECREASE_REPLICAS (1 << 1) + +#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_disk_fail_by_uuid { - __u32 flags; - __u32 pad; - uuid_le dev; -}; + __u64 start_inode; + __u64 start_offset; -struct bch_ioctl_query_uuid { - uuid_le uuid; + __u64 end_inode; + __u64 end_offset; }; #ifdef __cplusplus diff --git a/libbcache/alloc.c b/libbcache/alloc.c index 2392c688..2f892914 100644 --- a/libbcache/alloc.c +++ b/libbcache/alloc.c @@ -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); diff --git a/libbcache/btree_update.c b/libbcache/btree_update.c index 8db7034f..751a51c2 100644 --- a/libbcache/btree_update.c +++ b/libbcache/btree_update.c @@ -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); diff --git a/libbcache/buckets.c b/libbcache/buckets.c index b1b96d58..a28d4930 100644 --- a/libbcache/buckets.c +++ b/libbcache/buckets.c @@ -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)); diff --git a/libbcache/buckets.h b/libbcache/buckets.h index 9a00d38a..81355576 100644 --- a/libbcache/buckets.h +++ b/libbcache/buckets.h @@ -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) diff --git a/libbcache/buckets_types.h b/libbcache/buckets_types.h index 1856db93..ca187099 100644 --- a/libbcache/buckets_types.h +++ b/libbcache/buckets_types.h @@ -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 { diff --git a/libbcache/chardev.c b/libbcache/chardev.c index d98a3ee1..c764a9d0 100644 --- a/libbcache/chardev.c +++ b/libbcache/chardev.c @@ -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,10 +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_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; + + if (arg.flags || arg.pad) + return -EINVAL; + + 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_remove(struct bch_fs *c, + struct bch_ioctl_disk __user *user_arg) +{ + struct bch_ioctl_disk arg; struct bch_dev *ca; int ret; @@ -166,6 +212,51 @@ static long bch_ioctl_disk_remove(struct bch_fs *c, ret = bch_dev_remove(c, ca, arg.flags); + percpu_ref_put(&ca->ref); + return ret; +} + +static long bch_ioctl_disk_online(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; + + if (arg.flags || arg.pad) + return -EINVAL; + + 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_offline(struct bch_fs *c, + struct bch_ioctl_disk __user *user_arg) +{ + struct bch_ioctl_disk arg; + struct bch_dev *ca; + int ret; + + if (copy_from_user(&arg, user_arg, sizeof(arg))) + return -EFAULT; + + 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; } @@ -189,71 +280,26 @@ static long bch_ioctl_disk_set_state(struct bch_fs *c, return ret; } -static struct bch_member *bch_uuid_lookup(struct bch_fs *c, uuid_le uuid) +static long bch_ioctl_disk_evacuate(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; - - 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; -} - -static long bch_ioctl_disk_remove_by_uuid(struct bch_fs *c, - struct bch_ioctl_disk_remove_by_uuid __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); + 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; } -static long bch_ioctl_disk_fail_by_uuid(struct bch_fs *c, - struct bch_ioctl_disk_fail_by_uuid __user *user_arg) -{ - struct bch_ioctl_disk_fail_by_uuid arg; - struct bch_member *m; - int ret = -ENOENT; - - 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); - - return ret; -} - -static long bch_ioctl_query_uuid(struct bch_fs *c, - struct bch_ioctl_query_uuid __user *user_arg) -{ - return copy_to_user(&user_arg->uuid, - &c->sb.user_uuid, - sizeof(c->sb.user_uuid)); -} - long bch_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg) { /* ioctls that don't require admin cap: */ @@ -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; diff --git a/libbcache/extents.c b/libbcache/extents.c index c1bf47b6..76b55f64 100644 --- a/libbcache/extents.c +++ b/libbcache/extents.c @@ -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))); diff --git a/libbcache/notify.c b/libbcache/notify.c index 1d5f626f..b06a8749 100644 --- a/libbcache/notify.c +++ b/libbcache/notify.c @@ -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; diff --git a/libbcache/super.c b/libbcache/super.c index bb4a7dc3..1e272af2 100644 --- a/libbcache/super.c +++ b/libbcache/super.c @@ -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; } diff --git a/libbcache/super.h b/libbcache/super.h index 7999b74e..79da390e 100644 --- a/libbcache/super.h +++ b/libbcache/super.h @@ -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 *); diff --git a/libbcache/sysfs.c b/libbcache/sysfs.c index c96ad336..3536ec0c 100644 --- a/libbcache/sysfs.c +++ b/libbcache/sysfs.c @@ -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);