#include "caching/superblock.h" using namespace caching; using namespace superblock_detail; //---------------------------------------------------------------- void superblock_traits::unpack(superblock_disk const &disk, superblock &core) { core.csum = to_cpu(disk.csum); core.flags = to_cpu(disk.flags); core.blocknr = to_cpu(disk.blocknr); ::memcpy(core.uuid, disk.uuid, sizeof(core.uuid)); core.magic = to_cpu(disk.magic); core.version = to_cpu(disk.version); ::memcpy(core.policy_name, disk.policy_name, sizeof(core.policy_name)); for (unsigned i = 0; i < CACHE_POLICY_VERSION_SIZE; i++) core.policy_version[i] = to_cpu(disk.policy_version[i]); core.policy_hint_size = to_cpu(disk.policy_hint_size); ::memcpy(core.metadata_space_map_root, disk.metadata_space_map_root, sizeof(core.metadata_space_map_root)); core.mapping_root = to_cpu(disk.mapping_root); core.hint_root = to_cpu(disk.hint_root); core.discard_root = to_cpu(disk.discard_root); core.discard_block_size = to_cpu(disk.discard_block_size); core.discard_nr_blocks = to_cpu(disk.discard_nr_blocks); core.data_block_size = to_cpu(disk.data_block_size); core.metadata_block_size = to_cpu(disk.metadata_block_size); core.cache_blocks = to_cpu(disk.cache_blocks); core.compat_flags = to_cpu(disk.compat_flags); core.compat_ro_flags = to_cpu(disk.compat_ro_flags); core.incompat_flags = to_cpu(disk.incompat_flags); core.read_hits = to_cpu(disk.read_hits); core.read_misses = to_cpu(disk.read_misses); core.write_hits = to_cpu(disk.write_hits); core.write_misses = to_cpu(disk.write_misses); } void superblock_traits::pack(superblock const &core, superblock_disk &disk) { disk.csum = to_disk(core.csum); disk.flags = to_disk(core.flags); disk.blocknr = to_disk(core.blocknr); ::memcpy(disk.uuid, core.uuid, sizeof(disk.uuid)); disk.magic = to_disk(core.magic); disk.version = to_disk(core.version); ::memcpy(disk.policy_name, core.policy_name, sizeof(disk.policy_name)); for (unsigned i = 0; i < CACHE_POLICY_VERSION_SIZE; i++) disk.policy_version[i] = to_disk(core.policy_version[i]); disk.policy_hint_size = to_disk(core.policy_hint_size); ::memcpy(disk.metadata_space_map_root, core.metadata_space_map_root, sizeof(disk.metadata_space_map_root)); disk.mapping_root = to_disk(core.mapping_root); disk.hint_root = to_disk(core.hint_root); disk.discard_root = to_disk(core.discard_root); disk.discard_block_size = to_disk(core.discard_block_size); disk.discard_nr_blocks = to_disk(core.discard_nr_blocks); disk.data_block_size = to_disk(core.data_block_size); disk.metadata_block_size = to_disk(core.metadata_block_size); disk.cache_blocks = to_disk(core.cache_blocks); disk.compat_flags = to_disk(core.compat_flags); disk.compat_ro_flags = to_disk(core.compat_ro_flags); disk.incompat_flags = to_disk(core.incompat_flags); disk.read_hits = to_disk(core.read_hits); disk.read_misses = to_disk(core.read_misses); disk.write_hits = to_disk(core.write_hits); disk.write_misses = to_disk(core.write_misses); } //-------------------------------- superblock_corruption::superblock_corruption(std::string const &desc) : desc_(desc) { } void superblock_corruption::visit(damage_visitor &v) const { v.visit(*this); } //-------------------------------- namespace { using namespace persistent_data; using namespace superblock_detail; uint32_t const VERSION = 1; unsigned const SECTOR_TO_BLOCK_SHIFT = 3; uint32_t const SUPERBLOCK_CSUM_SEED = 9031977; struct sb_validator : public block_manager<>::validator { virtual void check(buffer<> const &b, block_address location) const { superblock_disk const *sbd = reinterpret_cast(&b); crc32c sum(SUPERBLOCK_CSUM_SEED); sum.append(&sbd->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); if (sum.get_sum() != to_cpu(sbd->csum)) throw checksum_error("bad checksum in superblock"); } virtual void prepare(buffer<> &b, block_address location) const { superblock_disk *sbd = reinterpret_cast(&b); crc32c sum(SUPERBLOCK_CSUM_SEED); sum.append(&sbd->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); sbd->csum = to_disk(sum.get_sum()); } }; } persistent_data::block_manager<>::validator::ptr caching::superblock_validator() { return block_manager<>::validator::ptr(new sb_validator); } //-------------------------------- superblock_detail::superblock caching::read_superblock(block_manager<>::ptr bm, block_address location) { using namespace superblock_detail; superblock sb; block_manager<>::read_ref r = bm->read_lock(location, superblock_validator()); superblock_disk const *sbd = reinterpret_cast(&r.data()); superblock_traits::unpack(*sbd, sb); return sb; } superblock_detail::superblock caching::read_superblock(persistent_data::block_manager<>::ptr bm) { return read_superblock(bm, SUPERBLOCK_LOCATION); } void caching::write_superblock(block_manager<>::ptr bm, block_address location, superblock_detail::superblock const &sb) { using namespace superblock_detail; block_manager<>::write_ref w = bm->write_lock(location, superblock_validator()); superblock_traits::pack(sb, *reinterpret_cast(&w.data())); } void caching::write_superblock(block_manager<>::ptr bm, superblock_detail::superblock const &sb) { write_superblock(bm, SUPERBLOCK_LOCATION, sb); } void caching::check_superblock(persistent_data::block_manager<>::ptr bm, superblock_detail::damage_visitor &visitor) { using namespace superblock_detail; try { bm->read_lock(SUPERBLOCK_LOCATION, superblock_validator()); } catch (std::exception const &e) { visitor.visit(superblock_corruption(e.what())); } } //----------------------------------------------------------------