Add some ftests, and fixup whitespace from Nikhil's work

This commit is contained in:
Joe Thornber 2019-10-28 11:52:21 +00:00
parent cb055c90e5
commit 5f2c3bed69
16 changed files with 460 additions and 433 deletions

View File

@ -101,7 +101,7 @@ SOURCE=\
thin-provisioning/metadata_checker.cc \
thin-provisioning/metadata_counter.cc \
thin-provisioning/metadata_dumper.cc \
thin-provisioning/override_emitter.cc \
thin-provisioning/override_emitter.cc \
thin-provisioning/pool_stream.cc \
thin-provisioning/restore_emitter.cc \
thin-provisioning/rmap_visitor.cc \

View File

@ -46,6 +46,9 @@ Options:
{-h|--help}
{-i|--input} <input xml file>
{-o|--output} <output device or file>
{--transaction-id} <natural>
{--data-block-size} <natural>
{--nr-data-blocks} <natural>
{-q|--quiet}
{-V|--version}")

View File

@ -216,6 +216,33 @@
(run-ok-rcv (stdout _) (thin-restore "-i" xml "-o" md "--quiet")
(assert-eof stdout)))))
(define-scenario (thin-restore override transaction-id)
"thin_restore obeys the --transaction-id override"
(with-empty-metadata (md)
(with-thin-xml (xml)
(run-ok-rcv (stdout stderr) (thin-restore "--transaction-id 2345" "-i" xml "-o" md)
(assert-eof stderr))
(run-ok-rcv (stdout stderr) (thin-dump md)
(assert-matches ".*transaction=\"2345\"" stdout)))))
(define-scenario (thin-restore override data-block-size)
"thin_restore obeys the --data-block-size override"
(with-empty-metadata (md)
(with-thin-xml (xml)
(run-ok-rcv (stdout stderr) (thin-restore "--data-block-size 8192" "-i" xml "-o" md)
(assert-eof stderr))
(run-ok-rcv (stdout stderr) (thin-dump md)
(assert-matches ".*data_block_size=\"8192\"" stdout)))))
(define-scenario (thin-restore override nr-data-blocks)
"thin_restore obeys the --nr-data-blocks override"
(with-empty-metadata (md)
(with-thin-xml (xml)
(run-ok-rcv (stdout stderr) (thin-restore "--nr-data-blocks 234500" "-i" xml "-o" md)
(assert-eof stderr))
(run-ok-rcv (stdout stderr) (thin-dump md)
(assert-matches ".*nr_data_blocks=\"234500\"" stdout)))))
;;;-----------------------------------------------------------
;;; thin_dump scenarios
;;;-----------------------------------------------------------

View File

@ -39,8 +39,8 @@ OPTIONS
This option may be specified multiple times to select more than one thin
device.
--transaction-id {natural} Override the transaction id given in the input xml.
--data-block-size {natural} Override the data block size given in the input xml.
--transaction-id {natural} Override the transaction id given in the input xml.
--data-block-size {natural} Override the data block size given in the input xml.
--nr-data-blocks {natural} Override the nr data blocks given in the input xml.
--skip-mappings Do not dump the mappings.

View File

@ -21,8 +21,8 @@ OPTIONS
If a file is used for output, then it must be preallocated, and large
enough to hold the metadata.
--transaction-id {natural} Override the transaction id given in the input xml.
--data-block-size {natural} Override the data block size given in the input xml.
--transaction-id {natural} Override the transaction id given in the input xml.
--data-block-size {natural} Override the data block size given in the input xml.
--nr-data-blocks {natural} Override the nr data blocks given in the input xml.
EXAMPLE

View File

@ -23,8 +23,8 @@ OPTIONS
If a file is used for output, then it must be preallocated, and large
enough to hold the metadata.
--transaction-id {natural} Override the transaction id given in the input xml.
--data-block-size {natural} Override the data block size given in the input xml.
--transaction-id {natural} Override the transaction id given in the input xml.
--data-block-size {natural} Override the data block size given in the input xml.
--nr-data-blocks {natural} Override the nr data blocks given in the input xml.
EXAMPLE

View File

@ -33,7 +33,6 @@
using namespace base;
using namespace thin_provisioning;
//----------------------------------------------------------------
namespace {

View File

@ -276,20 +276,19 @@ namespace {
class gatherer {
public:
gatherer(block_manager<> &bm)
: bm_(bm),
referenced_(bm.get_nr_blocks(), false),
examined_(bm.get_nr_blocks(), false) {
}
gatherer(block_manager<> &bm)
: bm_(bm),
referenced_(bm.get_nr_blocks(), false),
examined_(bm.get_nr_blocks(), false) {
}
struct roots {
block_address mapping_root;
block_address detail_root;
uint32_t time;
};
optional<roots>
struct roots {
block_address mapping_root;
block_address detail_root;
uint32_t time;
};
optional<roots>
find_best_roots(transaction_manager &tm) {
vector<node_info> mapping_roots;
vector<node_info> device_roots;
@ -304,16 +303,16 @@ namespace {
auto info = get_info(b);
if (info.valid) {
if (info.type == TOP_LEVEL) {
mapping_roots.push_back(info);
}
if (info.valid) {
if (info.type == TOP_LEVEL) {
mapping_roots.push_back(info);
}
else if (info.type == DEVICE_DETAILS) {
device_roots.push_back(info);
}
}
}
else if (info.type == DEVICE_DETAILS) {
device_roots.push_back(info);
}
}
}
#if SHOW_WORKING
cerr << "mapping candidates (" << mapping_roots.size() << "):\n";
@ -332,27 +331,27 @@ namespace {
cerr << "(" << p.first << ", " << p.second << ")\n";
#endif
if (pairs.size())
return mk_roots(pairs[0]);
else
return optional<roots>();
}
if (pairs.size())
return mk_roots(pairs[0]);
else
return optional<roots>();
}
private:
uint32_t get_time(block_address b) const {
auto i = lookup_info(b);
return i ? i->age : 0;
}
uint32_t get_time(block_address b) const {
auto i = lookup_info(b);
return i ? i->age : 0;
}
roots mk_roots(pair<block_address, block_address> const &p) {
roots r;
roots mk_roots(pair<block_address, block_address> const &p) {
roots r;
r.mapping_root = p.second;
r.detail_root = p.first;
r.time = max<block_address>(get_time(p.first), get_time(p.second));
r.mapping_root = p.second;
r.detail_root = p.first;
r.time = max<block_address>(get_time(p.first), get_time(p.second));
return r;
}
return r;
}
bool set_eq(set<uint32_t> const &lhs, set<uint32_t> const &rhs) {
for (auto v : lhs)
@ -624,14 +623,13 @@ namespace {
}
}
optional<node_info> lookup_info(block_address b) const {
auto it = infos_.find(b);
if (it == infos_.end())
return optional<node_info>();
return optional<node_info>(it->second);
}
optional<node_info> lookup_info(block_address b) const {
auto it = infos_.find(b);
if (it == infos_.end())
return optional<node_info>();
return optional<node_info>(it->second);
}
block_manager<> &bm_;
vector<bool> referenced_;
@ -779,102 +777,102 @@ namespace {
return 0ull;
}
void
emit_trees_(block_manager<>::ptr bm, superblock_detail::superblock const &sb,
void
emit_trees_(block_manager<>::ptr bm, superblock_detail::superblock const &sb,
emitter::ptr e, override_options const &ropts)
{
metadata md(bm, sb);
dump_options opts;
details_extractor de(opts);
device_tree_detail::damage_visitor::ptr dd_policy(details_damage_policy(true));
walk_device_tree(*md.details_, de, *dd_policy);
{
metadata md(bm, sb);
dump_options opts;
details_extractor de(opts);
device_tree_detail::damage_visitor::ptr dd_policy(details_damage_policy(true));
walk_device_tree(*md.details_, de, *dd_policy);
e->begin_superblock("", sb.time_,
sb.trans_id_,
sb.flags_,
sb.version_,
sb.data_block_size_,
get_nr_blocks(md),
boost::optional<block_address>());
e->begin_superblock("", sb.time_,
sb.trans_id_,
sb.flags_,
sb.version_,
sb.data_block_size_,
get_nr_blocks(md),
boost::optional<block_address>());
{
mapping_tree_detail::damage_visitor::ptr md_policy(mapping_damage_policy(true));
mapping_tree_emit_visitor mte(opts, *md.tm_, e, de.get_details(), mapping_damage_policy(true));
walk_mapping_tree(*md.mappings_top_level_, mte, *md_policy);
}
{
mapping_tree_detail::damage_visitor::ptr md_policy(mapping_damage_policy(true));
mapping_tree_emit_visitor mte(opts, *md.tm_, e, de.get_details(), mapping_damage_policy(true));
walk_mapping_tree(*md.mappings_top_level_, mte, *md_policy);
}
e->end_superblock();
}
e->end_superblock();
}
void
find_better_roots_(block_manager<>::ptr bm, superblock_detail::superblock &sb)
{
// We assume the superblock is wrong, and find the best roots
// for ourselves. We've had a few cases where people have
// activated a pool on multiple hosts at once, which results in
// the superblock being over written.
gatherer g(*bm);
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
auto p = g.find_best_roots(*tm);
void
find_better_roots_(block_manager<>::ptr bm, superblock_detail::superblock &sb)
{
// We assume the superblock is wrong, and find the best roots
// for ourselves. We've had a few cases where people have
// activated a pool on multiple hosts at once, which results in
// the superblock being over written.
gatherer g(*bm);
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
auto p = g.find_best_roots(*tm);
if (p) {
sb.metadata_snap_ = 0;
sb.time_ = p->time;
sb.device_details_root_ = p->detail_root;
sb.data_mapping_root_ = p->mapping_root;
sb.metadata_nr_blocks_ = bm->get_nr_blocks();
}
}
superblock_detail::superblock
recreate_superblock(override_options const &opts)
{
superblock_detail::superblock sb;
memset(&sb, 0, sizeof(sb));
// FIXME: we need to get this by walking both the mapping and device trees.
sb.time_ = 100000;
if (p) {
sb.metadata_snap_ = 0;
sb.time_ = p->time;
sb.device_details_root_ = p->detail_root;
sb.data_mapping_root_ = p->mapping_root;
sb.metadata_nr_blocks_ = bm->get_nr_blocks();
}
}
sb.trans_id_ = opts.get_transaction_id();
sb.version_ = superblock_detail::METADATA_VERSION;
sb.data_block_size_ = opts.get_data_block_size();
// Check that this has been overridden.
opts.get_nr_data_blocks();
superblock_detail::superblock
recreate_superblock(override_options const &opts)
{
superblock_detail::superblock sb;
memset(&sb, 0, sizeof(sb));
return sb;
}
// FIXME: we need to get this by walking both the mapping and device trees.
sb.time_ = 100000;
optional<superblock_detail::superblock>
maybe_read_superblock(block_manager<>::ptr bm)
{
try {
auto sb = read_superblock(bm);
return optional<superblock_detail::superblock>(sb);
} catch (...) {
}
return optional<superblock_detail::superblock>();
}
sb.trans_id_ = opts.get_transaction_id();
sb.version_ = superblock_detail::METADATA_VERSION;
sb.data_block_size_ = opts.get_data_block_size();
void
metadata_repair_(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts)
{
auto msb = maybe_read_superblock(bm);
if (!msb)
msb = recreate_superblock(opts);
// Check that this has been overridden.
opts.get_nr_data_blocks();
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
return sb;
}
if (!get_dev_ids(*tm, msb->device_details_root_) ||
!get_map_ids(*tm, msb->data_mapping_root_))
find_better_roots_(bm, *msb);
optional<superblock_detail::superblock>
maybe_read_superblock(block_manager<>::ptr bm)
{
try {
auto sb = read_superblock(bm);
return optional<superblock_detail::superblock>(sb);
} catch (...) {
}
emit_trees_(bm, *msb, e, opts);
}
return optional<superblock_detail::superblock>();
}
void
metadata_repair_(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts)
{
auto msb = maybe_read_superblock(bm);
if (!msb)
msb = recreate_superblock(opts);
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
if (!get_dev_ids(*tm, msb->device_details_root_) ||
!get_map_ids(*tm, msb->data_mapping_root_))
find_better_roots_(bm, *msb);
emit_trees_(bm, *msb, e, opts);
}
}
//----------------------------------------------------------------
@ -906,15 +904,15 @@ thin_provisioning::metadata_dump(metadata::ptr md, emitter::ptr e, dump_options
void
thin_provisioning::metadata_repair(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts)
{
try {
metadata_repair_(bm, e, opts);
try {
metadata_repair_(bm, e, opts);
} catch (override_error const &e) {
ostringstream out;
out << "The following field needs to be provided on the command line due to corruption in the superblock: "
<< e.what();
throw runtime_error(out.str());
}
} catch (override_error const &e) {
ostringstream out;
out << "The following field needs to be provided on the command line due to corruption in the superblock: "
<< e.what();
throw runtime_error(out.str());
}
}
//----------------------------------------------------------------

View File

@ -47,8 +47,7 @@ namespace thin_provisioning {
}
bool skip_mappings_;
override_options overrides_;
override_options overrides_;
using dev_set = std::set<uint64_t>;
using maybe_dev_set = boost::optional<dev_set>;
@ -61,10 +60,10 @@ namespace thin_provisioning {
// corruption encountered will cause an exception to be thrown.
void metadata_dump(metadata::ptr md, emitter::ptr e, dump_options const &opts);
// We have to provide a different interface for repairing, since
// the superblock itself may be corrupt, so we wont be able
// to create the metadata object.
void metadata_repair(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts);
// We have to provide a different interface for repairing, since
// the superblock itself may be corrupt, so we wont be able
// to create the metadata object.
void metadata_repair(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts);
// Only used by ll_restore, so we leave the repair arg
void metadata_dump_subtree(metadata::ptr md, emitter::ptr e, bool repair, uint64_t subtree_root);

View File

@ -23,72 +23,72 @@ using namespace thin_provisioning;
//----------------------------------------------------------------
namespace {
class override_emitter : public emitter {
public:
override_emitter(emitter::ptr inner, override_options const &opts)
: inner_(inner),
opts_(opts) {
}
class override_emitter : public emitter {
public:
override_emitter(emitter::ptr inner, override_options const &opts)
: inner_(inner),
opts_(opts) {
}
virtual void begin_superblock(std::string const &uuid,
uint64_t time,
uint64_t trans_id,
boost::optional<uint32_t> flags,
boost::optional<uint32_t> version,
uint32_t data_block_size,
uint64_t nr_data_blocks,
boost::optional<uint64_t> metadata_snap) {
inner_->begin_superblock(uuid, time, opts_.get_transaction_id(trans_id),
virtual void begin_superblock(std::string const &uuid,
uint64_t time,
uint64_t trans_id,
boost::optional<uint32_t> flags,
boost::optional<uint32_t> version,
uint32_t data_block_size,
uint64_t nr_data_blocks,
boost::optional<uint64_t> metadata_snap) {
inner_->begin_superblock(uuid, time, opts_.get_transaction_id(trans_id),
flags, version, opts_.get_data_block_size(data_block_size),
opts_.get_nr_data_blocks(nr_data_blocks),
metadata_snap);
}
}
virtual void end_superblock() {
inner_->end_superblock();
}
virtual void end_superblock() {
inner_->end_superblock();
}
virtual void begin_device(uint32_t dev,
uint64_t mapped_blocks,
uint64_t trans_id,
uint64_t creation_time,
uint64_t snap_time) {
inner_->begin_device(dev, mapped_blocks, trans_id, creation_time, snap_time);
}
virtual void begin_device(uint32_t dev,
uint64_t mapped_blocks,
uint64_t trans_id,
uint64_t creation_time,
uint64_t snap_time) {
inner_->begin_device(dev, mapped_blocks, trans_id, creation_time, snap_time);
}
virtual void end_device() {
inner_->end_device();
}
virtual void end_device() {
inner_->end_device();
}
virtual void begin_named_mapping(std::string const &name) {
inner_->begin_named_mapping(name);
}
virtual void begin_named_mapping(std::string const &name) {
inner_->begin_named_mapping(name);
}
virtual void end_named_mapping() {
inner_->end_named_mapping();
}
virtual void end_named_mapping() {
inner_->end_named_mapping();
}
virtual void identifier(std::string const &name) {
inner_->identifier(name);
}
virtual void identifier(std::string const &name) {
inner_->identifier(name);
}
virtual void range_map(uint64_t origin_begin, uint64_t data_begin, uint32_t time, uint64_t len) {
inner_->range_map(origin_begin, data_begin, time, len);
}
virtual void range_map(uint64_t origin_begin, uint64_t data_begin, uint32_t time, uint64_t len) {
inner_->range_map(origin_begin, data_begin, time, len);
}
virtual void single_map(uint64_t origin_block, uint64_t data_block, uint32_t time) {
inner_->single_map(origin_block, data_block, time);
}
virtual void single_map(uint64_t origin_block, uint64_t data_block, uint32_t time) {
inner_->single_map(origin_block, data_block, time);
}
private:
emitter::ptr inner_;
override_options opts_;
};
private:
emitter::ptr inner_;
override_options opts_;
};
}
emitter::ptr thin_provisioning::create_override_emitter(emitter::ptr inner, override_options const &opts)
{
return emitter::ptr(new override_emitter(inner, opts));
return emitter::ptr(new override_emitter(inner, opts));
}
//----------------------------------------------------------------

View File

@ -28,56 +28,57 @@
//----------------------------------------------------------------
namespace thin_provisioning {
struct override_error : public std::runtime_error {
override_error(std::string const &str)
: std::runtime_error(str) {
}
};
struct override_error : public std::runtime_error {
override_error(std::string const &str)
: std::runtime_error(str) {
}
};
struct override_options {
uint64_t get_transaction_id() const {
if (!transaction_id_)
bad_override_("transaction id");
struct override_options {
uint64_t get_transaction_id() const {
if (!transaction_id_)
bad_override_("transaction id");
return *transaction_id_;
}
return *transaction_id_;
}
uint64_t get_transaction_id(uint64_t dflt) const {
return transaction_id_ ? *transaction_id_ : dflt;
}
uint64_t get_transaction_id(uint64_t dflt) const {
return transaction_id_ ? *transaction_id_ : dflt;
}
uint32_t get_data_block_size() const {
if (!data_block_size_)
bad_override_("data block size");
uint32_t get_data_block_size() const {
if (!data_block_size_)
bad_override_("data block size");
return *data_block_size_;
}
uint32_t get_data_block_size(uint32_t dflt) const {
return data_block_size_ ? *data_block_size_ : dflt;
}
return *data_block_size_;
}
uint64_t get_nr_data_blocks() const {
if (!nr_data_blocks_)
bad_override_("nr data blocks");
uint32_t get_data_block_size(uint32_t dflt) const {
return data_block_size_ ? *data_block_size_ : dflt;
}
return *nr_data_blocks_;
}
uint64_t get_nr_data_blocks() const {
if (!nr_data_blocks_)
bad_override_("nr data blocks");
uint64_t get_nr_data_blocks(uint64_t dflt) const {
return nr_data_blocks_ ? *nr_data_blocks_ : dflt;
}
return *nr_data_blocks_;
}
boost::optional<uint64_t> transaction_id_;
boost::optional<uint32_t> data_block_size_;
boost::optional<uint64_t> nr_data_blocks_;
uint64_t get_nr_data_blocks(uint64_t dflt) const {
return nr_data_blocks_ ? *nr_data_blocks_ : dflt;
}
private:
void bad_override_(std::string const &field) const {
throw override_error(field);
}
};
boost::optional<uint64_t> transaction_id_;
boost::optional<uint32_t> data_block_size_;
boost::optional<uint64_t> nr_data_blocks_;
emitter::ptr create_override_emitter(emitter::ptr inner, override_options const &opts);
private:
void bad_override_(std::string const &field) const {
throw override_error(field);
}
};
emitter::ptr create_override_emitter(emitter::ptr inner, override_options const &opts);
}
//----------------------------------------------------------------

View File

@ -156,7 +156,7 @@ namespace {
}
metadata::ptr md_;
override_options opts_;
override_options opts_;
bool in_superblock_;
block_address nr_data_blocks_;

View File

@ -97,8 +97,7 @@ namespace thin_provisioning {
block_address const SUPERBLOCK_LOCATION = 0;
uint32_t const SUPERBLOCK_MAGIC = 27022010;
uint32_t const METADATA_VERSION = 2;
uint32_t const METADATA_VERSION = 2;
//--------------------------------

View File

@ -26,6 +26,7 @@
#include "thin-provisioning/human_readable_format.h"
#include "thin-provisioning/metadata.h"
#include "thin-provisioning/metadata_dumper.h"
#include "thin-provisioning/override_emitter.h"
#include "thin-provisioning/shared_library_emitter.h"
#include "thin-provisioning/xml_format.h"
#include "version.h"
@ -84,35 +85,34 @@ namespace {
return e;
}
int dump_(string const &path, ostream &out, struct flags &flags) {
try {
emitter::ptr inner = create_emitter(flags.format, out);
emitter::ptr e = create_override_emitter(inner, flags.opts.overrides_);
int dump_(string const &path, ostream &out, struct flags &flags) {
try {
emitter::ptr inner = create_emitter(flags.format, out);
emitter::ptr e = create_override_emitter(inner, flags.opts.overrides_);
if (flags.repair) {
auto bm = open_bm(path, block_manager<>::READ_ONLY, true);
metadata_repair(bm, e, flags.opts.overrides_);
} else {
metadata::ptr md = open_metadata(path, flags);
metadata_dump(md, e, flags.opts);
}
if (flags.repair) {
auto bm = open_bm(path, block_manager<>::READ_ONLY, true);
metadata_repair(bm, e, flags.opts.overrides_);
} else {
metadata::ptr md = open_metadata(path, flags);
metadata_dump(md, e, flags.opts);
}
} catch (std::exception &e) {
cerr << e.what() << endl;
return 1;
}
} catch (std::exception &e) {
cerr << e.what() << endl;
return 1;
}
return 0;
}
int dump(string const &path, char const *output, struct flags &flags) {
if (output) {
ofstream out(output);
return dump_(path, out, flags);
} else
return dump_(path, cout, flags);
}
return 0;
}
int dump(string const &path, char const *output, struct flags &flags) {
if (output) {
ofstream out(output);
return dump_(path, out, flags);
} else
return dump_(path, cout, flags);
}
}
//----------------------------------------------------------------
@ -156,6 +156,9 @@ thin_dump_cmd::run(int argc, char **argv)
{ "repair", no_argument, NULL, 'r'},
{ "dev-id", required_argument, NULL, 1 },
{ "skip-mappings", no_argument, NULL, 2 },
{ "transaction-id", required_argument, NULL, 3 },
{ "data-block-size", required_argument, NULL, 4 },
{ "nr-data-blocks", required_argument, NULL, 5 },
{ "version", no_argument, NULL, 'V'},
{ NULL, no_argument, NULL, 0 }
};
@ -207,17 +210,17 @@ thin_dump_cmd::run(int argc, char **argv)
flags.opts.skip_mappings_ = true;
break;
case 3:
flags.opts.overrides_.transaction_id_ = parse_uint64(optarg, "transaction id");
break;
case 3:
flags.opts.overrides_.transaction_id_ = parse_uint64(optarg, "transaction id");
break;
case 4:
flags.opts.overrides_.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
break;
case 4:
flags.opts.overrides_.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
break;
case 5:
flags.opts.overrides_.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
break;
case 5:
flags.opts.overrides_.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
break;
case 'V':
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;

View File

@ -6,6 +6,7 @@
#include "base/output_file_requirements.h"
#include "persistent-data/file_utils.h"
#include "thin-provisioning/commands.h"
#include "thin-provisioning/override_emitter.h"
#include "human_readable_format.h"
#include "metadata_dumper.h"
#include "metadata.h"
@ -17,28 +18,28 @@ using namespace std;
using namespace thin_provisioning;
namespace {
int repair(string const &old_path, string const &new_path, override_options const &opts) {
bool metadata_touched = false;
try {
// block size gets updated by the restorer
block_manager<>::ptr new_bm = open_bm(new_path, block_manager<>::READ_WRITE);
file_utils::check_file_exists(old_path, false);
metadata_touched = true;
metadata::ptr new_md(new metadata(new_bm, metadata::CREATE, 128, 0));
emitter::ptr inner = create_restore_emitter(new_md);
emitter::ptr e = create_override_emitter(inner, opts);
block_manager<>::ptr old_bm = open_bm(old_path, block_manager<>::READ_ONLY);
metadata_repair(old_bm, e, opts);
int repair(string const &old_path, string const &new_path, override_options const &opts) {
bool metadata_touched = false;
try {
// block size gets updated by the restorer
block_manager<>::ptr new_bm = open_bm(new_path, block_manager<>::READ_WRITE);
file_utils::check_file_exists(old_path, false);
metadata_touched = true;
metadata::ptr new_md(new metadata(new_bm, metadata::CREATE, 128, 0));
emitter::ptr inner = create_restore_emitter(new_md);
emitter::ptr e = create_override_emitter(inner, opts);
block_manager<>::ptr old_bm = open_bm(old_path, block_manager<>::READ_ONLY);
metadata_repair(old_bm, e, opts);
} catch (std::exception &e) {
if (metadata_touched)
file_utils::zero_superblock(new_path);
cerr << e.what() << endl;
return 1;
}
} catch (std::exception &e) {
if (metadata_touched)
file_utils::zero_superblock(new_path);
cerr << e.what() << endl;
return 1;
}
return 0;
}
return 0;
}
}
//----------------------------------------------------------------
@ -51,15 +52,15 @@ thin_repair_cmd::thin_repair_cmd()
void
thin_repair_cmd::usage(std::ostream &out) const
{
out << "Usage: " << get_name() << " [options] {device|file}" << endl
<< "Options:" << endl
<< " {-h|--help}" << endl
<< " {-i|--input} <input metadata (binary format)>" << endl
<< " {-o|--output} <output metadata (binary format)>" << endl
<< " {--transaction-id} <natural>" << endl
<< " {--data-block-size} <natural>" << endl
<< " {--nr-data-blocks} <natural>" << endl
<< " {-V|--version}" << endl;
out << "Usage: " << get_name() << " [options] {device|file}" << endl
<< "Options:" << endl
<< " {-h|--help}" << endl
<< " {-i|--input} <input metadata (binary format)>" << endl
<< " {-o|--output} <output metadata (binary format)>" << endl
<< " {--transaction-id} <natural>" << endl
<< " {--data-block-size} <natural>" << endl
<< " {--nr-data-blocks} <natural>" << endl
<< " {-V|--version}" << endl;
}
int
@ -67,56 +68,55 @@ thin_repair_cmd::run(int argc, char **argv)
{
int c;
boost::optional<string> input_path, output_path;
override_options opts;
override_options opts;
const char shortopts[] = "hi:o:V";
const struct option longopts[] = {
{ "help", no_argument, NULL, 'h'},
{ "input", required_argument, NULL, 'i'},
{ "output", required_argument, NULL, 'o'},
{ "transaction-id", required_argument, NULL, 1},
{ "data-block-size", required_argument, NULL, 2},
{ "nr-data-blocks", required_argument, NULL, 3},
{ "version", no_argument, NULL, 'V'},
{ NULL, no_argument, NULL, 0 }
};
const struct option longopts[] = {
{ "help", no_argument, NULL, 'h'},
{ "input", required_argument, NULL, 'i'},
{ "output", required_argument, NULL, 'o'},
{ "transaction-id", required_argument, NULL, 1},
{ "data-block-size", required_argument, NULL, 2},
{ "nr-data-blocks", required_argument, NULL, 3},
{ "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);
return 0;
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
switch(c) {
case 'h':
usage(cout);
return 0;
case 'i':
input_path = optarg;
break;
case 'i':
input_path = optarg;
break;
case 'o':
output_path = optarg;
break;
case 'o':
output_path = optarg;
break;
case 1:
opts.transaction_id_ = parse_uint64(optarg, "transaction id");
break;
case 1:
opts.transaction_id_ = parse_uint64(optarg, "transaction id");
break;
case 2:
opts.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
break;
case 2:
opts.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
break;
case 3:
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
break;
case 3:
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
break;
case 'V':
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
return 0;
case 'V':
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
return 0;
default:
usage(cerr);
return 1;
}
}
default:
usage(cerr);
return 1;
}
}
if (!input_path) {
cerr << "no input file provided" << endl;
@ -133,8 +133,7 @@ thin_repair_cmd::run(int argc, char **argv)
return 1;
}
return repair(*input_path, *output_path, opts);
return repair(*input_path, *output_path, opts);
}
//----------------------------------------------------------------

View File

@ -45,28 +45,28 @@ using namespace thin_provisioning;
//----------------------------------------------------------------
namespace {
int restore(string const &backup_file, string const &dev, bool quiet, override_options const &opts) {
bool metadata_touched = false;
try {
// The block size gets updated by the restorer.
block_manager<>::ptr bm(open_bm(dev, block_manager<>::READ_WRITE));
file_utils::check_file_exists(backup_file);
metadata_touched = true;
metadata::ptr md(new metadata(bm, metadata::CREATE, 128, 0));
emitter::ptr inner = create_restore_emitter(md);
emitter::ptr restorer = create_override_emitter(inner, opts);
int restore(string const &backup_file, string const &dev, bool quiet, override_options const &opts) {
bool metadata_touched = false;
try {
// The block size gets updated by the restorer.
block_manager<>::ptr bm(open_bm(dev, block_manager<>::READ_WRITE));
file_utils::check_file_exists(backup_file);
metadata_touched = true;
metadata::ptr md(new metadata(bm, metadata::CREATE, 128, 0));
emitter::ptr inner = create_restore_emitter(md);
emitter::ptr restorer = create_override_emitter(inner, opts);
parse_xml(backup_file, restorer, quiet);
parse_xml(backup_file, restorer, quiet);
} catch (std::exception &e) {
if (metadata_touched)
file_utils::zero_superblock(dev);
cerr << e.what() << endl;
return 1;
}
} catch (std::exception &e) {
if (metadata_touched)
file_utils::zero_superblock(dev);
cerr << e.what() << endl;
return 1;
}
return 0;
}
return 0;
}
}
//----------------------------------------------------------------
@ -79,99 +79,98 @@ thin_restore_cmd::thin_restore_cmd()
void
thin_restore_cmd::usage(std::ostream &out) const
{
out << "Usage: " << get_name() << " [options]" << endl
<< "Options:" << endl
<< " {-h|--help}" << endl
<< " {-i|--input} <input xml file>" << endl
<< " {-o|--output} <output device or file>" << endl
<< " {--transaction-id} <natural>" << endl
<< " {--data-block-size} <natural>" << endl
<< " {--nr-data-blocks} <natural>" << endl
<< " {-q|--quiet}" << endl
<< " {-V|--version}" << endl;
out << "Usage: " << get_name() << " [options]" << endl
<< "Options:" << endl
<< " {-h|--help}" << endl
<< " {-i|--input} <input xml file>" << endl
<< " {-o|--output} <output device or file>" << endl
<< " {--transaction-id} <natural>" << endl
<< " {--data-block-size} <natural>" << endl
<< " {--nr-data-blocks} <natural>" << endl
<< " {-q|--quiet}" << endl
<< " {-V|--version}" << endl;
}
int
thin_restore_cmd::run(int argc, char **argv)
{
int c;
const char *shortopts = "hi:o:qV";
string input, output;
bool quiet = false;
override_options opts;
int c;
const char *shortopts = "hi:o:qV";
string input, output;
bool quiet = false;
override_options opts;
const struct option longopts[] = {
{ "help", no_argument, NULL, 'h'},
{ "input", required_argument, NULL, 'i' },
{ "output", required_argument, NULL, 'o'},
{ "transaction-id", required_argument, NULL, 1},
{ "data-block-size", required_argument, NULL, 2},
{ "nr-data-blocks", required_argument, NULL, 3},
{ "quiet", no_argument, NULL, 'q'},
{ "version", no_argument, NULL, 'V'},
{ NULL, no_argument, NULL, 0 }
};
const struct option longopts[] = {
{ "help", no_argument, NULL, 'h'},
{ "input", required_argument, NULL, 'i' },
{ "output", required_argument, NULL, 'o'},
{ "transaction-id", required_argument, NULL, 1},
{ "data-block-size", required_argument, NULL, 2},
{ "nr-data-blocks", required_argument, NULL, 3},
{ "quiet", no_argument, NULL, 'q'},
{ "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);
return 0;
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
switch(c) {
case 'h':
usage(cout);
return 0;
case 'i':
input = optarg;
break;
case 'i':
input = optarg;
break;
case 'o':
output = optarg;
break;
case 'o':
output = optarg;
break;
case 1:
opts.transaction_id_ = parse_uint64(optarg, "transaction id");
break;
case 1:
opts.transaction_id_ = parse_uint64(optarg, "transaction id");
break;
case 2:
opts.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
break;
case 2:
opts.data_block_size_ = static_cast<uint32_t>(parse_uint64(optarg, "data block size"));
break;
case 3:
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
break;
case 3:
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
break;
case 'q':
quiet = true;
break;
case 'q':
quiet = true;
break;
case 'V':
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
return 0;
case 'V':
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
return 0;
default:
usage(cerr);
return 1;
}
}
default:
usage(cerr);
return 1;
}
}
if (argc != optind) {
usage(cerr);
return 1;
}
if (argc != optind) {
usage(cerr);
return 1;
}
if (input.empty()) {
cerr << "No input file provided." << endl << endl;
usage(cerr);
return 1;
}
cerr << "No input file provided." << endl << endl;
usage(cerr);
return 1;
}
if (output.empty()) {
cerr << "No output file provided." << endl << endl;
usage(cerr);
return 1;
} else
check_output_file_requirements(output);
if (output.empty()) {
cerr << "No output file provided." << endl << endl;
usage(cerr);
return 1;
} else
check_output_file_requirements(output);
return restore(input, output, quiet, opts);
return restore(input, output, quiet, opts);
}
//----------------------------------------------------------------