#include "common/blkdev.h"
#include "common/errno.h"
#include "common/Throttle.h"
+#include "include/compat.h"
+#include "include/encoding.h"
+#include "common/debug.h"
+#include "common/errno.h"
+#include "common/safe_io.h"
#include <iostream>
#include <boost/program_options.hpp>
#include <boost/scoped_ptr.hpp>
namespace rbd {
namespace action {
+namespace import_diff {
+
+namespace at = argument_types;
+namespace po = boost::program_options;
+
+static int do_import_diff(librbd::Image &image, const char *path,
+ bool no_progress)
+{
+ int fd, r;
+ struct stat stat_buf;
+ utils::ProgressContext pc("Importing image diff", no_progress);
+ uint64_t size = 0;
+ uint64_t off = 0;
+ string from, to;
+ char buf[utils::RBD_DIFF_BANNER.size() + 1];
+
+ bool from_stdin = !strcmp(path, "-");
+ if (from_stdin) {
+ fd = 0;
+ } else {
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ r = -errno;
+ std::cerr << "rbd: error opening " << path << std::endl;
+ return r;
+ }
+ r = ::fstat(fd, &stat_buf);
+ if (r < 0)
+ goto done;
+ size = (uint64_t)stat_buf.st_size;
+ }
+
+ r = safe_read_exact(fd, buf, utils::RBD_DIFF_BANNER.size());
+ if (r < 0)
+ goto done;
+ buf[utils::RBD_DIFF_BANNER.size()] = '\0';
+ if (strcmp(buf, utils::RBD_DIFF_BANNER.c_str())) {
+ std::cerr << "invalid banner '" << buf << "', expected '"
+ << utils::RBD_DIFF_BANNER << "'" << std::endl;
+ r = -EINVAL;
+ goto done;
+ }
+
+ while (true) {
+ __u8 tag;
+ r = safe_read_exact(fd, &tag, 1);
+ if (r < 0) {
+ goto done;
+ }
+
+ if (tag == RBD_DIFF_END) {
+ break;
+ } else if (tag == RBD_DIFF_FROM_SNAP) {
+ r = utils::read_string(fd, 4096, &from); // 4k limit to make sure we don't get a garbage string
+ if (r < 0)
+ goto done;
+
+ bool exists;
+ r = image.snap_exists2(from.c_str(), &exists);
+ if (r < 0)
+ goto done;
+
+ if (!exists) {
+ std::cerr << "start snapshot '" << from
+ << "' does not exist in the image, aborting" << std::endl;
+ r = -EINVAL;
+ goto done;
+ }
+ }
+ else if (tag == RBD_DIFF_TO_SNAP) {
+ r = utils::read_string(fd, 4096, &to); // 4k limit to make sure we don't get a garbage string
+ if (r < 0)
+ goto done;
+
+ // verify this snap isn't already present
+ bool exists;
+ r = image.snap_exists2(to.c_str(), &exists);
+ if (r < 0)
+ goto done;
+
+ if (exists) {
+ std::cerr << "end snapshot '" << to
+ << "' already exists, aborting" << std::endl;
+ r = -EEXIST;
+ goto done;
+ }
+ } else if (tag == RBD_DIFF_IMAGE_SIZE) {
+ uint64_t end_size;
+ char buf[8];
+ r = safe_read_exact(fd, buf, 8);
+ if (r < 0)
+ goto done;
+ bufferlist bl;
+ bl.append(buf, 8);
+ bufferlist::iterator p = bl.begin();
+ ::decode(end_size, p);
+ uint64_t cur_size;
+ image.size(&cur_size);
+ if (cur_size != end_size) {
+ image.resize(end_size);
+ } else {
+ }
+ if (from_stdin)
+ size = end_size;
+ } else if (tag == RBD_DIFF_WRITE || tag == RBD_DIFF_ZERO) {
+ uint64_t len;
+ char buf[16];
+ r = safe_read_exact(fd, buf, 16);
+ if (r < 0)
+ goto done;
+ bufferlist bl;
+ bl.append(buf, 16);
+ bufferlist::iterator p = bl.begin();
+ ::decode(off, p);
+ ::decode(len, p);
+
+ if (tag == RBD_DIFF_WRITE) {
+ bufferptr bp = buffer::create(len);
+ r = safe_read_exact(fd, bp.c_str(), len);
+ if (r < 0)
+ goto done;
+ bufferlist data;
+ data.append(bp);
+ image.write2(off, len, data, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
+ } else {
+ image.discard(off, len);
+ }
+ } else {
+ std::cerr << "unrecognized tag byte " << (int)tag
+ << " in stream; aborting" << std::endl;
+ r = -EINVAL;
+ goto done;
+ }
+ if (!from_stdin) {
+ // progress through input
+ uint64_t off = lseek64(fd, 0, SEEK_CUR);
+ pc.update_progress(off, size);
+ } else if (size) {
+ // progress through image offsets. this may jitter if blocks
+ // aren't in order, but it is better than nothing.
+ pc.update_progress(off, size);
+ }
+ }
+ // take final snap
+ if (to.length()) {
+ r = image.snap_create(to.c_str());
+ }
+
+ done:
+ if (r < 0)
+ pc.fail();
+ else
+ pc.finish();
+ if (!from_stdin)
+ close(fd);
+ return r;
+}
+
+void get_arguments(po::options_description *positional,
+ po::options_description *options) {
+ at::add_path_options(positional, options,
+ "import file (or '-' for stdin)");
+ at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
+ at::add_no_progress_option(options);
+}
+
+int execute(const po::variables_map &vm) {
+ std::string path;
+ int r = utils::get_path(vm, utils::get_positional_argument(vm, 0), &path);
+ if (r < 0) {
+ return r;
+ }
+
+ size_t arg_index = 1;
+ std::string pool_name;
+ std::string image_name;
+ std::string snap_name;
+ r = utils::get_pool_image_snapshot_names(
+ vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
+ &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::Rados rados;
+ librados::IoCtx io_ctx;
+ librbd::Image image;
+ r = utils::init_and_open_image(pool_name, image_name, "", false,
+ &rados, &io_ctx, &image);
+ if (r < 0) {
+ return r;
+ }
+
+ r = do_import_diff(image, path.c_str(), vm[at::NO_PROGRESS].as<bool>());
+ if (r < 0) {
+ cerr << "rbd: import-diff failed: " << cpp_strerror(r) << std::endl;
+ return r;
+ }
+ return 0;
+}
+
+Shell::Action action(
+ {"import-diff"}, {}, "Import an incremental diff.", "", &get_arguments,
+ &execute);
+
+} // namespace import_diff
+
namespace import {
namespace at = argument_types;
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "include/compat.h"
-#include "tools/rbd/ArgumentTypes.h"
-#include "tools/rbd/Shell.h"
-#include "tools/rbd/Utils.h"
-#include "include/encoding.h"
-#include "common/debug.h"
-#include "common/errno.h"
-#include "common/safe_io.h"
-#include <iostream>
-#include <boost/program_options.hpp>
-
-#define dout_context g_ceph_context
-#define dout_subsys ceph_subsys_rbd
-
-namespace rbd {
-namespace action {
-namespace import_diff {
-
-namespace at = argument_types;
-namespace po = boost::program_options;
-
-static int do_import_diff(librbd::Image &image, const char *path,
- bool no_progress)
-{
- int fd, r;
- struct stat stat_buf;
- utils::ProgressContext pc("Importing image diff", no_progress);
- uint64_t size = 0;
- uint64_t off = 0;
- string from, to;
- char buf[utils::RBD_DIFF_BANNER.size() + 1];
-
- bool from_stdin = !strcmp(path, "-");
- if (from_stdin) {
- fd = 0;
- } else {
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- r = -errno;
- std::cerr << "rbd: error opening " << path << std::endl;
- return r;
- }
- r = ::fstat(fd, &stat_buf);
- if (r < 0)
- goto done;
- size = (uint64_t)stat_buf.st_size;
- }
-
- r = safe_read_exact(fd, buf, utils::RBD_DIFF_BANNER.size());
- if (r < 0)
- goto done;
- buf[utils::RBD_DIFF_BANNER.size()] = '\0';
- if (strcmp(buf, utils::RBD_DIFF_BANNER.c_str())) {
- std::cerr << "invalid banner '" << buf << "', expected '"
- << utils::RBD_DIFF_BANNER << "'" << std::endl;
- r = -EINVAL;
- goto done;
- }
-
- while (true) {
- __u8 tag;
- r = safe_read_exact(fd, &tag, 1);
- if (r < 0) {
- goto done;
- }
-
- if (tag == RBD_DIFF_END) {
- dout(2) << " end diff" << dendl;
- break;
- } else if (tag == RBD_DIFF_FROM_SNAP) {
- r = utils::read_string(fd, 4096, &from); // 4k limit to make sure we don't get a garbage string
- if (r < 0)
- goto done;
- dout(2) << " from snap " << from << dendl;
-
- bool exists;
- r = image.snap_exists2(from.c_str(), &exists);
- if (r < 0)
- goto done;
-
- if (!exists) {
- std::cerr << "start snapshot '" << from
- << "' does not exist in the image, aborting" << std::endl;
- r = -EINVAL;
- goto done;
- }
- }
- else if (tag == RBD_DIFF_TO_SNAP) {
- r = utils::read_string(fd, 4096, &to); // 4k limit to make sure we don't get a garbage string
- if (r < 0)
- goto done;
- dout(2) << " to snap " << to << dendl;
-
- // verify this snap isn't already present
- bool exists;
- r = image.snap_exists2(to.c_str(), &exists);
- if (r < 0)
- goto done;
-
- if (exists) {
- std::cerr << "end snapshot '" << to
- << "' already exists, aborting" << std::endl;
- r = -EEXIST;
- goto done;
- }
- } else if (tag == RBD_DIFF_IMAGE_SIZE) {
- uint64_t end_size;
- char buf[8];
- r = safe_read_exact(fd, buf, 8);
- if (r < 0)
- goto done;
- bufferlist bl;
- bl.append(buf, 8);
- bufferlist::iterator p = bl.begin();
- ::decode(end_size, p);
- uint64_t cur_size;
- image.size(&cur_size);
- if (cur_size != end_size) {
- dout(2) << "resize " << cur_size << " -> " << end_size << dendl;
- image.resize(end_size);
- } else {
- dout(2) << "size " << end_size << " (no change)" << dendl;
- }
- if (from_stdin)
- size = end_size;
- } else if (tag == RBD_DIFF_WRITE || tag == RBD_DIFF_ZERO) {
- uint64_t len;
- char buf[16];
- r = safe_read_exact(fd, buf, 16);
- if (r < 0)
- goto done;
- bufferlist bl;
- bl.append(buf, 16);
- bufferlist::iterator p = bl.begin();
- ::decode(off, p);
- ::decode(len, p);
-
- if (tag == RBD_DIFF_WRITE) {
- bufferptr bp = buffer::create(len);
- r = safe_read_exact(fd, bp.c_str(), len);
- if (r < 0)
- goto done;
- bufferlist data;
- data.append(bp);
- dout(2) << " write " << off << "~" << len << dendl;
- image.write2(off, len, data, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
- } else {
- dout(2) << " zero " << off << "~" << len << dendl;
- image.discard(off, len);
- }
- } else {
- std::cerr << "unrecognized tag byte " << (int)tag
- << " in stream; aborting" << std::endl;
- r = -EINVAL;
- goto done;
- }
- if (!from_stdin) {
- // progress through input
- uint64_t off = lseek64(fd, 0, SEEK_CUR);
- pc.update_progress(off, size);
- } else if (size) {
- // progress through image offsets. this may jitter if blocks
- // aren't in order, but it is better than nothing.
- pc.update_progress(off, size);
- }
- }
- // take final snap
- if (to.length()) {
- dout(2) << " create end snap " << to << dendl;
- r = image.snap_create(to.c_str());
- }
-
- done:
- if (r < 0)
- pc.fail();
- else
- pc.finish();
- if (!from_stdin)
- close(fd);
- return r;
-}
-
-void get_arguments(po::options_description *positional,
- po::options_description *options) {
- at::add_path_options(positional, options,
- "import file (or '-' for stdin)");
- at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
- at::add_no_progress_option(options);
-}
-
-int execute(const po::variables_map &vm) {
- std::string path;
- int r = utils::get_path(vm, utils::get_positional_argument(vm, 0), &path);
- if (r < 0) {
- return r;
- }
-
- size_t arg_index = 1;
- std::string pool_name;
- std::string image_name;
- std::string snap_name;
- r = utils::get_pool_image_snapshot_names(
- vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
- &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
- if (r < 0) {
- return r;
- }
-
- librados::Rados rados;
- librados::IoCtx io_ctx;
- librbd::Image image;
- r = utils::init_and_open_image(pool_name, image_name, "", false,
- &rados, &io_ctx, &image);
- if (r < 0) {
- return r;
- }
-
- r = do_import_diff(image, path.c_str(), vm[at::NO_PROGRESS].as<bool>());
- if (r < 0) {
- cerr << "rbd: import-diff failed: " << cpp_strerror(r) << std::endl;
- return r;
- }
- return 0;
-}
-
-Shell::Action action(
- {"import-diff"}, {}, "Import an incremental diff.", "", &get_arguments,
- &execute);
-
-} // namespace import_diff
-} // namespace action
-} // namespace rbd