From 1439337e949c9fcb7d15eb38c22d19eb57d3d0f2 Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Sun, 19 Nov 2017 15:08:18 -0800 Subject: [PATCH] client: anchor Inode while trimming caps 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 --- src/client/Client.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 678184787a2..5b43fad0a00 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -4058,9 +4058,10 @@ void Client::trim_caps(MetaSession *s, uint64_t max) uint64_t trimmed = 0; xlist::iterator p = s->caps.begin(); + std::set 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 @@ -4070,16 +4071,16 @@ void Client::trim_caps(MetaSession *s, uint64_t 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::iterator q = in->dn_set.begin(); - InodeRef tmp_ref(in); while (q != in->dn_set.end()) { Dentry *dn = *q++; if (dn->lru_is_expireable()) { @@ -4090,6 +4091,8 @@ void Client::trim_caps(MetaSession *s, uint64_t 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; @@ -4102,6 +4105,8 @@ void Client::trim_caps(MetaSession *s, uint64_t max) } } } + ldout(cct, 20) << " clearing anchored inodes" << dendl; + anchor.clear(); caps_size = s->caps.size(); if (caps_size > max) -- 2.39.5