diff --git a/fs/eventpoll.c b/fs/eventpoll.c index f48b829a710f..7a32c70bf2ad 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1982,11 +1982,22 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, { int pwake = 0; poll_table pt; + int error; lockdep_assert_irqs_enabled(); init_poll_funcptr(&pt, NULL); + /* + * Create the wakeup source before committing the new event mask. + * Leave the old mask and data unchanged if allocation fails. + */ + if ((event->events & EPOLLWAKEUP) && !ep_has_wakeup_source(epi)) { + error = ep_create_wakeup_source(epi); + if (error) + return error; + } + /* * Set the new event interest mask before calling f_op->poll(); * otherwise we might miss an event that happens between the @@ -1994,12 +2005,9 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, */ epi->event.events = event->events; /* need barrier below */ epi->event.data = event->data; /* protected by mtx */ - if (epi->event.events & EPOLLWAKEUP) { - if (!ep_has_wakeup_source(epi)) - ep_create_wakeup_source(epi); - } else if (ep_has_wakeup_source(epi)) { + if (!(epi->event.events & EPOLLWAKEUP) && + ep_has_wakeup_source(epi)) ep_destroy_wakeup_source(epi); - } /* * The following barrier has two effects: