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: Tony Battersby <tonyb@cybernetics.com>
Acked-by: Davide Libenzi <davidel@xmailserver.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Tony Battersby 2009-03-31 15:24:15 -07:00 committed by Linus Torvalds
parent d030588282
commit d1bc90dd5d

View file

@ -394,27 +394,21 @@ 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 */ while (!list_empty(lsthead)) {
nwait = xchg(&epi->nwait, 0); pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
if (nwait) { list_del(&pwq->llink);
while (!list_empty(lsthead)) { remove_wait_queue(pwq->whead, &pwq->wait);
pwq = list_first_entry(lsthead, struct eppoll_entry, llink); kmem_cache_free(pwq_cache, pwq);
list_del_init(&pwq->llink);
remove_wait_queue(pwq->whead, &pwq->wait);
kmem_cache_free(pwq_cache, pwq);
}
} }
} }