From 08d0c2ab9f9487af0a74573e0c8b3fe262b799ff Mon Sep 17 00:00:00 2001 From: Dongsheng Yang Date: Thu, 20 Oct 2016 08:07:31 -0400 Subject: [PATCH] rbd: refactor export/import to v1 and v2 methods. Signed-off-by: Dongsheng Yang --- src/tools/rbd/Utils.h | 4 +- src/tools/rbd/action/Export.cc | 247 +++++++++++---------- src/tools/rbd/action/Import.cc | 388 ++++++++++++++++++--------------- 3 files changed, 349 insertions(+), 290 deletions(-) diff --git a/src/tools/rbd/Utils.h b/src/tools/rbd/Utils.h index 9ecb21eecc6..0023d431dfe 100644 --- a/src/tools/rbd/Utils.h +++ b/src/tools/rbd/Utils.h @@ -29,8 +29,8 @@ static const std::string RBD_DIFF_BANNER_V2 ("rbd diff v2\n"); #define RBD_EXPORT_IMAGE_ORDER 'O' #define RBD_EXPORT_IMAGE_FEATURES 'T' -#define RBD_EXPORT_IMAGE_STRIPEUNIT 'U' -#define RBD_EXPORT_IMAGE_STRIPECOUNT 'C' +#define RBD_EXPORT_IMAGE_STRIPE_UNIT 'U' +#define RBD_EXPORT_IMAGE_STRIPE_COUNT 'C' #define RBD_EXPORT_IMAGE_END 'E' enum SnapshotPresence { diff --git a/src/tools/rbd/action/Export.cc b/src/tools/rbd/action/Export.cc index b7fa6a44d21..771db32279c 100644 --- a/src/tools/rbd/action/Export.cc +++ b/src/tools/rbd/action/Export.cc @@ -356,6 +356,133 @@ private: int m_fd; }; +static int do_export_v2(librbd::Image& image, librbd::image_info_t &info, int fd, + uint64_t period, int max_concurrent_ops, utils::ProgressContext &pc) +{ + int r = 0; + size_t offset = 0; + // header + bufferlist bl; + bl.append(utils::RBD_IMAGE_BANNER_V2); + + __u8 tag; + uint64_t length; + // encode order + tag = RBD_EXPORT_IMAGE_ORDER; + length = 8; + ::encode(tag, bl); + ::encode(length, bl); + ::encode(uint64_t(info.order), bl); + + // encode features + tag = RBD_EXPORT_IMAGE_FEATURES; + uint64_t features; + image.features(&features); + length = 8; + ::encode(tag, bl); + ::encode(length, bl); + ::encode(features, bl); + + // encode stripe_unit and stripe_count + tag = RBD_EXPORT_IMAGE_STRIPE_UNIT; + uint64_t stripe_unit; + stripe_unit = image.get_stripe_unit(); + length = 8; + ::encode(tag, bl); + ::encode(length, bl); + ::encode(stripe_unit, bl); + + tag = RBD_EXPORT_IMAGE_STRIPE_COUNT; + uint64_t stripe_count; + stripe_count = image.get_stripe_count(); + length = 8; + ::encode(tag, bl); + ::encode(length, bl); + ::encode(stripe_count, bl); + + // encode end tag + tag = RBD_EXPORT_IMAGE_END; + ::encode(tag, bl); + + // write bl to fd. + r = bl.write_fd(fd); + if (r < 0) { + return r; + } + offset += bl.length(); + + lseek(fd, offset, SEEK_SET); + + // header for snapshots + bl.clear(); + bl.append(utils::RBD_IMAGE_DIFFS_BANNER_V2); + + std::vector snaps; + r = image.snap_list(snaps); + if (r < 0) { + return r; + } + + uint64_t diff_num = snaps.size() + 1; + ::encode(diff_num, bl); + + r = bl.write_fd(fd); + if (r < 0) { + return r; + } + + if (0 == diff_num) { + return r; + } 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) { + return r; + } + 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) { + return r; + } + pc.update_progress(snaps.size() + 1, snaps.size() + 1); + } + return r; +} + +static int do_export_v1(librbd::Image& image, librbd::image_info_t &info, int fd, + uint64_t period, int max_concurrent_ops, utils::ProgressContext &pc) +{ + int r = 0; + size_t file_size = 0; + SimpleThrottle throttle(max_concurrent_ops, false); + 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 (fd != 1) { + if (r >= 0) { + r = ftruncate(fd, file_size); + r = lseek(fd, file_size, SEEK_SET); + } + } + return r; +} + static int do_export(librbd::Image& image, const char *path, bool no_progress, int export_format) { librbd::image_info_t info; @@ -381,123 +508,13 @@ static int do_export(librbd::Image& image, const char *path, bool no_progress, i } utils::ProgressContext pc("Exporting image", no_progress); - SimpleThrottle throttle(max_concurrent_ops, false); uint64_t period = image.get_stripe_count() * (1ull << info.order); - 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); - - // TODO add more priorities here, such as image_feature... - __u8 tag; - - // encode order - tag = RBD_EXPORT_IMAGE_ORDER; - ::encode(tag, bl); - ::encode(uint64_t(info.order), bl); - - // encode features - tag = RBD_EXPORT_IMAGE_FEATURES; - uint64_t features; - image.features(&features); - ::encode(tag, bl); - ::encode(features, bl); - - // encode stripe_unit and stripe_count - tag = RBD_EXPORT_IMAGE_STRIPEUNIT; - uint64_t stripe_unit; - stripe_unit = image.get_stripe_unit(); - ::encode(tag, bl); - ::encode(stripe_unit, bl); - - tag = RBD_EXPORT_IMAGE_STRIPECOUNT; - uint64_t stripe_count; - stripe_count = image.get_stripe_count(); - ::encode(tag, bl); - ::encode(stripe_count, bl); - - // encode end tag - tag = RBD_EXPORT_IMAGE_END; - ::encode(tag, bl); - - // write bl to fd. - r = bl.write_fd(fd); - if (r < 0) { - goto out; - } - offset += bl.length(); - - lseek(fd, offset, SEEK_SET); - - // header for snapshots - bl.clear(); - bl.append(utils::RBD_IMAGE_SNAPS_BANNER_V2); - - 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); - } - } - } + if (export_format == 1) + r = do_export_v1(image, info, fd, period, max_concurrent_ops, pc); + else + r = do_export_v2(image, info, fd, period, max_concurrent_ops, pc); -out: if (r < 0) pc.fail(); else @@ -547,7 +564,7 @@ int execute(const po::variables_map &vm) { int format = 1; if (vm.count("export-format")) - format = vm["export-format"].as(); + format = vm["export-format"].as(); r = do_export(image, path.c_str(), vm[at::NO_PROGRESS].as(), format); if (r < 0) { diff --git a/src/tools/rbd/action/Import.cc b/src/tools/rbd/action/Import.cc index 342f43e14c1..8dac188aebb 100644 --- a/src/tools/rbd/action/Import.cc +++ b/src/tools/rbd/action/Import.cc @@ -29,7 +29,7 @@ int do_import_diff_fd(librbd::Image &image, int fd, uint64_t size = 0; uint64_t off = 0; string from, to; - string banner = (format == 1 ? utils::RBD_DIFF_BANNER:utils::RBD_DIFF_BANNER_V2); + string banner = (format == 1 ? utils::RBD_DIFF_BANNER : utils::RBD_DIFF_BANNER_V2); char buf[banner.size() + 1]; bool from_stdin = (fd == 0); @@ -289,6 +289,211 @@ private: uint64_t m_offset; }; +static int do_import_header(int fd, int import_format, uint64_t &size, librbd::ImageOptions& opts) +{ + int r = 0; + char image_buf[utils::RBD_IMAGE_BANNER_V2.size() + 1]; + + // There is no header in v1 image. + if (import_format == 1) + return r; + + if (fd == 0 || size < utils::RBD_IMAGE_BANNER_V2.size()) { + r = -EINVAL; + return r; + } + r = safe_read_exact(fd, image_buf, utils::RBD_IMAGE_BANNER_V2.size()); + if (r < 0) + return r; + + image_buf[utils::RBD_IMAGE_BANNER_V2.size()] = '\0'; + if (strcmp(image_buf, utils::RBD_IMAGE_BANNER_V2.c_str())) { + // Old format + r = -EINVAL; + return r; + } + + char buf[8]; + bufferlist bl; + bufferlist::iterator p; + + // As V1 format for image is already deprecated, import image in V2 by default. + uint64_t image_format = 2; + if (opts.get(RBD_IMAGE_OPTION_FORMAT, &image_format) != 0) { + opts.set(RBD_IMAGE_OPTION_FORMAT, image_format); + } + + while (1) { + __u8 tag; + uint64_t length; + r = safe_read_exact(fd, &tag, 1); + if (r < 0) { + return r; + } + + if (tag == RBD_EXPORT_IMAGE_END) { + break; + } else { + r = safe_read_exact(fd, &length, 8); + if (r < 0) { + return r; + } + + if (tag == RBD_EXPORT_IMAGE_ORDER) { + uint64_t order = 0; + r = safe_read_exact(fd, &order, 8); + if (r < 0) { + return r; + } + if (opts.get(RBD_IMAGE_OPTION_ORDER, &order) != 0) { + opts.set(RBD_IMAGE_OPTION_ORDER, order); + } + } else if (tag == RBD_EXPORT_IMAGE_FEATURES) { + uint64_t features = 0; + r = safe_read_exact(fd, &features, 8); + if (r < 0) { + return r; + } + if (opts.get(RBD_IMAGE_OPTION_FEATURES, &features) != 0) { + opts.set(RBD_IMAGE_OPTION_FEATURES, features); + } + } else if (tag == RBD_EXPORT_IMAGE_STRIPE_UNIT) { + uint64_t stripe_unit = 0; + r = safe_read_exact(fd, &stripe_unit, 8); + if (r < 0) { + return r; + } + if (opts.get(RBD_IMAGE_OPTION_STRIPE_UNIT, &stripe_unit) != 0) { + opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit); + } + } else if (tag == RBD_EXPORT_IMAGE_STRIPE_COUNT) { + uint64_t stripe_count = 0; + r = safe_read_exact(fd, &stripe_count, 8); + if (r < 0) { + return r; + } + if (opts.get(RBD_IMAGE_OPTION_STRIPE_COUNT, &stripe_count) != 0) { + opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count); + } + } else { + std::cerr << "rbd: invalid tag in image properties zone: " << tag << "Skip it." << std::endl; + ::lseek(fd, length, SEEK_CUR); + } + } + } + + return r; +} + +static int do_import_v2(int fd, librbd::Image &image, uint64_t size, + size_t imgblklen, boost::scoped_ptr &throttle, + utils::ProgressContext &pc) +{ + int r = 0; + char snap_buf[utils::RBD_IMAGE_DIFFS_BANNER_V2.size() + 1]; + uint64_t diff_num; + + r = safe_read_exact(fd, snap_buf, utils::RBD_IMAGE_DIFFS_BANNER_V2.size()); + if (r < 0) + return r; + snap_buf[utils::RBD_IMAGE_DIFFS_BANNER_V2.size()] = '\0'; + if (strcmp(snap_buf, utils::RBD_IMAGE_DIFFS_BANNER_V2.c_str())) { + cerr << "Incorrect RBD_IMAGE_DIFFS_BANNER." << snap_buf < &throttle, + utils::ProgressContext &pc) +{ + int r = 0; + size_t reqlen = imgblklen; // amount requested from read + ssize_t readlen; // amount received from one read + size_t blklen = 0; // amount accumulated from reads to fill blk + char *p = new char[imgblklen]; + uint64_t image_pos = 0; + bool from_stdin = (fd == 0); + + reqlen = min(reqlen, size); + // loop body handles 0 return, as we may have a block to flush + while ((readlen = ::read(fd, p + blklen, reqlen)) >= 0) { + if (throttle->pending_error()) { + break; + } + + blklen += readlen; + // if read was short, try again to fill the block before writing + if (readlen && ((size_t)readlen < reqlen)) { + reqlen -= readlen; + continue; + } + if (!from_stdin) + pc.update_progress(image_pos, size); + + bufferlist bl(blklen); + bl.append(p, blklen); + // resize output image by binary expansion as we go for stdin + if (from_stdin && (image_pos + (size_t)blklen) > size) { + size *= 2; + r = image.resize(size); + if (r < 0) { + std::cerr << "rbd: can't resize image during import" << std::endl; + goto out; + } + } + + // 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(); + } + + // done with whole block, whether written or not + image_pos += blklen; + if (!from_stdin && image_pos >= size) + break; + // if read had returned 0, we're at EOF and should quit + if (readlen == 0) + break; + blklen = 0; + reqlen = imgblklen; + } + r = throttle->wait_for_ret(); + if (r < 0) { + goto out; + } + + if (fd == 0) { + r = image.resize(image_pos); + if (r < 0) { + std::cerr << "rbd: final image resize failed" << std::endl; + goto out; + } + } +out: + delete[] p; + return r; +} + static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx, const char *imgname, const char *path, librbd::ImageOptions& opts, bool no_progress, @@ -306,16 +511,9 @@ static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx, } // try to fill whole imgblklen blocks for sparsification - uint64_t image_pos = 0; size_t imgblklen = 1 << order; - char *p = new char[imgblklen]; - size_t reqlen = imgblklen; // amount requested from read - ssize_t readlen; // amount received from one read - size_t blklen = 0; // amount accumulated from reads to fill blk librbd::Image image; uint64_t size = 0; - uint64_t snap_num; - char image_buf[utils::RBD_IMAGE_BANNER_V2.size() + 1]; boost::scoped_ptr throttle; bool from_stdin = !strcmp(path, "-"); @@ -360,85 +558,11 @@ static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx, posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); #endif } - - if (import_format == 2) { - if (from_stdin || size < utils::RBD_IMAGE_BANNER_V2.size()) { - r = -EINVAL; - goto done; - } - r = safe_read_exact(fd, image_buf, utils::RBD_IMAGE_BANNER_V2.size()); - if (r < 0) - goto done; - - image_buf[utils::RBD_IMAGE_BANNER_V2.size()] = '\0'; - if (strcmp(image_buf, utils::RBD_IMAGE_BANNER_V2.c_str())) { - // Old format - r = -EINVAL; - goto done; - } - r = safe_read_exact(fd, &size, 8); - if (r < 0) { - goto done; - } - - // As V1 format for image is already deprecated, import image in V2 by default. - uint64_t image_format = 2; - if (opts.get(RBD_IMAGE_OPTION_FORMAT, &image_format) != 0) { - opts.set(RBD_IMAGE_OPTION_FORMAT, image_format); - } - - while (1) { - __u8 tag; - r = safe_read_exact(fd, &tag, 1); - if (r < 0) { - goto done; - } - - if (tag == RBD_EXPORT_IMAGE_END) { - break; - } else if (tag == RBD_EXPORT_IMAGE_ORDER) { - uint64_t order = 0; - r = safe_read_exact(fd, &order, 8); - if (r < 0) { - goto done; - } - if (opts.get(RBD_IMAGE_OPTION_ORDER, &order) != 0) { - opts.set(RBD_IMAGE_OPTION_ORDER, order); - } else if (tag == RBD_EXPORT_IMAGE_FEATURES) { - uint64_t features = 0; - r = safe_read_exact(fd, &features, 8); - if (r < 0) { - goto done; - } - if (opts.get(RBD_IMAGE_OPTION_FEATURES, &features) != 0) { - opts.set(RBD_IMAGE_OPTION_FEATURES, features); - } - } else if (tag == RBD_EXPORT_IMAGE_STRIPEUNIT) { - uint64_t stripe_unit = 0; - r = safe_read_exact(fd, &stripe_unit, 8); - if (r < 0) { - goto done; - } - if (opts.get(RBD_IMAGE_OPTION_STRIPE_UNIT, &stripe_unit) != 0) { - opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit); - } - } else if (tag == RBD_EXPORT_IMAGE_STRIPECOUNT) { - uint64_t stripe_count = 0; - r = safe_read_exact(fd, &stripe_count, 8); - if (r < 0) { - goto done; - } - if (opts.get(RBD_IMAGE_OPTION_STRIPE_COUNT, &stripe_count) != 0) { - opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count); - } - } else { - std::cerr << "rbd: invalid tag in image priority zone: " << tag << std::endl; - r = -EINVAL; - goto done; - } - //TODO, set the image options according flags and appending data. - } + r = do_import_header(fd, import_format, size, opts); + if (r < 0) { + std::cerr << "rbd: import header failed." << std::endl; + goto done; } r = rbd.create4(io_ctx, imgname, size, opts); @@ -453,93 +577,12 @@ static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx, goto err; } - if (import_format == 2) { - char snap_buf[utils::RBD_IMAGE_SNAPS_BANNER_V2.size() + 1]; - - r = safe_read_exact(fd, snap_buf, utils::RBD_IMAGE_SNAPS_BANNER_V2.size()); - if (r < 0) - goto done; - snap_buf[utils::RBD_IMAGE_SNAPS_BANNER_V2.size()] = '\0'; - if (strcmp(snap_buf, utils::RBD_IMAGE_SNAPS_BANNER_V2.c_str())) { - cerr << "Incorrect RBD_IMAGE_SNAPS_BANNER." << std::endl; - return -EINVAL; - } else { - r = safe_read_exact(fd, &snap_num, 8); - if (r < 0) { - goto close; - } - } - - for (size_t i = 0; i < snap_num; i++) { - r = do_import_diff_fd(image, fd, true, 2); - if (r < 0) { - pc.fail(); - std::cerr << "rbd: import-diff failed: " << cpp_strerror(r) << std::endl; - return r; - } - pc.update_progress(i + 1, snap_num); - } + if (import_format == 1) { + r = do_import_v1(fd, image, size, imgblklen, throttle, pc); } else { - reqlen = min(reqlen, size); - // loop body handles 0 return, as we may have a block to flush - while ((readlen = ::read(fd, p + blklen, reqlen)) >= 0) { - if (throttle->pending_error()) { - break; - } - - blklen += readlen; - // if read was short, try again to fill the block before writing - if (readlen && ((size_t)readlen < reqlen)) { - reqlen -= readlen; - continue; - } - if (!from_stdin) - pc.update_progress(image_pos, size); - - bufferlist bl(blklen); - bl.append(p, blklen); - // resize output image by binary expansion as we go for stdin - if (from_stdin && (image_pos + (size_t)blklen) > size) { - size *= 2; - r = image.resize(size); - if (r < 0) { - std::cerr << "rbd: can't resize image during import" << std::endl; - goto close; - } - } - - // 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(); - } - - // done with whole block, whether written or not - image_pos += blklen; - if (!from_stdin && image_pos >= size) - break; - // if read had returned 0, we're at EOF and should quit - if (readlen == 0) - break; - blklen = 0; - reqlen = imgblklen; - } - r = throttle->wait_for_ret(); - if (r < 0) { - goto close; - } - - if (from_stdin) { - r = image.resize(image_pos); - if (r < 0) { - std::cerr << "rbd: final image resize failed" << std::endl; - goto close; - } - } + r = do_import_v2(fd, image, size, imgblklen, throttle, pc); } -close: r = image.close(); err: if (r < 0) @@ -552,7 +595,6 @@ done: if (!from_stdin) close(fd); done2: - delete[] p; return r; } @@ -627,8 +669,8 @@ int execute(const po::variables_map &vm) { } int format = 1; - if (vm.count("import-format")) - format = vm["import-format"].as(); + if (vm.count("export-format")) + format = vm["export-format"].as(); librbd::RBD rbd; r = do_import(rbd, io_ctx, image_name.c_str(), path.c_str(), -- 2.39.5