#include "bcache.h"
-#define __KERNEL__
-#include <linux/bcache-ioctl.h>
-#undef __KERNEL__
-
const char * const cache_state[] = {
"active",
"ro",
NULL
};
+const char * const compression_types[] = {
+ "none",
+ "lzo1x",
+ "gzip",
+ "xz",
+ NULL
+};
+
+const char * const error_actions[] = {
+ "continue",
+ "readonly",
+ "panic",
+ NULL
+};
+
const char * const bdev_cache_mode[] = {
"writethrough",
"writeback",
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;
}
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);
}
}
{
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)
-{
- char zeroes[SB_START] = {0};
- size_t bytes = ((void *) __bset_bkey_last(sb)) - (void *) sb;
-
- /* Zero start of disk */
- if (pwrite(fd, zeroes, SB_START, 0) != SB_START) {
- perror("write error trying to zero start of disk\n");
- exit(EXIT_FAILURE);
- }
- /* Write superblock */
- if (pwrite(fd, sb, bytes, SB_START) != bytes) {
- perror("write error trying to write superblock\n");
- exit(EXIT_FAILURE);
- }
-
- fsync(fd);
- close(fd);
-}
-
-void write_backingdev_sb(int fd, unsigned block_size, unsigned *bucket_sizes,
- 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;
-
- memset(&sb, 0, sizeof(struct cache_sb));
-
- sb.offset = SB_SECTOR;
- sb.version = BCACHE_SB_VERSION_BDEV;
- sb.magic = BCACHE_MAGIC;
- uuid_generate(sb.disk_uuid.b);
- sb.user_uuid = user_uuid;
- sb.set_uuid = set_uuid;
- sb.block_size = block_size;
-
- uuid_unparse(sb.disk_uuid.b, uuid_str);
- uuid_unparse(sb.set_uuid.b, set_uuid_str);
- if (label)
- memcpy(sb.label, label, SB_LABEL_SIZE);
-
- SET_BDEV_CACHE_MODE(&sb, mode);
-
- if (data_offset != BDEV_DATA_START_DEFAULT) {
- sb.version = BCACHE_SB_VERSION_BDEV_WITH_OFFSET;
- sb.bdev_data_offset = data_offset;
- }
-
- sb.csum = csum_set(&sb, BCH_CSUM_CRC64);
-
- printf("UUID: %s\n"
- "Set UUID: %s\n"
- "version: %u\n"
- "block_size: %u\n"
- "data_offset: %ju\n",
- uuid_str, set_uuid_str,
- (unsigned) sb.version,
- sb.block_size,
- data_offset);
-
- 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;
-}
-
-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->u64s = 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) {
- m->bucket_size = bucket_sizes[0];
- } else {
- if (!bucket_sizes[i]) {
- printf("No bucket size specified for cache %zu,"
- " using the default of %u",
- i, bucket_sizes[0]);
- m->bucket_size = bucket_sizes[0];
- } else {
- m->bucket_size = bucket_sizes[i];
- }
- }
-
- m->nbuckets = getblocks(fds[i]) / m->bucket_size;
- m->first_bucket = (23 / m->bucket_size) + 1;
-
- if (m->nbuckets < 1 << 7) {
- fprintf(stderr, "Not enough buckets: %llu, need %u\n",
- m->nbuckets, 1 << 7);
- exit(EXIT_FAILURE);
- }
- }
-
- for (i = 0; i < sb->nr_in_set; i++) {
- struct cache_member *m = sb->members + i;
-
- SET_CACHE_BTREE_NODE_SIZE(sb, min_size);
-
-
- sb->disk_uuid = m->uuid;
- sb->nr_this_dev = i;
-
- sb->csum = csum_set(sb, CACHE_SB_CSUM_TYPE(sb));
-
- uuid_unparse(sb->disk_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,
- m->nbuckets,
- sb->block_size,
- m->bucket_size,
- sb->nr_in_set,
- sb->nr_this_dev,
- m->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:
* 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;
}
{
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;
}
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);
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);
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);
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)
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,
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));
return strdup(buf);
}
-static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_name)
-{
- DIR *cachedir, *dir;
- struct stat cache_stat;
- char entry[MAX_PATH];
- 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);
- }
- }
- }
- }
-}
-
char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uuid)
{
/* Do a query-dev --uuid only to get the uuid
return err;
}
-char *list_cachesets(char *cset_dir, bool list_devs)
-{
- struct dirent *ent;
- DIR *dir;
- char *err = NULL;
-
- dir = opendir(cset_dir);
- if (!dir) {
- err = "Failed to open cacheset dir";
- goto err;
- }
-
- while ((ent = readdir(dir)) != NULL) {
- struct stat statbuf;
- char entry[MAX_PATH];
-
- if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
- continue;
-
- snprintf(entry, MAX_PATH, "%s/%s", cset_dir, ent->d_name);
- if(stat(entry, &statbuf) == -1) {
- err = "Failed to stat cacheset subdir";
- goto err;
- }
-
- if (S_ISDIR(statbuf.st_mode)) {
- printf("%s\n", ent->d_name);
-
- if(list_devs) {
- list_cacheset_devs(cset_dir, ent->d_name, true);
- }
- }
- }
-
-err:
- closedir(dir);
- return err;
-}
-
-char *register_bcache(char *const *devs)
+int bcachectl_open(void)
{
- int ret, bcachefd;
- char *err = NULL;
-
- bcachefd = open("/dev/bcache", O_RDWR);
- if (bcachefd < 0) {
- err = "Can't open bcache device";
- goto err;
- }
+ int fd = open("/dev/bcache-ctl", O_RDWR);
+ if (fd < 0)
+ die("Can't open bcache device: %s", strerror(errno));
- ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, devs);
- if (ret < 0) {
- char tmp[64];
- snprintf(tmp, 64, "ioctl register error: %s\n",
- strerror(ret));
- err = strdup(tmp);
- goto err;
- }
-
-err:
- if (bcachefd)
- close(bcachefd);
- return err;
-}
-
-char *unregister_bcache(char *const *devs)
-{
- int ret, bcachefd;
- char *err = NULL;
-
- bcachefd = open("/dev/bcache_extent0", O_RDWR);
- if (bcachefd < 0) {
- err = "Can't open bcache device";
- goto err;
- }
-
- ret = ioctl(bcachefd, BCH_IOCTL_STOP);
- if (ret < 0) {
- char tmp[64];
- snprintf(tmp, 64, "ioctl unregister error: %s\n",
- strerror(ret));
- err = strdup(tmp);
- goto err;
- }
-
-err:
- close(bcachefd);
- return err;
-}
-
-char *add_devices(char *const *devs)
-{
- int ret, bcachefd;
- char *err = NULL;
-
- bcachefd = open("/dev/bcache_extent0", O_RDWR);
- if (bcachefd < 0) {
- err = "Can't open bcache device";
- goto err;
- }
-
- struct bch_ioctl_add_disks ia;
- ia.devs = devs;
-
- ret = ioctl(bcachefd, BCH_IOCTL_ADD_DISKS, &ia);
- if (ret < 0) {
- char tmp[128];
- snprintf(tmp, 128, "ioctl add disk error: %s\n",
- strerror(ret));
- err = strdup(tmp);
- }
-
-err:
- close(bcachefd);
- return err;
-}
-
-char *remove_device(const char *dev, bool force)
-{
- int ret, bcachefd;
- char *err = NULL;
-
- bcachefd = open("/dev/bcache_extent0", O_RDWR);
- if (bcachefd < 0) {
- err = "Can't open bcache device";
- goto err;
- }
-
- struct bch_ioctl_rm_disk ir;
- ir.dev = dev;
- ir.force = force ? 1 : 0;
-
- ret = ioctl(bcachefd, BCH_IOCTL_RM_DISK, &ir);
- if (ret < 0) {
- char tmp[128];
- snprintf(tmp, 128, "ioctl add disk error: %s\n",
- strerror(ret));
- err = strdup(tmp);
- }
-
-err:
- close(bcachefd);
- 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;
- char uuid[40];
- blkid_probe pr;
- char *err = NULL;
-
- int fd = open(dev, O_RDONLY);
- if (fd == -1) {
- err = "Got file descriptor -1 trying to open dev";
- goto err;
- }
-
- if (!(pr = blkid_new_probe())) {
- err = "Failed trying to get a blkid for new probe";
- goto err;
- }
-
- if (blkid_probe_set_device(pr, fd, 0, 0)) {
- err = "Failed blkid probe set device";
- goto err;
- }
-
- /* probe partitions too */
- if (blkid_probe_enable_partitions(pr, true)) {
- err = "Enable probe partitions";
- goto err;
- }
-
- /* bail if anything was found
- * probe-bcache isn't needed once blkid recognizes bcache */
- if (!blkid_do_probe(pr)) {
- err = "blkid recognizes bcache";
- goto err;
- }
-
- if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) {
- err = "Failed to read superblock";
- goto err;
- }
-
- if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic))) {
- err = "Bcache magic incorrect";
- goto err;
- }
-
- uuid_unparse(sb.disk_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;
-
-err:
- return err;
+ return fd;
}
-char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, char *ret)
+unsigned nr_args(char *const *args)
{
- struct stat statbuf;
- char entry[MAX_PATH];
- char *err = NULL;
-
- snprintf(entry, MAX_PATH, "%s/%s", stats_dir, stat_name);
- if(stat(entry, &statbuf) == -1) {
- char tmp[MAX_PATH];
- snprintf(tmp, MAX_PATH, "Failed to stat %s\n", entry);
- err = strdup(tmp);
- goto err;
- }
-
- if (S_ISREG(statbuf.st_mode)) {
- FILE *fp = NULL;
+ unsigned i;
- fp = fopen(entry, "r");
- if(!fp) {
- /* If we can't open the file, this is probably because
- * of permissions, just move to the next file */
- return NULL;
- }
+ for (i = 0; args[i]; i++)
+ ;
- 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;
- char intbuf[4];
- double total_cap = 0, total_free = 0;
- int precision = 2;
-
- snprintf(bucket_size_path, MAX_PATH, "%s/%s/%s/%s", cset_dir,
- capacity_uuid, "cache0", "bucket_size_bytes");
- snprintf(nbuckets_path, MAX_PATH, "%s/%s/%s/%s", cset_dir,
- capacity_uuid, "cache0", "nbuckets");
- snprintf(avail_buckets_path, MAX_PATH, "%s/%s/%s/%s", cset_dir,
- capacity_uuid, "cache0", "available_buckets");
- snprintf(cache_path, MAX_PATH, "%s/%s/%s", cset_dir, capacity_uuid,
- "cache0");
-
- while (true) {
- char buf[MAX_PATH];
- int len;
- DIR *cache_dir;
-
- 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);
-
- err = read_stat_dir(cache_dir, cache_path,
- "nbuckets", buf);
- if (err)
- goto err;
- else
- 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);
- }
-
- snprintf(intbuf, 4, "%d", dev_count);
-
- /* remove i/stat and append i++/stat */
- bucket_size_path[strlen(cache_path) - strlen(intbuf)] = 0;
- nbuckets_path[strlen(cache_path) - strlen(intbuf)] = 0;
- avail_buckets_path[strlen(cache_path) - strlen(intbuf)] = 0;
- cache_path[strlen(cache_path) - strlen(intbuf)] = 0;
-
- dev_count++;
-
- strcat(cache_path, intbuf);
- strcat(bucket_size_path, intbuf);
- strcat(nbuckets_path, intbuf);
- strcat(avail_buckets_path, intbuf);
- }
-
- 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;
+ return i;
}