X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Feventpoll.c;h=4284cd31eba6dcb6f125f1fd574aa2213439b45f;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=dbec5f9d59921c39ba36cd14ddbccde877558b93;hpb=daddc0d38b3571bed170afa273a49a0eba090c1e;p=linux-2.6.git diff --git a/fs/eventpoll.c b/fs/eventpoll.c index dbec5f9d5..4284cd31e 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -29,10 +29,11 @@ #include #include #include +#include #include #include #include -#include +#include #include #include #include @@ -100,60 +101,14 @@ /* 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 - -/* 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) - -/* - * This is used to optimize the event transfer to userspace. Since this - * is kept on stack, it should be pretty small. - */ -#define EP_MAX_BUF_EVENTS 32 +/* Maximum msec timeout value storeable in a long int */ +#define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ) +struct epoll_filefd { + struct file *file; + int fd; +}; /* * Node that is linked into the "wake_task_list" member of the "struct poll_safewake". @@ -203,11 +158,8 @@ struct eventpoll { /* 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 */ @@ -233,14 +185,14 @@ struct eppoll_entry { * 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; @@ -251,9 +203,6 @@ struct epitem { /* 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; @@ -286,22 +235,16 @@ struct ep_pqueue { 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, @@ -309,7 +252,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi); static int ep_unlink(struct eventpoll *ep, struct epitem *epi); static int ep_remove(struct eventpoll *ep, struct epitem *epi); -static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync); +static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key); static int ep_eventpoll_close(struct inode *inode, struct file *file); static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait); static int ep_collect_ready_items(struct eventpoll *ep, @@ -331,7 +274,7 @@ static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, /* * This semaphore is used to serialize ep_free() and eventpoll_release_file(). */ -struct semaphore epsem; +static struct semaphore epsem; /* Safe wake up implementation */ static struct poll_safewake psw; @@ -368,6 +311,82 @@ static struct dentry_operations eventpollfs_dentry_operations = { +/* 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) { @@ -432,19 +451,6 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq) } -/* - * 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) { @@ -480,7 +486,7 @@ void eventpoll_release_file(struct file *file) 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); @@ -500,37 +506,37 @@ void eventpoll_release_file(struct file *file) 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)); - /* Correctly size the hash */ - hashbits = ep_get_hash_bits((unsigned int) size); + /* + * Sanity check on the size parameter, and create the internal data + * structure ( "struct eventpoll" ). + */ + error = -EINVAL; + if (size <= 0 || (error = ep_alloc(&ep)) != 0) + goto eexit_1; /* * 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)); @@ -557,7 +563,8 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event) 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 */ @@ -582,7 +589,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event) * 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; /* @@ -641,6 +648,7 @@ eexit_1: return error; } +#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) /* * Implement the event wait interface for the eventpoll file. It is the kernel @@ -657,12 +665,14 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, 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; @@ -675,7 +685,7 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, * the user passed to us _is_ an eventpoll file. */ error = -EINVAL; - if (!IS_FILE_EPOLL(file)) + if (!is_file_epoll(file)) goto eexit_2; /* @@ -700,7 +710,8 @@ eexit_1: /* * 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]; @@ -742,7 +753,7 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile) 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; @@ -750,7 +761,7 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile) 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); @@ -771,114 +782,31 @@ eexit_1: } -static int ep_alloc_pages(char **pages, int numpages) +static int ep_alloc(struct eventpoll **pep) { - 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; -} + struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL); - -static int ep_file_init(struct file *file, unsigned int hashbits) -{ - int error; - struct eventpoll *ep; - - 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 */ @@ -896,16 +824,12 @@ static void ep_free(struct eventpoll *ep) down(&epsem); /* - * 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); } /* @@ -914,20 +838,12 @@ static void ep_free(struct eventpoll *ep) * 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)); } @@ -938,29 +854,33 @@ static void ep_free(struct eventpoll *ep) */ 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; } @@ -984,7 +904,7 @@ static void ep_release_epitem(struct epitem *epi) { if (atomic_dec_and_test(&epi->usecnt)) - EPI_MEM_FREE(epi); + kmem_cache_free(epi_cache, epi); } @@ -995,10 +915,10 @@ 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) { - 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; @@ -1012,6 +932,26 @@ static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, } +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) { @@ -1021,18 +961,17 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, 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; @@ -1064,11 +1003,11 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, /* 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 */ @@ -1097,11 +1036,11 @@ eexit_2: * 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; } @@ -1129,7 +1068,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even * 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); @@ -1140,14 +1079,14 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even * 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 */ @@ -1187,9 +1126,9 @@ static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) 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); } } } @@ -1208,7 +1147,7 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *epi) * 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; /* @@ -1219,18 +1158,18 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *epi) 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: @@ -1250,7 +1189,7 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) { 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 @@ -1264,8 +1203,8 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) /* 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() */ @@ -1296,11 +1235,11 @@ eexit_1: * machanism. It is called by the stored file descriptors when they * have events to report. */ -static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync) +static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key) { 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", @@ -1318,7 +1257,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync) 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); @@ -1397,7 +1336,7 @@ static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist 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 @@ -1412,7 +1351,7 @@ static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist /* * Unlink the item from the ready list. */ - EP_LIST_DEL(&epi->rdllink); + ep_list_del(&epi->rdllink); } } @@ -1430,11 +1369,10 @@ static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist static int ep_send_events(struct eventpoll *ep, struct list_head *txlist, struct epoll_event __user *events) { - int eventcnt = 0, eventbuf = 0; + int eventcnt = 0; unsigned int revents; struct list_head *lnk; struct epitem *epi; - struct epoll_event event[EP_MAX_BUF_EVENTS]; /* * We can loop without lock because this is a task private list. @@ -1450,7 +1388,7 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist, * 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. @@ -1460,28 +1398,16 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist, epi->revents = revents & epi->event.events; if (epi->revents) { - event[eventbuf] = epi->event; - event[eventbuf].events &= revents; - eventbuf++; - if (eventbuf == EP_MAX_BUF_EVENTS) { - if (__copy_to_user(&events[eventcnt], event, - eventbuf * sizeof(struct epoll_event))) - return -EFAULT; - eventcnt += eventbuf; - eventbuf = 0; - } + if (__put_user(epi->revents, + &events[eventcnt].events) || + __put_user(epi->event.data, + &events[eventcnt].data)) + return -EFAULT; if (epi->event.events & EPOLLONESHOT) epi->event.events &= EP_PRIVATE_BITS; + eventcnt++; } } - - if (eventbuf) { - if (__copy_to_user(&events[eventcnt], event, - eventbuf * sizeof(struct epoll_event))) - return -EFAULT; - eventcnt += eventbuf; - } - return eventcnt; } @@ -1504,7 +1430,7 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist) 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 @@ -1513,8 +1439,8 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist) * 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++; } @@ -1584,8 +1510,8 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, * 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); @@ -1695,22 +1621,14 @@ static int __init eventpoll_init(void) ep_poll_safewake_init(&psw); /* Allocates slab cache used to allocate "struct epitem" items */ - error = -ENOMEM; - epi_cache = kmem_cache_create("eventpoll_epi", - sizeof(struct epitem), - 0, - SLAB_HWCACHE_ALIGN | EPI_SLAB_DEBUG, NULL, NULL); - if (!epi_cache) - goto eexit_1; + epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem), + 0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC, + NULL, NULL); /* Allocates slab cache used to allocate "struct eppoll_entry" */ - error = -ENOMEM; pwq_cache = kmem_cache_create("eventpoll_pwq", - sizeof(struct eppoll_entry), - 0, - EPI_SLAB_DEBUG, NULL, NULL); - if (!pwq_cache) - goto eexit_2; + sizeof(struct eppoll_entry), 0, + EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL); /* * Register the virtual file system that will be the source of inodes @@ -1718,27 +1636,20 @@ static int __init eventpoll_init(void) */ error = register_filesystem(&eventpoll_fs_type); if (error) - goto eexit_3; + goto epanic; /* Mount the above commented virtual file system */ eventpoll_mnt = kern_mount(&eventpoll_fs_type); error = PTR_ERR(eventpoll_mnt); if (IS_ERR(eventpoll_mnt)) - goto eexit_4; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: successfully initialized.\n", current)); + goto epanic; + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: successfully initialized.\n", + current)); return 0; -eexit_4: - unregister_filesystem(&eventpoll_fs_type); -eexit_3: - kmem_cache_destroy(pwq_cache); -eexit_2: - kmem_cache_destroy(epi_cache); -eexit_1: - - return error; +epanic: + panic("eventpoll_init() failed\n"); } @@ -1755,4 +1666,3 @@ module_init(eventpoll_init); module_exit(eventpoll_exit); MODULE_LICENSE("GPL"); -