From: YunfeiGuan Date: Tue, 8 May 2018 11:35:32 +0000 (+0800) Subject: ceph-fuse: Delete inode's bufferhead was in Tx state would lead a assert fail X-Git-Tag: v13.1.1~31^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=ede7817a36e7b10f01f906000ce3ed621c0fc358;p=ceph.git ceph-fuse: Delete inode's bufferhead was in Tx state would lead a assert fail Prematurely delted the bh which was in Tx state may lead the object can't be closed before its writer of this bh callback. Thus if inode's ref call put_inode decrease ref to zero and release inode's oset.An assert fail occur beacuse the oset can't be emptied. If gather.has_subs() is true, we can't call flush_set_callback() because this would cause a double drop of FILE_CACHE | FILE_BUFFER. Fixes:http://tracker.ceph.com/issues/23837 Signed-off-by: Guan yunfei (cherry picked from commit 07e3bceea78dc8ecd76abb1cafca5c9d1fde521e) --- diff --git a/src/client/Client.cc b/src/client/Client.cc index d87bd1e1bf10c..3c73a1dbe5c9c 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -3739,7 +3739,7 @@ void Client::_invalidate_inode_cache(Inode *in, int64_t off, int64_t len) if (cct->_conf->client_oc) { vector ls; Striper::file_to_extents(cct, in->ino, &in->layout, off, len, in->truncate_size, ls); - objectcacher->discard_set(&in->oset, ls); + objectcacher->discard_writeback(&in->oset, ls, nullptr); } _schedule_invalidate_callback(in, off, len); diff --git a/src/osdc/ObjectCacher.cc b/src/osdc/ObjectCacher.cc index 50f9a8d6a6c07..711e71fc99a04 100644 --- a/src/osdc/ObjectCacher.cc +++ b/src/osdc/ObjectCacher.cc @@ -609,7 +609,8 @@ void ObjectCacher::Object::discard(loff_t off, loff_t len, bh->bl.clear(); bh->set_nocache(true); oc->mark_zero(bh); - return; + // we should mark all Rx bh to zero + continue; } else { assert(bh->waitfor_read.empty()); } @@ -2489,8 +2490,8 @@ void ObjectCacher::discard_writeback(ObjectSet *oset, if (gather.has_subs()) { gather.set_finisher(new FunctionContext( - [this, oset, was_dirty, on_finish](int) { - _discard_finish(oset, was_dirty, on_finish); + [this, oset, on_finish](int) { + _discard_finish(oset, false, on_finish); })); gather.activate(); return;