]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: avoid freeing inode when it contains TX buffer heads 22136/head
authorYunfeiGuan <yunfeiguan@xtaotech.com>
Tue, 8 May 2018 11:35:32 +0000 (19:35 +0800)
committerYan, Zheng <zyan@redhat.com>
Tue, 22 May 2018 03:02:43 +0000 (11:02 +0800)
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 <yunfei.guan@xtaotech.com>
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
(cherry picked from commit 8a03757ca0ab493c6c2ea4fa4307e053e8ebc944)

src/client/Client.cc
src/osdc/ObjectCacher.cc

index d87bd1e1bf10c7cf6b01057b2a6dcfbcb84791b0..3c73a1dbe5c9ce58f92c3ac12b4f347426888efa 100644 (file)
@@ -3739,7 +3739,7 @@ void Client::_invalidate_inode_cache(Inode *in, int64_t off, int64_t len)
   if (cct->_conf->client_oc) {
     vector<ObjectExtent> 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);
index 50f9a8d6a6c07de069bcb044606fc2eff1258c51..4b658408ab2cf643cf38f3e37570a8143b7c64ae 100644 (file)
@@ -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;