aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2017-11-29 22:59:22 -0500
committerIlya Dryomov <idryomov@gmail.com>2017-12-08 05:07:12 -0500
commit040d786032bf59002d374b86d75b04d97624005c (patch)
treed2f3bfce2cb09ef1f6d7c6ce55b4646b8e3f13c9
parentae64f9bd1d3621b5e60d7363bc20afb46aede215 (diff)
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>
-rw-r--r--fs/ceph/mds_client.c42
1 files changed, 38 insertions, 4 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index ab69dcb70e8a..1b468250e947 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1440,6 +1440,29 @@ static int __close_session(struct ceph_mds_client *mdsc,
1440 return request_close_session(mdsc, session); 1440 return request_close_session(mdsc, session);
1441} 1441}
1442 1442
1443static bool drop_negative_children(struct dentry *dentry)
1444{
1445 struct dentry *child;
1446 bool all_negative = true;
1447
1448 if (!d_is_dir(dentry))
1449 goto out;
1450
1451 spin_lock(&dentry->d_lock);
1452 list_for_each_entry(child, &dentry->d_subdirs, d_child) {
1453 if (d_really_is_positive(child)) {
1454 all_negative = false;
1455 break;
1456 }
1457 }
1458 spin_unlock(&dentry->d_lock);
1459
1460 if (all_negative)
1461 shrink_dcache_parent(dentry);
1462out:
1463 return all_negative;
1464}
1465
1443/* 1466/*
1444 * Trim old(er) caps. 1467 * Trim old(er) caps.
1445 * 1468 *
@@ -1490,16 +1513,27 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
1490 if ((used | wanted) & ~oissued & mine) 1513 if ((used | wanted) & ~oissued & mine)
1491 goto out; /* we need these caps */ 1514 goto out; /* we need these caps */
1492 1515
1493 session->s_trim_caps--;
1494 if (oissued) { 1516 if (oissued) {
1495 /* we aren't the only cap.. just remove us */ 1517 /* we aren't the only cap.. just remove us */
1496 __ceph_remove_cap(cap, true); 1518 __ceph_remove_cap(cap, true);
1519 session->s_trim_caps--;
1497 } else { 1520 } else {
1521 struct dentry *dentry;
1498 /* try dropping referring dentries */ 1522 /* try dropping referring dentries */
1499 spin_unlock(&ci->i_ceph_lock); 1523 spin_unlock(&ci->i_ceph_lock);
1500 d_prune_aliases(inode); 1524 dentry = d_find_any_alias(inode);
1501 dout("trim_caps_cb %p cap %p pruned, count now %d\n", 1525 if (dentry && drop_negative_children(dentry)) {
1502 inode, cap, atomic_read(&inode->i_count)); 1526 int count;
1527 dput(dentry);
1528 d_prune_aliases(inode);
1529 count = atomic_read(&inode->i_count);
1530 if (count == 1)
1531 session->s_trim_caps--;
1532 dout("trim_caps_cb %p cap %p pruned, count now %d\n",
1533 inode, cap, count);
1534 } else {
1535 dput(dentry);
1536 }
1503 return 0; 1537 return 0;
1504 } 1538 }
1505 1539