diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-15 12:48:27 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-15 12:48:27 -0800 | 
| commit | dd3d66b8381a33f6d992e5890883e1d9fc8721af (patch) | |
| tree | 3bce1df52836b63e3b0b53d31f1207e9fd9f51f3 /fs | |
| parent | 227701e0e7078065f24f5a6ca220218fd80023a5 (diff) | |
| parent | 040d786032bf59002d374b86d75b04d97624005c (diff) | |
| download | linux-dd3d66b8381a33f6d992e5890883e1d9fc8721af.tar.bz2 | |
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
Diffstat (limited to 'fs')
| -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,  	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;  	} |