diff options
author | Tony Battersby <tonyb@cybernetics.com> | 2009-03-31 18:24:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-01 11:59:19 -0400 |
commit | d1bc90dd5d037079f96b3327f943eb6ae8ef7491 (patch) | |
tree | 0380bd32cee23815b214d81a12b618140c544799 /fs/eventpoll.c | |
parent | d0305882825784e74f68a56eee6c3a812a99f235 (diff) |
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>
Diffstat (limited to 'fs/eventpoll.c')
-rw-r--r-- | fs/eventpoll.c | 22 |
1 files changed, 8 insertions, 14 deletions
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index c806a0c4383c..64c55037c13b 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -394,27 +394,21 @@ static void ep_poll_safewake(wait_queue_head_t *wq) | |||
394 | } | 394 | } |
395 | 395 | ||
396 | /* | 396 | /* |
397 | * This function unregister poll callbacks from the associated file descriptor. | 397 | * This function unregisters poll callbacks from the associated file |
398 | * Since this must be called without holding "ep->lock" the atomic exchange trick | 398 | * descriptor. Must be called with "mtx" held (or "epmutex" if called from |
399 | * will protect us from multiple unregister. | 399 | * ep_free). |
400 | */ | 400 | */ |
401 | static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) | 401 | static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) |
402 | { | 402 | { |
403 | int nwait; | ||
404 | struct list_head *lsthead = &epi->pwqlist; | 403 | struct list_head *lsthead = &epi->pwqlist; |
405 | struct eppoll_entry *pwq; | 404 | struct eppoll_entry *pwq; |
406 | 405 | ||
407 | /* This is called without locks, so we need the atomic exchange */ | 406 | while (!list_empty(lsthead)) { |
408 | nwait = xchg(&epi->nwait, 0); | 407 | pwq = list_first_entry(lsthead, struct eppoll_entry, llink); |
409 | |||
410 | if (nwait) { | ||
411 | while (!list_empty(lsthead)) { | ||
412 | pwq = list_first_entry(lsthead, struct eppoll_entry, llink); | ||
413 | 408 | ||
414 | list_del_init(&pwq->llink); | 409 | list_del(&pwq->llink); |
415 | remove_wait_queue(pwq->whead, &pwq->wait); | 410 | remove_wait_queue(pwq->whead, &pwq->wait); |
416 | kmem_cache_free(pwq_cache, pwq); | 411 | kmem_cache_free(pwq_cache, pwq); |
417 | } | ||
418 | } | 412 | } |
419 | } | 413 | } |
420 | 414 | ||