return 0;
}
-static int do_image_io(ImportDiffContext *idiffctx, bool discard)
+static int do_image_io(ImportDiffContext *idiffctx, bool discard, size_t sparse_size)
{
int r;
char buf[16];
if (r < 0) {
return r;
}
- data.append(bp);
- }
- C_ImportDiff *ctx = new C_ImportDiff(idiffctx, data, off, len, discard);
- return ctx->send();
+ // skip writing zeros
+ size_t write_offset = 0;
+ size_t write_length = 0;
+ size_t offset = 0;
+ while (offset < len) {
+ if (utils::calc_sparse_extent(bp,
+ sparse_size,
+ len,
+ &write_offset,
+ &write_length,
+ &offset)) {
+ bufferptr write_ptr(bp, write_offset, write_length);
+ bufferlist write_bl;
+ write_bl.push_back(write_ptr);
+ C_ImportDiff *ctx = new C_ImportDiff(idiffctx, data, off, len, discard);
+ r = ctx->send();
+
+ if (r < 0) {
+ return r;
+ }
+ // Reset write offset and write length after current write submitted
+ write_offset = offset;
+ write_length = 0;
+ }
+ }
+ } else {
+ C_ImportDiff *ctx = new C_ImportDiff(idiffctx, data, off, len, discard);
+ return ctx->send();
+ }
+ return r;
}
static int validate_banner(int fd, std::string banner)
return 0;
}
-int do_import_diff_fd(librbd::Image &image, int fd, bool no_progress, int format)
+int do_import_diff_fd(librbd::Image &image, int fd, bool no_progress, int format, size_t sparse_size)
{
int r;
} else if (tag == RBD_DIFF_IMAGE_SIZE) {
r = do_image_resize(&idiffctx);
} else if (tag == RBD_DIFF_WRITE || tag == RBD_DIFF_ZERO) {
- r = do_image_io(&idiffctx, (tag == RBD_DIFF_ZERO));
+ r = do_image_io(&idiffctx, (tag == RBD_DIFF_ZERO), sparse_size);
} else {
std::cerr << "unrecognized tag byte " << (int)tag << " in stream; skipping"
<< std::endl;
}
int do_import_diff(librbd::Image &image, const char *path,
- bool no_progress)
+ bool no_progress, size_t sparse_size)
{
int r;
int fd;
return r;
}
}
- r = do_import_diff_fd(image, fd, no_progress, 1);
+ r = do_import_diff_fd(image, fd, no_progress, 1, sparse_size);
if (fd != 0)
close(fd);
at::add_path_options(positional, options,
"import file (or '-' for stdin)");
at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
+ at::add_sparse_size_option(options);
at::add_no_progress_option(options);
}
return r;
}
+ size_t sparse_size = utils::RBD_DEFAULT_SPARSE_SIZE;
+ if (vm.count(at::IMAGE_SPARSE_SIZE)) {
+ sparse_size = vm[at::IMAGE_SPARSE_SIZE].as<size_t>();
+ }
+
librados::Rados rados;
librados::IoCtx io_ctx;
librbd::Image image;
return r;
}
- r = do_import_diff(image, path.c_str(), vm[at::NO_PROGRESS].as<bool>());
+ r = do_import_diff(image, path.c_str(), vm[at::NO_PROGRESS].as<bool>(), sparse_size);
if (r < 0) {
cerr << "rbd: import-diff failed: " << cpp_strerror(r) << std::endl;
return r;
}
static int do_import_v2(int fd, librbd::Image &image, uint64_t size,
- size_t imgblklen, utils::ProgressContext &pc)
+ size_t imgblklen, utils::ProgressContext &pc,
+ size_t sparse_size)
{
int r = 0;
r = validate_banner(fd, utils::RBD_IMAGE_DIFFS_BANNER_V2);
::decode(diff_num, p);
for (size_t i = 0; i < diff_num; i++) {
- r = do_import_diff_fd(image, fd, true, 2);
+ r = do_import_diff_fd(image, fd, true, 2, sparse_size);
if (r < 0) {
pc.fail();
std::cerr << "rbd: import-diff failed: " << cpp_strerror(r) << std::endl;
}
static int do_import_v1(int fd, librbd::Image &image, uint64_t size,
- size_t imgblklen, utils::ProgressContext &pc)
+ size_t imgblklen, utils::ProgressContext &pc
+ size_t sparse_size)
{
int r = 0;
size_t reqlen = imgblklen; // amount requested from read
if (!from_stdin)
pc.update_progress(image_pos, size);
- bufferlist bl(blklen);
- bl.append(p, blklen);
+ bufferptr blkptr(p, blklen);
// resize output image by binary expansion as we go for stdin
if (from_stdin && (image_pos + (size_t)blklen) > size) {
size *= 2;
// write as much as we got; perhaps less than imgblklen
// but skip writing zeros to create sparse images
- if (!bl.is_zero()) {
- C_Import *ctx = new C_Import(*throttle, image, bl, image_pos);
- ctx->send();
+ size_t write_offset = 0;
+ size_t write_length = 0;
+ size_t offset = 0;
+ while (offset < blklen) {
+ if (utils::calc_sparse_extent(blkptr,
+ sparse_size,
+ blklen,
+ &write_offset,
+ &write_length,
+ &offset)) {
+ bufferptr write_ptr(blkptr, write_offset, write_length);
+ bufferlist write_bl;
+ write_bl.push_back(write_ptr);
+ C_Import *ctx = new C_Import(*throttle, image, write_bl, image_pos + write_offset);
+ ctx->send();
+
+ // Reset write offset and write length after current write submitted
+ write_offset = offset;
+ write_length = 0;
+ }
}
// done with whole block, whether written or not
static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx,
const char *imgname, const char *path,
librbd::ImageOptions& opts, bool no_progress,
- int import_format)
+ int import_format, size_t sparse_size)
{
int fd, r;
struct stat stat_buf;
}
if (import_format == 1) {
- r = do_import_v1(fd, image, size, imgblklen, pc);
+ r = do_import_v1(fd, image, size, imgblklen, pc, sparse_size);
} else {
- r = do_import_v2(fd, image, size, imgblklen, pc);
+ r = do_import_v2(fd, image, size, imgblklen, pc, sparse_size);
}
r = image.close();
"import file (or '-' for stdin)");
at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_DEST);
at::add_create_image_options(options, true);
+ at::add_sparse_size_option(options);
at::add_no_progress_option(options);
at::add_export_format_option(options);
deprecated_image_name = path.substr(path.find_last_of("/") + 1);
}
+ size_t sparse_size = utils::RBD_DEFAULT_SPARSE_SIZE;
+ if (vm.count(at::IMAGE_SPARSE_SIZE)) {
+ sparse_size = vm[at::IMAGE_SPARSE_SIZE].as<size_t>();
+ }
+
size_t arg_index = 1;
std::string pool_name = deprecated_pool_name;
std::string image_name;
librbd::RBD rbd;
r = do_import(rbd, io_ctx, image_name.c_str(), path.c_str(),
- opts, vm[at::NO_PROGRESS].as<bool>(), format);
+ opts, vm[at::NO_PROGRESS].as<bool>(), format, sparse_size);
if (r < 0) {
std::cerr << "rbd: import failed: " << cpp_strerror(r) << std::endl;
return r;