#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
+#include <dirent.h>
+
+#include "bcache.h"
+#include "bcacheadm-format.h"
+#include "bcacheadm-assemble.h"
+#include "bcacheadm-run.h"
+#include "bcacheadm-query.h"
#define PACKAGE_NAME "bcacheadm"
#define PACKAGE_VERSION "1.0"
-#define PACKAGE_BUGREPORT "bugreport"
-
-#define MAX_DEVS MAX_CACHES_PER_SET
-
-
-/* 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;
-
-/* probe globals */
-bool udev = false;
-
-/* list globals */
-char *cset_dir = "/sys/fs/bcache";
-
-/* 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;
-}
+#define PACKAGE_BUGREPORT "linux-bcache@vger.kernel.org"
+#if 0
+static bool modify_list_attrs = false;
+static const char *modify_set_uuid = NULL;
+static const char *modify_dev_uuid = NULL;
-/* 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},
-
- {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 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 query_devs_options[] = {
- {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL},
+static NihOption bcache_modify_options[] = {
+ {'l', "list", N_("list attributes"), NULL, NULL, &modify_list_attrs, NULL},
+ {'u', "set", N_("cacheset uuid"), NULL, "UUID", &modify_set_uuid, NULL},
+ {'d', "dev", N_("device uuid"), NULL, "UUID", &modify_dev_uuid, NULL},
NIH_OPTION_LAST
};
-static NihOption list_cachesets_options[] = {
- {'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL},
- NIH_OPTION_LAST
-};
-
-static NihOption status_options[] = {
- NIH_OPTION_LAST
-};
-
-static NihOption options[] = {
- NIH_OPTION_LAST
-};
-
-
-/* commands */
-int make_bcache (NihCommand *command, char *const *args)
+int bcache_modify(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;
+ char *err;
+ char path[MAX_PATH];
+ char *attr = args[0];
+ char *val = NULL;
+ int fd = -1;
- if (bdev == -1) {
- fprintf(stderr, "Please specify -C or -B\n");
- exit(EXIT_FAILURE);
+ if (modify_list_attrs) {
+ sysfs_attr_list();
+ return 0;
}
- if (!cache_set_sb->nr_in_set && !nr_backing_devices) {
- fprintf(stderr, "Please supply a device\n");
- exit(EXIT_FAILURE);
+ if (!modify_set_uuid) {
+ printf("Must provide a cacheset uuid\n");
+ return -1;
}
- 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);
+ snprintf(path, MAX_PATH, "%s/%s", cset_dir, modify_set_uuid);
- 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]));
+ if(!attr) {
+ printf("Must provide the name of an attribute to modify\n");
+ goto err;
}
- 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 probe_bcache (NihCommand *command, char *const *args)
-{
- int i;
-
- for (i = 0; args[i] != NULL; i++) {
- probe(args[i], udev);
+ enum sysfs_attr type = sysfs_attr_type(attr);
+
+ if (type == -1)
+ goto err;
+ else if(type == INTERNAL_ATTR)
+ strcat(path, "/internal");
+ else if(type == CACHE_ATTR) {
+ if(modify_dev_uuid) {
+ /* searches all cache# for a matching uuid,
+ * path gets modified to the correct cache path */
+ char subdir[10] = "/cache";
+ err = find_matching_uuid(path, subdir,
+ modify_dev_uuid);
+ if (err) {
+ printf("Failed to find "
+ "matching dev %s\n", err);
+ goto err;
+ } else {
+ strcat(path, subdir);
+ }
+ } else {
+ printf("Must provide a device uuid\n");
+ }
}
+ /* SET_ATTRs are just in the current dir */
- return 0;
-}
-
-int bcache_register (NihCommand *command, char *const *args)
-{
- int ret;
- char *arg_list = parse_array_to_list(args);
+ strcat(path, "/");
+ strcat(path, attr);
- if(arg_list) {
- ret = register_bcache(arg_list);
- free(arg_list);
+ val = args[1];
+ if (!val) {
+ printf("Must provide a value to change the attribute to\n");
+ goto err;
}
- return ret;
-}
-
-int bcache_list_cachesets (NihCommand *command, char *const *args)
-{
- return list_cachesets(cset_dir);
-}
-
-int bcache_query_devs (NihCommand *command, char *const *args)
-{
- int i;
-
- for (i = 0; args[i] != NULL; i++) {
- struct cache_sb *sb = query_dev(args[i], false);
- print_dev_info(sb, force_csum);
+ fd = open(path, O_WRONLY);
+ if (fd < 0) {
+ printf("Unable to open modify attr with path %s\n", path);
+ goto err;
}
-}
-int bcache_status (NihCommand *command, char *const *args)
-{
- int i;
- struct cache_sb *sb_tier0 = NULL, *sb_tier1 = NULL;
- char *dev0 = NULL, *dev1 = NULL;
+ write(fd, val, strlen(val));
- for (i = 0; args[i] != NULL; i++) {
- struct cache_sb *sb = query_dev(args[i], false);
- struct cache_member *m = ((struct cache_member *) sb->d) +
- sb->nr_this_dev;
- long long unsigned cache_tier = CACHE_TIER(m);
+err:
+ if(fd)
+ close(fd);
+ return 0;
+}
+#endif
- if (!cache_tier)
- if (!sb_tier0 || sb->seq > sb_tier0->seq) {
- sb_tier0 = sb;
- dev0 = args[i];
- }
- else if (cache_tier == 1)
- if (!sb_tier1 || sb->seq > sb_tier1->seq) {
- sb_tier1 = sb;
- dev1 = args[i];
- }
- }
- if (sb_tier0) sb_state(sb_tier0, dev0);
- if (sb_tier1) sb_state(sb_tier1, dev1);
+#define CMD(_command, _usage, _synopsis, _help) \
+{ \
+ .command = #_command, \
+ .usage = _usage, \
+ .synopsis = _synopsis, \
+ .help = _help, \
+ .group = NULL, \
+ .options = opts_##_command, \
+ .action = cmd_##_command, \
}
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},
- {"probe", N_("probe <list of devices>"),
- "Does a blkid_probe on a device",
- N_("Does a blkid_probe on a device"),
- NULL, probe_bcache_options, probe_bcache},
- {"register", N_("register <list of devices>"),
- "Registers a list of devices",
- N_("Registers a list of devices"),
- NULL, bcache_register_options, bcache_register},
- {"list-cachesets", N_("list-cachesets"),
- "Lists cachesets in /sys/fs/bcache",
- N_("Lists cachesets in /sys/fs/bcache"),
- NULL, list_cachesets_options, bcache_list_cachesets},
- {"query-devs", N_("query <list of devices>"),
- "Gives info about the superblock of a list of devices",
- N_("show superblock on each of the listed drive"),
- NULL, query_devs_options, bcache_query_devs},
- {"status", N_("status <list of devices>"),
- "Finds the status of the most up to date superblock",
- N_("Finds the status of the most up to date superblock"),
- NULL, status_options, bcache_status},
+ CMD(format, N_("<list of devices>"),
+ "Create a new bcache volume from one or more devices",
+ N_("format drive[s] for bcache")),
+
+ CMD(assemble, N_("<devices>"),
+ "Assembles one or more devices into a bcache volume",
+ N_("Registers a list of devices")),
+ CMD(incremental, N_("<device"),
+ "Incremental assemble bcache volumes",
+ N_("Incrementally registers a single device")),
+
+ CMD(run, N_("<volume>"),
+ "Start a partially assembled volume",
+ N_("Registers a list of devices")),
+ CMD(stop, N_("<volume>"),
+ "Stops a running bcache volume",
+ N_("Unregisters a list of devices")),
+ CMD(add, N_("<volume> <devices>"),
+ "Adds a list of devices to a volume",
+ N_("Adds a list of devices to a volume")),
+ CMD(readd, N_("<volume> <devices>"),
+ "Adds previously used members of a volume",
+ N_("Adds a list of devices to a volume")),
+ CMD(remove, N_("<volume> <devices>"),
+ "Removes a device from its volume",
+ N_("Removes a device from its volume")),
+ CMD(fail, N_("<volume> <devices>"),
+ "Sets a device to the FAILED state",
+ N_("Sets a device to the FAILED state")),
+
+#if 0
+ CMD(modify, N_("<options>"),
+ "Modifies attributes related to the volume",
+ N_("Modifies attributes related to the volume")),
+#endif
+ CMD(list, N_("list-cachesets"),
+ "Lists cachesets in /sys/fs/bcache",
+ N_("Lists cachesets in /sys/fs/bcache")),
+ CMD(query, N_("query <list of devices>"),
+ "Gives info about the superblock of a list of devices",
+ N_("show superblock on each of the listed drive")),
+ CMD(status, N_("status <list of devices>"),
+ "Finds the status of the most up to date superblock",
+ N_("Finds the status of the most up to date superblock")),
NIH_COMMAND_LAST
};
+static NihOption options[] = {
+ NIH_OPTION_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"));
+ 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);
+ int ret = nih_command_parser(NULL, argc, argv, options, commands);
if (ret < 0)
- exit (1);
+ exit(EXIT_FAILURE);
nih_signal_reset();
+
+ return 0;
}