size_t status_size, rbd_completion_t c)
CEPH_RBD_DEPRECATED;
+CEPH_RBD_API int rbd_aio_mirror_image_create_snapshot(rbd_image_t image,
+ uint32_t flags,
+ uint64_t *snap_id,
+ rbd_completion_t c);
+
// RBD groups support functions
CEPH_RBD_API int rbd_group_create(rados_ioctx_t p, const char *name);
CEPH_RBD_API int rbd_group_remove(rados_ioctx_t p, const char *name);
mirror_image_status_t *mirror_image_status, size_t status_size,
RBD::AioCompletion *c)
CEPH_RBD_DEPRECATED;
+ int aio_mirror_image_create_snapshot(uint32_t flags, uint64_t *snap_id,
+ RBD::AioCompletion *c);
int update_watch(UpdateWatchCtx *ctx, uint64_t *handle);
int update_unwatch(uint64_t handle);
#include "json_spirit/json_spirit.h"
#include <algorithm>
+#include <bitset>
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
}
};
+template <typename I>
+struct C_ImageSnapshotCreate : public Context {
+ I *ictx;
+ uint64_t *snap_id;
+ Context *on_finish;
+
+ cls::rbd::MirrorImage mirror_image;
+ mirror::PromotionState promotion_state;
+ std::string primary_mirror_uuid;
+
+ C_ImageSnapshotCreate(I *ictx, uint64_t *snap_id, Context *on_finish)
+ : ictx(ictx), snap_id(snap_id), on_finish(on_finish) {
+ }
+
+ void finish(int r) override {
+ if (r < 0 && r != -ENOENT) {
+ on_finish->complete(r);
+ return;
+ }
+
+ if (mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT ||
+ mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
+ lderr(ictx->cct) << "snapshot based mirroring is not enabled" << dendl;
+ on_finish->complete(-EINVAL);
+ return;
+ }
+
+ auto req = mirror::snapshot::CreatePrimaryRequest<I>::create(
+ ictx, mirror_image.global_image_id, CEPH_NOSNAP, 0U, snap_id, on_finish);
+ req->send();
+ }
+};
+
} // anonymous namespace
template <typename I>
}
template <typename I>
-int Mirror<I>::image_snapshot_create(I *ictx, uint64_t *snap_id) {
+int Mirror<I>::image_snapshot_create(I *ictx, uint32_t flags,
+ uint64_t *snap_id) {
+ C_SaferCond ctx;
+ Mirror<I>::image_snapshot_create(ictx, flags, snap_id, &ctx);
+
+ return ctx.wait();
+}
+
+template <typename I>
+void Mirror<I>::image_snapshot_create(I *ictx, uint32_t flags,
+ uint64_t *snap_id, Context *on_finish) {
CephContext *cct = ictx->cct;
ldout(cct, 20) << "ictx=" << ictx << dendl;
- int r = ictx->state->refresh_if_required();
- if (r < 0) {
- return r;
+ if (flags != 0U) {
+ lderr(cct) << "invalid snap create flags: " << std::bitset<32>(flags)
+ << dendl;
+ on_finish->complete(-EINVAL);
+ return;
}
- cls::rbd::MirrorImage mirror_image;
- r = cls_client::mirror_image_get(&ictx->md_ctx, ictx->id,
- &mirror_image);
- if (r == -ENOENT) {
- return -EINVAL;
- } else if (r < 0) {
- lderr(cct) << "failed to retrieve mirror image" << dendl;
- return r;
- }
+ auto on_refresh = new LambdaContext(
+ [ictx, snap_id, on_finish](int r) {
+ if (r < 0) {
+ lderr(ictx->cct) << "refresh failed: " << cpp_strerror(r) << dendl;
+ on_finish->complete(r);
+ return;
+ }
- if (mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT ||
- mirror_image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
- lderr(cct) << "snapshot based mirroring is not enabled" << dendl;
- return -EINVAL;
- }
+ auto ctx = new C_ImageSnapshotCreate<I>(ictx, snap_id, on_finish);
+ auto req = mirror::GetInfoRequest<I>::create(*ictx, &ctx->mirror_image,
+ &ctx->promotion_state,
+ &ctx->primary_mirror_uuid,
+ ctx);
+ req->send();
+ });
- C_SaferCond on_finish;
- auto req = mirror::snapshot::CreatePrimaryRequest<I>::create(
- ictx, mirror_image.global_image_id, CEPH_NOSNAP, 0U, snap_id, &on_finish);
- req->send();
- return on_finish.wait();
+ if (ictx->state->is_refresh_required()) {
+ ictx->state->refresh(on_refresh);
+ } else {
+ on_refresh->complete(0);
+ }
}
} // namespace api
Context *on_finish);
static int image_get_instance_id(ImageCtxT *ictx, std::string *instance_id);
- static int image_snapshot_create(ImageCtxT *ictx, uint64_t *snap_id);
+ static int image_snapshot_create(ImageCtxT *ictx, uint32_t flags,
+ uint64_t *snap_id);
+ static void image_snapshot_create(ImageCtxT *ictx, uint32_t flags,
+ uint64_t *snap_id, Context *on_finish);
};
} // namespace api
int Image::mirror_image_create_snapshot(uint64_t *snap_id)
{
ImageCtx *ictx = (ImageCtx *)ctx;
- return librbd::api::Mirror<>::image_snapshot_create(ictx, snap_id);
+ return librbd::api::Mirror<>::image_snapshot_create(ictx, 0U, snap_id);
}
int Image::mirror_image_get_info(mirror_image_info_t *mirror_image_info,
#pragma GCC diagnostic pop
+ int Image::aio_mirror_image_create_snapshot(uint32_t flags, uint64_t *snap_id,
+ RBD::AioCompletion *c) {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+
+ librbd::api::Mirror<>::image_snapshot_create(
+ ictx, flags, snap_id, new C_AioCompletion(ictx,
+ librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(c)));
+ return 0;
+ }
+
int Image::update_watch(UpdateWatchCtx *wctx, uint64_t *handle) {
ImageCtx *ictx = (ImageCtx *)ctx;
tracepoint(librbd, update_watch_enter, ictx, wctx);
uint64_t *snap_id)
{
librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
- return librbd::api::Mirror<>::image_snapshot_create(ictx, snap_id);
+ return librbd::api::Mirror<>::image_snapshot_create(ictx, 0U, snap_id);
}
extern "C" int rbd_mirror_image_get_info(rbd_image_t image,
#pragma GCC diagnostic pop
+extern "C" int rbd_aio_mirror_image_create_snapshot(rbd_image_t image,
+ uint32_t flags,
+ uint64_t *snap_id,
+ rbd_completion_t c) {
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
+
+ librbd::api::Mirror<>::image_snapshot_create(
+ ictx, flags, snap_id, new C_AioCompletion(ictx,
+ librbd::io::AIO_TYPE_GENERIC,
+ get_aio_completion(comp)));
+ return 0;
+}
+
extern "C" int rbd_update_watch(rbd_image_t image, uint64_t *handle,
rbd_update_callback_t watch_cb, void *arg)
{
ASSERT_EQ(0, m_rbd.mirror_peer_site_remove(m_ioctx, peer_uuid));
ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED));
}
+
+TEST_F(TestMirroring, AioSnapshotCreate)
+{
+ REQUIRE_FORMAT_V2();
+
+ std::list<std::string> image_names;
+ for (size_t idx = 0; idx < 10; ++idx) {
+ image_names.push_back(get_temp_image_name());
+ }
+
+ ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_IMAGE));
+ std::string peer_uuid;
+ ASSERT_EQ(0, m_rbd.mirror_peer_site_add(m_ioctx, &peer_uuid,
+ RBD_MIRROR_PEER_DIRECTION_RX_TX,
+ "cluster", "client"));
+ // create mirror images
+ uint64_t features;
+ ASSERT_TRUE(get_features(&features));
+ int order = 20;
+ std::list<librbd::Image> images;
+ for (auto &image_name : image_names) {
+ ASSERT_EQ(0, m_rbd.create2(m_ioctx, image_name.c_str(), 2048, features,
+ &order));
+ images.emplace_back();
+ ASSERT_EQ(0, m_rbd.open(m_ioctx, images.back(), image_name.c_str()));
+ ASSERT_EQ(0, images.back().mirror_image_enable2(
+ RBD_MIRROR_IMAGE_MODE_SNAPSHOT));
+ }
+
+ // create snapshots
+ std::list<uint64_t> snap_ids;
+ std::list<librbd::RBD::AioCompletion *> aio_comps;
+ for (auto &image : images) {
+ snap_ids.emplace_back();
+ aio_comps.push_back(new librbd::RBD::AioCompletion(nullptr, nullptr));
+ ASSERT_EQ(0, image.aio_mirror_image_create_snapshot(0, &snap_ids.back(),
+ aio_comps.back()));
+ }
+ for (auto aio_comp : aio_comps) {
+ ASSERT_EQ(0, aio_comp->wait_for_complete());
+ ASSERT_EQ(1, aio_comp->is_complete());
+ ASSERT_EQ(0, aio_comp->get_return_value());
+ aio_comp->release();
+ }
+ aio_comps.clear();
+
+ // verify
+ for (auto &image : images) {
+ vector<librbd::snap_info_t> snaps;
+ ASSERT_EQ(0, image.snap_list(snaps));
+ ASSERT_EQ(2U, snaps.size());
+ ASSERT_EQ(snaps[1].id, snap_ids.front());
+
+ std::string image_name;
+ ASSERT_EQ(0, image.get_name(&image_name));
+ ASSERT_EQ(0, image.close());
+ ASSERT_EQ(0, m_rbd.remove(m_ioctx, image_name.c_str()));
+ snap_ids.pop_front();
+ }
+
+ ASSERT_EQ(0, m_rbd.mirror_peer_site_remove(m_ioctx, peer_uuid));
+ ASSERT_EQ(0, m_rbd.mirror_mode_set(m_ioctx, RBD_MIRROR_MODE_DISABLED));
+}
} else {
uint64_t snap_id = CEPH_NOSNAP;
ASSERT_EQ(0, librbd::api::Mirror<>::image_snapshot_create(
- ictx, &snap_id));
+ ictx, 0U, &snap_id));
}
printf("flushed\n");