cache tools wip

This commit is contained in:
Joe Thornber 2013-03-15 14:59:21 +00:00
parent 12dff31358
commit 2ed1648896
5 changed files with 593 additions and 0 deletions

100
cache/cache_check.cc vendored Normal file
View File

@ -0,0 +1,100 @@
// 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 <getopt.h>
#include <libgen.h>
#include "array.h"
#include "metadata.h"
#include "metadata_checker.h"
#include "version.h"
using namespace persistent_data;
using namespace std;
using namespace thin_provisioning;
namespace {
int check(string const &path, bool quiet) {
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;
}
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;
}
}
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 << 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]));
exit(1);
}
return check(argv[optind], quiet);
}

119
cache/cache_dump.cc vendored Normal file
View File

@ -0,0 +1,119 @@
// 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>
#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);
}

143
cache/cache_metadata.h vendored Normal file
View 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

113
cache/cache_metadata_disk_structures.cc vendored Normal file
View File

@ -0,0 +1,113 @@
// 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 "cache_metadata_disk_structures.h"
#include <string.h>
using namespace cache_tools;
//----------------------------------------------------------------
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 &value, 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);
}
//----------------------------------------------------------------

118
cache/cache_metadata_disk_structures.h vendored Normal file
View File

@ -0,0 +1,118 @@
// 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 "endian_utils.h"
#include "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;
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