#include "librbd/PluginRegistry.h"
#include "include/Context.h"
#include "common/dout.h"
+#include "librbd/cache/ImageWriteback.h"
#include "librbd/ImageCtx.h"
#include "librbd/plugin/Api.h"
#include <boost/tokenizer.hpp>
template <typename I>
PluginRegistry<I>::PluginRegistry(I* image_ctx)
- : m_image_ctx(image_ctx), m_plugin_api(std::make_unique<plugin::Api<I>>()) {
+ : m_image_ctx(image_ctx), m_plugin_api(std::make_unique<plugin::Api<I>>()),
+ m_image_writeback(std::make_unique<cache::ImageWriteback<I>>(*image_ctx)) {
}
template <typename I>
break;
}
- m_plugin_hook_points.emplace_back();
- auto hook_points = &m_plugin_hook_points.back();
- plugin->init(m_image_ctx, *m_plugin_api, hook_points, ctx);
+ plugin->init(
+ m_image_ctx, *m_plugin_api, *m_image_writeback, m_plugin_hook_points, ctx);
}
gather_ctx->activate();
}
+template <typename I>
+void PluginRegistry<I>::acquired_exclusive_lock(Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ auto gather_ctx = new C_Gather(cct, on_finish);
+
+ for (auto &hook : m_plugin_hook_points) {
+ auto ctx = gather_ctx->new_sub();
+ hook->acquired_exclusive_lock(ctx);
+ }
+ gather_ctx->activate();
+}
+
+template <typename I>
+void PluginRegistry<I>::prerelease_exclusive_lock(Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ auto gather_ctx = new C_Gather(cct, on_finish);
+
+ for (auto &hook : m_plugin_hook_points) {
+ auto ctx = gather_ctx->new_sub();
+ hook->prerelease_exclusive_lock(ctx);
+ }
+ gather_ctx->activate();
+}
+
+template <typename I>
+void PluginRegistry<I>::discard(Context* on_finish) {
+ auto cct = m_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ auto gather_ctx = new C_Gather(cct, on_finish);
+
+ for (auto &hook : m_plugin_hook_points) {
+ auto ctx = gather_ctx->new_sub();
+ hook->discard(ctx);
+ }
+ gather_ctx->activate();
+}
+
} // namespace librbd
template class librbd::PluginRegistry<librbd::ImageCtx>;
struct ImageCtx;
+namespace cache {
+class ImageWritebackInterface;
+}
+
namespace plugin { template <typename> struct Api; }
template <typename ImageCtxT>
void init(const std::string& plugins, Context* on_finish);
-private:
- typedef std::list<plugin::HookPoints> PluginHookPoints;
+ void acquired_exclusive_lock(Context* on_finish);
+ void prerelease_exclusive_lock(Context* on_finish);
+ void discard(Context* on_finish);
+private:
ImageCtxT* m_image_ctx;
std::unique_ptr<plugin::Api<ImageCtxT>> m_plugin_api;
+ std::unique_ptr<cache::ImageWritebackInterface> m_image_writeback;
std::string m_plugins;
- PluginHookPoints m_plugin_hook_points;
+ plugin::PluginHookPoints m_plugin_hook_points;
};
#include "librbd/Utils.h"
#include "librbd/image/RefreshRequest.h"
#include "librbd/journal/Policy.h"
+#include "librbd/PluginRegistry.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
}
if (!journal_enabled) {
apply();
- send_open_image_cache();
+ send_process_plugin_acquire_lock();
return;
}
return;
}
+ send_process_plugin_acquire_lock();
+}
+
+template <typename I>
+void PostAcquireRequest<I>::send_process_plugin_acquire_lock() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << dendl;
+
+ using klass = PostAcquireRequest<I>;
+ Context *ctx = create_context_callback<
+ klass, &klass::handle_process_plugin_acquire_lock>(this);
+ m_image_ctx.plugin_registry->acquired_exclusive_lock(ctx);
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_process_plugin_acquire_lock(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << "r=" << r << dendl;
+
+ save_result(r);
+ if (r < 0) {
+ lderr(cct) << "failed to process plugins: " << cpp_strerror(r)
+ << dendl;
+ send_process_plugin_release_lock();
+ return;
+ }
+
send_open_image_cache();
}
+template <typename I>
+void PostAcquireRequest<I>::send_process_plugin_release_lock() {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << dendl;
+
+ using klass = PostAcquireRequest<I>;
+ Context *ctx = create_context_callback<
+ klass, &klass::handle_process_plugin_release_lock>(this);
+ m_image_ctx.plugin_registry->prerelease_exclusive_lock(ctx);
+}
+
+template <typename I>
+void PostAcquireRequest<I>::handle_process_plugin_release_lock(int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 10) << "r=" << r << dendl;
+
+ save_result(r);
+ if (r < 0) {
+ lderr(cct) << "failed to release plugins: " << cpp_strerror(r)
+ << dendl;
+ }
+ send_close_journal();
+}
+
template <typename I>
void PostAcquireRequest<I>::send_open_image_cache() {
CephContext *cct = m_image_ctx.cct;
if (r < 0) {
lderr(cct) << "failed to open image cache: " << cpp_strerror(r)
<< dendl;
- send_close_journal();
+ send_process_plugin_release_lock();
return;
}
* | * *
* | * *
* v * *
- * OPEN_IMAGE_CACHE * *
+ * PROCESS_PLUGIN_ACQUIRE*
+ * | * *
+ * | * *
+ * v * *
+ * OPEN_IMAGE_CACHE *
* | * * *
* | * * *
* | v v v
+ * | PROCESS_PLUGIN_RELEASE
+ * | |
+ * | v
* | CLOSE_JOURNAL
* | |
* | v
void send_close_object_map();
void handle_close_object_map(int r);
+ void send_process_plugin_acquire_lock();
+ void handle_process_plugin_acquire_lock(int r);
+
+ void send_process_plugin_release_lock();
+ void handle_process_plugin_release_lock(int r);
+
void send_open_image_cache();
void handle_open_image_cache(int r);
- void send_close_image_cache();
- void handle_close_image_cache(int r);
-
void apply();
void revert();
#include "librbd/io/ImageDispatcherInterface.h"
#include "librbd/io/ObjectDispatcherInterface.h"
#include "librbd/io/Types.h"
+#include "librbd/PluginRegistry.h"
#define dout_subsys ceph_subsys_rbd
#undef dout_prefix
template <typename I>
void PreReleaseRequest<I>::send_prepare_lock() {
if (m_shutting_down) {
- send_shut_down_image_cache();
+ send_process_plugin_release_lock();
return;
}
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << "r=" << r << dendl;
- send_shut_down_image_cache();
+ send_process_plugin_release_lock();
}
template <typename I>
-void PreReleaseRequest<I>::send_shut_down_image_cache() {
+void PreReleaseRequest<I>::send_process_plugin_release_lock() {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << dendl;
std::shared_lock owner_lock{m_image_ctx.owner_lock};
Context *ctx = create_async_context_callback(m_image_ctx, create_context_callback<
PreReleaseRequest<I>,
- &PreReleaseRequest<I>::handle_shut_down_image_cache>(this));
- m_image_ctx.io_image_dispatcher->shut_down_dispatch(
- io::IMAGE_DISPATCH_LAYER_WRITEBACK_CACHE, ctx);
+ &PreReleaseRequest<I>::handle_process_plugin_release_lock>(this));
+ m_image_ctx.plugin_registry->prerelease_exclusive_lock(ctx);
}
template <typename I>
-void PreReleaseRequest<I>::handle_shut_down_image_cache(int r) {
+void PreReleaseRequest<I>::handle_process_plugin_release_lock(int r) {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << "r=" << r << dendl;
if (r < 0) {
- lderr(cct) << "failed to shut down image cache: " << cpp_strerror(r)
- << dendl;
+ lderr(cct) << "failed to handle plugins before releasing lock: "
+ << cpp_strerror(r) << dendl;
m_image_dispatch->unset_require_lock(io::DIRECTION_BOTH);
save_result(r);
finish();
* PREPARE_LOCK
* |
* v
+ * PROCESS_PLUGIN_RELEASE
+ * |
+ * v
* SHUT_DOWN_IMAGE_CACHE
* |
* v
void send_prepare_lock();
void handle_prepare_lock(int r);
+ void send_process_plugin_release_lock();
+ void handle_process_plugin_release_lock(int r);
+
void send_shut_down_image_cache();
void handle_shut_down_image_cache(int r);
namespace plugin {
template <typename I>
-void ParentCache<I>::init(I* image_ctx, Api<I>& api, HookPoints* hook_points,
+void ParentCache<I>::init(I* image_ctx, Api<I>& api,
+ cache::ImageWritebackInterface& image_writeback,
+ PluginHookPoints& hook_points_list,
Context* on_finish) {
bool parent_cache_enabled = image_ctx->config.template get_val<bool>(
"rbd_parent_cache_enabled");
ParentCache(CephContext* cct) : Interface<ImageCtxT>(cct) {
}
- void init(ImageCtxT* image_ctx, Api<ImageCtxT>& api, HookPoints* hook_points,
+ void init(ImageCtxT* image_ctx, Api<ImageCtxT>& api,
+ cache::ImageWritebackInterface& image_writeback,
+ PluginHookPoints& hook_points_list,
Context* on_finish) override;
private:
#define CEPH_LIBRBD_PLUGIN_TYPES_H
#include "include/common_fwd.h"
+#include "include/Context.h"
#include "common/PluginRegistry.h"
-
-struct Context;
+#include "librbd/cache/ImageWriteback.h"
namespace librbd {
namespace plugin {
template <typename> struct Api;
struct HookPoints {
- // TODO later commits will add support for exclusive-lock hook points
+ virtual ~HookPoints() {
+ }
+ virtual void acquired_exclusive_lock(Context* on_finish) = 0;
+ virtual void prerelease_exclusive_lock(Context* on_finish) = 0;
+ virtual void discard(Context* on_finish) {
+ on_finish->complete(0);
+ }
};
+typedef std::list<std::unique_ptr<HookPoints>> PluginHookPoints;
+
template <typename ImageCtxT>
struct Interface : public ceph::Plugin {
Interface(CephContext* cct) : Plugin(cct) {
}
+ virtual ~Interface() {
+ }
+
virtual void init(ImageCtxT* image_ctx, Api<ImageCtxT>& api,
- HookPoints* hook_points, Context* on_finish) = 0;
+ librbd::cache::ImageWritebackInterface& image_writeback,
+ PluginHookPoints& hook_points_list, Context* on_finish) = 0;
};
} // namespace plugin
EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete());
}
- void expect_init_image_cache(MockTestImageCtx &mock_image_ctx,
- MockInitRequest &mock_init_request, int r) {
- EXPECT_CALL(mock_init_request, send())
- .WillOnce(FinishRequest(&mock_init_request, r, &mock_image_ctx));
+ void expect_acquired_exclusive_lock(MockTestImageCtx &mock_image_ctx, int r) {
+ EXPECT_CALL(*mock_image_ctx.plugin_registry, acquired_exclusive_lock(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
+ }
+
+ void expect_prerelease_exclusive_lock(MockTestImageCtx &mock_image_ctx, int r) {
+ EXPECT_CALL(*mock_image_ctx.plugin_registry, prerelease_exclusive_lock(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
}
};
expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
+ expect_acquired_exclusive_lock(mock_image_ctx, 0);
+
MockInitRequest mock_init_request;
expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
C_SaferCond acquire_ctx;
mock_image_ctx.image_lock, false);
expect_handle_prepare_lock_complete(mock_image_ctx);
+ expect_acquired_exclusive_lock(mock_image_ctx, 0);
+
MockInitRequest mock_init_request;
expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
mock_image_ctx.image_lock, false);
expect_handle_prepare_lock_complete(mock_image_ctx);
+ expect_acquired_exclusive_lock(mock_image_ctx, 0);
+
MockInitRequest mock_init_request;
expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
+ expect_acquired_exclusive_lock(mock_image_ctx, 0);
+
MockInitRequest mock_init_request;
expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
mock_image_ctx.image_lock, false);
expect_handle_prepare_lock_complete(mock_image_ctx);
+ expect_acquired_exclusive_lock(mock_image_ctx, 0);
+
MockInitRequest mock_init_request;
expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
+ expect_acquired_exclusive_lock(mock_image_ctx, -ENOENT);
+ expect_prerelease_exclusive_lock(mock_image_ctx, 0);
+
MockInitRequest mock_init_request;
expect_init_image_cache(mock_image_ctx, mock_init_request, -ENOENT);
expect_get_journal_policy(mock_image_ctx, mock_journal_policy);
expect_allocate_journal_tag(mock_image_ctx, mock_journal_policy, 0);
+ expect_acquired_exclusive_lock(mock_image_ctx, 0);
+
MockInitRequest mock_init_request;
expect_init_image_cache(mock_image_ctx, mock_init_request, 0);
.WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
}
- void expect_close_image_cache(MockTestImageCtx &mock_image_ctx, int r) {
- EXPECT_CALL(*mock_image_ctx.io_image_dispatcher,
- shut_down_dispatch(io::IMAGE_DISPATCH_LAYER_WRITEBACK_CACHE, _))
- .WillOnce(WithArg<1>(
- CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
+ void expect_prerelease_exclusive_lock(MockTestImageCtx &mock_image_ctx, int r) {
+ EXPECT_CALL(*mock_image_ctx.plugin_registry, prerelease_exclusive_lock(_))
+ .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
}
void expect_invalidate_cache(MockTestImageCtx &mock_image_ctx,
expect_prepare_lock(mock_image_ctx);
- expect_close_image_cache(mock_image_ctx, 0);
+ expect_prerelease_exclusive_lock(mock_image_ctx, 0);
expect_invalidate_cache(mock_image_ctx, 0);
expect_cancel_op_requests(mock_image_ctx, 0);
expect_prepare_lock(mock_image_ctx);
- expect_close_image_cache(mock_image_ctx, 0);
+ expect_prerelease_exclusive_lock(mock_image_ctx, 0);
expect_invalidate_cache(mock_image_ctx, 0);
InSequence seq;
expect_cancel_op_requests(mock_image_ctx, 0);
- expect_close_image_cache(mock_image_ctx, 0);
+ expect_prerelease_exclusive_lock(mock_image_ctx, 0);
expect_invalidate_cache(mock_image_ctx, 0);
-EBLOCKLISTED);
expect_prepare_lock(mock_image_ctx);
- expect_close_image_cache(mock_image_ctx, 0);
+ expect_prerelease_exclusive_lock(mock_image_ctx, 0);
expect_invalidate_cache(mock_image_ctx, -EBLOCKLISTED);
expect_prepare_lock(mock_image_ctx);
- expect_close_image_cache(mock_image_ctx, 0);
+ expect_prerelease_exclusive_lock(mock_image_ctx, 0);
expect_invalidate_cache(mock_image_ctx, 0);
#include "test/librbd/mock/MockJournal.h"
#include "test/librbd/mock/MockObjectMap.h"
#include "test/librbd/mock/MockOperations.h"
+#include "test/librbd/mock/MockPluginRegistry.h"
#include "test/librbd/mock/MockReadahead.h"
#include "test/librbd/mock/io/MockImageDispatcher.h"
#include "test/librbd/mock/io/MockObjectDispatcher.h"
io_image_dispatcher(new io::MockImageDispatcher()),
io_object_dispatcher(new io::MockObjectDispatcher()),
op_work_queue(new MockContextWQ()),
+ plugin_registry(new MockPluginRegistry()),
readahead_max_bytes(image_ctx.readahead_max_bytes),
event_socket(image_ctx.event_socket),
parent(NULL), operations(new MockOperations()),
delete operations;
delete image_watcher;
delete op_work_queue;
+ delete plugin_registry;
delete io_image_dispatcher;
delete io_object_dispatcher;
}
io::MockObjectDispatcher *io_object_dispatcher;
MockContextWQ *op_work_queue;
+ MockPluginRegistry* plugin_registry;
+
MockReadahead readahead;
uint64_t readahead_max_bytes;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_TEST_LIBRBD_MOCK_PLUGIN_REGISTRY_H
+#define CEPH_TEST_LIBRBD_MOCK_PLUGIN_REGISTRY_H
+
+#include <gmock/gmock.h>
+
+class Context;
+
+namespace librbd {
+
+struct MockPluginRegistry{
+ MOCK_METHOD2(init, void(const std::string&, Context*));
+ MOCK_METHOD1(acquired_exclusive_lock, void(Context*));
+ MOCK_METHOD1(prerelease_exclusive_lock, void(Context*));
+};
+
+} // namespace librbd
+
+#endif // CEPH_TEST_LIBRBD_MOCK_PLUGIN_REGISTRY_H