diff --git a/bcache.c b/bcache.c index fb3931ed..a69a46fb 100644 --- a/bcache.c +++ b/bcache.c @@ -906,30 +906,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)); return NULL; } - if (pread(fd, sb, bytes, SB_START) != bytes) { - fprintf(stderr, "Couldn't read\n"); - return NULL; - } - - 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"); + 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->keys * 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; @@ -1061,6 +1070,8 @@ char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uu 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); diff --git a/bcacheadm.c b/bcacheadm.c index 623ea830..f7b92cdf 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -559,6 +559,7 @@ int bcache_query_devs(NihCommand *command, char *const *args) set_uuid_str, clus_uuid); } + free(sb); } return 0; @@ -582,7 +583,8 @@ int bcache_status(NihCommand *command, char *const *args) seq = sb->seq; seq_sb = sb; nr_in_set = sb->nr_in_set; - } + } else + free(sb); } if(!seq_sb) @@ -601,6 +603,9 @@ int bcache_status(NihCommand *command, char *const *args) CACHE_TIER(m)); } + if(seq_sb) + free(seq_sb); + return 0; }