CephFS inode trimming fix from Zheng, marked for stable.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQEcBAABCAAGBQJaM/Y/AAoJEEp/3jgCEfOLSu0H/iFhQS+7rnyPcb3P8/YR785H
 IMPNWv8hg4UU6MDWC3lIliAPypAkaMLuEKOZvBRsLCW5esbOTlCP7w4bmO/YCI66
 DF0JfA4AV5yXIVMAtjP2EK3sFz0eCrK6S3XP3cT+x3K5qI6zwNN3Yvj78NFcvCOz
 IBgxrlhpu7/DfBsorhKEAEHXaYE+NKJNlcGBIisvM0BNC9dcm7ufTkP7pP6mRJC0
 GjjYqh8HMe45AvvIaE7o976M1GKexEDNsncHM8VlxuwkC5hz0SNAg73J7iwcDfUe
 hqfLeHcvTOrPQ0oB4Xz0Nh6cJ7tIv3gYZ941awhmH6XZCWgZhrBaLyipIenXEHM=
 =xpe2
 -----END PGP SIGNATURE-----

Merge tag 'ceph-for-4.15-rc4' of git://github.com/ceph/ceph-client

Pull ceph fix from Ilya Dryomov:
 "CephFS inode trimming fix from Zheng, marked for stable"

* tag 'ceph-for-4.15-rc4' of git://github.com/ceph/ceph-client:
  ceph: drop negative child dentries before try pruning inode's alias
This commit is contained in:
Linus Torvalds 2017-12-15 12:48:27 -08:00
commit dd3d66b838
1 changed files with 38 additions and 4 deletions

View File

@ -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);
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, atomic_read(&inode->i_count));
inode, cap, count);
} else {
dput(dentry);
}
return 0;
}