diff -Nru linux-2.5.45.vanilla/drivers/char/eventpoll.c linux-2.5.45.epoll/drivers/char/eventpoll.c
--- linux-2.5.45.vanilla/drivers/char/eventpoll.c	Wed Oct 30 16:42:27 2002
+++ linux-2.5.45.epoll/drivers/char/eventpoll.c	Wed Oct 30 17:50:19 2002
@@ -63,13 +63,13 @@
 #define DPI_SLAB_DEBUG 0
 #endif /* #if DEBUG_DPI != 0 */
 
-#define INITIAL_HASH_BITS 7
-#define MAX_HASH_BITS 18
-#define RESIZE_LENGTH 2
-
 #define DPI_MEM_ALLOC()	(struct epitem *) kmem_cache_alloc(dpi_cache, SLAB_KERNEL)
 #define DPI_MEM_FREE(p) kmem_cache_free(dpi_cache, p)
 #define IS_FILE_EPOLL(f) ((f)->f_op == &eventpoll_fops)
+#define EP_LIST_ITEM_INIT(p) (p)->next = (p)->prev = NULL
+#define EP_LIST_DEL(p) do { list_del(p); EP_LIST_ITEM_INIT(p); } while (0)
+#define EP_IS_LINKED(p) ((p)->next != NULL)
+
 
 
 /*
@@ -103,13 +103,11 @@
 	/* Wait queue used by file->poll() */
 	wait_queue_head_t poll_wait;
 
-	/* This is the hash used to store the "struct epitem" elements */
-	struct list_head *hash;
+	/* This is the list used to store the "struct epitem" elements */
+	struct list_head fdlist;
 
-	unsigned int hbits;
-	unsigned int hmask;
-	atomic_t hents;
-	atomic_t resize;
+	/* Number of file descriptors currently stored inside the interface */
+	atomic_t epitems;
 
 	/* Number of pages currently allocated in each side of the double buffer */
 	int numpages;
@@ -179,8 +177,19 @@
 	 * with the one inside the eventpoll structure.
 	 */
 	event_version_t ver;
+
+	/*
+	 * Used to keep track of the usage count of the structure. This avoids
+	 * that the structure will desappear from underneath our processing.
+	 */
+	atomic_t usecnt;
 };
 
+/* Structure used to search "struct epitem" using file_notify_search() */
+struct fcb_search {
+	struct eventpoll *ep;
+	struct epitem *dpi;
+};
 
 
 
@@ -189,13 +198,16 @@
 static int ep_free_pages(char **pages, int numpages);
 static int ep_init(struct eventpoll *ep);
 static void ep_free(struct eventpoll *ep);
-static struct epitem *ep_find_nl(struct eventpoll *ep, int fd);
-static struct epitem *ep_find(struct eventpoll *ep, int fd);
-static int ep_hashresize(struct eventpoll *ep, unsigned long *kflags);
+static int ep_cbsearch_proc(void *priv, void *data);
+static struct epitem *ep_find(struct eventpoll *ep, struct file *file);
+static struct epitem *ep_find_fd(struct eventpoll *ep, int fd);
+static void ep_free_dpi(struct file *file, void *data);
+static void ep_use_epitem(struct epitem *dpi);
+static void ep_release_epitem(struct epitem *dpi);
 static int ep_insert(struct eventpoll *ep, struct pollfd *pfd);
+static int ep_unlink(struct eventpoll *ep, struct epitem *dpi);
 static int ep_remove(struct eventpoll *ep, struct epitem *dpi);
-static void notify_proc(struct file *file, void *data, unsigned long *local,
-			long *event);
+static void notify_proc(struct file *file, void *data, long *event);
 static int open_eventpoll(struct inode *inode, struct file *file);
 static int close_eventpoll(struct inode *inode, struct file *file);
 static unsigned int poll_eventpoll(struct file *file, poll_table *wait);
@@ -205,8 +217,8 @@
 static int ep_do_alloc_pages(struct eventpoll *ep, int numpages);
 static int ioctl_eventpoll(struct inode *inode, struct file *file,
 			   unsigned int cmd, unsigned long arg);
-static void eventpoll_mm_open(struct vm_area_struct * vma);
-static void eventpoll_mm_close(struct vm_area_struct * vma);
+static void eventpoll_mm_open(struct vm_area_struct *vma);
+static void eventpoll_mm_close(struct vm_area_struct *vma);
 static int mmap_eventpoll(struct file *file, struct vm_area_struct *vma);
 static int eventpollfs_delete_dentry(struct dentry *dentry);
 static struct inode *get_eventpoll_inode(void);
@@ -377,7 +389,7 @@
 	pfd.events = events | POLLERR | POLLHUP;
 	pfd.revents = 0;
 
-	dpi = ep_find(ep, fd);
+	dpi = ep_find_fd(ep, fd);
 
 	error = -EINVAL;
 	switch (op) {
@@ -402,6 +414,13 @@
 		break;
 	}
 
+	/*
+	 * The function ep_find() increments the usage count of the structure
+	 * so, if this is not NULL, we need to release it.
+	 */
+	if (dpi)
+		ep_release_epitem(dpi);
+
 	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %u) = %d\n",
 		     current, epfd, op, fd, events, error));
 
@@ -548,7 +567,7 @@
 eexit_2:
 	put_filp(file);
 eexit_1:
-	return error;
+	return error;	
 }
 
 
@@ -585,29 +604,19 @@
 
 static int ep_init(struct eventpoll *ep)
 {
-	int ii, hentries;
 
 	init_rwsem(&ep->acsem);
 	rwlock_init(&ep->lock);
 	init_waitqueue_head(&ep->wq);
 	init_waitqueue_head(&ep->poll_wait);
-	ep->hbits = INITIAL_HASH_BITS;
-	ep->hmask = (1 << ep->hbits) - 1;
-	atomic_set(&ep->hents, 0);
-	atomic_set(&ep->resize, 0);
+	INIT_LIST_HEAD(&ep->fdlist);
 	atomic_set(&ep->mmapped, 0);
 	ep->numpages = 0;
 	ep->vmabase = 0;
 	ep->pages = ep->pages0;
 	ep->eventcnt = 0;
 	ep->ver = 1;
-
-	hentries = ep->hmask + 1;
-	if (!(ep->hash = (struct list_head *) vmalloc(hentries * sizeof(struct list_head))))
-		return -ENOMEM;
-
-	for (ii = 0; ii < hentries; ii++)
-		INIT_LIST_HEAD(&ep->hash[ii]);
+	atomic_set(&ep->epitems, 0);
 
 	return 0;
 }
@@ -615,30 +624,22 @@
 
 static void ep_free(struct eventpoll *ep)
 {
-	int ii;
 	struct list_head *lsthead;
 
 	/*
 	 * Walks through the whole hash by unregistering file callbacks and
 	 * freeing each "struct epitem".
 	 */
-	for (ii = 0; ii <= ep->hmask; ii++) {
-		lsthead = &ep->hash[ii];
-		while (!list_empty(lsthead)) {
-			struct epitem *dpi = list_entry(lsthead->next, struct epitem, llink);
-
-			file_notify_delcb(dpi->file, notify_proc);
-			list_del(lsthead->next);
-			DPI_MEM_FREE(dpi);
-		}
+	lsthead = &ep->fdlist;
+	while (!list_empty(lsthead)) {
+		struct epitem *dpi = list_entry(lsthead->next, struct epitem, llink);
+
+		ep_remove(ep, dpi);
 	}
 	/*
-	 * At this point we can free the hash and the pages used for the event
-	 * double buffer. The ep_free() function is called from the "close"
-	 * file operations callback, and this garanties us that the pages are
-	 * already unmapped.
+	 * The ep_free() function is called from the "close" file operations
+	 * callback, and this garanties us that the pages are already unmapped.
 	 */
-	vfree(ep->hash);
 	if (ep->numpages > 0) {
 		ep_free_pages(ep->pages0, ep->numpages);
 		ep_free_pages(ep->pages1, ep->numpages);
@@ -647,93 +648,111 @@
 
 
 /*
+ * Callabck used to search inside the file callbacks. It is passed to
+ * file_notify_search() to perform a find of eventual "struct epitem"
+ * dropped by the current interface ( "fcbs->ep" ).
+ */
+static int ep_cbsearch_proc(void *priv, void *data)
+{
+	struct fcb_search *fcbs = priv;
+	struct epitem *dpi = data;
+
+	if (dpi->ep != fcbs->ep)
+		return 0;
+
+	fcbs->dpi = dpi;
+	ep_use_epitem(dpi);
+
+	return 1;
+}
+
+
+/*
  * No lock version of ep_find(), used when the code had to acquire the lock
  * before calling the function.
  */
-static struct epitem *ep_find_nl(struct eventpoll *ep, int fd)
+static struct epitem *ep_find(struct eventpoll *ep, struct file *file)
 {
-	struct epitem *dpi = NULL;
-	struct list_head *lsthead, *lnk;
+	struct fcb_search fcbs;
 
-	lsthead = &ep->hash[fd & ep->hmask];
-	list_for_each(lnk, lsthead) {
-		dpi = list_entry(lnk, struct epitem, llink);
+	fcbs.ep = ep;
+	fcbs.dpi = NULL;
 
-		if (dpi->pfd.fd == fd) break;
-		dpi = NULL;
-	}
+	file_notify_search(file, notify_proc, ep_cbsearch_proc, &fcbs);
 
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_find(%d) -> %p\n",
-		     current, fd, dpi));
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_find(%p) -> %p\n",
+		     current, file, fcbs.dpi));
 
-	return dpi;
+	return fcbs.dpi;
 }
 
 
-static struct epitem *ep_find(struct eventpoll *ep, int fd)
+static struct epitem *ep_find_fd(struct eventpoll *ep, int fd)
 {
-	struct epitem *dpi;
-	unsigned long flags;
-
-	read_lock_irqsave(&ep->lock, flags);
+	struct file *file;
+	struct epitem *dpi = NULL;
 
-	dpi = ep_find_nl(ep, fd);
+	/*
+	 * Since ep_find_fd() might be called at process termination
+	 * time, when the kernel has already set "current->files" to
+	 * NULL, the test below is necessary to avoid fget() to crash
+	 * on us.
+	 */
+	if (current->files && (file = fget(fd))) {
+		dpi = ep_find(ep, file);
+		fput(file);
+	}
 
-	read_unlock_irqrestore(&ep->lock, flags);
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_find_fd(%d) -> %p\n",
+		     current, fd, dpi));
 
 	return dpi;
 }
 
 
-static int ep_hashresize(struct eventpoll *ep, unsigned long *kflags)
+/*
+ * This is the callback passed to file_notify_addcb() to enable
+ * automatic cleanup when the file inside the interest set is
+ * closed without being previously removed from the set.
+ */
+static void ep_free_dpi(struct file *file, void *data)
 {
-	struct list_head *hash, *oldhash;
-	unsigned int hbits = ep->hbits + 1;
-	unsigned int hmask = (1 << hbits) - 1;
-	int ii, res, hentries = hmask + 1;
-	unsigned long flags = *kflags;
-
-	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_hashresize(%p) bits=%u\n",
-		     current, ep, hbits));
-
-	write_unlock_irqrestore(&ep->lock, flags);
+	struct epitem *dpi = data;
 
-	res = -ENOMEM;
-	if (!(hash = (struct list_head *) vmalloc(hentries * sizeof(struct list_head)))) {
-		write_lock_irqsave(&ep->lock, flags);
-		goto eexit_1;
-	}
+	/*
+	 * We need to get the semaphore before calling functions that manipulates
+	 * the insertion/removal of "struct epitem".
+	 */
+	down_write(&dpi->ep->acsem);
 
-	for (ii = 0; ii < hentries; ii++)
-		INIT_LIST_HEAD(&hash[ii]);
+	ep_unlink(dpi->ep, dpi);
+	ep_release_epitem(dpi);
 
-	write_lock_irqsave(&ep->lock, flags);
+	up_write(&dpi->ep->acsem);
+}
 
-	oldhash = ep->hash;
-	for (ii = 0; ii <= ep->hmask; ii++) {
-		struct list_head *oldhead = &oldhash[ii], *lnk;
 
-		while (!list_empty(oldhead)) {
-			struct epitem *dpi = list_entry(lnk = oldhead->next, struct epitem, llink);
+/*
+ * Increment the usage count of the "struct epitem" making it sure
+ * that the user will have a valid pointer to reference.
+ */
+static void ep_use_epitem(struct epitem *dpi)
+{
 
-			list_del(lnk);
-			list_add(lnk, &hash[dpi->pfd.fd & hmask]);
-		}
-	}
+	atomic_inc(&dpi->usecnt);
+}
 
-	ep->hash = hash;
-	ep->hbits = hbits;
-	ep->hmask = hmask;
 
-	write_unlock_irqrestore(&ep->lock, flags);
-	vfree(oldhash);
-	write_lock_irqsave(&ep->lock, flags);
+/*
+ * Decrement ( release ) the usage count by signaling that the user
+ * has finished using the structure. It might lead to freeing the
+ * structure itself if the count goes to zero.
+ */
+static void ep_release_epitem(struct epitem *dpi)
+{
 
-	res = 0;
-eexit_1:
-	*kflags = flags;
-	atomic_dec(&ep->resize);
-	return res;
+	if (atomic_dec_and_test(&dpi->usecnt))
+		DPI_MEM_FREE(dpi);
 }
 
 
@@ -743,8 +762,9 @@
 	struct epitem *dpi;
 	struct file *file;
 	unsigned long flags;
+	struct fcb_priv_data priv;
 
-	if (atomic_read(&ep->hents) >= (ep->numpages * POLLFD_X_PAGE))
+	if (atomic_read(&ep->epitems) >= (ep->numpages * POLLFD_X_PAGE))
 		return -E2BIG;
 
 	file = fget(pfd->fd);
@@ -755,28 +775,24 @@
 	if (!(dpi = DPI_MEM_ALLOC()))
 		goto eexit_1;
 
-	INIT_LIST_HEAD(&dpi->llink);
+	EP_LIST_ITEM_INIT(&dpi->llink);
 	dpi->ep = ep;
 	dpi->file = file;
 	dpi->pfd = *pfd;
 	dpi->index = -1;
 	dpi->ver = ep->ver - 1;
+	atomic_set(&dpi->usecnt, 1);
 
 	write_lock_irqsave(&ep->lock, flags);
 
-	list_add(&dpi->llink, &ep->hash[pfd->fd & ep->hmask]);
-	atomic_inc(&ep->hents);
-
-	if (!atomic_read(&ep->resize) &&
-	    (atomic_read(&ep->hents) >> ep->hbits) > RESIZE_LENGTH &&
-	    ep->hbits < MAX_HASH_BITS) {
-		atomic_inc(&ep->resize);
-		ep_hashresize(ep, &flags);
-	}
+	atomic_inc(&ep->epitems);
+	list_add(&dpi->llink, &ep->fdlist);
 
 	write_unlock_irqrestore(&ep->lock, flags);
 
-	file_notify_addcb(file, notify_proc, dpi);
+	priv.data = dpi;
+	priv.desc = ep_free_dpi;
+	file_notify_addcb(file, notify_proc, &priv);
 
 	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %d)\n",
 		     current, ep, pfd->fd));
@@ -789,53 +805,80 @@
 }
 
 
-/*
- * Removes a "struct epitem" from the eventpoll hash and deallocates
- * all the associated resources.
- */
-static int ep_remove(struct eventpoll *ep, struct epitem *dpi)
+static int ep_unlink(struct eventpoll *ep, struct epitem *dpi)
 {
 	unsigned long flags;
 	struct pollfd *pfd, *lpfd;
 	struct epitem *ldpi;
 
-	/* First, removes the callback from the file callback list */
-	file_notify_delcb(dpi->file, notify_proc);
-
 	write_lock_irqsave(&ep->lock, flags);
 
-	list_del(&dpi->llink);
-	atomic_dec(&ep->hents);
-
-	/*
-	 * This is to remove stale events. We don't want that the removed file
-	 * has a pending event that might be associated with a file inserted
-	 * at a later time inside the eventpoll interface. this code checks
-	 * if the currently removed file has a valid pending event and, if it does,
-	 * manages things to remove it and decrement the currently available
-	 * event count.
-	 */
-	if (dpi->index >= 0 && dpi->ver == ep->ver && dpi->index < ep->eventcnt) {
-		pfd = (struct pollfd *) (ep->pages[EVENT_PAGE_INDEX(dpi->index)] +
-					 EVENT_PAGE_OFFSET(dpi->index));
-		if (pfd->fd == dpi->pfd.fd && dpi->index < --ep->eventcnt) {
-			lpfd = (struct pollfd *) (ep->pages[EVENT_PAGE_INDEX(ep->eventcnt)] +
-						  EVENT_PAGE_OFFSET(ep->eventcnt));
-			*pfd = *lpfd;
+	if (EP_IS_LINKED(&dpi->llink)) {
+		atomic_dec(&ep->epitems);
+		EP_LIST_DEL(&dpi->llink);
 
-			if ((ldpi = ep_find_nl(ep, pfd->fd))) ldpi->index = dpi->index;
+		/*
+		 * This is to remove stale events. We don't want that the
+		 * removed file has a pending event that might be associated
+		 * with a file inserted at a later time inside the eventpoll
+		 * interface. This code checks if the currently removed file
+		 * has a valid pending event and, if it does, manages things
+		 * to remove it and decrement the currently available event
+		 * count.
+		 */
+		if (dpi->index >= 0 && dpi->ver == ep->ver &&
+		    dpi->index < ep->eventcnt) {
+			pfd = (struct pollfd *) (ep->pages[EVENT_PAGE_INDEX(dpi->index)] +
+						 EVENT_PAGE_OFFSET(dpi->index));
+			if (pfd->fd == dpi->pfd.fd && dpi->index < --ep->eventcnt) {
+				lpfd = (struct pollfd *) (ep->pages[EVENT_PAGE_INDEX(ep->eventcnt)] +
+							  EVENT_PAGE_OFFSET(ep->eventcnt));
+				*pfd = *lpfd;
+
+				if ((ldpi = ep_find_fd(ep, pfd->fd))) {
+					ldpi->index = dpi->index;
+					ep_release_epitem(ldpi);
+				}
+			}
 		}
 	}
 
 	write_unlock_irqrestore(&ep->lock, flags);
 
+	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %d)\n",
+		     current, ep, dpi->pfd.fd));
+
+	return 0;
+}
+
+
+/*
+ * Removes a "struct epitem" from the eventpoll hash and deallocates
+ * all the associated resources.
+ */
+static int ep_remove(struct eventpoll *ep, struct epitem *dpi)
+{
+	int error;
+
+	/* First, removes the callback from the file callback list */
+	error = file_notify_delcb(dpi->file, notify_proc, dpi, 0);
+	if (error)
+		goto eexit_1;
+
+	/* Really unlink the item from the hash */
+	error = ep_unlink(ep, dpi);
+	if (error)
+		goto eexit_1;
+
 	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %d)\n",
 		     current, ep, dpi->pfd.fd));
 
 	/* At this point it is safe to free the eventpoll item */
-	DPI_MEM_FREE(dpi);
+	ep_release_epitem(dpi);
 
-	return 0;
+	error = 0;
+eexit_1:
+	return error;
 }
 
 
@@ -843,8 +886,7 @@
  * This is the event notify callback that is called from fs/fcblist.c because
  * of the registration ( file_notify_addcb() ) done in ep_insert().
  */
-static void notify_proc(struct file *file, void *data, unsigned long *local,
-			long *event)
+static void notify_proc(struct file *file, void *data, long *event)
 {
 	struct epitem *dpi = data;
 	struct eventpoll *ep = dpi->ep;
@@ -987,7 +1029,7 @@
 			goto eexit_2;
 		}
 
-		dpi = ep_find(ep, pfd.fd);
+		dpi = ep_find_fd(ep, pfd.fd);
 
 		if (pfd.fd >= current->files->max_fds || !current->files->fd[pfd.fd])
 			pfd.events = POLLREMOVE;
@@ -1006,6 +1048,9 @@
 				rcount += sizeof(pfd);
 		}
 
+		if (dpi)
+			ep_release_epitem(dpi);
+
 		buffer += sizeof(pfd);
 		count -= sizeof(pfd);
 	}
@@ -1054,7 +1099,7 @@
 		 * passed timeout is in milliseconds, that why (t * HZ) / 1000.
 		 */
 		timeout = dvp->ep_timeout == -1 || dvp->ep_timeout > MAX_SCHEDULE_TIMEOUT / HZ ?
-			MAX_SCHEDULE_TIMEOUT: (dvp->ep_timeout * HZ) / 1000;
+			MAX_SCHEDULE_TIMEOUT: (dvp->ep_timeout * HZ) / 1000; 
 
 		for (;;) {
 			/*
@@ -1211,17 +1256,19 @@
 		if (copy_from_user(&pfd, (void *) arg, sizeof(struct pollfd)))
 			return 0;
 
-		read_lock_irqsave(&ep->lock, flags);
+		down_read(&ep->acsem);
 
 		res = 0;
-		if (!(dpi = ep_find_nl(ep, pfd.fd)))
+		if (!(dpi = ep_find_fd(ep, pfd.fd)))
 			goto is_not_polled;
 
 		pfd = dpi->pfd;
+
+		ep_release_epitem(dpi);
 		res = 1;
 
 	is_not_polled:
-		read_unlock_irqrestore(&ep->lock, flags);
+		up_read(&ep->acsem);
 
 		if (res)
 			copy_to_user((void *) arg, &pfd, sizeof(struct pollfd));
@@ -1235,7 +1282,7 @@
 }
 
 
-static void eventpoll_mm_open(struct vm_area_struct * vma)
+static void eventpoll_mm_open(struct vm_area_struct *vma)
 {
 	struct file *file = vma->vm_file;
 	struct eventpoll *ep = file->private_data;
@@ -1246,7 +1293,7 @@
 }
 
 
-static void eventpoll_mm_close(struct vm_area_struct * vma)
+static void eventpoll_mm_close(struct vm_area_struct *vma)
 {
 	struct file *file = vma->vm_file;
 	struct eventpoll *ep = file->private_data;
diff -Nru linux-2.5.45.vanilla/fs/fcblist.c linux-2.5.45.epoll/fs/fcblist.c
--- linux-2.5.45.vanilla/fs/fcblist.c	Wed Oct 30 16:43:07 2002
+++ linux-2.5.45.epoll/fs/fcblist.c	Wed Oct 30 17:50:34 2002
@@ -13,6 +13,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
@@ -23,6 +24,27 @@
 #include <linux/fcblist.h>
 
 
+
+#define FCB_MEM_ALLOC()	(struct fcb_struct *) kmem_cache_alloc(fcb_cache, SLAB_KERNEL)
+#define FCB_MEM_FREE(p) kmem_cache_free(fcb_cache, p)
+
+#define DEBUG_FCB 0
+
+#if DEBUG_FCB != 0
+#define FCB_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */)
+#else /* #if DEBUG_DPI != 0 */
+#define FCB_SLAB_DEBUG 0
+#endif /* #if DEBUG_FCB != 0 */
+
+
+struct fcb_struct {
+	struct list_head llink;
+	void (*cbproc)(struct file *, void *, long *);
+	struct fcb_priv_data priv;
+};
+
+
+
 long ion_band_table[NSIGPOLL] = {
 	ION_IN,		/* POLL_IN */
 	ION_OUT,	/* POLL_OUT */
@@ -41,6 +63,9 @@
 	POLLHUP | POLLERR			/* POLL_HUP */
 };
 
+/* Slab cache used to allocate "struct fcb_struct" */
+static kmem_cache_t *fcb_cache;
+
 
 
 /*
@@ -60,7 +85,7 @@
 	list_for_each(lnk, lsthead) {
 		struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, llink);
 
-		fcbp->cbproc(filep, fcbp->data, fcbp->local, event);
+		fcbp->cbproc(filep, fcbp->priv.data, event);
 	}
 
 	read_unlock_irqrestore(&filep->f_cblock, flags);
@@ -71,18 +96,18 @@
  * Add a new callback to the list of file callbacks.
  */
 int file_notify_addcb(struct file *filep,
-		      void (*cbproc)(struct file *, void *, unsigned long *, long *),
-		      void *data)
+		      void (*cbproc)(struct file *, void *, long *),
+		      struct fcb_priv_data const *priv)
 {
 	unsigned long flags;
 	struct fcb_struct *fcbp;
 
-	if (!(fcbp = (struct fcb_struct *) kmalloc(sizeof(struct fcb_struct), GFP_KERNEL)))
+	if (!(fcbp = FCB_MEM_ALLOC()))
 		return -ENOMEM;
 
 	memset(fcbp, 0, sizeof(struct fcb_struct));
 	fcbp->cbproc = cbproc;
-	fcbp->data = data;
+	fcbp->priv = *priv;
 
 	write_lock_irqsave(&filep->f_cblock, flags);
 	list_add_tail(&fcbp->llink, &filep->f_cblist);
@@ -96,7 +121,8 @@
  * Removes the callback "cbproc" from the file callback list.
  */
 int file_notify_delcb(struct file *filep,
-		      void (*cbproc)(struct file *, void *, unsigned long *, long *))
+		      void (*cbproc)(struct file *, void *, long *), void *data,
+		      int freepriv)
 {
 	unsigned long flags;
 	struct list_head *lnk, *lsthead;
@@ -107,10 +133,12 @@
 	list_for_each(lnk, lsthead) {
 		struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, llink);
 
-		if (fcbp->cbproc == cbproc) {
+		if (fcbp->cbproc == cbproc && fcbp->priv.data == data) {
 			list_del(lnk);
 			write_unlock_irqrestore(&filep->f_cblock, flags);
-			kfree(fcbp);
+			if (freepriv)
+				FCB_PRIV_FREE(&fcbp->priv, filep);
+			FCB_MEM_FREE(fcbp);
 			return 0;
 		}
 	}
@@ -121,6 +149,29 @@
 }
 
 
+int file_notify_search(struct file *filep,
+		       void (*cbproc)(struct file *, void *, long *),
+		       int (*sproc)(void *, void *), void *priv)
+{
+	unsigned long flags;
+	struct list_head *lnk, *lsthead;
+
+	read_lock_irqsave(&filep->f_cblock, flags);
+
+	lsthead = &filep->f_cblist;
+	list_for_each(lnk, lsthead) {
+		struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, llink);
+
+		if (fcbp->cbproc == cbproc && sproc(priv, fcbp->priv.data))
+			break;
+	}
+
+	read_unlock_irqrestore(&filep->f_cblock, flags);
+
+	return 0;
+}
+
+
 /*
  * It is called at file cleanup time and removes all the registered callbacks.
  */
@@ -137,10 +188,43 @@
 
 		list_del(lsthead->next);
 		write_unlock_irqrestore(&filep->f_cblock, flags);
-		kfree(fcbp);
+		FCB_PRIV_FREE(&fcbp->priv, filep);
+		FCB_MEM_FREE(fcbp);
 		write_lock_irqsave(&filep->f_cblock, flags);
 	}
 
 	write_unlock_irqrestore(&filep->f_cblock, flags);
 }
+
+
+static int __init fcb_init(void)
+{
+	int error;
+
+	/* Allocates slab cache used to allocate "struct fcb_struct" items */
+	error = -ENOMEM;
+	fcb_cache = kmem_cache_create("fcblist",
+				      sizeof(struct fcb_struct),
+				      __alignof__(struct fcb_struct),
+				      FCB_SLAB_DEBUG, NULL, NULL);
+	if (!fcb_cache)
+		goto eexit_1;
+
+
+	error = 0;
+eexit_1:
+	return error;
+}
+
+
+static void __exit fcb_exit(void)
+{
+	/* Undo all operations done inside fcb_init() */
+	kmem_cache_destroy(fcb_cache);
+}
+
+module_init(fcb_init);
+module_exit(fcb_exit);
+
+MODULE_LICENSE("GPL");
 
diff -Nru linux-2.5.45.vanilla/fs/pipe.c linux-2.5.45.epoll/fs/pipe.c
--- linux-2.5.45.vanilla/fs/pipe.c	Wed Oct 30 16:42:57 2002
+++ linux-2.5.45.epoll/fs/pipe.c	Wed Oct 30 17:58:34 2002
@@ -112,7 +112,7 @@
 		}
 		/* Send notification message */
 		if (pfull && !PIPE_FULL(*inode) && PIPE_WRITEFILE(*inode))
-			file_send_notify(PIPE_WRITEFILE(*inode), ION_OUT, POLLOUT | POLLWRNORM | POLLWRBAND);
+			file_notify_send(PIPE_WRITEFILE(*inode), ION_OUT, POLLOUT | POLLWRNORM | POLLWRBAND);
 		if (do_wakeup) {
 			wake_up_interruptible_sync(PIPE_WAIT(*inode));
  			kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT);
@@ -121,7 +121,7 @@
 	}
 	/* Send notification message */
 	if (pfull && !PIPE_FULL(*inode) && PIPE_WRITEFILE(*inode))
-		file_send_notify(PIPE_WRITEFILE(*inode), ION_OUT, POLLOUT | POLLWRNORM | POLLWRBAND);
+		file_notify_send(PIPE_WRITEFILE(*inode), ION_OUT, POLLOUT | POLLWRNORM | POLLWRBAND);
 	up(PIPE_SEM(*inode));
 	/* Signal writers asynchronously that there is more room.  */
 	if (do_wakeup) {
@@ -205,7 +205,7 @@
 		}
 		/* Send notification message */
 		if (pempty && !PIPE_EMPTY(*inode) && PIPE_READFILE(*inode))
-			file_send_notify(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM);
+			file_notify_send(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM);
 		if (do_wakeup) {
 			wake_up_interruptible_sync(PIPE_WAIT(*inode));
 			kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN);
@@ -217,7 +217,7 @@
 	}
 	/* Send notification message */
 	if (pempty && !PIPE_EMPTY(*inode) && PIPE_READFILE(*inode))
-		file_send_notify(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM);
+		file_notify_send(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM);
 	up(PIPE_SEM(*inode));
 	if (do_wakeup) {
 		wake_up_interruptible(PIPE_WAIT(*inode));
@@ -290,12 +290,12 @@
  	if (decr && !PIPE_READERS(*inode)) {
 		PIPE_READFILE(*inode) = NULL;
 		if (wrfile)
-			file_send_notify(wrfile, ION_HUP, POLLHUP);
+			file_notify_send(wrfile, ION_HUP, POLLHUP);
 	}
 	if (decw && !PIPE_WRITERS(*inode)) {
 		PIPE_WRITEFILE(*inode) = NULL;
 		if (rdfile)
-			file_send_notify(rdfile, ION_HUP, POLLHUP);
+			file_notify_send(rdfile, ION_HUP, POLLHUP);
 	}
 	if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) {
 		struct pipe_inode_info *info = inode->i_pipe;
diff -Nru linux-2.5.45.vanilla/include/linux/fcblist.h linux-2.5.45.epoll/include/linux/fcblist.h
--- linux-2.5.45.vanilla/include/linux/fcblist.h	Wed Oct 30 16:43:34 2002
+++ linux-2.5.45.epoll/include/linux/fcblist.h	Wed Oct 30 17:50:44 2002
@@ -28,14 +28,17 @@
 #define ION_HUP		3
 #define ION_ERR		4
 
-#define FCB_LOCAL_SIZE	4
+/* Easy to use macro to test/free "struct fcb_priv_data" content */
+#define FCB_PRIV_FREE(p, f) do { if ((p)->desc) (p)->desc(f, (p)->data); } while (0)
 
 
-struct fcb_struct {
-	struct list_head llink;
-	void (*cbproc)(struct file *, void *, unsigned long *, long *);
+/*
+ * Generic private data encapsulation facility that enable customized
+ * data destruction through the callabck "desc".
+ */
+struct fcb_priv_data {
 	void *data;
-	unsigned long local[FCB_LOCAL_SIZE];
+	void (*desc)(struct file *, void *);
 };
 
 
@@ -44,14 +47,15 @@
 
 
 void file_notify_event(struct file *filep, long *event);
-
 int file_notify_addcb(struct file *filep,
-		      void (*cbproc)(struct file *, void *, unsigned long *, long *),
-		      void *data);
-
+		      void (*cbproc)(struct file *, void *, long *),
+		      struct fcb_priv_data const *priv);
 int file_notify_delcb(struct file *filep,
-		      void (*cbproc)(struct file *, void *, unsigned long *, long *));
-
+		      void (*cbproc)(struct file *, void *, long *), void *data,
+		      int freepriv);
+int file_notify_search(struct file *filep,
+		       void (*cbproc)(struct file *, void *, long *),
+		       int (*sproc)(void *, void *), void *priv);
 void file_notify_cleanup(struct file *filep);
 
 
@@ -61,7 +65,7 @@
 	INIT_LIST_HEAD(&filep->f_cblist);
 }
 
-static inline void file_send_notify(struct file *filep, long ioevt, long plevt)
+static inline void file_notify_send(struct file *filep, long ioevt, long plevt)
 {
 	long event[] = { ioevt, plevt, -1 };
 
diff -Nru linux-2.5.45.vanilla/include/net/sock.h linux-2.5.45.epoll/include/net/sock.h
--- linux-2.5.45.vanilla/include/net/sock.h	Wed Oct 30 16:43:33 2002
+++ linux-2.5.45.epoll/include/net/sock.h	Wed Oct 30 17:59:31 2002
@@ -771,7 +771,7 @@
 {
 	if (sk->socket) {
 		if (sk->socket->file)
-			file_send_notify(sk->socket->file, ion_band_table[band - POLL_IN],
+			file_notify_send(sk->socket->file, ion_band_table[band - POLL_IN],
 					 poll_band_table[band - POLL_IN]);
 		if (sk->socket->fasync_list)
 			sock_wake_async(sk->socket, how, band);
