Commit d1bc90dd authored by Tony Battersby's avatar Tony Battersby Committed by Linus Torvalds

epoll: remove unnecessary xchg

xchg in ep_unregister_pollwait() is unnecessary because it is protected by
either epmutex or ep->mtx (the same protection as ep_remove()).

If xchg was necessary, it would be insufficient to protect against
problems: if multiple concurrent calls to ep_unregister_pollwait() were
possible then a second caller that returns without doing anything because
nwait == 0 could return before the waitqueues are removed by the first
caller, which looks like it could lead to problematic races with
ep_poll_callback().

So remove xchg and add comments about the locking.
Signed-off-by: default avatarTony Battersby <tonyb@cybernetics.com>
Acked-by: default avatarDavide Libenzi <davidel@xmailserver.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d0305882
...@@ -394,28 +394,22 @@ static void ep_poll_safewake(wait_queue_head_t *wq) ...@@ -394,28 +394,22 @@ static void ep_poll_safewake(wait_queue_head_t *wq)
} }
/* /*
* This function unregister poll callbacks from the associated file descriptor. * This function unregisters poll callbacks from the associated file
* Since this must be called without holding "ep->lock" the atomic exchange trick * descriptor. Must be called with "mtx" held (or "epmutex" if called from
* will protect us from multiple unregister. * ep_free).
*/ */
static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
{ {
int nwait;
struct list_head *lsthead = &epi->pwqlist; struct list_head *lsthead = &epi->pwqlist;
struct eppoll_entry *pwq; struct eppoll_entry *pwq;
/* This is called without locks, so we need the atomic exchange */
nwait = xchg(&epi->nwait, 0);
if (nwait) {
while (!list_empty(lsthead)) { while (!list_empty(lsthead)) {
pwq = list_first_entry(lsthead, struct eppoll_entry, llink); pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
list_del_init(&pwq->llink); list_del(&pwq->llink);
remove_wait_queue(pwq->whead, &pwq->wait); remove_wait_queue(pwq->whead, &pwq->wait);
kmem_cache_free(pwq_cache, pwq); kmem_cache_free(pwq_cache, pwq);
} }
}
} }
/** /**
......
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