From: Jason Dillaman Date: Wed, 21 Oct 2015 17:12:48 +0000 (-0400) Subject: librbd: potential assertion failure during cache read X-Git-Tag: v0.94.5~1^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=d3abcbea1fdb04f0994f19584b93f6f1b1ff37ca;p=ceph.git librbd: potential assertion failure during cache read It's possible for a cache read from a clone to trigger a writeback if a previous read op determined the object doesn't exist in the clone, followed by a cached write to the non-existent clone object, followed by another read request to the same object. This causes the cache to flush the pending writeback ops while not holding the owner lock. Fixes: #13559 Backport: hammer Signed-off-by: Jason Dillaman (cherry picked from commit 4692c330bd992a06b97b5b8975ab71952b22477a) --- diff --git a/src/librbd/LibrbdWriteback.cc b/src/librbd/LibrbdWriteback.cc index 058760e6d979..ac778eec5455 100644 --- a/src/librbd/LibrbdWriteback.cc +++ b/src/librbd/LibrbdWriteback.cc @@ -45,15 +45,18 @@ namespace librbd { * @param c context to finish * @param l mutex to lock */ - class C_Request : public Context { + class C_ReadRequest : public Context { public: - C_Request(CephContext *cct, Context *c, Mutex *l) - : m_cct(cct), m_ctx(c), m_lock(l) {} - virtual ~C_Request() {} + C_ReadRequest(CephContext *cct, Context *c, RWLock *owner_lock, + Mutex *cache_lock) + : m_cct(cct), m_ctx(c), m_owner_lock(owner_lock), + m_cache_lock(cache_lock) { + } virtual void finish(int r) { ldout(m_cct, 20) << "aio_cb completing " << dendl; { - Mutex::Locker l(*m_lock); + RWLock::RLocker owner_locker(*m_owner_lock); + Mutex::Locker cache_locker(*m_cache_lock); m_ctx->complete(r); } ldout(m_cct, 20) << "aio_cb finished" << dendl; @@ -61,7 +64,8 @@ namespace librbd { private: CephContext *m_cct; Context *m_ctx; - Mutex *m_lock; + RWLock *m_owner_lock; + Mutex *m_cache_lock; }; class C_OrderedWrite : public Context { @@ -105,7 +109,8 @@ namespace librbd { __u32 trunc_seq, int op_flags, Context *onfinish) { // on completion, take the mutex and then call onfinish. - Context *req = new C_Request(m_ictx->cct, onfinish, &m_lock); + Context *req = new C_ReadRequest(m_ictx->cct, onfinish, &m_ictx->owner_lock, + &m_lock); { if (!m_ictx->object_map.object_may_exist(object_no)) { diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 447e9d00cd5c..7364e6cf101c 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -3563,6 +3563,8 @@ reprotect_and_return_err: return; } + RWLock::RLocker owner_locker(ictx->owner_lock); + // readahead const md_config_t *conf = ictx->cct->_conf; if (ictx->object_cacher && conf->rbd_readahead_max_bytes > 0 &&