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:
		| @@ -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; | ||||
| 	} | ||||
| 
 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user