* have an entry of this type linked to the "rbr" RB tree.
*/
struct epitem {
- /* RB-Tree node used to link this structure to the eventpoll rb-tree */
+ /* 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 */
/* List of ready file descriptors */
struct list_head rdllist;
- /* RB-Tree root used to store monitored fd structs */
+ /* RB tree root used to store monitored fd structs */
struct rb_root rbr;
/*
static struct kmem_cache *pwq_cache __read_mostly;
-/* Setup the structure that is used as key for the rb-tree */
+/* 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->fd = fd;
}
-/* Compare rb-tree keys */
+/* Compare RB tree keys */
static inline int ep_cmp_ffd(struct epoll_filefd *p1,
struct epoll_filefd *p2)
{
(p1->file < p2->file ? -1 : p1->fd - p2->fd));
}
-/* Special initialization for the rb-tree node to detect linkage */
+/* Special initialization for the RB tree node to detect linkage */
static inline void ep_rb_initnode(struct rb_node *n)
{
rb_set_parent(n, n);
}
-/* Removes a node from the rb-tree and marks it for a fast is-linked check */
+/* 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);
rb_set_parent(n, n);
}
-/* Fast check to verify that the item is linked to the main rb-tree */
+/* 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 rb_parent(n) != n;
int wake_nests = 0;
unsigned long flags;
struct task_struct *this_task = current;
- struct list_head *lsthead = &psw->wake_task_list, *lnk;
+ struct list_head *lsthead = &psw->wake_task_list;
struct wake_task_node *tncur;
struct wake_task_node tnode;
spin_lock_irqsave(&psw->lock, flags);
/* Try to see if the current task is already inside this wakeup call */
- list_for_each(lnk, lsthead) {
- tncur = list_entry(lnk, struct wake_task_node, llink);
+ list_for_each_entry(tncur, lsthead, llink) {
if (tncur->wq == wq ||
(tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) {
* holding "epmutex" we can be sure that no file cleanup code will hit
* us during this operation. So we can avoid the lock on "ep->lock".
*/
- while ((rbp = rb_first(&ep->rbr)) != 0) {
+ while ((rbp = rb_first(&ep->rbr)) != NULL) {
epi = rb_entry(rbp, struct epitem, rbn);
ep_remove(ep, epi);
}
mutex_unlock(&epmutex);
-
mutex_destroy(&ep->mtx);
+ kfree(ep);
}
static int ep_eventpoll_release(struct inode *inode, struct file *file)
{
struct eventpoll *ep = file->private_data;
- if (ep) {
+ if (ep)
ep_free(ep);
- kfree(ep);
- }
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep));
return 0;
* We don't want to get "file->f_ep_lock" because it is not
* necessary. It is not necessary because we're in the "struct file"
* cleanup path, and this means that noone is using this file anymore.
+ * So, for example, epoll_ctl() cannot hit here sicne if we reach this
+ * point, the file counter already went to zero and fget() would fail.
* The only hit might come from ep_free() but by holding the mutex
* will correctly serialize the operation. We do need to acquire
* "ep->mtx" after "epmutex" because ep_remove() requires it when called
/*
* We need to do this because an event could have been arrived on some
- * allocated wait queue.
+ * allocated wait queue. Note that we don't care about the ep->ovflist
+ * list, since that is used/cleaned only inside a section bound by "mtx".
+ * And ep_insert() is called with "mtx" held.
*/
spin_lock_irqsave(&ep->lock, flags);
if (ep_is_linked(&epi->rdllink))
/*
* 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.
+ * list, push it inside.
*/
if (revents & event->events) {
if (!ep_is_linked(&epi->rdllink)) {
ep->ovflist = EP_UNACTIVE_PTR;
/*
- * In case of error in the event-send loop, we might still have items
- * inside the "txlist". We need to splice them back inside ep->rdllist.
+ * In case of error in the event-send loop, or in case the number of
+ * ready events exceeds the userspace limit, we need to splice the
+ * "txlist" back inside ep->rdllist.
*/
list_splice(&txlist, &ep->rdllist);
if (!list_empty(&ep->rdllist)) {
/*
* Wake up (if active) both the eventpoll wait list and the ->poll()
- * wait list.
+ * wait list (delayed after we release the lock).
*/
if (waitqueue_active(&ep->wq))
__wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
}
/*
- * It opens an eventpoll file descriptor by suggesting a storage of "size"
- * file descriptors. The size parameter is just an hint about how to size
- * data structures. It won't prevent the user to store more than "size"
- * file descriptors inside the epoll interface. It is the kernel part of
- * the userspace epoll_create(2).
+ * It opens an eventpoll file descriptor. The "size" parameter is there
+ * for historical reasons, when epoll was using an hash instead of an
+ * RB tree. With the current implementation, the "size" parameter is ignored
+ * (besides sanity checks).
*/
asmlinkage long sys_epoll_create(int size)
{
error_free:
ep_free(ep);
- kfree(ep);
error_return:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
current, size, error));
/*
* The following function implements the controller interface for
* the eventpoll file that enables the insertion/removal/change of
- * file descriptors inside the interest set. It represents
- * the kernel part of the user space epoll_ctl(2).
+ * file descriptors inside the interest set.
*/
asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
struct epoll_event __user *event)
mutex_lock(&ep->mtx);
- /* Try to lookup the file inside our RB tree */
+ /*
+ * Try to lookup the file inside our RB tree, Since we grabbed "mtx"
+ * above, we can be sure to be able to use the item looked up by
+ * ep_find() till we release the mutex.
+ */
epi = ep_find(ep, tfile, fd);
error = -EINVAL;
/* Allocates slab cache used to allocate "struct epitem" items */
epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),
0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC,
- NULL, NULL);
+ NULL);
/* Allocates slab cache used to allocate "struct eppoll_entry" */
pwq_cache = kmem_cache_create("eventpoll_pwq",
sizeof(struct eppoll_entry), 0,
- EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);
+ EPI_SLAB_DEBUG|SLAB_PANIC, NULL);
return 0;
}