// vim: ts=8 sw=2 smarttab
#include "librbd/ExclusiveLock.h"
+#include "librbd/ImageCtx.h"
#include "librbd/ImageWatcher.h"
#include "librbd/ImageState.h"
#include "librbd/exclusive_lock/PreAcquireRequest.h"
template <typename I>
bool ExclusiveLock<I>::accept_ops() const {
Mutex::Locker locker(ML<I>::m_lock);
- bool accept_ops = (!ML<I>::is_state_shutdown() &&
- (ML<I>::is_state_locked() ||
- ML<I>::is_state_post_acquiring()));
+ bool accept = accept_ops(ML<I>::m_lock);
+ ldout(m_image_ctx.cct, 20) << "=" << accept << dendl;
+ return accept;
+}
- ldout(m_image_ctx.cct, 20) << "=" << accept_ops << dendl;
- return accept_ops;
+template <typename I>
+bool ExclusiveLock<I>::accept_ops(const Mutex &lock) const {
+ return (!ML<I>::is_state_shutdown() &&
+ (ML<I>::is_state_locked() || ML<I>::is_state_post_acquiring()));
}
template <typename I>
ML<I>::execute_next_action();
}
+template <typename I>
+Context *ExclusiveLock<I>::start_op() {
+ assert(m_image_ctx.owner_lock.is_locked());
+ Mutex::Locker locker(ML<I>::m_lock);
+
+ if (!accept_ops(ML<I>::m_lock)) {
+ return nullptr;
+ }
+
+ m_async_op_tracker.start_op();
+ return new FunctionContext([this](int r) {
+ m_async_op_tracker.finish_op();
+ });
+}
+
template <typename I>
void ExclusiveLock<I>::handle_init_complete(uint64_t features) {
ldout(m_image_ctx.cct, 10) << "features=" << features << dendl;
Mutex::Locker locker(ML<I>::m_lock);
PreReleaseRequest<I> *req = PreReleaseRequest<I>::create(
- m_image_ctx, shutting_down, on_finish);
+ m_image_ctx, shutting_down, m_async_op_tracker, on_finish);
m_image_ctx.op_work_queue->queue(new FunctionContext([req](int r) {
req->send();
}));
#define CEPH_LIBRBD_EXCLUSIVE_LOCK_H
#include "librbd/ManagedLock.h"
-#include "librbd/ImageCtx.h"
+#include "common/AsyncOpTracker.h"
namespace librbd {
void handle_peer_notification(int r);
+ Context *start_op();
+
protected:
void shutdown_handler(int r, Context *on_finish) override;
void pre_acquire_lock_handler(Context *on_finish) override;
ImageCtxT& m_image_ctx;
Context *m_pre_post_callback = nullptr;
+ AsyncOpTracker m_async_op_tracker;
+
uint32_t m_request_blocked_count = 0;
int m_request_blocked_ret_val = 0;
int m_acquire_lock_peer_ret_val = 0;
+ bool accept_ops(const Mutex &lock) const;
+
void handle_init_complete(uint64_t features);
void handle_post_acquiring_lock(int r);
void handle_post_acquired_lock(int r);
// vim: ts=8 sw=2 smarttab
#include "librbd/exclusive_lock/PreReleaseRequest.h"
+#include "common/AsyncOpTracker.h"
#include "common/dout.h"
#include "common/errno.h"
#include "librbd/ExclusiveLock.h"
using util::create_context_callback;
template <typename I>
-PreReleaseRequest<I>* PreReleaseRequest<I>::create(I &image_ctx,
- bool shutting_down,
- Context *on_finish) {
- return new PreReleaseRequest(image_ctx, shutting_down, on_finish);
+PreReleaseRequest<I>* PreReleaseRequest<I>::create(
+ I &image_ctx, bool shutting_down, AsyncOpTracker &async_op_tracker,
+ Context *on_finish) {
+ return new PreReleaseRequest(image_ctx, shutting_down, async_op_tracker,
+ on_finish);
}
template <typename I>
PreReleaseRequest<I>::PreReleaseRequest(I &image_ctx, bool shutting_down,
+ AsyncOpTracker &async_op_tracker,
Context *on_finish)
- : m_image_ctx(image_ctx),
- m_on_finish(create_async_context_callback(image_ctx, on_finish)),
- m_shutting_down(shutting_down), m_error_result(0), m_object_map(nullptr),
- m_journal(nullptr) {
+ : m_image_ctx(image_ctx), m_shutting_down(shutting_down),
+ m_async_op_tracker(async_op_tracker),
+ m_on_finish(create_async_context_callback(image_ctx, on_finish)) {
}
template <typename I>
return;
}
+ send_wait_for_ops();
+}
+
+template <typename I>
+void PreReleaseRequest<I>::send_wait_for_ops() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << dendl;
+
+ Context *ctx = create_context_callback<
+ PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_wait_for_ops>(this);
+ m_async_op_tracker.wait_for_ops(ctx);
+}
+
+template <typename I>
+void PreReleaseRequest<I>::handle_wait_for_ops(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << dendl;
+
send_invalidate_cache(false);
}
#include "librbd/ImageCtx.h"
#include <string>
+class AsyncOpTracker;
class Context;
namespace librbd {
class PreReleaseRequest {
public:
static PreReleaseRequest* create(ImageCtxT &image_ctx, bool shutting_down,
+ AsyncOpTracker &async_op_tracker,
Context *on_finish);
~PreReleaseRequest();
* BLOCK_WRITES
* |
* v
+ * WAIT_FOR_OPS
+ * |
+ * v
* INVALIDATE_CACHE
* |
* v
*/
PreReleaseRequest(ImageCtxT &image_ctx, bool shutting_down,
- Context *on_finish);
+ AsyncOpTracker &async_op_tracker, Context *on_finish);
ImageCtxT &m_image_ctx;
- Context *m_on_finish;
bool m_shutting_down;
+ AsyncOpTracker &m_async_op_tracker;
+ Context *m_on_finish;
- int m_error_result;
+ int m_error_result = 0;
- decltype(m_image_ctx.object_map) m_object_map;
- decltype(m_image_ctx.journal) m_journal;
+ decltype(m_image_ctx.object_map) m_object_map = nullptr;
+ decltype(m_image_ctx.journal) m_journal = nullptr;
void send_prepare_lock();
void handle_prepare_lock(int r);
void send_block_writes();
void handle_block_writes(int r);
+ void send_wait_for_ops();
+ void handle_wait_for_ops(int r);
+
void send_invalidate_cache(bool purge_on_error);
void handle_invalidate_cache(int r);
#include "test/librbd/mock/MockJournal.h"
#include "test/librbd/mock/MockObjectMap.h"
#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "common/AsyncOpTracker.h"
#include "librbd/exclusive_lock/PreReleaseRequest.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
}
+ AsyncOpTracker m_async_op_tracker;
};
TEST_F(TestMockExclusiveLockPreReleaseRequest, Success) {
C_SaferCond ctx;
MockPreReleaseRequest *req = MockPreReleaseRequest::create(
- mock_image_ctx, false, &ctx);
+ mock_image_ctx, false, m_async_op_tracker, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
C_SaferCond ctx;
MockPreReleaseRequest *req = MockPreReleaseRequest::create(
- mock_image_ctx, false, &ctx);
+ mock_image_ctx, false, m_async_op_tracker, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
C_SaferCond release_ctx;
C_SaferCond ctx;
MockPreReleaseRequest *req = MockPreReleaseRequest::create(
- mock_image_ctx, true, &ctx);
+ mock_image_ctx, true, m_async_op_tracker, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
C_SaferCond ctx;
MockPreReleaseRequest *req = MockPreReleaseRequest::create(
- mock_image_ctx, false, &ctx);
+ mock_image_ctx, false, m_async_op_tracker, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
C_SaferCond ctx;
MockPreReleaseRequest *req = MockPreReleaseRequest::create(
- mock_image_ctx, true, &ctx);
+ mock_image_ctx, true, m_async_op_tracker, &ctx);
req->send();
ASSERT_EQ(-EINVAL, ctx.wait());
}
C_SaferCond ctx;
MockPreReleaseRequest *req = MockPreReleaseRequest::create(
- mock_image_ctx, true, &ctx);
+ mock_image_ctx, true, m_async_op_tracker, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
MOCK_METHOD0(accept_requests, bool());
MOCK_METHOD0(accept_ops, bool());
+
+ MOCK_METHOD0(start_op, Context*());
};
} // namespace librbd
struct PreReleaseRequest<MockExclusiveLockImageCtx> : public BaseRequest<PreReleaseRequest<MockExclusiveLockImageCtx> > {
static PreReleaseRequest<MockExclusiveLockImageCtx> *create(
MockExclusiveLockImageCtx &image_ctx, bool shutting_down,
- Context *on_finish) {
+ AsyncOpTracker &async_op_tracker, Context *on_finish) {
return BaseRequest::create(image_ctx, nullptr, on_finish);
}
MOCK_METHOD0(send, void());