diff --git a/math_utils.h b/math_utils.h index d7f01fd..e02c0b6 100644 --- a/math_utils.h +++ b/math_utils.h @@ -9,6 +9,13 @@ namespace base { T div_up(T const &v, T const &divisor) { return (v + (divisor - 1)) / divisor; } + + // Seemingly pointless function, but it coerces the arguments + // nicely. + template + T div_down(T const &v, T const &divisor) { + return v / divisor; + } } //---------------------------------------------------------------- diff --git a/metadata.cc b/metadata.cc index 59f157b..a03bf66 100644 --- a/metadata.cc +++ b/metadata.cc @@ -2,6 +2,7 @@ #include "btree_checker.h" #include "core_map.h" +#include "math_utils.h" #include #include @@ -9,6 +10,13 @@ #include #include +#include +#include +#include +#include +#include + +using namespace base; using namespace std; using namespace persistent_data; using namespace thin_provisioning; @@ -22,13 +30,42 @@ namespace { unsigned const METADATA_CACHE_SIZE = 1024; unsigned const SECTOR_TO_BLOCK_SHIFT = 3; - // FIXME: get the file size - unsigned const NR_BLOCKS = 1024; + block_address get_nr_blocks(string const &path) { + struct stat info; + block_address nr_blocks; + + int r = ::stat(path.c_str(), &info); + if (r) + throw runtime_error("Couldn't stat dev path"); + + if (S_ISREG(info.st_mode)) + nr_blocks = div_down(info.st_size, MD_BLOCK_SIZE); + + else if (S_ISBLK(info.st_mode)) { + // To get the size of a block device we need to + // open it, and then make an ioctl call. + int fd = ::open(path.c_str(), O_RDONLY); + if (fd < 0) + throw runtime_error("couldn't open block device to ascertain size"); + + r = ::ioctl(fd, BLKGETSIZE64, &nr_blocks); + if (r) { + ::close(fd); + throw runtime_error("ioctl BLKGETSIZE64 failed"); + } + ::close(fd); + nr_blocks = div_down(nr_blocks, MD_BLOCK_SIZE); + } else + throw runtime_error("bad path"); + + return nr_blocks; + } transaction_manager::ptr open_tm(string const &dev_path) { - block_manager<>::ptr bm(new block_manager<>(dev_path, NR_BLOCKS)); - space_map::ptr sm(new core_map(NR_BLOCKS)); + block_address nr_blocks = get_nr_blocks(dev_path); + block_manager<>::ptr bm(new block_manager<>(dev_path, nr_blocks)); + space_map::ptr sm(new core_map(nr_blocks)); transaction_manager::ptr tm(new transaction_manager(bm, sm)); return tm; }