From: YunfeiGuan Date: Tue, 8 May 2018 11:35:32 +0000 (+0800) Subject: client: avoid freeing inode when it contains TX buffer heads X-Git-Tag: v12.2.6~74^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a6182cef9c0e31560dc3222d3345cd71aed07ab2;p=ceph.git client: avoid freeing inode when it contains TX buffer heads ObjectCacher::discard_set() prematurely delete TX buffer heads. But the pending writebacks still pin parent objects of these buffer heads. Assertion "oset.objects.empty()" gets triggered if inode with pending writebacks get freed. Fixes:http://tracker.ceph.com/issues/23837 Signed-off-by: Guan yunfei Signed-off-by: "Yan, Zheng" (cherry picked from commit 8a03757ca0ab493c6c2ea4fa4307e053e8ebc944) --- diff --git a/src/client/Client.cc b/src/client/Client.cc index 044c29f3a081..4dd66e9779df 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -3762,7 +3762,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 d031fe071382..bb974bed670f 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()); } @@ -2488,9 +2489,14 @@ void ObjectCacher::discard_writeback(ObjectSet *oset, _discard(oset, exls, &gather); if (gather.has_subs()) { + bool flushed = was_dirty && oset->dirty_or_tx == 0; gather.set_finisher(new FunctionContext( - [this, oset, was_dirty, on_finish](int) { - _discard_finish(oset, was_dirty, on_finish); + [this, oset, flushed, on_finish](int) { + assert(lock.is_locked()); + if (flushed && flush_set_callback) + flush_set_callback(flush_set_callback_arg, oset); + if (on_finish) + on_finish->complete(0); })); gather.activate(); return;