|
@@ -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;
|
|
|
}
|
|
|
|