AsyncObjectThrottle.cc
AsyncOperation.cc
AsyncRequest.cc
- DiffIterate.cc
ExclusiveLock.cc
- Group.cc
ImageCtx.cc
ImageState.cc
ImageWatcher.cc
Operations.cc
Utils.cc
Watcher.cc
+ api/DiffIterate.cc
+ api/Group.cc
api/Image.cc
api/Mirror.cc
cache/ImageWriteback.cc
+++ /dev/null
-// -*- 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 <boost/tuple/tuple.hpp>
-#include <list>
-#include <map>
-#include <vector>
-
-#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<uint64_t> 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<ObjectExtent> &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<uint64_t, size_t, bool> Diff;
- typedef std::list<Diff> 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<ObjectExtent> 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<uint64_t> 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<ObjectExtent>::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<ObjectExtent>::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<pair<uint64_t,uint64_t> >::iterator r =
- q->buffer_extents.begin();
- r != q->buffer_extents.end(); ++r) {
- interval_set<uint64_t> 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<uint64_t>::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<ObjectExtent>::iterator q = m_object_extents.begin();
- q != m_object_extents.end(); ++q) {
- for (vector<pair<uint64_t,uint64_t> >::iterator r =
- q->buffer_extents.begin();
- r != q->buffer_extents.end(); ++r) {
- interval_set<uint64_t> 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<uint64_t>::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_t,vector<ObjectExtent> > 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<object_t,vector<ObjectExtent> >::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<ObjectExtent>::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<librados::snap_t, SnapInfo>::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<uint32_t>(prev_object_map[i])
- << "->" << static_cast<uint32_t>(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<uint32_t>(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<uint64_t> *diff = static_cast<interval_set<uint64_t> *>(arg);
- diff->insert(off, len);
- }
- return 0;
-}
-
-} // namespace librbd
+++ /dev/null
-// -*- 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
+++ /dev/null
-// -*- 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<group_image_status_t> 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<string> *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<string, string> 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<string, string> 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<group_image_status_t> *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<cls::rbd::GroupImageStatus> image_ids;
-
- const int max_read = 1024;
- do {
- std::vector<cls::rbd::GroupImageStatus> 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<group_image_state_t>(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
+++ /dev/null
-// -*- 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 <string>
-#include <vector>
-
-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<std::string> *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<group_image_status_t> *images);
-int image_get_group(ImageCtx *ictx, group_spec_t *group_spec);
-
-} // namespace librbd
-
-#endif // CEPH_LIBRBD_GROUP_H
--- /dev/null
+// -*- 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 <boost/tuple/tuple.hpp>
+#include <list>
+#include <map>
+#include <vector>
+
+#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<uint64_t> parent_diff;
+ OrderedThrottle throttle;
+
+ template <typename I>
+ 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 <typename I>
+ C_DiffObject(I &image_ctx, librados::IoCtx &head_ctx,
+ DiffContext &diff_context, const std::string &oid,
+ uint64_t offset, const std::vector<ObjectExtent> &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<uint64_t, size_t, bool> Diff;
+ typedef std::list<Diff> 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<ObjectExtent> 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<uint64_t> 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<ObjectExtent>::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<ObjectExtent>::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<pair<uint64_t,uint64_t> >::iterator r =
+ q->buffer_extents.begin();
+ r != q->buffer_extents.end(); ++r) {
+ interval_set<uint64_t> 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<uint64_t>::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<ObjectExtent>::iterator q = m_object_extents.begin();
+ q != m_object_extents.end(); ++q) {
+ for (vector<pair<uint64_t,uint64_t> >::iterator r =
+ q->buffer_extents.begin();
+ r != q->buffer_extents.end(); ++r) {
+ interval_set<uint64_t> 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<uint64_t>::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<uint64_t> *diff = static_cast<interval_set<uint64_t> *>(arg);
+ diff->insert(off, len);
+ }
+ return 0;
+}
+
+} // anonymous namespace
+
+template <typename I>
+int DiffIterate<I>::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 <typename I>
+int DiffIterate<I>::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_t,vector<ObjectExtent> > 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<object_t,vector<ObjectExtent> >::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<ObjectExtent>::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 <typename I>
+int DiffIterate<I>::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<librados::snap_t, SnapInfo>::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<uint32_t>(prev_object_map[i])
+ << "->" << static_cast<uint32_t>(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<uint32_t>(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<librbd::ImageCtx>;
--- /dev/null
+// -*- 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 <typename ImageCtxT = librbd::ImageCtx>
+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<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_API_DIFF_ITERATE_H
--- /dev/null
+// -*- 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 <typename I>
+int Group<I>::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 <typename I>
+int Group<I>::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<group_image_status_t> 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 <typename I>
+int Group<I>::list(IoCtx& io_ctx, vector<string> *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<string, string> 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<string, string> 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 <typename I>
+int Group<I>::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 <typename I>
+int Group<I>::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 <typename I>
+int Group<I>::image_list(librados::IoCtx& group_ioctx,
+ const char *group_name,
+ std::vector<group_image_status_t> *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<cls::rbd::GroupImageStatus> image_ids;
+
+ const int max_read = 1024;
+ do {
+ std::vector<cls::rbd::GroupImageStatus> 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<group_image_state_t>(i.state)});
+ }
+
+ return 0;
+}
+
+template <typename I>
+int Group<I>::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<librbd::ImageCtx>;
--- /dev/null
+// -*- 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 <string>
+#include <vector>
+
+namespace librados { struct IoCtx; }
+
+namespace librbd {
+
+struct ImageCtx;
+
+namespace api {
+
+template <typename ImageCtxT = librbd::ImageCtx>
+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<std::string> *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<group_image_status_t> *images);
+
+ static int image_get_group(ImageCtxT *ictx, group_spec_t *group_spec);
+
+};
+
+} // namespace api
+} // namespace librbd
+
+extern template class librbd::api::Group<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_API_GROUP_H
#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"
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)
{
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<pair<uint64_t,uint64_t> >& image_extents);
#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"
TracepointProvider::initialize<tracepoint_traits>(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;
}
TracepointProvider::initialize<tracepoint_traits>(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;
}
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());
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;
}
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;
}
TracepointProvider::initialize<tracepoint_traits>(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;
}
{
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;
}
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;
}
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;
}
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;
}
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;
}
TracepointProvider::initialize<tracepoint_traits>(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;
}
TracepointProvider::initialize<tracepoint_traits>(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;
}
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;
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;
group_ioctx.get_id(), group_name);
std::vector<librbd::group_image_status_t> 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);
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();
// -*- 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"
#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"
interval_set<uint64_t> 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);
}