diff --git a/Makefile.in b/Makefile.in index 505166d..0d19c7f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -48,7 +48,7 @@ PDATA_SOURCE=\ SOURCE=\ $(PDATA_SOURCE) \ \ - cache/metadata_disk_structures.cc \ + caching/superblock.cc \ \ thin-provisioning/device_tree.cc \ thin-provisioning/file_utils.cc \ @@ -66,7 +66,7 @@ SOURCE=\ PDATA_OBJECTS=$(subst .cc,.o,$(SOURCE)) CXX_PROGRAM_SOURCE=\ - cache/check.cc \ + caching/check.cc \ \ thin-provisioning/thin_check.cc \ thin-provisioning/thin_dump.cc \ @@ -228,11 +228,11 @@ CACHE_CHECK_SOURCE=\ persistent-data/space-maps/recursive.cc \ persistent-data/space-maps/careful_alloc.cc \ persistent-data/transaction_manager.cc \ - cache/metadata_disk_structures.cc + caching/superblock.cc CACHE_CHECK_OBJECTS=$(subst .cc,.o,$(CACHE_CHECK_SOURCE)) -cache_check: $(CACHE_CHECK_OBJECTS) cache/check.o +cache_check: $(CACHE_CHECK_OBJECTS) caching/check.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) diff --git a/cache/metadata_disk_structures.h b/cache/metadata_disk_structures.h deleted file mode 100644 index fe6d261..0000000 --- a/cache/metadata_disk_structures.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (C) 2012 Red Hat, Inc. All rights reserved. -// -// This file is part of the thin-provisioning-tools source. -// -// thin-provisioning-tools is free software: you can redistribute it -// and/or modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. -// -// thin-provisioning-tools is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with thin-provisioning-tools. If not, see -// . - -#ifndef CACHE_METADATA_DISK_STRUCTURES_H -#define CACHE_METADATA_DISK_STRUCTURES_H - -#include "persistent-data/endian_utils.h" -#include "persistent-data/data-structures/btree.h" - -//---------------------------------------------------------------- - -// FIXME: rename to just METADATA_DISK_STRUCTURES -namespace cache_tools { - using namespace base; // FIXME: don't use namespaces in headers. - - unsigned const SPACE_MAP_ROOT_SIZE = 128; - unsigned const CACHE_POLICY_NAME_SIZE = 16; - unsigned const CACHE_POLICY_VERSION_SIZE = 3; - - typedef unsigned char __u8; - - struct superblock_disk { - le32 csum; - le32 flags; - le64 blocknr; - - __u8 uuid[16]; - le64 magic; - le32 version; - - __u8 policy_name[CACHE_POLICY_NAME_SIZE]; - le32 policy_version[CACHE_POLICY_VERSION_SIZE]; - le32 policy_hint_size; - - __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; - - le64 mapping_root; - le64 hint_root; - - le64 discard_root; - le64 discard_block_size; - le64 discard_nr_blocks; - - le32 data_block_size; /* in 512-byte sectors */ - le32 metadata_block_size; /* in 512-byte sectors */ - le32 cache_blocks; - - le32 compat_flags; - le32 compat_ro_flags; - le32 incompat_flags; - - le32 read_hits; - le32 read_misses; - le32 write_hits; - le32 write_misses; - } __attribute__ ((packed)); - - struct superblock { - uint32_t csum; - uint32_t flags; - uint64_t blocknr; - - __u8 uuid[16]; - uint64_t magic; - uint32_t version; - - __u8 policy_name[CACHE_POLICY_NAME_SIZE]; - uint32_t policy_version[CACHE_POLICY_VERSION_SIZE]; - uint32_t policy_hint_size; - - __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; - - uint64_t mapping_root; - uint64_t hint_root; - - uint64_t discard_root; - uint64_t discard_block_size; - uint64_t discard_nr_blocks; - - uint32_t data_block_size; /* in 512-byte sectors */ - uint32_t metadata_block_size; /* in 512-byte sectors */ - uint32_t cache_blocks; - - uint32_t compat_flags; - uint32_t compat_ro_flags; - uint32_t incompat_flags; - - uint32_t read_hits; - uint32_t read_misses; - uint32_t write_hits; - uint32_t write_misses; - }; - - struct superblock_traits { - typedef superblock_disk disk_type; - typedef superblock value_type; - - static void unpack(superblock_disk const &disk, superblock &value); - static void pack(superblock const &value, superblock_disk &disk); - }; -} - -//---------------------------------------------------------------- - -#endif diff --git a/cache/cache_metadata.h b/caching/cache_metadata.h similarity index 100% rename from cache/cache_metadata.h rename to caching/cache_metadata.h diff --git a/cache/check.cc b/caching/check.cc similarity index 100% rename from cache/check.cc rename to caching/check.cc diff --git a/cache/dump.cc b/caching/dump.cc similarity index 100% rename from cache/dump.cc rename to caching/dump.cc diff --git a/caching/metadata_disk_structures.cc b/caching/metadata_disk_structures.cc new file mode 100644 index 0000000..8face77 --- /dev/null +++ b/caching/metadata_disk_structures.cc @@ -0,0 +1,28 @@ +// Copyright (C) 2012 Red Hat, Inc. All rights reserved. +// +// This file is part of the thin-provisioning-tools source. +// +// thin-provisioning-tools is free software: you can redistribute it +// and/or modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// thin-provisioning-tools is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with thin-provisioning-tools. If not, see +// . + +#include "metadata_disk_structures.h" + +#include + +using namespace cache_tools; + +//---------------------------------------------------------------- + + +//---------------------------------------------------------------- diff --git a/caching/metadata_disk_structures.h b/caching/metadata_disk_structures.h new file mode 100644 index 0000000..ef2363e --- /dev/null +++ b/caching/metadata_disk_structures.h @@ -0,0 +1,35 @@ +// Copyright (C) 2012 Red Hat, Inc. All rights reserved. +// +// This file is part of the thin-provisioning-tools source. +// +// thin-provisioning-tools is free software: you can redistribute it +// and/or modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// thin-provisioning-tools is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with thin-provisioning-tools. If not, see +// . + +#ifndef CACHE_METADATA_DISK_STRUCTURES_H +#define CACHE_METADATA_DISK_STRUCTURES_H + +#include "persistent-data/endian_utils.h" +#include "persistent-data/data-structures/btree.h" + +//---------------------------------------------------------------- + +// FIXME: rename to just METADATA_DISK_STRUCTURES +namespace cache_tools { + using namespace base; // FIXME: don't use namespaces in headers. + +} + +//---------------------------------------------------------------- + +#endif diff --git a/cache/metadata_disk_structures.cc b/caching/superblock.cc similarity index 59% rename from cache/metadata_disk_structures.cc rename to caching/superblock.cc index d822fbd..4a8b153 100644 --- a/cache/metadata_disk_structures.cc +++ b/caching/superblock.cc @@ -1,26 +1,7 @@ -// Copyright (C) 2012 Red Hat, Inc. All rights reserved. -// -// This file is part of the thin-provisioning-tools source. -// -// thin-provisioning-tools is free software: you can redistribute it -// and/or modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. -// -// thin-provisioning-tools is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with thin-provisioning-tools. If not, see -// . +#include "caching/superblock.h" -#include "metadata_disk_structures.h" - -#include - -using namespace cache_tools; +using namespace caching; +using namespace superblock_detail; //---------------------------------------------------------------- @@ -110,4 +91,87 @@ superblock_traits::pack(superblock const &core, superblock_disk &disk) 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(persistent_data::block_manager<>::ptr bm, + persistent_data::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::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())); + } +} + //---------------------------------------------------------------- diff --git a/caching/superblock.h b/caching/superblock.h new file mode 100644 index 0000000..f6b9a0c --- /dev/null +++ b/caching/superblock.h @@ -0,0 +1,139 @@ +#ifndef CACHE_SUPERBLOCK_H +#define CACHE_SUPERBLOCK_H + +#include "persistent-data/endian_utils.h" +#include "persistent-data/data-structures/btree.h" + +//---------------------------------------------------------------- + +namespace caching { + namespace superblock_detail { + using namespace base; + + unsigned const SPACE_MAP_ROOT_SIZE = 128; + unsigned const CACHE_POLICY_NAME_SIZE = 16; + unsigned const CACHE_POLICY_VERSION_SIZE = 3; + + typedef unsigned char __u8; + + struct superblock_disk { + le32 csum; + le32 flags; + le64 blocknr; + + __u8 uuid[16]; + le64 magic; + le32 version; + + __u8 policy_name[CACHE_POLICY_NAME_SIZE]; + le32 policy_version[CACHE_POLICY_VERSION_SIZE]; + le32 policy_hint_size; + + __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; + + le64 mapping_root; + le64 hint_root; + + le64 discard_root; + le64 discard_block_size; + le64 discard_nr_blocks; + + le32 data_block_size; /* in 512-byte sectors */ + le32 metadata_block_size; /* in 512-byte sectors */ + le32 cache_blocks; + + le32 compat_flags; + le32 compat_ro_flags; + le32 incompat_flags; + + le32 read_hits; + le32 read_misses; + le32 write_hits; + le32 write_misses; + } __attribute__ ((packed)); + + struct superblock { + uint32_t csum; + uint32_t flags; + uint64_t blocknr; + + __u8 uuid[16]; + uint64_t magic; + uint32_t version; + + __u8 policy_name[CACHE_POLICY_NAME_SIZE]; + uint32_t policy_version[CACHE_POLICY_VERSION_SIZE]; + uint32_t policy_hint_size; + + __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; + + uint64_t mapping_root; + uint64_t hint_root; + + uint64_t discard_root; + uint64_t discard_block_size; + uint64_t discard_nr_blocks; + + uint32_t data_block_size; /* in 512-byte sectors */ + uint32_t metadata_block_size; /* in 512-byte sectors */ + uint32_t cache_blocks; + + uint32_t compat_flags; + uint32_t compat_ro_flags; + uint32_t incompat_flags; + + uint32_t read_hits; + uint32_t read_misses; + uint32_t write_hits; + uint32_t write_misses; + }; + + struct superblock_traits { + typedef superblock_disk disk_type; + typedef superblock value_type; + + static void unpack(superblock_disk const &disk, superblock &value); + static void pack(superblock const &value, superblock_disk &disk); + }; + + block_address const SUPERBLOCK_LOCATION = 0; + uint32_t const SUPERBLOCK_MAGIC = 06142003; + + //-------------------------------- + + class damage_visitor; + + struct damage { + virtual ~damage() {} + virtual void visit(damage_visitor &v) const = 0; + }; + + struct superblock_corruption : public damage { + superblock_corruption(std::string const &desc); + void visit(damage_visitor &v) const; + + std::string desc_; + }; + + class damage_visitor { + public: + virtual ~damage_visitor() {} + + void visit(damage const &d); + + virtual void visit(superblock_corruption const &d) = 0; + }; + } + + persistent_data::block_manager<>::validator::ptr superblock_validator(); + + superblock_detail::superblock read_superblock(persistent_data::block_manager<>::ptr bm); + superblock_detail::superblock read_superblock(persistent_data::block_manager<>::ptr bm, + persistent_data::block_address location); + void check_superblock(persistent_data::block_manager<>::ptr bm, + superblock_detail::damage_visitor &visitor); +} + +//---------------------------------------------------------------- + +#endif