--- x/fs/eventpoll.c +++ y/fs/eventpoll.c @@ -718,7 +718,7 @@ static void ep_free(struct eventpoll *ep * while running concurrently with eventpoll_release_file(). * Returns true if the eventpoll can be disposed. */ -static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) +static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force, int *del) { struct file *file = epi->ffd.file; struct epitems_head *to_free; @@ -726,6 +726,8 @@ static bool __ep_remove(struct eventpoll lockdep_assert_irqs_enabled(); + if (del) + *del = 0; /* * Removes poll wait queue hooks. */ @@ -754,6 +756,8 @@ static bool __ep_remove(struct eventpoll free_ephead(to_free); rb_erase_cached(&epi->rbn, &ep->rbr); + if (del) + *del = 1; write_lock_irq(&ep->lock); if (ep_is_linked(epi)) @@ -779,7 +783,7 @@ static bool __ep_remove(struct eventpoll */ static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi) { - WARN_ON_ONCE(__ep_remove(ep, epi, false)); + WARN_ON_ONCE(__ep_remove(ep, epi, false, NULL)); } static void ep_clear_and_put(struct eventpoll *ep) @@ -811,9 +815,16 @@ static void ep_clear_and_put(struct even * dispose it. */ while ((rbp = rb_first_cached(&ep->rbr)) != NULL) { + int del = 0; + epi = rb_entry(rbp, struct epitem, rbn); - ep_remove_safe(ep, epi); + __ep_remove(ep, epi, false, &del); cond_resched(); + if (!del) { /* epi is dying, lock and try again */ + mutex_unlock(&ep->mtx); + udelay(1); + mutex_lock(&ep->mtx); + } } dispose = ep_refcount_dec_and_test(ep); @@ -960,7 +971,7 @@ again: */ ep = epi->ep; mutex_lock(&ep->mtx); - dispose = __ep_remove(ep, epi, true); + dispose = __ep_remove(ep, epi, true, NULL); mutex_unlock(&ep->mtx); if (dispose)