rbd-mirror: helper state machine for opening local image

This state machine will open a local image and request the
exclusive lock.  If the open or lock fails, it will automatically
close the image.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
This commit is contained in:
Jason Dillaman 2016-03-13 22:09:19 -04:00 committed by Josh Durgin
parent d61293d4da
commit 3b1db9bbf5
2 changed files with 227 additions and 0 deletions

View File

@ -0,0 +1,140 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
#include "OpenLocalImageRequest.h"
#include "CloseImageRequest.h"
#include "common/errno.h"
#include "common/WorkQueue.h"
#include "librbd/ExclusiveLock.h"
#include "librbd/ImageCtx.h"
#include "librbd/ImageState.h"
#include "librbd/Utils.h"
#define dout_subsys ceph_subsys_rbd_mirror
#undef dout_prefix
#define dout_prefix *_dout << "rbd::mirror::image_replayer::OpenLocalImageRequest: " \
<< this << " " << __func__
namespace rbd {
namespace mirror {
namespace image_replayer {
using librbd::util::create_context_callback;
template <typename I>
OpenLocalImageRequest<I>::OpenLocalImageRequest(librados::IoCtx &local_io_ctx,
I **local_image_ctx,
const std::string &local_image_name,
const std::string &local_image_id,
ContextWQ *work_queue,
Context *on_finish)
: m_local_io_ctx(local_io_ctx), m_local_image_ctx(local_image_ctx),
m_local_image_name(local_image_name), m_local_image_id(local_image_id),
m_work_queue(work_queue), m_on_finish(on_finish) {
}
template <typename I>
void OpenLocalImageRequest<I>::send() {
send_open_image();
}
template <typename I>
void OpenLocalImageRequest<I>::send_open_image() {
dout(20) << dendl;
*m_local_image_ctx = new librbd::ImageCtx(m_local_image_name,
m_local_image_id, nullptr,
m_local_io_ctx, false);
Context *ctx = create_context_callback<
OpenLocalImageRequest<I>, &OpenLocalImageRequest<I>::handle_open_image>(
this);
(*m_local_image_ctx)->state->open(ctx);
}
template <typename I>
void OpenLocalImageRequest<I>::handle_open_image(int r) {
dout(20) << ": r=" << r << dendl;
if (r < 0) {
derr << "failed to open image '" << m_local_image_id << "': "
<< cpp_strerror(r) << dendl;
send_close_image(r);
return;
} else if ((*m_local_image_ctx)->exclusive_lock == nullptr) {
derr << "image does not support exclusive lock" << dendl;
send_close_image(-EINVAL);
return;
}
send_lock_image();
}
template <typename I>
void OpenLocalImageRequest<I>::send_lock_image() {
dout(20) << dendl;
Context *ctx = create_context_callback<
OpenLocalImageRequest<I>, &OpenLocalImageRequest<I>::handle_lock_image>(
this);
RWLock::RLocker owner_locker((*m_local_image_ctx)->owner_lock);
(*m_local_image_ctx)->exclusive_lock->request_lock(ctx);
}
template <typename I>
void OpenLocalImageRequest<I>::handle_lock_image(int r) {
dout(20) << ": r=" << r << dendl;
if (r < 0) {
derr << "failed to lock image '" << m_local_image_id << "': "
<< cpp_strerror(r) << dendl;
send_close_image(r);
return;
} else if ((*m_local_image_ctx)->exclusive_lock == nullptr ||
!(*m_local_image_ctx)->exclusive_lock->is_lock_owner()) {
derr << "image is not locked" << dendl;
send_close_image(-EBUSY);
return;
}
finish(0);
}
template <typename I>
void OpenLocalImageRequest<I>::send_close_image(int r) {
dout(20) << dendl;
if (m_ret_val == 0 && r < 0) {
m_ret_val = r;
}
Context *ctx = create_context_callback<
OpenLocalImageRequest<I>, &OpenLocalImageRequest<I>::handle_close_image>(
this);
CloseImageRequest<I> *request = CloseImageRequest<I>::create(
m_local_image_ctx, m_work_queue, ctx);
request->send();
}
template <typename I>
void OpenLocalImageRequest<I>::handle_close_image(int r) {
dout(20) << dendl;
assert(r == 0);
finish(m_ret_val);
}
template <typename I>
void OpenLocalImageRequest<I>::finish(int r) {
dout(20) << ": r=" << r << dendl;
m_on_finish->complete(r);
delete this;
}
} // namespace image_replayer
} // namespace mirror
} // namespace rbd
template class rbd::mirror::image_replayer::OpenLocalImageRequest<librbd::ImageCtx>;

View File

@ -0,0 +1,87 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
#ifndef RBD_MIRROR_IMAGE_REPLAYER_OPEN_LOCAL_IMAGE_REQUEST_H
#define RBD_MIRROR_IMAGE_REPLAYER_OPEN_LOCAL_IMAGE_REQUEST_H
#include "include/int_types.h"
#include "librbd/ImageCtx.h"
#include <string>
class Context;
class ContextWQ;
namespace librbd { class ImageCtx; }
namespace rbd {
namespace mirror {
namespace image_replayer {
template <typename ImageCtxT = librbd::ImageCtx>
class OpenLocalImageRequest {
public:
static OpenLocalImageRequest* create(librados::IoCtx &local_io_ctx,
ImageCtxT **local_image_ctx,
const std::string &local_image_name,
const std::string &local_image_id,
ContextWQ *work_queue,
Context *on_finish) {
return new OpenLocalImageRequest(local_io_ctx, local_image_ctx,
local_image_name, local_image_id,
work_queue, on_finish);
}
OpenLocalImageRequest(librados::IoCtx &local_io_ctx,
ImageCtxT **local_image_ctx,
const std::string &local_image_name,
const std::string &local_image_id,
ContextWQ *m_work_queue,
Context *on_finish);
void send();
private:
/**
* @verbatim
*
* <start>
* |
* v
* OPEN_IMAGE * * * * * * *
* | *
* v v
* LOCK_IMAGE * * * > CLOSE_IMAGE
* | |
* v |
* <finish> <-------------/
*
* @endverbatim
*/
librados::IoCtx &m_local_io_ctx;
ImageCtxT **m_local_image_ctx;
std::string m_local_image_name;
std::string m_local_image_id;
ContextWQ *m_work_queue;
Context *m_on_finish;
int m_ret_val = 0;
void send_open_image();
void handle_open_image(int r);
void send_lock_image();
void handle_lock_image(int r);
void send_close_image(int r);
void handle_close_image(int r);
void finish(int r);
};
} // namespace image_replayer
} // namespace mirror
} // namespace rbd
extern template class rbd::mirror::image_replayer::OpenLocalImageRequest<librbd::ImageCtx>;
#endif // RBD_MIRROR_IMAGE_REPLAYER_OPEN_LOCAL_IMAGE_REQUEST_H