mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-22 00:00:03 +03:00
Refactoring for device specific commands
This commit is contained in:
parent
3bf874183a
commit
d252e12acc
@ -1 +1 @@
|
|||||||
BCACHE_REVISION=5548432e689033ee93f0835b41571f8ec8b7bc48
|
BCACHE_REVISION=3ea79179e3101fb50de8730a809d00d189f05be5
|
||||||
|
153
bcache.c
153
bcache.c
@ -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;
|
||||||
}
|
}
|
||||||
|
268
cmd_device.c
268
cmd_device.c
@ -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;
|
||||||
}
|
}
|
||||||
|
12
cmd_format.c
12
cmd_format.c
@ -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
7
cmds.h
@ -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[]);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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)));
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 *);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user