mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-23 00:00:02 +03:00
bcacheadm tool
bcacheadm is a combination of make-bcache, probe-bcache, bcache-super-show, and bcachectl(register). Change-Id: Ia4f4cdd5f882516358eb0e26a75296d2103af1d0 Signed-off-by: Jacob Malevich <jam@daterainc.com>
This commit is contained in:
parent
0fca0e5502
commit
82ac2a0338
@ -9,7 +9,8 @@ AM_LDFLAGS=`pkg-config --libs uuid blkid` -L$(top_builddir)
|
||||
bin_PROGRAMS=make-bcache \
|
||||
probe-bcache \
|
||||
bcache-super-show \
|
||||
bcachectl
|
||||
bcachectl \
|
||||
bcacheadm
|
||||
|
||||
noinst_PROGRAMS=bcache-test
|
||||
|
||||
@ -32,6 +33,11 @@ bcache_test_SOURCES=bcache-test.c
|
||||
bcache_test_LDFLAGS=-lm `pkg-config --libs openssl`
|
||||
bcache_test_CFLAGS=$(AM_CFLAGS) `pkg-config --cflags openssl`
|
||||
|
||||
bcacheadm_SOURCES=bcacheadm.c
|
||||
bcacheadm_LDFLAGS=$(AM_LDFLAGS) -lnih
|
||||
bcacheadm_LDADD=libbcache.a
|
||||
|
||||
|
||||
udevrule_DATA=69-bcache.rules
|
||||
udevruledir=$(prefix)/lib/udev/rules.d
|
||||
|
||||
|
@ -7,7 +7,7 @@ License: GPL
|
||||
Group: tools
|
||||
BuildRoot: %{_tmppath}/%{name}-root
|
||||
Requires: libblkid
|
||||
BuildRequires: pkgconfig libblkid-devel linux-headers
|
||||
BuildRequires: pkgconfig libblkid-devel linux-headers libnih-devel
|
||||
|
||||
%package dev
|
||||
|
||||
|
403
bcacheadm.c
Normal file
403
bcacheadm.c
Normal file
@ -0,0 +1,403 @@
|
||||
/*
|
||||
* Authors: Kent Overstreet <kmo@daterainc.com>
|
||||
* Gabriel de Perthuis <g2p.code@gmail.com>
|
||||
* Jacob Malevich <jam@datera.io>
|
||||
*
|
||||
* GPLv2
|
||||
*/
|
||||
|
||||
#include <nih/option.h>
|
||||
#include <nih/command.h>
|
||||
#include <nih/main.h>
|
||||
#include <nih/logging.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <blkid.h>
|
||||
#include <string.h>
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <bcache.h> //libbcache
|
||||
#define __KERNEL__
|
||||
#include <linux/bcache-ioctl.h>
|
||||
#undef __KERNEL__
|
||||
|
||||
#define PACKAGE_NAME "bcacheadm"
|
||||
#define PACKAGE_VERSION "1.0"
|
||||
#define PACKAGE_BUGREPORT "bugreport"
|
||||
|
||||
//What is the actual max?
|
||||
#define MAX_DEVS 64
|
||||
|
||||
|
||||
|
||||
/* bcacheadm globals */
|
||||
enum exit {
|
||||
EXIT_OK = 0, /* Ok */
|
||||
EXIT_ERROR = 1, /* General/OS error */
|
||||
EXIT_SHELL = 2, /* Start maintenance shell */
|
||||
EXIT_SHELL_REBOOT = 3, /* Start maintenance shell, reboot when done */
|
||||
EXIT_REBOOT = 4, /* System must reboot */
|
||||
};
|
||||
|
||||
|
||||
/* make-bcache globals */
|
||||
int bdev = -1;
|
||||
int devs = 0;
|
||||
const char *cache_devices[MAX_DEVS];
|
||||
const char *backing_devices[MAX_DEVS];
|
||||
const char *backing_dev_labels[MAX_DEVS];
|
||||
size_t i, nr_backing_devices = 0;
|
||||
unsigned block_size = 0;
|
||||
unsigned bucket_sizes[MAX_DEVS];
|
||||
int num_bucket_sizes = 0;
|
||||
int writeback = 0, discard = 0, wipe_bcache = 0;
|
||||
unsigned replication_set = 0, tier = 0, replacement_policy = 0;
|
||||
uint64_t data_offset = BDEV_DATA_START_DEFAULT;
|
||||
char *label = NULL;
|
||||
struct cache_sb *cache_set_sb;
|
||||
enum long_opts {
|
||||
CACHE_SET_UUID = 256,
|
||||
CSUM_TYPE,
|
||||
REPLICATION_SET,
|
||||
META_REPLICAS,
|
||||
DATA_REPLICAS,
|
||||
};
|
||||
|
||||
|
||||
/* super-show globals */
|
||||
bool force_csum = false;
|
||||
char *show_dev = NULL;
|
||||
|
||||
|
||||
/* probe globals */
|
||||
bool udev = false;
|
||||
|
||||
/* register globals */
|
||||
int bcachefd;
|
||||
|
||||
/* make-bcache option setters */
|
||||
static int set_CACHE_SET_UUID(NihOption *option, const char *arg)
|
||||
{
|
||||
if(uuid_parse(arg, cache_set_sb->set_uuid.b)){
|
||||
fprintf(stderr, "Bad uuid\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int set_CSUM_TYPE(NihOption *option, const char *arg)
|
||||
{
|
||||
SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb,
|
||||
read_string_list_or_die(arg, csum_types,
|
||||
"csum type"));
|
||||
return 0;
|
||||
}
|
||||
static int set_REPLICATION_SET(NihOption *option, const char *arg)
|
||||
{
|
||||
replication_set = strtoul_or_die(arg,
|
||||
CACHE_REPLICATION_SET_MAX,
|
||||
"replication set");
|
||||
return 0;
|
||||
}
|
||||
static int set_META_REPLICAS(NihOption *option, const char *arg)
|
||||
{
|
||||
SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb,
|
||||
strtoul_or_die(arg,
|
||||
CACHE_SET_META_REPLICAS_WANT_MAX,
|
||||
"meta replicas"));
|
||||
return 0;
|
||||
}
|
||||
static int set_DATA_REPLICAS(NihOption *option, const char *arg)
|
||||
{
|
||||
SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb,
|
||||
strtoul_or_die(arg,
|
||||
CACHE_SET_DATA_REPLICAS_WANT_MAX,
|
||||
"data replicas"));
|
||||
return 0;
|
||||
}
|
||||
static int set_cache(NihOption *option, const char *arg)
|
||||
{
|
||||
bdev=0;
|
||||
cache_devices[cache_set_sb->nr_in_set] = arg;
|
||||
next_cache_device(cache_set_sb,
|
||||
replication_set,
|
||||
tier,
|
||||
replacement_policy,
|
||||
discard);
|
||||
devs++;
|
||||
return 0;
|
||||
}
|
||||
static int set_bdev(NihOption *option, const char *arg)
|
||||
{
|
||||
bdev=1;
|
||||
backing_dev_labels[nr_backing_devices]=label;
|
||||
backing_devices[nr_backing_devices++]=arg;
|
||||
devs++;
|
||||
return 0;
|
||||
}
|
||||
static int set_bucket_sizes(NihOption *option, const char *arg)
|
||||
{
|
||||
bucket_sizes[num_bucket_sizes]=hatoi_validate(arg, "bucket size");
|
||||
num_bucket_sizes++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* probe setters */
|
||||
static int set_udev(NihOption *option, const char *arg)
|
||||
{
|
||||
if (strcmp("udev", arg)) {
|
||||
printf("Invalid output format %s\n", arg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
udev = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* options */
|
||||
static NihOption make_bcache_options[] = {
|
||||
// {int shortoption, char* longoption, char* help, NihOptionGroup, char* argname, void *value, NihOptionSetter}
|
||||
{'C', "cache", N_("Format a cache device"), NULL, NULL, NULL, set_cache},
|
||||
{'B', "bdev", N_("Format a backing device"), NULL, NULL, NULL, set_bdev},
|
||||
{'l', "label", N_("label"), NULL, NULL, &label, NULL},
|
||||
//Only one bucket_size supported until a list of bucket sizes is parsed correctly
|
||||
{'b', "bucket", N_("bucket size"), NULL, NULL, NULL, set_bucket_sizes},
|
||||
//Does the default setter automatically convert strings to an int?
|
||||
{'w', "block", N_("block size (hard sector size of SSD, often 2k"), NULL,NULL, &block_size, NULL},
|
||||
{'t', "tier", N_("tier of subsequent devices"), NULL,NULL, &tier, NULL},
|
||||
{'p', "cache_replacement_policy", N_("one of (lru|fifo|random)"), NULL,NULL, &replacement_policy, NULL},
|
||||
{'o', "data_offset", N_("data offset in sectors"), NULL,NULL, &data_offset, NULL},
|
||||
{'h', "help", N_("display this help and exit"), NULL,NULL, NULL, NULL},
|
||||
|
||||
{0, "cset-uuid", N_("UUID for the cache set"), NULL, NULL, NULL, set_CACHE_SET_UUID },
|
||||
{0, "csum-type", N_("One of (none|crc32c|crc64)"), NULL, NULL, NULL, set_CSUM_TYPE },
|
||||
{0, "replication-set",N_("replication set of subsequent devices"), NULL, NULL, NULL, set_REPLICATION_SET },
|
||||
{0, "meta-replicas",N_("number of metadata replicas"), NULL, NULL, NULL, set_META_REPLICAS},
|
||||
{0, "data-replicas",N_("number of data replicas"), NULL, NULL, NULL, set_DATA_REPLICAS },
|
||||
|
||||
{0, "wipe-bcache", N_("destroy existing bcache data if present"), NULL, NULL, &wipe_bcache, NULL},
|
||||
{0, "discard", N_("enable discards"), NULL, NULL, &discard, NULL},
|
||||
{0, "writeback", N_("enable writeback"), NULL, NULL, &writeback, NULL},
|
||||
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption super_show_options[] = {
|
||||
{'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL},
|
||||
{0, "dev", N_("dev"), NULL, NULL, &show_dev, NULL},
|
||||
NIH_OPTION_LAST
|
||||
|
||||
};
|
||||
|
||||
static NihOption probe_bcache_options[] = {
|
||||
{'o', "udev", N_("udev"), NULL, NULL, NULL, set_udev},
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption bcache_register_options[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
static NihOption options[] = {
|
||||
NIH_OPTION_LAST
|
||||
};
|
||||
|
||||
|
||||
/* commands */
|
||||
int make_bcache (NihCommand *command, char *const *args)
|
||||
{
|
||||
int cache_dev_fd[devs];
|
||||
|
||||
int backing_dev_fd[devs];
|
||||
|
||||
cache_set_sb = calloc(1, sizeof(*cache_set_sb) +
|
||||
sizeof(struct cache_member) * devs);
|
||||
|
||||
uuid_generate(cache_set_sb->set_uuid.b);
|
||||
SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, BCH_CSUM_CRC32C);
|
||||
SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, 1);
|
||||
SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, 1);
|
||||
|
||||
if(!bucket_sizes[0]) bucket_sizes[0] = 1024;
|
||||
|
||||
if (bdev == -1) {
|
||||
fprintf(stderr, "Please specify -C or -B\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!cache_set_sb->nr_in_set && !nr_backing_devices) {
|
||||
fprintf(stderr, "Please supply a device\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
if (bucket_sizes[i] < block_size) {
|
||||
fprintf(stderr, "Bucket size cannot be smaller than block size\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
i++;
|
||||
} while (i < num_bucket_sizes);
|
||||
|
||||
if (!block_size) {
|
||||
for (i = 0; i < cache_set_sb->nr_in_set; i++)
|
||||
block_size = max(block_size,
|
||||
get_blocksize(cache_devices[i]));
|
||||
|
||||
for (i = 0; i < nr_backing_devices; i++)
|
||||
block_size = max(block_size,
|
||||
get_blocksize(backing_devices[i]));
|
||||
}
|
||||
|
||||
for (i = 0; i < cache_set_sb->nr_in_set; i++)
|
||||
cache_dev_fd[i] = dev_open(cache_devices[i], wipe_bcache);
|
||||
|
||||
for (i = 0; i < nr_backing_devices; i++)
|
||||
backing_dev_fd[i] = dev_open(backing_devices[i], wipe_bcache);
|
||||
|
||||
write_cache_sbs(cache_dev_fd, cache_set_sb, block_size,
|
||||
bucket_sizes, num_bucket_sizes);
|
||||
|
||||
for (i = 0; i < nr_backing_devices; i++)
|
||||
write_backingdev_sb(backing_dev_fd[i],
|
||||
block_size, bucket_sizes,
|
||||
writeback, data_offset,
|
||||
backing_dev_labels[i],
|
||||
cache_set_sb->set_uuid);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int super_show (NihCommand *command, char *const *args)
|
||||
{
|
||||
struct cache_sb sb_stack, *sb = &sb_stack;
|
||||
size_t bytes = sizeof(*sb);
|
||||
|
||||
int fd = open(show_dev, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
printf("Can't open dev %s: %s\n", show_dev, strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (pread(fd, sb, bytes, SB_START) != bytes) {
|
||||
fprintf(stderr, "Couldn't read\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (sb->keys) {
|
||||
bytes = sizeof(*sb) + sb->keys * sizeof(uint64_t);
|
||||
sb = malloc(bytes);
|
||||
|
||||
if (pread(fd, sb, bytes, SB_START) != bytes) {
|
||||
fprintf(stderr, "Couldn't read\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!SB_IS_BDEV(sb))
|
||||
show_super_cache(sb, force_csum);
|
||||
else
|
||||
show_super_backingdev(sb, force_csum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int probe_bcache (NihCommand *command, char *const *args)
|
||||
{
|
||||
int i;
|
||||
struct cache_sb sb;
|
||||
char uuid[40];
|
||||
blkid_probe pr;
|
||||
|
||||
for (i = 0; args[i]!=NULL; i++) {
|
||||
int fd = open(args[i], O_RDONLY);
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
if (!(pr = blkid_new_probe()))
|
||||
continue;
|
||||
if (blkid_probe_set_device(pr, fd, 0, 0))
|
||||
continue;
|
||||
/* probe partitions too */
|
||||
if (blkid_probe_enable_partitions(pr, true))
|
||||
continue;
|
||||
/* bail if anything was found
|
||||
* probe-bcache isn't needed once blkid recognizes bcache */
|
||||
if (!blkid_do_probe(pr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb))
|
||||
continue;
|
||||
|
||||
if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic)))
|
||||
continue;
|
||||
|
||||
uuid_unparse(sb.uuid.b, uuid);
|
||||
|
||||
if (udev)
|
||||
printf("ID_FS_UUID=%s\n"
|
||||
"ID_FS_UUID_ENC=%s\n"
|
||||
"ID_FS_TYPE=bcache\n",
|
||||
uuid, uuid);
|
||||
else
|
||||
printf("%s: UUID=\"\" TYPE=\"bcache\"\n", uuid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcache_register (NihCommand *command, char *const *args)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bcachefd = open("/dev/bcache", O_RDWR);
|
||||
if (bcachefd < 0) {
|
||||
perror("Can't open bcache device");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, args);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ioctl error %d", ret);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static NihCommand commands[] = {
|
||||
{"format", N_("format <list of drives>"), "Format one or a list of devices with bcache datastructures. You need to do this before you create a volume", N_("format drive[s] with bcache"), NULL, make_bcache_options, make_bcache},
|
||||
{"show-sb", N_("show-sb <list of drives>"), "View a superblock on one or a list of bcache formated devices", N_("show superblock on each of the listed drive"), NULL, super_show_options, super_show},
|
||||
{"probe", N_("probe <list of drives>"), NULL, NULL, NULL, probe_bcache_options, probe_bcache},
|
||||
{"register", N_("register <list of devices>"), NULL, NULL, NULL, bcache_register_options, bcache_register},
|
||||
NIH_COMMAND_LAST
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
nih_main_init (argv[0]);
|
||||
|
||||
nih_option_set_synopsis (_("Manage bcache devices"));
|
||||
nih_option_set_help (
|
||||
_("Helps you manage bcache devices"));
|
||||
|
||||
ret = nih_command_parser (NULL, argc, argv, options, commands);
|
||||
if (ret < 0)
|
||||
exit (1);
|
||||
|
||||
nih_signal_reset();
|
||||
}
|
@ -11,7 +11,6 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
|
||||
|
||||
# Checks for libraries.
|
||||
|
||||
# Checks for header files.
|
||||
|
Loading…
Reference in New Issue
Block a user