]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
client: anchor Inode while trimming caps 19105/head
authorPatrick Donnelly <pdonnell@redhat.com>
Sun, 19 Nov 2017 23:08:18 +0000 (15:08 -0800)
committerPatrick Donnelly <pdonnell@redhat.com>
Wed, 22 Nov 2017 21:49:57 +0000 (13:49 -0800)
This prevents the Inode from being deleted until after cap trimming is
finished. In particular, this prevents remove_all_caps from being called which
screws up the traversal of caps in trim_caps.

Fixes: http://tracker.ceph.com/issues/22157
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
(cherry picked from commit 1439337e949c9fcb7d15eb38c22d19eb57d3d0f2)

src/client/Client.cc

index 1d9277a61b6ecfb1d5c01f83d2aedc4418600e3f..55c00695db60d575679017d57453f4f7842f4c41 100644 (file)
@@ -4068,9 +4068,10 @@ void Client::trim_caps(MetaSession *s, int max)
 
   int trimmed = 0;
   xlist<Cap*>::iterator p = s->caps.begin();
+  std::set<InodeRef> anchor; /* prevent put_inode from deleting all caps during traversal */
   while ((caps_size - trimmed) > max && !p.end()) {
     Cap *cap = *p;
-    Inode *in = cap->inode;
+    InodeRef in(cap->inode);
 
     // Increment p early because it will be invalidated if cap
     // is deleted inside remove_cap
@@ -4080,16 +4081,16 @@ void Client::trim_caps(MetaSession *s, int max)
       int mine = cap->issued | cap->implemented;
       int oissued = in->auth_cap ? in->auth_cap->issued : 0;
       // disposable non-auth cap
-      if (!(get_caps_used(in) & ~oissued & mine)) {
+      if (!(get_caps_used(in.get()) & ~oissued & mine)) {
        ldout(cct, 20) << " removing unused, unneeded non-auth cap on " << *in << dendl;
        remove_cap(cap, true);
+        /* N.B. no need to push onto anchor, as we are only removing one cap */
        trimmed++;
       }
     } else {
       ldout(cct, 20) << " trying to trim dentries for " << *in << dendl;
       bool all = true;
       set<Dentry*>::iterator q = in->dn_set.begin();
-      InodeRef tmp_ref(in);
       while (q != in->dn_set.end()) {
        Dentry *dn = *q++;
        if (dn->lru_is_expireable()) {
@@ -4100,6 +4101,8 @@ void Client::trim_caps(MetaSession *s, int max)
            // the end of this function.
            _schedule_invalidate_dentry_callback(dn, true);
          }
+          ldout(cct, 20) << " anchoring inode: " << in->ino << dendl;
+          anchor.insert(in);
          trim_dentry(dn);
         } else {
           ldout(cct, 20) << "  not expirable: " << dn->name << dendl;
@@ -4112,6 +4115,8 @@ void Client::trim_caps(MetaSession *s, int max)
       }
     }
   }
+  ldout(cct, 20) << " clearing anchored inodes" << dendl;
+  anchor.clear();
 
   if (s->caps.size() > max)
     _invalidate_kernel_dcache();