ceph: drop negative child dentries before try pruning inode's alias
Negative child dentry holds reference on inode's alias, it makes d_prune_aliases() do nothing. Cc: stable@vger.kernel.org Signed-off-by: "Yan, Zheng" <zyan@redhat.com> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
parent
ae64f9bd1d
commit
040d786032
1 changed files with 38 additions and 4 deletions
|
@ -1440,6 +1440,29 @@ 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_negative = 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_negative = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&dentry->d_lock);
|
||||
|
||||
if (all_negative)
|
||||
shrink_dcache_parent(dentry);
|
||||
out:
|
||||
return all_negative;
|
||||
}
|
||||
|
||||
/*
|
||||
* Trim old(er) caps.
|
||||
*
|
||||
|
@ -1490,16 +1513,27 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
|
|||
if ((used | wanted) & ~oissued & mine)
|
||||
goto out; /* we need these caps */
|
||||
|
||||
session->s_trim_caps--;
|
||||
if (oissued) {
|
||||
/* we aren't the only cap.. just remove us */
|
||||
__ceph_remove_cap(cap, true);
|
||||
session->s_trim_caps--;
|
||||
} else {
|
||||
struct dentry *dentry;
|
||||
/* try dropping referring dentries */
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
d_prune_aliases(inode);
|
||||
dout("trim_caps_cb %p cap %p pruned, count now %d\n",
|
||||
inode, cap, atomic_read(&inode->i_count));
|
||||
dentry = d_find_any_alias(inode);
|
||||
if (dentry && drop_negative_children(dentry)) {
|
||||
int count;
|
||||
dput(dentry);
|
||||
d_prune_aliases(inode);
|
||||
count = atomic_read(&inode->i_count);
|
||||
if (count == 1)
|
||||
session->s_trim_caps--;
|
||||
dout("trim_caps_cb %p cap %p pruned, count now %d\n",
|
||||
inode, cap, count);
|
||||
} else {
|
||||
dput(dentry);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue