diff --git a/bcache.c b/bcache.c index 366962cd..d1ae1a6f 100644 --- a/bcache.c +++ b/bcache.c @@ -896,7 +896,6 @@ int list_cachesets(char *cset_dir) fprintf(stderr, "Failed to open dir %s\n", cset_dir); return 1; } - printf("cachesets:\n"); while ((ent = readdir(dir)) != NULL) { struct stat statbuf; @@ -913,7 +912,7 @@ int list_cachesets(char *cset_dir) return 1; } if (S_ISDIR(statbuf.st_mode)) { - printf("\t%s\n", ent->d_name); + printf("%s\n", ent->d_name); } } @@ -1014,3 +1013,37 @@ void sb_state(struct cache_sb *sb, char *dev) printf("\tseq#: \t%llu\n", sb->seq); } + +void read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) +{ + struct stat statbuf; + char entry[150]; + + strcpy(entry, stats_dir); + strcat(entry, "/"); + strcat(entry, stat_name); + if(stat(entry, &statbuf) == -1) { + fprintf(stderr, "Failed to stat %s\n", entry); + return; + } + + if (S_ISREG(statbuf.st_mode)) { + char buf[100]; + FILE *fp = NULL; + + 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; + } + + while(fgets(buf, 100, fp)); + + if(print_val) + printf("%s\t%s", stat_name, buf); + else + printf("%s\n", stat_name); + fclose(fp); + } +} diff --git a/bcache.h b/bcache.h index c81d12fb..69b3345b 100644 --- a/bcache.h +++ b/bcache.h @@ -8,6 +8,7 @@ #define _BCACHE_H #include +#include typedef __u8 u8; typedef __u16 u16; @@ -63,6 +64,7 @@ int register_bcache(); int probe(char *, int); void print_dev_info(struct cache_sb *, bool); void sb_state(struct cache_sb *, char *); +void read_stat_dir(DIR *, char *, char *, bool); #define csum_set(i, type) \ diff --git a/bcacheadm.c b/bcacheadm.c index d9a9c462..29fe1249 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include //libbcache #define PACKAGE_NAME "bcacheadm" @@ -60,7 +61,7 @@ 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; +struct cache_sb *cache_set_sb = NULL; enum long_opts { CACHE_SET_UUID = 256, CSUM_TYPE, @@ -79,6 +80,14 @@ bool udev = false; /* list globals */ char *cset_dir = "/sys/fs/bcache"; +/* status globals */ +bool status_all = false; + +/* stats globals */ +bool stats_all = false; +bool stats_list = false; +static const char *stats_uuid = NULL; + /* make-bcache option setters */ static int set_CACHE_SET_UUID(NihOption *option, const char *arg) { @@ -145,7 +154,6 @@ static int set_bucket_sizes(NihOption *option, const char *arg) return 0; } - /* probe setters */ static int set_udev(NihOption *option, const char *arg) { @@ -205,6 +213,14 @@ static NihOption list_cachesets_options[] = { }; static NihOption status_options[] = { + {'a', "all", N_("all"), NULL, NULL, &status_all, NULL}, + NIH_OPTION_LAST +}; + +static NihOption stats_options[] = { + {'a', "all", N_("all"), NULL, NULL, &stats_all, NULL}, + {'l', "list", N_("list"), NULL, NULL, &stats_list, NULL}, + {'u', "uuid", N_("cache_set UUID"), NULL, "UUID", &stats_uuid, NULL}, NIH_OPTION_LAST }; @@ -345,6 +361,49 @@ int bcache_status (NihCommand *command, char *const *args) if (sb_tier1) sb_state(sb_tier1, dev1); } +int bcache_stats (NihCommand *command, char *const *args) +{ + /* all prints out a STAT:\tVALUE table + * list prints out a list of all STATS + * args contains a list of STAT, and prints their VALUE + */ + int i; + char *stats_dir = NULL; + DIR *dir = NULL; + struct dirent *ent = NULL; + + if (stats_uuid) { + /* + * dev or uuid must be passed in + * check that the given has an existing STAT directory + */ + stats_dir = (char*)malloc(sizeof(char)* + (strlen(cset_dir) + + strlen(stats_uuid) + 2)); + strcpy(stats_dir, cset_dir); + strcat(stats_dir, "/"); + strcat(stats_dir, stats_uuid); + + dir = opendir(stats_dir); + if (!dir) { + fprintf(stderr, "Failed to open dir %s\n", cset_dir); + return 1; + } + } else { + printf("Must provide a cacheset uuid\n"); + exit(EXIT_FAILURE); + } + + if(stats_list || stats_all) + while ((ent = readdir(dir)) != NULL) + read_stat_dir(dir, stats_dir, ent->d_name, stats_all); + + for (i = 0; args[i] != NULL; i++) + read_stat_dir(dir, stats_dir, args[i], true); + + closedir(dir); +} + static NihCommand commands[] = { {"format", N_("format "), "Format one or a list of devices with bcache datastructures." @@ -371,6 +430,10 @@ static NihCommand commands[] = { "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}, + {"stats", N_("stats "), + "List various bcache statistics", + N_("List various bcache statistics"), + NULL, stats_options, bcache_stats}, NIH_COMMAND_LAST };