Commit cb55ed7f authored by Al Viro's avatar Al Viro Committed by Greg Kroah-Hartman

dentry_kill(): don't try to remove from shrink list

commit 41edf278 upstream.

If the victim in on the shrink list, don't remove it from there.
If shrink_dentry_list() manages to remove it from the list before
we are done - fine, we'll just free it as usual.  If not - mark
it with new flag (DCACHE_MAY_FREE) and leave it there.

Eventually, shrink_dentry_list() will get to it, remove the sucker
from shrink list and call dentry_kill(dentry, 0).  Which is where
we'll deal with freeing.

Since now dentry_kill(dentry, 0) may happen after or during
dentry_kill(dentry, 1), we need to recognize that (by seeing
DCACHE_DENTRY_KILLED already set), unlock everything
and either free the sucker (in case DCACHE_MAY_FREE has been
set) or leave it for ongoing dentry_kill(dentry, 1) to deal with.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Cc: "Nicholas A. Bellinger" <nab@linux-iscsi.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 065c70fd
...@@ -466,7 +466,14 @@ dentry_kill(struct dentry *dentry, int unlock_on_failure) ...@@ -466,7 +466,14 @@ dentry_kill(struct dentry *dentry, int unlock_on_failure)
__releases(dentry->d_lock) __releases(dentry->d_lock)
{ {
struct inode *inode; struct inode *inode;
struct dentry *parent; struct dentry *parent = NULL;
bool can_free = true;
if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) {
can_free = dentry->d_flags & DCACHE_MAY_FREE;
spin_unlock(&dentry->d_lock);
goto out;
}
inode = dentry->d_inode; inode = dentry->d_inode;
if (inode && !spin_trylock(&inode->i_lock)) { if (inode && !spin_trylock(&inode->i_lock)) {
...@@ -477,9 +484,7 @@ dentry_kill(struct dentry *dentry, int unlock_on_failure) ...@@ -477,9 +484,7 @@ dentry_kill(struct dentry *dentry, int unlock_on_failure)
} }
return dentry; /* try again with same dentry */ return dentry; /* try again with same dentry */
} }
if (IS_ROOT(dentry)) if (!IS_ROOT(dentry))
parent = NULL;
else
parent = dentry->d_parent; parent = dentry->d_parent;
if (parent && !spin_trylock(&parent->d_lock)) { if (parent && !spin_trylock(&parent->d_lock)) {
if (inode) if (inode)
...@@ -502,8 +507,6 @@ dentry_kill(struct dentry *dentry, int unlock_on_failure) ...@@ -502,8 +507,6 @@ dentry_kill(struct dentry *dentry, int unlock_on_failure)
if (dentry->d_flags & DCACHE_LRU_LIST) { if (dentry->d_flags & DCACHE_LRU_LIST) {
if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) if (!(dentry->d_flags & DCACHE_SHRINK_LIST))
d_lru_del(dentry); d_lru_del(dentry);
else
d_shrink_del(dentry);
} }
/* if it was on the hash then remove it */ /* if it was on the hash then remove it */
__d_drop(dentry); __d_drop(dentry);
...@@ -525,7 +528,15 @@ dentry_kill(struct dentry *dentry, int unlock_on_failure) ...@@ -525,7 +528,15 @@ dentry_kill(struct dentry *dentry, int unlock_on_failure)
if (dentry->d_op && dentry->d_op->d_release) if (dentry->d_op && dentry->d_op->d_release)
dentry->d_op->d_release(dentry); dentry->d_op->d_release(dentry);
dentry_free(dentry); spin_lock(&dentry->d_lock);
if (dentry->d_flags & DCACHE_SHRINK_LIST) {
dentry->d_flags |= DCACHE_MAY_FREE;
can_free = false;
}
spin_unlock(&dentry->d_lock);
out:
if (likely(can_free))
dentry_free(dentry);
return parent; return parent;
} }
...@@ -830,7 +841,7 @@ static void shrink_dentry_list(struct list_head *list) ...@@ -830,7 +841,7 @@ static void shrink_dentry_list(struct list_head *list)
* We found an inuse dentry which was not removed from * We found an inuse dentry which was not removed from
* the LRU because of laziness during lookup. Do not free it. * the LRU because of laziness during lookup. Do not free it.
*/ */
if (dentry->d_lockref.count) { if ((int)dentry->d_lockref.count > 0) {
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
continue; continue;
} }
......
...@@ -221,6 +221,8 @@ struct dentry_operations { ...@@ -221,6 +221,8 @@ struct dentry_operations {
#define DCACHE_SYMLINK_TYPE 0x00300000 /* Symlink */ #define DCACHE_SYMLINK_TYPE 0x00300000 /* Symlink */
#define DCACHE_FILE_TYPE 0x00400000 /* Other file type */ #define DCACHE_FILE_TYPE 0x00400000 /* Other file type */
#define DCACHE_MAY_FREE 0x00800000
extern seqlock_t rename_lock; extern seqlock_t rename_lock;
static inline int dname_external(const struct dentry *dentry) static inline int dname_external(const struct dentry *dentry)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment