X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=bcache.c;h=e2de70b96608c06f44addd770214e58cdd2d493b;hb=e13d21ade75401f944cbbb7438f3e569bdfaf247;hp=ec88ffc985e0c48de552822bd6e47a923614152f;hpb=1c113a126b499dea3bbf3b4f93836f60763edff3;p=bcachefs-tools-debian diff --git a/bcache.c b/bcache.c index ec88ffc..e2de70b 100644 --- a/bcache.c +++ b/bcache.c @@ -48,6 +48,13 @@ const char * const csum_types[] = { NULL }; +const char * const error_actions[] = { + "continue", + "readonly", + "panic", + NULL +}; + const char * const bdev_cache_mode[] = { "writethrough", "writeback", @@ -64,6 +71,42 @@ const char * const bdev_state[] = { NULL }; +const char * const set_attrs[] = { + "btree_flush_delay", + "btree_scan_ratelimit", + "bucket_reserve_percent", + "cache_reserve_percent", + "checksum_type", + "congested_read_threshold_us", + "congested_write_threshold_us", + "data_replicas", + "errors", + "foreground_target_percent", + "gc_sector_percent", + "journal_delay_ms", + "meta_replicas", + "sector_reserve_percent", + "tiering_percent", + NULL +}; + +const char * const cache_attrs[] = { + "cache_replacement_policy", + "discard", + "state", + "tier", + NULL +}; + +const char * const internal_attrs[] = { + "btree_shrinker_disabled", + "copy_gc_enabled", + "foreground_write_rate", + "tiering_enabled", + "tiering_rate", + NULL +}; + char *skip_spaces(const char *str) { while (isspace(*str)) @@ -114,11 +157,8 @@ ssize_t read_string_list_or_die(const char *opt, const char * const list[], const char *msg) { ssize_t v = read_string_list(opt, list); - if (v < 0) { - fprintf(stderr, "Bad %s %s\n", msg, opt); - exit(EXIT_FAILURE); - - } + if (v < 0) + die("Bad %s %s", msg, opt); return v; } @@ -355,8 +395,7 @@ static uint64_t bch_checksum_update(unsigned type, uint64_t crc, const void *dat case BCH_CSUM_CRC64: return bch_crc64_update(crc, data, len); default: - fprintf(stderr, "Unknown checksum type %u\n", type); - exit(EXIT_FAILURE); + die("Unknown checksum type %u", type); } } @@ -411,30 +450,24 @@ unsigned hatoi_validate(const char *s, const char *msg) { uint64_t v = hatoi(s); - if (v & (v - 1)) { - fprintf(stderr, "%s must be a power of two\n", msg); - exit(EXIT_FAILURE); - } + if (v & (v - 1)) + die("%s must be a power of two", msg); v /= 512; - if (v > USHRT_MAX) { - fprintf(stderr, "%s too large\n", msg); - exit(EXIT_FAILURE); - } + if (v > USHRT_MAX) + die("%s too large\n", msg); - if (!v) { - fprintf(stderr, "%s too small\n", msg); - exit(EXIT_FAILURE); - } + if (!v) + die("%s too small\n", msg); return v; } -static void do_write_sb(int fd, struct cache_sb *sb) +void do_write_sb(int fd, struct cache_sb *sb) { char zeroes[SB_START] = {0}; - size_t bytes = ((void *) bset_bkey_last(sb)) - (void *) sb; + size_t bytes = ((void *) __bset_bkey_last(sb)) - (void *) sb; /* Zero start of disk */ if (pwrite(fd, zeroes, SB_START, 0) != SB_START) { @@ -451,10 +484,9 @@ static void do_write_sb(int fd, struct cache_sb *sb) close(fd); } -void write_backingdev_sb(int fd, unsigned block_size, unsigned *bucket_sizes, - bool writeback, uint64_t data_offset, - const char *label, - uuid_le set_uuid) +void write_backingdev_sb(int fd, unsigned block_size, unsigned mode, + uint64_t data_offset, const char *label, + uuid_le user_uuid, uuid_le set_uuid) { char uuid_str[40], set_uuid_str[40]; struct cache_sb sb; @@ -464,23 +496,21 @@ void write_backingdev_sb(int fd, unsigned block_size, unsigned *bucket_sizes, sb.offset = SB_SECTOR; sb.version = BCACHE_SB_VERSION_BDEV; sb.magic = BCACHE_MAGIC; - uuid_generate(sb.uuid.b); + uuid_generate(sb.disk_uuid.b); + sb.user_uuid = user_uuid; sb.set_uuid = set_uuid; - sb.bucket_size = bucket_sizes[0]; sb.block_size = block_size; - uuid_unparse(sb.uuid.b, uuid_str); - uuid_unparse(sb.set_uuid.b, set_uuid_str); + uuid_unparse(sb.disk_uuid.b, uuid_str); + uuid_unparse(sb.user_uuid.b, set_uuid_str); if (label) memcpy(sb.label, label, SB_LABEL_SIZE); - SET_BDEV_CACHE_MODE(&sb, writeback - ? CACHE_MODE_WRITEBACK - : CACHE_MODE_WRITETHROUGH); + SET_BDEV_CACHE_MODE(&sb, mode); if (data_offset != BDEV_DATA_START_DEFAULT) { sb.version = BCACHE_SB_VERSION_BDEV_WITH_OFFSET; - sb.data_offset = data_offset; + sb.bdev_data_offset = data_offset; } sb.csum = csum_set(&sb, BCH_CSUM_CRC64); @@ -498,169 +528,37 @@ void write_backingdev_sb(int fd, unsigned block_size, unsigned *bucket_sizes, do_write_sb(fd, &sb); } -int dev_open(const char *dev, bool wipe_bcache) +int dev_open(const char *dev) { - struct cache_sb sb; blkid_probe pr; int fd; - char err[MAX_PATH]; - if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) { - sprintf(err, "Can't open dev %s: %s\n", dev, strerror(errno)); - goto err; - } + if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) + die("Can't open dev %s: %s\n", dev, strerror(errno)); - if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) { - sprintf(err, "Failed to read superblock"); - goto err; - } + if (!(pr = blkid_new_probe())) + die("Failed to create a new probe"); + if (blkid_probe_set_device(pr, fd, 0, 0)) + die("failed to set probe to device"); - if (!memcmp(&sb.magic, &BCACHE_MAGIC, 16) && !wipe_bcache) { - sprintf(err, "Already a bcache device on %s, " - "overwrite with --wipe-bcache\n", dev); - goto err; - } - - if (!(pr = blkid_new_probe())) { - sprintf(err, "Failed to create a new probe"); - goto err; - } - if (blkid_probe_set_device(pr, fd, 0, 0)) { - sprintf(err, "failed to set probe to device"); - goto err; - } /* enable ptable probing; superblock probing is enabled by default */ - if (blkid_probe_enable_partitions(pr, true)) { - sprintf(err, "Failed to enable partitions on probe"); - goto err; - } - if (!blkid_do_probe(pr)) { + if (blkid_probe_enable_partitions(pr, true)) + die("Failed to enable partitions on probe"); + + if (!blkid_do_probe(pr)) /* XXX wipefs doesn't know how to remove partition tables */ - sprintf(err, "Device %s already has a non-bcache superblock, " - "remove it using wipefs and wipefs -a\n", dev); - goto err; - } + die("Device %s already has a non-bcache superblock, " + "remove it using wipefs and wipefs -a\n", dev); return fd; - - err: - fprintf(stderr, "dev_open failed with: %s", err); - exit(EXIT_FAILURE); -} - -static unsigned min_bucket_size(int num_bucket_sizes, unsigned *bucket_sizes) -{ - int i; - unsigned min = bucket_sizes[0]; - - for (i = 0; i < num_bucket_sizes; i++) - min = bucket_sizes[i] < min ? bucket_sizes[i] : min; - - return min; } -static unsigned node_size(unsigned bucket_size) { - - if (bucket_size <= 256) - return bucket_size; - else if (bucket_size <= 512) - return bucket_size / 2; - else - return bucket_size / 4; -} - -void write_cache_sbs(int *fds, struct cache_sb *sb, - unsigned block_size, unsigned *bucket_sizes, - int num_bucket_sizes) -{ - char uuid_str[40], set_uuid_str[40]; - size_t i; - unsigned min_size = min_bucket_size(num_bucket_sizes, bucket_sizes); - - sb->offset = SB_SECTOR; - sb->version = BCACHE_SB_VERSION_CDEV_V3; - sb->magic = BCACHE_MAGIC; - sb->block_size = block_size; - sb->keys = bch_journal_buckets_offset(sb); - - /* - * don't have a userspace crc32c implementation handy, just always use - * crc64 - */ - SET_CACHE_SB_CSUM_TYPE(sb, BCH_CSUM_CRC64); - - for (i = 0; i < sb->nr_in_set; i++) { - struct cache_member *m = sb->members + i; - - if (num_bucket_sizes <= 1) - sb->bucket_size = bucket_sizes[0]; - else - sb->bucket_size = bucket_sizes[i]; - SET_CACHE_BTREE_NODE_SIZE(sb, node_size(min_size)); - - sb->uuid = m->uuid; - sb->nbuckets = getblocks(fds[i]) / sb->bucket_size; - sb->nr_this_dev = i; - sb->first_bucket = (23 / sb->bucket_size) + 1; - - if (sb->nbuckets < 1 << 7) { - fprintf(stderr, "Not enough buckets: %llu, need %u\n", - sb->nbuckets, 1 << 7); - exit(EXIT_FAILURE); - } - - sb->csum = csum_set(sb, CACHE_SB_CSUM_TYPE(sb)); - - uuid_unparse(sb->uuid.b, uuid_str); - uuid_unparse(sb->set_uuid.b, set_uuid_str); - printf("UUID: %s\n" - "Set UUID: %s\n" - "version: %u\n" - "nbuckets: %llu\n" - "block_size: %u\n" - "bucket_size: %u\n" - "nr_in_set: %u\n" - "nr_this_dev: %u\n" - "first_bucket: %u\n", - uuid_str, set_uuid_str, - (unsigned) sb->version, - sb->nbuckets, - sb->block_size, - sb->bucket_size, - sb->nr_in_set, - sb->nr_this_dev, - sb->first_bucket); - - do_write_sb(fds[i], sb); - } -} - -void next_cache_device(struct cache_sb *sb, - unsigned replication_set, - int tier, - unsigned replacement_policy, - bool discard) -{ - struct cache_member *m = sb->members + sb->nr_in_set; - - SET_CACHE_REPLICATION_SET(m, replication_set); - SET_CACHE_TIER(m, tier); - SET_CACHE_REPLACEMENT(m, replacement_policy); - SET_CACHE_DISCARD(m, discard); - uuid_generate(m->uuid.b); - - sb->nr_in_set++; -} - -unsigned get_blocksize(const char *path) +unsigned get_blocksize(const char *path, int fd) { struct stat statbuf; - if (stat(path, &statbuf)) { - fprintf(stderr, "Error statting %s: %s\n", - path, strerror(errno)); - exit(EXIT_FAILURE); - } + if (fstat(fd, &statbuf)) + die("Error statting %s: %s", path, strerror(errno)); if (S_ISBLK(statbuf.st_mode)) { /* check IO limits: @@ -676,17 +574,9 @@ unsigned get_blocksize(const char *path) * we want to use logical_block_size. */ unsigned int logical_block_size; - int fd = open(path, O_RDONLY); + if (ioctl(fd, BLKSSZGET, &logical_block_size)) + die("ioctl(%s, BLKSSZGET) failed: %m", path); - if (fd < 0) { - fprintf(stderr, "open(%s) failed: %m\n", path); - exit(EXIT_FAILURE); - } - if (ioctl(fd, BLKSSZGET, &logical_block_size)) { - fprintf(stderr, "ioctl(%s, BLKSSZGET) failed: %m\n", path); - exit(EXIT_FAILURE); - } - close(fd); return logical_block_size / 512; } @@ -700,10 +590,8 @@ long strtoul_or_die(const char *p, size_t max, const char *msg) { errno = 0; long v = strtol(p, NULL, 10); - if (errno || v < 0 || v >= max) { - fprintf(stderr, "Invalid %s %zi\n", msg, v); - exit(EXIT_FAILURE); - } + if (errno || v < 0 || v >= max) + die("Invalid %s %zi", msg, v); return v; } @@ -719,7 +607,7 @@ static void print_encode(char *in) } static void show_uuid_only(struct cache_sb *sb, char *dev_uuid) { - uuid_unparse(sb->uuid.b, dev_uuid); + uuid_unparse(sb->disk_uuid.b, dev_uuid); } static void show_super_common(struct cache_sb *sb, bool force_csum) @@ -733,8 +621,7 @@ static void show_super_common(struct cache_sb *sb, bool force_csum) printf("ok\n"); } else { printf("bad magic\n"); - fprintf(stderr, "Invalid superblock (bad magic)\n"); - exit(2); + die("Invalid superblock (bad magic)"); } printf("sb.first_sector\t\t%ju", (uint64_t) sb->offset); @@ -742,8 +629,7 @@ static void show_super_common(struct cache_sb *sb, bool force_csum) printf(" [match]\n"); } else { printf(" [expected %ds]\n", SB_SECTOR); - fprintf(stderr, "Invalid superblock (bad sector)\n"); - exit(2); + die("Invalid superblock (bad sector)"); } printf("sb.csum\t\t\t%ju", (uint64_t) sb->csum); @@ -755,10 +641,8 @@ static void show_super_common(struct cache_sb *sb, bool force_csum) printf(" [match]\n"); } else { printf(" [expected %" PRIX64 "]\n", expected_csum); - if (!force_csum) { - fprintf(stderr, "Corrupt superblock (bad csum)\n"); - exit(2); - } + if (force_csum) + die("Corrupt superblock (bad csum)"); } printf("sb.version\t\t%ju", (uint64_t) sb->version); @@ -792,11 +676,15 @@ static void show_super_common(struct cache_sb *sb, bool force_csum) printf("(empty)"); putchar('\n'); - uuid_unparse(sb->uuid.b, uuid); + uuid_unparse(sb->disk_uuid.b, uuid); printf("dev.uuid\t\t%s\n", uuid); - uuid_unparse(sb->set_uuid.b, uuid); + uuid_unparse(sb->user_uuid.b, uuid); printf("cset.uuid\t\t%s\n", uuid); + + uuid_unparse(sb->set_uuid.b, uuid); + printf("internal.uuid\t%s\n", uuid); + } void show_super_backingdev(struct cache_sb *sb, bool force_csum) @@ -808,12 +696,7 @@ void show_super_backingdev(struct cache_sb *sb, bool force_csum) if (sb->version == BCACHE_SB_VERSION_BDEV) { first_sector = BDEV_DATA_START_DEFAULT; } else { - if (sb->keys == 1 || sb->d[0]) { - fprintf(stderr, - "Possible experimental format detected, bailing\n"); - exit(3); - } - first_sector = sb->data_offset; + first_sector = sb->bdev_data_offset; } printf("dev.data.first_sector\t%ju\n" @@ -824,32 +707,20 @@ void show_super_backingdev(struct cache_sb *sb, bool force_csum) bdev_state[BDEV_STATE(sb)]); } -static void show_cache_member(struct cache_sb *sb, unsigned i) -{ - struct cache_member *m = ((struct cache_member *) sb->d) + i; - - printf("cache.state\t%s\n", cache_state[CACHE_STATE(m)]); - printf("cache.tier\t%llu\n", CACHE_TIER(m)); - - printf("cache.replication_set\t%llu\n", CACHE_REPLICATION_SET(m)); - printf("cache.cur_meta_replicas\t%llu\n", REPLICATION_SET_CUR_META_REPLICAS(m)); - printf("cache.cur_data_replicas\t%llu\n", REPLICATION_SET_CUR_DATA_REPLICAS(m)); - - printf("cache.has_metadata\t%llu\n", CACHE_HAS_METADATA(m)); - printf("cache.has_data\t%llu\n", CACHE_HAS_DATA(m)); - - printf("cache.replacement\t%s\n", replacement_policies[CACHE_REPLACEMENT(m)]); - printf("cache.discard\t%llu\n", CACHE_DISCARD(m)); -} - void show_super_cache(struct cache_sb *sb, bool force_csum) { + struct cache_member *m = sb->members + sb->nr_this_dev; + char uuid[16]; + show_super_common(sb, force_csum); + uuid_unparse(m->uuid.b, uuid); + printf("dev.cache.uuid\t%s\n", uuid); + printf("dev.sectors_per_block\t%u\n" "dev.sectors_per_bucket\t%u\n", sb->block_size, - sb->bucket_size); + m->bucket_size); // total_sectors includes the superblock; printf("dev.cache.first_sector\t%u\n" @@ -858,26 +729,36 @@ void show_super_cache(struct cache_sb *sb, bool force_csum) "dev.cache.ordered\t%s\n" "dev.cache.pos\t\t%u\n" "dev.cache.setsize\t\t%u\n", - sb->bucket_size * sb->first_bucket, - sb->bucket_size * (sb->nbuckets - sb->first_bucket), - sb->bucket_size * sb->nbuckets, + m->bucket_size * m->first_bucket, + m->bucket_size * (m->nbuckets - m->first_bucket), + m->bucket_size * m->nbuckets, CACHE_SYNC(sb) ? "yes" : "no", sb->nr_this_dev, sb->nr_in_set); - show_cache_member(sb, sb->nr_this_dev); + printf("cache.state\t%s\n", cache_state[CACHE_STATE(m)]); + + printf("cache.tier\t%llu\n", CACHE_TIER(m)); + + printf("cache.replication_set\t%llu\n", CACHE_REPLICATION_SET(m)); + + printf("cache.has_metadata\t%llu\n", CACHE_HAS_METADATA(m)); + printf("cache.has_data\t%llu\n", CACHE_HAS_DATA(m)); + + printf("cache.replacement\t%s\n", replacement_policies[CACHE_REPLACEMENT(m)]); + printf("cache.discard\t%llu\n", CACHE_DISCARD(m)); } -static int __sysfs_attr_type(char *attr, const char **attr_arr) { - int i, j; - for(i = 0; attr_arr[i] != NULL; i++) +static int __sysfs_attr_type(const char *attr, const char * const *attr_arr) +{ + for (unsigned i = 0; attr_arr[i] != NULL; i++) if(!strcmp(attr, attr_arr[i])) return 1; return 0; } -enum sysfs_attr sysfs_attr_type(char *attr) { - int ret; +enum sysfs_attr sysfs_attr_type(const char *attr) +{ if(__sysfs_attr_type(attr, set_attrs)) return SET_ATTR; if(__sysfs_attr_type(attr, cache_attrs)) @@ -890,13 +771,14 @@ enum sysfs_attr sysfs_attr_type(char *attr) { return -1; } -static void __sysfs_attr_list(const char **attr_arr) { - int i, j; - for (i = 0; attr_arr[i] != NULL; i++) +static void __sysfs_attr_list(const char * const *attr_arr) +{ + for (unsigned i = 0; attr_arr[i] != NULL; i++) printf("%s\n", attr_arr[i]); } -void sysfs_attr_list() { +void sysfs_attr_list() +{ __sysfs_attr_list(set_attrs); __sysfs_attr_list(cache_attrs); __sysfs_attr_list(internal_attrs); @@ -905,30 +787,39 @@ void sysfs_attr_list() { struct cache_sb *query_dev(char *dev, bool force_csum, bool print_sb, bool uuid_only, char *dev_uuid) { - struct cache_sb sb_stack, *sb = &sb_stack; - size_t bytes = sizeof(*sb); + size_t bytes = 4096; + struct cache_sb *sb = aligned_alloc(bytes, bytes); - int fd = open(dev, O_RDONLY); + int fd = open(dev, O_RDONLY|O_DIRECT); if (fd < 0) { printf("Can't open dev %s: %s\n", dev, strerror(errno)); - exit(2); + return NULL; } - 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); + while (true) { + int ret = pread(fd, sb, bytes, SB_START); + if (ret < 0) { + fprintf(stderr, "Couldn't read superblock: %s\n", + strerror(errno)); + close(fd); + free(sb); + return NULL; + } else if (bytes > sizeof(sb) + sb->u64s * sizeof(u64)) { + /* We read the whole superblock */ + break; } + + /* + * otherwise double the size of our dest + * and read again + */ + free(sb); + bytes *= 2; + sb = aligned_alloc(4096, bytes); } + close(fd); + if(uuid_only) { show_uuid_only(sb, dev_uuid); return sb; @@ -944,7 +835,7 @@ struct cache_sb *query_dev(char *dev, bool force_csum, return sb; } -static void dev_name(const char *ugly_path) { +char *dev_name(const char *ugly_path) { char buf[32]; int i, end = strlen(ugly_path); @@ -958,46 +849,60 @@ static void dev_name(const char *ugly_path) { // Is the dev guaranteed to be in /dev? // This is needed for finding the superblock with a query-dev - printf("/dev%s\n", buf); + return strdup(buf); } -static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_name) { - int i = 0; - DIR *cachedir; +static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_name) +{ + DIR *cachedir, *dir; struct stat cache_stat; - char intbuf[4]; char entry[MAX_PATH]; - - snprintf(entry, MAX_PATH, "%s/%s/cache0", cset_dir, cset_name); - snprintf(intbuf, 4, "%d", i); - - while(true) { - char buf[MAX_PATH]; - int len; - - if((cachedir = opendir(entry)) == NULL) - break; - - if(stat(entry, &cache_stat)) - break; - - if((len = readlink(entry, buf, sizeof(buf) - 1)) != -1) { - buf[len] = '\0'; - if(parse_dev_name) - dev_name(buf); - else - printf("\t%s\n", buf); + struct dirent *ent; + snprintf(entry, MAX_PATH, "%s/%s", cset_dir, cset_name); + + if((dir = opendir(entry)) != NULL) { + while((ent = readdir(dir)) != NULL) { + char buf[MAX_PATH]; + int len; + char *tmp; + + /* + * We are looking for all cache# directories + * do a strlen < 9 to skip over other entries + * that also start with "cache" + */ + if(strncmp(ent->d_name, "cache", 5) || + !(strlen(ent->d_name) < 9)) + continue; + + snprintf(entry, MAX_PATH, "%s/%s/%s", + cset_dir, + cset_name, + ent->d_name); + + if((cachedir = opendir(entry)) == NULL) + continue; + + if(stat(entry, &cache_stat)) + continue; + + if((len = readlink(entry, buf, sizeof(buf) - 1)) != + -1) { + buf[len] = '\0'; + if(parse_dev_name) { + tmp = dev_name(buf); + printf("/dev%s\n", tmp); + free(tmp); + } else { + printf("\t%s\n", buf); + } + } } - - /* remove i from end and append i++ */ - entry[strlen(entry)-strlen(intbuf)] = 0; - i++; - snprintf(intbuf, 4, "%d", i); - strcat(entry, intbuf); } } -char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uuid) { +char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uuid) +{ /* Do a query-dev --uuid only to get the uuid * repeat on each dev until we find a matching one * append that cache# to subdir and return @@ -1029,6 +934,7 @@ char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uu buf[len] = '\0'; int i, end = strlen(buf); char tmp[32], devname[32]; + struct cache_sb *sb; /* Chop off "/bcache", then look for the * next '/' from the end @@ -1042,10 +948,16 @@ char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uu strcpy(devname, "/dev"); strcat(devname, tmp); - query_dev(devname, false, false, true, dev_uuid); + err = "Unable to open superblock"; + sb = query_dev(devname, false, false, true, dev_uuid); + if(!sb) + return err; + else + free(sb); + if(!strcmp(stats_dev_uuid, dev_uuid)) { strcat(subdir, intbuf); - return err; + return NULL; } } @@ -1131,13 +1043,13 @@ char *unregister_bcache(char *const *devs) int ret, bcachefd; char *err = NULL; - bcachefd = open("/dev/bcache", O_RDWR); + bcachefd = open("/dev/bcache_extent0", O_RDWR); if (bcachefd < 0) { err = "Can't open bcache device"; goto err; } - ret = ioctl(bcachefd, BCH_IOCTL_UNREGISTER, devs); + ret = ioctl(bcachefd, BCH_IOCTL_STOP); if (ret < 0) { char tmp[64]; snprintf(tmp, 64, "ioctl unregister error: %s\n", @@ -1151,12 +1063,12 @@ err: return err; } -char *add_devices(char *const *devs, char *uuid) +char *add_devices(char *const *devs) { int ret, bcachefd; char *err = NULL; - bcachefd = open("/dev/bcache", O_RDWR); + bcachefd = open("/dev/bcache_extent0", O_RDWR); if (bcachefd < 0) { err = "Can't open bcache device"; goto err; @@ -1164,7 +1076,6 @@ char *add_devices(char *const *devs, char *uuid) struct bch_ioctl_add_disks ia; ia.devs = devs; - ia.uuid = uuid; ret = ioctl(bcachefd, BCH_IOCTL_ADD_DISKS, &ia); if (ret < 0) { @@ -1184,7 +1095,7 @@ char *remove_device(const char *dev, bool force) int ret, bcachefd; char *err = NULL; - bcachefd = open("/dev/bcache", O_RDWR); + bcachefd = open("/dev/bcache_extent0", O_RDWR); if (bcachefd < 0) { err = "Can't open bcache device"; goto err; @@ -1207,6 +1118,34 @@ err: return err; } +char *device_set_failed(const char *dev_uuid) { + int ret, bcachefd; + char *err = NULL; + uuid_le dev; + struct bch_ioctl_disk_failed df; + + bcachefd = open("/dev/bcache_extent0", O_RDWR); + if (bcachefd < 0) { + err = "Can't open bcache device"; + goto err; + } + + uuid_parse(dev_uuid, dev.b); + df.dev_uuid = dev; + + ret = ioctl(bcachefd, BCH_IOCTL_SET_DISK_FAILED, &df); + if (ret < 0) { + char tmp[128]; + snprintf(tmp, 128, "ioctl set disk failed error %s\n", + strerror(ret)); + err = strdup(tmp); + } + +err: + close(bcachefd); + return err; +} + char *probe(char *dev, int udev) { struct cache_sb sb; @@ -1253,7 +1192,7 @@ char *probe(char *dev, int udev) goto err; } - uuid_unparse(sb.uuid.b, uuid); + uuid_unparse(sb.disk_uuid.b, uuid); if (udev) printf("ID_FS_UUID=%s\n" @@ -1269,7 +1208,7 @@ err: return err; } -char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) +char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, char *ret) { struct stat statbuf; char entry[MAX_PATH]; @@ -1284,7 +1223,6 @@ char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) } if (S_ISREG(statbuf.st_mode)) { - char buf[MAX_PATH]; FILE *fp = NULL; fp = fopen(entry, "r"); @@ -1294,14 +1232,101 @@ char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) return NULL; } - while(fgets(buf, MAX_PATH, fp)); + while(fgets(ret, MAX_PATH, fp)); + fclose(fp); + } +err: + return err; +} + +char *bcache_get_capacity(const char *cset_dir, const char *capacity_uuid, + bool show_devs) +{ + char *err = NULL; + char bucket_size_path[MAX_PATH]; + char nbuckets_path[MAX_PATH]; + char avail_buckets_path[MAX_PATH]; + char cache_path[MAX_PATH]; + + double bucket_sizes[MAX_DEVS]; + double nbuckets[MAX_DEVS]; + double avail_buckets[MAX_DEVS]; + char *dev_names[MAX_DEVS]; + int dev_count = 0, i; + double total_cap = 0, total_free = 0; + int precision = 2; + + + while (true) { + char buf[MAX_PATH]; + int len; + DIR *cache_dir; + + snprintf(bucket_size_path, sizeof(bucket_size_path), "%s/%s/%s%d/%s", cset_dir, + capacity_uuid, "cache", dev_count, "bucket_size_bytes"); + snprintf(nbuckets_path, sizeof(nbuckets_path), "%s/%s/%s%d/%s", cset_dir, + capacity_uuid, "cache", dev_count, "nbuckets"); + snprintf(avail_buckets_path, sizeof(avail_buckets_path), "%s/%s/%s%d/%s", cset_dir, + capacity_uuid, "cache", dev_count, "available_buckets"); + snprintf(cache_path, sizeof(cache_path), "%s/%s/%s%d", cset_dir, capacity_uuid, + "cache", dev_count); + + if((cache_dir = opendir(cache_path)) == NULL) + break; + + err = read_stat_dir(cache_dir, cache_path, + "bucket_size_bytes", buf); + if (err) + goto err; + else + bucket_sizes[dev_count] = atof(buf); - if(print_val) - printf("%s\n", buf); + err = read_stat_dir(cache_dir, cache_path, + "nbuckets", buf); + if (err) + goto err; else - printf("%s\n", stat_name); - fclose(fp); + nbuckets[dev_count] = atof(buf); + + err = read_stat_dir(cache_dir, cache_path, + "available_buckets", buf); + if (err) + goto err; + else + avail_buckets[dev_count] = atof(buf); + + if((len = readlink(cache_path, buf, sizeof(buf) - 1)) != -1) { + buf[len] = '\0'; + dev_names[dev_count] = dev_name(buf); + } + + dev_count++; + } + + printf("%-15s%-25s%-25s\n", "Device Name", "Capacity (512 Blocks)", "Free (512 Blocks)"); + + if (show_devs) { + for (i = 0; i < dev_count; i++) { + printf("%s%-11s%-25.*f%-25.*f\n", "/dev", dev_names[i], + precision, + (bucket_sizes[i] * nbuckets[i]) / 512, + precision, + (bucket_sizes[i] * avail_buckets[i]) / 512); + } } + + for (i = 0; i < dev_count; i++) { + total_cap += (bucket_sizes[i] * nbuckets[i]) / 512; + total_free += (bucket_sizes[i] * avail_buckets[i]) / 512; + + } + + printf("%-15s%-25.*f%-25.*f\n", "Total", precision, total_cap, + precision, total_free); + err: + for (i = 0; i < dev_count; i++) + if (dev_names[i]) + free(dev_names[i]); return err; }