Commit 92a88ec9 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] epoll cross-thread deletion fix

From: Davide Libenzi <davidel@xmailserver.org>


This fixes a bug that might happen having a thread doing epoll_wait() with
another thread doing epoll_ctl(EPOLL_CTL_DEL) and close(). The fast check
inside eventpoll_release() is good to not effect performace of code not
using epoll, but it requires get_file() to be called ( that can be avoided
by dropping the fast check ). I opted to keep the fast check and to have
epoll to call get_file() before the event send loop. I tested it on UP and
2SMP with a bug-exploiting program provided by @pivia.com ( thx to them )
and it looks fine. I also update the 2.4.20 epoll patch with this fix :
parent 7b78878b
......@@ -1341,6 +1341,13 @@ static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist
*/
ep_use_epitem(epi);
/*
* We need to increase the usage count of the "struct file" because
* another thread might call close() on this target and make the file
* to vanish before we will be able to call f_op->poll().
*/
get_file(epi->file);
/*
* This is initialized in this way so that the default
* behaviour of the reinjecting code will be to push back
......@@ -1385,6 +1392,14 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
/* Get the ready file event set */
revents = epi->file->f_op->poll(epi->file, NULL);
/*
* Release the file usage before checking the event mask.
* In case this call will lead to the file removal, its
* ->event.events member has been already set to zero and
* this will make the event to be dropped.
*/
fput(epi->file);
/*
* Set the return event set for the current file descriptor.
* Note that only the task task was successfully able to link
......@@ -1398,8 +1413,17 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
eventbuf++;
if (eventbuf == EP_MAX_BUF_EVENTS) {
if (__copy_to_user(&events[eventcnt], event,
eventbuf * sizeof(struct epoll_event)))
eventbuf * sizeof(struct epoll_event))) {
/*
* We need to complete the loop to decrement the file
* usage before returning from this function.
*/
for (lnk = lnk->next; lnk != txlist; lnk = lnk->next) {
epi = list_entry(lnk, struct epitem, txlink);
fput(epi->file);
}
return -EFAULT;
}
eventcnt += eventbuf;
eventbuf = 0;
}
......
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