#include <iostream>
#include <boost/program_options.hpp>
#include <boost/scoped_ptr.hpp>
-#include "include/assert.h"
+#include "include/ceph_assert.h"
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_rbd
ImportDiffContext(librbd::Image *image, int fd, size_t size, bool no_progress)
: image(image), fd(fd), size(size), pc("Importing image diff", no_progress),
throttle((fd == STDIN_FILENO) ? 1 :
- g_conf->get_val<int64_t>("rbd_concurrent_management_ops"),
+ g_conf().get_val<uint64_t>("rbd_concurrent_management_ops"),
false),
last_offset(0) {
}
class C_ImportDiff : public Context {
public:
C_ImportDiff(ImportDiffContext *idiffctx, bufferlist data, uint64_t offset,
- uint64_t length, bool discard)
+ uint64_t length, bool write_zeroes)
: m_idiffctx(idiffctx), m_data(data), m_offset(offset), m_length(length),
- m_discard(discard) {
+ m_write_zeroes(write_zeroes) {
// use block offset (stdin) or import file position to report
// progress.
if (m_idiffctx->fd == STDIN_FILENO) {
new librbd::RBD::AioCompletion(ctx, &utils::aio_context_callback);
int r;
- if (m_discard) {
- r = m_idiffctx->image->aio_discard(m_offset, m_length, aio_completion);
+ if (m_write_zeroes) {
+ r = m_idiffctx->image->aio_write_zeroes(m_offset, m_length,
+ aio_completion, 0U,
+ LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
} else {
r = m_idiffctx->image->aio_write2(m_offset, m_length, m_data,
- aio_completion, LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
+ aio_completion,
+ LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
}
if (r < 0) {
bufferlist m_data;
uint64_t m_offset;
uint64_t m_length;
- bool m_discard;
+ bool m_write_zeroes;
uint64_t m_prog_offset;
};
string from;
r = utils::read_string(idiffctx->fd, 4096, &from); // 4k limit to make sure we don't get a garbage string
if (r < 0) {
+ std::cerr << "rbd: failed to decode start snap name" << std::endl;
return r;
}
bool exists;
r = idiffctx->image->snap_exists2(from.c_str(), &exists);
if (r < 0) {
+ std::cerr << "rbd: failed to query start snap state" << std::endl;
return r;
}
string to;
r = utils::read_string(idiffctx->fd, 4096, &to); // 4k limit to make sure we don't get a garbage string
if (r < 0) {
+ std::cerr << "rbd: failed to decode end snap name" << std::endl;
return r;
}
bool exists;
r = idiffctx->image->snap_exists2(to.c_str(), &exists);
if (r < 0) {
+ std::cerr << "rbd: failed to query end snap state" << std::endl;
return r;
}
if (exists) {
- std::cerr << "end snapshot '" << to << "' already exists, aborting" << std::endl;
+ std::cerr << "end snapshot '" << to << "' already exists, aborting"
+ << std::endl;
return -EEXIST;
}
return 0;
}
+static int get_snap_protection_status(ImportDiffContext *idiffctx,
+ bool *is_protected)
+{
+ int r;
+ char buf[sizeof(__u8)];
+ r = safe_read_exact(idiffctx->fd, buf, sizeof(buf));
+ if (r < 0) {
+ std::cerr << "rbd: failed to decode snap protection status" << std::endl;
+ return r;
+ }
+
+ *is_protected = (buf[0] != 0);
+ idiffctx->update_progress();
+
+ return 0;
+}
+
static int do_image_resize(ImportDiffContext *idiffctx)
{
int r;
uint64_t end_size;
r = safe_read_exact(idiffctx->fd, buf, sizeof(buf));
if (r < 0) {
+ std::cerr << "rbd: failed to decode image size" << std::endl;
return r;
}
bufferlist bl;
bl.append(buf, sizeof(buf));
- bufferlist::iterator p = bl.begin();
- ::decode(end_size, p);
+ auto p = bl.cbegin();
+ decode(end_size, p);
uint64_t cur_size;
idiffctx->image->size(&cur_size);
return 0;
}
-static int do_image_io(ImportDiffContext *idiffctx, bool discard, size_t sparse_size)
+static int do_image_io(ImportDiffContext *idiffctx, bool write_zeroes,
+ size_t sparse_size)
{
int r;
char buf[16];
r = safe_read_exact(idiffctx->fd, buf, sizeof(buf));
if (r < 0) {
+ std::cerr << "rbd: failed to decode IO length" << std::endl;
return r;
}
bufferlist bl;
bl.append(buf, sizeof(buf));
- bufferlist::iterator p = bl.begin();
+ auto p = bl.cbegin();
uint64_t image_offset, buffer_length;
- ::decode(image_offset, p);
- ::decode(buffer_length, p);
+ decode(image_offset, p);
+ decode(buffer_length, p);
- if (!discard) {
+ if (!write_zeroes) {
bufferptr bp = buffer::create(buffer_length);
r = safe_read_exact(idiffctx->fd, bp.c_str(), buffer_length);
if (r < 0) {
+ std::cerr << "rbd: failed to decode write data" << std::endl;
return r;
}
bool zeroed = false;
utils::calc_sparse_extent(bp, sparse_size, buffer_offset, buffer_length,
&write_length, &zeroed);
- assert(write_length > 0);
+ ceph_assert(write_length > 0);
bufferlist write_bl;
if (!zeroed) {
bufferptr write_ptr(bp, buffer_offset, write_length);
write_bl.push_back(write_ptr);
- assert(write_bl.length() == write_length);
+ ceph_assert(write_bl.length() == write_length);
}
C_ImportDiff *ctx = new C_ImportDiff(idiffctx, write_bl,
{
int r;
char buf[banner.size() + 1];
+ memset(buf, 0, sizeof(buf));
r = safe_read_exact(fd, buf, banner.size());
if (r < 0) {
+ std::cerr << "rbd: failed to decode diff banner" << std::endl;
return r;
}
buf[banner.size()] = '\0';
if (strcmp(buf, banner.c_str())) {
- std::cerr << "invalid banner '" << buf << "', expected '" << banner << "'" << std::endl;
+ std::cerr << "rbd: invalid or unexpected diff banner" << std::endl;
return -EINVAL;
}
uint64_t len = min<uint64_t>(length, sizeof(buf));
while (len > 0) {
r = safe_read_exact(fd, buf, len);
- if (r < 0)
+ if (r < 0) {
+ std::cerr << "rbd: failed to decode skipped tag data" << std::endl;
return r;
+ }
length -= len;
len = min<uint64_t>(length, sizeof(buf));
}
r = safe_read_exact(fd, &read_tag, sizeof(read_tag));
if (r < 0) {
+ std::cerr << "rbd: failed to decode tag" << std::endl;
return r;
}
char buf[sizeof(uint64_t)];
r = safe_read_exact(fd, buf, sizeof(buf));
if (r < 0) {
+ std::cerr << "rbd: failed to decode tag length" << std::endl;
return r;
}
bufferlist bl;
bl.append(buf, sizeof(buf));
- bufferlist::iterator p = bl.begin();
- ::decode(*readlen, p);
+ auto p = bl.cbegin();
+ decode(*readlen, p);
}
return 0;
struct stat stat_buf;
r = ::fstat(fd, &stat_buf);
if (r < 0) {
+ std::cerr << "rbd: failed to stat specified diff file" << std::endl;
return r;
}
size = (uint64_t)stat_buf.st_size;
return r;
}
- std::string skip_partial_discard;
- r = rados.conf_get("rbd_skip_partial_discard", skip_partial_discard);
- if (r < 0 || skip_partial_discard != "false") {
- dout(1) << "disabling sparse import" << dendl;
- sparse_size = 0;
- r = 0;
- }
-
// begin image import
std::string tosnap;
+ bool is_protected = false;
ImportDiffContext idiffctx(&image, fd, size, no_progress);
while (r == 0) {
__u8 tag;
r = do_image_snap_from(&idiffctx);
} else if (tag == RBD_DIFF_TO_SNAP) {
r = do_image_snap_to(&idiffctx, &tosnap);
+ } else if (tag == RBD_SNAP_PROTECTION_STATUS) {
+ r = get_snap_protection_status(&idiffctx, &is_protected);
} else if (tag == RBD_DIFF_IMAGE_SIZE) {
r = do_image_resize(&idiffctx);
} else if (tag == RBD_DIFF_WRITE || tag == RBD_DIFF_ZERO) {
int temp_r = idiffctx.throttle.wait_for_ret();
r = (r < 0) ? r : temp_r; // preserve original error
if (r == 0 && tosnap.length()) {
- idiffctx.image->snap_create(tosnap.c_str());
+ r = idiffctx.image->snap_create(tosnap.c_str());
+ if (r == 0 && is_protected) {
+ r = idiffctx.image->snap_protect(tosnap.c_str());
+ }
}
idiffctx.finish(r);
if (strcmp(path, "-") == 0) {
fd = STDIN_FILENO;
} else {
- fd = open(path, O_RDONLY);
+ fd = open(path, O_RDONLY|O_BINARY);
if (fd < 0) {
r = -errno;
std::cerr << "rbd: error opening " << path << std::endl;
at::add_no_progress_option(options);
}
-int execute_diff(const po::variables_map &vm) {
+int execute_diff(const po::variables_map &vm,
+ const std::vector<std::string> &ceph_global_init_args) {
std::string path;
- int r = utils::get_path(vm, utils::get_positional_argument(vm, 0), &path);
+ size_t arg_index = 0;
+ int r = utils::get_path(vm, &arg_index, &path);
if (r < 0) {
return r;
}
- size_t arg_index = 1;
std::string pool_name;
+ std::string namespace_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);
+ vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+ &image_name, &snap_name, true, 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);
+ r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
+ false, &rados, &io_ctx, &image);
if (r < 0) {
return r;
}
r = do_import_diff(rados, image, path.c_str(),
vm[at::NO_PROGRESS].as<bool>(), sparse_size);
+ if (r == -EDOM) {
+ r = -EBADMSG;
+ }
if (r < 0) {
cerr << "rbd: import-diff failed: " << cpp_strerror(r) << std::endl;
return r;
r = safe_read_exact(fd, buf, sizeof(buf));
if (r < 0) {
+ std::cerr << "rbd: failed to decode image option" << std::endl;
return r;
}
bufferlist bl;
bl.append(buf, sizeof(buf));
- bufferlist::iterator it;
- it = bl.begin();
+ auto it = bl.cbegin();
uint64_t val;
- ::decode(val, it);
+ decode(val, it);
if (opts.get(imageopt, &val) != 0) {
opts.set(imageopt, val);
return 0;
}
-static int do_import_header(int fd, int import_format, uint64_t &size, librbd::ImageOptions& opts)
+static int do_import_metadata(int import_format, librbd::Image& image,
+ const std::map<std::string, std::string> &imagemetas)
{
- // There is no header in v1 image.
+ int r = 0;
+
+ //v1 format
if (import_format == 1) {
return 0;
}
- if (fd == STDIN_FILENO || size < utils::RBD_IMAGE_BANNER_V2.size()) {
- return -EINVAL;
+ for (std::map<std::string, std::string>::const_iterator it = imagemetas.begin();
+ it != imagemetas.end(); ++it) {
+ r = image.metadata_set(it->first, it->second);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int decode_imagemeta(int fd, uint64_t length, std::map<std::string, std::string>* imagemetas)
+{
+ int r;
+ string key;
+ string value;
+
+ r = utils::read_string(fd, length, &key);
+ if (r < 0) {
+ std::cerr << "rbd: failed to decode metadata key" << std::endl;
+ return r;
+ }
+
+ r = utils::read_string(fd, length, &value);
+ if (r < 0) {
+ std::cerr << "rbd: failed to decode metadata value" << std::endl;
+ return r;
+ }
+
+ (*imagemetas)[key] = value;
+ return 0;
+}
+
+static int do_import_header(int fd, int import_format, librbd::ImageOptions& opts,
+ std::map<std::string, std::string>* imagemetas)
+{
+ // There is no header in v1 image.
+ if (import_format == 1) {
+ return 0;
}
int r;
while (r == 0) {
__u8 tag;
- uint64_t length;
+ uint64_t length = 0;
r = read_tag(fd, RBD_EXPORT_IMAGE_END, image_format, &tag, &length);
if (r < 0 || tag == RBD_EXPORT_IMAGE_END) {
break;
r = decode_and_set_image_option(fd, RBD_IMAGE_OPTION_STRIPE_UNIT, opts);
} else if (tag == RBD_EXPORT_IMAGE_STRIPE_COUNT) {
r = decode_and_set_image_option(fd, RBD_IMAGE_OPTION_STRIPE_COUNT, opts);
+ } else if (tag == RBD_EXPORT_IMAGE_META) {
+ r = decode_imagemeta(fd, length, imagemetas);
} else {
std::cerr << "rbd: invalid tag in image properties zone: " << tag << "Skip it."
<< std::endl;
char buf[sizeof(uint64_t)];
r = safe_read_exact(fd, buf, sizeof(buf));
if (r < 0) {
+ std::cerr << "rbd: failed to decode diff count" << std::endl;
return r;
}
bufferlist bl;
bl.append(buf, sizeof(buf));
- bufferlist::iterator p = bl.begin();
+ auto p = bl.cbegin();
uint64_t diff_num;
- ::decode(diff_num, p);
-
+ decode(diff_num, p);
for (size_t i = 0; i < diff_num; i++) {
r = do_import_diff_fd(rados, image, fd, true, 2, sparse_size);
if (r < 0) {
throttle.reset(new SimpleThrottle(1, false));
} else {
throttle.reset(new SimpleThrottle(
- g_conf->get_val<int64_t>("rbd_concurrent_management_ops"), false));
+ g_conf().get_val<uint64_t>("rbd_concurrent_management_ops"), false));
}
reqlen = min<uint64_t>(reqlen, size);
bufferlist write_bl;
bufferptr write_ptr(blkptr, buffer_offset, write_length);
write_bl.push_back(write_ptr);
- assert(write_bl.length() == write_length);
+ ceph_assert(write_bl.length() == write_length);
C_Import *ctx = new C_Import(*throttle, image, write_bl,
image_pos + buffer_offset);
int fd, r;
struct stat stat_buf;
utils::ProgressContext pc("Importing image", no_progress);
+ std::map<std::string, std::string> imagemetas;
- assert(imgname);
+ ceph_assert(imgname);
uint64_t order;
if (opts.get(RBD_IMAGE_OPTION_ORDER, &order) != 0) {
- order = g_conf->get_val<int64_t>("rbd_default_order");
+ order = g_conf().get_val<uint64_t>("rbd_default_order");
}
// try to fill whole imgblklen blocks for sparsification
fd = STDIN_FILENO;
size = 1ULL << order;
} else {
- if ((fd = open(path, O_RDONLY)) < 0) {
+ if ((fd = open(path, O_RDONLY|O_BINARY)) < 0) {
r = -errno;
std::cerr << "rbd: error opening " << path << std::endl;
goto done2;
if (!size) {
int64_t bdev_size = 0;
- r = get_block_device_size(fd, &bdev_size);
+ BlkDev blkdev(fd);
+ r = blkdev.get_size(&bdev_size);
if (r < 0) {
std::cerr << "rbd: unable to get size of file/block device"
<< std::endl;
goto done;
}
- assert(bdev_size >= 0);
+ ceph_assert(bdev_size >= 0);
size = (uint64_t) bdev_size;
}
#ifdef HAVE_POSIX_FADVISE
#endif
}
- r = do_import_header(fd, import_format, size, opts);
+ r = do_import_header(fd, import_format, opts, &imagemetas);
if (r < 0) {
std::cerr << "rbd: import header failed." << std::endl;
goto done;
goto err;
}
+ r = do_import_metadata(import_format, image, imagemetas);
+ if (r < 0) {
+ std::cerr << "rbd: failed to import image-meta" << std::endl;
+ goto err;
+ }
+
if (import_format == 1) {
r = do_import_v1(fd, image, size, imgblklen, pc, sparse_size);
} else {
// TODO legacy rbd allowed import to accept both 'image'/'dest' and
// 'pool'/'dest-pool'
- at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE, " (deprecated)");
- at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE, " (deprecated)");
+ at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE, " deprecated[:dest-pool]");
+ at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE, " deprecated[:dest]");
}
-int execute(const po::variables_map &vm) {
+int execute(const po::variables_map &vm,
+ const std::vector<std::string> &ceph_global_init_args) {
std::string path;
- int r = utils::get_path(vm, utils::get_positional_argument(vm, 0), &path);
+ size_t arg_index = 0;
+ int r = utils::get_path(vm, &arg_index, &path);
if (r < 0) {
return r;
}
std::string deprecated_pool_name;
if (vm.count(at::POOL_NAME)) {
deprecated_pool_name = vm[at::POOL_NAME].as<std::string>();
- std::cerr << "rbd: --pool is deprecated for import, use --dest-pool"
- << std::endl;
}
std::string deprecated_image_name;
if (vm.count(at::IMAGE_NAME)) {
deprecated_image_name = vm[at::IMAGE_NAME].as<std::string>();
- std::cerr << "rbd: --image is deprecated for import, use --dest"
- << std::endl;
} else {
- deprecated_image_name = path.substr(path.find_last_of("/") + 1);
+ deprecated_image_name = path.substr(path.find_last_of("/\\") + 1);
}
std::string deprecated_snap_name;
r = utils::extract_spec(deprecated_image_name, &deprecated_pool_name,
- &deprecated_image_name, &deprecated_snap_name,
- utils::SPEC_VALIDATION_FULL);
+ nullptr, &deprecated_image_name,
+ &deprecated_snap_name, utils::SPEC_VALIDATION_FULL);
if (r < 0) {
return r;
}
sparse_size = vm[at::IMAGE_SPARSE_SIZE].as<size_t>();
}
- size_t arg_index = 1;
std::string pool_name = deprecated_pool_name;
+ std::string namespace_name;
std::string image_name;
std::string snap_name = deprecated_snap_name;
r = utils::get_pool_image_snapshot_names(
- vm, at::ARGUMENT_MODIFIER_DEST, &arg_index, &pool_name, &image_name,
- &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL,
- false);
+ vm, at::ARGUMENT_MODIFIER_DEST, &arg_index, &pool_name, &namespace_name,
+ &image_name, &snap_name, false, utils::SNAPSHOT_PRESENCE_NONE,
+ utils::SPEC_VALIDATION_FULL);
if (r < 0) {
return r;
}
librados::Rados rados;
librados::IoCtx io_ctx;
- r = utils::init(pool_name, &rados, &io_ctx);
+ r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
if (r < 0) {
return r;
}