#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/rwsem.h>
+#include <linux/rbtree.h>
#include <linux/wait.h>
#include <linux/eventpoll.h>
#include <linux/mount.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
* LOCKING:
* There are three level of locking required by epoll :
*
- * 1) epsem (semaphore)
+ * 1) epmutex (mutex)
* 2) ep->sem (rw_semaphore)
* 3) ep->lock (rw_lock)
*
* if a file has been pushed inside an epoll set and it is then
* close()d without a previous call toepoll_ctl(EPOLL_CTL_DEL).
* It is possible to drop the "ep->sem" and to use the global
- * semaphore "epsem" (together with "ep->lock") to have it working,
+ * semaphore "epmutex" (together with "ep->lock") to have it working,
* but having "ep->sem" will make the interface more scalable.
- * Events that require holding "epsem" are very rare, while for
+ * Events that require holding "epmutex" are very rare, while for
* normal operations the epoll private "ep->sem" will guarantee
* a greater scalability.
*/
/* Maximum number of poll wake up nests we are allowing */
#define EP_MAX_POLLWAKE_NESTS 4
-/* Maximum size of the hash in bits ( 2^N ) */
-#define EP_MAX_HASH_BITS 17
+/* Maximum msec timeout value storeable in a long int */
+#define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
-/* Minimum size of the hash in bits ( 2^N ) */
-#define EP_MIN_HASH_BITS 9
-/* Number of hash entries ( "struct list_head" ) inside a page */
-#define EP_HENTRY_X_PAGE (PAGE_SIZE / sizeof(struct list_head))
-
-/* Maximum size of the hash in pages */
-#define EP_MAX_HPAGES ((1 << EP_MAX_HASH_BITS) / EP_HENTRY_X_PAGE + 1)
-
-/* Number of pages allocated for an "hbits" sized hash table */
-#define EP_HASH_PAGES(hbits) ((int) ((1 << (hbits)) / EP_HENTRY_X_PAGE + \
- ((1 << (hbits)) % EP_HENTRY_X_PAGE ? 1: 0)))
-
-/* Macro to allocate a "struct epitem" from the slab cache */
-#define EPI_MEM_ALLOC() (struct epitem *) kmem_cache_alloc(epi_cache, SLAB_KERNEL)
-
-/* Macro to free a "struct epitem" to the slab cache */
-#define EPI_MEM_FREE(p) kmem_cache_free(epi_cache, p)
-
-/* Macro to allocate a "struct eppoll_entry" from the slab cache */
-#define PWQ_MEM_ALLOC() (struct eppoll_entry *) kmem_cache_alloc(pwq_cache, SLAB_KERNEL)
-
-/* Macro to free a "struct eppoll_entry" to the slab cache */
-#define PWQ_MEM_FREE(p) kmem_cache_free(pwq_cache, p)
-
-/* Fast test to see if the file is an evenpoll file */
-#define IS_FILE_EPOLL(f) ((f)->f_op == &eventpoll_fops)
-
-/*
- * Remove the item from the list and perform its initialization.
- * This is useful for us because we can test if the item is linked
- * using "EP_IS_LINKED(p)".
- */
-#define EP_LIST_DEL(p) do { list_del(p); INIT_LIST_HEAD(p); } while (0)
-
-/* Tells us if the item is currently linked */
-#define EP_IS_LINKED(p) (!list_empty(p))
-
-/* Get the "struct epitem" from a wait queue pointer */
-#define EP_ITEM_FROM_WAIT(p) ((struct epitem *) container_of(p, struct eppoll_entry, wait)->base)
-
-/* Get the "struct epitem" from an epoll queue wrapper */
-#define EP_ITEM_FROM_EPQUEUE(p) (container_of(p, struct ep_pqueue, pt)->epi)
+struct epoll_filefd {
+ struct file *file;
+ int fd;
+};
/*
* Node that is linked into the "wake_task_list" member of the "struct poll_safewake".
/* List of ready file descriptors */
struct list_head rdllist;
- /* Size of the hash */
- unsigned int hashbits;
-
- /* Pages for the "struct epitem" hash */
- char *hpages[EP_MAX_HPAGES];
+ /* RB-Tree root used to store monitored fd structs */
+ struct rb_root rbr;
};
/* Wait structure used by the poll hooks */
* have an entry of this type linked to the hash.
*/
struct epitem {
- /* List header used to link this structure to the eventpoll hash */
- struct list_head llink;
+ /* RB-Tree node used to link this structure to the eventpoll rb-tree */
+ struct rb_node rbn;
/* List header used to link this structure to the eventpoll ready list */
struct list_head rdllink;
- /* The file descriptor this item refers to */
- int fd;
+ /* The file descriptor information this item refers to */
+ struct epoll_filefd ffd;
/* Number of active wait queue attached to poll operations */
int nwait;
/* The "container" of this item */
struct eventpoll *ep;
- /* The file this item refers to */
- struct file *file;
-
/* The structure that describe the interested events and the source fd */
struct epoll_event event;
static void ep_poll_safewake_init(struct poll_safewake *psw);
static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq);
-static unsigned int ep_get_hash_bits(unsigned int hintsize);
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile);
-static int ep_alloc_pages(char **pages, int numpages);
-static int ep_free_pages(char **pages, int numpages);
-static int ep_file_init(struct file *file, unsigned int hashbits);
-static unsigned int ep_hash_index(struct eventpoll *ep, struct file *file,
- int fd);
-static struct list_head *ep_hash_entry(struct eventpoll *ep,
- unsigned int index);
-static int ep_init(struct eventpoll *ep, unsigned int hashbits);
+static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
+ struct eventpoll *ep);
+static int ep_alloc(struct eventpoll **pep);
static void ep_free(struct eventpoll *ep);
static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd);
static void ep_use_epitem(struct epitem *epi);
static void ep_release_epitem(struct epitem *epi);
static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
poll_table *pt);
+static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi);
static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
struct file *tfile, int fd);
static int ep_modify(struct eventpoll *ep, struct epitem *epi,
/*
* This semaphore is used to serialize ep_free() and eventpoll_release_file().
*/
-struct semaphore epsem;
+static struct mutex epmutex;
/* Safe wake up implementation */
static struct poll_safewake psw;
/* Slab cache used to allocate "struct epitem" */
-static kmem_cache_t *epi_cache;
+static kmem_cache_t *epi_cache __read_mostly;
/* Slab cache used to allocate "struct eppoll_entry" */
-static kmem_cache_t *pwq_cache;
+static kmem_cache_t *pwq_cache __read_mostly;
/* Virtual fs used to allocate inodes for eventpoll files */
-static struct vfsmount *eventpoll_mnt;
+static struct vfsmount *eventpoll_mnt __read_mostly;
/* File callbacks that implement the eventpoll file behaviour */
-static struct file_operations eventpoll_fops = {
+static const struct file_operations eventpoll_fops = {
.release = ep_eventpoll_close,
.poll = ep_eventpoll_poll
};
+/* Fast test to see if the file is an evenpoll file */
+static inline int is_file_epoll(struct file *f)
+{
+ return f->f_op == &eventpoll_fops;
+}
+
+/* Setup the structure that is used as key for the rb-tree */
+static inline void ep_set_ffd(struct epoll_filefd *ffd,
+ struct file *file, int fd)
+{
+ ffd->file = file;
+ ffd->fd = fd;
+}
+
+/* Compare rb-tree keys */
+static inline int ep_cmp_ffd(struct epoll_filefd *p1,
+ struct epoll_filefd *p2)
+{
+ return (p1->file > p2->file ? +1:
+ (p1->file < p2->file ? -1 : p1->fd - p2->fd));
+}
+
+/* Special initialization for the rb-tree node to detect linkage */
+static inline void ep_rb_initnode(struct rb_node *n)
+{
+ n->rb_parent = n;
+}
+
+/* Removes a node from the rb-tree and marks it for a fast is-linked check */
+static inline void ep_rb_erase(struct rb_node *n, struct rb_root *r)
+{
+ rb_erase(n, r);
+ n->rb_parent = n;
+}
+
+/* Fast check to verify that the item is linked to the main rb-tree */
+static inline int ep_rb_linked(struct rb_node *n)
+{
+ return n->rb_parent != n;
+}
+
+/*
+ * Remove the item from the list and perform its initialization.
+ * This is useful for us because we can test if the item is linked
+ * using "ep_is_linked(p)".
+ */
+static inline void ep_list_del(struct list_head *p)
+{
+ list_del(p);
+ INIT_LIST_HEAD(p);
+}
+
+/* Tells us if the item is currently linked */
+static inline int ep_is_linked(struct list_head *p)
+{
+ return !list_empty(p);
+}
+
+/* Get the "struct epitem" from a wait queue pointer */
+static inline struct epitem * ep_item_from_wait(wait_queue_t *p)
+{
+ return container_of(p, struct eppoll_entry, wait)->base;
+}
+
+/* Get the "struct epitem" from an epoll queue wrapper */
+static inline struct epitem * ep_item_from_epqueue(poll_table *p)
+{
+ return container_of(p, struct ep_pqueue, pt)->epi;
+}
+
+/* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
+static inline int ep_op_hash_event(int op)
+{
+ return op != EPOLL_CTL_DEL;
+}
+
/* Initialize the poll safe wake up structure */
static void ep_poll_safewake_init(struct poll_safewake *psw)
{
}
-/*
- * Calculate the size of the hash in bits. The returned size will be
- * bounded between EP_MIN_HASH_BITS and EP_MAX_HASH_BITS.
- */
-static unsigned int ep_get_hash_bits(unsigned int hintsize)
-{
- unsigned int i, val;
-
- for (i = 0, val = 1; val < hintsize && i < EP_MAX_HASH_BITS; i++, val <<= 1);
- return i < EP_MIN_HASH_BITS ? EP_MIN_HASH_BITS: i;
-}
-
-
-/* Used to initialize the epoll bits inside the "struct file" */
-void eventpoll_init_file(struct file *file)
-{
-
- INIT_LIST_HEAD(&file->f_ep_links);
- spin_lock_init(&file->f_ep_lock);
-}
-
-
/*
* This is called from eventpoll_release() to unlink files from the eventpoll
* interface. We need to have this facility to cleanup correctly files that are
* cleanup path, and this means that noone is using this file anymore.
* The only hit might come from ep_free() but by holding the semaphore
* will correctly serialize the operation. We do need to acquire
- * "ep->sem" after "epsem" because ep_remove() requires it when called
+ * "ep->sem" after "epmutex" because ep_remove() requires it when called
* from anywhere but ep_free().
*/
- down(&epsem);
+ mutex_lock(&epmutex);
while (!list_empty(lsthead)) {
epi = list_entry(lsthead->next, struct epitem, fllink);
ep = epi->ep;
- EP_LIST_DEL(&epi->fllink);
+ ep_list_del(&epi->fllink);
down_write(&ep->sem);
ep_remove(ep, epi);
up_write(&ep->sem);
}
- up(&epsem);
+ mutex_unlock(&epmutex);
}
asmlinkage long sys_epoll_create(int size)
{
int error, fd;
- unsigned int hashbits;
+ struct eventpoll *ep;
struct inode *inode;
struct file *file;
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
current, size));
- /* Sanity check on the size parameter */
+ /*
+ * Sanity check on the size parameter, and create the internal data
+ * structure ( "struct eventpoll" ).
+ */
error = -EINVAL;
- if (size <= 0)
+ if (size <= 0 || (error = ep_alloc(&ep)) != 0)
goto eexit_1;
- /* Correctly size the hash */
- hashbits = ep_get_hash_bits((unsigned int) size);
-
/*
* Creates all the items needed to setup an eventpoll file. That is,
* a file structure, and inode and a free file descriptor.
*/
- error = ep_getfd(&fd, &inode, &file);
- if (error)
- goto eexit_1;
-
- /* Setup the file internal data structure ( "struct eventpoll" ) */
- error = ep_file_init(file, hashbits);
+ error = ep_getfd(&fd, &inode, &file, ep);
if (error)
goto eexit_2;
-
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
current, size, fd));
return fd;
eexit_2:
- sys_close(fd);
+ ep_free(ep);
+ kfree(ep);
eexit_1:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
current, size, error));
current, epfd, op, fd, event));
error = -EFAULT;
- if (copy_from_user(&epds, event, sizeof(struct epoll_event)))
+ if (ep_op_hash_event(op) &&
+ copy_from_user(&epds, event, sizeof(struct epoll_event)))
goto eexit_1;
/* Get the "struct file *" for the eventpoll file */
* adding an epoll file descriptor inside itself.
*/
error = -EINVAL;
- if (file == tfile || !IS_FILE_EPOLL(file))
+ if (file == tfile || !is_file_epoll(file))
goto eexit_3;
/*
return error;
}
+#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
/*
* Implement the event wait interface for the eventpoll file. It is the kernel
current, epfd, events, maxevents, timeout));
/* The maximum number of event must be greater than zero */
- if (maxevents <= 0)
+ if (maxevents <= 0 || maxevents > MAX_EVENTS)
return -EINVAL;
/* Verify that the area passed by the user is writeable */
- if ((error = verify_area(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))))
+ if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) {
+ error = -EFAULT;
goto eexit_1;
+ }
/* Get the "struct file *" for the eventpoll file */
error = -EBADF;
* the user passed to us _is_ an eventpoll file.
*/
error = -EINVAL;
- if (!IS_FILE_EPOLL(file))
+ if (!is_file_epoll(file))
goto eexit_2;
/*
/*
* Creates the file descriptor to be used by the epoll interface.
*/
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile)
+static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
+ struct eventpoll *ep)
{
struct qstr this;
char name[32];
dentry->d_op = &eventpollfs_dentry_operations;
d_add(dentry, inode);
file->f_vfsmnt = mntget(eventpoll_mnt);
- file->f_dentry = dget(dentry);
+ file->f_dentry = dentry;
file->f_mapping = inode->i_mapping;
file->f_pos = 0;
file->f_op = &eventpoll_fops;
file->f_mode = FMODE_READ;
file->f_version = 0;
- file->private_data = NULL;
+ file->private_data = ep;
/* Install the new setup file into the allocated fd. */
fd_install(fd, file);
}
-static int ep_alloc_pages(char **pages, int numpages)
-{
- int i;
-
- for (i = 0; i < numpages; i++) {
- pages[i] = (char *) __get_free_pages(GFP_KERNEL, 0);
- if (!pages[i]) {
- for (--i; i >= 0; i--) {
- ClearPageReserved(virt_to_page(pages[i]));
- free_pages((unsigned long) pages[i], 0);
- }
- return -ENOMEM;
- }
- SetPageReserved(virt_to_page(pages[i]));
- }
- return 0;
-}
-
-
-static int ep_free_pages(char **pages, int numpages)
-{
- int i;
-
- for (i = 0; i < numpages; i++) {
- ClearPageReserved(virt_to_page(pages[i]));
- free_pages((unsigned long) pages[i], 0);
- }
- return 0;
-}
-
-
-static int ep_file_init(struct file *file, unsigned int hashbits)
+static int ep_alloc(struct eventpoll **pep)
{
- int error;
- struct eventpoll *ep;
+ struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL);
- if (!(ep = kmalloc(sizeof(struct eventpoll), GFP_KERNEL)))
+ if (!ep)
return -ENOMEM;
- memset(ep, 0, sizeof(*ep));
-
- error = ep_init(ep, hashbits);
- if (error) {
- kfree(ep);
- return error;
- }
-
- file->private_data = ep;
-
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_file_init() ep=%p\n",
- current, ep));
- return 0;
-}
-
-
-/*
- * Calculate the index of the hash relative to "file".
- */
-static unsigned int ep_hash_index(struct eventpoll *ep, struct file *file, int fd)
-{
- unsigned long ptr = (unsigned long) file ^ (fd << ep->hashbits);
-
- return (unsigned int) hash_ptr((void *) ptr, ep->hashbits);
-}
-
-
-/*
- * Returns the hash entry ( struct list_head * ) of the passed index.
- */
-static struct list_head *ep_hash_entry(struct eventpoll *ep, unsigned int index)
-{
-
- return (struct list_head *) (ep->hpages[index / EP_HENTRY_X_PAGE] +
- (index % EP_HENTRY_X_PAGE) * sizeof(struct list_head));
-}
-
-
-static int ep_init(struct eventpoll *ep, unsigned int hashbits)
-{
- int error;
- unsigned int i, hsize;
-
rwlock_init(&ep->lock);
init_rwsem(&ep->sem);
init_waitqueue_head(&ep->wq);
init_waitqueue_head(&ep->poll_wait);
INIT_LIST_HEAD(&ep->rdllist);
+ ep->rbr = RB_ROOT;
- /* Hash allocation and setup */
- ep->hashbits = hashbits;
- error = ep_alloc_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits));
- if (error)
- goto eexit_1;
-
- /* Initialize hash buckets */
- for (i = 0, hsize = 1 << hashbits; i < hsize; i++)
- INIT_LIST_HEAD(ep_hash_entry(ep, i));
+ *pep = ep;
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n",
+ current, ep));
return 0;
-eexit_1:
- return error;
}
static void ep_free(struct eventpoll *ep)
{
- unsigned int i, hsize;
- struct list_head *lsthead, *lnk;
+ struct rb_node *rbp;
struct epitem *epi;
/* We need to release all tasks waiting for these file */
* We do not need to hold "ep->sem" here because the epoll file
* is on the way to be removed and no one has references to it
* anymore. The only hit might come from eventpoll_release_file() but
- * holding "epsem" is sufficent here.
+ * holding "epmutex" is sufficent here.
*/
- down(&epsem);
+ mutex_lock(&epmutex);
/*
- * Walks through the whole hash by unregistering poll callbacks.
+ * Walks through the whole tree by unregistering poll callbacks.
*/
- for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) {
- lsthead = ep_hash_entry(ep, i);
-
- list_for_each(lnk, lsthead) {
- epi = list_entry(lnk, struct epitem, llink);
+ for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
+ epi = rb_entry(rbp, struct epitem, rbn);
- ep_unregister_pollwait(ep, epi);
- }
+ ep_unregister_pollwait(ep, epi);
}
/*
* write-holding "sem" we can be sure that no file cleanup code will hit
* us during this operation. So we can avoid the lock on "ep->lock".
*/
- for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) {
- lsthead = ep_hash_entry(ep, i);
-
- while (!list_empty(lsthead)) {
- epi = list_entry(lsthead->next, struct epitem, llink);
-
- ep_remove(ep, epi);
- }
+ while ((rbp = rb_first(&ep->rbr)) != 0) {
+ epi = rb_entry(rbp, struct epitem, rbn);
+ ep_remove(ep, epi);
}
- up(&epsem);
-
- /* Free hash pages */
- ep_free_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits));
+ mutex_unlock(&epmutex);
}
*/
static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd)
{
+ int kcmp;
unsigned long flags;
- struct list_head *lsthead, *lnk;
- struct epitem *epi = NULL;
+ struct rb_node *rbp;
+ struct epitem *epi, *epir = NULL;
+ struct epoll_filefd ffd;
+ ep_set_ffd(&ffd, file, fd);
read_lock_irqsave(&ep->lock, flags);
-
- lsthead = ep_hash_entry(ep, ep_hash_index(ep, file, fd));
- list_for_each(lnk, lsthead) {
- epi = list_entry(lnk, struct epitem, llink);
-
- if (epi->file == file && epi->fd == fd) {
+ for (rbp = ep->rbr.rb_node; rbp; ) {
+ epi = rb_entry(rbp, struct epitem, rbn);
+ kcmp = ep_cmp_ffd(&ffd, &epi->ffd);
+ if (kcmp > 0)
+ rbp = rbp->rb_right;
+ else if (kcmp < 0)
+ rbp = rbp->rb_left;
+ else {
ep_use_epitem(epi);
+ epir = epi;
break;
}
- epi = NULL;
}
-
read_unlock_irqrestore(&ep->lock, flags);
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_find(%p) -> %p\n",
- current, file, epi));
+ current, file, epir));
- return epi;
+ return epir;
}
{
if (atomic_dec_and_test(&epi->usecnt))
- EPI_MEM_FREE(epi);
+ kmem_cache_free(epi_cache, epi);
}
static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
poll_table *pt)
{
- struct epitem *epi = EP_ITEM_FROM_EPQUEUE(pt);
+ struct epitem *epi = ep_item_from_epqueue(pt);
struct eppoll_entry *pwq;
- if (epi->nwait >= 0 && (pwq = PWQ_MEM_ALLOC())) {
+ if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, SLAB_KERNEL))) {
init_waitqueue_func_entry(&pwq->wait, ep_poll_callback);
pwq->whead = whead;
pwq->base = epi;
}
+static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
+{
+ int kcmp;
+ struct rb_node **p = &ep->rbr.rb_node, *parent = NULL;
+ struct epitem *epic;
+
+ while (*p) {
+ parent = *p;
+ epic = rb_entry(parent, struct epitem, rbn);
+ kcmp = ep_cmp_ffd(&epi->ffd, &epic->ffd);
+ if (kcmp > 0)
+ p = &parent->rb_right;
+ else
+ p = &parent->rb_left;
+ }
+ rb_link_node(&epi->rbn, parent, p);
+ rb_insert_color(&epi->rbn, &ep->rbr);
+}
+
+
static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
struct file *tfile, int fd)
{
struct ep_pqueue epq;
error = -ENOMEM;
- if (!(epi = EPI_MEM_ALLOC()))
+ if (!(epi = kmem_cache_alloc(epi_cache, SLAB_KERNEL)))
goto eexit_1;
/* Item initialization follow here ... */
- INIT_LIST_HEAD(&epi->llink);
+ ep_rb_initnode(&epi->rbn);
INIT_LIST_HEAD(&epi->rdllink);
INIT_LIST_HEAD(&epi->fllink);
INIT_LIST_HEAD(&epi->txlink);
INIT_LIST_HEAD(&epi->pwqlist);
epi->ep = ep;
- epi->file = tfile;
- epi->fd = fd;
+ ep_set_ffd(&epi->ffd, tfile, fd);
epi->event = *event;
atomic_set(&epi->usecnt, 1);
epi->nwait = 0;
/* We have to drop the new item inside our item list to keep track of it */
write_lock_irqsave(&ep->lock, flags);
- /* Add the current item to the hash table */
- list_add(&epi->llink, ep_hash_entry(ep, ep_hash_index(ep, tfile, fd)));
+ /* Add the current item to the rb-tree */
+ ep_rbtree_insert(ep, epi);
/* If the file is already "ready" we drop it inside the ready list */
- if ((revents & event->events) && !EP_IS_LINKED(&epi->rdllink)) {
+ if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
/* Notify waiting tasks that events are available */
* allocated wait queue.
*/
write_lock_irqsave(&ep->lock, flags);
- if (EP_IS_LINKED(&epi->rdllink))
- EP_LIST_DEL(&epi->rdllink);
+ if (ep_is_linked(&epi->rdllink))
+ ep_list_del(&epi->rdllink);
write_unlock_irqrestore(&ep->lock, flags);
- EPI_MEM_FREE(epi);
+ kmem_cache_free(epi_cache, epi);
eexit_1:
return error;
}
* Get current event bits. We can safely use the file* here because
* its usage count has been increased by the caller of this function.
*/
- revents = epi->file->f_op->poll(epi->file, NULL);
+ revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
write_lock_irqsave(&ep->lock, flags);
* If the item is not linked to the hash it means that it's on its
* way toward the removal. Do nothing in this case.
*/
- if (EP_IS_LINKED(&epi->llink)) {
+ if (ep_rb_linked(&epi->rbn)) {
/*
* If the item is "hot" and it is not registered inside the ready
* list, push it inside. If the item is not "hot" and it is currently
* registered inside the ready list, unlink it.
*/
if (revents & event->events) {
- if (!EP_IS_LINKED(&epi->rdllink)) {
+ if (!ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
/* Notify waiting tasks that events are available */
while (!list_empty(lsthead)) {
pwq = list_entry(lsthead->next, struct eppoll_entry, llink);
- EP_LIST_DEL(&pwq->llink);
+ ep_list_del(&pwq->llink);
remove_wait_queue(pwq->whead, &pwq->wait);
- PWQ_MEM_FREE(pwq);
+ kmem_cache_free(pwq_cache, pwq);
}
}
}
* The check protect us from doing a double unlink ( crash ).
*/
error = -ENOENT;
- if (!EP_IS_LINKED(&epi->llink))
+ if (!ep_rb_linked(&epi->rbn))
goto eexit_1;
/*
epi->event.events = 0;
/*
- * At this point is safe to do the job, unlink the item from our list.
+ * At this point is safe to do the job, unlink the item from our rb-tree.
* This operation togheter with the above check closes the door to
* double unlinks.
*/
- EP_LIST_DEL(&epi->llink);
+ ep_rb_erase(&epi->rbn, &ep->rbr);
/*
* If the item we are going to remove is inside the ready file descriptors
* we want to remove it from this list to avoid stale events.
*/
- if (EP_IS_LINKED(&epi->rdllink))
- EP_LIST_DEL(&epi->rdllink);
+ if (ep_is_linked(&epi->rdllink))
+ ep_list_del(&epi->rdllink);
error = 0;
eexit_1:
{
int error;
unsigned long flags;
- struct file *file = epi->file;
+ struct file *file = epi->ffd.file;
/*
* Removes poll wait queue hooks. We _have_ to do this without holding
/* Remove the current item from the list of epoll hooks */
spin_lock(&file->f_ep_lock);
- if (EP_IS_LINKED(&epi->fllink))
- EP_LIST_DEL(&epi->fllink);
+ if (ep_is_linked(&epi->fllink))
+ ep_list_del(&epi->fllink);
spin_unlock(&file->f_ep_lock);
/* We need to acquire the write IRQ lock before calling ep_unlink() */
{
int pwake = 0;
unsigned long flags;
- struct epitem *epi = EP_ITEM_FROM_WAIT(wait);
+ struct epitem *epi = ep_item_from_wait(wait);
struct eventpoll *ep = epi->ep;
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
goto is_disabled;
/* If this file is already in the ready list we exit soon */
- if (EP_IS_LINKED(&epi->rdllink))
+ if (ep_is_linked(&epi->rdllink))
goto is_linked;
list_add_tail(&epi->rdllink, &ep->rdllist);
lnk = lnk->next;
/* If this file is already in the ready list we exit soon */
- if (!EP_IS_LINKED(&epi->txlink)) {
+ if (!ep_is_linked(&epi->txlink)) {
/*
* This is initialized in this way so that the default
* behaviour of the reinjecting code will be to push back
/*
* Unlink the item from the ready list.
*/
- EP_LIST_DEL(&epi->rdllink);
+ ep_list_del(&epi->rdllink);
}
}
* because we are holding the "sem" in read and this will
* guarantee that both the file and the item will not vanish.
*/
- revents = epi->file->f_op->poll(epi->file, NULL);
+ revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
/*
* Set the return event set for the current file descriptor.
epi = list_entry(txlist->next, struct epitem, txlink);
/* Unlink the current item from the transfer list */
- EP_LIST_DEL(&epi->txlink);
+ ep_list_del(&epi->txlink);
/*
* If the item is no more linked to the interest set, we don't
* item is set to have an Edge Triggered behaviour, we don't have
* to push it back either.
*/
- if (EP_IS_LINKED(&epi->llink) && !(epi->event.events & EPOLLET) &&
- (epi->revents & epi->event.events) && !EP_IS_LINKED(&epi->rdllink)) {
+ if (ep_rb_linked(&epi->rbn) && !(epi->event.events & EPOLLET) &&
+ (epi->revents & epi->event.events) && !ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
ricnt++;
}
* and the overflow condition. The passed timeout is in milliseconds,
* that why (t * HZ) / 1000.
*/
- jtimeout = timeout == -1 || timeout > (MAX_SCHEDULE_TIMEOUT - 1000) / HZ ?
- MAX_SCHEDULE_TIMEOUT: (timeout * HZ + 999) / 1000;
+ jtimeout = (timeout < 0 || timeout >= EP_MAX_MSTIMEO) ?
+ MAX_SCHEDULE_TIMEOUT : (timeout * HZ + 999) / 1000;
retry:
write_lock_irqsave(&ep->lock, flags);
{
int error;
- init_MUTEX(&epsem);
+ mutex_init(&epmutex);
/* Initialize the structure used to perform safe poll wait head wake ups */
ep_poll_safewake_init(&psw);