caching/superblock.{h,cc}
This commit is contained in:
143
caching/cache_metadata.h
Normal file
143
caching/cache_metadata.h
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright (C) 2011 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
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef CACHE_METADATA_H
|
||||
#define CACHE_METADATA_H
|
||||
|
||||
#include "block.h"
|
||||
#include "array.h"
|
||||
#include "endian_utils.h"
|
||||
#include "space_map_disk.h"
|
||||
#include "transaction_manager.h"
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace cache {
|
||||
// FIXME: don't use namespaces in a header
|
||||
using namespace base;
|
||||
using namespace persistent_data;
|
||||
|
||||
block_address const SUPERBLOCK_LOCATION = 0;
|
||||
|
||||
typedef uint64_t sector_t;
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
class space_map_ref_counter {
|
||||
public:
|
||||
space_map_ref_counter(space_map::ptr sm)
|
||||
: sm_(sm) {
|
||||
}
|
||||
|
||||
void inc(block_address b) {
|
||||
sm_->inc(b);
|
||||
}
|
||||
|
||||
void dec(block_address b) {
|
||||
sm_->dec(b);
|
||||
}
|
||||
|
||||
private:
|
||||
space_map::ptr sm_;
|
||||
};
|
||||
|
||||
struct block_flags {
|
||||
uint64_t block_;
|
||||
uint32_t flags_;
|
||||
};
|
||||
|
||||
class block_flags_ref_counter {
|
||||
public:
|
||||
block_flags_ref_counter(space_map::ptr sm)
|
||||
: sm_(sm) {
|
||||
}
|
||||
|
||||
void inc(block_flags bf) {
|
||||
sm_->inc(bf.block_);
|
||||
}
|
||||
|
||||
void dec(block_flags bf) {
|
||||
sm_->dec(bf.block_);
|
||||
}
|
||||
|
||||
private:
|
||||
space_map::ptr sm_;
|
||||
};
|
||||
|
||||
struct block_traits {
|
||||
typedef base::__le64 disk_type;
|
||||
typedef block_flags value_type;
|
||||
typedef block_flags_ref_counter ref_counter;
|
||||
|
||||
static void unpack(disk_type const &disk, value_type &value) {
|
||||
uint64_t v = to_cpu<uint64_t>(disk);
|
||||
value.block_ = v >> 24;
|
||||
value.flags_ = v & ((1 << 24) - 1);
|
||||
}
|
||||
|
||||
static void pack(value_type const &value, disk_type &disk) {
|
||||
uint64_t v = (value.block_ << 24) | value.flags_;
|
||||
disk = base::to_disk<base::__le64>(v);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
// FIXME: should these be in a sub-namespace?
|
||||
typedef persistent_data::transaction_manager::ptr tm_ptr;
|
||||
typedef persistent_data::btree<1, device_details_traits> detail_tree;
|
||||
typedef persistent_data::btree<1, mtree_traits> dev_tree;
|
||||
typedef persistent_data::btree<2, block_traits> mapping_tree;
|
||||
typedef persistent_data::btree<1, block_traits> single_mapping_tree;
|
||||
|
||||
// The tools require different interfaces onto the metadata than
|
||||
// the in kernel driver. This class gives access to the low-level
|
||||
// implementation of metadata. Implement more specific interfaces
|
||||
// on top of this.
|
||||
struct metadata {
|
||||
enum open_type {
|
||||
CREATE,
|
||||
OPEN
|
||||
};
|
||||
|
||||
metadata(std::string const &dev_path, open_type ot,
|
||||
sector_t data_block_size = 128,
|
||||
block_address nr_cache_blocks = 0); // Only used if CREATE
|
||||
|
||||
metadata(std::string const &dev_path, block_address metadata_snap);
|
||||
|
||||
void commit();
|
||||
|
||||
typedef block_manager<>::read_ref read_ref;
|
||||
typedef block_manager<>::write_ref write_ref;
|
||||
typedef boost::shared_ptr<metadata> ptr;
|
||||
|
||||
tm_ptr tm_;
|
||||
superblock sb_;
|
||||
|
||||
checked_space_map::ptr metadata_sm_;
|
||||
checked_space_map::ptr data_sm_;
|
||||
detail_tree::ptr details_;
|
||||
dev_tree::ptr mappings_top_level_;
|
||||
mapping_tree::ptr mappings_;
|
||||
};
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
166
caching/check.cc
Normal file
166
caching/check.cc
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright (C) 2011 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
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
struct stat guarded_stat(string const &path) {
|
||||
struct stat info;
|
||||
|
||||
int r = ::stat(path.c_str(), &info);
|
||||
if (r) {
|
||||
ostringstream msg;
|
||||
char buffer[128], *ptr;
|
||||
|
||||
ptr = ::strerror_r(errno, buffer, sizeof(buffer));
|
||||
msg << path << ": " << ptr;
|
||||
throw runtime_error(msg.str());
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
int open_file(string const &path, int mode) {
|
||||
int fd = open(path.c_str(), mode);
|
||||
if (fd < 0) {
|
||||
ostringstream msg;
|
||||
char buffer[128], *ptr;
|
||||
|
||||
ptr = strerror_r(errno, buffer, sizeof(buffer));
|
||||
msg << path << ": " << ptr;
|
||||
throw runtime_error(msg.str());
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int check(string const &path, bool quiet) {
|
||||
struct stat info = guarded_stat(path);
|
||||
|
||||
if (!S_ISREG(info.st_mode) && !S_ISBLK(info.st_mode)) {
|
||||
ostringstream msg;
|
||||
msg << path << ": " << "Not a block device or regular file";
|
||||
throw runtime_error(msg.str());
|
||||
}
|
||||
|
||||
int fd = open_file(path, O_RDONLY);
|
||||
|
||||
ostringstream msg;
|
||||
msg << path << ": " << "No superblock found";
|
||||
throw runtime_error(msg.str());
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
try {
|
||||
metadata::ptr md(new metadata(path, metadata::OPEN));
|
||||
|
||||
optional<error_set::ptr> maybe_errors = metadata_check(md);
|
||||
if (maybe_errors) {
|
||||
if (!quiet)
|
||||
cerr << error_selector(*maybe_errors, 3);
|
||||
return 1;
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
if (!quiet)
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void usage(ostream &out, string const &cmd) {
|
||||
out << "Usage: " << cmd << " [options] {device|file}" << endl
|
||||
<< "Options:" << endl
|
||||
<< " {-q|--quiet}" << endl
|
||||
<< " {-h|--help}" << endl
|
||||
<< " {-V|--version}" << endl;
|
||||
}
|
||||
|
||||
char const *TOOLS_VERSION = "0.1.6";
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
bool quiet = false;
|
||||
const char shortopts[] = "qhV";
|
||||
const struct option longopts[] = {
|
||||
{ "quiet", no_argument, NULL, 'q'},
|
||||
{ "help", no_argument, NULL, 'h'},
|
||||
{ "version", no_argument, NULL, 'V'},
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(cout, basename(argv[0]));
|
||||
return 0;
|
||||
|
||||
case 'q':
|
||||
quiet = true;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
cout << TOOLS_VERSION << endl;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
usage(cerr, basename(argv[0]));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == optind) {
|
||||
cerr << "No input file provided." << endl;
|
||||
usage(cerr, basename(argv[0]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
check(argv[optind], quiet);
|
||||
|
||||
} catch (exception const &e) {
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
125
caching/dump.cc
Normal file
125
caching/dump.cc
Normal file
@@ -0,0 +1,125 @@
|
||||
// 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
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <iostream>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#if 0
|
||||
#include "human_readable_format.h"
|
||||
#include "cache_metadata_dumper.h"
|
||||
#include "cache_metadata.h"
|
||||
#include "xml_format.h"
|
||||
#include "version.h"
|
||||
|
||||
using namespace persistent_data;
|
||||
using namespace std;
|
||||
using namespace thin_provisioning;
|
||||
|
||||
namespace {
|
||||
int dump(string const &path, string const &format, bool repair,
|
||||
block_address metadata_snap = 0) {
|
||||
try {
|
||||
metadata::ptr md(metadata_snap ?
|
||||
new metadata(path, metadata_snap) :
|
||||
new metadata(path, metadata::OPEN));
|
||||
emitter::ptr e;
|
||||
|
||||
if (format == "xml")
|
||||
e = create_xml_emitter(cout);
|
||||
else if (format == "human_readable")
|
||||
e = create_human_readable_emitter(cout);
|
||||
else {
|
||||
cerr << "unknown format '" << format << "'" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
metadata_dump(md, e, repair);
|
||||
|
||||
} catch (std::exception &e) {
|
||||
cerr << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(ostream &out, string const &cmd) {
|
||||
out << "Usage: " << cmd << " [options] {device|file}" << endl
|
||||
<< "Options:" << endl
|
||||
<< " {-h|--help}" << endl
|
||||
<< " {-f|--format} {xml|human_readable}" << endl
|
||||
<< " {-r|--repair}" << endl
|
||||
<< " {-m|--metadata-snap}" << endl
|
||||
<< " {-V|--version}" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
bool repair = false;
|
||||
const char shortopts[] = "hm:f:rV";
|
||||
string format = "xml";
|
||||
char *end_ptr;
|
||||
|
||||
const struct option longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h'},
|
||||
{ "format", required_argument, NULL, 'f' },
|
||||
{ "repair", no_argument, NULL, 'r'},
|
||||
{ "version", no_argument, NULL, 'V'},
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(cout, basename(argv[0]));
|
||||
return 0;
|
||||
|
||||
case 'f':
|
||||
format = optarg;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
repair = true;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
usage(cerr, basename(argv[0]));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == optind) {
|
||||
cerr << "No input file provided." << endl;
|
||||
usage(cerr, basename(argv[0]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return dump(argv[optind], format, repair, metadata_snap);
|
||||
}
|
||||
#else
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
28
caching/metadata_disk_structures.cc
Normal file
28
caching/metadata_disk_structures.cc
Normal file
@@ -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
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "metadata_disk_structures.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
using namespace cache_tools;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
35
caching/metadata_disk_structures.h
Normal file
35
caching/metadata_disk_structures.h
Normal file
@@ -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
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#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
|
||||
177
caching/superblock.cc
Normal file
177
caching/superblock.cc
Normal file
@@ -0,0 +1,177 @@
|
||||
#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<uint32_t>(disk.csum);
|
||||
core.flags = to_cpu<uint32_t>(disk.flags);
|
||||
core.blocknr = to_cpu<uint64_t>(disk.blocknr);
|
||||
|
||||
::memcpy(core.uuid, disk.uuid, sizeof(core.uuid));
|
||||
core.magic = to_cpu<uint64_t>(disk.magic);
|
||||
core.version = to_cpu<uint32_t>(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<uint32_t>(disk.policy_version[i]);
|
||||
|
||||
core.policy_hint_size = to_cpu<uint32_t>(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<uint64_t>(disk.mapping_root);
|
||||
core.hint_root = to_cpu<uint64_t>(disk.hint_root);
|
||||
|
||||
core.discard_root = to_cpu<uint64_t>(disk.discard_root);
|
||||
core.discard_block_size = to_cpu<uint64_t>(disk.discard_block_size);
|
||||
core.discard_nr_blocks = to_cpu<uint64_t>(disk.discard_nr_blocks);
|
||||
|
||||
core.data_block_size = to_cpu<uint32_t>(disk.data_block_size);
|
||||
core.metadata_block_size = to_cpu<uint32_t>(disk.metadata_block_size);
|
||||
core.cache_blocks = to_cpu<uint32_t>(disk.cache_blocks);
|
||||
|
||||
core.compat_flags = to_cpu<uint32_t>(disk.compat_flags);
|
||||
core.compat_ro_flags = to_cpu<uint32_t>(disk.compat_ro_flags);
|
||||
core.incompat_flags = to_cpu<uint32_t>(disk.incompat_flags);
|
||||
|
||||
core.read_hits = to_cpu<uint32_t>(disk.read_hits);
|
||||
core.read_misses = to_cpu<uint32_t>(disk.read_misses);
|
||||
core.write_hits = to_cpu<uint32_t>(disk.write_hits);
|
||||
core.write_misses = to_cpu<uint32_t>(disk.write_misses);
|
||||
}
|
||||
|
||||
void
|
||||
superblock_traits::pack(superblock const &core, superblock_disk &disk)
|
||||
{
|
||||
disk.csum = to_disk<le32>(core.csum);
|
||||
disk.flags = to_disk<le32>(core.flags);
|
||||
disk.blocknr = to_disk<le64>(core.blocknr);
|
||||
|
||||
::memcpy(disk.uuid, core.uuid, sizeof(disk.uuid));
|
||||
disk.magic = to_disk<le64>(core.magic);
|
||||
disk.version = to_disk<le32>(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<le32>(core.policy_version[i]);
|
||||
|
||||
disk.policy_hint_size = to_disk<le32>(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<le64>(core.mapping_root);
|
||||
disk.hint_root = to_disk<le64>(core.hint_root);
|
||||
|
||||
disk.discard_root = to_disk<le64>(core.discard_root);
|
||||
disk.discard_block_size = to_disk<le64>(core.discard_block_size);
|
||||
disk.discard_nr_blocks = to_disk<le64>(core.discard_nr_blocks);
|
||||
|
||||
disk.data_block_size = to_disk<le32>(core.data_block_size);
|
||||
disk.metadata_block_size = to_disk<le32>(core.metadata_block_size);
|
||||
disk.cache_blocks = to_disk<le32>(core.cache_blocks);
|
||||
|
||||
disk.compat_flags = to_disk<le32>(core.compat_flags);
|
||||
disk.compat_ro_flags = to_disk<le32>(core.compat_ro_flags);
|
||||
disk.incompat_flags = to_disk<le32>(core.incompat_flags);
|
||||
|
||||
disk.read_hits = to_disk<le32>(core.read_hits);
|
||||
disk.read_misses = to_disk<le32>(core.read_misses);
|
||||
disk.write_hits = to_disk<le32>(core.write_hits);
|
||||
disk.write_misses = to_disk<le32>(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<superblock_disk const *>(&b);
|
||||
crc32c sum(SUPERBLOCK_CSUM_SEED);
|
||||
sum.append(&sbd->flags, MD_BLOCK_SIZE - sizeof(uint32_t));
|
||||
if (sum.get_sum() != to_cpu<uint32_t>(sbd->csum))
|
||||
throw checksum_error("bad checksum in superblock");
|
||||
}
|
||||
|
||||
virtual void prepare(buffer<> &b, block_address location) const {
|
||||
superblock_disk *sbd = reinterpret_cast<superblock_disk *>(&b);
|
||||
crc32c sum(SUPERBLOCK_CSUM_SEED);
|
||||
sum.append(&sbd->flags, MD_BLOCK_SIZE - sizeof(uint32_t));
|
||||
sbd->csum = to_disk<base::le32>(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<superblock_disk const *>(&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()));
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
139
caching/superblock.h
Normal file
139
caching/superblock.h
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user