diff options
-rw-r--r-- | fs/eventpoll.c | 30 | ||||
-rw-r--r-- | fs/signalfd.c | 6 |
2 files changed, 32 insertions, 4 deletions
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 34bbfc6dd8dc..ea54cdef04dd 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -320,6 +320,11 @@ static inline int ep_is_linked(struct list_head *p) | |||
320 | return !list_empty(p); | 320 | return !list_empty(p); |
321 | } | 321 | } |
322 | 322 | ||
323 | static inline struct eppoll_entry *ep_pwq_from_wait(wait_queue_t *p) | ||
324 | { | ||
325 | return container_of(p, struct eppoll_entry, wait); | ||
326 | } | ||
327 | |||
323 | /* Get the "struct epitem" from a wait queue pointer */ | 328 | /* Get the "struct epitem" from a wait queue pointer */ |
324 | static inline struct epitem *ep_item_from_wait(wait_queue_t *p) | 329 | static inline struct epitem *ep_item_from_wait(wait_queue_t *p) |
325 | { | 330 | { |
@@ -467,6 +472,18 @@ static void ep_poll_safewake(wait_queue_head_t *wq) | |||
467 | put_cpu(); | 472 | put_cpu(); |
468 | } | 473 | } |
469 | 474 | ||
475 | static void ep_remove_wait_queue(struct eppoll_entry *pwq) | ||
476 | { | ||
477 | wait_queue_head_t *whead; | ||
478 | |||
479 | rcu_read_lock(); | ||
480 | /* If it is cleared by POLLFREE, it should be rcu-safe */ | ||
481 | whead = rcu_dereference(pwq->whead); | ||
482 | if (whead) | ||
483 | remove_wait_queue(whead, &pwq->wait); | ||
484 | rcu_read_unlock(); | ||
485 | } | ||
486 | |||
470 | /* | 487 | /* |
471 | * This function unregisters poll callbacks from the associated file | 488 | * This function unregisters poll callbacks from the associated file |
472 | * descriptor. Must be called with "mtx" held (or "epmutex" if called from | 489 | * descriptor. Must be called with "mtx" held (or "epmutex" if called from |
@@ -481,7 +498,7 @@ static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) | |||
481 | pwq = list_first_entry(lsthead, struct eppoll_entry, llink); | 498 | pwq = list_first_entry(lsthead, struct eppoll_entry, llink); |
482 | 499 | ||
483 | list_del(&pwq->llink); | 500 | list_del(&pwq->llink); |
484 | remove_wait_queue(pwq->whead, &pwq->wait); | 501 | ep_remove_wait_queue(pwq); |
485 | kmem_cache_free(pwq_cache, pwq); | 502 | kmem_cache_free(pwq_cache, pwq); |
486 | } | 503 | } |
487 | } | 504 | } |
@@ -842,9 +859,16 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k | |||
842 | struct epitem *epi = ep_item_from_wait(wait); | 859 | struct epitem *epi = ep_item_from_wait(wait); |
843 | struct eventpoll *ep = epi->ep; | 860 | struct eventpoll *ep = epi->ep; |
844 | 861 | ||
845 | /* the caller holds eppoll_entry->whead->lock */ | 862 | if ((unsigned long)key & POLLFREE) { |
846 | if ((unsigned long)key & POLLFREE) | 863 | ep_pwq_from_wait(wait)->whead = NULL; |
864 | /* | ||
865 | * whead = NULL above can race with ep_remove_wait_queue() | ||
866 | * which can do another remove_wait_queue() after us, so we | ||
867 | * can't use __remove_wait_queue(). whead->lock is held by | ||
868 | * the caller. | ||
869 | */ | ||
847 | list_del_init(&wait->task_list); | 870 | list_del_init(&wait->task_list); |
871 | } | ||
848 | 872 | ||
849 | spin_lock_irqsave(&ep->lock, flags); | 873 | spin_lock_irqsave(&ep->lock, flags); |
850 | 874 | ||
diff --git a/fs/signalfd.c b/fs/signalfd.c index 79c1eea98a3a..7ae2a574cb25 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c | |||
@@ -33,7 +33,11 @@ | |||
33 | void signalfd_cleanup(struct sighand_struct *sighand) | 33 | void signalfd_cleanup(struct sighand_struct *sighand) |
34 | { | 34 | { |
35 | wait_queue_head_t *wqh = &sighand->signalfd_wqh; | 35 | wait_queue_head_t *wqh = &sighand->signalfd_wqh; |
36 | 36 | /* | |
37 | * The lockless check can race with remove_wait_queue() in progress, | ||
38 | * but in this case its caller should run under rcu_read_lock() and | ||
39 | * sighand_cachep is SLAB_DESTROY_BY_RCU, we can safely return. | ||
40 | */ | ||
37 | if (likely(!waitqueue_active(wqh))) | 41 | if (likely(!waitqueue_active(wqh))) |
38 | return; | 42 | return; |
39 | 43 | ||