From: Jason Dillaman Date: Thu, 2 Feb 2017 18:54:13 +0000 (-0500) Subject: librbd: move group and diff API functions X-Git-Tag: v12.0.1~112^2~5 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c701e0689790a1dec84aea33354d62677e19fb94;p=ceph.git librbd: move group and diff API functions The group and diff_iterate API functions are already in separate units, so it's trivial to move them to the new 'api' namespace. Signed-off-by: Jason Dillaman --- diff --git a/src/librbd/CMakeLists.txt b/src/librbd/CMakeLists.txt index c7b003b46675b..456c2d8f58295 100644 --- a/src/librbd/CMakeLists.txt +++ b/src/librbd/CMakeLists.txt @@ -7,9 +7,7 @@ set(librbd_internal_srcs AsyncObjectThrottle.cc AsyncOperation.cc AsyncRequest.cc - DiffIterate.cc ExclusiveLock.cc - Group.cc ImageCtx.cc ImageState.cc ImageWatcher.cc @@ -23,6 +21,8 @@ set(librbd_internal_srcs Operations.cc Utils.cc Watcher.cc + api/DiffIterate.cc + api/Group.cc api/Image.cc api/Mirror.cc cache/ImageWriteback.cc diff --git a/src/librbd/DiffIterate.cc b/src/librbd/DiffIterate.cc deleted file mode 100644 index d24153e13f440..0000000000000 --- a/src/librbd/DiffIterate.cc +++ /dev/null @@ -1,461 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "librbd/DiffIterate.h" -#include "librbd/ImageCtx.h" -#include "librbd/ObjectMap.h" -#include "librbd/Utils.h" -#include "include/rados/librados.hpp" -#include "include/interval_set.h" -#include "common/errno.h" -#include "common/Throttle.h" -#include "librados/snap_set_diff.h" -#include -#include -#include -#include - -#define dout_subsys ceph_subsys_rbd -#undef dout_prefix -#define dout_prefix *_dout << "librbd::DiffIterate: " - -namespace librbd { - -namespace { - -enum ObjectDiffState { - OBJECT_DIFF_STATE_NONE = 0, - OBJECT_DIFF_STATE_UPDATED = 1, - OBJECT_DIFF_STATE_HOLE = 2 -}; - -struct DiffContext { - DiffIterate::Callback callback; - void *callback_arg; - bool whole_object; - uint64_t from_snap_id; - uint64_t end_snap_id; - interval_set parent_diff; - OrderedThrottle throttle; - - DiffContext(ImageCtx &image_ctx, DiffIterate::Callback callback, - void *callback_arg, bool _whole_object, uint64_t _from_snap_id, - uint64_t _end_snap_id) - : callback(callback), callback_arg(callback_arg), - whole_object(_whole_object), from_snap_id(_from_snap_id), - end_snap_id(_end_snap_id), - throttle(image_ctx.concurrent_management_ops, true) { - } -}; - -class C_DiffObject : public Context { -public: - C_DiffObject(ImageCtx &image_ctx, librados::IoCtx &head_ctx, - DiffContext &diff_context, const std::string &oid, - uint64_t offset, const std::vector &object_extents) - : m_image_ctx(image_ctx), m_head_ctx(head_ctx), - m_diff_context(diff_context), m_oid(oid), m_offset(offset), - m_object_extents(object_extents), m_snap_ret(0) { - } - - void send() { - C_OrderedThrottle *ctx = m_diff_context.throttle.start_op(this); - librados::AioCompletion *rados_completion = - util::create_rados_callback(ctx); - - librados::ObjectReadOperation op; - op.list_snaps(&m_snap_set, &m_snap_ret); - - int r = m_head_ctx.aio_operate(m_oid, rados_completion, &op, NULL); - assert(r == 0); - rados_completion->release(); - } - -protected: - typedef boost::tuple Diff; - typedef std::list Diffs; - - void finish(int r) override { - CephContext *cct = m_image_ctx.cct; - if (r == 0 && m_snap_ret < 0) { - r = m_snap_ret; - } - - Diffs diffs; - if (r == 0) { - ldout(cct, 20) << "object " << m_oid << ": list_snaps complete" << dendl; - compute_diffs(&diffs); - } else if (r == -ENOENT) { - ldout(cct, 20) << "object " << m_oid << ": list_snaps (not found)" - << dendl; - r = 0; - compute_parent_overlap(&diffs); - } else { - ldout(cct, 20) << "object " << m_oid << ": list_snaps failed: " - << cpp_strerror(r) << dendl; - } - - if (r == 0) { - for (Diffs::const_iterator d = diffs.begin(); d != diffs.end(); ++d) { - r = m_diff_context.callback(d->get<0>(), d->get<1>(), d->get<2>(), - m_diff_context.callback_arg); - if (r < 0) { - break; - } - } - } - m_diff_context.throttle.end_op(r); - } - -private: - ImageCtx &m_image_ctx; - librados::IoCtx &m_head_ctx; - DiffContext &m_diff_context; - std::string m_oid; - uint64_t m_offset; - std::vector m_object_extents; - - librados::snap_set_t m_snap_set; - int m_snap_ret; - - void compute_diffs(Diffs *diffs) { - CephContext *cct = m_image_ctx.cct; - - // calc diff from from_snap_id -> to_snap_id - interval_set diff; - uint64_t end_size; - bool end_exists; - librados::snap_t clone_end_snap_id; - calc_snap_set_diff(cct, m_snap_set, m_diff_context.from_snap_id, - m_diff_context.end_snap_id, &diff, &end_size, - &end_exists, &clone_end_snap_id); - ldout(cct, 20) << " diff " << diff << " end_exists=" << end_exists - << dendl; - if (diff.empty()) { - if (m_diff_context.from_snap_id == 0 && !end_exists) { - compute_parent_overlap(diffs); - } - return; - } else if (m_diff_context.whole_object) { - // provide the full object extents to the callback - for (vector::iterator q = m_object_extents.begin(); - q != m_object_extents.end(); ++q) { - diffs->push_back(boost::make_tuple(m_offset + q->offset, q->length, - end_exists)); - } - return; - } - - for (vector::iterator q = m_object_extents.begin(); - q != m_object_extents.end(); ++q) { - ldout(cct, 20) << "diff_iterate object " << m_oid << " extent " - << q->offset << "~" << q->length << " from " - << q->buffer_extents << dendl; - uint64_t opos = q->offset; - for (vector >::iterator r = - q->buffer_extents.begin(); - r != q->buffer_extents.end(); ++r) { - interval_set overlap; // object extents - overlap.insert(opos, r->second); - overlap.intersection_of(diff); - ldout(m_image_ctx.cct, 20) << " opos " << opos - << " buf " << r->first << "~" << r->second - << " overlap " << overlap << dendl; - for (interval_set::iterator s = overlap.begin(); - s != overlap.end(); ++s) { - uint64_t su_off = s.get_start() - opos; - uint64_t logical_off = m_offset + r->first + su_off; - ldout(cct, 20) << " overlap extent " << s.get_start() << "~" - << s.get_len() << " logical " << logical_off << "~" - << s.get_len() << dendl; - diffs->push_back(boost::make_tuple(logical_off, s.get_len(), - end_exists)); - } - opos += r->second; - } - assert(opos == q->offset + q->length); - } - } - - void compute_parent_overlap(Diffs *diffs) { - if (m_diff_context.from_snap_id == 0 && - !m_diff_context.parent_diff.empty()) { - // report parent diff instead - for (vector::iterator q = m_object_extents.begin(); - q != m_object_extents.end(); ++q) { - for (vector >::iterator r = - q->buffer_extents.begin(); - r != q->buffer_extents.end(); ++r) { - interval_set o; - o.insert(m_offset + r->first, r->second); - o.intersection_of(m_diff_context.parent_diff); - ldout(m_image_ctx.cct, 20) << " reporting parent overlap " << o - << dendl; - for (interval_set::iterator s = o.begin(); s != o.end(); - ++s) { - diffs->push_back(boost::make_tuple(s.get_start(), s.get_len(), - true)); - } - } - } - } - } -}; - -} // anonymous namespace - -int DiffIterate::execute() { - CephContext* cct = m_image_ctx.cct; - - librados::IoCtx head_ctx; - librados::snap_t from_snap_id = 0; - librados::snap_t end_snap_id; - uint64_t from_size = 0; - uint64_t end_size; - { - RWLock::RLocker md_locker(m_image_ctx.md_lock); - RWLock::RLocker snap_locker(m_image_ctx.snap_lock); - head_ctx.dup(m_image_ctx.data_ctx); - if (m_from_snap_name) { - from_snap_id = m_image_ctx.get_snap_id(m_from_snap_name); - from_size = m_image_ctx.get_image_size(from_snap_id); - } - end_snap_id = m_image_ctx.snap_id; - end_size = m_image_ctx.get_image_size(end_snap_id); - } - - if (from_snap_id == CEPH_NOSNAP) { - return -ENOENT; - } - if (from_snap_id == end_snap_id) { - // no diff. - return 0; - } - if (from_snap_id >= end_snap_id) { - return -EINVAL; - } - - int r; - bool fast_diff_enabled = false; - BitVector<2> object_diff_state; - { - RWLock::RLocker snap_locker(m_image_ctx.snap_lock); - if (m_whole_object && (m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) { - r = diff_object_map(from_snap_id, end_snap_id, &object_diff_state); - if (r < 0) { - ldout(cct, 5) << "fast diff disabled" << dendl; - } else { - ldout(cct, 5) << "fast diff enabled" << dendl; - fast_diff_enabled = true; - } - } - } - - // we must list snaps via the head, not end snap - head_ctx.snap_set_read(CEPH_SNAPDIR); - - ldout(cct, 5) << "diff_iterate from " << from_snap_id << " to " - << end_snap_id << " size from " << from_size - << " to " << end_size << dendl; - - // check parent overlap only if we are comparing to the beginning of time - DiffContext diff_context(m_image_ctx, m_callback, m_callback_arg, - m_whole_object, from_snap_id, end_snap_id); - if (m_include_parent && from_snap_id == 0) { - RWLock::RLocker l(m_image_ctx.snap_lock); - RWLock::RLocker l2(m_image_ctx.parent_lock); - uint64_t overlap = 0; - m_image_ctx.get_parent_overlap(m_image_ctx.snap_id, &overlap); - r = 0; - if (m_image_ctx.parent && overlap > 0) { - ldout(cct, 10) << " first getting parent diff" << dendl; - DiffIterate diff_parent(*m_image_ctx.parent, NULL, 0, overlap, - m_include_parent, m_whole_object, - &DiffIterate::simple_diff_cb, - &diff_context.parent_diff); - r = diff_parent.execute(); - } - if (r < 0) { - return r; - } - } - - uint64_t period = m_image_ctx.get_stripe_period(); - uint64_t off = m_offset; - uint64_t left = m_length; - - while (left > 0) { - uint64_t period_off = off - (off % period); - uint64_t read_len = min(period_off + period - off, left); - - // map to extents - map > object_extents; - Striper::file_to_extents(cct, m_image_ctx.format_string, - &m_image_ctx.layout, off, read_len, 0, - object_extents, 0); - - // get snap info for each object - for (map >::iterator p = - object_extents.begin(); - p != object_extents.end(); ++p) { - ldout(cct, 20) << "object " << p->first << dendl; - - if (fast_diff_enabled) { - const uint64_t object_no = p->second.front().objectno; - if (object_diff_state[object_no] != OBJECT_DIFF_STATE_NONE) { - bool updated = (object_diff_state[object_no] == - OBJECT_DIFF_STATE_UPDATED); - for (std::vector::iterator q = p->second.begin(); - q != p->second.end(); ++q) { - r = m_callback(off + q->offset, q->length, updated, m_callback_arg); - if (r < 0) { - return r; - } - } - } - } else { - C_DiffObject *diff_object = new C_DiffObject(m_image_ctx, head_ctx, - diff_context, - p->first.name, off, - p->second); - diff_object->send(); - - if (diff_context.throttle.pending_error()) { - r = diff_context.throttle.wait_for_ret(); - return r; - } - } - } - - left -= read_len; - off += read_len; - } - - r = diff_context.throttle.wait_for_ret(); - if (r < 0) { - return r; - } - return 0; -} - -int DiffIterate::diff_object_map(uint64_t from_snap_id, uint64_t to_snap_id, - BitVector<2>* object_diff_state) { - assert(m_image_ctx.snap_lock.is_locked()); - CephContext* cct = m_image_ctx.cct; - - bool diff_from_start = (from_snap_id == 0); - if (from_snap_id == 0) { - if (!m_image_ctx.snaps.empty()) { - from_snap_id = m_image_ctx.snaps.back(); - } else { - from_snap_id = CEPH_NOSNAP; - } - } - - object_diff_state->clear(); - uint64_t current_snap_id = from_snap_id; - uint64_t next_snap_id = to_snap_id; - BitVector<2> prev_object_map; - bool prev_object_map_valid = false; - while (true) { - uint64_t current_size = m_image_ctx.size; - if (current_snap_id != CEPH_NOSNAP) { - std::map::const_iterator snap_it = - m_image_ctx.snap_info.find(current_snap_id); - assert(snap_it != m_image_ctx.snap_info.end()); - current_size = snap_it->second.size; - - ++snap_it; - if (snap_it != m_image_ctx.snap_info.end()) { - next_snap_id = snap_it->first; - } else { - next_snap_id = CEPH_NOSNAP; - } - } - - uint64_t flags; - int r = m_image_ctx.get_flags(from_snap_id, &flags); - if (r < 0) { - lderr(cct) << "diff_object_map: failed to retrieve image flags" << dendl; - return r; - } - if ((flags & RBD_FLAG_FAST_DIFF_INVALID) != 0) { - ldout(cct, 1) << "diff_object_map: cannot perform fast diff on invalid " - << "object map" << dendl; - return -EINVAL; - } - - BitVector<2> object_map; - std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, - current_snap_id)); - r = cls_client::object_map_load(&m_image_ctx.md_ctx, oid, &object_map); - if (r < 0) { - lderr(cct) << "diff_object_map: failed to load object map " << oid - << dendl; - return r; - } - ldout(cct, 20) << "diff_object_map: loaded object map " << oid << dendl; - - uint64_t num_objs = Striper::get_num_objects(m_image_ctx.layout, - current_size); - if (object_map.size() < num_objs) { - ldout(cct, 1) << "diff_object_map: object map too small: " - << object_map.size() << " < " << num_objs << dendl; - return -EINVAL; - } - object_map.resize(num_objs); - - uint64_t overlap = MIN(object_map.size(), prev_object_map.size()); - for (uint64_t i = 0; i < overlap; ++i) { - ldout(cct, 20) << __func__ << ": object state: " << i << " " - << static_cast(prev_object_map[i]) - << "->" << static_cast(object_map[i]) << dendl; - if (object_map[i] == OBJECT_NONEXISTENT) { - if (prev_object_map[i] != OBJECT_NONEXISTENT) { - (*object_diff_state)[i] = OBJECT_DIFF_STATE_HOLE; - } - } else if (object_map[i] == OBJECT_EXISTS || - (prev_object_map[i] != object_map[i] && - !(prev_object_map[i] == OBJECT_EXISTS && - object_map[i] == OBJECT_EXISTS_CLEAN))) { - (*object_diff_state)[i] = OBJECT_DIFF_STATE_UPDATED; - } - } - ldout(cct, 20) << "diff_object_map: computed overlap diffs" << dendl; - - object_diff_state->resize(object_map.size()); - if (object_map.size() > prev_object_map.size() && - (diff_from_start || prev_object_map_valid)) { - for (uint64_t i = overlap; i < object_diff_state->size(); ++i) { - ldout(cct, 20) << __func__ << ": object state: " << i << " " - << "->" << static_cast(object_map[i]) << dendl; - if (object_map[i] == OBJECT_NONEXISTENT) { - (*object_diff_state)[i] = OBJECT_DIFF_STATE_NONE; - } else { - (*object_diff_state)[i] = OBJECT_DIFF_STATE_UPDATED; - } - } - } - ldout(cct, 20) << "diff_object_map: computed resize diffs" << dendl; - - if (current_snap_id == next_snap_id || next_snap_id > to_snap_id) { - break; - } - current_snap_id = next_snap_id; - prev_object_map = object_map; - prev_object_map_valid = true; - } - return 0; -} - -int DiffIterate::simple_diff_cb(uint64_t off, size_t len, int exists, - void *arg) { - // it's possible for a discard to create a hole in the parent image -- ignore - if (exists) { - interval_set *diff = static_cast *>(arg); - diff->insert(off, len); - } - return 0; -} - -} // namespace librbd diff --git a/src/librbd/DiffIterate.h b/src/librbd/DiffIterate.h deleted file mode 100644 index 6b80af3ad68b6..0000000000000 --- a/src/librbd/DiffIterate.h +++ /dev/null @@ -1,47 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -#ifndef CEPH_LIBRBD_DIFF_ITERATE_H -#define CEPH_LIBRBD_DIFF_ITERATE_H - -#include "include/int_types.h" -#include "common/bit_vector.hpp" - -namespace librbd { - -class ImageCtx; - -class DiffIterate { -public: - typedef int (*Callback)(uint64_t, size_t, int, void *); - - DiffIterate(ImageCtx &image_ctx, const char *from_snap_name, uint64_t off, - uint64_t len, bool include_parent, bool whole_object, - Callback callback, void *callback_arg) - : m_image_ctx(image_ctx), m_from_snap_name(from_snap_name), m_offset(off), - m_length(len), m_include_parent(include_parent), - m_whole_object(whole_object), m_callback(callback), - m_callback_arg(callback_arg) - { - } - - int execute(); - -private: - ImageCtx &m_image_ctx; - const char* m_from_snap_name; - uint64_t m_offset; - uint64_t m_length; - bool m_include_parent; - bool m_whole_object; - Callback m_callback; - void *m_callback_arg; - - int diff_object_map(uint64_t from_snap_id, uint64_t to_snap_id, - BitVector<2>* object_diff_state); - - static int simple_diff_cb(uint64_t off, size_t len, int exists, void *arg); -}; - -} // namespace librbd - -#endif // CEPH_LIBRBD_DIFF_ITERATE_H diff --git a/src/librbd/Group.cc b/src/librbd/Group.cc deleted file mode 100644 index 8e3d82b2e8ccc..0000000000000 --- a/src/librbd/Group.cc +++ /dev/null @@ -1,385 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "common/errno.h" - -#include "librbd/Group.h" -#include "librbd/ImageState.h" -#include "librbd/Utils.h" -#include "librbd/io/AioCompletion.h" - -#define dout_subsys ceph_subsys_rbd -#undef dout_prefix -#define dout_prefix *_dout << "librbd::Group: " - -using std::map; -using std::pair; -using std::set; -using std::string; -using std::vector; -// list binds to list() here, so std::list is explicitly used below - -using ceph::bufferlist; -using librados::snap_t; -using librados::IoCtx; -using librados::Rados; - -namespace librbd { - -// Consistency groups functions - -int group_create(librados::IoCtx& io_ctx, const char *group_name) -{ - CephContext *cct = (CephContext *)io_ctx.cct(); - - Rados rados(io_ctx); - uint64_t bid = rados.get_instance_id(); - - uint32_t extra = rand() % 0xFFFFFFFF; - ostringstream bid_ss; - bid_ss << std::hex << bid << std::hex << extra; - string id = bid_ss.str(); - - ldout(cct, 2) << "adding consistency group to directory..." << dendl; - - int r = cls_client::group_dir_add(&io_ctx, RBD_GROUP_DIRECTORY, group_name, id); - if (r < 0) { - lderr(cct) << "error adding consistency group to directory: " - << cpp_strerror(r) - << dendl; - return r; - } - string header_oid = util::group_header_name(id); - - r = cls_client::group_create(&io_ctx, header_oid); - if (r < 0) { - lderr(cct) << "error writing header: " << cpp_strerror(r) << dendl; - goto err_remove_from_dir; - } - - return 0; - -err_remove_from_dir: - int remove_r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY, - group_name, id); - if (remove_r < 0) { - lderr(cct) << "error cleaning up consistency group from rbd_directory " - << "object after creation failed: " << cpp_strerror(remove_r) - << dendl; - } - - return r; -} - -int group_remove(librados::IoCtx& io_ctx, const char *group_name) -{ - CephContext *cct((CephContext *)io_ctx.cct()); - ldout(cct, 20) << "group_remove " << &io_ctx << " " << group_name << dendl; - - std::vector images; - int r = group_image_list(io_ctx, group_name, &images); - if (r < 0 && r != -ENOENT) { - lderr(cct) << "error listing group images" << dendl; - return r; - } - - for (auto i : images) { - librados::Rados rados(io_ctx); - IoCtx image_ioctx; - rados.ioctx_create2(i.pool, image_ioctx); - r = group_image_remove(io_ctx, group_name, image_ioctx, i.name.c_str()); - if (r < 0 && r != -ENOENT) { - lderr(cct) << "error removing image from a group" << dendl; - return r; - } - } - - std::string group_id; - r = cls_client::dir_get_id(&io_ctx, RBD_GROUP_DIRECTORY, - std::string(group_name), &group_id); - if (r < 0 && r != -ENOENT) { - lderr(cct) << "error getting id of group" << dendl; - return r; - } - - string header_oid = util::group_header_name(group_id); - - r = io_ctx.remove(header_oid); - if (r < 0 && r != -ENOENT) { - lderr(cct) << "error removing header: " << cpp_strerror(-r) << dendl; - return r; - } - - r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY, - group_name, group_id); - if (r < 0 && r != -ENOENT) { - lderr(cct) << "error removing group from directory" << dendl; - return r; - } - - return 0; -} - -int group_list(IoCtx& io_ctx, vector *names) -{ - CephContext *cct = (CephContext *)io_ctx.cct(); - ldout(cct, 20) << "group_list " << &io_ctx << dendl; - - int max_read = 1024; - string last_read = ""; - int r; - do { - map groups; - r = cls_client::group_dir_list(&io_ctx, RBD_GROUP_DIRECTORY, last_read, - max_read, &groups); - if (r < 0) { - lderr(cct) << "error listing group in directory: " - << cpp_strerror(r) << dendl; - return r; - } - for (pair group : groups) { - names->push_back(group.first); - } - if (!groups.empty()) { - last_read = groups.rbegin()->first; - } - r = groups.size(); - } while (r == max_read); - - return 0; -} - -int group_image_add(librados::IoCtx& group_ioctx, const char *group_name, - librados::IoCtx& image_ioctx, const char *image_name) -{ - CephContext *cct = (CephContext *)group_ioctx.cct(); - ldout(cct, 20) << "group_image_add " << &group_ioctx - << " group name " << group_name << " image " - << &image_ioctx << " name " << image_name << dendl; - - string group_id; - - int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, group_name, &group_id); - if (r < 0) { - lderr(cct) << "error reading consistency group id object: " - << cpp_strerror(r) - << dendl; - return r; - } - string group_header_oid = util::group_header_name(group_id); - - - ldout(cct, 20) << "adding image to group name " << group_name - << " group id " << group_header_oid << dendl; - - string image_id; - - r = cls_client::dir_get_id(&image_ioctx, RBD_DIRECTORY, image_name, &image_id); - if (r < 0) { - lderr(cct) << "error reading image id object: " - << cpp_strerror(-r) << dendl; - return r; - } - - string image_header_oid = util::header_name(image_id); - - ldout(cct, 20) << "adding image " << image_name - << " image id " << image_header_oid << dendl; - - cls::rbd::GroupImageStatus incomplete_st(image_id, image_ioctx.get_id(), - cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE); - cls::rbd::GroupImageStatus attached_st(image_id, image_ioctx.get_id(), - cls::rbd::GROUP_IMAGE_LINK_STATE_ATTACHED); - - r = cls_client::group_image_set(&group_ioctx, group_header_oid, - incomplete_st); - - cls::rbd::GroupSpec group_spec(group_id, group_ioctx.get_id()); - - if (r < 0) { - lderr(cct) << "error adding image reference to consistency group: " - << cpp_strerror(-r) << dendl; - return r; - } - - r = cls_client::image_add_group(&image_ioctx, image_header_oid, - group_spec); - if (r < 0) { - lderr(cct) << "error adding group reference to image: " - << cpp_strerror(-r) << dendl; - cls::rbd::GroupImageSpec spec(image_id, image_ioctx.get_id()); - cls_client::group_image_remove(&group_ioctx, group_header_oid, spec); - // Ignore errors in the clean up procedure. - return r; - } - - r = cls_client::group_image_set(&group_ioctx, group_header_oid, - attached_st); - - return r; -} - -int group_image_remove(librados::IoCtx& group_ioctx, const char *group_name, - librados::IoCtx& image_ioctx, const char *image_name) -{ - CephContext *cct = (CephContext *)group_ioctx.cct(); - ldout(cct, 20) << "group_remove_image " << &group_ioctx - << " group name " << group_name << " image " - << &image_ioctx << " name " << image_name << dendl; - - string group_id; - - int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, group_name, &group_id); - if (r < 0) { - lderr(cct) << "error reading consistency group id object: " - << cpp_strerror(r) - << dendl; - return r; - } - string group_header_oid = util::group_header_name(group_id); - - ldout(cct, 20) << "adding image to group name " << group_name - << " group id " << group_header_oid << dendl; - - string image_id; - r = cls_client::dir_get_id(&image_ioctx, RBD_DIRECTORY, image_name, &image_id); - if (r < 0) { - lderr(cct) << "error reading image id object: " - << cpp_strerror(-r) << dendl; - return r; - } - - string image_header_oid = util::header_name(image_id); - - ldout(cct, 20) << "removing image " << image_name - << " image id " << image_header_oid << dendl; - - cls::rbd::GroupSpec group_spec(group_id, group_ioctx.get_id()); - - cls::rbd::GroupImageStatus incomplete_st(image_id, image_ioctx.get_id(), - cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE); - - cls::rbd::GroupImageSpec spec(image_id, image_ioctx.get_id()); - - r = cls_client::group_image_set(&group_ioctx, group_header_oid, - incomplete_st); - - if (r < 0) { - lderr(cct) << "couldn't put image into removing state: " - << cpp_strerror(-r) << dendl; - return r; - } - - r = cls_client::image_remove_group(&image_ioctx, image_header_oid, - group_spec); - if ((r < 0) && (r != -ENOENT)) { - lderr(cct) << "couldn't remove group reference from image" - << cpp_strerror(-r) << dendl; - return r; - } - - r = cls_client::group_image_remove(&group_ioctx, group_header_oid, spec); - if (r < 0) { - lderr(cct) << "couldn't remove image from group" - << cpp_strerror(-r) << dendl; - return r; - } - - return 0; -} - -int group_image_list(librados::IoCtx& group_ioctx, - const char *group_name, - std::vector *images) -{ - CephContext *cct = (CephContext *)group_ioctx.cct(); - ldout(cct, 20) << "group_image_list " << &group_ioctx - << " group name " << group_name << dendl; - - string group_id; - - int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, - group_name, &group_id); - if (r < 0) { - lderr(cct) << "error reading consistency group id object: " - << cpp_strerror(r) - << dendl; - return r; - } - string group_header_oid = util::group_header_name(group_id); - - ldout(cct, 20) << "listing images in group name " - << group_name << " group id " << group_header_oid << dendl; - - std::vector image_ids; - - const int max_read = 1024; - do { - std::vector image_ids_page; - cls::rbd::GroupImageSpec start_last; - - r = cls_client::group_image_list(&group_ioctx, group_header_oid, - start_last, max_read, &image_ids_page); - - if (r < 0) { - lderr(cct) << "error reading image list from consistency group: " - << cpp_strerror(-r) << dendl; - return r; - } - image_ids.insert(image_ids.end(), - image_ids_page.begin(), image_ids_page.end()); - - if (image_ids_page.size() > 0) - start_last = image_ids_page.rbegin()->spec; - - r = image_ids_page.size(); - } while (r == max_read); - - for (auto i : image_ids) { - librados::Rados rados(group_ioctx); - IoCtx ioctx; - rados.ioctx_create2(i.spec.pool_id, ioctx); - std::string image_name; - r = cls_client::dir_get_name(&ioctx, RBD_DIRECTORY, - i.spec.image_id, &image_name); - if (r < 0) { - return r; - } - - images->push_back( - group_image_status_t { - image_name, - i.spec.pool_id, - static_cast(i.state)}); - } - - return 0; -} - -int image_get_group(ImageCtx *ictx, group_spec_t *group_spec) -{ - int r = ictx->state->refresh_if_required(); - if (r < 0) - return r; - - if (-1 != ictx->group_spec.pool_id) { - librados::Rados rados(ictx->md_ctx); - IoCtx ioctx; - rados.ioctx_create2(ictx->group_spec.pool_id, ioctx); - - std::string group_name; - r = cls_client::dir_get_name(&ioctx, RBD_GROUP_DIRECTORY, - ictx->group_spec.group_id, &group_name); - if (r < 0) - return r; - group_spec->pool = ictx->group_spec.pool_id; - group_spec->name = group_name; - } else { - group_spec->pool = -1; - group_spec->name = ""; - } - - return 0; -} - -} // namespace librbd diff --git a/src/librbd/Group.h b/src/librbd/Group.h deleted file mode 100644 index 87b638b9c8c9f..0000000000000 --- a/src/librbd/Group.h +++ /dev/null @@ -1,30 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#ifndef CEPH_LIBRBD_GROUP_H -#define CEPH_LIBRBD_GROUP_H - -#include "include/rados/librados.hpp" -#include "include/rbd/librbd.hpp" -#include -#include - -namespace librbd { - -struct ImageCtx; - -// Consistency groups functions -int group_create(librados::IoCtx& io_ctx, const char *imgname); -int group_remove(librados::IoCtx& io_ctx, const char *group_name); -int group_list(librados::IoCtx& io_ctx, std::vector *names); -int group_image_add(librados::IoCtx& group_ioctx, const char *group_name, - librados::IoCtx& image_ioctx, const char *image_name); -int group_image_remove(librados::IoCtx& group_ioctx, const char *group_name, - librados::IoCtx& image_ioctx, const char *image_name); -int group_image_list(librados::IoCtx& group_ioctx, const char *group_name, - std::vector *images); -int image_get_group(ImageCtx *ictx, group_spec_t *group_spec); - -} // namespace librbd - -#endif // CEPH_LIBRBD_GROUP_H diff --git a/src/librbd/api/DiffIterate.cc b/src/librbd/api/DiffIterate.cc new file mode 100644 index 0000000000000..28b3b83eefd65 --- /dev/null +++ b/src/librbd/api/DiffIterate.cc @@ -0,0 +1,503 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "librbd/api/DiffIterate.h" +#include "librbd/ImageCtx.h" +#include "librbd/ImageState.h" +#include "librbd/ObjectMap.h" +#include "librbd/Utils.h" +#include "librbd/internal.h" +#include "include/rados/librados.hpp" +#include "include/interval_set.h" +#include "common/errno.h" +#include "common/Throttle.h" +#include "librados/snap_set_diff.h" +#include +#include +#include +#include + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::DiffIterate: " + +namespace librbd { +namespace api { + +namespace { + +enum ObjectDiffState { + OBJECT_DIFF_STATE_NONE = 0, + OBJECT_DIFF_STATE_UPDATED = 1, + OBJECT_DIFF_STATE_HOLE = 2 +}; + +struct DiffContext { + DiffIterate<>::Callback callback; + void *callback_arg; + bool whole_object; + uint64_t from_snap_id; + uint64_t end_snap_id; + interval_set parent_diff; + OrderedThrottle throttle; + + template + DiffContext(I &image_ctx, DiffIterate<>::Callback callback, + void *callback_arg, bool _whole_object, uint64_t _from_snap_id, + uint64_t _end_snap_id) + : callback(callback), callback_arg(callback_arg), + whole_object(_whole_object), from_snap_id(_from_snap_id), + end_snap_id(_end_snap_id), + throttle(image_ctx.concurrent_management_ops, true) { + } +}; + +class C_DiffObject : public Context { +public: + template + C_DiffObject(I &image_ctx, librados::IoCtx &head_ctx, + DiffContext &diff_context, const std::string &oid, + uint64_t offset, const std::vector &object_extents) + : m_cct(image_ctx.cct), m_head_ctx(head_ctx), + m_diff_context(diff_context), m_oid(oid), m_offset(offset), + m_object_extents(object_extents), m_snap_ret(0) { + } + + void send() { + C_OrderedThrottle *ctx = m_diff_context.throttle.start_op(this); + librados::AioCompletion *rados_completion = + util::create_rados_callback(ctx); + + librados::ObjectReadOperation op; + op.list_snaps(&m_snap_set, &m_snap_ret); + + int r = m_head_ctx.aio_operate(m_oid, rados_completion, &op, NULL); + assert(r == 0); + rados_completion->release(); + } + +protected: + typedef boost::tuple Diff; + typedef std::list Diffs; + + void finish(int r) override { + CephContext *cct = m_cct; + if (r == 0 && m_snap_ret < 0) { + r = m_snap_ret; + } + + Diffs diffs; + if (r == 0) { + ldout(cct, 20) << "object " << m_oid << ": list_snaps complete" << dendl; + compute_diffs(&diffs); + } else if (r == -ENOENT) { + ldout(cct, 20) << "object " << m_oid << ": list_snaps (not found)" + << dendl; + r = 0; + compute_parent_overlap(&diffs); + } else { + ldout(cct, 20) << "object " << m_oid << ": list_snaps failed: " + << cpp_strerror(r) << dendl; + } + + if (r == 0) { + for (Diffs::const_iterator d = diffs.begin(); d != diffs.end(); ++d) { + r = m_diff_context.callback(d->get<0>(), d->get<1>(), d->get<2>(), + m_diff_context.callback_arg); + if (r < 0) { + break; + } + } + } + m_diff_context.throttle.end_op(r); + } + +private: + CephContext *m_cct; + librados::IoCtx &m_head_ctx; + DiffContext &m_diff_context; + std::string m_oid; + uint64_t m_offset; + std::vector m_object_extents; + + librados::snap_set_t m_snap_set; + int m_snap_ret; + + void compute_diffs(Diffs *diffs) { + CephContext *cct = m_cct; + + // calc diff from from_snap_id -> to_snap_id + interval_set diff; + uint64_t end_size; + bool end_exists; + librados::snap_t clone_end_snap_id; + calc_snap_set_diff(cct, m_snap_set, m_diff_context.from_snap_id, + m_diff_context.end_snap_id, &diff, &end_size, + &end_exists, &clone_end_snap_id); + ldout(cct, 20) << " diff " << diff << " end_exists=" << end_exists + << dendl; + if (diff.empty()) { + if (m_diff_context.from_snap_id == 0 && !end_exists) { + compute_parent_overlap(diffs); + } + return; + } else if (m_diff_context.whole_object) { + // provide the full object extents to the callback + for (vector::iterator q = m_object_extents.begin(); + q != m_object_extents.end(); ++q) { + diffs->push_back(boost::make_tuple(m_offset + q->offset, q->length, + end_exists)); + } + return; + } + + for (vector::iterator q = m_object_extents.begin(); + q != m_object_extents.end(); ++q) { + ldout(cct, 20) << "diff_iterate object " << m_oid << " extent " + << q->offset << "~" << q->length << " from " + << q->buffer_extents << dendl; + uint64_t opos = q->offset; + for (vector >::iterator r = + q->buffer_extents.begin(); + r != q->buffer_extents.end(); ++r) { + interval_set overlap; // object extents + overlap.insert(opos, r->second); + overlap.intersection_of(diff); + ldout(cct, 20) << " opos " << opos + << " buf " << r->first << "~" << r->second + << " overlap " << overlap << dendl; + for (interval_set::iterator s = overlap.begin(); + s != overlap.end(); ++s) { + uint64_t su_off = s.get_start() - opos; + uint64_t logical_off = m_offset + r->first + su_off; + ldout(cct, 20) << " overlap extent " << s.get_start() << "~" + << s.get_len() << " logical " << logical_off << "~" + << s.get_len() << dendl; + diffs->push_back(boost::make_tuple(logical_off, s.get_len(), + end_exists)); + } + opos += r->second; + } + assert(opos == q->offset + q->length); + } + } + + void compute_parent_overlap(Diffs *diffs) { + if (m_diff_context.from_snap_id == 0 && + !m_diff_context.parent_diff.empty()) { + // report parent diff instead + for (vector::iterator q = m_object_extents.begin(); + q != m_object_extents.end(); ++q) { + for (vector >::iterator r = + q->buffer_extents.begin(); + r != q->buffer_extents.end(); ++r) { + interval_set o; + o.insert(m_offset + r->first, r->second); + o.intersection_of(m_diff_context.parent_diff); + ldout(m_cct, 20) << " reporting parent overlap " << o << dendl; + for (interval_set::iterator s = o.begin(); s != o.end(); + ++s) { + diffs->push_back(boost::make_tuple(s.get_start(), s.get_len(), + true)); + } + } + } + } + } +}; + +int simple_diff_cb(uint64_t off, size_t len, int exists, void *arg) { + // it's possible for a discard to create a hole in the parent image -- ignore + if (exists) { + interval_set *diff = static_cast *>(arg); + diff->insert(off, len); + } + return 0; +} + +} // anonymous namespace + +template +int DiffIterate::diff_iterate(I *ictx, const char *fromsnapname, + uint64_t off, uint64_t len, + bool include_parent, bool whole_object, + int (*cb)(uint64_t, size_t, int, void *), + void *arg) +{ + ldout(ictx->cct, 20) << "diff_iterate " << ictx << " off = " << off + << " len = " << len << dendl; + + // ensure previous writes are visible to listsnaps + { + RWLock::RLocker owner_locker(ictx->owner_lock); + ictx->flush(); + } + + int r = ictx->state->refresh_if_required(); + if (r < 0) { + return r; + } + + ictx->snap_lock.get_read(); + r = clip_io(ictx, off, &len); + ictx->snap_lock.put_read(); + if (r < 0) { + return r; + } + + DiffIterate command(*ictx, fromsnapname, off, len, include_parent, + whole_object, cb, arg); + r = command.execute(); + return r; +} + +template +int DiffIterate::execute() { + CephContext* cct = m_image_ctx.cct; + + librados::IoCtx head_ctx; + librados::snap_t from_snap_id = 0; + librados::snap_t end_snap_id; + uint64_t from_size = 0; + uint64_t end_size; + { + RWLock::RLocker md_locker(m_image_ctx.md_lock); + RWLock::RLocker snap_locker(m_image_ctx.snap_lock); + head_ctx.dup(m_image_ctx.data_ctx); + if (m_from_snap_name) { + from_snap_id = m_image_ctx.get_snap_id(m_from_snap_name); + from_size = m_image_ctx.get_image_size(from_snap_id); + } + end_snap_id = m_image_ctx.snap_id; + end_size = m_image_ctx.get_image_size(end_snap_id); + } + + if (from_snap_id == CEPH_NOSNAP) { + return -ENOENT; + } + if (from_snap_id == end_snap_id) { + // no diff. + return 0; + } + if (from_snap_id >= end_snap_id) { + return -EINVAL; + } + + int r; + bool fast_diff_enabled = false; + BitVector<2> object_diff_state; + { + RWLock::RLocker snap_locker(m_image_ctx.snap_lock); + if (m_whole_object && (m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) { + r = diff_object_map(from_snap_id, end_snap_id, &object_diff_state); + if (r < 0) { + ldout(cct, 5) << "fast diff disabled" << dendl; + } else { + ldout(cct, 5) << "fast diff enabled" << dendl; + fast_diff_enabled = true; + } + } + } + + // we must list snaps via the head, not end snap + head_ctx.snap_set_read(CEPH_SNAPDIR); + + ldout(cct, 5) << "diff_iterate from " << from_snap_id << " to " + << end_snap_id << " size from " << from_size + << " to " << end_size << dendl; + + // check parent overlap only if we are comparing to the beginning of time + DiffContext diff_context(m_image_ctx, m_callback, m_callback_arg, + m_whole_object, from_snap_id, end_snap_id); + if (m_include_parent && from_snap_id == 0) { + RWLock::RLocker l(m_image_ctx.snap_lock); + RWLock::RLocker l2(m_image_ctx.parent_lock); + uint64_t overlap = 0; + m_image_ctx.get_parent_overlap(m_image_ctx.snap_id, &overlap); + r = 0; + if (m_image_ctx.parent && overlap > 0) { + ldout(cct, 10) << " first getting parent diff" << dendl; + DiffIterate diff_parent(*m_image_ctx.parent, NULL, 0, overlap, + m_include_parent, m_whole_object, + &simple_diff_cb, + &diff_context.parent_diff); + r = diff_parent.execute(); + } + if (r < 0) { + return r; + } + } + + uint64_t period = m_image_ctx.get_stripe_period(); + uint64_t off = m_offset; + uint64_t left = m_length; + + while (left > 0) { + uint64_t period_off = off - (off % period); + uint64_t read_len = min(period_off + period - off, left); + + // map to extents + map > object_extents; + Striper::file_to_extents(cct, m_image_ctx.format_string, + &m_image_ctx.layout, off, read_len, 0, + object_extents, 0); + + // get snap info for each object + for (map >::iterator p = + object_extents.begin(); + p != object_extents.end(); ++p) { + ldout(cct, 20) << "object " << p->first << dendl; + + if (fast_diff_enabled) { + const uint64_t object_no = p->second.front().objectno; + if (object_diff_state[object_no] != OBJECT_DIFF_STATE_NONE) { + bool updated = (object_diff_state[object_no] == + OBJECT_DIFF_STATE_UPDATED); + for (std::vector::iterator q = p->second.begin(); + q != p->second.end(); ++q) { + r = m_callback(off + q->offset, q->length, updated, m_callback_arg); + if (r < 0) { + return r; + } + } + } + } else { + C_DiffObject *diff_object = new C_DiffObject(m_image_ctx, head_ctx, + diff_context, + p->first.name, off, + p->second); + diff_object->send(); + + if (diff_context.throttle.pending_error()) { + r = diff_context.throttle.wait_for_ret(); + return r; + } + } + } + + left -= read_len; + off += read_len; + } + + r = diff_context.throttle.wait_for_ret(); + if (r < 0) { + return r; + } + return 0; +} + +template +int DiffIterate::diff_object_map(uint64_t from_snap_id, uint64_t to_snap_id, + BitVector<2>* object_diff_state) { + assert(m_image_ctx.snap_lock.is_locked()); + CephContext* cct = m_image_ctx.cct; + + bool diff_from_start = (from_snap_id == 0); + if (from_snap_id == 0) { + if (!m_image_ctx.snaps.empty()) { + from_snap_id = m_image_ctx.snaps.back(); + } else { + from_snap_id = CEPH_NOSNAP; + } + } + + object_diff_state->clear(); + uint64_t current_snap_id = from_snap_id; + uint64_t next_snap_id = to_snap_id; + BitVector<2> prev_object_map; + bool prev_object_map_valid = false; + while (true) { + uint64_t current_size = m_image_ctx.size; + if (current_snap_id != CEPH_NOSNAP) { + std::map::const_iterator snap_it = + m_image_ctx.snap_info.find(current_snap_id); + assert(snap_it != m_image_ctx.snap_info.end()); + current_size = snap_it->second.size; + + ++snap_it; + if (snap_it != m_image_ctx.snap_info.end()) { + next_snap_id = snap_it->first; + } else { + next_snap_id = CEPH_NOSNAP; + } + } + + uint64_t flags; + int r = m_image_ctx.get_flags(from_snap_id, &flags); + if (r < 0) { + lderr(cct) << "diff_object_map: failed to retrieve image flags" << dendl; + return r; + } + if ((flags & RBD_FLAG_FAST_DIFF_INVALID) != 0) { + ldout(cct, 1) << "diff_object_map: cannot perform fast diff on invalid " + << "object map" << dendl; + return -EINVAL; + } + + BitVector<2> object_map; + std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, + current_snap_id)); + r = cls_client::object_map_load(&m_image_ctx.md_ctx, oid, &object_map); + if (r < 0) { + lderr(cct) << "diff_object_map: failed to load object map " << oid + << dendl; + return r; + } + ldout(cct, 20) << "diff_object_map: loaded object map " << oid << dendl; + + uint64_t num_objs = Striper::get_num_objects(m_image_ctx.layout, + current_size); + if (object_map.size() < num_objs) { + ldout(cct, 1) << "diff_object_map: object map too small: " + << object_map.size() << " < " << num_objs << dendl; + return -EINVAL; + } + object_map.resize(num_objs); + + uint64_t overlap = MIN(object_map.size(), prev_object_map.size()); + for (uint64_t i = 0; i < overlap; ++i) { + ldout(cct, 20) << __func__ << ": object state: " << i << " " + << static_cast(prev_object_map[i]) + << "->" << static_cast(object_map[i]) << dendl; + if (object_map[i] == OBJECT_NONEXISTENT) { + if (prev_object_map[i] != OBJECT_NONEXISTENT) { + (*object_diff_state)[i] = OBJECT_DIFF_STATE_HOLE; + } + } else if (object_map[i] == OBJECT_EXISTS || + (prev_object_map[i] != object_map[i] && + !(prev_object_map[i] == OBJECT_EXISTS && + object_map[i] == OBJECT_EXISTS_CLEAN))) { + (*object_diff_state)[i] = OBJECT_DIFF_STATE_UPDATED; + } + } + ldout(cct, 20) << "diff_object_map: computed overlap diffs" << dendl; + + object_diff_state->resize(object_map.size()); + if (object_map.size() > prev_object_map.size() && + (diff_from_start || prev_object_map_valid)) { + for (uint64_t i = overlap; i < object_diff_state->size(); ++i) { + ldout(cct, 20) << __func__ << ": object state: " << i << " " + << "->" << static_cast(object_map[i]) << dendl; + if (object_map[i] == OBJECT_NONEXISTENT) { + (*object_diff_state)[i] = OBJECT_DIFF_STATE_NONE; + } else { + (*object_diff_state)[i] = OBJECT_DIFF_STATE_UPDATED; + } + } + } + ldout(cct, 20) << "diff_object_map: computed resize diffs" << dendl; + + if (current_snap_id == next_snap_id || next_snap_id > to_snap_id) { + break; + } + current_snap_id = next_snap_id; + prev_object_map = object_map; + prev_object_map_valid = true; + } + return 0; +} + +} // namespace api +} // namespace librbd + +template class librbd::api::DiffIterate; diff --git a/src/librbd/api/DiffIterate.h b/src/librbd/api/DiffIterate.h new file mode 100644 index 0000000000000..7790dcd6a87c9 --- /dev/null +++ b/src/librbd/api/DiffIterate.h @@ -0,0 +1,59 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_API_DIFF_ITERATE_H +#define CEPH_LIBRBD_API_DIFF_ITERATE_H + +#include "include/int_types.h" +#include "common/bit_vector.hpp" + +namespace librbd { + +class ImageCtx; + +namespace api { + +template +class DiffIterate { +public: + typedef int (*Callback)(uint64_t, size_t, int, void *); + + static int diff_iterate(ImageCtxT *ictx, const char *fromsnapname, + uint64_t off, uint64_t len, bool include_parent, + bool whole_object, + int (*cb)(uint64_t, size_t, int, void *), + void *arg); + +private: + ImageCtxT &m_image_ctx; + const char* m_from_snap_name; + uint64_t m_offset; + uint64_t m_length; + bool m_include_parent; + bool m_whole_object; + Callback m_callback; + void *m_callback_arg; + + DiffIterate(ImageCtxT &image_ctx, const char *from_snap_name, uint64_t off, + uint64_t len, bool include_parent, bool whole_object, + Callback callback, void *callback_arg) + : m_image_ctx(image_ctx), m_from_snap_name(from_snap_name), m_offset(off), + m_length(len), m_include_parent(include_parent), + m_whole_object(whole_object), m_callback(callback), + m_callback_arg(callback_arg) + { + } + + int execute(); + + int diff_object_map(uint64_t from_snap_id, uint64_t to_snap_id, + BitVector<2>* object_diff_state); + +}; + +} // namespace api +} // namespace librbd + +extern template class librbd::api::DiffIterate; + +#endif // CEPH_LIBRBD_API_DIFF_ITERATE_H diff --git a/src/librbd/api/Group.cc b/src/librbd/api/Group.cc new file mode 100644 index 0000000000000..7e60fc5202140 --- /dev/null +++ b/src/librbd/api/Group.cc @@ -0,0 +1,401 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "librbd/api/Group.h" +#include "common/errno.h" +#include "librbd/ImageState.h" +#include "librbd/Utils.h" +#include "librbd/io/AioCompletion.h" + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::api::Group: " << __func__ << ": " + +using std::map; +using std::pair; +using std::set; +using std::string; +using std::vector; +// list binds to list() here, so std::list is explicitly used below + +using ceph::bufferlist; +using librados::snap_t; +using librados::IoCtx; +using librados::Rados; + +namespace librbd { +namespace api { + +// Consistency groups functions + +template +int Group::create(librados::IoCtx& io_ctx, const char *group_name) +{ + CephContext *cct = (CephContext *)io_ctx.cct(); + + Rados rados(io_ctx); + uint64_t bid = rados.get_instance_id(); + + uint32_t extra = rand() % 0xFFFFFFFF; + ostringstream bid_ss; + bid_ss << std::hex << bid << std::hex << extra; + string id = bid_ss.str(); + + ldout(cct, 2) << "adding consistency group to directory..." << dendl; + + int r = cls_client::group_dir_add(&io_ctx, RBD_GROUP_DIRECTORY, group_name, + id); + if (r < 0) { + lderr(cct) << "error adding consistency group to directory: " + << cpp_strerror(r) + << dendl; + return r; + } + string header_oid = util::group_header_name(id); + + r = cls_client::group_create(&io_ctx, header_oid); + if (r < 0) { + lderr(cct) << "error writing header: " << cpp_strerror(r) << dendl; + goto err_remove_from_dir; + } + + return 0; + +err_remove_from_dir: + int remove_r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY, + group_name, id); + if (remove_r < 0) { + lderr(cct) << "error cleaning up consistency group from rbd_directory " + << "object after creation failed: " << cpp_strerror(remove_r) + << dendl; + } + + return r; +} + +template +int Group::remove(librados::IoCtx& io_ctx, const char *group_name) +{ + CephContext *cct((CephContext *)io_ctx.cct()); + ldout(cct, 20) << "io_ctx=" << &io_ctx << " " << group_name << dendl; + + std::vector images; + int r = image_list(io_ctx, group_name, &images); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "error listing group images" << dendl; + return r; + } + + for (auto i : images) { + librados::Rados rados(io_ctx); + IoCtx image_ioctx; + rados.ioctx_create2(i.pool, image_ioctx); + r = image_remove(io_ctx, group_name, image_ioctx, i.name.c_str()); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "error removing image from a group" << dendl; + return r; + } + } + + std::string group_id; + r = cls_client::dir_get_id(&io_ctx, RBD_GROUP_DIRECTORY, + std::string(group_name), &group_id); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "error getting id of group" << dendl; + return r; + } + + string header_oid = util::group_header_name(group_id); + + r = io_ctx.remove(header_oid); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "error removing header: " << cpp_strerror(-r) << dendl; + return r; + } + + r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY, group_name, + group_id); + if (r < 0 && r != -ENOENT) { + lderr(cct) << "error removing group from directory" << dendl; + return r; + } + + return 0; +} + +template +int Group::list(IoCtx& io_ctx, vector *names) +{ + CephContext *cct = (CephContext *)io_ctx.cct(); + ldout(cct, 20) << "io_ctx=" << &io_ctx << dendl; + + int max_read = 1024; + string last_read = ""; + int r; + do { + map groups; + r = cls_client::group_dir_list(&io_ctx, RBD_GROUP_DIRECTORY, last_read, + max_read, &groups); + if (r < 0) { + lderr(cct) << "error listing group in directory: " + << cpp_strerror(r) << dendl; + return r; + } + for (pair group : groups) { + names->push_back(group.first); + } + if (!groups.empty()) { + last_read = groups.rbegin()->first; + } + r = groups.size(); + } while (r == max_read); + + return 0; +} + +template +int Group::image_add(librados::IoCtx& group_ioctx, const char *group_name, + librados::IoCtx& image_ioctx, const char *image_name) +{ + CephContext *cct = (CephContext *)group_ioctx.cct(); + ldout(cct, 20) << "io_ctx=" << &group_ioctx + << " group name " << group_name << " image " + << &image_ioctx << " name " << image_name << dendl; + + string group_id; + + int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, group_name, + &group_id); + if (r < 0) { + lderr(cct) << "error reading consistency group id object: " + << cpp_strerror(r) + << dendl; + return r; + } + string group_header_oid = util::group_header_name(group_id); + + + ldout(cct, 20) << "adding image to group name " << group_name + << " group id " << group_header_oid << dendl; + + string image_id; + + r = cls_client::dir_get_id(&image_ioctx, RBD_DIRECTORY, image_name, + &image_id); + if (r < 0) { + lderr(cct) << "error reading image id object: " + << cpp_strerror(-r) << dendl; + return r; + } + + string image_header_oid = util::header_name(image_id); + + ldout(cct, 20) << "adding image " << image_name + << " image id " << image_header_oid << dendl; + + cls::rbd::GroupImageStatus incomplete_st( + image_id, image_ioctx.get_id(), + cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE); + cls::rbd::GroupImageStatus attached_st( + image_id, image_ioctx.get_id(), cls::rbd::GROUP_IMAGE_LINK_STATE_ATTACHED); + + r = cls_client::group_image_set(&group_ioctx, group_header_oid, + incomplete_st); + + cls::rbd::GroupSpec group_spec(group_id, group_ioctx.get_id()); + + if (r < 0) { + lderr(cct) << "error adding image reference to consistency group: " + << cpp_strerror(-r) << dendl; + return r; + } + + r = cls_client::image_add_group(&image_ioctx, image_header_oid, group_spec); + if (r < 0) { + lderr(cct) << "error adding group reference to image: " + << cpp_strerror(-r) << dendl; + cls::rbd::GroupImageSpec spec(image_id, image_ioctx.get_id()); + cls_client::group_image_remove(&group_ioctx, group_header_oid, spec); + // Ignore errors in the clean up procedure. + return r; + } + + r = cls_client::group_image_set(&group_ioctx, group_header_oid, + attached_st); + + return r; +} + +template +int Group::image_remove(librados::IoCtx& group_ioctx, const char *group_name, + librados::IoCtx& image_ioctx, const char *image_name) +{ + CephContext *cct = (CephContext *)group_ioctx.cct(); + ldout(cct, 20) << "io_ctx=" << &group_ioctx + << " group name " << group_name << " image " + << &image_ioctx << " name " << image_name << dendl; + + string group_id; + + int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, group_name, + &group_id); + if (r < 0) { + lderr(cct) << "error reading consistency group id object: " + << cpp_strerror(r) + << dendl; + return r; + } + string group_header_oid = util::group_header_name(group_id); + + ldout(cct, 20) << "adding image to group name " << group_name + << " group id " << group_header_oid << dendl; + + string image_id; + r = cls_client::dir_get_id(&image_ioctx, RBD_DIRECTORY, image_name, + &image_id); + if (r < 0) { + lderr(cct) << "error reading image id object: " + << cpp_strerror(-r) << dendl; + return r; + } + + string image_header_oid = util::header_name(image_id); + + ldout(cct, 20) << "removing image " << image_name + << " image id " << image_header_oid << dendl; + + cls::rbd::GroupSpec group_spec(group_id, group_ioctx.get_id()); + + cls::rbd::GroupImageStatus incomplete_st( + image_id, image_ioctx.get_id(), + cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE); + + cls::rbd::GroupImageSpec spec(image_id, image_ioctx.get_id()); + + r = cls_client::group_image_set(&group_ioctx, group_header_oid, + incomplete_st); + + if (r < 0) { + lderr(cct) << "couldn't put image into removing state: " + << cpp_strerror(-r) << dendl; + return r; + } + + r = cls_client::image_remove_group(&image_ioctx, image_header_oid, + group_spec); + if ((r < 0) && (r != -ENOENT)) { + lderr(cct) << "couldn't remove group reference from image" + << cpp_strerror(-r) << dendl; + return r; + } + + r = cls_client::group_image_remove(&group_ioctx, group_header_oid, spec); + if (r < 0) { + lderr(cct) << "couldn't remove image from group" + << cpp_strerror(-r) << dendl; + return r; + } + + return 0; +} + +template +int Group::image_list(librados::IoCtx& group_ioctx, + const char *group_name, + std::vector *images) +{ + CephContext *cct = (CephContext *)group_ioctx.cct(); + ldout(cct, 20) << "io_ctx=" << &group_ioctx + << " group name " << group_name << dendl; + + string group_id; + + int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, + group_name, &group_id); + if (r < 0) { + lderr(cct) << "error reading consistency group id object: " + << cpp_strerror(r) + << dendl; + return r; + } + string group_header_oid = util::group_header_name(group_id); + + ldout(cct, 20) << "listing images in group name " + << group_name << " group id " << group_header_oid << dendl; + + std::vector image_ids; + + const int max_read = 1024; + do { + std::vector image_ids_page; + cls::rbd::GroupImageSpec start_last; + + r = cls_client::group_image_list(&group_ioctx, group_header_oid, + start_last, max_read, &image_ids_page); + + if (r < 0) { + lderr(cct) << "error reading image list from consistency group: " + << cpp_strerror(-r) << dendl; + return r; + } + image_ids.insert(image_ids.end(), + image_ids_page.begin(), image_ids_page.end()); + + if (image_ids_page.size() > 0) + start_last = image_ids_page.rbegin()->spec; + + r = image_ids_page.size(); + } while (r == max_read); + + for (auto i : image_ids) { + librados::Rados rados(group_ioctx); + IoCtx ioctx; + rados.ioctx_create2(i.spec.pool_id, ioctx); + std::string image_name; + r = cls_client::dir_get_name(&ioctx, RBD_DIRECTORY, + i.spec.image_id, &image_name); + if (r < 0) { + return r; + } + + images->push_back( + group_image_status_t { + image_name, + i.spec.pool_id, + static_cast(i.state)}); + } + + return 0; +} + +template +int Group::image_get_group(I *ictx, group_spec_t *group_spec) +{ + int r = ictx->state->refresh_if_required(); + if (r < 0) + return r; + + if (-1 != ictx->group_spec.pool_id) { + librados::Rados rados(ictx->md_ctx); + IoCtx ioctx; + rados.ioctx_create2(ictx->group_spec.pool_id, ioctx); + + std::string group_name; + r = cls_client::dir_get_name(&ioctx, RBD_GROUP_DIRECTORY, + ictx->group_spec.group_id, &group_name); + if (r < 0) + return r; + group_spec->pool = ictx->group_spec.pool_id; + group_spec->name = group_name; + } else { + group_spec->pool = -1; + group_spec->name = ""; + } + + return 0; +} + +} // namespace api +} // namespace librbd + +template class librbd::api::Group; diff --git a/src/librbd/api/Group.h b/src/librbd/api/Group.h new file mode 100644 index 0000000000000..4773cb5af7497 --- /dev/null +++ b/src/librbd/api/Group.h @@ -0,0 +1,42 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_API_GROUP_H +#define CEPH_LIBRBD_API_GROUP_H + +#include "include/rbd/librbd.hpp" +#include +#include + +namespace librados { struct IoCtx; } + +namespace librbd { + +struct ImageCtx; + +namespace api { + +template +struct Group { + + static int create(librados::IoCtx& io_ctx, const char *imgname); + static int remove(librados::IoCtx& io_ctx, const char *group_name); + static int list(librados::IoCtx& io_ctx, std::vector *names); + + static int image_add(librados::IoCtx& group_ioctx, const char *group_name, + librados::IoCtx& image_ioctx, const char *image_name); + static int image_remove(librados::IoCtx& group_ioctx, const char *group_name, + librados::IoCtx& image_ioctx, const char *image_name); + static int image_list(librados::IoCtx& group_ioctx, const char *group_name, + std::vector *images); + + static int image_get_group(ImageCtxT *ictx, group_spec_t *group_spec); + +}; + +} // namespace api +} // namespace librbd + +extern template class librbd::api::Group; + +#endif // CEPH_LIBRBD_API_GROUP_H diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index c7b6611aba1f2..3432ae71c4579 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -21,7 +21,6 @@ #include "cls/journal/cls_journal_types.h" #include "cls/journal/cls_journal_client.h" -#include "librbd/DiffIterate.h" #include "librbd/ExclusiveLock.h" #include "librbd/ImageCtx.h" #include "librbd/ImageState.h" @@ -2015,37 +2014,6 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) { return total_read; } - int diff_iterate(ImageCtx *ictx, const char *fromsnapname, uint64_t off, - uint64_t len, bool include_parent, bool whole_object, - int (*cb)(uint64_t, size_t, int, void *), void *arg) - { - ldout(ictx->cct, 20) << "diff_iterate " << ictx << " off = " << off - << " len = " << len << dendl; - - // ensure previous writes are visible to listsnaps - { - RWLock::RLocker owner_locker(ictx->owner_lock); - ictx->flush(); - } - - int r = ictx->state->refresh_if_required(); - if (r < 0) { - return r; - } - - ictx->snap_lock.get_read(); - r = clip_io(ictx, off, &len); - ictx->snap_lock.put_read(); - if (r < 0) { - return r; - } - - DiffIterate command(*ictx, fromsnapname, off, len, include_parent, - whole_object, cb, arg); - r = command.execute(); - return r; - } - // validate extent against image size; clip to image size if necessary int clip_io(ImageCtx *ictx, uint64_t off, uint64_t *len) { diff --git a/src/librbd/internal.h b/src/librbd/internal.h index 80043f2d5f178..65bb5a40eab10 100644 --- a/src/librbd/internal.h +++ b/src/librbd/internal.h @@ -185,10 +185,6 @@ namespace librbd { int64_t read_iterate(ImageCtx *ictx, uint64_t off, uint64_t len, int (*cb)(uint64_t, size_t, const char *, void *), void *arg); - int diff_iterate(ImageCtx *ictx, const char *fromsnapname, uint64_t off, - uint64_t len, bool include_parent, bool whole_object, - int (*cb)(uint64_t, size_t, int, void *), - void *arg); void readahead(ImageCtx *ictx, const vector >& image_extents); diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 390af617d50b9..dea4ecb9478e5 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -23,11 +23,12 @@ #include "cls/rbd/cls_rbd_client.h" #include "cls/rbd/cls_rbd_types.h" -#include "librbd/Group.h" #include "librbd/ImageCtx.h" #include "librbd/ImageState.h" #include "librbd/internal.h" #include "librbd/Operations.h" +#include "librbd/api/DiffIterate.h" +#include "librbd/api/Group.h" #include "librbd/api/Mirror.h" #include "librbd/io/AioCompletion.h" #include "librbd/io/ImageRequestWQ.h" @@ -477,7 +478,7 @@ namespace librbd { TracepointProvider::initialize(get_cct(io_ctx)); tracepoint(librbd, group_create_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), group_name); - int r = librbd::group_create(io_ctx, group_name); + int r = librbd::api::Group<>::create(io_ctx, group_name); tracepoint(librbd, group_create_exit, r); return r; } @@ -487,7 +488,7 @@ namespace librbd { TracepointProvider::initialize(get_cct(io_ctx)); tracepoint(librbd, group_remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), group_name); - int r = librbd::group_remove(io_ctx, group_name); + int r = librbd::api::Group<>::remove(io_ctx, group_name); tracepoint(librbd, group_remove_exit, r); return r; } @@ -498,7 +499,7 @@ namespace librbd { tracepoint(librbd, group_list_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id()); - int r = librbd::group_list(io_ctx, names); + int r = librbd::api::Group<>::list(io_ctx, names); if (r >= 0) { for (auto itr : *names) { tracepoint(librbd, group_list_entry, itr.c_str()); @@ -515,7 +516,8 @@ namespace librbd { tracepoint(librbd, group_image_add_enter, group_ioctx.get_pool_name().c_str(), group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(), image_ioctx.get_id(), image_name); - int r = librbd::group_image_add(group_ioctx, group_name, image_ioctx, image_name); + int r = librbd::api::Group<>::image_add(group_ioctx, group_name, + image_ioctx, image_name); tracepoint(librbd, group_image_add_exit, r); return r; } @@ -527,7 +529,8 @@ namespace librbd { tracepoint(librbd, group_image_remove_enter, group_ioctx.get_pool_name().c_str(), group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(), image_ioctx.get_id(), image_name); - int r = librbd::group_image_remove(group_ioctx, group_name, image_ioctx, image_name); + int r = librbd::api::Group<>::image_remove(group_ioctx, group_name, + image_ioctx, image_name); tracepoint(librbd, group_image_remove_exit, r); return r; } @@ -538,7 +541,7 @@ namespace librbd { TracepointProvider::initialize(get_cct(group_ioctx)); tracepoint(librbd, group_image_list_enter, group_ioctx.get_pool_name().c_str(), group_ioctx.get_id(), group_name); - int r = librbd::group_image_list(group_ioctx, group_name, images); + int r = librbd::api::Group<>::image_list(group_ioctx, group_name, images); tracepoint(librbd, group_image_list_exit, r); return r; } @@ -743,7 +746,7 @@ namespace librbd { { ImageCtx *ictx = (ImageCtx *)ctx; tracepoint(librbd, image_get_group_enter, ictx->name.c_str()); - int r = librbd::image_get_group(ictx, group_spec); + int r = librbd::api::Group<>::image_get_group(ictx, group_spec); tracepoint(librbd, image_get_group_exit, r); return r; } @@ -1277,8 +1280,8 @@ namespace librbd { tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len, true, false); - int r = librbd::diff_iterate(ictx, fromsnapname, ofs, len, true, false, cb, - arg); + int r = librbd::api::DiffIterate<>::diff_iterate(ictx, fromsnapname, ofs, + len, true, false, cb, arg); tracepoint(librbd, diff_iterate_exit, r); return r; } @@ -1291,8 +1294,9 @@ namespace librbd { tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len, include_parent, whole_object); - int r = librbd::diff_iterate(ictx, fromsnapname, ofs, len, include_parent, - whole_object, cb, arg); + int r = librbd::api::DiffIterate<>::diff_iterate(ictx, fromsnapname, ofs, + len, include_parent, + whole_object, cb, arg); tracepoint(librbd, diff_iterate_exit, r); return r; } @@ -2890,8 +2894,8 @@ extern "C" int rbd_diff_iterate(rbd_image_t image, tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len, true, false); - int r = librbd::diff_iterate(ictx, fromsnapname, ofs, len, true, false, cb, - arg); + int r = librbd::api::DiffIterate<>::diff_iterate(ictx, fromsnapname, ofs, len, + true, false, cb, arg); tracepoint(librbd, diff_iterate_exit, r); return r; } @@ -2906,8 +2910,9 @@ extern "C" int rbd_diff_iterate2(rbd_image_t image, const char *fromsnapname, tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len, include_parent != 0, whole_object != 0); - int r = librbd::diff_iterate(ictx, fromsnapname, ofs, len, include_parent, - whole_object, cb, arg); + int r = librbd::api::DiffIterate<>::diff_iterate(ictx, fromsnapname, ofs, len, + include_parent, whole_object, + cb, arg); tracepoint(librbd, diff_iterate_exit, r); return r; } @@ -3395,7 +3400,7 @@ extern "C" int rbd_group_create(rados_ioctx_t p, const char *name) TracepointProvider::initialize(get_cct(io_ctx)); tracepoint(librbd, group_create_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name); - int r = librbd::group_create(io_ctx, name); + int r = librbd::api::Group<>::create(io_ctx, name); tracepoint(librbd, group_create_exit, r); return r; } @@ -3407,7 +3412,7 @@ extern "C" int rbd_group_remove(rados_ioctx_t p, const char *name) TracepointProvider::initialize(get_cct(io_ctx)); tracepoint(librbd, group_remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name); - int r = librbd::group_remove(io_ctx, name); + int r = librbd::api::Group<>::remove(io_ctx, name); tracepoint(librbd, group_remove_exit, r); return r; } @@ -3475,7 +3480,8 @@ extern "C" int rbd_group_image_add( group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(), image_ioctx.get_id(), image_name); - int r = librbd::group_image_add(group_ioctx, group_name, image_ioctx, image_name); + int r = librbd::api::Group<>::image_add(group_ioctx, group_name, image_ioctx, + image_name); tracepoint(librbd, group_image_add_exit, r); return r; @@ -3496,7 +3502,8 @@ extern "C" int rbd_group_image_remove( group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(), image_ioctx.get_id(), image_name); - int r = librbd::group_image_remove(group_ioctx, group_name, image_ioctx, image_name); + int r = librbd::api::Group<>::image_remove(group_ioctx, group_name, + image_ioctx, image_name); tracepoint(librbd, group_image_remove_exit, r); return r; @@ -3515,7 +3522,8 @@ extern "C" int rbd_group_image_list(rados_ioctx_t group_p, group_ioctx.get_id(), group_name); std::vector cpp_images; - int r = librbd::group_image_list(group_ioctx, group_name, &cpp_images); + int r = librbd::api::Group<>::image_list(group_ioctx, group_name, + &cpp_images); if (r == -ENOENT) { tracepoint(librbd, group_image_list_exit, 0); @@ -3556,7 +3564,7 @@ extern "C" int rbd_image_get_group(rados_ioctx_t image_p, tracepoint(librbd, image_get_group_enter, ictx->name.c_str()); librbd::group_spec_t group_spec; - r = librbd::image_get_group(ictx, &group_spec); + r = librbd::api::Group<>::image_get_group(ictx, &group_spec); group_spec_cpp_to_c(group_spec, c_group_spec); tracepoint(librbd, image_get_group_exit, r); ictx->state->close(); diff --git a/src/test/librbd/test_internal.cc b/src/test/librbd/test_internal.cc index db3bbbffaca9d..ed247a3a22591 100644 --- a/src/test/librbd/test_internal.cc +++ b/src/test/librbd/test_internal.cc @@ -1,5 +1,6 @@ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab + #include "cls/rbd/cls_rbd_types.h" #include "test/librbd/test_fixture.h" #include "test/librbd/test_support.h" @@ -10,6 +11,7 @@ #include "librbd/internal.h" #include "librbd/ObjectMap.h" #include "librbd/Operations.h" +#include "librbd/api/DiffIterate.h" #include "librbd/io/AioCompletion.h" #include "librbd/io/ImageRequest.h" #include "librbd/io/ImageRequestWQ.h" @@ -966,8 +968,8 @@ TEST_F(TestInternal, DiffIterateCloneOverwrite) { interval_set diff; ASSERT_EQ(0, librbd::snap_set(ictx, "one")); - ASSERT_EQ(0, librbd::diff_iterate(ictx, nullptr, 0, size, true, false, - iterate_cb, (void *)&diff)); + ASSERT_EQ(0, librbd::api::DiffIterate<>::diff_iterate( + ictx, nullptr, 0, size, true, false, iterate_cb, (void *)&diff)); ASSERT_EQ(one, diff); }