diff options
author | Yan, Zheng <zyan@redhat.com> | 2017-11-29 22:59:22 -0500 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2017-12-08 05:07:12 -0500 |
commit | 040d786032bf59002d374b86d75b04d97624005c (patch) | |
tree | d2f3bfce2cb09ef1f6d7c6ce55b4646b8e3f13c9 | |
parent | ae64f9bd1d3621b5e60d7363bc20afb46aede215 (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.c | 42 |
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 | ||
1443 | static 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); | ||
1462 | out: | ||
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 | ||