
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 :

http://www.xmailserver.org/linux-patches/epoll-lt-2.4.20-0.5.diff



 25-akpm/fs/eventpoll.c |   26 +++++++++++++++++++++++++-
 1 files changed, 25 insertions(+), 1 deletion(-)

diff -puN fs/eventpoll.c~epoll-cross-thread-deletion-fix fs/eventpoll.c
--- 25/fs/eventpoll.c~epoll-cross-thread-deletion-fix	Mon Apr  7 12:27:47 2003
+++ 25-akpm/fs/eventpoll.c	Mon Apr  7 12:27:47 2003
@@ -1342,6 +1342,13 @@ static int ep_collect_ready_items(struct
 			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
 			 * the item inside the ready list.
@@ -1386,6 +1393,14 @@ static int ep_send_events(struct eventpo
 		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
 		 * the item to its "txlist" will write this field.
@@ -1398,8 +1413,17 @@ static int ep_send_events(struct eventpo
 			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;
 			}

_
