The ObjectCacher complete the read callback while still holding
the cache lock. This introduces lock ordering issues which are
resolved by queuing the completion to execute in a clean (unlocked)
context.
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
(cherry picked from commit
0024677dc8adfd610418ca47599dd95d3a5a6612)
#include "common/ceph_context.h"
#include "common/dout.h"
#include "common/errno.h"
+#include "common/WorkQueue.h"
#include "librbd/AioRequest.h"
#include "librbd/internal.h"
m_completion->complete_request(m_cct, r);
}
+ void C_CacheRead::complete(int r) {
+ if (!m_enqueued) {
+ // cache_lock creates a lock ordering issue -- so re-execute this context
+ // outside the cache_lock
+ m_enqueued = true;
+ m_image_ctx.op_work_queue->queue(this, r);
+ return;
+ }
+ Context::complete(r);
+ }
+
void C_CacheRead::finish(int r)
{
m_req->complete(r);
class C_CacheRead : public Context {
public:
- explicit C_CacheRead(AioRead *req) : m_req(req) {}
- virtual ~C_CacheRead() {}
+ explicit C_CacheRead(ImageCtx *ictx, AioRead *req)
+ : m_image_ctx(*ictx), m_req(req), m_enqueued(false) {}
+ virtual void complete(int r);
+ protected:
virtual void finish(int r);
private:
+ ImageCtx &m_image_ctx;
AioRead *m_req;
+ bool m_enqueued;
};
}
c->add_request();
if (ictx->object_cacher) {
- C_CacheRead *cache_comp = new C_CacheRead(req);
+ C_CacheRead *cache_comp = new C_CacheRead(ictx, req);
ictx->aio_read_from_cache(q->oid, q->objectno, &req->data(),
q->length, q->offset,
cache_comp, op_flags);