Refactoring for device specific commands

This commit is contained in:
Kent Overstreet 2017-03-12 06:53:43 -08:00
parent 3bf874183a
commit d252e12acc
17 changed files with 599 additions and 402 deletions

View File

@ -1 +1 @@
BCACHE_REVISION=5548432e689033ee93f0835b41571f8ec8b7bc48 BCACHE_REVISION=3ea79179e3101fb50de8730a809d00d189f05be5

153
bcache.c
View File

@ -28,56 +28,113 @@ static void usage(void)
puts("bcache - tool for managing bcache volumes/filesystems\n" puts("bcache - tool for managing bcache volumes/filesystems\n"
"usage: bcache <command> [<args>]\n" "usage: bcache <command> [<args>]\n"
"\n" "\n"
"Commands for formatting, startup and shutdown:\n" "Superblock commands:\n"
" format Format a new filesystem\n" " format Format a new filesystem\n"
" unlock Unlock an encrypted filesystem prior to running/mounting\n" " show-super Dump superblock information to stdout\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"
"\n" "\n"
"Repair:\n" "Repair:\n"
" bcache fsck Check an existing filesystem for errors\n" " bcache fsck Check an existing filesystem for errors\n"
"\n" "\n"
"Debug:\n" "Startup/shutdown, assembly of multi device filesystems:\n"
" bcache dump Dump filesystem metadata to a qcow2 image\n" " unlock Unlock an encrypted filesystem prior to running/mounting\n"
" bcache list List filesystem metadata in textual form\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" "\n"
"Migrate:\n" "Migrate:\n"
" bcache migrate Migrate an existing filesystem to bcachefs, in place\n" " migrate Migrate an existing filesystem to bcachefs, in place\n"
" bcache migrate_superblock\n" " migrate-superblock\n"
" Add default superblock, after bcache migrate\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; if (*argc < 2) {
setvbuf(stdout, NULL, _IOLBF, 0);
if (argc < 2) {
printf("%s: missing command\n", argv[0]); printf("%s: missing command\n", argv[0]);
usage(); usage();
exit(EXIT_FAILURE); 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])); full_cmd = mprintf("%s %s", full_cmd, cmd);
argc--; 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")) if (!strcmp(cmd, "format"))
return cmd_format(argc, argv); 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")) if (!strcmp(cmd, "assemble"))
return cmd_assemble(argc, argv); return cmd_assemble(argc, argv);
if (!strcmp(cmd, "incremental")) if (!strcmp(cmd, "incremental"))
@ -87,36 +144,22 @@ int main(int argc, char *argv[])
if (!strcmp(cmd, "stop")) if (!strcmp(cmd, "stop"))
return cmd_stop(argc, argv); return cmd_stop(argc, argv);
if (!strcmp(cmd, "fs_show")) if (!strcmp(cmd, "fs"))
return cmd_fs_show(argc, argv); return fs_cmds(argc, argv);
if (!strcmp(cmd, "fs_set"))
return cmd_fs_set(argc, argv);
if (!strcmp(cmd, "device_show")) if (!strcmp(cmd, "device"))
return cmd_device_show(argc, argv); return device_cmds(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, "fsck")) if (!strcmp(cmd, "migrate"))
return cmd_fsck(argc, argv); return cmd_migrate(argc, argv);
if (!strcmp(cmd, "migrate-superblock"))
if (!strcmp(cmd, "unlock")) return cmd_migrate_superblock(argc, argv);
return cmd_unlock(argc, argv);
if (!strcmp(cmd, "dump")) if (!strcmp(cmd, "dump"))
return cmd_dump(argc, argv); return cmd_dump(argc, argv);
if (!strcmp(cmd, "list")) if (!strcmp(cmd, "list"))
return cmd_list(argc, argv); 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(); usage();
return 0; return 0;
} }

View File

@ -15,6 +15,7 @@
#include "cmds.h" #include "cmds.h"
#include "libbcache.h" #include "libbcache.h"
#include "linux/bcache-ioctl.h" #include "linux/bcache-ioctl.h"
#include "opts.h"
#include "tools-util.h" #include "tools-util.h"
/* This code belongs under show_fs */ /* This code belongs under show_fs */
@ -164,23 +165,17 @@ int cmd_device_show(int argc, char *argv[])
} }
#endif #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) xioctl(bcache_fs_open(fs).ioctl_fd, cmd, &i);
die("please supply a single device");
sb = bcache_super_read(argv[1]);
bcache_super_print(sb, HUMAN_READABLE);
return 0;
} }
static void device_add_usage(void) static void device_add_usage(void)
{ {
puts("bcache device_add - add a device to an existing filesystem\n" puts("bcache device add - add a device to an existing filesystem\n"
"Usage: bcache device_add [OPTION]... filesystem device\n" "Usage: bcache device add [OPTION]... filesystem device\n"
"\n" "\n"
"Options:\n" "Options:\n"
" --fs_size=size Size of filesystem on device\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>"); "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[]) 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 format_opts format_opts = format_opts_default();
struct dev_opts dev_opts = { 0 }; struct dev_opts dev_opts = { 0 };
bool force = false; bool force = false;
int opt; int opt;
while ((opt = getopt_long(argc, argv, "t:fh", while ((opt = getopt_long(argc, argv, "t:fh",
device_add_opts, NULL)) != -1) longopts, NULL)) != -1)
switch (opt) { switch (opt) {
case 'S': case 'S':
if (bch_strtoull_h(optarg, &dev_opts.size)) if (bch_strtoull_h(optarg, &dev_opts.size))
@ -256,78 +250,16 @@ int cmd_device_add(int argc, char *argv[])
fsync(dev_opts.fd); fsync(dev_opts.fd);
close(dev_opts.fd); close(dev_opts.fd);
struct bch_ioctl_disk_add ia = { struct bch_ioctl_disk i = { .dev = (__u64) dev_opts.path, };
.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 <linux-bcache@vger.kernel.org>");
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);
}
xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &i);
return 0; return 0;
} }
static void device_remove_usage(void) static void device_remove_usage(void)
{ {
puts("bcache device_remove - remove one or more devices from a filesystem\n" puts("bcache device_remove - remove a device from a filesystem\n"
"Usage: bcache device_remove filesystem [devices]\n" "Usage: bcache device remove filesystem device\n"
"\n" "\n"
"Options:\n" "Options:\n"
" -f, --force Force removal, even if some data\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' }, { "help", 0, NULL, 'h' },
{ NULL } { NULL }
}; };
int opt, force_data = 0, force_metadata = 0; int opt, flags = 0;
while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1) while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
switch (opt) { switch (opt) {
case 'f': case 'f':
force_data = 1; flags |= BCH_FORCE_IF_DATA_LOST;
break; break;
case 'F': case 'F':
force_metadata = 1; flags |= BCH_FORCE_IF_METADATA_LOST;
break; break;
case 'h': case 'h':
device_remove_usage(); device_remove_usage();
} }
if (argc - optind < 2) if (argc - optind != 2)
die("Please supply a filesystem and at least one device to remove"); 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 <linux-bcache@vger.kernel.org>");
}
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 <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_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]); struct bcache_handle fs = bcache_fs_open(argv[optind]);
for (unsigned i = optind + 1; i < argc; i++) { struct bch_ioctl_disk_set_state i = {
struct bch_ioctl_disk_remove ir = { .flags = flags,
.dev = (__u64) argv[i], .dev = (__u64) argv[optind + 1],
}; .new_state = read_string_list_or_die(argv[optind + 2],
bch_dev_state, "device state"),
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);
}
xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &i);
return 0; return 0;
} }

View File

@ -268,3 +268,15 @@ int cmd_format(int argc, char *argv[])
return 0; 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;
}

7
cmds.h
View File

@ -10,6 +10,7 @@
#include "tools-util.h" #include "tools-util.h"
int cmd_format(int argc, char *argv[]); int cmd_format(int argc, char *argv[]);
int cmd_show_super(int argc, char *argv[]);
int cmd_unlock(int argc, char *argv[]); int cmd_unlock(int argc, char *argv[]);
int cmd_assemble(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_show(int argc, char *argv[]);
int cmd_fs_set(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_add(int argc, char *argv[]);
int cmd_device_fail(int argc, char *argv[]);
int cmd_device_remove(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[]); int cmd_fsck(int argc, char *argv[]);

View File

@ -8,8 +8,6 @@
extern "C" { extern "C" {
#endif #endif
/* global control dev: */
#define BCH_FORCE_IF_DATA_LOST (1 << 0) #define BCH_FORCE_IF_DATA_LOST (1 << 0)
#define BCH_FORCE_IF_METADATA_LOST (1 << 1) #define BCH_FORCE_IF_METADATA_LOST (1 << 1)
#define BCH_FORCE_IF_DATA_DEGRADED (1 << 2) #define BCH_FORCE_IF_DATA_DEGRADED (1 << 2)
@ -19,24 +17,12 @@ extern "C" {
(BCH_FORCE_IF_DATA_DEGRADED| \ (BCH_FORCE_IF_DATA_DEGRADED| \
BCH_FORCE_IF_METADATA_DEGRADED) BCH_FORCE_IF_METADATA_DEGRADED)
#define BCH_IOCTL_ASSEMBLE _IOW('r', 1, struct bch_ioctl_assemble) #define BCH_BY_UUID (1 << 4)
#define BCH_IOCTL_INCREMENTAL _IOW('r', 1, struct bch_ioctl_incremental)
/* cache set control dev: */ /* global control dev: */
#define BCH_IOCTL_RUN _IO('r', 2) #define BCH_IOCTL_ASSEMBLE _IOW(0xbc, 1, struct bch_ioctl_assemble)
#define BCH_IOCTL_STOP _IO('r', 3) #define BCH_IOCTL_INCREMENTAL _IOW(0xbc, 2, struct bch_ioctl_incremental)
#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)
struct bch_ioctl_assemble { struct bch_ioctl_assemble {
__u32 flags; __u32 flags;
@ -51,13 +37,29 @@ struct bch_ioctl_incremental {
__u64 dev; __u64 dev;
}; };
struct bch_ioctl_disk_add { /* filesystem ioctls: */
__u32 flags;
__u32 pad; #define BCH_IOCTL_QUERY_UUID _IOR(0xbc, 1, struct bch_ioctl_query_uuid)
__u64 dev; #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 flags;
__u32 pad; __u32 pad;
__u64 dev; __u64 dev;
@ -70,20 +72,21 @@ struct bch_ioctl_disk_set_state {
__u64 dev; __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 flags;
__u32 pad; __u32 pad;
uuid_le dev;
};
struct bch_ioctl_disk_fail_by_uuid { __u64 start_inode;
__u32 flags; __u64 start_offset;
__u32 pad;
uuid_le dev;
};
struct bch_ioctl_query_uuid { __u64 end_inode;
uuid_le uuid; __u64 end_offset;
}; };
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -154,11 +154,10 @@ static void pd_controllers_update(struct work_struct *work)
s64 fragmented = ((stats.buckets_dirty + s64 fragmented = ((stats.buckets_dirty +
stats.buckets_cached) << stats.buckets_cached) <<
bucket_bits) - bucket_bits) -
((stats.sectors_dirty + ((stats.sectors[S_DIRTY] +
stats.sectors_cached) << 9); stats.sectors[S_CACHED] ) << 9);
if (fragmented < 0) fragmented = max(0LL, fragmented);
fragmented = 0;
bch_pd_controller_update(&ca->moving_gc_pd, bch_pd_controller_update(&ca->moving_gc_pd,
free, fragmented, -1); free, fragmented, -1);

View 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, bch_btree_node_free_index(c, NULL, old->btree_id,
bkey_i_to_s_c(&old->key), bkey_i_to_s_c(&old->key),
&stats); &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)); 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), bkey_disassemble(b, k, &tmp),
&stats); &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); bch_btree_bset_insert_key(iter, b, node_iter, insert);
set_btree_node_dirty(b); set_btree_node_dirty(b);

View File

@ -204,7 +204,21 @@ static inline int is_cached_bucket(struct bucket_mark m)
!m.dirty_sectors && !!m.cached_sectors; !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 bch_fs_usage *stats,
struct disk_reservation *disk_res, struct disk_reservation *disk_res,
struct gc_pos gc_pos) struct gc_pos gc_pos)
@ -241,62 +255,43 @@ void bch_fs_stats_apply(struct bch_fs *c,
memset(stats, 0, sizeof(*stats)); memset(stats, 0, sizeof(*stats));
} }
static bool bucket_became_unavailable(struct bch_fs *c, static void bch_fs_usage_update(struct bch_fs_usage *fs_usage,
struct bucket_mark old, struct bucket_mark old, struct bucket_mark new)
struct bucket_mark new)
{ {
return is_available_bucket(old) && fs_usage->s[S_COMPRESSED][S_CACHED] +=
!is_available_bucket(new) && (int) new.cached_sectors - (int) old.cached_sectors;
c && c->gc_pos.phase == GC_PHASE_DONE; 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, static void bch_dev_usage_update(struct bch_dev *ca,
struct bucket_mark old, struct bucket_mark new, struct bucket_mark old, struct bucket_mark new)
struct bch_fs_usage *bch_alloc_stats)
{ {
struct bch_fs *c = ca->fs; 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 && bch_fs_inconsistent_on(old.data_type && new.data_type &&
old.data_type != new.data_type, c, old.data_type != new.data_type, c,
"different types of metadata in same bucket: %u, %u", "different types of metadata in same bucket: %u, %u",
old.data_type, new.data_type); 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(); 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; (int) new.cached_sectors - (int) old.cached_sectors;
if (is_meta_bucket(old)) dev_usage->sectors[bucket_type(old)] -= old.dirty_sectors;
cache_stats->sectors_meta -= old.dirty_sectors; dev_usage->sectors[bucket_type(new)] += new.dirty_sectors;
else
cache_stats->sectors_dirty -= old.dirty_sectors;
if (is_meta_bucket(new)) dev_usage->buckets_alloc +=
cache_stats->sectors_meta += new.dirty_sectors;
else
cache_stats->sectors_dirty += new.dirty_sectors;
cache_stats->buckets_alloc +=
(int) new.owned_by_allocator - (int) old.owned_by_allocator; (int) new.owned_by_allocator - (int) old.owned_by_allocator;
cache_stats->buckets_meta += is_meta_bucket(new) - is_meta_bucket(old); dev_usage->buckets_meta += is_meta_bucket(new) - is_meta_bucket(old);
cache_stats->buckets_cached += is_cached_bucket(new) - is_cached_bucket(old); dev_usage->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_dirty += is_dirty_bucket(new) - is_dirty_bucket(old);
preempt_enable(); preempt_enable();
if (!is_available_bucket(old) && is_available_bucket(new)) 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) \ #define bucket_data_cmpxchg(ca, g, new, expr) \
({ \ ({ \
struct bch_fs_usage _stats = { 0 }; \
struct bucket_mark _old = bucket_cmpxchg(g, new, expr); \ struct bucket_mark _old = bucket_cmpxchg(g, new, expr); \
\ \
bch_usage_update(ca, _old, new, &_stats); \ bch_dev_usage_update(ca, _old, new); \
_old; \ _old; \
}) })
@ -317,7 +311,7 @@ void bch_invalidate_bucket(struct bch_dev *ca, struct bucket *g)
struct bch_fs_usage stats = { 0 }; struct bch_fs_usage stats = { 0 };
struct bucket_mark old, new; struct bucket_mark old, new;
old = bucket_cmpxchg(g, new, ({ old = bucket_data_cmpxchg(ca, g, new, ({
new.owned_by_allocator = 1; new.owned_by_allocator = 1;
new.had_metadata = 0; new.had_metadata = 0;
new.data_type = 0; new.data_type = 0;
@ -327,23 +321,8 @@ void bch_invalidate_bucket(struct bch_dev *ca, struct bucket *g)
new.gen++; new.gen++;
})); }));
bch_usage_update(ca, old, new, &stats); /* XXX: we're not actually updating fs usage's cached sectors... */
bch_fs_usage_update(&stats, old, new);
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)));
if (!old.owned_by_allocator && old.cached_sectors) if (!old.owned_by_allocator && old.cached_sectors)
trace_bcache_invalidate(ca, g - ca->buckets, trace_bcache_invalidate(ca, g - ca->buckets,
@ -452,7 +431,6 @@ static void bch_mark_pointer(struct bch_fs *c,
unsigned saturated; unsigned saturated;
struct bch_dev *ca = c->devs[ptr->dev]; struct bch_dev *ca = c->devs[ptr->dev];
struct bucket *g = ca->buckets + PTR_BUCKET_NR(ca, ptr); struct bucket *g = ca->buckets + PTR_BUCKET_NR(ca, ptr);
u64 v;
unsigned old_sectors, new_sectors; unsigned old_sectors, new_sectors;
int disk_sectors, compressed_sectors; int disk_sectors, compressed_sectors;
@ -476,9 +454,7 @@ static void bch_mark_pointer(struct bch_fs *c,
goto out; goto out;
} }
v = READ_ONCE(g->_mark.counter); old = bucket_data_cmpxchg(ca, g, new, ({
do {
new.counter = old.counter = v;
saturated = 0; saturated = 0;
/* /*
@ -523,11 +499,7 @@ static void bch_mark_pointer(struct bch_fs *c,
} }
new.had_metadata |= is_meta_bucket(new); 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 && BUG_ON(!may_make_unavailable &&
bucket_became_unavailable(c, old, new)); bucket_became_unavailable(c, old, new));

View 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 *);
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); struct disk_reservation *, struct gc_pos);
static inline u64 __bch_fs_sectors_used(struct bch_fs *c) static inline u64 __bch_fs_sectors_used(struct bch_fs *c)

View File

@ -65,15 +65,10 @@ struct bucket {
}; };
}; };
struct bch_dev_usage { enum s_compressed {
u64 buckets_dirty; S_COMPRESSED,
u64 buckets_cached; S_UNCOMPRESSED,
u64 buckets_meta; S_COMPRESSED_NR,
u64 buckets_alloc;
u64 sectors_dirty;
u64 sectors_cached;
u64 sectors_meta;
}; };
enum s_alloc { enum s_alloc {
@ -83,10 +78,13 @@ enum s_alloc {
S_ALLOC_NR, S_ALLOC_NR,
}; };
enum s_compressed { struct bch_dev_usage {
S_COMPRESSED, u64 buckets_dirty;
S_UNCOMPRESSED, u64 buckets_cached;
S_COMPRESSED_NR, u64 buckets_meta;
u64 buckets_alloc;
u64 sectors[S_ALLOC_NR];
}; };
struct bch_fs_usage { struct bch_fs_usage {

View 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))) if (copy_from_user(&arg, user_arg, sizeof(arg)))
return -EFAULT; return -EFAULT;
if (arg.flags || arg.pad)
return -EINVAL;
user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL); user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL);
if (!devs) if (!devs)
return -ENOMEM; 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))) if (copy_from_user(&arg, user_arg, sizeof(arg)))
return -EFAULT; return -EFAULT;
if (arg.flags || arg.pad)
return -EINVAL;
path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX); path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
if (!path) if (!path)
return -ENOMEM; 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 copy_to_user(&user_arg->uuid,
return 0; &c->sb.user_uuid,
sizeof(c->sb.user_uuid));
} }
static long bch_ioctl_disk_add(struct bch_fs *c, static long bch_ioctl_start(struct bch_fs *c, struct bch_ioctl_start __user *user_arg)
struct bch_ioctl_disk_add __user *user_arg)
{ {
struct bch_ioctl_disk_add arg; struct bch_ioctl_start arg;
char *path;
int ret;
if (copy_from_user(&arg, user_arg, sizeof(arg))) if (copy_from_user(&arg, user_arg, sizeof(arg)))
return -EFAULT; return -EFAULT;
path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX); if (arg.flags || arg.pad)
if (!path) return -EINVAL;
return -ENOMEM;
ret = bch_dev_add(c, path); return bch_fs_start(c) ? -EIO : 0;
kfree(path); }
return ret; static long bch_ioctl_stop(struct bch_fs *c)
{
bch_fs_stop(c);
return 0;
} }
/* returns with ref on ca->ref */ /* returns with ref on ca->ref */
@ -150,10 +157,49 @@ found:
return ca; return ca;
} }
static long bch_ioctl_disk_remove(struct bch_fs *c, #if 0
struct bch_ioctl_disk_remove __user *user_arg) 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; struct bch_dev *ca;
int ret; int ret;
@ -166,6 +212,51 @@ static long bch_ioctl_disk_remove(struct bch_fs *c,
ret = bch_dev_remove(c, ca, arg.flags); 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; return ret;
} }
@ -189,71 +280,26 @@ static long bch_ioctl_disk_set_state(struct bch_fs *c,
return ret; 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); struct bch_ioctl_disk arg;
unsigned i; struct bch_dev *ca;
int ret;
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;
if (copy_from_user(&arg, user_arg, sizeof(arg))) if (copy_from_user(&arg, user_arg, sizeof(arg)))
return -EFAULT; return -EFAULT;
mutex_lock(&c->sb_lock); ca = bch_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
if ((m = bch_uuid_lookup(c, arg.dev))) { if (IS_ERR(ca))
/* XXX: */ return PTR_ERR(ca);
SET_BCH_MEMBER_STATE(m, BCH_MEMBER_STATE_FAILED);
bch_write_super(c);
ret = 0;
}
mutex_unlock(&c->sb_lock);
ret = bch_dev_migrate(c, ca);
percpu_ref_put(&ca->ref);
return ret; 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) long bch_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
{ {
/* ioctls that don't require admin cap: */ /* 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: */ /* ioctls that do require admin cap: */
switch (cmd) { switch (cmd) {
case BCH_IOCTL_RUN: case BCH_IOCTL_START:
return -ENOTTY; return bch_ioctl_start(c, arg);
case BCH_IOCTL_STOP: case BCH_IOCTL_STOP:
return bch_ioctl_stop(c); 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); return bch_ioctl_disk_add(c, arg);
case BCH_IOCTL_DISK_REMOVE: case BCH_IOCTL_DISK_REMOVE:
return bch_ioctl_disk_remove(c, arg); 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: case BCH_IOCTL_DISK_SET_STATE:
return bch_ioctl_disk_set_state(c, arg); return bch_ioctl_disk_set_state(c, arg);
case BCH_IOCTL_DISK_EVACUATE:
case BCH_IOCTL_DISK_REMOVE_BY_UUID: return bch_ioctl_disk_evacuate(c, arg);
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);
default: default:
return -ENOTTY; return -ENOTTY;

View File

@ -931,7 +931,7 @@ struct extent_insert_state {
struct btree_insert *trans; struct btree_insert *trans;
struct btree_insert_entry *insert; struct btree_insert_entry *insert;
struct bpos committed; struct bpos committed;
struct bch_fs_usage stats; struct bch_fs_usage stats;
/* for deleting: */ /* for deleting: */
struct bkey_i whiteout; struct bkey_i whiteout;
@ -1554,7 +1554,7 @@ next:
stop: stop:
extent_insert_committed(s); 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)); gc_pos_btree_node(b));
EBUG_ON(bkey_cmp(iter->pos, s->committed)); EBUG_ON(bkey_cmp(iter->pos, s->committed));
@ -1716,7 +1716,7 @@ stop:
bkey_start_offset(&insert->k->k), bkey_start_offset(&insert->k->k),
insert->k->k.size); 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)); gc_pos_btree_node(b));
EBUG_ON(bkey_cmp(iter->pos, bkey_start_pos(&insert->k->k))); EBUG_ON(bkey_cmp(iter->pos, bkey_start_pos(&insert->k->k)));

View File

@ -94,33 +94,6 @@ void bch_notify_dev_added(struct bch_dev *ca)
notify_put(c); 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) void bch_notify_dev_error(struct bch_dev *ca, bool fatal)
{ {
struct bch_fs *c = ca->fs; struct bch_fs *c = ca->fs;

View File

@ -1069,7 +1069,7 @@ static void bch_dev_io_ref_release(struct percpu_ref *ref)
complete(&ca->offline_complete); 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; struct bch_fs *c = ca->fs;
@ -1244,7 +1244,7 @@ err:
return -ENOMEM; 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; struct bch_dev *ca;
int ret; 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_journal_meta(&c->journal);
bch_dev_offline(ca); __bch_dev_offline(ca);
bch_dev_stop(ca); bch_dev_stop(ca);
bch_dev_free(ca); bch_dev_free(ca);
@ -1644,7 +1644,7 @@ have_slot:
goto err_unlock; goto err_unlock;
} }
if (bch_dev_online(c, &sb)) { if (__bch_dev_online(c, &sb)) {
err = "bch_dev_online() error"; err = "bch_dev_online() error";
ret = -ENOMEM; ret = -ENOMEM;
goto err_unlock; goto err_unlock;
@ -1677,6 +1677,88 @@ err:
return ret ?: -EINVAL; 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: */ /* Filesystem open: */
const char *bch_fs_open(char * const *devices, unsigned nr_devices, 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"; err = "bch_dev_online() error";
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
for (i = 0; i < nr_devices; i++) 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); mutex_unlock(&c->sb_lock);
goto err; goto err;
} }
@ -1803,7 +1885,7 @@ static const char *__bch_fs_open_incremental(struct bcache_superblock *sb,
err = "bch_dev_online() error"; err = "bch_dev_online() error";
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
if (bch_dev_online(c, sb)) { if (__bch_dev_online(c, sb)) {
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
goto err; goto err;
} }

View 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_fail(struct bch_dev *, int);
int bch_dev_remove(struct bch_fs *, 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_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 *); void bch_fs_detach(struct bch_fs *);

View File

@ -1174,11 +1174,11 @@ SHOW(bch_dev)
sysfs_print(io_errors, sysfs_print(io_errors,
atomic_read(&ca->io_errors) >> IO_ERROR_SHIFT); atomic_read(&ca->io_errors) >> IO_ERROR_SHIFT);
sysfs_hprint(dirty_data, stats.sectors_dirty << 9); sysfs_hprint(dirty_data, stats.sectors[S_DIRTY] << 9);
sysfs_print(dirty_bytes, stats.sectors_dirty << 9); sysfs_print(dirty_bytes, stats.sectors[S_DIRTY] << 9);
sysfs_print(dirty_buckets, stats.buckets_dirty); sysfs_print(dirty_buckets, stats.buckets_dirty);
sysfs_hprint(cached_data, stats.sectors_cached << 9); sysfs_hprint(cached_data, stats.sectors[S_CACHED] << 9);
sysfs_print(cached_bytes, stats.sectors_cached << 9); sysfs_print(cached_bytes, stats.sectors[S_CACHED] << 9);
sysfs_print(cached_buckets, stats.buckets_cached); sysfs_print(cached_buckets, stats.buckets_cached);
sysfs_print(meta_buckets, stats.buckets_meta); sysfs_print(meta_buckets, stats.buckets_meta);
sysfs_print(alloc_buckets, stats.buckets_alloc); sysfs_print(alloc_buckets, stats.buckets_alloc);