#include "persistent-data/checksum.h" #include "persistent-data/errors.h" #include "thin-provisioning/superblock.h" #include "persistent-data/file_utils.h" #include using namespace thin_provisioning; using namespace superblock_detail; using namespace std; //---------------------------------------------------------------- void superblock_traits::unpack(superblock_disk const &disk, superblock &value) { value.csum_ = to_cpu(disk.csum_); value.flags_ = to_cpu(disk.flags_); value.blocknr_ = to_cpu(disk.blocknr_); ::memcpy(value.uuid_, disk.uuid_, sizeof(value.uuid_)); value.magic_ = to_cpu(disk.magic_); value.version_ = to_cpu(disk.version_); value.time_ = to_cpu(disk.time_); value.trans_id_ = to_cpu(disk.trans_id_); value.metadata_snap_ = to_cpu(disk.metadata_snap_); ::memcpy(value.data_space_map_root_, disk.data_space_map_root_, sizeof(value.data_space_map_root_)); ::memcpy(value.metadata_space_map_root_, disk.metadata_space_map_root_, sizeof(value.metadata_space_map_root_)); value.data_mapping_root_ = to_cpu(disk.data_mapping_root_); value.device_details_root_ = to_cpu(disk.device_details_root_); value.data_block_size_ = to_cpu(disk.data_block_size_); value.metadata_block_size_ = to_cpu(disk.metadata_block_size_); value.metadata_nr_blocks_ = to_cpu(disk.metadata_nr_blocks_); value.compat_flags_ = to_cpu(disk.compat_flags_); value.compat_ro_flags_ = to_cpu(disk.compat_ro_flags_); value.incompat_flags_ = to_cpu(disk.incompat_flags_); } void superblock_traits::pack(superblock const &value, superblock_disk &disk) { disk.csum_ = to_disk(value.csum_); disk.flags_ = to_disk(value.flags_); disk.blocknr_ = to_disk(value.blocknr_); ::memcpy(disk.uuid_, value.uuid_, sizeof(disk.uuid_)); disk.magic_ = to_disk(value.magic_); disk.version_ = to_disk(value.version_); disk.time_ = to_disk(value.time_); disk.trans_id_ = to_disk(value.trans_id_); disk.metadata_snap_ = to_disk(value.metadata_snap_); ::memcpy(disk.data_space_map_root_, value.data_space_map_root_, sizeof(disk.data_space_map_root_)); ::memcpy(disk.metadata_space_map_root_, value.metadata_space_map_root_, sizeof(disk.metadata_space_map_root_)); disk.data_mapping_root_ = to_disk(value.data_mapping_root_); disk.device_details_root_ = to_disk(value.device_details_root_); disk.data_block_size_ = to_disk(value.data_block_size_); disk.metadata_block_size_ = to_disk(value.metadata_block_size_); disk.metadata_nr_blocks_ = to_disk(value.metadata_nr_blocks_); disk.compat_flags_ = to_disk(value.compat_flags_); disk.compat_ro_flags_ = to_disk(value.compat_ro_flags_); disk.incompat_flags_ = to_disk(value.incompat_flags_); } //---------------------------------------------------------------- namespace { using namespace persistent_data; using namespace superblock_detail; uint32_t const SUPERBLOCK_CSUM_SEED = 160774; struct sb_validator : public bcache::validator { virtual void check(void const *raw, block_address location) const { superblock_disk const *sbd = reinterpret_cast(raw); crc32c sum(SUPERBLOCK_CSUM_SEED); sum.append(&sbd->flags_, MD_BLOCK_SIZE - sizeof(uint32_t)); if (sum.get_sum() != to_cpu(sbd->csum_)) { ostringstream out; out << "bad checksum in superblock, wanted " << sum.get_sum(); throw checksum_error(out.str()); } } virtual bool check_raw(void const *raw) const { superblock_disk const *sbd = reinterpret_cast(raw); crc32c sum(SUPERBLOCK_CSUM_SEED); sum.append(&sbd->flags_, MD_BLOCK_SIZE - sizeof(uint32_t)); if (sum.get_sum() != to_cpu(sbd->csum_)) return false; return true; } virtual void prepare(void *raw, block_address location) const { superblock_disk *sbd = reinterpret_cast(raw); crc32c sum(SUPERBLOCK_CSUM_SEED); sum.append(&sbd->flags_, MD_BLOCK_SIZE - sizeof(uint32_t)); sbd->csum_ = to_disk(sum.get_sum()); } }; } bcache::validator::ptr thin_provisioning::superblock_validator() { return bcache::validator::ptr(new sb_validator); } //---------------------------------------------------------------- namespace thin_provisioning { namespace superblock_detail { namespace { unsigned const NEEDS_CHECK_BIT = 0; } bool superblock::get_needs_check_flag() const { return flags_ & (1 << NEEDS_CHECK_BIT); } void superblock::set_needs_check_flag(bool val) { if (val) flags_ |= (1 << NEEDS_CHECK_BIT); else flags_ &= ~(1 << NEEDS_CHECK_BIT); }; superblock_corruption::superblock_corruption(std::string const &desc) : desc_(desc) { } void superblock_corruption::visit(damage_visitor &v) const { v.visit(*this); } void damage_visitor::visit(damage const &d) { d.visit(*this); } } superblock_detail::superblock read_superblock(block_manager const &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 read_superblock(block_manager::ptr bm, block_address location) { return read_superblock(*bm, location); } superblock_detail::superblock read_superblock(block_manager::ptr bm) { return read_superblock(bm, SUPERBLOCK_LOCATION); } superblock_detail::superblock read_superblock(block_manager const &bm) { return read_superblock(bm, SUPERBLOCK_LOCATION); } void write_superblock(block_manager::ptr bm, superblock_detail::superblock const &sb) { block_manager::write_ref w = bm->write_lock(SUPERBLOCK_LOCATION, superblock_validator()); superblock_disk *disk = reinterpret_cast(w.data()); superblock_traits::pack(sb, *disk); } void check_superblock(block_manager::ptr bm, superblock_detail::damage_visitor &visitor, block_address sb_location) { using namespace superblock_detail; try { bm->read_lock(sb_location, superblock_validator()); } catch (std::exception const &e) { visitor.visit(superblock_corruption(e.what())); } } } //----------------------------------------------------------------