This commit is contained in:
Kent Overstreet 2017-12-28 01:01:16 -05:00
parent 9d2dfea54b
commit aca9f96dcc
10 changed files with 332 additions and 106 deletions

View File

@ -51,6 +51,7 @@ static void usage(void)
" device offline Take a device offline, without removing it\n"
" device evacuate Migrate data off of a specific device\n"
" device set-state Mark a device as failed\n"
" device resize Resize filesystem on a device\n"
"\n"
"Encryption:\n"
" unlock Unlock an encrypted filesystem prior to running/mounting\n"
@ -112,6 +113,8 @@ static int device_cmds(int argc, char *argv[])
return cmd_device_offline(argc, argv);
if (!strcmp(cmd, "set-state"))
return cmd_device_set_state(argc, argv);
if (!strcmp(cmd, "resize"))
return cmd_device_resize(argc, argv);
usage();
return 0;

View File

@ -9,6 +9,7 @@
#include "libbcachefs/bcachefs_ioctl.h"
#include "cmds.h"
#include "libbcachefs.h"
int cmd_assemble(int argc, char *argv[])
{

View File

@ -13,6 +13,7 @@
#include <unistd.h>
#include "libbcachefs/bcachefs_ioctl.h"
#include "libbcachefs/super-io.h"
#include "cmds.h"
#include "libbcachefs.h"
#include "libbcachefs/opts.h"
@ -99,7 +100,7 @@ int cmd_device_show(int argc, char *argv[])
if (argc != 2)
die("Please supply a single device");
struct bcache_handle fs = bcache_fs_open(argv[1]);
struct bchfs_handle fs = bcache_fs_open(argv[1]);
struct dirent *entry;
struct bcache_dev devices[256];
@ -240,7 +241,7 @@ int cmd_device_add(int argc, char *argv[])
if (argc - optind != 2)
die("Please supply a filesystem and a device to add");
struct bcache_handle fs = bcache_fs_open(argv[optind]);
struct bchfs_handle fs = bcache_fs_open(argv[optind]);
dev_opts.path = argv[optind + 1];
dev_opts.fd = open_for_format(dev_opts.path, force);
@ -255,9 +256,7 @@ int cmd_device_add(int argc, char *argv[])
fsync(dev_opts.fd);
close(dev_opts.fd);
struct bch_ioctl_disk i = { .dev = (__u64) dev_opts.path, };
xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &i);
bchu_disk_add(fs, dev_opts.path);
return 0;
}
@ -436,20 +435,113 @@ int cmd_device_set_state(int argc, char *argv[])
if (argc - optind != 3)
die("Please supply a filesystem, device and state");
struct bcache_handle fs = bcache_fs_open(argv[optind]);
struct bchfs_handle fs = bcache_fs_open(argv[optind]);
struct bch_ioctl_disk_set_state i = {
.flags = flags,
.new_state = read_string_list_or_die(argv[optind + 2],
bch2_dev_state, "device state"),
};
const char *dev = argv[optind + 1];
if (!kstrtoull(dev, 10, &i.dev))
i.flags |= BCH_BY_INDEX;
else
i.dev = (u64) dev;
xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &i);
bchu_disk_set_state(fs, argv[optind + 1],
read_string_list_or_die(argv[optind + 2],
bch2_dev_state, "device state"),
flags);
return 0;
}
static void device_resize_usage(void)
{
puts("bcachefs device resize \n"
"Usage: bcachefs device resize device [ size ]\n"
"\n"
"Options:\n"
" -h, --help display this help and exit\n"
"Report bugs to <linux-bcache@vger.kernel.org>");
exit(EXIT_SUCCESS);
}
int cmd_device_resize(int argc, char *argv[])
{
static const struct option longopts[] = {
{ "help", 0, NULL, 'h' },
{ NULL }
};
u64 size;
int opt;
while ((opt = getopt_long(argc, argv, "h", longopts, NULL)) != -1)
switch (opt) {
case 'h':
device_resize_usage();
}
if (argc < optind + 1)
die("Please supply a device to resize");
char *dev = argv[optind];
int dev_fd = xopen(dev, O_RDONLY);
if (argc == optind + 1)
size = get_size(dev, dev_fd);
else if (bch2_strtoull_h(argv[optind + 1], &size))
die("invalid size");
size >>= 9;
if (argc > optind + 2)
die("Too many arguments");
struct stat dev_stat = xfstat(dev_fd);
char *mount = dev_to_mount(dev);
if (mount) {
if (!S_ISBLK(dev_stat.st_mode))
die("%s is mounted but isn't a block device?!", dev);
printf("Doing online resize of %s\n", dev);
struct bchfs_handle fs = bcache_fs_open(mount);
unsigned idx = bchu_disk_get_idx(fs, dev_stat.st_rdev);
struct bch_sb *sb = bchu_read_super(fs, -1);
if (idx >= sb->nr_devices)
die("error reading superblock: dev idx >= sb->nr_devices");
struct bch_sb_field_members *mi = bch2_sb_get_members(sb);
if (!mi)
die("error reading superblock: no member info");
/* could also just read this out of sysfs... meh */
struct bch_member *m = mi->members + idx;
u64 nbuckets = size / le16_to_cpu(m->bucket_size);
printf("resizing %s to %llu buckets\n", dev, nbuckets);
bchu_disk_resize(fs, idx, nbuckets);
} else {
printf("Doing offline resize of %s\n", dev);
struct bch_fs *c = NULL;
struct bch_opts opts = bch2_opts_empty();
const char *err = bch2_fs_open(&dev, 1, opts, &c);
if (err)
die("error opening %s: %s", argv[optind], err);
struct bch_dev *ca, *resize = NULL;
unsigned i;
for_each_online_member(ca, c, i) {
if (resize)
die("confused: more than one online device?");
resize = ca;
percpu_ref_get(&resize->io_ref);
}
u64 nbuckets = size / le16_to_cpu(resize->mi.bucket_size);
printf("resizing %s to %llu buckets\n", dev, nbuckets);
int ret = bch2_dev_resize(c, resize, nbuckets);
if (ret)
fprintf(stderr, "resize error: %s\n", strerror(-ret));
percpu_ref_put(&resize->io_ref);
bch2_fs_stop(c);
}
return 0;
}

View File

@ -8,6 +8,7 @@
#include "libbcachefs/opts.h"
#include "cmds.h"
#include "libbcachefs.h"
static inline int printf_pad(unsigned pad, const char * fmt, ...)
{
@ -26,21 +27,11 @@ static inline int printf_pad(unsigned pad, const char * fmt, ...)
static void print_fs_usage(const char *path, enum units units)
{
unsigned i, j, nr_devices = 4;
struct bcache_handle fs = bcache_fs_open(path);
struct bch_ioctl_usage *u = NULL;
unsigned i, j;
char uuid[40];
while (1) {
u = xrealloc(u, sizeof(*u) + sizeof(u->devs[0]) * nr_devices);
u->nr_devices = nr_devices;
if (!ioctl(fs.ioctl_fd, BCH_IOCTL_USAGE, u))
break;
if (errno != ENOSPC)
die("BCH_IOCTL_USAGE error: %m");
nr_devices *= 2;
}
struct bchfs_handle fs = bcache_fs_open(path);
struct bch_ioctl_usage *u = bchu_usage(fs);
uuid_unparse(fs.uuid.b, uuid);
printf("Filesystem %s:\n", uuid);

View File

@ -13,6 +13,7 @@
#include "libbcachefs/bcachefs_ioctl.h"
#include "cmds.h"
#include "libbcachefs.h"
int cmd_run(int argc, char *argv[])
{
@ -24,7 +25,7 @@ int cmd_stop(int argc, char *argv[])
if (argc != 2)
die("Please supply a filesystem");
struct bcache_handle fs = bcache_fs_open(argv[1]);
struct bchfs_handle fs = bcache_fs_open(argv[1]);
xioctl(fs.ioctl_fd, BCH_IOCTL_STOP);
return 0;
}

1
cmds.h
View File

@ -25,6 +25,7 @@ int cmd_device_online(int argc, char *argv[]);
int cmd_device_offline(int argc, char *argv[]);
int cmd_device_evacuate(int argc, char *argv[]);
int cmd_device_set_state(int argc, char *argv[]);
int cmd_device_resize(int argc, char *argv[]);
int cmd_unlock(int argc, char *argv[]);
int cmd_set_passphrase(int argc, char *argv[]);

View File

@ -455,3 +455,57 @@ void bch2_super_print(struct bch_sb *sb, int units)
BCH_MEMBER_DISCARD(m));
}
}
/* ioctl interface: */
/* Global control device: */
int bcachectl_open(void)
{
return xopen("/dev/bcachefs-ctl", O_RDWR);
}
/* Filesystem handles (ioctl, sysfs dir): */
#define SYSFS_BASE "/sys/fs/bcachefs/"
void bcache_fs_close(struct bchfs_handle fs)
{
close(fs.ioctl_fd);
close(fs.sysfs_fd);
}
struct bchfs_handle bcache_fs_open(const char *path)
{
struct bchfs_handle ret;
if (!uuid_parse(path, ret.uuid.b)) {
/* It's a UUID, look it up in sysfs: */
char *sysfs = mprintf("%s%s", SYSFS_BASE, path);
ret.sysfs_fd = xopen(sysfs, O_RDONLY);
char *minor = read_file_str(ret.sysfs_fd, "minor");
char *ctl = mprintf("/dev/bcachefs%s-ctl", minor);
ret.ioctl_fd = xopen(ctl, O_RDWR);
free(sysfs);
free(minor);
free(ctl);
} else {
/* It's a path: */
ret.ioctl_fd = xopen(path, O_RDONLY);
struct bch_ioctl_query_uuid uuid;
xioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid);
ret.uuid = uuid.uuid;
char uuid_str[40];
uuid_unparse(uuid.uuid.b, uuid_str);
char *sysfs = mprintf("%s%s", SYSFS_BASE, uuid_str);
ret.sysfs_fd = xopen(sysfs, O_RDONLY);
free(sysfs);
}
return ret;
}

View File

@ -5,6 +5,7 @@
#include <stdbool.h>
#include "libbcachefs/bcachefs_format.h"
#include "libbcachefs/bcachefs_ioctl.h"
#include "tools-util.h"
#include "libbcachefs/vstructs.h"
@ -76,4 +77,103 @@ struct bch_sb *__bch2_super_read(int, u64);
void bch2_super_print(struct bch_sb *, int);
/* ioctl interface: */
int bcachectl_open(void);
struct bchfs_handle {
uuid_le uuid;
int ioctl_fd;
int sysfs_fd;
};
void bcache_fs_close(struct bchfs_handle);
struct bchfs_handle bcache_fs_open(const char *);
static inline void bchu_disk_add(struct bchfs_handle fs, char *dev)
{
struct bch_ioctl_disk i = { .dev = (__u64) dev, };
xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_ADD, &i);
}
static inline void bchu_disk_set_state(struct bchfs_handle fs, const char *dev,
unsigned new_state, unsigned flags)
{
struct bch_ioctl_disk_set_state i = {
.flags = flags,
.new_state = new_state,
};
if (!kstrtoull(dev, 10, &i.dev))
i.flags |= BCH_BY_INDEX;
else
i.dev = (u64) dev;
xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_SET_STATE, &i);
}
static inline struct bch_ioctl_usage *bchu_usage(struct bchfs_handle fs)
{
struct bch_ioctl_usage *u = NULL;
unsigned nr_devices = 4;
while (1) {
u = xrealloc(u, sizeof(*u) + sizeof(u->devs[0]) * nr_devices);
u->nr_devices = nr_devices;
if (!ioctl(fs.ioctl_fd, BCH_IOCTL_USAGE, u))
return u;
if (errno != ENOSPC)
die("BCH_IOCTL_USAGE error: %m");
nr_devices *= 2;
}
}
static inline struct bch_sb *bchu_read_super(struct bchfs_handle fs, unsigned idx)
{
size_t size = 4096;
struct bch_sb *sb = NULL;
while (1) {
sb = xrealloc(sb, size);
struct bch_ioctl_read_super i = {
.size = size,
.sb = (u64) sb,
};
if (idx != -1) {
i.flags |= BCH_READ_DEV|BCH_BY_INDEX;
i.dev = idx;
}
if (!ioctl(fs.ioctl_fd, BCH_IOCTL_READ_SUPER, &i))
return sb;
if (errno != ERANGE)
die("BCH_IOCTL_READ_SUPER error: %m");
size *= 2;
}
}
static inline unsigned bchu_disk_get_idx(struct bchfs_handle fs, dev_t dev)
{
struct bch_ioctl_disk_get_idx i = { .dev = dev };
return xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_GET_IDX, &i);
}
static inline void bchu_disk_resize(struct bchfs_handle fs,
unsigned idx,
u64 nbuckets)
{
struct bch_ioctl_disk_resize i = {
.flags = BCH_BY_INDEX,
.dev = idx,
.nbuckets = nbuckets,
};
xioctl(fs.ioctl_fd, BCH_IOCTL_DISK_RESIZE, &i);
}
#endif /* _LIBBCACHE_H */

View File

@ -262,58 +262,6 @@ int open_for_format(const char *dev, bool force)
return fd;
}
/* Global control device: */
int bcachectl_open(void)
{
return xopen("/dev/bcachefs-ctl", O_RDWR);
}
/* Filesystem handles (ioctl, sysfs dir): */
#define SYSFS_BASE "/sys/fs/bcachefs/"
void bcache_fs_close(struct bcache_handle fs)
{
close(fs.ioctl_fd);
close(fs.sysfs_fd);
}
struct bcache_handle bcache_fs_open(const char *path)
{
struct bcache_handle ret;
if (!uuid_parse(path, ret.uuid.b)) {
/* It's a UUID, look it up in sysfs: */
char *sysfs = mprintf("%s%s", SYSFS_BASE, path);
ret.sysfs_fd = xopen(sysfs, O_RDONLY);
char *minor = read_file_str(ret.sysfs_fd, "minor");
char *ctl = mprintf("/dev/bcachefs%s-ctl", minor);
ret.ioctl_fd = xopen(ctl, O_RDWR);
free(sysfs);
free(minor);
free(ctl);
} else {
/* It's a path: */
ret.ioctl_fd = xopen(path, O_RDONLY);
struct bch_ioctl_query_uuid uuid;
xioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid);
ret.uuid = uuid.uuid;
char uuid_str[40];
uuid_unparse(uuid.uuid.b, uuid_str);
char *sysfs = mprintf("%s%s", SYSFS_BASE, uuid_str);
ret.sysfs_fd = xopen(sysfs, O_RDONLY);
free(sysfs);
}
return ret;
}
bool ask_yn(void)
{
const char *short_yes = "yY";
@ -586,9 +534,9 @@ u32 crc32c(u32 crc, const void *buf, size_t size)
#endif /* HAVE_WORKING_IFUNC */
char *dev_to_path(dev_t dev)
char *dev_to_name(dev_t dev)
{
char *line = NULL, *name = NULL, *path = NULL;
char *line = NULL, *name = NULL;
size_t n = 0;
FILE *f = fopen("/proc/partitions", "r");
@ -602,17 +550,58 @@ char *dev_to_path(dev_t dev)
name = realloc(name, n + 1);
if (sscanf(line, " %u %u %llu %s", &ma, &mi, &sectors, name) == 4 &&
ma == major(dev) && mi == minor(dev)) {
path = mprintf("/dev/%s", name);
break;
}
ma == major(dev) && mi == minor(dev))
goto found;
}
free(name);
name = NULL;
found:
fclose(f);
free(line);
return name;
}
char *dev_to_path(dev_t dev)
{
char *name = dev_to_name(dev);
if (!name)
return NULL;
char *path = mprintf("/dev/%s", name);
free(name);
return path;
}
char *dev_to_mount(char *dev)
{
char *line = NULL, *ret = NULL;
size_t n = 0;
FILE *f = fopen("/proc/mounts", "r");
if (!f)
die("error opening /proc/mounts: %m");
while (getline(&line, &n, f) != -1) {
char *d, *p = line;
char *devs = strsep(&p, " ");
char *mount = strsep(&p, " ");
if (!devs || !mount)
continue;
p = devs;
while ((d = strsep(&p, ":")))
if (!strcmp(d, dev)) {
ret = strdup(mount);
goto found;
}
}
found:
fclose(f);
free(line);
return ret;
}
#endif

View File

@ -5,6 +5,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@ -39,10 +40,12 @@ struct stat xfstat(int);
#define xopen(...) xopenat(AT_FDCWD, __VA_ARGS__)
#define xioctl(_fd, _nr, ...) \
do { \
if (ioctl((_fd), (_nr), ##__VA_ARGS__)) \
({ \
int _ret = ioctl((_fd), (_nr), ##__VA_ARGS__); \
if (_ret < 0) \
die(#_nr " ioctl error: %m"); \
} while (0)
_ret; \
})
enum units {
BYTES,
@ -68,17 +71,6 @@ u64 get_size(const char *, int);
unsigned get_blocksize(const char *, int);
int open_for_format(const char *, bool);
int bcachectl_open(void);
struct bcache_handle {
uuid_le uuid;
int ioctl_fd;
int sysfs_fd;
};
void bcache_fs_close(struct bcache_handle);
struct bcache_handle bcache_fs_open(const char *);
bool ask_yn(void);
struct range {
@ -155,6 +147,8 @@ unsigned hatoi_validate(const char *, const char *);
u32 crc32c(u32, const void *, size_t);
char *dev_to_name(dev_t);
char *dev_to_path(dev_t);
char *dev_to_mount(char *);
#endif /* _TOOLS_UTIL_H */