From 85d1701ba1a0c246c9eca31a6c921b59972c8504 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 26 May 2015 12:06:34 +0100 Subject: [PATCH 01/59] [btree_damage_visitor] Check the value_size agrees. Patch from Ming-Hung Tsai --- persistent-data/data-structures/btree.h | 3 +++ persistent-data/data-structures/btree.tcc | 26 ++++++++++++++----- .../data-structures/btree_damage_visitor.h | 12 +++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/persistent-data/data-structures/btree.h b/persistent-data/data-structures/btree.h index f4130c7..3966148 100644 --- a/persistent-data/data-structures/btree.h +++ b/persistent-data/data-structures/btree.h @@ -161,6 +161,9 @@ namespace persistent_data { return raw_; } + bool value_sizes_match() const; + std::string value_mismatch_string() const; + private: static unsigned calc_max_entries(void); void check_fits_within_block() const; diff --git a/persistent-data/data-structures/btree.tcc b/persistent-data/data-structures/btree.tcc index ef03013..74cbd15 100644 --- a/persistent-data/data-structures/btree.tcc +++ b/persistent-data/data-structures/btree.tcc @@ -362,19 +362,31 @@ namespace persistent_data { } } + template + bool + node_ref::value_sizes_match() const { + return sizeof(typename ValueTraits::disk_type) == get_value_size(); + } + + template + std::string + node_ref::value_mismatch_string() const { + std::ostringstream out; + out << "value size mismatch: expected " << sizeof(typename ValueTraits::disk_type) + << ", but got " << get_value_size() + << ". This is not the btree you are looking for." << std::endl; + + return out.str(); + } + template void node_ref::check_fits_within_block() const { if (checked_) return; - if (sizeof(typename ValueTraits::disk_type) != get_value_size()) { - std::ostringstream out; - out << "value size mismatch: expected " << sizeof(typename ValueTraits::disk_type) - << ", but got " << get_value_size() - << ". This is not the btree you are looking for." << std::endl; - throw std::runtime_error(out.str()); - } + if (!value_sizes_match()) + throw std::runtime_error(value_mismatch_string()); unsigned max = calc_max_entries(); diff --git a/persistent-data/data-structures/btree_damage_visitor.h b/persistent-data/data-structures/btree_damage_visitor.h index 1eede99..ca4a069 100644 --- a/persistent-data/data-structures/btree_damage_visitor.h +++ b/persistent-data/data-structures/btree_damage_visitor.h @@ -210,6 +210,7 @@ namespace persistent_data { btree_detail::node_ref const &n) { if (!already_visited(n) && check_block_nr(n) && + check_value_size(n) && check_max_entries(n) && check_nr_entries(n, loc.is_sub_root()) && check_ordered_keys(n) && @@ -229,6 +230,7 @@ namespace persistent_data { btree_detail::node_ref const &n) { if (!already_visited(n) && check_block_nr(n) && + check_value_size(n) && check_max_entries(n) && check_nr_entries(n, loc.is_sub_root()) && check_ordered_keys(n) && @@ -275,6 +277,16 @@ namespace persistent_data { return true; } + template + bool check_value_size(node const &n) { + if (!n.value_sizes_match()) { + report_damage(n.value_mismatch_string()); + return false; + } + + return true; + } + template bool check_max_entries(node const &n) { size_t elt_size = sizeof(uint64_t) + n.get_value_size(); From 880785a9bfa4f1adad701f03a13f575ca86433d0 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 26 May 2015 12:49:27 +0100 Subject: [PATCH 02/59] [damage_tracker] Reset the tracker in the end() method so we can reuse it. The *_check tools already reuse trackers. Patch from Ming-Hung Tsai. --- .../data-structures/btree_damage_visitor.h | 11 +++++++++-- unit-tests/damage_tracker_t.cc | 11 +++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/persistent-data/data-structures/btree_damage_visitor.h b/persistent-data/data-structures/btree_damage_visitor.h index ca4a069..2e248e8 100644 --- a/persistent-data/data-structures/btree_damage_visitor.h +++ b/persistent-data/data-structures/btree_damage_visitor.h @@ -70,10 +70,17 @@ namespace persistent_data { } maybe_run64 end() { + maybe_run64 r; + if (damaged_) - return maybe_run64(damage_begin_); + r = maybe_run64(damage_begin_); else - return maybe_run64(); + r = maybe_run64(); + + damaged_ = false; + damage_begin_ = 0; + + return r; } private: diff --git a/unit-tests/damage_tracker_t.cc b/unit-tests/damage_tracker_t.cc index a2f54a4..f211592 100644 --- a/unit-tests/damage_tracker_t.cc +++ b/unit-tests/damage_tracker_t.cc @@ -98,4 +98,15 @@ TEST_F(DamageTrackerTests, gi_bi_gi_bl_gl) assert_damage(dt.good_leaf(15, 20), run64(10ull, 15ull)); } +TEST_F(DamageTrackerTests, end_resets_tracker) +{ + dt.good_internal(0); + dt.good_leaf(0, 10); + dt.bad_node(); + assert_damage(dt.end(), run64(10ull)); + + assert_no_damage(dt.good_leaf(20, 30)); + assert_no_damage(dt.end()); +} + //---------------------------------------------------------------- From cf903cfea62c59f92e2e50bfe64b893f7e23db55 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 26 May 2015 14:09:29 +0100 Subject: [PATCH 03/59] [btree] lower bound search should return an empty optional if every entry in the node is higher. Patch from Ming-Hung Tsai --- persistent-data/data-structures/btree.tcc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/persistent-data/data-structures/btree.tcc b/persistent-data/data-structures/btree.tcc index 74cbd15..cf929ec 100644 --- a/persistent-data/data-structures/btree.tcc +++ b/persistent-data/data-structures/btree.tcc @@ -458,7 +458,8 @@ namespace persistent_data { template struct lower_bound_search { static boost::optional search(btree_detail::node_ref n, uint64_t key) { - return n.lower_bound(key); + int i = n.lower_bound(key); + return (i < 0) ? boost::optional() : boost::optional(i); } }; From c8d8af488fa9c72f98a9644952c56bdd4250ed7a Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 26 May 2015 14:24:55 +0100 Subject: [PATCH 04/59] [btree] When using lower_bound() assign to an int rather than unsigned Patch from Ming-Hung Tsai --- persistent-data/data-structures/btree.tcc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/persistent-data/data-structures/btree.tcc b/persistent-data/data-structures/btree.tcc index cf929ec..1cbfc61 100644 --- a/persistent-data/data-structures/btree.tcc +++ b/persistent-data/data-structures/btree.tcc @@ -608,9 +608,13 @@ namespace persistent_data { } - mi = leaf.lower_bound(key); - if (!mi || *mi < 0) - return boost::optional(); + { + int lb = leaf.lower_bound(key); + if (lb < 0) + return boost::optional(); + + mi = lb; + } node_ref internal = spine.template get_node(); block = internal.value_at(*mi); From 6ab0833b2e32fb7d728be11408cd8e5941706c29 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 9 Jun 2015 14:01:22 +0100 Subject: [PATCH 05/59] cache_check: add --clear-needs-check --- caching/cache_check.cc | 28 +++++++++++++++++++++++- caching/superblock.cc | 8 +++++++ caching/superblock.h | 6 +++-- features/cache_check.feature | 5 +++++ features/step_definitions/cache_steps.rb | 1 + 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/caching/cache_check.cc b/caching/cache_check.cc index ba750d5..005159e 100644 --- a/caching/cache_check.cc +++ b/caching/cache_check.cc @@ -187,7 +187,8 @@ namespace { check_hints_(true), check_discards_(true), ignore_non_fatal_errors_(false), - quiet_(false) { + quiet_(false), + clear_needs_check_on_success_(false) { } bool check_mappings_; @@ -195,6 +196,7 @@ namespace { bool check_discards_; bool ignore_non_fatal_errors_; bool quiet_; + bool clear_needs_check_on_success_; }; struct stat guarded_stat(string const &path) { @@ -210,6 +212,14 @@ namespace { return info; } + void clear_needs_check(string const &path) { + block_manager<>::ptr bm = open_bm(path, block_manager<>::READ_WRITE); + + superblock sb = read_superblock(bm); + sb.flags.clear_flag(superblock_flags::NEEDS_CHECK); + write_superblock(bm, sb); + } + error_state metadata_check(block_manager<>::ptr bm, flags const &fs) { nested_output out(cerr, 2); if (fs.quiet_) @@ -288,6 +298,16 @@ namespace { block_manager<>::ptr bm = open_bm(path, block_manager<>::READ_ONLY); err = metadata_check(bm, fs); + bool success = false; + + if (fs.ignore_non_fatal_errors_) + success = (err == FATAL) ? false : true; + else + success = (err == NO_ERROR) ? true : false; + + if (success && fs.clear_needs_check_on_success_) + clear_needs_check(path); + return err == NO_ERROR ? 0 : 1; } @@ -312,6 +332,7 @@ namespace { << " {-q|--quiet}" << endl << " {-h|--help}" << endl << " {-V|--version}" << endl + << " {--clear-needs-check-flag}" << endl << " {--super-block-only}" << endl << " {--skip-mappings}" << endl << " {--skip-hints}" << endl @@ -332,6 +353,7 @@ int cache_check_main(int argc, char **argv) { "skip-mappings", no_argument, NULL, 2 }, { "skip-hints", no_argument, NULL, 3 }, { "skip-discards", no_argument, NULL, 4 }, + { "clear-needs-check-flag", no_argument, NULL, 5 }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, no_argument, NULL, 0 } @@ -356,6 +378,10 @@ int cache_check_main(int argc, char **argv) fs.check_discards_ = false; break; + case 5: + fs.clear_needs_check_on_success_ = true; + break; + case 'h': usage(cout, basename(argv[0])); return 0; diff --git a/caching/superblock.cc b/caching/superblock.cc index 4089eee..2edd6c1 100644 --- a/caching/superblock.cc +++ b/caching/superblock.cc @@ -74,6 +74,11 @@ superblock_flags::superblock_flags(uint32_t bits) bits &= ~(1 << CLEAN_SHUTDOWN_BIT); } + if (bits & (1u << NEEDS_CHECK_BIT)) { + flags_.insert(NEEDS_CHECK); + bits &= ~(1u << NEEDS_CHECK_BIT); + } + unhandled_flags_ = bits; } @@ -103,6 +108,9 @@ superblock_flags::encode() const if (get_flag(CLEAN_SHUTDOWN)) r = r | (1 << CLEAN_SHUTDOWN_BIT); + if (get_flag(NEEDS_CHECK)) + r = r | (1u << NEEDS_CHECK_BIT); + return r; } diff --git a/caching/superblock.h b/caching/superblock.h index b59365a..fdac263 100644 --- a/caching/superblock.h +++ b/caching/superblock.h @@ -19,11 +19,13 @@ namespace caching { class superblock_flags { public: enum flag { - CLEAN_SHUTDOWN + CLEAN_SHUTDOWN, + NEEDS_CHECK }; enum flag_bits { - CLEAN_SHUTDOWN_BIT = 0 + CLEAN_SHUTDOWN_BIT = 0, + NEEDS_CHECK_BIT = 1, }; superblock_flags(); diff --git a/features/cache_check.feature b/features/cache_check.feature index a47274c..7efbd40 100644 --- a/features/cache_check.feature +++ b/features/cache_check.feature @@ -93,3 +93,8 @@ Feature: cache_check And I run cache_restore with -i metadata.xml -o input --debug-override-metadata-version 12345 When I run `cache_check input` Then it should fail + + Scenario: Accepts --clear-needs-check-flag + Given valid cache metadata + When I run `cache_check --clear-needs-check-flag metadata.bin` + Then it should pass \ No newline at end of file diff --git a/features/step_definitions/cache_steps.rb b/features/step_definitions/cache_steps.rb index ffc8150..7949cd0 100644 --- a/features/step_definitions/cache_steps.rb +++ b/features/step_definitions/cache_steps.rb @@ -40,6 +40,7 @@ Options: {-q|--quiet} {-h|--help} {-V|--version} + {--clear-needs-check-flag} {--super-block-only} {--skip-mappings} {--skip-hints} From 082491d140970e4adc463689c380947f248809aa Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Mon, 22 Jun 2015 11:13:19 +0100 Subject: [PATCH 06/59] thin_check: tidy up some unintuitive code --- thin-provisioning/thin_check.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/thin-provisioning/thin_check.cc b/thin-provisioning/thin_check.cc index 7eb5bd0..9e46af4 100644 --- a/thin-provisioning/thin_check.cc +++ b/thin-provisioning/thin_check.cc @@ -323,11 +323,11 @@ namespace { err = metadata_check(path, fs); if (fs.ignore_non_fatal_errors) - success = (err == FATAL) ? 1 : 0; + success = (err == FATAL) ? false : true; else - success = (err == NO_ERROR) ? 0 : 1; + success = (err == NO_ERROR) ? true : false; - if (!success && fs.clear_needs_check_flag_on_success) + if (success && fs.clear_needs_check_flag_on_success) clear_needs_check(path); } catch (std::exception &e) { @@ -337,7 +337,7 @@ namespace { return 1; } - return success; + return !success; } void usage(ostream &out, string const &cmd) { From 4ee6df3a7072bb048489992de17d68b61945a59b Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Mon, 22 Jun 2015 11:58:18 +0100 Subject: [PATCH 07/59] [cucumber tests] update thin_delta help output --- features/thin_delta.feature | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/features/thin_delta.feature b/features/thin_delta.feature index 8658b9e..4363a9e 100644 --- a/features/thin_delta.feature +++ b/features/thin_delta.feature @@ -12,8 +12,11 @@ Feature: thin_delta Then it should pass with: """ - Usage: thin_delta [options] --snap1 --snap2 + Usage: thin_delta [options] Options: + {--thin1, --snap1} + {--thin2, --snap2} + {-m, --metadata-snap} [block#] {--verbose} {-h|--help} {-V|--version} @@ -23,8 +26,11 @@ Feature: thin_delta When I run `thin_delta -h` Then it should pass with: """ - Usage: thin_delta [options] --snap1 --snap2 + Usage: thin_delta [options] Options: + {--thin1, --snap1} + {--thin2, --snap2} + {-m, --metadata-snap} [block#] {--verbose} {-h|--help} {-V|--version} From 125cec0193dab142941d44b4f35db9e9c5221a42 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Mon, 22 Jun 2015 12:02:16 +0100 Subject: [PATCH 08/59] bump to version 0.5 --- CHANGES | 2 ++ VERSION | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 3de75c1..3cecff6 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,8 @@ v0.5 ==== - thin_delta, thin_trim +- --clear-needs-check flag for cache_check +- space map checking for thin check v0.4 ==== diff --git a/VERSION b/VERSION index 267577d..2eb3c4f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.1 +0.5 From c6844dc7e64bb111a35b52232c655375e6026a36 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 24 Jun 2015 16:32:17 +0100 Subject: [PATCH 09/59] [metadata space map] Restrict space map size Previously it would crash with v. large metadata areas. --- persistent-data/space-maps/disk.cc | 5 +++++ persistent-data/space-maps/disk_structures.h | 1 + 2 files changed, 6 insertions(+) diff --git a/persistent-data/space-maps/disk.cc b/persistent-data/space-maps/disk.cc index e641c89..e915eb4 100644 --- a/persistent-data/space-maps/disk.cc +++ b/persistent-data/space-maps/disk.cc @@ -747,6 +747,11 @@ persistent_data::create_metadata_sm(transaction_manager &tm, block_address nr_bl { index_store::ptr store(new metadata_index_store(tm)); checked_space_map::ptr sm(new sm_disk(store, tm)); + + if (nr_blocks > MAX_METADATA_BLOCKS) { + cerr << "truncating metadata device to " << MAX_METADATA_BLOCKS << " 4k blocks\n"; + nr_blocks = MAX_METADATA_BLOCKS; + } sm->extend(nr_blocks); sm->commit(); return create_careful_alloc_sm( diff --git a/persistent-data/space-maps/disk_structures.h b/persistent-data/space-maps/disk_structures.h index 1429d36..0a57e61 100644 --- a/persistent-data/space-maps/disk_structures.h +++ b/persistent-data/space-maps/disk_structures.h @@ -61,6 +61,7 @@ namespace persistent_data { }; unsigned const MAX_METADATA_BITMAPS = 255; + unsigned const MAX_METADATA_BLOCKS = (255 * ((1 << 14) - 64)); unsigned const ENTRIES_PER_BYTE = 4; struct metadata_index { From 33af9774ae28b6dceeb2a64344e04b35d3025ce7 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 25 Jun 2015 10:50:29 +0100 Subject: [PATCH 10/59] v0.5.1 --- CHANGES | 6 ++++++ VERSION | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 3cecff6..9698fe3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +v0.5.1 +====== + +Fix bug where the tools would crash if given a very large metadata +device to restore to. + v0.5 ==== diff --git a/VERSION b/VERSION index 2eb3c4f..4b9fcbe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5 +0.5.1 From f85b7cef3fddee1411e2e49ad0a6b9ec12fd4012 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Fri, 3 Jul 2015 13:00:13 +0100 Subject: [PATCH 11/59] thin_dump, thin_check: Fix bug in damage reporting --- thin-provisioning/mapping_tree.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/thin-provisioning/mapping_tree.cc b/thin-provisioning/mapping_tree.cc index 421c8fe..454e85c 100644 --- a/thin-provisioning/mapping_tree.cc +++ b/thin-provisioning/mapping_tree.cc @@ -178,6 +178,10 @@ namespace { v_.visit(missing_devices(d.desc_, d.lost_keys_)); break; + case 1: + v_.visit(missing_mappings(d.desc_, path[0], d.lost_keys_)); + break; + default: throw std::runtime_error("mapping_tree_damage_visitor: path too long"); } @@ -196,7 +200,7 @@ namespace { virtual void visit(btree_path const &path, btree_detail::damage const &d) { switch (path.size()) { case 0: - v_.visit(missing_mappings(d.desc_, path[0], d.lost_keys_)); + v_.visit(missing_devices(d.desc_, d.lost_keys_)); break; default: From 7d8b6adf4e75776e3128398a509589fda6362b64 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Fri, 3 Jul 2015 13:00:49 +0100 Subject: [PATCH 12/59] v0.5.2 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4b9fcbe..cb0c939 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.1 +0.5.2 From 642ae6e7c273560f93e753737899add661e6f14a Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 7 Jul 2015 13:47:00 +0100 Subject: [PATCH 13/59] Tools now open the metadata device in O_EXCL mode. An attempt to stop people running the tools on active metadata. --- persistent-data/block.h | 6 ++++-- persistent-data/block.tcc | 21 +++++++++++++-------- persistent-data/file_utils.cc | 4 ++-- persistent-data/file_utils.h | 3 ++- thin-provisioning/metadata.cc | 2 +- thin-provisioning/thin_dump.cc | 29 +++++++++++++++++------------ 6 files changed, 39 insertions(+), 26 deletions(-) diff --git a/persistent-data/block.h b/persistent-data/block.h index fa587ac..09646c7 100644 --- a/persistent-data/block.h +++ b/persistent-data/block.h @@ -52,7 +52,8 @@ namespace persistent_data { block_manager(std::string const &path, block_address nr_blocks, unsigned max_concurrent_locks, - mode m); + mode m, + bool excl = true); class read_ref { public: @@ -134,7 +135,8 @@ namespace persistent_data { bool is_locked(block_address b) const; private: - int open_or_create_block_file(std::string const &path, off_t file_size, mode m); + int open_or_create_block_file(std::string const &path, off_t file_size, + mode m, bool excl); void check(block_address b) const; int fd_; diff --git a/persistent-data/block.tcc b/persistent-data/block.tcc index 529f7af..d21caad 100644 --- a/persistent-data/block.tcc +++ b/persistent-data/block.tcc @@ -80,7 +80,7 @@ namespace { throw runtime_error(out.str()); } - int fd = open_file(path, O_CREAT | O_RDWR); + int fd = open_file(path, O_CREAT | O_EXCL | O_RDWR); int r = ::ftruncate(fd, file_size); if (r < 0) @@ -89,14 +89,18 @@ namespace { return fd; } - int open_block_file(string const &path, off_t min_size, bool writeable) { + int open_block_file(string const &path, off_t min_size, bool writeable, bool excl = true) { if (!file_exists(path)) { ostringstream out; out << __FUNCTION__ << ": file '" << path << "' doesn't exist"; throw runtime_error(out.str()); } - return open_file(path, writeable ? O_RDWR : O_RDONLY); + int flags = writeable ? O_RDWR : O_RDONLY; + if (excl) + flags |= O_EXCL; + + return open_file(path, flags); } }; @@ -208,8 +212,9 @@ namespace persistent_data { block_manager::block_manager(std::string const &path, block_address nr_blocks, unsigned max_concurrent_blocks, - mode m) - : fd_(open_or_create_block_file(path, nr_blocks * BlockSize, m)), + mode m, + bool excl) + : fd_(open_or_create_block_file(path, nr_blocks * BlockSize, m, excl)), bc_(fd_, BlockSize >> SECTOR_SHIFT, nr_blocks, 1024u * 1024u * 16), superblock_ref_count_(0) { @@ -217,14 +222,14 @@ namespace persistent_data { template int - block_manager::open_or_create_block_file(string const &path, off_t file_size, mode m) + block_manager::open_or_create_block_file(string const &path, off_t file_size, mode m, bool excl) { switch (m) { case READ_ONLY: - return open_block_file(path, file_size, false); + return open_block_file(path, file_size, false, excl); case READ_WRITE: - return open_block_file(path, file_size, true); + return open_block_file(path, file_size, true, excl); case CREATE: return create_block_file(path, file_size); diff --git a/persistent-data/file_utils.cc b/persistent-data/file_utils.cc index 3dc9e2d..2467079 100644 --- a/persistent-data/file_utils.cc +++ b/persistent-data/file_utils.cc @@ -48,10 +48,10 @@ persistent_data::get_nr_blocks(string const &path) } persistent_data::block_manager<>::ptr -persistent_data::open_bm(std::string const &dev_path, block_manager<>::mode m) +persistent_data::open_bm(std::string const &dev_path, block_manager<>::mode m, bool excl) { block_address nr_blocks = get_nr_blocks(dev_path); - return block_manager<>::ptr(new block_manager<>(dev_path, nr_blocks, 1, m)); + return block_manager<>::ptr(new block_manager<>(dev_path, nr_blocks, 1, m, excl)); } void diff --git a/persistent-data/file_utils.h b/persistent-data/file_utils.h index d08fa96..fcf203d 100644 --- a/persistent-data/file_utils.h +++ b/persistent-data/file_utils.h @@ -10,7 +10,8 @@ // FIXME: move to a different unit namespace persistent_data { persistent_data::block_address get_nr_blocks(string const &path); - block_manager<>::ptr open_bm(std::string const &dev_path, block_manager<>::mode m); + block_manager<>::ptr open_bm(std::string const &dev_path, + block_manager<>::mode m, bool excl = true); void check_file_exists(std::string const &file); } diff --git a/thin-provisioning/metadata.cc b/thin-provisioning/metadata.cc index 098314c..aa29f78 100644 --- a/thin-provisioning/metadata.cc +++ b/thin-provisioning/metadata.cc @@ -118,7 +118,7 @@ metadata::metadata(std::string const &dev_path, open_type ot, metadata::metadata(std::string const &dev_path, block_address metadata_snap) { - tm_ = open_tm(open_bm(dev_path, block_manager<>::READ_ONLY)); + tm_ = open_tm(open_bm(dev_path, block_manager<>::READ_ONLY, !metadata_snap)); sb_ = read_superblock(tm_->get_bm(), metadata_snap); // We don't open the metadata sm for a held root diff --git a/thin-provisioning/thin_dump.cc b/thin-provisioning/thin_dump.cc index 853a512..c302bd0 100644 --- a/thin-provisioning/thin_dump.cc +++ b/thin-provisioning/thin_dump.cc @@ -27,6 +27,7 @@ #include "xml_format.h" #include "version.h" #include "thin-provisioning/commands.h" +#include "persistent-data/file_utils.h" using namespace persistent_data; using namespace std; @@ -38,24 +39,25 @@ struct flags { }; namespace { + block_address find_metadata_snap(string const &path) + { + superblock_detail::superblock sb = read_superblock(open_bm(path, block_manager<>::READ_ONLY, false), 0); + uint64_t ms = sb.metadata_snap_; + + if (!ms) { + cerr << "no metadata snapshot found!" << endl; + exit(1); + } + + return ms; + } + int dump_(string const &path, ostream &out, string const &format, struct flags &flags, block_address metadata_snap) { try { metadata::ptr md(new metadata(path, metadata_snap)); emitter::ptr e; - if (flags.find_metadata_snap) { - uint64_t metadata_snap_root = md->sb_.metadata_snap_; /* FIXME: use thin_pool method? */ - - if (metadata_snap_root) { - md.reset(); - md = metadata::ptr(new metadata(path, metadata_snap_root)); - } else { - cerr << "no metadata snapshot found!" << endl; - exit(1); - } - } - if (format == "xml") e = create_xml_emitter(out); else if (format == "human_readable") @@ -164,6 +166,9 @@ int thin_dump_main(int argc, char **argv) return 1; } + if (flags.find_metadata_snap) + metadata_snap = find_metadata_snap(argv[optind]); + return dump(argv[optind], output, format, flags, metadata_snap); } From 93fb540bd4d1904c87cb43f524d78dd2e40f27f0 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Mon, 27 Jul 2015 14:30:09 +0100 Subject: [PATCH 14/59] [thinp tools] move find_metadata_snap to superblock.cc --- VERSION | 2 +- thin-provisioning/superblock.cc | 15 +++++++++++++++ thin-provisioning/superblock.h | 3 +++ thin-provisioning/thin_dump.cc | 13 ------------- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/VERSION b/VERSION index cb0c939..be14282 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.2 +0.5.3 diff --git a/thin-provisioning/superblock.cc b/thin-provisioning/superblock.cc index 1f54b64..32f32de 100644 --- a/thin-provisioning/superblock.cc +++ b/thin-provisioning/superblock.cc @@ -1,6 +1,7 @@ #include "persistent-data/checksum.h" #include "persistent-data/errors.h" #include "thin-provisioning/superblock.h" +#include "persistent-data/file_utils.h" using namespace thin_provisioning; using namespace superblock_detail; @@ -180,6 +181,20 @@ namespace thin_provisioning { visitor.visit(superblock_corruption(e.what())); } } + + block_address find_metadata_snap(string const &path) + { + superblock_detail::superblock sb = + read_superblock(open_bm(path, block_manager<>::READ_ONLY, false), 0); + uint64_t ms = sb.metadata_snap_; + + if (!ms) { + cerr << "no metadata snapshot found!" << endl; + exit(1); + } + + return ms; + } } //---------------------------------------------------------------- diff --git a/thin-provisioning/superblock.h b/thin-provisioning/superblock.h index f527a15..dbe733a 100644 --- a/thin-provisioning/superblock.h +++ b/thin-provisioning/superblock.h @@ -137,6 +137,9 @@ namespace thin_provisioning { void check_superblock(persistent_data::block_manager<>::ptr bm, superblock_detail::damage_visitor &visitor); + + persistent_data::block_address find_metadata_snap(string const &path); + } //---------------------------------------------------------------- diff --git a/thin-provisioning/thin_dump.cc b/thin-provisioning/thin_dump.cc index c302bd0..191acb5 100644 --- a/thin-provisioning/thin_dump.cc +++ b/thin-provisioning/thin_dump.cc @@ -39,19 +39,6 @@ struct flags { }; namespace { - block_address find_metadata_snap(string const &path) - { - superblock_detail::superblock sb = read_superblock(open_bm(path, block_manager<>::READ_ONLY, false), 0); - uint64_t ms = sb.metadata_snap_; - - if (!ms) { - cerr << "no metadata snapshot found!" << endl; - exit(1); - } - - return ms; - } - int dump_(string const &path, ostream &out, string const &format, struct flags &flags, block_address metadata_snap) { try { From 3a881e9513ec05f2fb8b77fd6b8bd001ed56ad40 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 28 Jul 2015 11:26:58 +0100 Subject: [PATCH 15/59] [thin_delta] Allow optional arg when using -m --- CHANGES | 5 +++++ thin-provisioning/superblock.cc | 6 ++---- thin-provisioning/thin_delta.cc | 27 +++++++++++++++------------ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index 9698fe3..60520a2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +v0.5.5 +====== + +You may now give the --metadata_snap option to thin_delta without specifying where the snap is. + v0.5.1 ====== diff --git a/thin-provisioning/superblock.cc b/thin-provisioning/superblock.cc index 32f32de..0d1ca63 100644 --- a/thin-provisioning/superblock.cc +++ b/thin-provisioning/superblock.cc @@ -188,10 +188,8 @@ namespace thin_provisioning { read_superblock(open_bm(path, block_manager<>::READ_ONLY, false), 0); uint64_t ms = sb.metadata_snap_; - if (!ms) { - cerr << "no metadata snapshot found!" << endl; - exit(1); - } + if (!ms) + throw runtime_error("no metadata snapshot found!\n"); return ms; } diff --git a/thin-provisioning/thin_delta.cc b/thin-provisioning/thin_delta.cc index 7cb7d75..5758a35 100644 --- a/thin-provisioning/thin_delta.cc +++ b/thin-provisioning/thin_delta.cc @@ -64,7 +64,8 @@ namespace local { struct flags { flags() - : verbose(false) { + : verbose(false), + find_metadata_snap(false) { } boost::optional dev; @@ -72,17 +73,11 @@ namespace local { boost::optional snap1; boost::optional snap2; bool verbose; + bool find_metadata_snap; }; //-------------------------------- - block_manager<>::ptr - open_bm(string const &path) { - block_address nr_blocks = get_nr_blocks(path); - block_manager<>::mode m = block_manager<>::READ_ONLY; - return block_manager<>::ptr(new block_manager<>(path, nr_blocks, 1, m)); - } - transaction_manager::ptr open_tm(block_manager<>::ptr bm) { space_map::ptr sm(new core_map(bm->get_nr_blocks())); @@ -533,7 +528,7 @@ namespace local { checked_space_map::ptr data_sm; { - block_manager<>::ptr bm = open_bm(*fs.dev); + block_manager<>::ptr bm = open_bm(*fs.dev, block_manager<>::READ_ONLY, !fs.metadata_snap); transaction_manager::ptr tm = open_tm(bm); sb = fs.metadata_snap ? read_superblock(bm, *fs.metadata_snap) : read_superblock(bm); @@ -616,7 +611,7 @@ int thin_delta_main(int argc, char **argv) flags fs; local::application app(basename(argv[0])); - char const shortopts[] = "hVm"; + char const shortopts[] = "hVm::"; option const longopts[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, @@ -624,7 +619,7 @@ int thin_delta_main(int argc, char **argv) { "snap1", required_argument, NULL, 1 }, { "thin2", required_argument, NULL, 2 }, { "snap2", required_argument, NULL, 2 }, - { "metadata-snap", no_argument, NULL, 'm' }, + { "metadata-snap", optional_argument, NULL, 'm' }, { "verbose", no_argument, NULL, 4 } }; @@ -647,7 +642,10 @@ int thin_delta_main(int argc, char **argv) break; case 'm': - fs.metadata_snap = app.parse_int(optarg, "metadata snapshot block"); + if (optarg) + fs.metadata_snap = app.parse_int(optarg, "metadata snapshot block"); + else + fs.find_metadata_snap = true; break; case 4: @@ -671,6 +669,11 @@ int thin_delta_main(int argc, char **argv) if (!fs.snap2) app.die("--snap2 not specified."); + if (fs.find_metadata_snap) { + fs.metadata_snap = find_metadata_snap(*fs.dev); + cerr << "metadata snap = " << fs.metadata_snap << "\n"; + } + return delta(app, fs); } From 271ff67f910b651d973ed4a69d8b958239053bce Mon Sep 17 00:00:00 2001 From: Zdenek Kabelac Date: Wed, 15 Jul 2015 13:54:21 +0200 Subject: [PATCH 16/59] Cache check close RO opened device before reopen. When check_check is used with --clear-needs-check-flag option, device needs to be opened in RW exclusive mode, but for this existing RO exlusive open must be closed. LVM2 will consider version 0.5.3 as a version without flag support for cache_check since it cannot successfully pass cache_check. TODO: when 'RO' parts detects there is nothing to 'clear' it should completely skip RW open to avoid udev rule processing. --- caching/cache_check.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/caching/cache_check.cc b/caching/cache_check.cc index 005159e..9bd34be 100644 --- a/caching/cache_check.cc +++ b/caching/cache_check.cc @@ -220,7 +220,9 @@ namespace { write_superblock(bm, sb); } - error_state metadata_check(block_manager<>::ptr bm, flags const &fs) { + error_state metadata_check(string const &path, flags const &fs) { + block_manager<>::ptr bm = open_bm(path, block_manager<>::READ_ONLY); + nested_output out(cerr, 2); if (fs.quiet_) out.disable(); @@ -295,8 +297,7 @@ namespace { throw runtime_error(msg.str()); } - block_manager<>::ptr bm = open_bm(path, block_manager<>::READ_ONLY); - err = metadata_check(bm, fs); + err = metadata_check(path, fs); bool success = false; From 7134a581340d798ba56fd48629edb4c59501d761 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 30 Jul 2015 11:45:13 +0100 Subject: [PATCH 17/59] [thin_metadata_size] use floor rather than truncl --- thin-provisioning/thin_metadata_size.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thin-provisioning/thin_metadata_size.cc b/thin-provisioning/thin_metadata_size.cc index 8ea3eba..e45e04c 100644 --- a/thin-provisioning/thin_metadata_size.cc +++ b/thin-provisioning/thin_metadata_size.cc @@ -324,7 +324,7 @@ static const unsigned mappings_per_block(void) static void print_precision(struct global *g, double r, unsigned idx) { bool full = g->options.n[NUMERIC] == NO_NUMBER; - double rtrunc = truncl(r); + double rtrunc = floor(r); if (full) printf("%s - ", g->prg); From b67cc2960929e875021d567cd81930896f29fc2f Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 4 Aug 2015 15:12:41 +0100 Subject: [PATCH 18/59] [btree] bad checksum exceptions now mention the block location --- persistent-data/data-structures/btree.tcc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/persistent-data/data-structures/btree.tcc b/persistent-data/data-structures/btree.tcc index 1cbfc61..cd19fc4 100644 --- a/persistent-data/data-structures/btree.tcc +++ b/persistent-data/data-structures/btree.tcc @@ -38,11 +38,17 @@ namespace { node_header const *n = &data->header; crc32c sum(BTREE_CSUM_XOR); sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); - if (sum.get_sum() != to_cpu(n->csum)) - throw checksum_error("bad checksum in btree node"); + if (sum.get_sum() != to_cpu(n->csum)) { + std::ostringstream out; + out << "bad checksum in btree node (block " << location << ")"; + throw checksum_error(out.str()); + } - if (to_cpu(n->blocknr) != location) - throw checksum_error("bad block nr in btree node"); + if (to_cpu(n->blocknr) != location) { + std::ostringstream out; + out << "bad block nr in btree node (block = " << location << ")"; + throw checksum_error(out.str()); + } } virtual void prepare(void *raw, block_address location) const { From 5d28c05dc324227967b902ae8ccb18e781b35487 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 4 Aug 2015 15:14:02 +0100 Subject: [PATCH 19/59] [thin_check] detail and mapping trees weren't being counted properly for the metadata snap. This could result in block counts being unexpectedly non zero. --- thin-provisioning/thin_check.cc | 39 +++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/thin-provisioning/thin_check.cc b/thin-provisioning/thin_check.cc index 9e46af4..f14ee37 100644 --- a/thin-provisioning/thin_check.cc +++ b/thin-provisioning/thin_check.cc @@ -169,23 +169,9 @@ namespace { bool clear_needs_check_flag_on_success; }; - error_state check_space_map_counts(flags const &fs, nested_output &out, - superblock_detail::superblock &sb, - block_manager<>::ptr bm, - transaction_manager::ptr tm) { - block_counter bc; - - // Count the superblock - bc.inc(superblock_detail::SUPERBLOCK_LOCATION); - - // Count the metadata snap, if present - if (sb.metadata_snap_ != superblock_detail::SUPERBLOCK_LOCATION) { - bc.inc(sb.metadata_snap_); - - superblock_detail::superblock snap = read_superblock(bm, sb.metadata_snap_); - bc.inc(snap.data_mapping_root_); - bc.inc(snap.device_details_root_); - } + void count_trees(transaction_manager::ptr tm, + superblock_detail::superblock &sb, + block_counter &bc) { // Count the device tree { @@ -202,6 +188,25 @@ namespace { mapping_tree_detail::block_traits::ref_counter(tm->get_sm())); count_btree_blocks(mtree, bc, vc); } + } + + error_state check_space_map_counts(flags const &fs, nested_output &out, + superblock_detail::superblock &sb, + block_manager<>::ptr bm, + transaction_manager::ptr tm) { + block_counter bc; + + // Count the superblock + bc.inc(superblock_detail::SUPERBLOCK_LOCATION); + count_trees(tm, sb, bc); + + // Count the metadata snap, if present + if (sb.metadata_snap_ != superblock_detail::SUPERBLOCK_LOCATION) { + bc.inc(sb.metadata_snap_); + + superblock_detail::superblock snap = read_superblock(bm, sb.metadata_snap_); + count_trees(tm, snap, bc); + } // Count the metadata space map { From c32aaab028d4bcfbac502e5348ae500159df4b8b Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 11 Aug 2015 11:58:07 +0100 Subject: [PATCH 20/59] [validators] Move the btree node validator into a separate file. --- Makefile.in | 1 + persistent-data/data-structures/btree.h | 31 +------------ persistent-data/data-structures/btree.tcc | 34 ++------------- persistent-data/validators.cc | 53 +++++++++++++++++++++++ persistent-data/validators.h | 14 ++++++ 5 files changed, 72 insertions(+), 61 deletions(-) create mode 100644 persistent-data/validators.cc create mode 100644 persistent-data/validators.h diff --git a/Makefile.in b/Makefile.in index eaff125..e67b300 100644 --- a/Makefile.in +++ b/Makefile.in @@ -70,6 +70,7 @@ SOURCE=\ persistent-data/space-maps/recursive.cc \ persistent-data/space_map.cc \ persistent-data/transaction_manager.cc \ + persistent-data/validators.cc \ thin-provisioning/device_tree.cc \ thin-provisioning/human_readable_format.cc \ thin-provisioning/mapping_tree.cc \ diff --git a/persistent-data/data-structures/btree.h b/persistent-data/data-structures/btree.h index 3966148..b91fb20 100644 --- a/persistent-data/data-structures/btree.h +++ b/persistent-data/data-structures/btree.h @@ -22,6 +22,7 @@ #include "base/endian_utils.h" #include "persistent-data/transaction_manager.h" #include "persistent-data/data-structures/ref_counter.h" +#include "persistent-data/data-structures/btree_disk_structures.h" #include #include @@ -61,36 +62,6 @@ namespace persistent_data { using namespace base; using namespace std; - uint32_t const BTREE_CSUM_XOR = 121107; - - //------------------------------------------------ - // On disk data layout for btree nodes - enum node_flags { - INTERNAL_NODE = 1, - LEAF_NODE = 1 << 1 - }; - - struct node_header { - le32 csum; - le32 flags; - le64 blocknr; /* which block this node is supposed to live in */ - - le32 nr_entries; - le32 max_entries; - le32 value_size; - le32 padding; - } __attribute__((packed)); - - struct disk_node { - struct node_header header; - le64 keys[0]; - } __attribute__((packed)); - - enum node_type { - INTERNAL, - LEAF - }; - //------------------------------------------------ // Class that acts as an interface over the raw little endian btree // node data. diff --git a/persistent-data/data-structures/btree.tcc b/persistent-data/data-structures/btree.tcc index cd19fc4..80f2b94 100644 --- a/persistent-data/data-structures/btree.tcc +++ b/persistent-data/data-structures/btree.tcc @@ -21,6 +21,7 @@ #include "persistent-data/errors.h" #include "persistent-data/checksum.h" #include "persistent-data/transaction_manager.h" +#include "persistent-data/validators.h" #include @@ -32,35 +33,6 @@ namespace { using namespace btree_detail; using namespace std; - struct btree_node_validator : public bcache::validator { - virtual void check(void const *raw, block_address location) const { - disk_node const *data = reinterpret_cast(raw); - node_header const *n = &data->header; - crc32c sum(BTREE_CSUM_XOR); - sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); - if (sum.get_sum() != to_cpu(n->csum)) { - std::ostringstream out; - out << "bad checksum in btree node (block " << location << ")"; - throw checksum_error(out.str()); - } - - if (to_cpu(n->blocknr) != location) { - std::ostringstream out; - out << "bad block nr in btree node (block = " << location << ")"; - throw checksum_error(out.str()); - } - } - - virtual void prepare(void *raw, block_address location) const { - disk_node *data = reinterpret_cast(raw); - node_header *n = &data->header; - n->blocknr = to_disk(location); - - crc32c sum(BTREE_CSUM_XOR); - sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); - n->csum = to_disk(sum.get_sum()); - } - }; } //---------------------------------------------------------------- @@ -416,7 +388,7 @@ namespace persistent_data { destroy_(false), internal_rc_(tm.get_sm()), rc_(rc), - validator_(new btree_node_validator) + validator_(create_btree_node_validator()) { using namespace btree_detail; @@ -450,7 +422,7 @@ namespace persistent_data { root_(root), internal_rc_(tm.get_sm()), rc_(rc), - validator_(new btree_node_validator) + validator_(create_btree_node_validator()) { } diff --git a/persistent-data/validators.cc b/persistent-data/validators.cc new file mode 100644 index 0000000..b9c163c --- /dev/null +++ b/persistent-data/validators.cc @@ -0,0 +1,53 @@ +#include "persistent-data/block.h" +#include "persistent-data/checksum.h" +#include "persistent-data/data-structures/btree_disk_structures.h" +#include "persistent-data/errors.h" +#include "persistent-data/validators.h" + +using namespace bcache; +using namespace persistent_data; + +//---------------------------------------------------------------- + +namespace { + using namespace btree_detail; + + struct btree_node_validator : public bcache::validator { + virtual void check(void const *raw, block_address location) const { + disk_node const *data = reinterpret_cast(raw); + node_header const *n = &data->header; + crc32c sum(BTREE_CSUM_XOR); + sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); + if (sum.get_sum() != to_cpu(n->csum)) { + std::ostringstream out; + out << "bad checksum in btree node (block " << location << ")"; + throw checksum_error(out.str()); + } + + if (to_cpu(n->blocknr) != location) { + std::ostringstream out; + out << "bad block nr in btree node (block = " << location << ")"; + throw checksum_error(out.str()); + } + } + + virtual void prepare(void *raw, block_address location) const { + disk_node *data = reinterpret_cast(raw); + node_header *n = &data->header; + n->blocknr = to_disk(location); + + crc32c sum(BTREE_CSUM_XOR); + sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); + n->csum = to_disk(sum.get_sum()); + } + }; +} + +//---------------------------------------------------------------- + +bcache::validator::ptr persistent_data::create_btree_node_validator() +{ + return bcache::validator::ptr(new btree_node_validator()); +} + +//---------------------------------------------------------------- diff --git a/persistent-data/validators.h b/persistent-data/validators.h new file mode 100644 index 0000000..0068883 --- /dev/null +++ b/persistent-data/validators.h @@ -0,0 +1,14 @@ +#ifndef PERSISTENT_DATA_VALIDATORS_H +#define PERSISTENT_DATA_VALIDATORS_H + +#include "block-cache/block_cache.h" + +//---------------------------------------------------------------- + +namespace persistent_data { + bcache::validator::ptr create_btree_node_validator(); +} + +//---------------------------------------------------------------- + +#endif From 8fab56680c3ba5618eda05a95c62cad3c1481773 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 13 Aug 2015 12:57:07 +0100 Subject: [PATCH 21/59] [all tools] Improve the error message if opening the metadata fails. Remind the admin that you shouldn't run the tools on live data. --- persistent-data/block.tcc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/persistent-data/block.tcc b/persistent-data/block.tcc index d21caad..6e47a91 100644 --- a/persistent-data/block.tcc +++ b/persistent-data/block.tcc @@ -46,14 +46,23 @@ namespace { // to exception.h void syscall_failed(char const *call) { ostringstream out; - out << "syscall '" << call << "' failed: " << base::error_string(errno);; + out << "syscall '" << call << "' failed: " << base::error_string(errno); + throw runtime_error(out.str()); + } + + void syscall_failed(string const &call, string const &message) + { + ostringstream out; + out << "syscall '" << call << "' failed: " << base::error_string(errno) << "\n" + << message; throw runtime_error(out.str()); } int open_file(string const &path, int flags) { int fd = ::open(path.c_str(), OPEN_FLAGS | flags, DEFAULT_MODE); if (fd < 0) - syscall_failed("open"); + syscall_failed("open", + "Note: you cannot run this tool with these options on live metadata."); return fd; } From 32e92ce8979e12267d56e80498c6c872284a64d6 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 13 Aug 2015 13:39:20 +0100 Subject: [PATCH 22/59] update man pages to forbid running on live metadata --- man8/cache_check.8 | 2 ++ man8/cache_dump.8 | 2 ++ man8/cache_repair.8 | 2 ++ man8/cache_restore.8 | 2 ++ man8/era_check.8 | 2 ++ man8/era_dump.8 | 2 ++ man8/era_invalidate.8 | 2 ++ man8/thin_check.8 | 2 ++ man8/thin_delta.8 | 3 ++- man8/thin_dump.8 | 4 +++- man8/thin_repair.8 | 2 ++ man8/thin_restore.8 | 2 ++ man8/thin_rmap.8 | 4 +++- man8/thin_trim.8 | 6 +++--- 14 files changed, 31 insertions(+), 6 deletions(-) diff --git a/man8/cache_check.8 b/man8/cache_check.8 index 5cc7dff..1d53c18 100644 --- a/man8/cache_check.8 +++ b/man8/cache_check.8 @@ -15,6 +15,8 @@ the device-mapper cache target on a or .I file. +This tool cannot be run on live metadata. + .SH OPTIONS .IP "\fB\-q, \-\-quiet\fP" Suppress output messages, return only exit code. diff --git a/man8/cache_dump.8 b/man8/cache_dump.8 index a0c2924..00a6cfc 100644 --- a/man8/cache_dump.8 +++ b/man8/cache_dump.8 @@ -23,6 +23,8 @@ in order to put it back onto a metadata (to process by the device-mapper target) or .I file. +This tool cannot be run on live metadata. + .IP "\fB\-r, \-\-repair\fP". Repair the metadata whilst dumping it. diff --git a/man8/cache_repair.8 b/man8/cache_repair.8 index ef04a7f..b702707 100644 --- a/man8/cache_repair.8 +++ b/man8/cache_repair.8 @@ -26,6 +26,8 @@ If written to a metadata , the metadata can be processed by the device-mapper target. +This tool cannot be run on live metadata. + .IP "\fB\-i, \-\-input\fP \fI{device|file}\fP" Input file or device with binary metadata. diff --git a/man8/cache_restore.8 b/man8/cache_restore.8 index 5f9fdca..d9fd580 100644 --- a/man8/cache_restore.8 +++ b/man8/cache_restore.8 @@ -24,6 +24,8 @@ If restored to a metadata .I device , the metadata can be processed by the device-mapper target. +This tool cannot be run on live metadata. + .IP "\fB\-i, \-\-input\fP \fI{device|file}\fP" Input file or device with metadata. diff --git a/man8/era_check.8 b/man8/era_check.8 index e8610eb..43b3ee0 100644 --- a/man8/era_check.8 +++ b/man8/era_check.8 @@ -15,6 +15,8 @@ the device-mapper era target on a or .I file. +This tool cannot be run on live metadata. + .SH OPTIONS .IP "\fB\-q, \-\-quiet\fP" Suppress output messages, return only exit code. diff --git a/man8/era_dump.8 b/man8/era_dump.8 index 275ad97..b1ad2b6 100644 --- a/man8/era_dump.8 +++ b/man8/era_dump.8 @@ -23,6 +23,8 @@ in order to put it back onto a metadata (to process by the device-mapper target) or .I file. +This tool cannot be run on live metadata. + .IP "\fB\-r, \-\-repair\fP". Repair the metadata whilst dumping it. diff --git a/man8/era_invalidate.8 b/man8/era_invalidate.8 index 8c10728..2e67d4a 100644 --- a/man8/era_invalidate.8 +++ b/man8/era_invalidate.8 @@ -11,6 +11,8 @@ era_invalidate \- Provide a list of blocks that have changed since a particular .B era_invalidate Examines era metadata and lists blocks that may have changed since a given era. +This tool cannot be run on live metadata. + .SH OPTIONS .IP "\fB\-h, \-\-help\fP" Print help and exit. diff --git a/man8/thin_check.8 b/man8/thin_check.8 index 0981d77..f5b6496 100644 --- a/man8/thin_check.8 +++ b/man8/thin_check.8 @@ -15,6 +15,8 @@ the device-mapper thin provisioning target on a or .I file. +This tool cannot be run on live metadata. + .SH OPTIONS .IP "\fB\-q, \-\-quiet\fP" Suppress output messages, return only exit code. diff --git a/man8/thin_delta.8 b/man8/thin_delta.8 index 1ebfcbe..565ad71 100644 --- a/man8/thin_delta.8 +++ b/man8/thin_delta.8 @@ -10,7 +10,8 @@ thin_delta \- Print the differences in the mappings between two thin devices. .SH DESCRIPTION .B thin_delta allows you to compare the mappings in two thin volumes (snapshots allow common blocks between thin volumes). -. + +This tool cannot be run on live metadata unless the \fB\-\-metadata\-snap\fP option is used. .SH OPTIONS .IP "\fB\-\-thin1, \-\-snap1\fP" diff --git a/man8/thin_dump.8 b/man8/thin_dump.8 index a8c92fe..7a9f785 100644 --- a/man8/thin_dump.8 +++ b/man8/thin_dump.8 @@ -24,13 +24,15 @@ in order to put it back onto a metadata (to process by the device-mapper target) or .I file. +This tool cannot be run on live metadata unless the \fB\-\-metadata\-snap\fP option is used. + .IP "\fB\-f, \-\-format\fP \fI{xml|human_readable}\fP". Print output in XML or human readable format. .IP "\fB\-r, \-\-repair\fP". Repair the metadata whilst dumping it. -.IP "\fB\-m, \-\-metadata_snap\fP [block#]". +.IP "\fB\-m, \-\-metadata\-snap\fP [block#]". Dump metadata snapshot created by device-mapper thin provisioning target. If block is not provided, access the default metadata snapshot created by the thin provisioning device-mapper target, else try the one at block#. diff --git a/man8/thin_repair.8 b/man8/thin_repair.8 index 1048de5..a8bd529 100644 --- a/man8/thin_repair.8 +++ b/man8/thin_repair.8 @@ -26,6 +26,8 @@ If written to a metadata , the metadata can be processed by the device-mapper target. +This tool cannot be run on live metadata. + .IP "\fB\-i, \-\-input\fP \fI{device|file}\fP" Input file or device with binary metadata. diff --git a/man8/thin_restore.8 b/man8/thin_restore.8 index 17b2e6e..f4d590d 100644 --- a/man8/thin_restore.8 +++ b/man8/thin_restore.8 @@ -24,6 +24,8 @@ If restored to a metadata .I device , the metadata can be processed by the device-mapper target. +This tool cannot be run on live metadata. + .IP "\fB\-q, \-\-quiet\fP" Suppress output messages, return only exit code. diff --git a/man8/thin_rmap.8 b/man8/thin_rmap.8 index 125e49c..75dfb38 100644 --- a/man8/thin_rmap.8 +++ b/man8/thin_rmap.8 @@ -16,6 +16,8 @@ or between a region of thin provisioned pool blocks and the associated thin provisioned devices. +This tool cannot be run on live metadata. + .IP "\fB\\-\-region\fP \fI\fP". output reverse map @@ -29,7 +31,7 @@ Output version information and exit. output reverse map for pool blocks 5..45 (denotes blocks 5 to 44 inclusive, but not block 45) .sp -.B thin_rmap --region 5..45 /dev/vg/pool +.B thin_rmap --region 5..45 /dev/pool-metadata .SH DIAGNOSTICS .B thin_rmap diff --git a/man8/thin_trim.8 b/man8/thin_trim.8 index de702f0..050135a 100644 --- a/man8/thin_trim.8 +++ b/man8/thin_trim.8 @@ -9,9 +9,9 @@ thin_trim \- Issue discard requests for free pool space (offline tool). .SH DESCRIPTION .B thin_trim -sends discard requests to the pool device for unprovisioned areas. It is an offline tool, -.B do not run it while the pool is active -. +sends discard requests to the pool device for unprovisioned areas. + +This tool cannot be run on live metadata. .SH OPTIONS .IP "\fB\-\-pool-inactive\fP" From d63b73ea93ffe780fcb12d2ad376d7598030cfc8 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 13 Aug 2015 13:50:36 +0100 Subject: [PATCH 23/59] bump version --- CHANGES | 4 ++++ VERSION | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 60520a2..72986d0 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,10 @@ v0.5.5 You may now give the --metadata_snap option to thin_delta without specifying where the snap is. +Update man pages to make it clearer that most tools shouldn't be run on live metadata. + +Fix some bugs in the metadata reference counting for thin_check. + v0.5.1 ====== diff --git a/VERSION b/VERSION index be14282..d1d899f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.3 +0.5.5 From 71aea2efcc2d65203b3ff84d515eb5900d52eee7 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 13 Aug 2015 14:28:07 +0100 Subject: [PATCH 24/59] add btree_disk_structures.h --- .../data-structures/btree_disk_structures.h | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 persistent-data/data-structures/btree_disk_structures.h diff --git a/persistent-data/data-structures/btree_disk_structures.h b/persistent-data/data-structures/btree_disk_structures.h new file mode 100644 index 0000000..16cad4e --- /dev/null +++ b/persistent-data/data-structures/btree_disk_structures.h @@ -0,0 +1,64 @@ +// 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 +// . + +#ifndef PERSISTENT_DATA_BTREE_DISK_STRUCTURES_H +#define PERSISTENT_DATA_BTREE_DISK_STRUCTURES_H + +#include "base/endian_utils.h" + +//---------------------------------------------------------------- + +namespace persistent_data { + namespace btree_detail { + using namespace base; + + uint32_t const BTREE_CSUM_XOR = 121107; + + //------------------------------------------------ + // On disk data layout for btree nodes + enum node_flags { + INTERNAL_NODE = 1, + LEAF_NODE = 1 << 1 + }; + + struct node_header { + le32 csum; + le32 flags; + le64 blocknr; /* which block this node is supposed to live in */ + + le32 nr_entries; + le32 max_entries; + le32 value_size; + le32 padding; + } __attribute__((packed)); + + struct disk_node { + struct node_header header; + le64 keys[0]; + } __attribute__((packed)); + + enum node_type { + INTERNAL, + LEAF + }; + } +} + +//---------------------------------------------------------------- + +#endif From 29c2a949f4a389e77de3b602090518220c3b7d58 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 13 Aug 2015 14:56:30 +0100 Subject: [PATCH 25/59] remove a bit of debug --- thin-provisioning/thin_delta.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/thin-provisioning/thin_delta.cc b/thin-provisioning/thin_delta.cc index 5758a35..deb5798 100644 --- a/thin-provisioning/thin_delta.cc +++ b/thin-provisioning/thin_delta.cc @@ -669,10 +669,8 @@ int thin_delta_main(int argc, char **argv) if (!fs.snap2) app.die("--snap2 not specified."); - if (fs.find_metadata_snap) { + if (fs.find_metadata_snap) fs.metadata_snap = find_metadata_snap(*fs.dev); - cerr << "metadata snap = " << fs.metadata_snap << "\n"; - } return delta(app, fs); } From 78b24dee19dd491331d764f584477e37111f3681 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 8 Sep 2015 10:12:56 +0100 Subject: [PATCH 26/59] [era_invalidate] Don't open in exclusive mode if using a metadata snap. Patch from bobk-rey on github --- era/era_invalidate.cc | 2 +- man8/era_invalidate.8 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/era/era_invalidate.cc b/era/era_invalidate.cc index c81b5af..20490a0 100644 --- a/era/era_invalidate.cc +++ b/era/era_invalidate.cc @@ -152,7 +152,7 @@ namespace { int invalidate(string const &dev, string const &output, flags const &fs) { try { set blocks; - block_manager<>::ptr bm = open_bm(dev, block_manager<>::READ_ONLY); + block_manager<>::ptr bm = open_bm(dev, block_manager<>::READ_ONLY, !fs.metadata_snapshot_); if (fs.metadata_snapshot_) { superblock sb = read_superblock(bm); diff --git a/man8/era_invalidate.8 b/man8/era_invalidate.8 index 2e67d4a..9bc6994 100644 --- a/man8/era_invalidate.8 +++ b/man8/era_invalidate.8 @@ -11,7 +11,7 @@ era_invalidate \- Provide a list of blocks that have changed since a particular .B era_invalidate Examines era metadata and lists blocks that may have changed since a given era. -This tool cannot be run on live metadata. +This tool cannot be run on live metadata unless the \fB\-\-metadata\-snap\fP option is used. .SH OPTIONS .IP "\fB\-h, \-\-help\fP" From 2b12854ecdd87eacb26c0abeff4d842724732a73 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 8 Sep 2015 10:20:42 +0100 Subject: [PATCH 27/59] bump version to 0.5.6 --- CHANGES | 5 +++++ VERSION | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 72986d0..ee92eee 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +v0.5.6 +====== + +era_invalidate may be run on live metadata if the --metadata-snap option is given. + v0.5.5 ====== diff --git a/VERSION b/VERSION index d1d899f..b49b253 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.5 +0.5.6 From febe80f4bb2bcb3c612c102c1c2395b43989f5ca Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Wed, 30 Sep 2015 08:00:00 +0800 Subject: [PATCH 28/59] [damage_visitor] update path_tracker in error_accessing_node() --- persistent-data/data-structures/btree_damage_visitor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/persistent-data/data-structures/btree_damage_visitor.h b/persistent-data/data-structures/btree_damage_visitor.h index 2e248e8..fa11378 100644 --- a/persistent-data/data-structures/btree_damage_visitor.h +++ b/persistent-data/data-structures/btree_damage_visitor.h @@ -197,6 +197,7 @@ namespace persistent_data { error_outcome error_accessing_node(node_location const &l, block_address b, std::string const &what) { + update_path(l.path); report_damage(what); return btree::visitor::EXCEPTION_HANDLED; } From 77f803c52896831a319fb750f2a2f982a52db924 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Thu, 26 Nov 2015 15:00:00 +0800 Subject: [PATCH 29/59] [build] Support external strip command --- Makefile.in | 4 +++- configure.ac | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index e67b300..003cb3d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -93,6 +93,7 @@ SOURCE=\ CC:=@CC@ CXX:=@CXX@ +STRIP:=@STRIP@ OBJECTS:=$(subst .cc,.o,$(SOURCE)) TOP_DIR:=@top_srcdir@ TOP_BUILDDIR:=@top_builddir@ @@ -112,7 +113,7 @@ MANPATH:=$(DATADIR)/man vpath %.cc $(TOP_DIR) INSTALL_DIR = $(INSTALL) -m 755 -d -INSTALL_PROGRAM = $(INSTALL) -m 755 -s +INSTALL_PROGRAM = $(INSTALL) -m 755 INSTALL_DATA = $(INSTALL) -p -m 644 ifeq ("@TESTING@", "yes") @@ -165,6 +166,7 @@ distclean: clean install: bin/pdata_tools $(INSTALL_DIR) $(BINDIR) $(INSTALL_PROGRAM) bin/pdata_tools $(BINDIR) + $(STRIP) $(BINDIR)/pdata_tools ln -s -f pdata_tools $(BINDIR)/cache_check ln -s -f pdata_tools $(BINDIR)/cache_dump ln -s -f pdata_tools $(BINDIR)/cache_metadata_size diff --git a/configure.ac b/configure.ac index 3e6c6a9..f5e7a2e 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,9 @@ AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_MKDIR_P AC_PROG_INSTALL +AC_DEFUN([AC_PROG_STRIP], [AC_CHECK_TOOL(STRIP, strip, :)]) +AC_PROG_STRIP +AC_ARG_VAR(STRIP, [Command for discarding symbols from object files]) ################################################################ dnl -- Checks for functions. From 03590d3c915f0821852e45f981b5c65d64c0c7c3 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Fri, 27 Nov 2015 23:38:27 +0800 Subject: [PATCH 30/59] Fix bug in superblock UUID string copy --- thin-provisioning/restore_emitter.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/thin-provisioning/restore_emitter.cc b/thin-provisioning/restore_emitter.cc index 5fae879..fd83f56 100644 --- a/thin-provisioning/restore_emitter.cc +++ b/thin-provisioning/restore_emitter.cc @@ -50,7 +50,8 @@ namespace { in_superblock_ = true; nr_data_blocks_ = nr_data_blocks; superblock &sb = md_->sb_; - memcpy(&sb.uuid_, &uuid, sizeof(sb.uuid_)); + memset(&sb.uuid_, 0, sizeof(sb.uuid_)); + memcpy(&sb.uuid_, uuid.c_str(), std::min(sizeof(sb.uuid_), uuid.length())); sb.time_ = time; sb.trans_id_ = trans_id; sb.data_block_size_ = data_block_size; From 856bd95d8e2d4a2d7e89e9b367d87a1c534af17e Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Fri, 27 Nov 2015 23:38:37 +0800 Subject: [PATCH 31/59] Fix the unit of superblock::metadata_block_size_ to be sector-based --- thin-provisioning/metadata.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/thin-provisioning/metadata.cc b/thin-provisioning/metadata.cc index aa29f78..e3db414 100644 --- a/thin-provisioning/metadata.cc +++ b/thin-provisioning/metadata.cc @@ -109,7 +109,7 @@ metadata::metadata(std::string const &dev_path, open_type ot, sb_.data_mapping_root_ = mappings_->get_root(); sb_.device_details_root_ = details_->get_root(); sb_.data_block_size_ = data_block_size; - sb_.metadata_block_size_ = MD_BLOCK_SIZE; + sb_.metadata_block_size_ = MD_BLOCK_SIZE >> SECTOR_SHIFT; sb_.metadata_nr_blocks_ = tm_->get_bm()->get_nr_blocks(); break; @@ -177,7 +177,7 @@ metadata::metadata(block_manager<>::ptr bm, open_type ot, sb_.data_mapping_root_ = mappings_->get_root(); sb_.device_details_root_ = details_->get_root(); sb_.data_block_size_ = data_block_size; - sb_.metadata_block_size_ = MD_BLOCK_SIZE; + sb_.metadata_block_size_ = MD_BLOCK_SIZE >> SECTOR_SHIFT; sb_.metadata_nr_blocks_ = tm_->get_bm()->get_nr_blocks(); break; From e528fa197258081d02b187b4b3b61894dc5d2e48 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Fri, 27 Nov 2015 23:38:42 +0800 Subject: [PATCH 32/59] Add BLKDISCARD definition --- thin-provisioning/thin_trim.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/thin-provisioning/thin_trim.cc b/thin-provisioning/thin_trim.cc index 0118b62..38a95f2 100644 --- a/thin-provisioning/thin_trim.cc +++ b/thin-provisioning/thin_trim.cc @@ -6,6 +6,10 @@ #undef BLOCK_SIZE +#ifndef BLKDISCARD +#define BLKDISCARD _IO(0x12,119) +#endif + #include "thin-provisioning/commands.h" #include "metadata.h" #include "version.h" From 3be4fe985f5b8084bcbc2180df4abcda5a608757 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Fri, 27 Nov 2015 23:38:55 +0800 Subject: [PATCH 33/59] [build] Add AC_SYS_LARGEFILE to check for large-file support To use off64_t on 32-bit system --- Makefile.in | 2 ++ configure.ac | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/Makefile.in b/Makefile.in index 003cb3d..ac2a2f4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -98,10 +98,12 @@ OBJECTS:=$(subst .cc,.o,$(SOURCE)) TOP_DIR:=@top_srcdir@ TOP_BUILDDIR:=@top_builddir@ CFLAGS+=-g -Wall -O3 +CFLAGS+=@LFS_FLAGS@ CXXFLAGS+=-g -Wall -fno-strict-aliasing CXXFLAGS+=@CXXOPTIMISE_FLAG@ CXXFLAGS+=@CXXDEBUG_FLAG@ CXXFLAGS+=@CXX_STRERROR_FLAG@ +CXXFLAGS+=@LFS_FLAGS@ INCLUDES+=-I$(TOP_BUILDDIR) -I$(TOP_DIR) -I$(TOP_DIR)/thin-provisioning LIBS:=-lstdc++ -laio -lexpat INSTALL:=@INSTALL@ diff --git a/configure.ac b/configure.ac index f5e7a2e..5de0fe4 100644 --- a/configure.ac +++ b/configure.ac @@ -45,6 +45,16 @@ AC_DEFUN([AC_PROG_STRIP], [AC_CHECK_TOOL(STRIP, strip, :)]) AC_PROG_STRIP AC_ARG_VAR(STRIP, [Command for discarding symbols from object files]) +################################################################ +dnl -- Check for large file support +AC_SYS_LARGEFILE +if test x$ac_cv_sys_file_offset_bits = x64; then + LFS_FLAGS+="-D_FILE_OFFSET_BITS=64" +fi +if test x$ac_cv_sys_large_files = x1; then + LFS_FLAGS+="-D_LARGE_FILES" +fi + ################################################################ dnl -- Checks for functions. AC_FUNC_STRERROR_R @@ -147,6 +157,7 @@ VERSION_PATCHLEVEL=`echo "$VER" | $AWK -F '[[(.]]' '{print $3}'` AC_SUBST(CXXDEBUG_FLAG) AC_SUBST(CXXOPTIMISE_FLAG) AC_SUBST(CXX_STRERROR_FLAG) +AC_SUBST(LFS_FLAGS) AC_SUBST(INSTALL) AC_SUBST(prefix) AC_SUBST(RELEASE_DATE) From 30a3bf67d1fcb13e40ab96774e8d6c644f1b7b26 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Mon, 14 Dec 2015 15:29:57 +0000 Subject: [PATCH 34/59] [thin tools] Change the metadata contructors to take a block_manager<>::ptr Also check any metadata snap passed in matches what's in the superblock. --- thin-provisioning/metadata.cc | 109 +++++++++--------------------- thin-provisioning/metadata.h | 13 +--- thin-provisioning/thin_dump.cc | 3 +- thin-provisioning/thin_repair.cc | 7 +- thin-provisioning/thin_restore.cc | 3 +- thin-provisioning/thin_trim.cc | 4 +- 6 files changed, 46 insertions(+), 93 deletions(-) diff --git a/thin-provisioning/metadata.cc b/thin-provisioning/metadata.cc index aa29f78..9d9b652 100644 --- a/thin-provisioning/metadata.cc +++ b/thin-provisioning/metadata.cc @@ -60,80 +60,6 @@ namespace { //---------------------------------------------------------------- -metadata::metadata(std::string const &dev_path, open_type ot, - sector_t data_block_size, block_address nr_data_blocks) -{ - switch (ot) { - case OPEN: - tm_ = open_tm(open_bm(dev_path, block_manager<>::READ_ONLY)); - sb_ = read_superblock(tm_->get_bm()); - - if (sb_.version_ != 1) - throw runtime_error("unknown metadata version"); - - metadata_sm_ = open_metadata_sm(*tm_, &sb_.metadata_space_map_root_); - tm_->set_sm(metadata_sm_); - - data_sm_ = open_disk_sm(*tm_, static_cast(&sb_.data_space_map_root_)); - - details_ = device_tree::ptr( - new device_tree(*tm_, sb_.device_details_root_, - device_tree_detail::device_details_traits::ref_counter())); - - mappings_top_level_ = dev_tree::ptr( - new dev_tree(*tm_, sb_.data_mapping_root_, - mapping_tree_detail::mtree_ref_counter(tm_))); - - mappings_ = mapping_tree::ptr( - new mapping_tree(*tm_, sb_.data_mapping_root_, - mapping_tree_detail::block_time_ref_counter(data_sm_))); - break; - - case CREATE: - tm_ = open_tm(open_bm(dev_path, block_manager<>::READ_WRITE)); - space_map::ptr core = tm_->get_sm(); - metadata_sm_ = create_metadata_sm(*tm_, tm_->get_bm()->get_nr_blocks()); - copy_space_maps(metadata_sm_, core); - tm_->set_sm(metadata_sm_); - - data_sm_ = create_disk_sm(*tm_, nr_data_blocks); - details_ = device_tree::ptr(new device_tree(*tm_, device_tree_detail::device_details_traits::ref_counter())); - mappings_ = mapping_tree::ptr(new mapping_tree(*tm_, - mapping_tree_detail::block_time_ref_counter(data_sm_))); - mappings_top_level_ = dev_tree::ptr(new dev_tree(*tm_, mappings_->get_root(), - mapping_tree_detail::mtree_ref_counter(tm_))); - - ::memset(&sb_, 0, sizeof(sb_)); - sb_.magic_ = SUPERBLOCK_MAGIC; - sb_.version_ = 1; - sb_.data_mapping_root_ = mappings_->get_root(); - sb_.device_details_root_ = details_->get_root(); - sb_.data_block_size_ = data_block_size; - sb_.metadata_block_size_ = MD_BLOCK_SIZE; - sb_.metadata_nr_blocks_ = tm_->get_bm()->get_nr_blocks(); - - break; - } -} - -metadata::metadata(std::string const &dev_path, block_address metadata_snap) -{ - tm_ = open_tm(open_bm(dev_path, block_manager<>::READ_ONLY, !metadata_snap)); - sb_ = read_superblock(tm_->get_bm(), metadata_snap); - - // We don't open the metadata sm for a held root - //metadata_sm_ = open_metadata_sm(tm_, &sb_.metadata_space_map_root_); - //tm_->set_sm(metadata_sm_); - - data_sm_ = open_disk_sm(*tm_, static_cast(&sb_.data_space_map_root_)); - details_ = device_tree::ptr(new device_tree(*tm_, sb_.device_details_root_, device_tree_detail::device_details_traits::ref_counter())); - mappings_top_level_ = dev_tree::ptr(new dev_tree(*tm_, sb_.data_mapping_root_, - mapping_tree_detail::mtree_ref_counter(tm_))); - mappings_ = mapping_tree::ptr(new mapping_tree(*tm_, sb_.data_mapping_root_, - mapping_tree_detail::block_time_ref_counter(data_sm_))); -} - -// FIXME: duplication metadata::metadata(block_manager<>::ptr bm, open_type ot, sector_t data_block_size, block_address nr_data_blocks) @@ -150,7 +76,8 @@ metadata::metadata(block_manager<>::ptr bm, open_type ot, tm_->set_sm(metadata_sm_); data_sm_ = open_disk_sm(*tm_, static_cast(&sb_.data_space_map_root_)); - details_ = device_tree::ptr(new device_tree(*tm_, sb_.device_details_root_, device_tree_detail::device_details_traits::ref_counter())); + details_ = device_tree::ptr(new device_tree(*tm_, sb_.device_details_root_, + device_tree_detail::device_details_traits::ref_counter())); mappings_top_level_ = dev_tree::ptr(new dev_tree(*tm_, sb_.data_mapping_root_, mapping_tree_detail::mtree_ref_counter(tm_))); mappings_ = mapping_tree::ptr(new mapping_tree(*tm_, sb_.data_mapping_root_, @@ -165,7 +92,8 @@ metadata::metadata(block_manager<>::ptr bm, open_type ot, tm_->set_sm(metadata_sm_); data_sm_ = create_disk_sm(*tm_, nr_data_blocks); - details_ = device_tree::ptr(new device_tree(*tm_, device_tree_detail::device_details_traits::ref_counter())); + details_ = device_tree::ptr(new device_tree(*tm_, + device_tree_detail::device_details_traits::ref_counter())); mappings_ = mapping_tree::ptr(new mapping_tree(*tm_, mapping_tree_detail::block_time_ref_counter(data_sm_))); mappings_top_level_ = dev_tree::ptr(new dev_tree(*tm_, mappings_->get_root(), @@ -184,6 +112,35 @@ metadata::metadata(block_manager<>::ptr bm, open_type ot, } } +metadata::metadata(block_manager<>::ptr bm, block_address metadata_snap) +{ + tm_ = open_tm(bm); + + if (metadata_snap) { + if (metadata_snap != sb_.metadata_snap_) + throw runtime_error("metadata snapshot does not match that in superblock"); + + sb_ = read_superblock(tm_->get_bm(), metadata_snap); + + // metadata snaps don't record the space maps + + } else { + sb_ = read_superblock(tm_->get_bm(), SUPERBLOCK_LOCATION); + + metadata_sm_ = open_metadata_sm(*tm_, &sb_.metadata_space_map_root_); + tm_->set_sm(metadata_sm_); + + data_sm_ = open_disk_sm(*tm_, static_cast(&sb_.data_space_map_root_)); + } + + details_ = device_tree::ptr(new device_tree(*tm_, sb_.device_details_root_, + device_tree_detail::device_details_traits::ref_counter())); + mappings_top_level_ = dev_tree::ptr(new dev_tree(*tm_, sb_.data_mapping_root_, + mapping_tree_detail::mtree_ref_counter(tm_))); + mappings_ = mapping_tree::ptr(new mapping_tree(*tm_, sb_.data_mapping_root_, + mapping_tree_detail::block_time_ref_counter(data_sm_))); +} + void metadata::commit() { diff --git a/thin-provisioning/metadata.h b/thin-provisioning/metadata.h index c0913a0..be20e16 100644 --- a/thin-provisioning/metadata.h +++ b/thin-provisioning/metadata.h @@ -59,21 +59,10 @@ namespace thin_provisioning { typedef block_manager<>::write_ref write_ref; typedef boost::shared_ptr ptr; - - // Deprecated: it would be better if we passed in an already - // constructed block_manager. - metadata(std::string const &dev_path, open_type ot, - sector_t data_block_size = 128, // Only used if CREATE - block_address nr_data_blocks = 0); // Only used if CREATE - - metadata(std::string const &dev_path, - block_address metadata_snap = 0); - - // ... use these instead ... metadata(block_manager<>::ptr bm, open_type ot, sector_t data_block_size = 128, block_address nr_data_blocks = 0); // Only used if CREATE - metadata(block_manager<>::ptr bm, block_address metadata_snap); + metadata(block_manager<>::ptr bm, block_address metadata_snap = 0); void commit(); diff --git a/thin-provisioning/thin_dump.cc b/thin-provisioning/thin_dump.cc index 191acb5..2e49a66 100644 --- a/thin-provisioning/thin_dump.cc +++ b/thin-provisioning/thin_dump.cc @@ -42,7 +42,8 @@ namespace { int dump_(string const &path, ostream &out, string const &format, struct flags &flags, block_address metadata_snap) { try { - metadata::ptr md(new metadata(path, metadata_snap)); + block_manager<>::ptr bm = open_bm(path, block_manager<>::READ_ONLY, !metadata_snap); + metadata::ptr md(new metadata(bm, metadata_snap)); emitter::ptr e; if (format == "xml") diff --git a/thin-provisioning/thin_repair.cc b/thin-provisioning/thin_repair.cc index 7ba58a5..8751b47 100644 --- a/thin-provisioning/thin_repair.cc +++ b/thin-provisioning/thin_repair.cc @@ -2,6 +2,7 @@ #include #include +#include "persistent-data/file_utils.h" #include "thin-provisioning/commands.h" #include "human_readable_format.h" #include "metadata_dumper.h" @@ -17,10 +18,12 @@ namespace { int repair(string const &old_path, string const &new_path) { try { // block size gets updated by the restorer - metadata::ptr new_md(new metadata(new_path, metadata::CREATE, 128, 0)); + block_manager<>::ptr new_bm = open_bm(new_path, block_manager<>::READ_WRITE); + metadata::ptr new_md(new metadata(new_bm, metadata::CREATE, 128, 0)); emitter::ptr e = create_restore_emitter(new_md); - metadata::ptr old_md(new metadata(old_path)); + block_manager<>::ptr old_bm = open_bm(old_path, block_manager<>::READ_ONLY); + metadata::ptr old_md(new metadata(old_bm)); metadata_dump(old_md, e, true); } catch (std::exception &e) { diff --git a/thin-provisioning/thin_restore.cc b/thin-provisioning/thin_restore.cc index 57b82c3..293a45b 100644 --- a/thin-provisioning/thin_restore.cc +++ b/thin-provisioning/thin_restore.cc @@ -45,7 +45,8 @@ namespace { int restore(string const &backup_file, string const &dev, bool quiet) { try { // The block size gets updated by the restorer. - metadata::ptr md(new metadata(dev, metadata::CREATE, 128, 0)); + block_manager<>::ptr bm(open_bm(dev, block_manager<>::READ_WRITE)); + metadata::ptr md(new metadata(bm, metadata::CREATE, 128, 0)); emitter::ptr restorer = create_restore_emitter(md); parse_xml(backup_file, restorer, quiet); diff --git a/thin-provisioning/thin_trim.cc b/thin-provisioning/thin_trim.cc index 0118b62..19c48cd 100644 --- a/thin-provisioning/thin_trim.cc +++ b/thin-provisioning/thin_trim.cc @@ -6,6 +6,7 @@ #undef BLOCK_SIZE +#include "persistent-data/file_utils.h" #include "thin-provisioning/commands.h" #include "metadata.h" #include "version.h" @@ -118,7 +119,8 @@ namespace { int trim(string const &metadata_dev, string const &data_dev) { // We can trim any block that has zero count in the data // space map. - metadata md(metadata_dev, 0); + block_manager<>::ptr bm = open_bm(metadata_dev, block_manager<>::READ_ONLY); + metadata md(bm); if (!md.data_sm_->get_nr_free()) return 0; From a709b9718b9eefed5fd3523f606ba7bafccc6310 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 15 Dec 2015 10:08:07 +0000 Subject: [PATCH 35/59] [thin] Make the metadata class resposible for locating metadata snapshots --- thin-provisioning/metadata.cc | 59 +++++++++++++++++++++------------ thin-provisioning/metadata.h | 20 ++++++++++- thin-provisioning/superblock.cc | 12 ------- thin-provisioning/superblock.h | 3 -- thin-provisioning/thin_delta.cc | 35 +++++++++---------- thin-provisioning/thin_dump.cc | 52 ++++++++++++++++++----------- 6 files changed, 104 insertions(+), 77 deletions(-) diff --git a/thin-provisioning/metadata.cc b/thin-provisioning/metadata.cc index 9d9b652..69a3d4d 100644 --- a/thin-provisioning/metadata.cc +++ b/thin-provisioning/metadata.cc @@ -112,33 +112,32 @@ metadata::metadata(block_manager<>::ptr bm, open_type ot, } } -metadata::metadata(block_manager<>::ptr bm, block_address metadata_snap) +metadata::metadata(block_manager<>::ptr bm) +{ + tm_ = open_tm(bm); + sb_ = read_superblock(tm_->get_bm(), SUPERBLOCK_LOCATION); + + open_space_maps(); + open_btrees(); +} + +metadata::metadata(block_manager<>::ptr bm, + boost::optional metadata_snap) { tm_ = open_tm(bm); - if (metadata_snap) { - if (metadata_snap != sb_.metadata_snap_) + superblock_detail::superblock actual_sb = read_superblock(bm, SUPERBLOCK_LOCATION); + + if (!actual_sb.metadata_snap_) + throw runtime_error("no current metadata snap"); + + if (metadata_snap && *metadata_snap != actual_sb.metadata_snap_) throw runtime_error("metadata snapshot does not match that in superblock"); - sb_ = read_superblock(tm_->get_bm(), metadata_snap); + sb_ = read_superblock(bm, actual_sb.metadata_snap_); - // metadata snaps don't record the space maps - - } else { - sb_ = read_superblock(tm_->get_bm(), SUPERBLOCK_LOCATION); - - metadata_sm_ = open_metadata_sm(*tm_, &sb_.metadata_space_map_root_); - tm_->set_sm(metadata_sm_); - - data_sm_ = open_disk_sm(*tm_, static_cast(&sb_.data_space_map_root_)); - } - - details_ = device_tree::ptr(new device_tree(*tm_, sb_.device_details_root_, - device_tree_detail::device_details_traits::ref_counter())); - mappings_top_level_ = dev_tree::ptr(new dev_tree(*tm_, sb_.data_mapping_root_, - mapping_tree_detail::mtree_ref_counter(tm_))); - mappings_ = mapping_tree::ptr(new mapping_tree(*tm_, sb_.data_mapping_root_, - mapping_tree_detail::block_time_ref_counter(data_sm_))); + // metadata snaps don't record the space maps + open_btrees(); } void @@ -158,4 +157,22 @@ metadata::commit() superblock_traits::pack(sb_, *disk); } +void metadata::open_space_maps() +{ + metadata_sm_ = open_metadata_sm(*tm_, &sb_.metadata_space_map_root_); + tm_->set_sm(metadata_sm_); + + data_sm_ = open_disk_sm(*tm_, static_cast(&sb_.data_space_map_root_)); +} + +void metadata::open_btrees() +{ + details_ = device_tree::ptr(new device_tree(*tm_, sb_.device_details_root_, + device_tree_detail::device_details_traits::ref_counter())); + mappings_top_level_ = dev_tree::ptr(new dev_tree(*tm_, sb_.data_mapping_root_, + mapping_tree_detail::mtree_ref_counter(tm_))); + mappings_ = mapping_tree::ptr(new mapping_tree(*tm_, sb_.data_mapping_root_, + mapping_tree_detail::block_time_ref_counter(data_sm_))); +} + //---------------------------------------------------------------- diff --git a/thin-provisioning/metadata.h b/thin-provisioning/metadata.h index be20e16..d020542 100644 --- a/thin-provisioning/metadata.h +++ b/thin-provisioning/metadata.h @@ -62,7 +62,21 @@ namespace thin_provisioning { metadata(block_manager<>::ptr bm, open_type ot, sector_t data_block_size = 128, block_address nr_data_blocks = 0); // Only used if CREATE - metadata(block_manager<>::ptr bm, block_address metadata_snap = 0); + + // Ideally we'd like the metadata snap argument to be a + // boolean, and we'd read the snap location from the + // superblock. But the command line interface for some of + // the tools allows the user to pass in a block, which + // they've retrieved from the pool status. So we have to + // support 3 cases: + // + // i) Read superblock + // ii) Read the metadata snap as given in the superblock + // iii) Read the metadata snap given on command line, checking it matches superblock. + // + metadata(block_manager<>::ptr bm); // (i) + metadata(block_manager<>::ptr, + boost::optional metadata_snap); // (ii) and (iii) void commit(); @@ -75,6 +89,10 @@ namespace thin_provisioning { device_tree::ptr details_; dev_tree::ptr mappings_top_level_; mapping_tree::ptr mappings_; + + private: + void open_space_maps(); + void open_btrees(); }; } diff --git a/thin-provisioning/superblock.cc b/thin-provisioning/superblock.cc index 0d1ca63..9258b53 100644 --- a/thin-provisioning/superblock.cc +++ b/thin-provisioning/superblock.cc @@ -181,18 +181,6 @@ namespace thin_provisioning { visitor.visit(superblock_corruption(e.what())); } } - - block_address find_metadata_snap(string const &path) - { - superblock_detail::superblock sb = - read_superblock(open_bm(path, block_manager<>::READ_ONLY, false), 0); - uint64_t ms = sb.metadata_snap_; - - if (!ms) - throw runtime_error("no metadata snapshot found!\n"); - - return ms; - } } //---------------------------------------------------------------- diff --git a/thin-provisioning/superblock.h b/thin-provisioning/superblock.h index dbe733a..f527a15 100644 --- a/thin-provisioning/superblock.h +++ b/thin-provisioning/superblock.h @@ -137,9 +137,6 @@ namespace thin_provisioning { void check_superblock(persistent_data::block_manager<>::ptr bm, superblock_detail::damage_visitor &visitor); - - persistent_data::block_address find_metadata_snap(string const &path); - } //---------------------------------------------------------------- diff --git a/thin-provisioning/thin_delta.cc b/thin-provisioning/thin_delta.cc index deb5798..de2c0d7 100644 --- a/thin-provisioning/thin_delta.cc +++ b/thin-provisioning/thin_delta.cc @@ -14,6 +14,7 @@ #include "persistent-data/file_utils.h" #include "thin-provisioning/superblock.h" #include "thin-provisioning/mapping_tree.h" +#include "thin-provisioning/metadata.h" #include "thin-provisioning/commands.h" using namespace std; @@ -65,15 +66,16 @@ namespace local { struct flags { flags() : verbose(false), - find_metadata_snap(false) { + use_metadata_snap(false) { } + bool verbose; + bool use_metadata_snap; + boost::optional dev; boost::optional metadata_snap; boost::optional snap1; boost::optional snap2; - bool verbose; - bool find_metadata_snap; }; //-------------------------------- @@ -528,17 +530,12 @@ namespace local { checked_space_map::ptr data_sm; { - block_manager<>::ptr bm = open_bm(*fs.dev, block_manager<>::READ_ONLY, !fs.metadata_snap); - transaction_manager::ptr tm = open_tm(bm); - - sb = fs.metadata_snap ? read_superblock(bm, *fs.metadata_snap) : read_superblock(bm); - data_sm = open_disk_sm(*tm, static_cast(&sb.data_space_map_root_)); - - dev_tree dtree(*tm, sb.data_mapping_root_, - mapping_tree_detail::mtree_traits::ref_counter(tm)); + block_manager<>::ptr bm = open_bm(*fs.dev, block_manager<>::READ_ONLY, !fs.use_metadata_snap); + metadata::ptr md(fs.use_metadata_snap ? new metadata(bm, fs.metadata_snap) : new metadata(bm)); + sb = md->sb_; dev_tree::key k = {*fs.snap1}; - boost::optional snap1_root = dtree.lookup(k); + boost::optional snap1_root = md->mappings_top_level_->lookup(k); if (!snap1_root) { ostringstream out; @@ -546,10 +543,11 @@ namespace local { app.die(out.str()); } - single_mapping_tree snap1(*tm, *snap1_root, mapping_tree_detail::block_traits::ref_counter(tm->get_sm())); + single_mapping_tree snap1(*md->tm_, *snap1_root, + mapping_tree_detail::block_traits::ref_counter(md->tm_->get_sm())); k[0] = *fs.snap2; - boost::optional snap2_root = dtree.lookup(k); + boost::optional snap2_root = md->mappings_top_level_->lookup(k); if (!snap2_root) { ostringstream out; @@ -557,7 +555,8 @@ namespace local { app.die(out.str()); } - single_mapping_tree snap2(*tm, *snap2_root, mapping_tree_detail::block_traits::ref_counter(tm->get_sm())); + single_mapping_tree snap2(*md->tm_, *snap2_root, + mapping_tree_detail::block_traits::ref_counter(md->tm_->get_sm())); btree_visit_values(snap1, mr1, damage_v); mr1.complete(); @@ -642,10 +641,9 @@ int thin_delta_main(int argc, char **argv) break; case 'm': + fs.use_metadata_snap = true; if (optarg) fs.metadata_snap = app.parse_int(optarg, "metadata snapshot block"); - else - fs.find_metadata_snap = true; break; case 4: @@ -669,9 +667,6 @@ int thin_delta_main(int argc, char **argv) if (!fs.snap2) app.die("--snap2 not specified."); - if (fs.find_metadata_snap) - fs.metadata_snap = find_metadata_snap(*fs.dev); - return delta(app, fs); } diff --git a/thin-provisioning/thin_dump.cc b/thin-provisioning/thin_dump.cc index 2e49a66..97ecf5f 100644 --- a/thin-provisioning/thin_dump.cc +++ b/thin-provisioning/thin_dump.cc @@ -29,27 +29,42 @@ #include "thin-provisioning/commands.h" #include "persistent-data/file_utils.h" +using namespace boost; using namespace persistent_data; using namespace std; using namespace thin_provisioning; -struct flags { - bool find_metadata_snap; - bool repair; -}; - namespace { - int dump_(string const &path, ostream &out, string const &format, struct flags &flags, - block_address metadata_snap) { + // FIXME: put the path into the flags + struct flags { + flags() + : repair(false), + use_metadata_snap(false) { + } + + bool repair; + bool use_metadata_snap; + optional snap_location; + }; + + metadata::ptr open_metadata(string const &path, struct flags &flags) { + block_manager<>::ptr bm = open_bm(path, block_manager<>::READ_ONLY, !flags.use_metadata_snap); + metadata::ptr md(flags.use_metadata_snap ? new metadata(bm, flags.snap_location) : new metadata(bm)); + + return md; + } + + int dump_(string const &path, ostream &out, string const &format, struct flags &flags) { try { - block_manager<>::ptr bm = open_bm(path, block_manager<>::READ_ONLY, !metadata_snap); - metadata::ptr md(new metadata(bm, metadata_snap)); + metadata::ptr md = open_metadata(path, flags); emitter::ptr e; if (format == "xml") e = create_xml_emitter(out); + else if (format == "human_readable") e = create_human_readable_emitter(out); + else { cerr << "unknown format '" << format << "'" << endl; exit(1); @@ -65,13 +80,12 @@ namespace { return 0; } - int dump(string const &path, char const *output, string const &format, struct flags &flags, - block_address metadata_snap = 0) { + int dump(string const &path, char const *output, string const &format, struct flags &flags) { if (output) { ofstream out(output); - return dump_(path, out, format, flags, metadata_snap); + return dump_(path, out, format, flags); } else - return dump_(path, cout, format, flags, metadata_snap); + return dump_(path, cout, format, flags); } void usage(ostream &out, string const &cmd) { @@ -95,7 +109,6 @@ int thin_dump_main(int argc, char **argv) string format = "xml"; block_address metadata_snap = 0; struct flags flags; - flags.find_metadata_snap = flags.repair = false; const struct option longopts[] = { { "help", no_argument, NULL, 'h'}, @@ -122,16 +135,18 @@ int thin_dump_main(int argc, char **argv) break; case 'm': + flags.use_metadata_snap = true; if (optarg) { + // FIXME: deprecate this option metadata_snap = strtoull(optarg, &end_ptr, 10); if (end_ptr == optarg) { cerr << "couldn't parse " << endl; usage(cerr, basename(argv[0])); return 1; } - } else - flags.find_metadata_snap = true; + flags.snap_location = metadata_snap; + } break; case 'o': @@ -154,10 +169,7 @@ int thin_dump_main(int argc, char **argv) return 1; } - if (flags.find_metadata_snap) - metadata_snap = find_metadata_snap(argv[optind]); - - return dump(argv[optind], output, format, flags, metadata_snap); + return dump(argv[optind], output, format, flags); } base::command thin_provisioning::thin_dump_cmd("thin_dump", thin_dump_main); From c93e728ef49527a0ccb43f35b3f9063493339691 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Fri, 8 Jan 2016 12:51:52 +0000 Subject: [PATCH 36/59] [base] introduce a command type that gets registered with the app --- Makefile.in | 5 + base/application.cc | 37 +++- base/application.h | 38 +++- caching/cache_check.cc | 45 ++-- caching/cache_dump.cc | 36 ++-- caching/cache_metadata_size.cc | 260 ++++++++++++------------ caching/cache_repair.cc | 38 ++-- caching/cache_restore.cc | 52 ++--- caching/commands.cc | 18 ++ caching/commands.h | 63 +++++- era/commands.cc | 16 ++ era/commands.h | 33 ++- era/era_check.cc | 36 ++-- era/era_dump.cc | 38 ++-- era/era_invalidate.cc | 38 ++-- era/era_restore.cc | 45 ++-- main.cc | 24 +-- thin-provisioning/commands.cc | 22 ++ thin-provisioning/commands.h | 74 ++++++- thin-provisioning/metadata_dumper.cc | 2 +- thin-provisioning/thin_check.cc | 44 ++-- thin-provisioning/thin_delta.cc | 16 +- thin-provisioning/thin_dump.cc | 33 ++- thin-provisioning/thin_metadata_size.cc | 20 +- thin-provisioning/thin_repair.cc | 40 ++-- thin-provisioning/thin_restore.cc | 42 ++-- thin-provisioning/thin_rmap.cc | 40 ++-- thin-provisioning/thin_trim.cc | 32 +-- 28 files changed, 776 insertions(+), 411 deletions(-) create mode 100644 caching/commands.cc create mode 100644 era/commands.cc create mode 100644 thin-provisioning/commands.cc diff --git a/Makefile.in b/Makefile.in index e67b300..cbe9347 100644 --- a/Makefile.in +++ b/Makefile.in @@ -38,6 +38,7 @@ SOURCE=\ caching/cache_metadata_size.cc \ caching/cache_repair.cc \ caching/cache_restore.cc \ + caching/commands.cc \ caching/hint_array.cc \ caching/mapping_array.cc \ caching/metadata.cc \ @@ -45,6 +46,7 @@ SOURCE=\ caching/restore_emitter.cc \ caching/superblock.cc \ caching/xml_format.cc \ + era/commands.cc \ era/era_array.cc \ era/era_check.cc \ era/era_detail.cc \ @@ -71,6 +73,7 @@ SOURCE=\ persistent-data/space_map.cc \ persistent-data/transaction_manager.cc \ persistent-data/validators.cc \ + thin-provisioning/commands.cc \ thin-provisioning/device_tree.cc \ thin-provisioning/human_readable_format.cc \ thin-provisioning/mapping_tree.cc \ @@ -173,6 +176,7 @@ install: bin/pdata_tools ln -s -f pdata_tools $(BINDIR)/thin_check ln -s -f pdata_tools $(BINDIR)/thin_delta ln -s -f pdata_tools $(BINDIR)/thin_dump + ln -s -f pdata_tools $(BINDIR)/thin_ls ln -s -f pdata_tools $(BINDIR)/thin_repair ln -s -f pdata_tools $(BINDIR)/thin_restore ln -s -f pdata_tools $(BINDIR)/thin_rmap @@ -190,6 +194,7 @@ install: bin/pdata_tools $(INSTALL_DATA) man8/thin_check.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_delta.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_dump.8 $(MANPATH)/man8 + $(INSTALL_DATA) man8/thin_ls.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_repair.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_restore.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_rmap.8 $(MANPATH)/man8 diff --git a/base/application.cc b/base/application.cc index 9e1f0dd..0ec1749 100644 --- a/base/application.cc +++ b/base/application.cc @@ -1,14 +1,47 @@ #include "base/application.h" +#include #include #include #include +#include using namespace base; +using namespace boost; using namespace std; //---------------------------------------------------------------- +command::command(string const &name) + : name_(name) { +} + +void +command::die(string const &msg) +{ + cerr << msg << endl; + usage(cerr); + exit(1); +} + +uint64_t +command::parse_uint64(string const &str, string const &desc) +{ + try { + // FIXME: check trailing garbage is handled + return lexical_cast(str); + + } catch (...) { + ostringstream out; + out << "Couldn't parse " << desc << ": '" << str << "'"; + die(out.str()); + } + + return 0; // never get here +} + +//---------------------------------------------------------------- + int application::run(int argc, char **argv) { @@ -26,7 +59,7 @@ application::run(int argc, char **argv) cmd = argv[0]; } - std::list::const_iterator it; + std::list::const_iterator it; for (it = cmds_.begin(); it != cmds_.end(); ++it) { if (cmd == (*it)->get_name()) return (*it)->run(argc, argv); @@ -43,7 +76,7 @@ application::usage() std::cerr << "Usage: \n" << "commands:\n"; - std::list::const_iterator it; + std::list::const_iterator it; for (it = cmds_.begin(); it != cmds_.end(); ++it) { std::cerr << " " << (*it)->get_name() << "\n"; } diff --git a/base/application.h b/base/application.h index d01eb36..d3864af 100644 --- a/base/application.h +++ b/base/application.h @@ -1,40 +1,60 @@ #ifndef BASE_APPLICATION_H #define BASE_APPLICATION_H +#include #include #include #include #include +#include //---------------------------------------------------------------- namespace base { class command { public: - typedef int (*cmd_fn)(int, char **); + typedef boost::shared_ptr ptr; - command(std::string const &name, cmd_fn fn) - : name_(name), - fn_(fn) { - } + command(std::string const &name); + virtual ~command() {} + + void die(std::string const &msg); + uint64_t parse_uint64(std::string const &str, std::string const &desc); + + + virtual void usage(std::ostream &out) const = 0; + virtual int run(int argc, char **argv) = 0; std::string const &get_name() const { return name_; } + private: + std::string name_; + + }; + + class command_old : public command { + public: + typedef int (*cmd_fn)(int, char **); + + command_old(std::string const &name, cmd_fn fn) + : command(name), + fn_(fn) { + } + int run(int argc, char **argv) const { return fn_(argc, argv); } private: - std::string name_; cmd_fn fn_; }; class application { public: - void add_cmd(command const &c) { - cmds_.push_back(&c); + void add_cmd(command::ptr c) { + cmds_.push_back(c); } int run(int argc, char **argv); @@ -43,7 +63,7 @@ namespace base { void usage(); std::string get_basename(std::string const &path) const; - std::list cmds_; + std::list cmds_; }; } diff --git a/caching/cache_check.cc b/caching/cache_check.cc index 9bd34be..33d041b 100644 --- a/caching/cache_check.cc +++ b/caching/cache_check.cc @@ -31,7 +31,6 @@ using namespace std; //---------------------------------------------------------------- namespace { - class reporter_base { public: reporter_base(nested_output &o) @@ -326,24 +325,32 @@ namespace { return r; } - - 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 - << " {--clear-needs-check-flag}" << endl - << " {--super-block-only}" << endl - << " {--skip-mappings}" << endl - << " {--skip-hints}" << endl - << " {--skip-discards}" << endl; - } } //---------------------------------------------------------------- -int cache_check_main(int argc, char **argv) +cache_check_cmd::cache_check_cmd() + : command("cache_check") +{ +} + +void +cache_check_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-q|--quiet}" << endl + << " {-h|--help}" << endl + << " {-V|--version}" << endl + << " {--clear-needs-check-flag}" << endl + << " {--super-block-only}" << endl + << " {--skip-mappings}" << endl + << " {--skip-hints}" << endl + << " {--skip-discards}" << endl; +} + +int +cache_check_cmd::run(int argc, char **argv) { int c; flags fs; @@ -384,7 +391,7 @@ int cache_check_main(int argc, char **argv) break; case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'q': @@ -396,20 +403,18 @@ int cache_check_main(int argc, char **argv) return 0; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } return check_with_exception_handling(argv[optind], fs); } -base::command caching::cache_check_cmd("cache_check", cache_check_main); - //---------------------------------------------------------------- diff --git a/caching/cache_dump.cc b/caching/cache_dump.cc index 117f86d..1831752 100644 --- a/caching/cache_dump.cc +++ b/caching/cache_dump.cc @@ -54,20 +54,28 @@ namespace { return 0; } - - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options] {device|file}" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-o }" << endl - << " {-V|--version}" << endl - << " {--repair}" << endl; - } } //---------------------------------------------------------------- -int cache_dump_main(int argc, char **argv) +cache_dump_cmd::cache_dump_cmd() + : command("cache_dump") +{ +} + +void +cache_dump_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-o }" << endl + << " {-V|--version}" << endl + << " {--repair}" << endl; +} + +int +cache_dump_cmd::run(int argc, char **argv) { int c; flags fs; @@ -89,7 +97,7 @@ int cache_dump_main(int argc, char **argv) break; case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'o': @@ -101,20 +109,18 @@ int cache_dump_main(int argc, char **argv) return 0; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } return dump(argv[optind], output, fs); } -base::command caching::cache_dump_cmd("cache_dump", cache_dump_main); - //---------------------------------------------------------------- diff --git a/caching/cache_metadata_size.cc b/caching/cache_metadata_size.cc index dd806c8..57cfe03 100644 --- a/caching/cache_metadata_size.cc +++ b/caching/cache_metadata_size.cc @@ -9,141 +9,145 @@ #include #include +using namespace caching; using namespace std; //---------------------------------------------------------------- -namespace { - struct flags { - flags() - : max_hint_width(4) { +cache_metadata_size_cmd::flags::flags() + : max_hint_width(4) { - // Dance around some spurious compiler warnings - device_size = 0; - block_size = 0; - nr_blocks = 0; + // Dance around some spurious compiler warnings + device_size = 0; + block_size = 0; + nr_blocks = 0; - device_size.reset(); - block_size.reset(); - nr_blocks.reset(); - } - - boost::optional device_size; - boost::optional block_size; - boost::optional nr_blocks; - uint32_t max_hint_width; - }; - - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options]" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-V|--version}" << endl - << " {--block-size }" << endl - << " {--device-size }" << endl - << " {--nr-blocks }" << endl << endl - << "These all relate to the size of the fast device (eg, SSD), rather" << endl - << "than the whole cached device." << endl; - } - - enum parse_result { - FINISH, - CONTINUE - }; - - parse_result parse_command_line(string const &prog_name, int argc, char **argv, flags &fs) { - - int c; - char const short_opts[] = "hV"; - option const long_opts[] = { - { "block-size", required_argument, NULL, 0 }, - { "device-size", required_argument, NULL, 1 }, - { "nr-blocks", required_argument, NULL, 2 }, - { "max-hint-width", required_argument, NULL, 3 }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { NULL, no_argument, NULL, 0 } - }; - - while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { - switch (c) { - case 0: - fs.block_size = boost::lexical_cast(optarg); - break; - - case 1: - fs.device_size = boost::lexical_cast(optarg); - break; - - case 2: - fs.nr_blocks = boost::lexical_cast(optarg); - break; - - case 3: - fs.max_hint_width = boost::lexical_cast(optarg); - break; - - case 'h': - usage(cout, prog_name); - return FINISH; - break; - - case 'V': - cout << THIN_PROVISIONING_TOOLS_VERSION << endl; - return FINISH; - break; - - default: - usage(cerr, prog_name); - throw runtime_error("Invalid command line"); - break; - } - } - - return CONTINUE; - } - - uint64_t get_nr_blocks(flags &fs) { - if (fs.device_size) { - if (!fs.block_size) - throw runtime_error("If you specify --device-size you must also give --block-size."); - - uint64_t nr_blocks = *fs.device_size / *fs.block_size; - if (fs.nr_blocks) { - if (nr_blocks != *fs.nr_blocks) - throw runtime_error( - "Contradictory arguments given, --nr-blocks doesn't match the --device-size and --block-size."); - } - - return nr_blocks; - } - - if (fs.block_size && !fs.device_size) - throw runtime_error("If you specify --block-size you must also give --device-size."); - - if (fs.nr_blocks) - return *fs.nr_blocks; - - throw runtime_error("Please specify either --device-size and --block-size, or --nr-blocks."); - } - - uint64_t meg(uint64_t n) { - return n * 2048; - } - - uint64_t calc_size(uint64_t nr_blocks, uint32_t max_hint_width) { - uint64_t const SECTOR_SIZE = 512; - uint64_t const TRANSACTION_OVERHEAD = meg(4); - uint64_t const BYTES_PER_BLOCK = 16; - uint64_t const HINT_OVERHEAD_PER_BLOCK = 8; - - uint64_t mapping_size = (nr_blocks * BYTES_PER_BLOCK) / SECTOR_SIZE; - uint64_t hint_size = (nr_blocks * (max_hint_width + HINT_OVERHEAD_PER_BLOCK)) / SECTOR_SIZE; - return TRANSACTION_OVERHEAD + mapping_size + hint_size; - } + device_size.reset(); + block_size.reset(); + nr_blocks.reset(); } -int cache_metadata_size_main(int argc, char **argv) +cache_metadata_size_cmd::parse_result +cache_metadata_size_cmd::parse_command_line(string const &prog_name, int argc, char **argv, flags &fs) +{ + int c; + char const short_opts[] = "hV"; + option const long_opts[] = { + { "block-size", required_argument, NULL, 0 }, + { "device-size", required_argument, NULL, 1 }, + { "nr-blocks", required_argument, NULL, 2 }, + { "max-hint-width", required_argument, NULL, 3 }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { NULL, no_argument, NULL, 0 } + }; + + while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { + switch (c) { + case 0: + fs.block_size = boost::lexical_cast(optarg); + break; + + case 1: + fs.device_size = boost::lexical_cast(optarg); + break; + + case 2: + fs.nr_blocks = boost::lexical_cast(optarg); + break; + + case 3: + fs.max_hint_width = boost::lexical_cast(optarg); + break; + + case 'h': + usage(cout); + return FINISH; + break; + + case 'V': + cout << THIN_PROVISIONING_TOOLS_VERSION << endl; + return FINISH; + break; + + default: + usage(cerr); + throw runtime_error("Invalid command line"); + break; + } + } + + return CONTINUE; +} + +uint64_t +cache_metadata_size_cmd::get_nr_blocks(flags &fs) +{ + if (fs.device_size) { + if (!fs.block_size) + throw runtime_error("If you specify --device-size you must also give --block-size."); + + uint64_t nr_blocks = *fs.device_size / *fs.block_size; + if (fs.nr_blocks) { + if (nr_blocks != *fs.nr_blocks) + throw runtime_error( + "Contradictory arguments given, --nr-blocks doesn't match the --device-size and --block-size."); + } + + return nr_blocks; + } + + if (fs.block_size && !fs.device_size) + throw runtime_error("If you specify --block-size you must also give --device-size."); + + if (fs.nr_blocks) + return *fs.nr_blocks; + + throw runtime_error("Please specify either --device-size and --block-size, or --nr-blocks."); +} + +uint64_t +cache_metadata_size_cmd::meg(uint64_t n) +{ + return n * 2048; +} + +uint64_t +cache_metadata_size_cmd::calc_size(uint64_t nr_blocks, uint32_t max_hint_width) +{ + uint64_t const SECTOR_SIZE = 512; + uint64_t const TRANSACTION_OVERHEAD = meg(4); + uint64_t const BYTES_PER_BLOCK = 16; + uint64_t const HINT_OVERHEAD_PER_BLOCK = 8; + + uint64_t mapping_size = (nr_blocks * BYTES_PER_BLOCK) / SECTOR_SIZE; + uint64_t hint_size = (nr_blocks * (max_hint_width + HINT_OVERHEAD_PER_BLOCK)) / SECTOR_SIZE; + return TRANSACTION_OVERHEAD + mapping_size + hint_size; +} + +//---------------------------------------------------------------- + +cache_metadata_size_cmd::cache_metadata_size_cmd() + : command("cache_metadata_size") +{ +} + +void +cache_metadata_size_cmd::usage(ostream &out) const +{ + out << "Usage: " << get_name() << " [options]" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-V|--version}" << endl + << " {--block-size }" << endl + << " {--device-size }" << endl + << " {--nr-blocks }" << endl << endl + << "These all relate to the size of the fast device (eg, SSD), rather" << endl + << "than the whole cached device." << endl; +} + +int +cache_metadata_size_cmd::run(int argc, char **argv) { flags fs; @@ -167,6 +171,4 @@ int cache_metadata_size_main(int argc, char **argv) return 0; } -base::command caching::cache_metadata_size_cmd("cache_metadata_size", cache_metadata_size_main); - //---------------------------------------------------------------- diff --git a/caching/cache_repair.cc b/caching/cache_repair.cc index 8419796..dfe644b 100644 --- a/caching/cache_repair.cc +++ b/caching/cache_repair.cc @@ -40,20 +40,28 @@ namespace { return 0; } - - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options] {device|file}" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-i|--input} " << endl - << " {-o|--output} " << endl - << " {-V|--version}" << endl; - } } //---------------------------------------------------------------- -int cache_repair_main(int argc, char **argv) +cache_repair_cmd::cache_repair_cmd() + : command("cache_repair") +{ +} + +void +cache_repair_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-i|--input} " << endl + << " {-o|--output} " << endl + << " {-V|--version}" << endl; +} + +int +cache_repair_cmd::run(int argc, char **argv) { int c; boost::optional input_path, output_path; @@ -70,7 +78,7 @@ int cache_repair_main(int argc, char **argv) while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'i': @@ -86,26 +94,24 @@ int cache_repair_main(int argc, char **argv) return 0; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (!input_path) { cerr << "no input file provided" << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } if (!output_path) { cerr << "no output file provided" << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } return repair(*input_path, *output_path); } -base::command caching::cache_repair_cmd("cache_repair", cache_repair_main); - //---------------------------------------------------------------- diff --git a/caching/cache_restore.cc b/caching/cache_restore.cc index b0a6437..a357eed 100644 --- a/caching/cache_restore.cc +++ b/caching/cache_restore.cc @@ -80,27 +80,35 @@ namespace { return 0; } - - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options]" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-i|--input} " << endl - << " {-o|--output} " << endl - << " {-q|--quiet}" << endl - << " {-V|--version}" << endl - << endl - << " {--debug-override-metadata-version} " << endl - << " {--omit-clean-shutdown}" << endl; - - } } -int cache_restore_main(int argc, char **argv) +//---------------------------------------------------------------- + +cache_restore_cmd::cache_restore_cmd() + : command("cache_restore") +{ +} + +void +cache_restore_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options]" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-i|--input} " << endl + << " {-o|--output} " << endl + << " {-q|--quiet}" << endl + << " {-V|--version}" << endl + << endl + << " {--debug-override-metadata-version} " << endl + << " {--omit-clean-shutdown}" << endl; +} + +int +cache_restore_cmd::run(int argc, char **argv) { int c; flags fs; - char const *prog_name = basename(argv[0]); char const *short_opts = "hi:o:qV"; option const long_opts[] = { { "debug-override-metadata-version", required_argument, NULL, 0 }, @@ -125,7 +133,7 @@ int cache_restore_main(int argc, char **argv) break; case 'h': - usage(cout, prog_name); + usage(cout); return 0; case 'i': @@ -145,31 +153,29 @@ int cache_restore_main(int argc, char **argv) return 0; default: - usage(cerr, prog_name); + usage(cerr); return 1; } } if (argc != optind) { - usage(cerr, prog_name); + usage(cerr); return 1; } if (!fs.input) { cerr << "No input file provided." << endl << endl; - usage(cerr, prog_name); + usage(cerr); return 1; } if (!fs.output) { cerr << "No output file provided." << endl << endl; - usage(cerr, prog_name); + usage(cerr); return 1; } return restore(fs); } -base::command caching::cache_restore_cmd("cache_restore", cache_restore_main); - //---------------------------------------------------------------- diff --git a/caching/commands.cc b/caching/commands.cc new file mode 100644 index 0000000..1ab79e6 --- /dev/null +++ b/caching/commands.cc @@ -0,0 +1,18 @@ +#include "caching/commands.h" + +using namespace base; +using namespace caching; + +//---------------------------------------------------------------- + +void +caching::register_cache_commands(application &app) +{ + app.add_cmd(command::ptr(new cache_check_cmd)); + app.add_cmd(command::ptr(new cache_dump_cmd)); + app.add_cmd(command::ptr(new cache_metadata_size_cmd)); + app.add_cmd(command::ptr(new cache_restore_cmd)); + app.add_cmd(command::ptr(new cache_repair_cmd)); +} + +//---------------------------------------------------------------- diff --git a/caching/commands.h b/caching/commands.h index 1396b9b..022ac06 100644 --- a/caching/commands.h +++ b/caching/commands.h @@ -2,15 +2,68 @@ #define CACHING_COMMANDS_H #include "base/application.h" +#include "boost/optional.hpp" //---------------------------------------------------------------- namespace caching { - extern base::command cache_check_cmd; - extern base::command cache_dump_cmd; - extern base::command cache_metadata_size_cmd; - extern base::command cache_restore_cmd; - extern base::command cache_repair_cmd; + class cache_check_cmd : public base::command { + public: + cache_check_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class cache_dump_cmd : public base::command { + public: + cache_dump_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class cache_metadata_size_cmd : public base::command { + public: + cache_metadata_size_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + + + private: + struct flags { + flags(); + + boost::optional device_size; + boost::optional block_size; + boost::optional nr_blocks; + uint32_t max_hint_width; + }; + + enum parse_result { + FINISH, + CONTINUE + }; + + parse_result parse_command_line(std::string const &prog_name, int argc, char **argv, flags &fs); + uint64_t get_nr_blocks(flags &fs); + uint64_t meg(uint64_t n); + uint64_t calc_size(uint64_t nr_blocks, uint32_t max_hint_width); + }; + + class cache_repair_cmd : public base::command { + public: + cache_repair_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class cache_restore_cmd : public base::command { + public: + cache_restore_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + void register_cache_commands(base::application &app); } //---------------------------------------------------------------- diff --git a/era/commands.cc b/era/commands.cc new file mode 100644 index 0000000..5a8efb0 --- /dev/null +++ b/era/commands.cc @@ -0,0 +1,16 @@ +#include "era/commands.h" + +using namespace base; + +//---------------------------------------------------------------- + +void +era::register_era_commands(base::application &app) +{ + app.add_cmd(command::ptr(new era_check_cmd())); + app.add_cmd(command::ptr(new era_dump_cmd())); + app.add_cmd(command::ptr(new era_invalidate_cmd())); + app.add_cmd(command::ptr(new era_restore_cmd())); +} + +//---------------------------------------------------------------- diff --git a/era/commands.h b/era/commands.h index f556fbf..8e7a92c 100644 --- a/era/commands.h +++ b/era/commands.h @@ -6,10 +6,35 @@ //---------------------------------------------------------------- namespace era { - extern base::command era_check_cmd; - extern base::command era_dump_cmd; - extern base::command era_invalidate_cmd; - extern base::command era_restore_cmd; + class era_check_cmd : public base::command { + public: + era_check_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class era_dump_cmd : public base::command { + public: + era_dump_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class era_invalidate_cmd : public base::command { + public: + era_invalidate_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class era_restore_cmd : public base::command { + public: + era_restore_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + void register_era_commands(base::application &app); } //---------------------------------------------------------------- diff --git a/era/era_check.cc b/era/era_check.cc index d64999d..73e5169 100644 --- a/era/era_check.cc +++ b/era/era_check.cc @@ -262,20 +262,28 @@ namespace { return r; } - - 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 - << " {--super-block-only}" << endl; - } } //---------------------------------------------------------------- -int era_check_main(int argc, char **argv) +era_check_cmd::era_check_cmd() + : command("era_check") +{ +} + +void +era_check_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-q|--quiet}" << endl + << " {-h|--help}" << endl + << " {-V|--version}" << endl + << " {--super-block-only}" << endl; +} + +int +era_check_cmd::run(int argc, char **argv) { int c; flags fs; @@ -295,7 +303,7 @@ int era_check_main(int argc, char **argv) break; case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'q': @@ -307,20 +315,18 @@ int era_check_main(int argc, char **argv) return 0; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } return check_with_exception_handling(argv[optind], fs); } -base::command era::era_check_cmd("era_check", era_check_main); - //---------------------------------------------------------------- diff --git a/era/era_dump.cc b/era/era_dump.cc index c279cd1..f2c1957 100644 --- a/era/era_dump.cc +++ b/era/era_dump.cc @@ -57,21 +57,29 @@ namespace { return 0; } - - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options] {device|file}" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-o }" << endl - << " {-V|--version}" << endl - << " {--repair}" << endl - << " {--logical}" << endl; - } } //---------------------------------------------------------------- -int era_dump_main(int argc, char **argv) +era_dump_cmd::era_dump_cmd() + : command("era_dump") +{ +} + +void +era_dump_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-o }" << endl + << " {-V|--version}" << endl + << " {--repair}" << endl + << " {--logical}" << endl; +} + +int +era_dump_cmd::run(int argc, char **argv) { int c; flags fs; @@ -98,7 +106,7 @@ int era_dump_main(int argc, char **argv) break; case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'o': @@ -110,20 +118,18 @@ int era_dump_main(int argc, char **argv) return 0; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } return dump(argv[optind], output, fs); } -base::command era::era_dump_cmd("era_dump", era_dump_main); - //---------------------------------------------------------------- diff --git a/era/era_invalidate.cc b/era/era_invalidate.cc index 20490a0..76eaadd 100644 --- a/era/era_invalidate.cc +++ b/era/era_invalidate.cc @@ -182,20 +182,28 @@ namespace { return 0; } - - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options] --written-since {device|file}\n" - << "Options:\n" - << " {-h|--help}\n" - << " {-o }\n" - << " {--metadata-snapshot}\n" - << " {-V|--version}" << endl; - } } //---------------------------------------------------------------- -int era_invalidate_main(int argc, char **argv) +era_invalidate_cmd::era_invalidate_cmd() + : command("era_invalidate") +{ +} + +void +era_invalidate_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] --written-since {device|file}\n" + << "Options:\n" + << " {-h|--help}\n" + << " {-o }\n" + << " {--metadata-snapshot}\n" + << " {-V|--version}" << endl; +} + +int +era_invalidate_cmd::run(int argc, char **argv) { int c; flags fs; @@ -222,7 +230,7 @@ int era_invalidate_main(int argc, char **argv) break; case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'o': @@ -234,26 +242,24 @@ int era_invalidate_main(int argc, char **argv) return 0; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } if (!fs.era_threshold_) { cerr << "Please specify --written-since" << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } return invalidate(argv[optind], output, fs); } -base::command era::era_invalidate_cmd("era_invalidate", era_invalidate_main); - //---------------------------------------------------------------- diff --git a/era/era_restore.cc b/era/era_restore.cc index 761f920..0f41a96 100644 --- a/era/era_restore.cc +++ b/era/era_restore.cc @@ -46,23 +46,32 @@ namespace { return 0; } - - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options]" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-i|--input} " << endl - << " {-o|--output} " << endl - << " {-q|--quiet}" << endl - << " {-V|--version}" << endl; - } } -int era_restore_main(int argc, char **argv) +//---------------------------------------------------------------- + +era_restore_cmd::era_restore_cmd() + : command("era_restore") +{ +} + +void +era_restore_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options]" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-i|--input} " << endl + << " {-o|--output} " << endl + << " {-q|--quiet}" << endl + << " {-V|--version}" << endl; +} + +int +era_restore_cmd::run(int argc, char **argv) { int c; flags fs; - char const *prog_name = basename(argv[0]); char const *short_opts = "hi:o:qV"; option const long_opts[] = { { "help", no_argument, NULL, 'h'}, @@ -76,7 +85,7 @@ int era_restore_main(int argc, char **argv) while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { switch(c) { case 'h': - usage(cout, prog_name); + usage(cout); return 0; case 'i': @@ -96,31 +105,29 @@ int era_restore_main(int argc, char **argv) return 0; default: - usage(cerr, prog_name); + usage(cerr); return 1; } } if (argc != optind) { - usage(cerr, prog_name); + usage(cerr); return 1; } if (!fs.input) { cerr << "No input file provided." << endl << endl; - usage(cerr, prog_name); + usage(cerr); return 1; } if (!fs.output) { cerr << "No output file provided." << endl << endl; - usage(cerr, prog_name); + usage(cerr); return 1; } return restore(fs, fs.quiet); } -base::command era::era_restore_cmd("era_restore", era_restore_main); - //---------------------------------------------------------------- diff --git a/main.cc b/main.cc index ed69ba9..98c9003 100644 --- a/main.cc +++ b/main.cc @@ -14,27 +14,9 @@ int main(int argc, char **argv) application app; - app.add_cmd(caching::cache_check_cmd); - app.add_cmd(caching::cache_dump_cmd); - app.add_cmd(caching::cache_metadata_size_cmd); - app.add_cmd(caching::cache_restore_cmd); - app.add_cmd(caching::cache_repair_cmd); - - app.add_cmd(era::era_check_cmd); - app.add_cmd(era::era_dump_cmd); - app.add_cmd(era::era_invalidate_cmd); - app.add_cmd(era::era_restore_cmd); - - app.add_cmd(thin_provisioning::thin_check_cmd); - app.add_cmd(thin_provisioning::thin_delta_cmd); - app.add_cmd(thin_provisioning::thin_dump_cmd); - app.add_cmd(thin_provisioning::thin_metadata_size_cmd); - app.add_cmd(thin_provisioning::thin_restore_cmd); - app.add_cmd(thin_provisioning::thin_repair_cmd); - app.add_cmd(thin_provisioning::thin_rmap_cmd); - - // FIXME: convert thin_metadata_size to c++ - //app.add_cmd(thin_provisioning::thin_metadata_size_cmd); + caching::register_cache_commands(app); + era::register_era_commands(app); + thin_provisioning::register_thin_commands(app); return app.run(argc, argv); } diff --git a/thin-provisioning/commands.cc b/thin-provisioning/commands.cc new file mode 100644 index 0000000..cd51000 --- /dev/null +++ b/thin-provisioning/commands.cc @@ -0,0 +1,22 @@ +#include "thin-provisioning/commands.h" + +using namespace base; +using namespace thin_provisioning; + +//---------------------------------------------------------------- + +void +thin_provisioning::register_thin_commands(base::application &app) +{ + app.add_cmd(command::ptr(new thin_check_cmd())); + app.add_cmd(command::ptr(new thin_delta_cmd())); + app.add_cmd(command::ptr(new thin_dump_cmd())); + //app.add_cmd(command::ptr(new thin_ls_cmd())); + app.add_cmd(command::ptr(new thin_metadata_size_cmd())); + app.add_cmd(command::ptr(new thin_restore_cmd())); + app.add_cmd(command::ptr(new thin_repair_cmd())); + app.add_cmd(command::ptr(new thin_rmap_cmd())); + app.add_cmd(command::ptr(new thin_trim_cmd())); +} + +//---------------------------------------------------------------- diff --git a/thin-provisioning/commands.h b/thin-provisioning/commands.h index de63e53..ec1f1ec 100644 --- a/thin-provisioning/commands.h +++ b/thin-provisioning/commands.h @@ -2,19 +2,75 @@ #define THIN_PROVISIONING_COMMANDS_H #include "base/application.h" +#include "boost/optional.hpp" //---------------------------------------------------------------- namespace thin_provisioning { - extern base::command thin_check_cmd; - extern base::command thin_delta_cmd; - extern base::command thin_dump_cmd; - extern base::command thin_metadata_size_cmd; - extern base::command thin_restore_cmd; - extern base::command thin_repair_cmd; - extern base::command thin_rmap_cmd; - extern base::command thin_trim_cmd; - extern base::command thin_metadata_size_cmd; + class thin_check_cmd : public base::command { + public: + thin_check_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class thin_delta_cmd : public base::command { + public: + thin_delta_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class thin_dump_cmd : public base::command { + public: + thin_dump_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class thin_ls_cmd : public base::command { + public: + thin_ls_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class thin_metadata_size_cmd : public base::command { + public: + thin_metadata_size_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class thin_restore_cmd : public base::command { + public: + thin_restore_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class thin_repair_cmd : public base::command { + public: + thin_repair_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class thin_rmap_cmd : public base::command { + public: + thin_rmap_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + class thin_trim_cmd : public base::command { + public: + thin_trim_cmd(); + virtual void usage(std::ostream &out) const; + virtual int run(int argc, char **argv); + }; + + void register_thin_commands(base::application &app); } //---------------------------------------------------------------- diff --git a/thin-provisioning/metadata_dumper.cc b/thin-provisioning/metadata_dumper.cc index db656ee..52199f2 100644 --- a/thin-provisioning/metadata_dumper.cc +++ b/thin-provisioning/metadata_dumper.cc @@ -84,7 +84,7 @@ namespace { //-------------------------------- - typedef map dd_map; + typedef map dd_map; class details_extractor : public device_tree_detail::device_visitor { public: diff --git a/thin-provisioning/thin_check.cc b/thin-provisioning/thin_check.cc index f14ee37..2451db2 100644 --- a/thin-provisioning/thin_check.cc +++ b/thin-provisioning/thin_check.cc @@ -344,21 +344,31 @@ namespace { return !success; } - - 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 - << " {--clear-needs-check-flag}" << endl - << " {--ignore-non-fatal-errors}" << endl - << " {--skip-mappings}" << endl - << " {--super-block-only}" << endl; - } } -int thin_check_main(int argc, char **argv) +//---------------------------------------------------------------- + +thin_check_cmd::thin_check_cmd() + : command("thin_check") +{ +} + +void +thin_check_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-q|--quiet}" << endl + << " {-h|--help}" << endl + << " {-V|--version}" << endl + << " {--clear-needs-check-flag}" << endl + << " {--ignore-non-fatal-errors}" << endl + << " {--skip-mappings}" << endl + << " {--super-block-only}" << endl; +} + +int +thin_check_cmd::run(int argc, char **argv) { int c; flags fs; @@ -378,7 +388,7 @@ int thin_check_main(int argc, char **argv) while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'q': @@ -412,7 +422,7 @@ int thin_check_main(int argc, char **argv) break; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } @@ -420,7 +430,7 @@ int thin_check_main(int argc, char **argv) if (argc == optind) { if (!fs.quiet) { cerr << "No input file provided." << endl; - usage(cerr, basename(argv[0])); + usage(cerr); } exit(1); @@ -429,6 +439,4 @@ int thin_check_main(int argc, char **argv) return check(argv[optind], fs); } -base::command thin_provisioning::thin_check_cmd("thin_check", thin_check_main); - //---------------------------------------------------------------- diff --git a/thin-provisioning/thin_delta.cc b/thin-provisioning/thin_delta.cc index de2c0d7..3ec71c8 100644 --- a/thin-provisioning/thin_delta.cc +++ b/thin-provisioning/thin_delta.cc @@ -602,7 +602,19 @@ namespace local { // FIXME: add metadata snap switch -int thin_delta_main(int argc, char **argv) +thin_delta_cmd::thin_delta_cmd() + : command("thin_delta") +{ +} + +void +thin_delta_cmd::usage(std::ostream &out) const +{ + // FIXME: finish +} + +int +thin_delta_cmd::run(int argc, char **argv) { using namespace local; @@ -670,6 +682,4 @@ int thin_delta_main(int argc, char **argv) return delta(app, fs); } -base::command thin_provisioning::thin_delta_cmd("thin_delta", thin_delta_main); - //---------------------------------------------------------------- diff --git a/thin-provisioning/thin_dump.cc b/thin-provisioning/thin_dump.cc index 97ecf5f..4a1108b 100644 --- a/thin-provisioning/thin_dump.cc +++ b/thin-provisioning/thin_dump.cc @@ -100,7 +100,28 @@ namespace { } } -int thin_dump_main(int argc, char **argv) +//---------------------------------------------------------------- + +thin_dump_cmd::thin_dump_cmd() + : command("thin_dump") +{ +} + +void +thin_dump_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-f|--format} {xml|human_readable}" << endl + << " {-r|--repair}" << endl + << " {-m|--metadata-snap} [block#]" << endl + << " {-o }" << endl + << " {-V|--version}" << endl; +} + +int +thin_dump_cmd::run(int argc, char **argv) { int c; char const *output = NULL; @@ -123,7 +144,7 @@ int thin_dump_main(int argc, char **argv) while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'f': @@ -141,7 +162,7 @@ int thin_dump_main(int argc, char **argv) metadata_snap = strtoull(optarg, &end_ptr, 10); if (end_ptr == optarg) { cerr << "couldn't parse " << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } @@ -158,20 +179,18 @@ int thin_dump_main(int argc, char **argv) return 0; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } return dump(argv[optind], output, format, flags); } -base::command thin_provisioning::thin_dump_cmd("thin_dump", thin_dump_main); - //---------------------------------------------------------------- diff --git a/thin-provisioning/thin_metadata_size.cc b/thin-provisioning/thin_metadata_size.cc index e45e04c..8fc953c 100644 --- a/thin-provisioning/thin_metadata_size.cc +++ b/thin-provisioning/thin_metadata_size.cc @@ -35,6 +35,8 @@ #include +using namespace thin_provisioning; + /*----------------------------------------------------------------*/ enum numeric_options { BLOCKSIZE, POOLSIZE, MAXTHINS, NUMERIC, OPT_END}; @@ -362,7 +364,21 @@ static void print_estimated_result(struct global *g) print_precision(g, r, g->options.unit_idx); } -int thin_metadata_size_main(int argc, char **argv) +//---------------------------------------------------------------- + +thin_metadata_size_cmd::thin_metadata_size_cmd() + : command("thin_metadata_size") +{ +} + +void +thin_metadata_size_cmd::usage(std::ostream &out) const +{ + // FIXME: finish +} + +int +thin_metadata_size_cmd::run(int argc, char **argv) { struct global *g = init_prg(*argv); @@ -372,4 +388,4 @@ int thin_metadata_size_main(int argc, char **argv) return 0; /* Doesn't get here... */ } -base::command thin_provisioning::thin_metadata_size_cmd("thin_metadata_size", thin_metadata_size_main); +//---------------------------------------------------------------- diff --git a/thin-provisioning/thin_repair.cc b/thin-provisioning/thin_repair.cc index 8751b47..abae4ca 100644 --- a/thin-provisioning/thin_repair.cc +++ b/thin-provisioning/thin_repair.cc @@ -33,18 +33,28 @@ namespace { return 0; } - - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options] {device|file}" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-i|--input} " << endl - << " {-o|--output} " << endl - << " {-V|--version}" << endl; - } } -int thin_repair_main(int argc, char **argv) +//---------------------------------------------------------------- + +thin_repair_cmd::thin_repair_cmd() + : command("thin_repair") +{ +} + +void +thin_repair_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-i|--input} " << endl + << " {-o|--output} " << endl + << " {-V|--version}" << endl; +} + +int +thin_repair_cmd::run(int argc, char **argv) { int c; boost::optional input_path, output_path; @@ -61,7 +71,7 @@ int thin_repair_main(int argc, char **argv) while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'i': @@ -77,26 +87,24 @@ int thin_repair_main(int argc, char **argv) return 0; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (!input_path) { cerr << "no input file provided" << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } if (!output_path) { cerr << "no output file provided" << endl; - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } return repair(*input_path, *output_path); } -base::command thin_provisioning::thin_repair_cmd("thin_repair", thin_repair_main); - //---------------------------------------------------------------- diff --git a/thin-provisioning/thin_restore.cc b/thin-provisioning/thin_restore.cc index 293a45b..39f9c54 100644 --- a/thin-provisioning/thin_restore.cc +++ b/thin-provisioning/thin_restore.cc @@ -60,20 +60,32 @@ namespace { } void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options]" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-i|--input} " << endl - << " {-o|--output} " << endl - << " {-q|--quiet}" << endl - << " {-V|--version}" << endl; } } -int thin_restore_main(int argc, char **argv) +//---------------------------------------------------------------- + +thin_restore_cmd::thin_restore_cmd() + : command("thin_restore") +{ +} + +void +thin_restore_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options]" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-i|--input} " << endl + << " {-o|--output} " << endl + << " {-q|--quiet}" << endl + << " {-V|--version}" << endl; +} + +int +thin_restore_cmd::run(int argc, char **argv) { int c; - char const *prog_name = basename(argv[0]); const char *shortopts = "hi:o:qV"; string input, output; bool quiet = false; @@ -89,7 +101,7 @@ int thin_restore_main(int argc, char **argv) while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 'h': - usage(cout, prog_name); + usage(cout); return 0; case 'i': @@ -109,31 +121,29 @@ int thin_restore_main(int argc, char **argv) return 0; default: - usage(cerr, prog_name); + usage(cerr); return 1; } } if (argc != optind) { - usage(cerr, prog_name); + usage(cerr); return 1; } if (input.empty()) { cerr << "No input file provided." << endl << endl; - usage(cerr, prog_name); + usage(cerr); return 1; } if (output.empty()) { cerr << "No output file provided." << endl << endl; - usage(cerr, prog_name); + usage(cerr); return 1; } return restore(input, output, quiet); } -base::command thin_provisioning::thin_restore_cmd("thin_restore", thin_restore_main); - //---------------------------------------------------------------- diff --git a/thin-provisioning/thin_rmap.cc b/thin-provisioning/thin_rmap.cc index 9083c6f..956fdf4 100644 --- a/thin-provisioning/thin_rmap.cc +++ b/thin-provisioning/thin_rmap.cc @@ -111,22 +111,30 @@ namespace { return region(begin, end); }; - - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options] {device|file}" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-V|--version}" << endl - << " {--region }*" << endl - << "Where:" << endl - << " is of the form .." << endl - << " for example 5..45 denotes blocks 5 to 44 inclusive, but not block 45" << endl; - } } //---------------------------------------------------------------- -int thin_rmap_main(int argc, char **argv) +thin_rmap_cmd::thin_rmap_cmd() + : command("thin_rmap") +{ +} + +void +thin_rmap_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-V|--version}" << endl + << " {--region }*" << endl + << "Where:" << endl + << " is of the form .." << endl + << " for example 5..45 denotes blocks 5 to 44 inclusive, but not block 45" << endl; +} + +int +thin_rmap_cmd::run(int argc, char **argv) { int c; vector regions; @@ -141,7 +149,7 @@ int thin_rmap_main(int argc, char **argv) while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch (c) { case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'V': @@ -161,20 +169,18 @@ int thin_rmap_main(int argc, char **argv) break; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; - usage(cerr, basename(argv[0])); + usage(cerr); exit(1); } return rmap(argv[optind], regions); } -base::command thin_provisioning::thin_rmap_cmd("thin_rmap", thin_rmap_main); - //---------------------------------------------------------------- diff --git a/thin-provisioning/thin_trim.cc b/thin-provisioning/thin_trim.cc index 19c48cd..35c4d9e 100644 --- a/thin-provisioning/thin_trim.cc +++ b/thin-provisioning/thin_trim.cc @@ -135,14 +135,6 @@ namespace { return 0; } - void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options] {device|file}\n" - << "Options:\n" - << " {--pool-inactive}\n" - << " {-h|--help}\n" - << " {-V|--version}" << endl; - } - struct flags { boost::optional metadata_dev; boost::optional data_dev; @@ -151,7 +143,23 @@ namespace { //---------------------------------------------------------------- -int thin_trim_main(int argc, char **argv) +thin_trim_cmd::thin_trim_cmd() + : command("thin_trim") +{ +} + +void +thin_trim_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}\n" + << "Options:\n" + << " {--pool-inactive}\n" + << " {-h|--help}\n" + << " {-V|--version}" << endl; +} + +int +thin_trim_cmd::run(int argc, char **argv) { int c; flags fs; @@ -177,7 +185,7 @@ int thin_trim_main(int argc, char **argv) break; case 'h': - usage(cout, basename(argv[0])); + usage(cout); return 0; case 'V': @@ -185,13 +193,13 @@ int thin_trim_main(int argc, char **argv) return 0; default: - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } } if (!fs.metadata_dev || !fs.data_dev) { - usage(cerr, basename(argv[0])); + usage(cerr); return 1; } From c3973c044ce90ad83f6ef9ba5a4fd035d420b6d3 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 12 Jan 2016 15:02:19 +0000 Subject: [PATCH 37/59] [thin_ls] First code drop. Output still needs formatting. More testing needed in dmtest. --- Makefile.in | 1 + bin/thin_ls | 1 + thin-provisioning/commands.cc | 2 +- thin-provisioning/thin_ls.cc | 298 ++++++++++++++++++++++++++++++++++ 4 files changed, 301 insertions(+), 1 deletion(-) create mode 120000 bin/thin_ls create mode 100644 thin-provisioning/thin_ls.cc diff --git a/Makefile.in b/Makefile.in index cbe9347..d10cac6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -86,6 +86,7 @@ SOURCE=\ thin-provisioning/thin_check.cc \ thin-provisioning/thin_delta.cc \ thin-provisioning/thin_dump.cc \ + thin-provisioning/thin_ls.cc \ thin-provisioning/thin_metadata_size.cc \ thin-provisioning/thin_pool.cc \ thin-provisioning/thin_repair.cc \ diff --git a/bin/thin_ls b/bin/thin_ls new file mode 120000 index 0000000..84c01e7 --- /dev/null +++ b/bin/thin_ls @@ -0,0 +1 @@ +pdata_tools \ No newline at end of file diff --git a/thin-provisioning/commands.cc b/thin-provisioning/commands.cc index cd51000..c25abce 100644 --- a/thin-provisioning/commands.cc +++ b/thin-provisioning/commands.cc @@ -11,7 +11,7 @@ thin_provisioning::register_thin_commands(base::application &app) app.add_cmd(command::ptr(new thin_check_cmd())); app.add_cmd(command::ptr(new thin_delta_cmd())); app.add_cmd(command::ptr(new thin_dump_cmd())); - //app.add_cmd(command::ptr(new thin_ls_cmd())); + app.add_cmd(command::ptr(new thin_ls_cmd())); app.add_cmd(command::ptr(new thin_metadata_size_cmd())); app.add_cmd(command::ptr(new thin_restore_cmd())); app.add_cmd(command::ptr(new thin_repair_cmd())); diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc new file mode 100644 index 0000000..1d57149 --- /dev/null +++ b/thin-provisioning/thin_ls.cc @@ -0,0 +1,298 @@ +// Copyright (C) 2015 Red Hat, Inc. All rights reserved. +// +// This file is part of the thin-provisioning-tools source. +// +// thin-provisioning-tools is free software: you can redistribute it +// and/or modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// thin-provisioning-tools is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with thin-provisioning-tools. If not, see +// . + +#include +#include +#include +#include + +#include "human_readable_format.h" +#include "metadata_dumper.h" +#include "metadata.h" +#include "xml_format.h" +#include "version.h" +#include "thin-provisioning/commands.h" +#include "persistent-data/file_utils.h" +#include "boost/optional.hpp" + +using namespace boost; +using namespace persistent_data; +using namespace std; +using namespace thin_provisioning; + + +//---------------------------------------------------------------- + +namespace { + class mapping_set { + public: + mapping_set(block_address nr_blocks) + : bits_(nr_blocks * 2, false) { + } + + enum block_state { + UNMAPPED, + EXCLUSIVE, + SHARED + }; + + void inc(block_address b) { + if (bits_[b * 2]) + bits_[b * 2 + 1] = true; // shared + else + bits_[b * 2] = true; // exclusive + } + + block_state get_state(block_address b) const { + if (bits_[b * 2]) { + if (bits_[b * 2 + 1]) + return SHARED; + else + return EXCLUSIVE; + } else + return UNMAPPED; + } + + private: + vector bits_; + }; + + //------------------------------------------------ + + struct flags { + flags() + : use_metadata_snap(false) { + } + + bool use_metadata_snap; + }; + + class mapping_pass1 : public mapping_tree_detail::mapping_visitor { + public: + mapping_pass1(mapping_set &mappings) + : mappings_(mappings) { + } + + virtual void visit(btree_path const &path, mapping_tree_detail::block_time const &bt) { + mappings_.inc(bt.block_); + } + + private: + mapping_set &mappings_; + }; + + class mapping_pass2 : public mapping_tree_detail::mapping_visitor { + public: + mapping_pass2(mapping_set const &mappings) + : mappings_(mappings), + exclusives_(0) { + } + + virtual void visit(btree_path const &path, mapping_tree_detail::block_time const &bt) { + if (mappings_.get_state(bt.block_) == mapping_set::EXCLUSIVE) + exclusives_++; + } + + block_address get_exclusives() const { + return exclusives_; + } + + private: + mapping_set const &mappings_; + block_address exclusives_; + }; + + void raise_metadata_damage() { + throw std::runtime_error("metadata contains errors (run thin_check for details)."); + } + + class fatal_mapping_damage : public mapping_tree_detail::damage_visitor { + public: + virtual void visit(mapping_tree_detail::missing_devices const &d) { + raise_metadata_damage(); + } + + virtual void visit(mapping_tree_detail::missing_mappings const &d) { + raise_metadata_damage(); + } + }; + + void pass1(metadata::ptr md, mapping_set &mappings, uint64_t dev_id) { + dev_tree::key k = {dev_id}; + optional dev_root = md->mappings_top_level_->lookup(k); + + if (!dev_root) + throw runtime_error("couldn't find mapping tree root"); + + single_mapping_tree dev_mappings(*md->tm_, *dev_root, + mapping_tree_detail::block_traits::ref_counter(md->tm_->get_sm())); + + mapping_pass1 pass1(mappings); + fatal_mapping_damage dv; + walk_mapping_tree(dev_mappings, pass1, dv); + } + + + block_address count_exclusives(metadata::ptr md, mapping_set const &mappings, uint64_t dev_id) { + dev_tree::key k = {dev_id}; + optional dev_root = md->mappings_top_level_->lookup(k); + + if (!dev_root) + throw runtime_error("couldn't find mapping tree root"); + + single_mapping_tree dev_mappings(*md->tm_, *dev_root, + mapping_tree_detail::block_traits::ref_counter(md->tm_->get_sm())); + + mapping_pass2 pass2(mappings); + fatal_mapping_damage dv; + walk_mapping_tree(dev_mappings, pass2, dv); + return pass2.get_exclusives(); + } + + //------------------------------------------------ + + typedef map dd_map; + + class details_extractor : public device_tree_detail::device_visitor { + public: + void visit(block_address dev_id, device_tree_detail::device_details const &dd) { + dd_.insert(make_pair(dev_id, dd)); + } + + dd_map const &get_details() const { + return dd_; + } + + private: + dd_map dd_; + }; + + struct fatal_details_damage : public device_tree_detail::damage_visitor { + void visit(device_tree_detail::missing_devices const &d) { + raise_metadata_damage(); + } + }; + + device_tree_detail::damage_visitor::ptr details_damage_policy() { + typedef device_tree_detail::damage_visitor::ptr dvp; + return dvp(new fatal_details_damage()); + } + + //------------------------------------------------ + + int ls_(string const &path, ostream &out, struct flags &flags) { + try { + block_manager<>::ptr bm(open_bm(path, block_manager<>::READ_ONLY)); + metadata::ptr md(new metadata(bm)); + + details_extractor de; + device_tree_detail::damage_visitor::ptr dd_policy(details_damage_policy()); + walk_device_tree(*md->details_, de, *dd_policy); + + mapping_set mappings(md->data_sm_->get_nr_blocks()); + + dd_map const &map = de.get_details(); + dd_map::const_iterator it; + for (it = map.begin(); it != map.end(); ++it) + pass1(md, mappings, it->first); + + for (it = map.begin(); it != map.end(); ++it) { + block_address exclusive = count_exclusives(md, mappings, it->first); + + out << it->first << ": " + << it->second.mapped_blocks_ << " mapped blocks, " + << exclusive << " exclusive blocks\n"; + } + + } catch (std::exception &e) { + cerr << e.what() << endl; + return 1; + } + + return 0; + } + + int ls(string const &path, struct flags &flags) { + return ls_(path, cout, flags); + } + + void usage(ostream &out, string const &cmd) { + } +} + +//---------------------------------------------------------------- + +thin_ls_cmd::thin_ls_cmd() + : command("thin_ls") +{ +} + +void +thin_ls_cmd::usage(std::ostream &out) const +{ + out << "Usage: " << get_name() << " [options] {device|file}" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-m|--metadata-snap}" << endl + << " {-V|--version}" << endl; +} + +int +thin_ls_cmd::run(int argc, char **argv) +{ + int c; + struct flags flags; + const char shortopts[] = "hm::V"; + + const struct option longopts[] = { + { "help", no_argument, NULL, 'h'}, + { "metadata-snap", no_argument, NULL, 'm' }, + { "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; + + case 'm': + flags.use_metadata_snap = true; + break; + + case 'V': + cout << THIN_PROVISIONING_TOOLS_VERSION << endl; + return 0; + + default: + usage(cerr); + return 1; + } + } + + if (argc == optind) { + cerr << "No input file provided." << endl; + usage(cerr); + return 1; + } + + return ls(argv[optind], flags); +} + +//---------------------------------------------------------------- From 47bd31da8d52f8aff57ab1b93cd173a609ff7f6e Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 11:16:25 +0000 Subject: [PATCH 38/59] [thin_ls] more work on thin_ls --- thin-provisioning/thin_ls.cc | 340 ++++++++++++++++++++++++++++++++--- 1 file changed, 315 insertions(+), 25 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 1d57149..56e80fb 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -29,6 +29,7 @@ #include "thin-provisioning/commands.h" #include "persistent-data/file_utils.h" #include "boost/optional.hpp" +#include "boost/lexical_cast.hpp" using namespace boost; using namespace persistent_data; @@ -39,6 +40,156 @@ using namespace thin_provisioning; //---------------------------------------------------------------- namespace { + + enum disk_unit { + UNIT_BYTE, + UNIT_SECTOR, + + // decimal multipliers + UNIT_kB, + UNIT_MB, + UNIT_GB, + UNIT_TB, + UNIT_PB, + + // binary mulitpliers + UNIT_KiB, + UNIT_MiB, + UNIT_GiB, + UNIT_TiB, + UNIT_PiB + }; + + unsigned long long disk_unit_multiplier(disk_unit u) { + switch (u) { + case UNIT_BYTE: + return 1; + + case UNIT_SECTOR: + return 512; + + case UNIT_kB: + return 1000; + + case UNIT_MB: + return 1000000; + + case UNIT_GB: + return 1000000000ull; + + case UNIT_TB: + return 1000000000000ull; + + case UNIT_PB: + return 1000000000000000ull; + + case UNIT_KiB: + return 1024ull; + + case UNIT_MiB: + return 1024ull * 1024ull; + + case UNIT_GiB: + return 1024ull * 1024ull * 1024ull; + + case UNIT_TiB: + return 1024ull * 1024ull * 1024ull * 1024ull; + + case UNIT_PiB: + return 1024ull * 1024ull * 1024ull * 1024ull * 1024ull; + } + + throw runtime_error("unknown unit type"); + return 1; + } + + string format_disk_unit(unsigned long long numerator, disk_unit u) { + numerator *= disk_unit_multiplier(u); + unsigned i; + for (i = 0; numerator >= 1024; i++) + numerator /= 1024; + + char const *extensions[] = { + "", "KiB", "MiB", "GiB", "TiB", "PiB" + }; + + // FIXME: check subscript of i + return lexical_cast(numerator) + " " + extensions[i]; + } + + //------------------------------------------------ + + // FIXME: move to own file + class grid_layout { + public: + typedef list row; + typedef list grid; + + grid_layout() + : nr_fields_(0) { + new_row(); + } + + void render(ostream &out) { + vector widths; + calc_field_widths(widths); + + grid::const_iterator row; + for (row = grid_.begin(); row != grid_.end(); ++row) { + row::const_iterator col; + unsigned i; + for (col = row->begin(), i = 0; col != row->end(); ++col, ++i) + out << justify(widths[i], *col) << " "; + out << "\n"; + } + } + + void new_row() { + grid_.push_back(row()); + } + + template + void field(T const &t) { + push_field(lexical_cast(t)); + } + + private: + row ¤t_row() { + return grid_.back(); + } + + void push_field(string const &s) { + current_row().push_back(s); + nr_fields_ = max(nr_fields_, current_row().size()); + } + + void calc_field_widths(vector &widths) const { + widths.resize(nr_fields_, 0); + + grid::const_iterator row; + for (row = grid_.begin(); row != grid_.end(); ++row) { + row::const_iterator col; + unsigned i; + for (col = row->begin(), i = 0; col != row->end(); ++col, ++i) + widths[i] = max(widths[i], col->length()); + } + } + + string justify(unsigned width, string const &txt) const { + if (txt.length() > width) + throw runtime_error("string field too long, internal error"); + + string result(width - txt.length(), ' '); + result += txt; + return result; + } + + grid grid_; + unsigned nr_fields_; + }; + + //------------------------------------------------ + class mapping_set { public: mapping_set(block_address nr_blocks) @@ -74,14 +225,86 @@ namespace { //------------------------------------------------ + enum output_field { + DEV_ID, + MAPPED_BLOCKS, + MAPPED_EXCL_BLOCKS, + MAPPED_SHARED_BLOCKS, + MAPPED, + EXCLUSIVE, + SHARED, + TRANSACTION_ID, + CREATION_TIME, + SNAPSHOT_TIME + }; + + string header(output_field const &f) { + switch (f) { + case DEV_ID: + return "DEV"; + + case MAPPED_BLOCKS: + return "BLOCKS"; + + case MAPPED_EXCL_BLOCKS: + return "BLOCKS_EXCL"; + + case MAPPED_SHARED_BLOCKS: + return "BLOCKS_SHARED"; + + case MAPPED: + return "MAPPED"; + + case EXCLUSIVE: + return "EXCLUSIVE"; + + case SHARED: + return "SHARED"; + + case TRANSACTION_ID: + return "TRANSACTION"; + + case CREATION_TIME: + return "CREATION"; + + case SNAPSHOT_TIME: + return "SNAPSHOT"; + } + + return ""; + } + + void print_headers(grid_layout &out, vector const &fields) { + vector::const_iterator it; + for (it = fields.begin(); it != fields.end(); ++it) + out.field(header(*it)); + + out.new_row(); + } + + struct flags { flags() : use_metadata_snap(false) { + + fields.push_back(DEV_ID); + fields.push_back(MAPPED_BLOCKS); + fields.push_back(MAPPED_EXCL_BLOCKS); + fields.push_back(MAPPED_SHARED_BLOCKS); + fields.push_back(MAPPED); + fields.push_back(EXCLUSIVE); + fields.push_back(SHARED); + fields.push_back(TRANSACTION_ID); + fields.push_back(CREATION_TIME); + fields.push_back(SNAPSHOT_TIME); } bool use_metadata_snap; + vector fields; }; + //------------------------------------------------ + class mapping_pass1 : public mapping_tree_detail::mapping_visitor { public: mapping_pass1(mapping_set &mappings) @@ -195,29 +418,103 @@ namespace { //------------------------------------------------ - int ls_(string const &path, ostream &out, struct flags &flags) { - try { - block_manager<>::ptr bm(open_bm(path, block_manager<>::READ_ONLY)); - metadata::ptr md(new metadata(bm)); + void ls_(string const &path, ostream &out, struct flags &flags) { + grid_layout grid; - details_extractor de; - device_tree_detail::damage_visitor::ptr dd_policy(details_damage_policy()); - walk_device_tree(*md->details_, de, *dd_policy); + block_manager<>::ptr bm(open_bm(path, block_manager<>::READ_ONLY)); + metadata::ptr md; - mapping_set mappings(md->data_sm_->get_nr_blocks()); + if (flags.use_metadata_snap) + md.reset(new metadata(bm, optional())); + else + md.reset(new metadata(bm)); - dd_map const &map = de.get_details(); - dd_map::const_iterator it; - for (it = map.begin(); it != map.end(); ++it) - pass1(md, mappings, it->first); + details_extractor de; + device_tree_detail::damage_visitor::ptr dd_policy(details_damage_policy()); + walk_device_tree(*md->details_, de, *dd_policy); - for (it = map.begin(); it != map.end(); ++it) { - block_address exclusive = count_exclusives(md, mappings, it->first); + mapping_set mappings(md->data_sm_->get_nr_blocks()); - out << it->first << ": " - << it->second.mapped_blocks_ << " mapped blocks, " - << exclusive << " exclusive blocks\n"; + dd_map const &map = de.get_details(); + dd_map::const_iterator it; + for (it = map.begin(); it != map.end(); ++it) + pass1(md, mappings, it->first); + + print_headers(grid, flags.fields); + + for (it = map.begin(); it != map.end(); ++it) { + vector::const_iterator f; + + optional exclusive; + + for (f = flags.fields.begin(); f != flags.fields.end(); ++f) { + switch (*f) { + case DEV_ID: + grid.field(it->first); + break; + + case MAPPED_BLOCKS: + grid.field(it->second.mapped_blocks_); + break; + + case MAPPED_EXCL_BLOCKS: + if (!exclusive) + exclusive = count_exclusives(md, mappings, it->first); + grid.field(*exclusive); + break; + + case MAPPED_SHARED_BLOCKS: + if (!exclusive) + exclusive = count_exclusives(md, mappings, it->first); + grid.field(it->second.mapped_blocks_ - *exclusive); + break; + + case MAPPED: + grid.field( + format_disk_unit(it->second.mapped_blocks_ * + md->sb_.data_block_size_, UNIT_SECTOR)); + break; + + case EXCLUSIVE: + if (!exclusive) + exclusive = count_exclusives(md, mappings, it->first); + + grid.field( + format_disk_unit(*exclusive * md->sb_.data_block_size_, + UNIT_SECTOR)); + break; + + case SHARED: + if (!exclusive) + exclusive = count_exclusives(md, mappings, it->first); + + grid.field( + format_disk_unit((it->second.mapped_blocks_ - *exclusive) * + md->sb_.data_block_size_, UNIT_SECTOR)); + break; + + + case TRANSACTION_ID: + grid.field(it->second.transaction_id_); + break; + + case CREATION_TIME: + grid.field(it->second.creation_time_); + break; + + case SNAPSHOT_TIME: + grid.field(it->second.snapshotted_time_); + } } + grid.new_row(); + } + + grid.render(out); + } + + int ls(string const &path, ostream &out, struct flags &flags) { + try { + ls_(path, out, flags); } catch (std::exception &e) { cerr << e.what() << endl; @@ -226,13 +523,6 @@ namespace { return 0; } - - int ls(string const &path, struct flags &flags) { - return ls_(path, cout, flags); - } - - void usage(ostream &out, string const &cmd) { - } } //---------------------------------------------------------------- @@ -292,7 +582,7 @@ thin_ls_cmd::run(int argc, char **argv) return 1; } - return ls(argv[optind], flags); + return ls(argv[optind], cout, flags); } //---------------------------------------------------------------- From 7ce4e451ffebb1ad155beb8a387d6ac88eebe980 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 11:40:00 +0000 Subject: [PATCH 39/59] [base, thin_ls] factor out disk_units code --- Makefile.in | 1 + base/disk_units.cc | 72 ++++++++++++++++++++++++++++++ base/disk_units.h | 34 ++++++++++++++ thin-provisioning/thin_ls.cc | 86 +++--------------------------------- 4 files changed, 113 insertions(+), 80 deletions(-) create mode 100644 base/disk_units.cc create mode 100644 base/disk_units.h diff --git a/Makefile.in b/Makefile.in index d10cac6..0b47826 100644 --- a/Makefile.in +++ b/Makefile.in @@ -27,6 +27,7 @@ all: $(PROGRAMS) SOURCE=\ base/application.cc \ base/base64.cc \ + base/disk_units.cc \ base/endian_utils.cc \ base/error_state.cc \ base/error_string.cc \ diff --git a/base/disk_units.cc b/base/disk_units.cc new file mode 100644 index 0000000..b3e0244 --- /dev/null +++ b/base/disk_units.cc @@ -0,0 +1,72 @@ +#include "base/disk_units.h" + +#include +#include + +using namespace std; +using namespace boost; + +//---------------------------------------------------------------- + +unsigned long long +base::disk_unit_multiplier(disk_unit u) +{ + switch (u) { + case UNIT_BYTE: + return 1; + + case UNIT_SECTOR: + return 512; + + case UNIT_kB: + return 1000; + + case UNIT_MB: + return 1000000; + + case UNIT_GB: + return 1000000000ull; + + case UNIT_TB: + return 1000000000000ull; + + case UNIT_PB: + return 1000000000000000ull; + + case UNIT_KiB: + return 1024ull; + + case UNIT_MiB: + return 1024ull * 1024ull; + + case UNIT_GiB: + return 1024ull * 1024ull * 1024ull; + + case UNIT_TiB: + return 1024ull * 1024ull * 1024ull * 1024ull; + + case UNIT_PiB: + return 1024ull * 1024ull * 1024ull * 1024ull * 1024ull; + } + + throw runtime_error("unknown unit type"); + return 1; +} + +string +base::format_disk_unit(unsigned long long numerator, disk_unit u) +{ + numerator *= disk_unit_multiplier(u); + unsigned i; + for (i = 0; numerator >= 1024; i++) + numerator /= 1024; + + char const *extensions[] = { + "", "KiB", "MiB", "GiB", "TiB", "PiB" + }; + + // FIXME: check subscript of i + return lexical_cast(numerator) + " " + extensions[i]; +} + +//---------------------------------------------------------------- diff --git a/base/disk_units.h b/base/disk_units.h new file mode 100644 index 0000000..b29d0ca --- /dev/null +++ b/base/disk_units.h @@ -0,0 +1,34 @@ +#ifndef BASE_DISK_UNITS_H +#define BASE_DISK_UNITS_H + +#include + +//---------------------------------------------------------------- + +namespace base { + enum disk_unit { + UNIT_BYTE, + UNIT_SECTOR, + + // decimal multipliers + UNIT_kB, + UNIT_MB, + UNIT_GB, + UNIT_TB, + UNIT_PB, + + // binary multipliers + UNIT_KiB, + UNIT_MiB, + UNIT_GiB, + UNIT_TiB, + UNIT_PiB + }; + + unsigned long long disk_unit_multiplier(disk_unit u); + std::string format_disk_unit(unsigned long long numerator, disk_unit u); +} + +//---------------------------------------------------------------- + +#endif diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 56e80fb..31f5e65 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -21,16 +21,18 @@ #include #include -#include "human_readable_format.h" -#include "metadata_dumper.h" -#include "metadata.h" -#include "xml_format.h" +#include "base/disk_units.h" +#include "thin-provisioning/human_readable_format.h" +#include "thin-provisioning/metadata_dumper.h" +#include "thin-provisioning/metadata.h" +#include "thin-provisioning/xml_format.h" #include "version.h" #include "thin-provisioning/commands.h" #include "persistent-data/file_utils.h" #include "boost/optional.hpp" #include "boost/lexical_cast.hpp" +using namespace base; using namespace boost; using namespace persistent_data; using namespace std; @@ -41,82 +43,6 @@ using namespace thin_provisioning; namespace { - enum disk_unit { - UNIT_BYTE, - UNIT_SECTOR, - - // decimal multipliers - UNIT_kB, - UNIT_MB, - UNIT_GB, - UNIT_TB, - UNIT_PB, - - // binary mulitpliers - UNIT_KiB, - UNIT_MiB, - UNIT_GiB, - UNIT_TiB, - UNIT_PiB - }; - - unsigned long long disk_unit_multiplier(disk_unit u) { - switch (u) { - case UNIT_BYTE: - return 1; - - case UNIT_SECTOR: - return 512; - - case UNIT_kB: - return 1000; - - case UNIT_MB: - return 1000000; - - case UNIT_GB: - return 1000000000ull; - - case UNIT_TB: - return 1000000000000ull; - - case UNIT_PB: - return 1000000000000000ull; - - case UNIT_KiB: - return 1024ull; - - case UNIT_MiB: - return 1024ull * 1024ull; - - case UNIT_GiB: - return 1024ull * 1024ull * 1024ull; - - case UNIT_TiB: - return 1024ull * 1024ull * 1024ull * 1024ull; - - case UNIT_PiB: - return 1024ull * 1024ull * 1024ull * 1024ull * 1024ull; - } - - throw runtime_error("unknown unit type"); - return 1; - } - - string format_disk_unit(unsigned long long numerator, disk_unit u) { - numerator *= disk_unit_multiplier(u); - unsigned i; - for (i = 0; numerator >= 1024; i++) - numerator /= 1024; - - char const *extensions[] = { - "", "KiB", "MiB", "GiB", "TiB", "PiB" - }; - - // FIXME: check subscript of i - return lexical_cast(numerator) + " " + extensions[i]; - } - //------------------------------------------------ // FIXME: move to own file From 208fdd86e6989696742afa0158a05a0fda29aa10 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 13:40:36 +0000 Subject: [PATCH 40/59] [thin_ls] add support for --format --- thin-provisioning/thin_ls.cc | 71 ++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 31f5e65..1dc4b90 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -42,9 +42,6 @@ using namespace thin_provisioning; //---------------------------------------------------------------- namespace { - - //------------------------------------------------ - // FIXME: move to own file class grid_layout { public: @@ -419,7 +416,6 @@ namespace { md->sb_.data_block_size_, UNIT_SECTOR)); break; - case TRANSACTION_ID: grid.field(it->second.transaction_id_); break; @@ -462,10 +458,64 @@ void thin_ls_cmd::usage(std::ostream &out) const { out << "Usage: " << get_name() << " [options] {device|file}" << endl - << "Options:" << endl - << " {-h|--help}" << endl - << " {-m|--metadata-snap}" << endl - << " {-V|--version}" << endl; + << "Options:\n" + << " {-h|--help}\n" + << " {-m|--metadata-snap}\n" + << " {-o|--format }\n" + << " {-V|--version}\n\n" + << "where is a comma separated list from:\n" + << " DEV_ID, MAPPED_BLOCKS, MAPPED_EXCL_BLOCKS, MAPPED_SHARED_BLOCKS,\n" + << " MAPPED, EXCLUSIVE, SHARED, TRANSACTION_ID, CREATION_TIME,\n" + << " SNAPSHOT_TIME" + << endl; +} + + + +vector parse_fields(string const &str) { + vector fields; + vector tokens; + + stringstream in(str); + string item; + + while (getline(in, item, ',')) + tokens.push_back(item); + + vector::const_iterator tok; + for (tok = tokens.begin(); tok != tokens.end(); ++tok) { + if (*tok == "DEV_ID") + fields.push_back(DEV_ID); + + else if (*tok == "MAPPED_BLOCKS") + fields.push_back(MAPPED_BLOCKS); + + else if (*tok == "MAPPED_EXCL_BLOCKS") + fields.push_back(MAPPED_EXCL_BLOCKS); + + else if (*tok == "MAPPED_SHARED_BLOCKS") + fields.push_back(MAPPED_SHARED_BLOCKS); + + else if (*tok == "MAPPED") + fields.push_back(MAPPED); + + else if (*tok == "EXCLUSIVE") + fields.push_back(EXCLUSIVE); + + else if (*tok == "SHARED") + fields.push_back(SHARED); + + else if (*tok == "TRANSACTION_ID") + fields.push_back(TRANSACTION_ID); + + else if (*tok == "CREATION_TIME") + fields.push_back(CREATION_TIME); + + else if (*tok == "SNAPSHOT_TIME") + fields.push_back(SNAPSHOT_TIME); + } + + return fields; } int @@ -479,6 +529,7 @@ thin_ls_cmd::run(int argc, char **argv) { "help", no_argument, NULL, 'h'}, { "metadata-snap", no_argument, NULL, 'm' }, { "version", no_argument, NULL, 'V'}, + { "format", required_argument, NULL, 'o' }, { NULL, no_argument, NULL, 0 } }; @@ -492,6 +543,10 @@ thin_ls_cmd::run(int argc, char **argv) flags.use_metadata_snap = true; break; + case 'o': + flags.fields = parse_fields(optarg); + break; + case 'V': cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; From d65bf29eb79baad47340d96a5f9eea14df7e9660 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 13:54:15 +0000 Subject: [PATCH 41/59] [thin_ls] change default fields --- thin-provisioning/thin_ls.cc | 79 +++++++++++++++++------------------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 1dc4b90..fcfef1e 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -161,6 +161,41 @@ namespace { SNAPSHOT_TIME }; + output_field string_to_field(string const &str) { + if (str == "DEV_ID") + return DEV_ID; + + else if (str == "MAPPED_BLOCKS") + return MAPPED_BLOCKS; + + else if (str == "MAPPED_EXCL_BLOCKS") + return MAPPED_EXCL_BLOCKS; + + else if (str == "MAPPED_SHARED_BLOCKS") + return MAPPED_SHARED_BLOCKS; + + else if (str == "MAPPED") + return MAPPED; + + else if (str == "EXCLUSIVE") + return EXCLUSIVE; + + else if (str == "SHARED") + return SHARED; + + else if (str == "TRANSACTION_ID") + return TRANSACTION_ID; + + else if (str == "CREATION_TIME") + return CREATION_TIME; + + else if (str == "SNAPSHOT_TIME") + return SNAPSHOT_TIME; + + throw runtime_error("unknown field"); + return DEV_ID; + } + string header(output_field const &f) { switch (f) { case DEV_ID: @@ -211,13 +246,9 @@ namespace { : use_metadata_snap(false) { fields.push_back(DEV_ID); - fields.push_back(MAPPED_BLOCKS); - fields.push_back(MAPPED_EXCL_BLOCKS); - fields.push_back(MAPPED_SHARED_BLOCKS); fields.push_back(MAPPED); fields.push_back(EXCLUSIVE); fields.push_back(SHARED); - fields.push_back(TRANSACTION_ID); fields.push_back(CREATION_TIME); fields.push_back(SNAPSHOT_TIME); } @@ -472,48 +503,14 @@ thin_ls_cmd::usage(std::ostream &out) const -vector parse_fields(string const &str) { +vector parse_fields(string const &str) +{ vector fields; - vector tokens; - stringstream in(str); string item; while (getline(in, item, ',')) - tokens.push_back(item); - - vector::const_iterator tok; - for (tok = tokens.begin(); tok != tokens.end(); ++tok) { - if (*tok == "DEV_ID") - fields.push_back(DEV_ID); - - else if (*tok == "MAPPED_BLOCKS") - fields.push_back(MAPPED_BLOCKS); - - else if (*tok == "MAPPED_EXCL_BLOCKS") - fields.push_back(MAPPED_EXCL_BLOCKS); - - else if (*tok == "MAPPED_SHARED_BLOCKS") - fields.push_back(MAPPED_SHARED_BLOCKS); - - else if (*tok == "MAPPED") - fields.push_back(MAPPED); - - else if (*tok == "EXCLUSIVE") - fields.push_back(EXCLUSIVE); - - else if (*tok == "SHARED") - fields.push_back(SHARED); - - else if (*tok == "TRANSACTION_ID") - fields.push_back(TRANSACTION_ID); - - else if (*tok == "CREATION_TIME") - fields.push_back(CREATION_TIME); - - else if (*tok == "SNAPSHOT_TIME") - fields.push_back(SNAPSHOT_TIME); - } + fields.push_back(string_to_field(item)); return fields; } From c5a1a814f3f4d8fbfc0d0fe396c4fc757b2bf393 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 14:11:31 +0000 Subject: [PATCH 42/59] [thin_ls] rationalise the field names by using a static array of names --- thin-provisioning/thin_ls.cc | 97 ++++++++++-------------------------- 1 file changed, 26 insertions(+), 71 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index fcfef1e..2e8071d 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -22,15 +22,16 @@ #include #include "base/disk_units.h" +#include "boost/lexical_cast.hpp" +#include "boost/optional.hpp" +#include "boost/range.hpp" +#include "persistent-data/file_utils.h" +#include "thin-provisioning/commands.h" #include "thin-provisioning/human_readable_format.h" -#include "thin-provisioning/metadata_dumper.h" #include "thin-provisioning/metadata.h" +#include "thin-provisioning/metadata_dumper.h" #include "thin-provisioning/xml_format.h" #include "version.h" -#include "thin-provisioning/commands.h" -#include "persistent-data/file_utils.h" -#include "boost/optional.hpp" -#include "boost/lexical_cast.hpp" using namespace base; using namespace boost; @@ -161,85 +162,41 @@ namespace { SNAPSHOT_TIME }; + char const *field_names[] = { + "DEV", + "MAPPED_BLOCKS", + "MAPPED_EXCL_BLOCKS", + "MAPPED_SHARED_BLOCKS", + "MAPPED", + "EXCLUSIVE", + "SHARED", + "TRANSACTION_ID", + "CREATION_TIME", + "SNAPSHOT_TIME" + }; + output_field string_to_field(string const &str) { - if (str == "DEV_ID") - return DEV_ID; - - else if (str == "MAPPED_BLOCKS") - return MAPPED_BLOCKS; - - else if (str == "MAPPED_EXCL_BLOCKS") - return MAPPED_EXCL_BLOCKS; - - else if (str == "MAPPED_SHARED_BLOCKS") - return MAPPED_SHARED_BLOCKS; - - else if (str == "MAPPED") - return MAPPED; - - else if (str == "EXCLUSIVE") - return EXCLUSIVE; - - else if (str == "SHARED") - return SHARED; - - else if (str == "TRANSACTION_ID") - return TRANSACTION_ID; - - else if (str == "CREATION_TIME") - return CREATION_TIME; - - else if (str == "SNAPSHOT_TIME") - return SNAPSHOT_TIME; + for (unsigned i = 0; i < size(field_names); i++) + if (str == field_names[i]) + return static_cast(i); throw runtime_error("unknown field"); return DEV_ID; } - string header(output_field const &f) { - switch (f) { - case DEV_ID: - return "DEV"; - - case MAPPED_BLOCKS: - return "BLOCKS"; - - case MAPPED_EXCL_BLOCKS: - return "BLOCKS_EXCL"; - - case MAPPED_SHARED_BLOCKS: - return "BLOCKS_SHARED"; - - case MAPPED: - return "MAPPED"; - - case EXCLUSIVE: - return "EXCLUSIVE"; - - case SHARED: - return "SHARED"; - - case TRANSACTION_ID: - return "TRANSACTION"; - - case CREATION_TIME: - return "CREATION"; - - case SNAPSHOT_TIME: - return "SNAPSHOT"; - } - - return ""; + string field_to_string(output_field const &f) { + return field_names[static_cast(f)]; } void print_headers(grid_layout &out, vector const &fields) { vector::const_iterator it; for (it = fields.begin(); it != fields.end(); ++it) - out.field(header(*it)); + out.field(field_to_string(*it)); out.new_row(); } + //------------------------------------------------ struct flags { flags() @@ -501,8 +458,6 @@ thin_ls_cmd::usage(std::ostream &out) const << endl; } - - vector parse_fields(string const &str) { vector fields; From 87d8d630f680e004a08ecdbf11b54e97ff24c897 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 14:16:02 +0000 Subject: [PATCH 43/59] [thin_ls] more tidying --- thin-provisioning/thin_ls.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 2e8071d..f03c312 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -159,7 +159,7 @@ namespace { SHARED, TRANSACTION_ID, CREATION_TIME, - SNAPSHOT_TIME + SNAPSHOT_TIME // make sure this is always the last one }; char const *field_names[] = { @@ -445,17 +445,17 @@ thin_ls_cmd::thin_ls_cmd() void thin_ls_cmd::usage(std::ostream &out) const { - out << "Usage: " << get_name() << " [options] {device|file}" << endl + out << "Usage: " << get_name() << " [options] {device|file}\n" << "Options:\n" << " {-h|--help}\n" << " {-m|--metadata-snap}\n" << " {-o|--format }\n" << " {-V|--version}\n\n" - << "where is a comma separated list from:\n" - << " DEV_ID, MAPPED_BLOCKS, MAPPED_EXCL_BLOCKS, MAPPED_SHARED_BLOCKS,\n" - << " MAPPED, EXCLUSIVE, SHARED, TRANSACTION_ID, CREATION_TIME,\n" - << " SNAPSHOT_TIME" - << endl; + << "where is a comma separated list from:\n"; + + for (unsigned i = 0; i <= static_cast(SNAPSHOT_TIME); i++) { + out << " " << field_to_string(static_cast(i)) << "\n"; + } } vector parse_fields(string const &str) From 3dd45e1ceb243cb902ac807d28cd44d08e633116 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 14:30:13 +0000 Subject: [PATCH 44/59] [thin_ls] tweak the field names --- thin-provisioning/thin_ls.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index f03c312..b7db4f1 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -170,9 +170,9 @@ namespace { "MAPPED", "EXCLUSIVE", "SHARED", - "TRANSACTION_ID", - "CREATION_TIME", - "SNAPSHOT_TIME" + "TRANSACTION", + "CREATE_TIME", + "SNAP_TIME" }; output_field string_to_field(string const &str) { From 8030a98bd8a6904489fd3edb4a5ed2088bb6832b Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 14:43:37 +0000 Subject: [PATCH 45/59] [thin_ls] add MAPPED_SECTORS, EXCLUSIVE_SECTORS, SHARED_SECTORS --- thin-provisioning/thin_ls.cc | 40 ++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index b7db4f1..881d58b 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -154,6 +154,11 @@ namespace { MAPPED_BLOCKS, MAPPED_EXCL_BLOCKS, MAPPED_SHARED_BLOCKS, + + MAPPED_SECTORS, + EXCLUSIVE_SECTORS, + SHARED_SECTORS, + MAPPED, EXCLUSIVE, SHARED, @@ -167,9 +172,15 @@ namespace { "MAPPED_BLOCKS", "MAPPED_EXCL_BLOCKS", "MAPPED_SHARED_BLOCKS", + + "MAPPED_SECTORS", + "EXCLUSIVE_SECTORS", + "SHARED_SECTORS", + "MAPPED", "EXCLUSIVE", "SHARED", + "TRANSACTION", "CREATE_TIME", "SNAP_TIME" @@ -204,8 +215,6 @@ namespace { fields.push_back(DEV_ID); fields.push_back(MAPPED); - fields.push_back(EXCLUSIVE); - fields.push_back(SHARED); fields.push_back(CREATION_TIME); fields.push_back(SNAPSHOT_TIME); } @@ -340,6 +349,8 @@ namespace { else md.reset(new metadata(bm)); + block_address block_size = md->sb_.data_block_size_; + details_extractor de; device_tree_detail::damage_visitor::ptr dd_policy(details_damage_policy()); walk_device_tree(*md->details_, de, *dd_policy); @@ -380,10 +391,27 @@ namespace { grid.field(it->second.mapped_blocks_ - *exclusive); break; + case MAPPED_SECTORS: + grid.field(it->second.mapped_blocks_ * block_size); + break; + + case EXCLUSIVE_SECTORS: + if (!exclusive) + exclusive = count_exclusives(md, mappings, it->first); + grid.field(*exclusive * block_size); + break; + + case SHARED_SECTORS: + if (!exclusive) + exclusive = count_exclusives(md, mappings, it->first); + grid.field((it->second.mapped_blocks_ - *exclusive) * block_size); + break; + + case MAPPED: grid.field( - format_disk_unit(it->second.mapped_blocks_ * - md->sb_.data_block_size_, UNIT_SECTOR)); + format_disk_unit(it->second.mapped_blocks_ * block_size, + UNIT_SECTOR)); break; case EXCLUSIVE: @@ -391,7 +419,7 @@ namespace { exclusive = count_exclusives(md, mappings, it->first); grid.field( - format_disk_unit(*exclusive * md->sb_.data_block_size_, + format_disk_unit(*exclusive * block_size, UNIT_SECTOR)); break; @@ -401,7 +429,7 @@ namespace { grid.field( format_disk_unit((it->second.mapped_blocks_ - *exclusive) * - md->sb_.data_block_size_, UNIT_SECTOR)); + block_size, UNIT_SECTOR)); break; case TRANSACTION_ID: From 070b7e6fe196c6da4c625bdee08f3062c150bbde Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 14:44:06 +0000 Subject: [PATCH 46/59] [disk_units] Don't put a space between numerator and unit --- base/disk_units.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/disk_units.cc b/base/disk_units.cc index b3e0244..8e5faf1 100644 --- a/base/disk_units.cc +++ b/base/disk_units.cc @@ -66,7 +66,7 @@ base::format_disk_unit(unsigned long long numerator, disk_unit u) }; // FIXME: check subscript of i - return lexical_cast(numerator) + " " + extensions[i]; + return lexical_cast(numerator) + extensions[i]; } //---------------------------------------------------------------- From f6f38fbc1f01819e112caa451664b95a27755c4f Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 14:50:04 +0000 Subject: [PATCH 47/59] [thin_ls] tweak enum names --- thin-provisioning/thin_ls.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 881d58b..4ceb3d0 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -152,8 +152,8 @@ namespace { enum output_field { DEV_ID, MAPPED_BLOCKS, - MAPPED_EXCL_BLOCKS, - MAPPED_SHARED_BLOCKS, + EXCLUSIVE_BLOCKS, + SHARED_BLOCKS, MAPPED_SECTORS, EXCLUSIVE_SECTORS, @@ -162,6 +162,7 @@ namespace { MAPPED, EXCLUSIVE, SHARED, + TRANSACTION_ID, CREATION_TIME, SNAPSHOT_TIME // make sure this is always the last one @@ -170,8 +171,8 @@ namespace { char const *field_names[] = { "DEV", "MAPPED_BLOCKS", - "MAPPED_EXCL_BLOCKS", - "MAPPED_SHARED_BLOCKS", + "EXCLUSIVE_BLOCKS", + "SHARED_BLOCKS", "MAPPED_SECTORS", "EXCLUSIVE_SECTORS", @@ -379,13 +380,13 @@ namespace { grid.field(it->second.mapped_blocks_); break; - case MAPPED_EXCL_BLOCKS: + case EXCLUSIVE_BLOCKS: if (!exclusive) exclusive = count_exclusives(md, mappings, it->first); grid.field(*exclusive); break; - case MAPPED_SHARED_BLOCKS: + case SHARED_BLOCKS: if (!exclusive) exclusive = count_exclusives(md, mappings, it->first); grid.field(it->second.mapped_blocks_ - *exclusive); From f3e23c54170e152fa5b829cbe40253dd6cb74bd8 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 14:56:48 +0000 Subject: [PATCH 48/59] [thin_ls] add --no-headers --- thin-provisioning/thin_ls.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 4ceb3d0..adc58d1 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -212,7 +212,8 @@ namespace { struct flags { flags() - : use_metadata_snap(false) { + : use_metadata_snap(false), + headers(true) { fields.push_back(DEV_ID); fields.push_back(MAPPED); @@ -221,6 +222,7 @@ namespace { } bool use_metadata_snap; + bool headers; vector fields; }; @@ -363,7 +365,8 @@ namespace { for (it = map.begin(); it != map.end(); ++it) pass1(md, mappings, it->first); - print_headers(grid, flags.fields); + if (flags.headers) + print_headers(grid, flags.fields); for (it = map.begin(); it != map.end(); ++it) { vector::const_iterator f; @@ -478,6 +481,7 @@ thin_ls_cmd::usage(std::ostream &out) const << "Options:\n" << " {-h|--help}\n" << " {-m|--metadata-snap}\n" + << " {--no-headers}\n" << " {-o|--format }\n" << " {-V|--version}\n\n" << "where is a comma separated list from:\n"; @@ -511,6 +515,7 @@ thin_ls_cmd::run(int argc, char **argv) { "metadata-snap", no_argument, NULL, 'm' }, { "version", no_argument, NULL, 'V'}, { "format", required_argument, NULL, 'o' }, + { "no-headers", no_argument, NULL, 1 }, { NULL, no_argument, NULL, 0 } }; @@ -532,6 +537,10 @@ thin_ls_cmd::run(int argc, char **argv) cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; + case 1: + flags.headers = false; + break; + default: usage(cerr); return 1; From 5aaa26fe34ca2cbdf6f934a3a29c412db39a2441 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 19 Jan 2016 15:50:15 +0000 Subject: [PATCH 49/59] [thin_ls] only run pass1 if needed --- thin-provisioning/thin_ls.cc | 57 ++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index adc58d1..be34fca 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -341,6 +341,21 @@ namespace { //------------------------------------------------ + bool pass1_needed(vector const &fields) { + vector::const_iterator it; + for (it = fields.begin(); it != fields.end(); ++it) { + if (*it == EXCLUSIVE_BLOCKS || + *it == SHARED_BLOCKS || + *it == EXCLUSIVE_SECTORS || + *it == SHARED_SECTORS || + *it == EXCLUSIVE || + *it == SHARED) + return true; + } + + return false; + } + void ls_(string const &path, ostream &out, struct flags &flags) { grid_layout grid; @@ -359,11 +374,14 @@ namespace { walk_device_tree(*md->details_, de, *dd_policy); mapping_set mappings(md->data_sm_->get_nr_blocks()); - - dd_map const &map = de.get_details(); dd_map::const_iterator it; - for (it = map.begin(); it != map.end(); ++it) - pass1(md, mappings, it->first); + dd_map const &map = de.get_details(); + + bool some_exclusive_fields = pass1_needed(flags.fields); + if (some_exclusive_fields) { + for (it = map.begin(); it != map.end(); ++it) + pass1(md, mappings, it->first); + } if (flags.headers) print_headers(grid, flags.fields); @@ -371,7 +389,10 @@ namespace { for (it = map.begin(); it != map.end(); ++it) { vector::const_iterator f; - optional exclusive; + block_address exclusive = 0; + + if (some_exclusive_fields) + exclusive = count_exclusives(md, mappings, it->first); for (f = flags.fields.begin(); f != flags.fields.end(); ++f) { switch (*f) { @@ -384,15 +405,11 @@ namespace { break; case EXCLUSIVE_BLOCKS: - if (!exclusive) - exclusive = count_exclusives(md, mappings, it->first); - grid.field(*exclusive); + grid.field(exclusive); break; case SHARED_BLOCKS: - if (!exclusive) - exclusive = count_exclusives(md, mappings, it->first); - grid.field(it->second.mapped_blocks_ - *exclusive); + grid.field(it->second.mapped_blocks_ - exclusive); break; case MAPPED_SECTORS: @@ -400,15 +417,11 @@ namespace { break; case EXCLUSIVE_SECTORS: - if (!exclusive) - exclusive = count_exclusives(md, mappings, it->first); - grid.field(*exclusive * block_size); + grid.field(exclusive * block_size); break; case SHARED_SECTORS: - if (!exclusive) - exclusive = count_exclusives(md, mappings, it->first); - grid.field((it->second.mapped_blocks_ - *exclusive) * block_size); + grid.field((it->second.mapped_blocks_ - exclusive) * block_size); break; @@ -419,20 +432,14 @@ namespace { break; case EXCLUSIVE: - if (!exclusive) - exclusive = count_exclusives(md, mappings, it->first); - grid.field( - format_disk_unit(*exclusive * block_size, + format_disk_unit(exclusive * block_size, UNIT_SECTOR)); break; case SHARED: - if (!exclusive) - exclusive = count_exclusives(md, mappings, it->first); - grid.field( - format_disk_unit((it->second.mapped_blocks_ - *exclusive) * + format_disk_unit((it->second.mapped_blocks_ - exclusive) * block_size, UNIT_SECTOR)); break; From e15b11edb115c3438f4cda60519ccbc3e4a16322 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 06:58:59 +0000 Subject: [PATCH 50/59] [thin_ls, base] Factor out grid_layout --- Makefile.in | 1 + base/grid_layout.cc | 82 ++++++++++++++++++++++++++++++++++++ base/grid_layout.h | 41 ++++++++++++++++++ thin-provisioning/thin_ls.cc | 72 +------------------------------ 4 files changed, 125 insertions(+), 71 deletions(-) create mode 100644 base/grid_layout.cc create mode 100644 base/grid_layout.h diff --git a/Makefile.in b/Makefile.in index 0b47826..7c02a7f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,6 +31,7 @@ SOURCE=\ base/endian_utils.cc \ base/error_state.cc \ base/error_string.cc \ + base/grid_layout.cc \ base/progress_monitor.cc \ base/xml_utils.cc \ block-cache/block_cache.cc \ diff --git a/base/grid_layout.cc b/base/grid_layout.cc new file mode 100644 index 0000000..5ba12b4 --- /dev/null +++ b/base/grid_layout.cc @@ -0,0 +1,82 @@ +#include "base/grid_layout.h" + +#include + +using namespace base; +using namespace std; + +//---------------------------------------------------------------- + +grid_layout::grid_layout() + : nr_fields_(0) +{ + new_row(); +} + +void +grid_layout::render(ostream &out) const +{ + vector widths; + calc_field_widths(widths); + + grid::const_iterator row; + for (row = grid_.begin(); row != grid_.end(); ++row) { + row::const_iterator col; + unsigned i; + for (col = row->begin(), i = 0; col != row->end(); ++col, ++i) + out << justify(widths[i], *col) << " "; + out << "\n"; + } +} + +void +grid_layout::new_row() +{ + grid_.push_back(row()); +} + +grid_layout::row const & +grid_layout::current_row() const +{ + return grid_.back(); +} + +grid_layout::row & +grid_layout::current_row() +{ + return grid_.back(); +} + +void +grid_layout::push_field(string const &s) +{ + current_row().push_back(s); + nr_fields_ = max(nr_fields_, current_row().size()); +} + +void +grid_layout::calc_field_widths(vector &widths) const +{ + widths.resize(nr_fields_, 0); + + grid::const_iterator row; + for (row = grid_.begin(); row != grid_.end(); ++row) { + row::const_iterator col; + unsigned i; + for (col = row->begin(), i = 0; col != row->end(); ++col, ++i) + widths[i] = max(widths[i], col->length()); + } +} + +string +grid_layout::justify(unsigned width, string const &txt) const +{ + if (txt.length() > width) + throw runtime_error("string field too long, internal error"); + + string result(width - txt.length(), ' '); + result += txt; + return result; +} + +//---------------------------------------------------------------- diff --git a/base/grid_layout.h b/base/grid_layout.h new file mode 100644 index 0000000..7e3ad5b --- /dev/null +++ b/base/grid_layout.h @@ -0,0 +1,41 @@ +#ifndef BASE_GRID_LAYOUT_H +#define BASE_GRID_LAYOUT_H + +#include +#include +#include +#include +#include + +//---------------------------------------------------------------- + +namespace base { + class grid_layout { + public: + typedef std::list row; + typedef std::list grid; + + grid_layout(); + void render(std::ostream &out) const; + void new_row(); + + template + void field(T const &t) { + push_field(boost::lexical_cast(t)); + } + + private: + row ¤t_row(); + row const ¤t_row() const; + void push_field(std::string const &s); + void calc_field_widths(std::vector &widths) const; + std::string justify(unsigned width, std::string const &txt) const; + + grid grid_; + unsigned nr_fields_; + }; +} + +//---------------------------------------------------------------- + +#endif diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index be34fca..8a104c1 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -22,6 +22,7 @@ #include #include "base/disk_units.h" +#include "base/grid_layout.h" #include "boost/lexical_cast.hpp" #include "boost/optional.hpp" #include "boost/range.hpp" @@ -43,77 +44,6 @@ using namespace thin_provisioning; //---------------------------------------------------------------- namespace { - // FIXME: move to own file - class grid_layout { - public: - typedef list row; - typedef list grid; - - grid_layout() - : nr_fields_(0) { - new_row(); - } - - void render(ostream &out) { - vector widths; - calc_field_widths(widths); - - grid::const_iterator row; - for (row = grid_.begin(); row != grid_.end(); ++row) { - row::const_iterator col; - unsigned i; - for (col = row->begin(), i = 0; col != row->end(); ++col, ++i) - out << justify(widths[i], *col) << " "; - out << "\n"; - } - } - - void new_row() { - grid_.push_back(row()); - } - - template - void field(T const &t) { - push_field(lexical_cast(t)); - } - - private: - row ¤t_row() { - return grid_.back(); - } - - void push_field(string const &s) { - current_row().push_back(s); - nr_fields_ = max(nr_fields_, current_row().size()); - } - - void calc_field_widths(vector &widths) const { - widths.resize(nr_fields_, 0); - - grid::const_iterator row; - for (row = grid_.begin(); row != grid_.end(); ++row) { - row::const_iterator col; - unsigned i; - for (col = row->begin(), i = 0; col != row->end(); ++col, ++i) - widths[i] = max(widths[i], col->length()); - } - } - - string justify(unsigned width, string const &txt) const { - if (txt.length() > width) - throw runtime_error("string field too long, internal error"); - - string result(width - txt.length(), ' '); - result += txt; - return result; - } - - grid grid_; - unsigned nr_fields_; - }; - - //------------------------------------------------ - class mapping_set { public: mapping_set(block_address nr_blocks) From 944b9c0c573598ff6305ab9bc03a866922771843 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 06:59:55 +0000 Subject: [PATCH 51/59] [thin_ls] wire up -o --- thin-provisioning/thin_ls.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 8a104c1..4e354b3 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -445,7 +445,7 @@ thin_ls_cmd::run(int argc, char **argv) { int c; struct flags flags; - const char shortopts[] = "hm::V"; + const char shortopts[] = "ho:m::V"; const struct option longopts[] = { { "help", no_argument, NULL, 'h'}, From d19164a177c4863a3111d1a022d6f154e204a0b9 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 09:50:47 +0000 Subject: [PATCH 52/59] [disk_units] tweak rounding --- base/disk_units.cc | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/base/disk_units.cc b/base/disk_units.cc index 8e5faf1..04de8ad 100644 --- a/base/disk_units.cc +++ b/base/disk_units.cc @@ -53,13 +53,35 @@ base::disk_unit_multiplier(disk_unit u) return 1; } + +namespace { + bool small_enough(unsigned long long n) { + if (n > 1024ull * 1024ull) + return false; + + if (n < 1024ull) + return true; + + return (n & 1023) && (n < 8ull * 1024ull); + } + + unsigned long long round_ull(unsigned long long n, unsigned long long d) { + return round(static_cast(n) / static_cast(d)); + } +} + string base::format_disk_unit(unsigned long long numerator, disk_unit u) { numerator *= disk_unit_multiplier(u); unsigned i; - for (i = 0; numerator >= 1024; i++) - numerator /= 1024; + for (i = 0; numerator > 1024ull * 1024ull; i++) + numerator /= 1024ull; + + if (numerator > 8 * 1024ull) { + numerator = round_ull(numerator, 1024ull); + i++; + } char const *extensions[] = { "", "KiB", "MiB", "GiB", "TiB", "PiB" From d858a43f0785d1676760d4b5515acfd29c3abaf5 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 10:40:48 +0000 Subject: [PATCH 53/59] [grid_layout] avoid extra newline at end of grid --- base/grid_layout.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/base/grid_layout.cc b/base/grid_layout.cc index 5ba12b4..813be44 100644 --- a/base/grid_layout.cc +++ b/base/grid_layout.cc @@ -20,12 +20,21 @@ grid_layout::render(ostream &out) const calc_field_widths(widths); grid::const_iterator row; + bool newline_needed = false; + for (row = grid_.begin(); row != grid_.end(); ++row) { row::const_iterator col; unsigned i; - for (col = row->begin(), i = 0; col != row->end(); ++col, ++i) + + if (newline_needed) { + out << "\n"; + newline_needed = false; + } + + for (col = row->begin(), i = 0; col != row->end(); ++col, ++i) { out << justify(widths[i], *col) << " "; - out << "\n"; + newline_needed = true; + } } } From 7a4a5aa87ef83cee6d681494277d915dd587bfec Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 13:25:09 +0000 Subject: [PATCH 54/59] [thin_ls] fluff --- thin-provisioning/thin_ls.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 4e354b3..1160921 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -414,7 +414,7 @@ thin_ls_cmd::thin_ls_cmd() void thin_ls_cmd::usage(std::ostream &out) const { - out << "Usage: " << get_name() << " [options] {device|file}\n" + out << "Usage: " << get_name() << " [options] {metadata device}\n" << "Options:\n" << " {-h|--help}\n" << " {-m|--metadata-snap}\n" @@ -423,9 +423,8 @@ thin_ls_cmd::usage(std::ostream &out) const << " {-V|--version}\n\n" << "where is a comma separated list from:\n"; - for (unsigned i = 0; i <= static_cast(SNAPSHOT_TIME); i++) { + for (unsigned i = 0; i <= static_cast(SNAPSHOT_TIME); i++) out << " " << field_to_string(static_cast(i)) << "\n"; - } } vector parse_fields(string const &str) From 8ec37aedd2563c45943bbfae0e1ad811a4829b06 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 13:25:28 +0000 Subject: [PATCH 55/59] [thin_ls] add man page --- man8/thin_ls.8 | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 man8/thin_ls.8 diff --git a/man8/thin_ls.8 b/man8/thin_ls.8 new file mode 100644 index 0000000..0fbde6c --- /dev/null +++ b/man8/thin_ls.8 @@ -0,0 +1,48 @@ +.TH THIN_LS 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- +.SH NAME +thin_ls \- List thin volumes within a pool. + +.SH SYNOPSIS +.B thin_ls +.RB [ options ] +.I {metadata device} + +.SH DESCRIPTION +.B thin_ls +Displays infomation about thin volumes in a pool. Pass the metadata device on the command line, not the +pool device. + +This tool cannot be run on live metadata unless the \fB\-\-metadata\-snap\fP option is used. + +.SH OPTIONS + +.IP "\fB\-o, \-\-format\fP" +Give a comma separated list of the fields to be output. Valid fields are: +DEV, MAPPED_BLOCKS, EXCLUSIVE_BLOCKS, SHARED_BLOCKS, MAPPED_SECTORS, +EXCLUSIVE_SECTORS, SHARED_SECTORS, MAPPED, EXCLUSIVE, SHARED, TRANSACTION +CREATE_TIME, SNAP_TIME + +.IP "\fB\-m, \-\-metadata\-snap\fP" + +If you want to get information out of a live pool then you will need +to take a metadata snapshot and use this switch. + +.IP "\fB\-\-verbose" +Provide extra information on the mappings. + +.IP "\fB\-h, \-\-help\fP" +Print help and exit. + +.IP "\fB\-V, \-\-version\fP" +Output version information and exit. + +.SH SEE ALSO +.B thin_dump(8) +.B thin_repair(8) +.B thin_restore(8) +.B thin_rmap(8) +.B thin_trim(8) +.B thin_metadata_size(8) + +.SH AUTHOR +Joe Thornber From f385198cfc28433ff585f4a9227e1b9cfd677970 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 14:45:38 +0000 Subject: [PATCH 56/59] [thin_ls] get it working with a metadata snap --- thin-provisioning/thin_ls.cc | 41 +++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/thin-provisioning/thin_ls.cc b/thin-provisioning/thin_ls.cc index 1160921..869c7cf 100644 --- a/thin-provisioning/thin_ls.cc +++ b/thin-provisioning/thin_ls.cc @@ -46,8 +46,8 @@ using namespace thin_provisioning; namespace { class mapping_set { public: - mapping_set(block_address nr_blocks) - : bits_(nr_blocks * 2, false) { + mapping_set() + : bits_(10240, false) { } enum block_state { @@ -57,15 +57,15 @@ namespace { }; void inc(block_address b) { - if (bits_[b * 2]) - bits_[b * 2 + 1] = true; // shared + if (get_bit(b * 2)) + set_bit(b * 2 + 1, true); // shared else - bits_[b * 2] = true; // exclusive + set_bit(b * 2, true); // exclusive } block_state get_state(block_address b) const { - if (bits_[b * 2]) { - if (bits_[b * 2 + 1]) + if (get_bit(b * 2)) { + if (get_bit(b * 2 + 1)) return SHARED; else return EXCLUSIVE; @@ -74,7 +74,27 @@ namespace { } private: - vector bits_; + void ensure_size(block_address bit) const { + if (bit >= bits_.size()) { + unsigned new_size = bits_.size() * 2; + while (new_size < bit) + new_size *= 2; + + bits_.resize(new_size, false); + } + } + + bool get_bit(block_address bit) const { + ensure_size(bit); + return bits_[bit]; + } + + void set_bit(block_address bit, bool v) { + ensure_size(bit); + bits_[bit] = v; + } + + mutable vector bits_; }; //------------------------------------------------ @@ -289,7 +309,8 @@ namespace { void ls_(string const &path, ostream &out, struct flags &flags) { grid_layout grid; - block_manager<>::ptr bm(open_bm(path, block_manager<>::READ_ONLY)); + block_manager<>::ptr bm(open_bm(path, block_manager<>::READ_ONLY, + !flags.use_metadata_snap)); metadata::ptr md; if (flags.use_metadata_snap) @@ -303,7 +324,7 @@ namespace { device_tree_detail::damage_visitor::ptr dd_policy(details_damage_policy()); walk_device_tree(*md->details_, de, *dd_policy); - mapping_set mappings(md->data_sm_->get_nr_blocks()); + mapping_set mappings; dd_map::const_iterator it; dd_map const &map = de.get_details(); From 04976a34fd1af5bebf328d4704798ea12cf0a75d Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 14:47:38 +0000 Subject: [PATCH 57/59] [thin_ls] update man page with --no-headers --- man8/thin_ls.8 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/man8/thin_ls.8 b/man8/thin_ls.8 index 0fbde6c..7d5081b 100644 --- a/man8/thin_ls.8 +++ b/man8/thin_ls.8 @@ -22,6 +22,9 @@ DEV, MAPPED_BLOCKS, EXCLUSIVE_BLOCKS, SHARED_BLOCKS, MAPPED_SECTORS, EXCLUSIVE_SECTORS, SHARED_SECTORS, MAPPED, EXCLUSIVE, SHARED, TRANSACTION CREATE_TIME, SNAP_TIME +.IP "\fB\-\-no\-headers\fP" +Don't output headers. + .IP "\fB\-m, \-\-metadata\-snap\fP" If you want to get information out of a live pool then you will need From 5b922c0c9f8add23505a3b0f59784bafcf89fd5c Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 15:43:21 +0000 Subject: [PATCH 58/59] Bump to v0.6.0 --- CHANGES | 5 +++++ VERSION | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index ee92eee..af6b3fc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +v0.6.0 +====== + +thin_ls + v0.5.6 ====== diff --git a/VERSION b/VERSION index b49b253..a918a2a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.6 +0.6.0 From 1e0d2a16cce9fcbd4714b25639f0991f00a55f93 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 20 Jan 2016 18:11:48 +0000 Subject: [PATCH 59/59] [disk_units] add missing header --- base/disk_units.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/base/disk_units.cc b/base/disk_units.cc index 04de8ad..66f71a2 100644 --- a/base/disk_units.cc +++ b/base/disk_units.cc @@ -1,7 +1,8 @@ #include "base/disk_units.h" -#include #include +#include +#include using namespace std; using namespace boost;