Corrupt superblock repair
This commit is contained in:
parent
0fc7529c01
commit
91b4714e38
@ -101,6 +101,7 @@ SOURCE=\
|
|||||||
thin-provisioning/metadata_checker.cc \
|
thin-provisioning/metadata_checker.cc \
|
||||||
thin-provisioning/metadata_counter.cc \
|
thin-provisioning/metadata_counter.cc \
|
||||||
thin-provisioning/metadata_dumper.cc \
|
thin-provisioning/metadata_dumper.cc \
|
||||||
|
thin-provisioning/override_emitter.cc \
|
||||||
thin-provisioning/pool_stream.cc \
|
thin-provisioning/pool_stream.cc \
|
||||||
thin-provisioning/restore_emitter.cc \
|
thin-provisioning/restore_emitter.cc \
|
||||||
thin-provisioning/rmap_visitor.cc \
|
thin-provisioning/rmap_visitor.cc \
|
||||||
|
@ -51,6 +51,16 @@
|
|||||||
(with-temp-file-sized ((md "thin.bin" (meg 4)))
|
(with-temp-file-sized ((md "thin.bin" (meg 4)))
|
||||||
b1 b2 ...))))
|
b1 b2 ...))))
|
||||||
|
|
||||||
|
(define (damage-superblock md)
|
||||||
|
(system (string-append "dd if=/dev/zero of=" md " bs=4K count=1 conv=notrunc > /dev/null 2>&1")))
|
||||||
|
|
||||||
|
(define-syntax with-damaged-superblock
|
||||||
|
(syntax-rules ()
|
||||||
|
((_ (md) b1 b2 ...)
|
||||||
|
(with-valid-metadata (md)
|
||||||
|
(damage-superblock md)
|
||||||
|
b1 b2 ...))))
|
||||||
|
|
||||||
;; We have to export something that forces all the initialisation expressions
|
;; We have to export something that forces all the initialisation expressions
|
||||||
;; to run.
|
;; to run.
|
||||||
(define (register-thin-tests) #t)
|
(define (register-thin-tests) #t)
|
||||||
@ -230,6 +240,54 @@
|
|||||||
(run-ok-rcv (stdout stderr) (thin-dump md)
|
(run-ok-rcv (stdout stderr) (thin-dump md)
|
||||||
(assert-eof stderr))))
|
(assert-eof stderr))))
|
||||||
|
|
||||||
|
(define-scenario (thin-dump override transaction-id)
|
||||||
|
"thin_dump obeys the --transaction-id override"
|
||||||
|
(with-valid-metadata (md)
|
||||||
|
(run-ok-rcv (stdout stderr) (thin-dump "--transaction-id 2345" md)
|
||||||
|
(assert-eof stderr)
|
||||||
|
(assert-matches ".*transaction=\"2345\"" stdout))))
|
||||||
|
|
||||||
|
(define-scenario (thin-dump override data-block-size)
|
||||||
|
"thin_dump obeys the --data-block-size override"
|
||||||
|
(with-valid-metadata (md)
|
||||||
|
(run-ok-rcv (stdout stderr) (thin-dump "--data-block-size 8192" md)
|
||||||
|
(assert-eof stderr)
|
||||||
|
(assert-matches ".*data_block_size=\"8192\"" stdout))))
|
||||||
|
|
||||||
|
(define-scenario (thin-dump override nr-data-blocks)
|
||||||
|
"thin_dump obeys the --nr-data-blocks override"
|
||||||
|
(with-valid-metadata (md)
|
||||||
|
(run-ok-rcv (stdout stderr) (thin-dump "--nr-data-blocks 234500" md)
|
||||||
|
(assert-eof stderr)
|
||||||
|
(assert-matches ".*nr_data_blocks=\"234500\"" stdout))))
|
||||||
|
|
||||||
|
(define-scenario (thin-dump repair-superblock succeeds)
|
||||||
|
"thin_dump can restore a missing superblock"
|
||||||
|
(with-valid-metadata (md)
|
||||||
|
(run-ok-rcv (expected-xml stderr) (thin-dump "--transaction-id=5" "--data-block-size=128" "--nr-data-blocks=4096000" md)
|
||||||
|
(damage-superblock md)
|
||||||
|
(run-ok-rcv (repaired-xml stderr) (thin-dump "--repair" "--transaction-id=5" "--data-block-size=128" "--nr-data-blocks=4096000" md)
|
||||||
|
(assert-eof stderr)
|
||||||
|
(assert-equal expected-xml repaired-xml)))))
|
||||||
|
|
||||||
|
(define-scenario (thin-dump repair-superblock missing-transaction-id)
|
||||||
|
"--transaction-id is mandatory if the superblock is damaged"
|
||||||
|
(with-damaged-superblock (md)
|
||||||
|
(run-fail-rcv (_ stderr) (thin-dump "--repair" "--data-block-size=128" "--nr-data-blocks=4096000" md)
|
||||||
|
(assert-matches ".*transaction id.*" stderr))))
|
||||||
|
|
||||||
|
(define-scenario (thin-dump repair-superblock missing-data-block-size)
|
||||||
|
"--data-block-size is mandatory if the superblock is damaged"
|
||||||
|
(with-damaged-superblock (md)
|
||||||
|
(run-fail-rcv (_ stderr) (thin-dump "--repair" "--transaction-id=5" "--nr-data-blocks=4096000" md)
|
||||||
|
(assert-matches ".*data block size.*" stderr))))
|
||||||
|
|
||||||
|
(define-scenario (thin-dump repair-superblock missing-nr-data-blocks)
|
||||||
|
"--nr-data-blocks is mandatory if the superblock is damaged"
|
||||||
|
(with-damaged-superblock (md)
|
||||||
|
(run-fail-rcv (_ stderr) (thin-dump "--repair" "--transaction-id=5" "--data-block-size=128" md)
|
||||||
|
(assert-matches ".*nr data blocks.*" stderr))))
|
||||||
|
|
||||||
;;;-----------------------------------------------------------
|
;;;-----------------------------------------------------------
|
||||||
;;; thin_rmap scenarios
|
;;; thin_rmap scenarios
|
||||||
;;;-----------------------------------------------------------
|
;;;-----------------------------------------------------------
|
||||||
@ -356,4 +414,63 @@
|
|||||||
(run-fail-rcv (_ stderr) (thin-repair "-i " xml)
|
(run-fail-rcv (_ stderr) (thin-repair "-i " xml)
|
||||||
(assert-starts-with "No output file provided." stderr))))
|
(assert-starts-with "No output file provided." stderr))))
|
||||||
|
|
||||||
|
(define-scenario (thin-repair override transaction-id)
|
||||||
|
"thin_repair obeys the --transaction-id override"
|
||||||
|
(with-valid-metadata (md1)
|
||||||
|
(with-empty-metadata (md2)
|
||||||
|
(run-ok-rcv (stdout stderr) (thin-repair "--transaction-id 2345" "-i" md1 "-o" md2)
|
||||||
|
(assert-eof stderr))
|
||||||
|
(run-ok-rcv (stdout stderr) (thin-dump md2)
|
||||||
|
(assert-matches ".*transaction=\"2345\"" stdout)))))
|
||||||
|
|
||||||
|
(define-scenario (thin-repair override data-block-size)
|
||||||
|
"thin_repair obeys the --data-block-size override"
|
||||||
|
(with-valid-metadata (md1)
|
||||||
|
(with-empty-metadata (md2)
|
||||||
|
(run-ok-rcv (stdout stderr) (thin-repair "--data-block-size 8192" "-i" md1 "-o" md2)
|
||||||
|
(assert-eof stderr))
|
||||||
|
(run-ok-rcv (stdout stderr) (thin-dump md2)
|
||||||
|
(assert-matches ".*data_block_size=\"8192\"" stdout)))))
|
||||||
|
|
||||||
|
(define-scenario (thin-repair override nr-data-blocks)
|
||||||
|
"thin_repair obeys the --nr-data-blocks override"
|
||||||
|
(with-valid-metadata (md1)
|
||||||
|
(with-empty-metadata (md2)
|
||||||
|
(run-ok-rcv (stdout stderr) (thin-repair "--nr-data-blocks 234500" "-i" md1 "-o" md2)
|
||||||
|
(assert-eof stderr))
|
||||||
|
(run-ok-rcv (stdout stderr) (thin-dump md2)
|
||||||
|
(assert-matches ".*nr_data_blocks=\"234500\"" stdout)))))
|
||||||
|
|
||||||
|
(define-scenario (thin-repair superblock succeeds)
|
||||||
|
"thin_repair can restore a missing superblock"
|
||||||
|
(with-valid-metadata (md1)
|
||||||
|
(run-ok-rcv (expected-xml stderr) (thin-dump "--transaction-id=5" "--data-block-size=128" "--nr-data-blocks=4096000" md1)
|
||||||
|
(damage-superblock md1)
|
||||||
|
(with-empty-metadata (md2)
|
||||||
|
(run-ok-rcv (_ stderr) (thin-repair "--transaction-id=5" "--data-block-size=128" "--nr-data-blocks=4096000" "-i" md1 "-o" md2)
|
||||||
|
(assert-eof stderr))
|
||||||
|
(run-ok-rcv (repaired-xml stderr) (thin-dump md2)
|
||||||
|
(assert-eof stderr)
|
||||||
|
(assert-equal expected-xml repaired-xml))))))
|
||||||
|
|
||||||
|
(define-scenario (thin-repair superblock missing-transaction-id)
|
||||||
|
"--transaction-id is mandatory if the superblock is damaged"
|
||||||
|
(with-damaged-superblock (md1)
|
||||||
|
(with-empty-metadata (md2)
|
||||||
|
(run-fail-rcv (_ stderr) (thin-repair "--data-block-size=128" "--nr-data-blocks=4096000" "-i" md1 "-o" md2)
|
||||||
|
(assert-matches ".*transaction id.*" stderr)))))
|
||||||
|
|
||||||
|
(define-scenario (thin-repair superblock missing-data-block-size)
|
||||||
|
"--data-block-size is mandatory if the superblock is damaged"
|
||||||
|
(with-damaged-superblock (md1)
|
||||||
|
(with-empty-metadata (md2)
|
||||||
|
(run-fail-rcv (_ stderr) (thin-repair "--transaction-id=5" "--nr-data-blocks=4096000" "-i" md1 "-o" md2)
|
||||||
|
(assert-matches ".*data block size.*" stderr)))))
|
||||||
|
|
||||||
|
(define-scenario (thin-repair superblock missing-nr-data-blocks)
|
||||||
|
"--nr-data-blocks is mandatory if the superblock is damaged"
|
||||||
|
(with-damaged-superblock (md1)
|
||||||
|
(with-empty-metadata (md2)
|
||||||
|
(run-fail-rcv (_ stderr) (thin-repair "--transaction-id=5" "--data-block-size=128" "-i" md1 "-o" md2)
|
||||||
|
(assert-matches ".*nr data blocks.*" stderr)))))
|
||||||
)
|
)
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
using namespace base;
|
using namespace base;
|
||||||
using namespace thin_provisioning;
|
using namespace thin_provisioning;
|
||||||
|
|
||||||
#define METADATA_VERSION 2
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "thin-provisioning/mapping_tree.h"
|
#include "thin-provisioning/mapping_tree.h"
|
||||||
#include "thin-provisioning/metadata_dumper.h"
|
#include "thin-provisioning/metadata_dumper.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -281,7 +282,14 @@ namespace {
|
|||||||
examined_(bm.get_nr_blocks(), false) {
|
examined_(bm.get_nr_blocks(), false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<pair<block_address, block_address>>
|
struct roots {
|
||||||
|
block_address mapping_root;
|
||||||
|
block_address detail_root;
|
||||||
|
uint32_t time;
|
||||||
|
};
|
||||||
|
|
||||||
|
optional<roots>
|
||||||
|
|
||||||
find_best_roots(transaction_manager &tm) {
|
find_best_roots(transaction_manager &tm) {
|
||||||
vector<node_info> mapping_roots;
|
vector<node_info> mapping_roots;
|
||||||
vector<node_info> device_roots;
|
vector<node_info> device_roots;
|
||||||
@ -297,13 +305,15 @@ namespace {
|
|||||||
auto info = get_info(b);
|
auto info = get_info(b);
|
||||||
|
|
||||||
if (info.valid) {
|
if (info.valid) {
|
||||||
if (info.type == TOP_LEVEL)
|
if (info.type == TOP_LEVEL) {
|
||||||
mapping_roots.push_back(info);
|
mapping_roots.push_back(info);
|
||||||
|
}
|
||||||
|
|
||||||
else if (info.type == DEVICE_DETAILS)
|
else if (info.type == DEVICE_DETAILS) {
|
||||||
device_roots.push_back(info);
|
device_roots.push_back(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if SHOW_WORKING
|
#if SHOW_WORKING
|
||||||
cerr << "mapping candidates (" << mapping_roots.size() << "):\n";
|
cerr << "mapping candidates (" << mapping_roots.size() << "):\n";
|
||||||
@ -323,12 +333,27 @@ namespace {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pairs.size())
|
if (pairs.size())
|
||||||
return pairs[0];
|
return mk_roots(pairs[0]);
|
||||||
else
|
else
|
||||||
return optional<pair<block_address, block_address>>();
|
return optional<roots>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
bool set_eq(set<uint32_t> const &lhs, set<uint32_t> const &rhs) {
|
bool set_eq(set<uint32_t> const &lhs, set<uint32_t> const &rhs) {
|
||||||
for (auto v : lhs)
|
for (auto v : lhs)
|
||||||
if (!rhs.count(v))
|
if (!rhs.count(v))
|
||||||
@ -599,6 +624,15 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
block_manager<> &bm_;
|
block_manager<> &bm_;
|
||||||
vector<bool> referenced_;
|
vector<bool> referenced_;
|
||||||
vector<bool> examined_;
|
vector<bool> examined_;
|
||||||
@ -745,8 +779,10 @@ namespace {
|
|||||||
return 0ull;
|
return 0ull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
do_repair_(block_manager<>::ptr bm, superblock_detail::superblock const &sb, emitter::ptr e)
|
emit_trees_(block_manager<>::ptr bm, superblock_detail::superblock const &sb,
|
||||||
|
emitter::ptr e, override_options const &ropts)
|
||||||
{
|
{
|
||||||
metadata md(bm, sb);
|
metadata md(bm, sb);
|
||||||
dump_options opts;
|
dump_options opts;
|
||||||
@ -772,7 +808,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
metadata_repair_(block_manager<>::ptr bm, emitter::ptr e)
|
find_better_roots_(block_manager<>::ptr bm, superblock_detail::superblock &sb)
|
||||||
{
|
{
|
||||||
// We assume the superblock is wrong, and find the best roots
|
// We assume the superblock is wrong, and find the best roots
|
||||||
// for ourselves. We've had a few cases where people have
|
// for ourselves. We've had a few cases where people have
|
||||||
@ -781,17 +817,64 @@ namespace {
|
|||||||
gatherer g(*bm);
|
gatherer g(*bm);
|
||||||
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
|
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
|
||||||
auto p = g.find_best_roots(*tm);
|
auto p = g.find_best_roots(*tm);
|
||||||
auto sb = read_superblock(*bm);
|
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
sb.metadata_snap_ = 0;
|
sb.metadata_snap_ = 0;
|
||||||
sb.device_details_root_ = p->first;
|
sb.time_ = p->time;
|
||||||
sb.data_mapping_root_ = p->second;
|
sb.device_details_root_ = p->detail_root;
|
||||||
|
sb.data_mapping_root_ = p->mapping_root;
|
||||||
sb.metadata_nr_blocks_ = bm->get_nr_blocks();
|
sb.metadata_nr_blocks_ = bm->get_nr_blocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
do_repair_(bm, sb, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
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>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
@ -821,18 +904,17 @@ thin_provisioning::metadata_dump(metadata::ptr md, emitter::ptr e, dump_options
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
thin_provisioning::metadata_repair(block_manager<>::ptr bm, emitter::ptr e)
|
thin_provisioning::metadata_repair(block_manager<>::ptr bm, emitter::ptr e, override_options const &opts)
|
||||||
{
|
{
|
||||||
auto sb = read_superblock(*bm);
|
try {
|
||||||
auto tm = open_tm(bm, superblock_detail::SUPERBLOCK_LOCATION);
|
metadata_repair_(bm, e, opts);
|
||||||
|
|
||||||
if (get_dev_ids(*tm, sb.device_details_root_) && get_map_ids(*tm, sb.data_mapping_root_)) {
|
} catch (override_error const &e) {
|
||||||
// The roots in the superblock look ok (perhaps the corruption was in the
|
ostringstream out;
|
||||||
// space maps).
|
out << "The following field needs to be provided on the command line due to corruption in the superblock: "
|
||||||
auto sb = read_superblock(bm);
|
<< e.what();
|
||||||
do_repair_(bm, sb, e);
|
throw runtime_error(out.str());
|
||||||
} else
|
}
|
||||||
metadata_repair_(bm, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
#ifndef METADATA_DUMPER_H
|
#ifndef METADATA_DUMPER_H
|
||||||
#define METADATA_DUMPER_H
|
#define METADATA_DUMPER_H
|
||||||
|
|
||||||
#include "emitter.h"
|
#include "thin-provisioning/emitter.h"
|
||||||
#include "metadata.h"
|
#include "thin-provisioning/metadata.h"
|
||||||
|
#include "thin-provisioning/override_emitter.h"
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -46,6 +47,8 @@ namespace thin_provisioning {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool skip_mappings_;
|
bool skip_mappings_;
|
||||||
|
override_options overrides_;
|
||||||
|
|
||||||
|
|
||||||
using dev_set = std::set<uint64_t>;
|
using dev_set = std::set<uint64_t>;
|
||||||
using maybe_dev_set = boost::optional<dev_set>;
|
using maybe_dev_set = boost::optional<dev_set>;
|
||||||
@ -61,7 +64,7 @@ namespace thin_provisioning {
|
|||||||
// We have to provide a different interface for repairing, since
|
// We have to provide a different interface for repairing, since
|
||||||
// the superblock itself may be corrupt, so we wont be able
|
// the superblock itself may be corrupt, so we wont be able
|
||||||
// to create the metadata object.
|
// to create the metadata object.
|
||||||
void metadata_repair(block_manager<>::ptr bm, emitter::ptr e);
|
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
|
// 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);
|
void metadata_dump_subtree(metadata::ptr md, emitter::ptr e, bool repair, uint64_t subtree_root);
|
||||||
|
95
thin-provisioning/override_emitter.cc
Normal file
95
thin-provisioning/override_emitter.cc
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright (C) 2019 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 "thin-provisioning/override_emitter.h"
|
||||||
|
|
||||||
|
using namespace thin_provisioning;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
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),
|
||||||
|
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 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 begin_named_mapping(std::string const &name) {
|
||||||
|
inner_->begin_named_mapping(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void end_named_mapping() {
|
||||||
|
inner_->end_named_mapping();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter::ptr thin_provisioning::create_override_emitter(emitter::ptr inner, override_options const &opts)
|
||||||
|
{
|
||||||
|
return emitter::ptr(new override_emitter(inner, opts));
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
85
thin-provisioning/override_emitter.h
Normal file
85
thin-provisioning/override_emitter.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright (C) 2019 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 TP_OVERRIDE_EMITTER_H
|
||||||
|
#define TP_OVERRIDE_EMITTER_H
|
||||||
|
|
||||||
|
#include "emitter.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace thin_provisioning {
|
||||||
|
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");
|
||||||
|
|
||||||
|
return *transaction_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
return *data_block_size_;
|
||||||
|
}
|
||||||
|
uint32_t get_data_block_size(uint32_t dflt) const {
|
||||||
|
return data_block_size_ ? *data_block_size_ : dflt;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t get_nr_data_blocks() const {
|
||||||
|
if (!nr_data_blocks_)
|
||||||
|
bad_override_("nr data blocks");
|
||||||
|
|
||||||
|
return *nr_data_blocks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t get_nr_data_blocks(uint64_t dflt) const {
|
||||||
|
return nr_data_blocks_ ? *nr_data_blocks_ : dflt;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<uint64_t> transaction_id_;
|
||||||
|
boost::optional<uint32_t> data_block_size_;
|
||||||
|
boost::optional<uint64_t> nr_data_blocks_;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif
|
@ -16,6 +16,7 @@
|
|||||||
// with thin-provisioning-tools. If not, see
|
// with thin-provisioning-tools. If not, see
|
||||||
// <http://www.gnu.org/licenses/>.
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "thin-provisioning/override_emitter.h"
|
||||||
#include "thin-provisioning/restore_emitter.h"
|
#include "thin-provisioning/restore_emitter.h"
|
||||||
#include "thin-provisioning/superblock.h"
|
#include "thin-provisioning/superblock.h"
|
||||||
|
|
||||||
@ -155,6 +156,8 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
metadata::ptr md_;
|
metadata::ptr md_;
|
||||||
|
override_options opts_;
|
||||||
|
|
||||||
bool in_superblock_;
|
bool in_superblock_;
|
||||||
block_address nr_data_blocks_;
|
block_address nr_data_blocks_;
|
||||||
boost::optional<uint32_t> current_device_;
|
boost::optional<uint32_t> current_device_;
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include "emitter.h"
|
#include "emitter.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
namespace thin_provisioning {
|
namespace thin_provisioning {
|
||||||
|
@ -97,6 +97,8 @@ namespace thin_provisioning {
|
|||||||
|
|
||||||
block_address const SUPERBLOCK_LOCATION = 0;
|
block_address const SUPERBLOCK_LOCATION = 0;
|
||||||
uint32_t const SUPERBLOCK_MAGIC = 27022010;
|
uint32_t const SUPERBLOCK_MAGIC = 27022010;
|
||||||
|
uint32_t const METADATA_VERSION = 2;
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------
|
//--------------------------------
|
||||||
|
|
||||||
|
@ -86,11 +86,12 @@ namespace {
|
|||||||
|
|
||||||
int dump_(string const &path, ostream &out, struct flags &flags) {
|
int dump_(string const &path, ostream &out, struct flags &flags) {
|
||||||
try {
|
try {
|
||||||
emitter::ptr e = create_emitter(flags.format, out);
|
emitter::ptr inner = create_emitter(flags.format, out);
|
||||||
|
emitter::ptr e = create_override_emitter(inner, flags.opts.overrides_);
|
||||||
|
|
||||||
if (flags.repair) {
|
if (flags.repair) {
|
||||||
auto bm = open_bm(path, block_manager<>::READ_ONLY, true);
|
auto bm = open_bm(path, block_manager<>::READ_ONLY, true);
|
||||||
metadata_repair(bm, e);
|
metadata_repair(bm, e, flags.opts.overrides_);
|
||||||
} else {
|
} else {
|
||||||
metadata::ptr md = open_metadata(path, flags);
|
metadata::ptr md = open_metadata(path, flags);
|
||||||
metadata_dump(md, e, flags.opts);
|
metadata_dump(md, e, flags.opts);
|
||||||
@ -111,6 +112,7 @@ namespace {
|
|||||||
} else
|
} else
|
||||||
return dump_(path, cout, flags);
|
return dump_(path, cout, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
@ -205,6 +207,18 @@ thin_dump_cmd::run(int argc, char **argv)
|
|||||||
flags.opts.skip_mappings_ = true;
|
flags.opts.skip_mappings_ = true;
|
||||||
break;
|
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 5:
|
||||||
|
flags.opts.overrides_.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
|
||||||
|
break;
|
||||||
|
|
||||||
case 'V':
|
case 'V':
|
||||||
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -17,7 +17,7 @@ using namespace std;
|
|||||||
using namespace thin_provisioning;
|
using namespace thin_provisioning;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int repair(string const &old_path, string const &new_path) {
|
int repair(string const &old_path, string const &new_path, override_options const &opts) {
|
||||||
bool metadata_touched = false;
|
bool metadata_touched = false;
|
||||||
try {
|
try {
|
||||||
// block size gets updated by the restorer
|
// block size gets updated by the restorer
|
||||||
@ -25,9 +25,10 @@ namespace {
|
|||||||
file_utils::check_file_exists(old_path, false);
|
file_utils::check_file_exists(old_path, false);
|
||||||
metadata_touched = true;
|
metadata_touched = true;
|
||||||
metadata::ptr new_md(new metadata(new_bm, metadata::CREATE, 128, 0));
|
metadata::ptr new_md(new metadata(new_bm, metadata::CREATE, 128, 0));
|
||||||
emitter::ptr e = create_restore_emitter(new_md);
|
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);
|
block_manager<>::ptr old_bm = open_bm(old_path, block_manager<>::READ_ONLY);
|
||||||
metadata_repair(old_bm, e);
|
metadata_repair(old_bm, e, opts);
|
||||||
|
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
if (metadata_touched)
|
if (metadata_touched)
|
||||||
@ -55,6 +56,9 @@ thin_repair_cmd::usage(std::ostream &out) const
|
|||||||
<< " {-h|--help}" << endl
|
<< " {-h|--help}" << endl
|
||||||
<< " {-i|--input} <input metadata (binary format)>" << endl
|
<< " {-i|--input} <input metadata (binary format)>" << endl
|
||||||
<< " {-o|--output} <output 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;
|
<< " {-V|--version}" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,12 +67,17 @@ thin_repair_cmd::run(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
boost::optional<string> input_path, output_path;
|
boost::optional<string> input_path, output_path;
|
||||||
|
override_options opts;
|
||||||
|
|
||||||
const char shortopts[] = "hi:o:V";
|
const char shortopts[] = "hi:o:V";
|
||||||
|
|
||||||
const struct option longopts[] = {
|
const struct option longopts[] = {
|
||||||
{ "help", no_argument, NULL, 'h'},
|
{ "help", no_argument, NULL, 'h'},
|
||||||
{ "input", required_argument, NULL, 'i'},
|
{ "input", required_argument, NULL, 'i'},
|
||||||
{ "output", required_argument, NULL, 'o'},
|
{ "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'},
|
{ "version", no_argument, NULL, 'V'},
|
||||||
{ NULL, no_argument, NULL, 0 }
|
{ NULL, no_argument, NULL, 0 }
|
||||||
};
|
};
|
||||||
@ -87,6 +96,18 @@ thin_repair_cmd::run(int argc, char **argv)
|
|||||||
output_path = optarg;
|
output_path = optarg;
|
||||||
break;
|
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 3:
|
||||||
|
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
|
||||||
|
break;
|
||||||
|
|
||||||
case 'V':
|
case 'V':
|
||||||
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
||||||
return 0;
|
return 0;
|
||||||
@ -112,7 +133,8 @@ thin_repair_cmd::run(int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return repair(*input_path, *output_path);
|
return repair(*input_path, *output_path, opts);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "thin-provisioning/emitter.h"
|
#include "thin-provisioning/emitter.h"
|
||||||
#include "thin-provisioning/human_readable_format.h"
|
#include "thin-provisioning/human_readable_format.h"
|
||||||
#include "thin-provisioning/metadata.h"
|
#include "thin-provisioning/metadata.h"
|
||||||
|
#include "thin-provisioning/override_emitter.h"
|
||||||
#include "thin-provisioning/restore_emitter.h"
|
#include "thin-provisioning/restore_emitter.h"
|
||||||
#include "thin-provisioning/xml_format.h"
|
#include "thin-provisioning/xml_format.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
@ -44,7 +45,7 @@ using namespace thin_provisioning;
|
|||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int restore(string const &backup_file, string const &dev, bool quiet) {
|
int restore(string const &backup_file, string const &dev, bool quiet, override_options const &opts) {
|
||||||
bool metadata_touched = false;
|
bool metadata_touched = false;
|
||||||
try {
|
try {
|
||||||
// The block size gets updated by the restorer.
|
// The block size gets updated by the restorer.
|
||||||
@ -52,7 +53,8 @@ namespace {
|
|||||||
file_utils::check_file_exists(backup_file);
|
file_utils::check_file_exists(backup_file);
|
||||||
metadata_touched = true;
|
metadata_touched = true;
|
||||||
metadata::ptr md(new metadata(bm, metadata::CREATE, 128, 0));
|
metadata::ptr md(new metadata(bm, metadata::CREATE, 128, 0));
|
||||||
emitter::ptr restorer = create_restore_emitter(md);
|
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);
|
||||||
|
|
||||||
@ -82,6 +84,9 @@ thin_restore_cmd::usage(std::ostream &out) const
|
|||||||
<< " {-h|--help}" << endl
|
<< " {-h|--help}" << endl
|
||||||
<< " {-i|--input} <input xml file>" << endl
|
<< " {-i|--input} <input xml file>" << endl
|
||||||
<< " {-o|--output} <output device or 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
|
<< " {-q|--quiet}" << endl
|
||||||
<< " {-V|--version}" << endl;
|
<< " {-V|--version}" << endl;
|
||||||
}
|
}
|
||||||
@ -93,10 +98,15 @@ thin_restore_cmd::run(int argc, char **argv)
|
|||||||
const char *shortopts = "hi:o:qV";
|
const char *shortopts = "hi:o:qV";
|
||||||
string input, output;
|
string input, output;
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
|
override_options opts;
|
||||||
|
|
||||||
const struct option longopts[] = {
|
const struct option longopts[] = {
|
||||||
{ "help", no_argument, NULL, 'h'},
|
{ "help", no_argument, NULL, 'h'},
|
||||||
{ "input", required_argument, NULL, 'i' },
|
{ "input", required_argument, NULL, 'i' },
|
||||||
{ "output", required_argument, NULL, 'o'},
|
{ "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'},
|
{ "quiet", no_argument, NULL, 'q'},
|
||||||
{ "version", no_argument, NULL, 'V'},
|
{ "version", no_argument, NULL, 'V'},
|
||||||
{ NULL, no_argument, NULL, 0 }
|
{ NULL, no_argument, NULL, 0 }
|
||||||
@ -116,6 +126,18 @@ thin_restore_cmd::run(int argc, char **argv)
|
|||||||
output = optarg;
|
output = optarg;
|
||||||
break;
|
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 3:
|
||||||
|
opts.nr_data_blocks_ = parse_uint64(optarg, "nr data blocks");
|
||||||
|
break;
|
||||||
|
|
||||||
case 'q':
|
case 'q':
|
||||||
quiet = true;
|
quiet = true;
|
||||||
break;
|
break;
|
||||||
@ -148,7 +170,8 @@ thin_restore_cmd::run(int argc, char **argv)
|
|||||||
} else
|
} else
|
||||||
check_output_file_requirements(output);
|
check_output_file_requirements(output);
|
||||||
|
|
||||||
return restore(input, output, quiet);
|
return restore(input, output, quiet, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
#include "thin-provisioning/superblock.h"
|
#include "thin-provisioning/superblock.h"
|
||||||
#include "thin-provisioning/variable_chunk_stream.h"
|
#include "thin-provisioning/variable_chunk_stream.h"
|
||||||
|
|
||||||
#include <boost/uuid/sha1.hpp>
|
#include <boost/compute/detail/sha1.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
Loading…
Reference in New Issue
Block a user