From: Dongsheng Yang Date: Thu, 28 Jul 2016 12:11:08 +0000 (-0400) Subject: rbd: introduce --export-format to export command X-Git-Tag: v12.0.1~342^2~13 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=26b858ee1e7ac04d8cb4176c01836ecd63d0b7c1;p=ceph.git rbd: introduce --export-format to export command Signed-off-by: Dongsheng Yang --- diff --git a/doc/man/8/rbd.rst b/doc/man/8/rbd.rst index d848214d58e6..f2d0d92a3a60 100644 --- a/doc/man/8/rbd.rst +++ b/doc/man/8/rbd.rst @@ -224,8 +224,10 @@ Commands Deletes an rbd image (including all data blocks). If the image has snapshots, this fails and nothing is deleted. -:command:`export` (*image-spec* | *snap-spec*) [*dest-path*] +:command:`export` [--export-format *format (1 or 2)*] (*image-spec* | *snap-spec*) [*dest-path*] Exports image to dest path (use - for stdout). + The --export-format accepts '1' or '2' currently. Format 2 allow us to export not only the content + of image, but also the snapshots and other priorities, such as image_order, features. :command:`import` [--import-format *format (1 or 2)*] [--image-format *format-id*] [--object-size *size-in-B/K/M*] [--stripe-unit *size-in-B/K/M* --stripe-count *num*] [--image-feature *feature-name*]... [--image-shared] *src-path* [*image-spec*] Creates a new image and imports its data from path (use - for diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index 820b7ea74d1c..12a68367c6f4 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -320,6 +320,7 @@ rbd help export usage: rbd export [--pool ] [--image ] [--snap ] [--path ] [--no-progress] + [--export-format ] Export image to file. @@ -336,6 +337,7 @@ --snap arg source snapshot name --path arg export file (or '-' for stdout) --no-progress disable progress output + --export-format arg format of image file rbd help export-diff usage: rbd export-diff [--pool ] [--image ] [--snap ] @@ -585,7 +587,7 @@ [--journal-splay-width ] [--journal-object-size ] [--journal-pool ] [--no-progress] - [--import-format ] [--pool ] + [--export-format ] [--pool ] [--image ] @@ -617,7 +619,7 @@ --journal-object-size arg size of journal objects --journal-pool arg pool for journal objects --no-progress disable progress output - --import-format arg format of the file to be imported + --export-format arg format of image file -p [ --pool ] arg pool name (deprecated) --image arg image name (deprecated) diff --git a/src/tools/rbd/action/Export.cc b/src/tools/rbd/action/Export.cc index bffeb22611b3..6c07440ee16e 100644 --- a/src/tools/rbd/action/Export.cc +++ b/src/tools/rbd/action/Export.cc @@ -110,7 +110,7 @@ private: int do_export_diff_fd(librbd::Image& image, const char *fromsnapname, const char *endsnapname, bool whole_object, - int fd, bool no_progress) + int fd, bool no_progress, int export_format) { int r; librbd::image_info_t info; @@ -122,7 +122,10 @@ int do_export_diff_fd(librbd::Image& image, const char *fromsnapname, { // header bufferlist bl; - bl.append(utils::RBD_DIFF_BANNER); + if (export_format == 1) + bl.append(utils::RBD_DIFF_BANNER); + else + bl.append(utils::RBD_DIFF_BANNER_V2); __u8 tag; if (fromsnapname) { @@ -192,9 +195,10 @@ int do_export_diff(librbd::Image& image, const char *fromsnapname, if (fd < 0) return -errno; - r = do_export_diff_fd(image, fromsnapname, endsnapname, whole_object, fd, no_progress); + r = do_export_diff_fd(image, fromsnapname, endsnapname, whole_object, fd, no_progress, 1); - close(fd); + if (fd != 1) + close(fd); if (r < 0 && fd != 1) { remove(path); } @@ -283,11 +287,11 @@ class C_Export : public Context { public: C_Export(SimpleThrottle &simple_throttle, librbd::Image &image, - uint64_t offset, uint64_t length, int fd) + uint64_t fd_offset, uint64_t offset, uint64_t length, int fd) : m_aio_completion( new librbd::RBD::AioCompletion(this, &utils::aio_context_callback)), - m_throttle(simple_throttle), m_image(image), m_offset(offset), - m_length(length), m_fd(fd) + m_throttle(simple_throttle), m_image(image), m_dest_offset(fd_offset), + m_offset(offset), m_length(length), m_fd(fd) { } @@ -325,10 +329,10 @@ public: return; } - uint64_t chkret = lseek64(m_fd, m_offset, SEEK_SET); - if (chkret != m_offset) { + uint64_t chkret = lseek64(m_fd, m_dest_offset, SEEK_SET); + if (chkret != m_dest_offset) { cerr << "rbd: error seeking destination image to offset " - << m_offset << std::endl; + << m_dest_offset << std::endl; r = -errno; return; } @@ -337,7 +341,7 @@ public: r = m_bufferlist.write_fd(m_fd); if (r < 0) { cerr << "rbd: error writing to destination image at offset " - << m_offset << std::endl; + << m_dest_offset << std::endl; } } @@ -346,13 +350,20 @@ private: SimpleThrottle &m_throttle; librbd::Image &m_image; bufferlist m_bufferlist; + uint64_t m_dest_offset; uint64_t m_offset; uint64_t m_length; int m_fd; }; -static int do_export(librbd::Image& image, const char *path, bool no_progress) +static int do_export(librbd::Image& image, const char *path, bool no_progress, int export_format) { + // check current supported formats. + if (export_format != 1 && export_format != 2) { + std::cerr << "rbd: wrong file format to import" << std::endl; + return -EINVAL; + } + librbd::image_info_t info; int64_t r = image.stat(info, sizeof(info)); if (r < 0) @@ -376,34 +387,96 @@ static int do_export(librbd::Image& image, const char *path, bool no_progress) } utils::ProgressContext pc("Exporting image", no_progress); - SimpleThrottle throttle(max_concurrent_ops, false); uint64_t period = image.get_stripe_count() * (1ull << info.order); - for (uint64_t offset = 0; offset < info.size; offset += period) { - if (throttle.pending_error()) { - break; + + if (export_format == 2) { + size_t offset = 0; + // header + bufferlist bl; + bl.append(utils::RBD_IMAGE_BANNER_V2); + + // size in header + uint64_t size = info.size; + ::encode(size, bl); + + r = bl.write_fd(fd); + if (r < 0) { + goto out; } + offset += bl.length(); - uint64_t length = min(period, info.size - offset); - C_Export *ctx = new C_Export(throttle, image, offset, length, fd); - ctx->send(); + lseek(fd, offset, SEEK_SET); - pc.update_progress(offset, info.size); - } + // header for snapshots + bl.clear(); + bl.append(utils::RBD_IMAGE_SNAPS_BANNER_V2); - r = throttle.wait_for_ret(); - if (!to_stdout) { - if (r >= 0) { - r = ftruncate(fd, info.size); + std::vector snaps; + r = image.snap_list(snaps); + if (r < 0) { + goto out; + } + + uint64_t snap_num = snaps.size() + 1; + ::encode(snap_num, bl); + + r = bl.write_fd(fd); + if (r < 0) { + goto out; + } + + if (0 == snap_num) { + goto out; + } else { + const char *last_snap = NULL; + for (size_t i = 0; i < snaps.size(); ++i) { + utils::snap_set(image, snaps[i].name.c_str()); + r = do_export_diff_fd(image, last_snap, snaps[i].name.c_str(), false, fd, true, 2); + if (r < 0) { + goto out; + } + pc.update_progress(i, snaps.size() + 1); + last_snap = snaps[i].name.c_str(); + } + utils::snap_set(image, std::string("")); + r = do_export_diff_fd(image, last_snap, nullptr, false, fd, true, 2); + if (r < 0) { + goto out; + } + pc.update_progress(snaps.size() + 1, snaps.size() + 1); + } + } else { + size_t file_size = 0; + for (uint64_t offset = 0; offset < info.size; offset += period) { + if (throttle.pending_error()) { + break; + } + + uint64_t length = min(period, info.size - offset); + C_Export *ctx = new C_Export(throttle, image, file_size + offset, offset, length, fd); + ctx->send(); + + pc.update_progress(offset, info.size); + } + + file_size += info.size; + r = throttle.wait_for_ret(); + if (!to_stdout) { + if (r >= 0) { + r = ftruncate(fd, file_size); + r = lseek(fd, file_size, SEEK_SET); + } } - close(fd); } - if (r < 0) { +out: + if (r < 0) pc.fail(); - } else { + else pc.finish(); - } + if (!to_stdout) + close(fd); return r; } @@ -414,6 +487,8 @@ void get_arguments(po::options_description *positional, at::add_path_options(positional, options, "export file (or '-' for stdout)"); at::add_no_progress_option(options); + options->add_options() + ("export-format", po::value(), "format to export image"); } int execute(const po::variables_map &vm) { @@ -443,8 +518,12 @@ int execute(const po::variables_map &vm) { if (r < 0) { return r; } + + int format = 1; + if (vm.count("export-format")) + format = vm["export-format"].as(); - r = do_export(image, path.c_str(), vm[at::NO_PROGRESS].as()); + r = do_export(image, path.c_str(), vm[at::NO_PROGRESS].as(), format); if (r < 0) { std::cerr << "rbd: export error: " << cpp_strerror(r) << std::endl; return r;