]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: pin parent dentry of inode who has ll_ref > 0 1606/head
authorYan, Zheng <zheng.z.yan@intel.com>
Sat, 5 Apr 2014 14:16:08 +0000 (22:16 +0800)
committerYan, Zheng <zheng.z.yan@intel.com>
Mon, 7 Apr 2014 05:36:05 +0000 (13:36 +0800)
This prevents Client:trim_dentry() from unlinking parent dentry of
directory inode referenced by fuse kernel module.

Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
src/client/Client.cc

index 79c724cb5736a58fc87f135c67d7c99efd48996e..7093d3cadd4d91c22900c3bc01c44bb7d666b2d7 100644 (file)
@@ -2203,8 +2203,12 @@ Dentry* Client::link(Dir *dir, const string& name, Inode *in, Dentry *dn)
   if (in) {    // link to inode
     dn->inode = in;
     in->get();
-    if (in->dir)
-      dn->get();  // dir -> dn pin
+    if (in->is_dir()) {
+      if (in->dir)
+       dn->get(); // dir -> dn pin
+      if (in->ll_ref)
+       dn->get(); // ll_ref -> dn pin
+    }
 
     assert(in->dn_set.count(dn) == 0);
 
@@ -2231,8 +2235,12 @@ void Client::unlink(Dentry *dn, bool keepdir)
 
   // unlink from inode
   if (in) {
-    if (in->dir)
-      dn->put();        // dir -> dn pin
+    if (in->is_dir()) {
+      if (in->dir)
+       dn->put(); // dir -> dn pin
+      if (in->ll_ref)
+       dn->put(); // ll_ref -> dn pin
+    }
     dn->inode = 0;
     assert(in->dn_set.count(dn));
     in->dn_set.erase(dn);
@@ -7031,8 +7039,13 @@ int Client::ll_walk(const char* name, Inode **i, struct stat *attr)
 
 void Client::_ll_get(Inode *in)
 {
-  if (in->ll_ref == 0)
+  if (in->ll_ref == 0) {
     in->get();
+    if (in->is_dir() && !in->dn_set.empty()) {
+      assert(in->dn_set.size() == 1); // dirs can't be hard-linked
+      in->get_first_parent()->get(); // pin dentry
+    }
+  }
   in->ll_get();
   ldout(cct, 20) << "_ll_get " << in << " " << in->ino << " -> " << in->ll_ref << dendl;
 }
@@ -7042,6 +7055,10 @@ int Client::_ll_put(Inode *in, int num)
   in->ll_put(num);
   ldout(cct, 20) << "_ll_put " << in << " " << in->ino << " " << num << " -> " << in->ll_ref << dendl;
   if (in->ll_ref == 0) {
+    if (in->is_dir() && !in->dn_set.empty()) {
+      assert(in->dn_set.size() == 1); // dirs can't be hard-linked
+      in->get_first_parent()->put(); // unpin dentry
+    }
     put_inode(in);
     return 0;
   } else {
@@ -7081,8 +7098,8 @@ bool Client::ll_forget(Inode *in, int count)
     ldout(cct, 1) << "WARNING: ll_forget on " << ino << " " << count
                  << ", which only has ll_ref=" << in->ll_ref << dendl;
     _ll_put(in, in->ll_ref);
-      last = true;
-    } else {
+    last = true;
+  } else {
     if (_ll_put(in, count) == 0)
       last = true;
   }