int devs = 0;
char *cache_devices[MAX_DEVS];
int tier_mapping[MAX_DEVS];
+unsigned replacement_policy_mapping[MAX_DEVS];
char *backing_devices[MAX_DEVS];
char *backing_dev_labels[MAX_DEVS];
size_t i, nr_backing_devices = 0, nr_cache_devices = 0;
unsigned block_size = 0;
+unsigned btree_node_size = 0;
unsigned bucket_sizes[MAX_DEVS];
int num_bucket_sizes = 0;
-int writeback = 0, discard = 0, wipe_bcache = 0;
-unsigned replication_set = 0, replacement_policy = 0;
+int writeback = 0, writearound = 0, discard = 0, wipe_bcache = 0;
+unsigned replication_set = 0;
+char *replacement_policy = 0;
uint64_t data_offset = BDEV_DATA_START_DEFAULT;
char *label = NULL;
struct cache_sb *cache_set_sb = NULL;
char *data_replicas = 0;
char *tier = 0;
-/* add-dev globals */
-char *add_dev_uuid = NULL;
-
/* rm-dev globals */
bool force_remove = false;
/* list globals */
char *cset_dir = "/sys/fs/bcache";
bool list_devs = false;
+static const char *internal_uuid = NULL;
/* status globals */
bool status_all = false;
bool stats_day = false;
bool stats_total = false;
+/* set_failed globals */
+static const char *dev_failed_uuid = NULL;
+
/* make-bcache option setters */
static int set_block_size(NihOption *option, const char *arg)
{
return 0;
}
+static int set_btree_node_size(NihOption *option, const char *arg)
+{
+ btree_node_size = hatoi_validate(arg, "btree node size");
+ return 0;
+}
+
static int set_cache(NihOption *option, const char *arg)
{
bdev = 0;
if(ntier == 0 || ntier == 1)
tier_mapping[nr_cache_devices] = ntier;
else
- printf("Invalid tier\n");
+ printf("Invalid tier %s\n", tier);
+ }
+
+ if (!replacement_policy)
+ replacement_policy_mapping[nr_cache_devices] = 0;
+ else {
+ int i = 0;
+
+ while (replacement_policies[i] != NULL) {
+ if (!strcmp(replacement_policy,
+ replacement_policies[i])) {
+ replacement_policy_mapping[nr_cache_devices] = i;
+ break;
+ }
+ i++;
+ }
+
+ if (replacement_policies[i] == NULL)
+ printf("Invalid replacement policy: %s\n",
+ replacement_policy);
}
devs++;
//Only one bucket_size supported until a list of bucket sizes is parsed correctly
{'b', "bucket", N_("bucket size"), NULL, "size", 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,"size", NULL, set_block_size},
+ {'w', "block", N_("block size (hard sector size of SSD, often 2k"), NULL, "size", NULL, set_block_size},
+
+ {'n', "btree-node", N_("Btree node size, default 256k"), NULL, "size", NULL, set_btree_node_size},
+
{'t', "tier", N_("tier of subsequent devices"), NULL,"#", &tier, NULL},
{'p', "cache_replacement_policy", N_("one of (lru|fifo|random)"), NULL,"policy", &replacement_policy, NULL},
{'o', "data_offset", N_("data offset in sectors"), NULL,"offset", &data_offset, NULL},
{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},
+ {0, "writearound", N_("enable writearound"), NULL, NULL, &writearound, NULL},
NIH_OPTION_LAST
};
};
static NihOption bcache_add_device_options[] = {
- {'u', "set", N_("cacheset uuid"), NULL, "UUID", &add_dev_uuid, NULL},
NIH_OPTION_LAST
};
static NihOption list_cachesets_options[] = {
{'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL},
{0, "list-devs", N_("list all devices in the cache sets as well"), NULL, NULL, &list_devs, NULL},
+ {0, "internal_uuid", N_("Show the internal UUID for the given cacheset UUID"), NULL, "UUID", &internal_uuid, NULL},
NIH_OPTION_LAST
};
static NihOption capacity_options[] = {
{'u', "set", N_("cache_set UUID"), NULL, "UUID", &capacity_uuid, NULL},
- {'d', "devs", N_("dev UUID"), NULL, NULL, &capacity_devs, NULL},
+ {'d', "devs", N_("Individual device capacities"), NULL, NULL, &capacity_devs, NULL},
NIH_OPTION_LAST
};
NIH_OPTION_LAST
};
+static NihOption set_failed_options[] = {
+ {'d', "dev", N_("dev UUID"), NULL, "UUID", &dev_failed_uuid, NULL},
+ NIH_OPTION_LAST
+};
+
static NihOption options[] = {
NIH_OPTION_LAST
};
int make_bcache(NihCommand *command, char *const *args)
{
int cache_dev_fd[devs];
+ int data_replicas_num, metadata_replicas_num;
int backing_dev_fd[devs];
+ unsigned cache_mode;
+
cache_set_sb = calloc(1, sizeof(*cache_set_sb) +
sizeof(struct cache_member) * devs);
+ uuid_generate(cache_set_sb->set_uuid.b);
+
if (cache_set_uuid) {
- if(uuid_parse(cache_set_uuid, cache_set_sb->set_uuid.b)) {
+ if(uuid_parse(cache_set_uuid, cache_set_sb->user_uuid.b)) {
fprintf(stderr, "Bad uuid\n");
return -1;
}
} else {
- uuid_generate(cache_set_sb->set_uuid.b);
+ uuid_generate(cache_set_sb->user_uuid.b);
}
- if (label)
+ if (label)
memcpy(cache_set_sb->label, label, sizeof(cache_set_sb->label));
if (csum_type) {
}
if (metadata_replicas) {
- SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb,
- strtoul_or_die(metadata_replicas,
- CACHE_SET_META_REPLICAS_WANT_MAX,
- "meta replicas"));
+ metadata_replicas_num =
+ strtoul_or_die(metadata_replicas,
+ CACHE_SET_META_REPLICAS_WANT_MAX,
+ "meta replicas");
} else {
- SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, 1);
+ metadata_replicas_num = 1;
}
+ SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb,
+ metadata_replicas_num);
+ SET_CACHE_SET_META_REPLICAS_HAVE(cache_set_sb,
+ metadata_replicas_num);
+
if (data_replicas) {
- SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb,
+ data_replicas_num =
strtoul_or_die(data_replicas,
CACHE_SET_DATA_REPLICAS_WANT_MAX,
- "data replicas"));
+ "data replicas");
} else {
- SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, 1);
+ data_replicas_num = 1;
}
+ SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb,
+ data_replicas_num);
+ SET_CACHE_SET_DATA_REPLICAS_HAVE(cache_set_sb,
+ data_replicas_num);
+
if (bdev == -1) {
fprintf(stderr, "Please specify -C or -B\n");
exit(EXIT_FAILURE);
}
- if(!bucket_sizes[0]) bucket_sizes[0] = 1024;
+ if (!bucket_sizes[0])
+ bucket_sizes[0] = 1024;
- for(i = 0; i < nr_cache_devices; i++)
+ for (i = 0; i < nr_cache_devices; i++)
next_cache_device(cache_set_sb,
replication_set,
tier_mapping[i],
- replacement_policy,
+ replacement_policy_mapping[i],
discard);
if (!cache_set_sb->nr_in_set && !nr_backing_devices) {
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);
+ bucket_sizes, num_bucket_sizes, btree_node_size);
+
+ if (writeback)
+ cache_mode = CACHE_MODE_WRITEBACK;
+ else if (writearound)
+ cache_mode = CACHE_MODE_WRITEAROUND;
+ else
+ cache_mode = CACHE_MODE_WRITETHROUGH;
for (i = 0; i < nr_backing_devices; i++)
write_backingdev_sb(backing_dev_fd[i],
block_size, bucket_sizes,
- writeback, data_offset,
+ cache_mode, data_offset,
backing_dev_labels[i],
+ cache_set_sb->user_uuid,
cache_set_sb->set_uuid);
{
char *err;
- if (!add_dev_uuid) {
- printf("Must specify a cacheset uuid to add the disk to\n");
- return -1;
- }
-
- err = add_devices(args, add_dev_uuid);
+ err = add_devices(args);
if (err) {
printf("bcache_add_devices error: %s\n", err);
return -1;
{
char *err;
+ if (!args[0]) {
+ printf("Must provide a device name\n");
+ return -1;
+ }
+
err = remove_device(args[0], force_remove);
if (err) {
printf("bcache_rm_devices error: %s\n", err);
{
char *err;
char path[MAX_PATH];
- DIR *path_dir;
- struct stat cache_stat;
char *attr = args[0];
char *val = NULL;
int fd = -1;
int bcache_list_cachesets(NihCommand *command, char *const *args)
{
char *err = NULL;
- err = list_cachesets(cset_dir, list_devs);
- if (err) {
- printf("bcache_list_cachesets error :%s\n", err);
- return -1;
+
+ if (internal_uuid) {
+ char uuid_path[MAX_PATH];
+ DIR *uuid_dir;
+ char buf[MAX_PATH];
+
+ snprintf(uuid_path, MAX_PATH, "%s/%s", cset_dir, internal_uuid);
+
+ err = "uuid does not exist";
+ if((uuid_dir = opendir(uuid_path)) == NULL)
+ goto err;
+
+ err = read_stat_dir(uuid_dir, uuid_path, "/internal/internal_uuid", buf);
+ if (err)
+ goto err;
+ printf("%s", buf);
+ return 0;
}
+ err = list_cachesets(cset_dir, list_devs);
+ if (err)
+ goto err;
+
return 0;
+
+err:
+ printf("bcache_list_cachesets error :%s\n", err);
+ return -1;
}
int bcache_query_devs(NihCommand *command, char *const *args)
char set_uuid_str[40], dev_uuid_str[40];
char *clus_uuid = (char *)sb->label;
- uuid_unparse(sb->set_uuid.b, set_uuid_str);
- uuid_unparse(sb->uuid.b, dev_uuid_str);
+ uuid_unparse(sb->user_uuid.b, set_uuid_str);
+ uuid_unparse(sb->disk_uuid.b, dev_uuid_str);
if (!strcmp(clus_uuid, ""))
clus_uuid = "None";
int bcache_status(NihCommand *command, char *const *args)
{
- int i, seq, nr_in_set = 0;
+ int i, dev_count = 0, seq, cache_count = 0;
struct cache_sb *seq_sb = NULL;
+ char cache_path[MAX_PATH];
+ char *dev_names[MAX_DEVS];
+ char *dev_uuids[MAX_DEVS];
+ char intbuf[4];
+ char set_uuid[40];
for (i = 0; args[i] != NULL; i++) {
struct cache_sb *sb = query_dev(args[i], false, false,
false, NULL);
- if(!sb) {
+ if (!sb) {
printf("Unable to open superblock, bad path\n");
return -1;
}
- if(!seq_sb || sb->seq > seq) {
+ if (!seq_sb || sb->seq > seq) {
seq = sb->seq;
seq_sb = sb;
- nr_in_set = sb->nr_in_set;
} else
free(sb);
}
- if(!seq_sb) {
+ if (!seq_sb) {
printf("Unable to find a superblock\n");
return -1;
} else {
+ uuid_unparse(seq_sb->user_uuid.b, set_uuid);
printf("%-50s%-15s%-4s\n", "uuid", "state", "tier");
}
+ snprintf(intbuf, 4, "%d", i);
+ snprintf(cache_path, MAX_PATH, "%s/%s/%s", cset_dir, set_uuid,
+ "cache0");
+
+ /*
+ * Get a list of all the devices from sysfs first, then
+ * compare it to the list we get back from the most up
+ * to date superblock. If there are any devices in the superblock
+ * that are not in sysfs, print out 'missing'
+ */
+ while (true) {
+ char buf[MAX_PATH];
+ int len;
+ DIR *cache_dir;
+
+ if(((cache_dir = opendir(cache_path)) == NULL) &&
+ cache_count > MAX_DEVS)
+ break;
+
+ if (cache_dir)
+ closedir(cache_dir);
+
+ if((len = readlink(cache_path, buf, sizeof(buf) - 1)) != -1) {
+ struct cache_sb *sb;
+ char dev_uuid[40];
+ char dev_path[32];
+
+ buf[len] = '\0';
+ dev_names[dev_count] = dev_name(buf);
+ snprintf(dev_path, MAX_PATH, "%s/%s", "/dev",
+ dev_names[dev_count]);
+ sb = query_dev(dev_path, false, false,
+ true, dev_uuid);
+ if (!sb) {
+ printf("error reading %s\n", dev_path);
+ return -1;
+ } else
+ free(sb);
+
+ dev_uuids[dev_count] = strdup(dev_uuid);
+ dev_count++;
+ }
+
+ cache_path[strlen(cache_path) - strlen(intbuf)] = 0;
+ cache_count++;
+
+ snprintf(intbuf, 4, "%d", cache_count);
+ strcat(cache_path, intbuf);
+ }
+
for (i = 0; i < seq_sb->nr_in_set; i++) {
char uuid_str[40];
- struct cache_member *m = ((struct cache_member *) seq_sb->d) + i;
+ struct cache_member *m = seq_sb->members + i;
+ char dev_state[32];
+ int j;
uuid_unparse(m->uuid.b, uuid_str);
+ snprintf(dev_state, MAX_PATH, "%s",
+ cache_state[CACHE_STATE(m)]);
+
+ for (j = 0; j < dev_count; j++) {
+ if (!strcmp(uuid_str, dev_uuids[j])) {
+ break;
+ } else if (j == dev_count - 1) {
+ if (!strcmp(cache_state[CACHE_STATE(m)], "active"))
+ snprintf(dev_state, MAX_PATH, "%s", "missing");
+ break;
+ }
+ }
- printf("%-50s%-15s%-4llu\n", uuid_str,
- cache_state[CACHE_STATE(m)],
+ printf("%-50s%-15s%-4llu\n", uuid_str, dev_state,
CACHE_TIER(m));
}
- if(seq_sb)
+ if (seq_sb)
free(seq_sb);
+ for (i = 0; i < dev_count; i++) {
+ free(dev_names[i]);
+ free(dev_uuids[i]);
+ }
return 0;
}
return -1;
}
+int bcache_set_failed(NihCommand *command, char *const *args)
+{
+ char *err = NULL;
+
+ if (!dev_failed_uuid) {
+ printf("Pass in a dev uuid\n");
+ return -1;
+ }
+
+ err = device_set_failed(dev_failed_uuid);
+ if (err) {
+ printf("bcache_set_failed_ioctl error: %s\n", err);
+ return -1;
+ }
+
+ return 0;
+}
+
static NihCommand commands[] = {
{"format", N_("format <list of drives>"),
"Format one or a list of devices with bcache datastructures."
"Unregisters a list of devices",
N_("Unregisters a list of devices"),
NULL, bcache_unregister_options, bcache_unregister},
- {"add-devs", N_("add-devs --set=UUID --tier=# <list of devices>"),
+ {"add-devs", N_("add-devs --tier=# <list of devices>"),
"Adds a list of devices to a cacheset",
N_("Adds a list of devices to a cacheset"),
NULL, bcache_add_device_options, bcache_add_devices},
"List various bcache statistics",
N_("List various bcache statistics"),
NULL, stats_options, bcache_stats},
+ {"set-failed", N_("set-failed --dev=UUID"),
+ "Sets a device to the FAILED state",
+ N_("Sets a device to the FAILED state"),
+ NULL, set_failed_options, bcache_set_failed},
NIH_COMMAND_LAST
};