]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - bcacheadm.c
bcache-tools: update for superblock changes
[bcachefs-tools-debian] / bcacheadm.c
index 837219edf02028a6f1a5df2ae29c24aa68b232b8..d6e2d8698aad2e5495e8d8301e5bccf33ed1478c 100644 (file)
@@ -41,14 +41,17 @@ int bdev = -1;
 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;
@@ -58,9 +61,6 @@ char *metadata_replicas = 0;
 char *data_replicas = 0;
 char *tier = 0;
 
-/* add-dev globals */
-char *add_dev_uuid = NULL;
-
 /* rm-dev globals */
 bool force_remove = false;
 
@@ -80,6 +80,7 @@ bool udev = 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;
@@ -99,6 +100,9 @@ bool stats_hour = 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)
 {
@@ -106,6 +110,12 @@ 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;
@@ -117,7 +127,26 @@ static int set_cache(NihOption *option, const char *arg)
                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++;
@@ -169,7 +198,10 @@ static NihOption make_bcache_options[] = {
        //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},
@@ -183,6 +215,7 @@ static NihOption make_bcache_options[] = {
        {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
 };
@@ -201,7 +234,6 @@ static NihOption bcache_unregister_options[] = {
 };
 
 static NihOption bcache_add_device_options[] = {
-       {'u', "set", N_("cacheset uuid"), NULL, "UUID", &add_dev_uuid, NULL},
        NIH_OPTION_LAST
 };
 
@@ -227,6 +259,7 @@ static NihOption query_devs_options[] = {
 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
 };
 
@@ -237,7 +270,7 @@ static NihOption status_options[] = {
 
 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
 };
 
@@ -254,6 +287,11 @@ static NihOption stats_options[] = {
        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
 };
@@ -263,22 +301,27 @@ static NihOption options[] = {
 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) {
@@ -290,35 +333,46 @@ int make_bcache(NihCommand *command, char *const *args)
        }
 
        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) {
@@ -353,13 +407,21 @@ int make_bcache(NihCommand *command, char *const *args)
                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);
 
 
@@ -412,12 +474,7 @@ int bcache_add_devices(NihCommand *command, char *const *args)
 {
        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;
@@ -430,6 +487,11 @@ int bcache_rm_device(NihCommand *command, char *const *args)
 {
        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);
@@ -443,8 +505,6 @@ int bcache_modify(NihCommand *command, char *const *args)
 {
        char *err;
        char path[MAX_PATH];
-       DIR *path_dir;
-       struct stat cache_stat;
        char *attr = args[0];
        char *val = NULL;
        int fd = -1;
@@ -518,13 +578,34 @@ err:
 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)
@@ -552,8 +633,8 @@ 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";
 
@@ -570,46 +651,118 @@ int bcache_query_devs(NihCommand *command, char *const *args)
 
 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;
 }
@@ -714,6 +867,24 @@ err:
        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."
@@ -732,7 +903,7 @@ static NihCommand commands[] = {
                     "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},
@@ -764,6 +935,10 @@ static NihCommand commands[] = {
                  "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
 };