negtive child dentry holds reference on inode's alias, it makes d_prune_aliases() do nothing. Signed-off-by: "Yan, Zheng" <zyan@xxxxxxxxxx> --- fs/ceph/mds_client.c | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index da181acd4a61..9e7bb5fa9295 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1440,6 +1440,30 @@ static int __close_session(struct ceph_mds_client *mdsc, return request_close_session(mdsc, session); } +static bool drop_negative_children(struct dentry *dentry) +{ + struct dentry *child; + bool all_negtive = true; + + if (!d_is_dir(dentry)) + goto out; + + spin_lock(&dentry->d_lock); + list_for_each_entry(child, &dentry->d_subdirs, d_child) { + if (d_really_is_positive(child)) { + all_negtive = false; + break; + } + } + spin_unlock(&dentry->d_lock); + + if (all_negtive) + shrink_dcache_parent(dentry); +out: + dput(dentry); + return all_negtive; +} + /* * Trim old(er) caps. * @@ -1495,15 +1519,20 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg) __ceph_remove_cap(cap, true); session->s_trim_caps--; } else { - int refs; + struct dentry *dentry; /* try dropping referring dentries */ spin_unlock(&ci->i_ceph_lock); - d_prune_aliases(inode); - refs = atomic_read(&inode->i_count); - if (refs == 1) - session->s_trim_caps--; - dout("trim_caps_cb %p cap %p pruned, count now %d\n", - inode, cap, refs); + dentry = d_find_any_alias(inode); + /* drop_negative_children() calls dput() */ + if (dentry && drop_negative_children(dentry)) { + int refs; + d_prune_aliases(inode); + refs = atomic_read(&inode->i_count); + if (refs == 1) + session->s_trim_caps--; + dout("trim_caps_cb %p cap %p pruned, count now %d\n", + inode, cap, refs); + } return 0; } -- 2.13.6 -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html