Signed-off-by: Al Viro --- fs/dcache.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index beb0523c3304..1f4435b7f9ce 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -630,12 +630,14 @@ struct completion_list { * Use ->waiters for a single-linked list of struct completion_list of * waiters. */ -static inline void d_add_waiter(struct dentry *dentry, struct completion_list *p) +static inline bool d_add_waiter(struct dentry *dentry, struct completion_list *p) { - struct completion_list *v = dentry->waiters; + if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) + return false; init_completion(&p->completion); - p->next = v; + p->next = dentry->waiters; dentry->waiters = p; + return true; } static inline void d_complete_waiters(struct dentry *dentry) @@ -1705,7 +1707,9 @@ static enum d_walk_ret select_collect2(void *_data, struct dentry *dentry) static void shrink_dcache_tree(struct dentry *parent, bool for_umount) { for (;;) { - struct select_data data = {.start = parent}; + struct completion_list wait; + bool need_wait = false; + struct select_data data = { .start = parent }; INIT_LIST_HEAD(&data.dispose); d_walk(parent, &data, @@ -1737,22 +1741,18 @@ static void shrink_dcache_tree(struct dentry *parent, bool for_umount) spin_lock(&v->d_lock); rcu_read_unlock(); - if (v->d_lockref.count < 0 && - !(v->d_flags & DCACHE_DENTRY_KILLED)) { - struct completion_list wait; - // It's busy dying; have it notify us once - // it becomes invisible to d_walk(). - d_add_waiter(v, &wait); + if (unlikely(v->d_lockref.count < 0)) { + // It's doomed; if it isn't dead yet, notify us + // once it becomes invisible to d_walk(). + need_wait = d_add_waiter(v, &wait); spin_unlock(&v->d_lock); - if (!list_empty(&data.dispose)) - shrink_dentry_list(&data.dispose); - wait_for_completion(&wait.completion); - continue; + } else { + shrink_kill(v); } - shrink_kill(v); } - if (!list_empty(&data.dispose)) - shrink_dentry_list(&data.dispose); + shrink_dentry_list(&data.dispose); + if (unlikely(need_wait)) + wait_for_completion(&wait.completion); } } -- 2.47.3