diff options
author | Davide Libenzi <davidel@xmailserver.org> | 2008-10-17 19:17:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-26 15:09:49 -0400 |
commit | 9ce209d64d820a6d5ed6b952e2c0f917faad6031 (patch) | |
tree | 817c5bd01e6666c8269d29d3d8292b5e75ea7fb3 /fs/eventpoll.c | |
parent | 4d36a9e65d4966b433b2f3424d9457468bc80e00 (diff) |
epoll: avoid double-inserts in case of EFAULT
In commit f337b9c58332bdecde965b436e47ea4c94d30da0 ("epoll: drop
unnecessary test") Thomas found that there is an unnecessary (always
true) test in ep_send_events(). The callback never inserts into
->rdllink while the send loop is performed, and also does the
~EP_PRIVATE_BITS test. Given we're holding the mutex during this time,
the conditions tested inside the loop are always true.
HOWEVER.
The test "!ep_is_linked(&epi->rdllink)" wasn't there because we insert
into ->rdllink, but because the send-events loop might terminate before
the whole list is scanned (-EFAULT).
In such cases, when the loop terminates early, and when a (leftover)
file received an event while we're performing the lockless loop, we need
such test to avoid to double insert the epoll items. The list_splice()
done a few steps below, will correctly re-insert the ones that were left
on "txlist".
This should fix the kenrel.org bugzilla entry 11831.
Signed-off-by: Davide Libenzi <davidel@xmailserver.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/eventpoll.c')
-rw-r--r-- | fs/eventpoll.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 99368bda0261..aec5c13f6341 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -930,8 +930,15 @@ errxit: | |||
930 | * inside the main ready-list here. | 930 | * inside the main ready-list here. |
931 | */ | 931 | */ |
932 | for (nepi = ep->ovflist; (epi = nepi) != NULL; | 932 | for (nepi = ep->ovflist; (epi = nepi) != NULL; |
933 | nepi = epi->next, epi->next = EP_UNACTIVE_PTR) | 933 | nepi = epi->next, epi->next = EP_UNACTIVE_PTR) { |
934 | list_add_tail(&epi->rdllink, &ep->rdllist); | 934 | /* |
935 | * If the above loop quit with errors, the epoll item might still | ||
936 | * be linked to "txlist", and the list_splice() done below will | ||
937 | * take care of those cases. | ||
938 | */ | ||
939 | if (!ep_is_linked(&epi->rdllink)) | ||
940 | list_add_tail(&epi->rdllink, &ep->rdllist); | ||
941 | } | ||
935 | /* | 942 | /* |
936 | * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after | 943 | * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after |
937 | * releasing the lock, events will be queued in the normal way inside | 944 | * releasing the lock, events will be queued in the normal way inside |