/*
* fs/eventpoll.c ( Efficent event polling implementation )
- * Copyright (C) 2001,...,2006 Davide Libenzi
+ * Copyright (C) 2001,...,2003 Davide Libenzi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <linux/eventpoll.h>
#include <linux/mount.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) epmutex (mutex)
+ * 1) epsem (semaphore)
* 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 "epmutex" (together with "ep->lock") to have it working,
+ * semaphore "epsem" (together with "ep->lock") to have it working,
* but having "ep->sem" will make the interface more scalable.
- * Events that require holding "epmutex" are very rare, while for
+ * Events that require holding "epsem" are very rare, while for
* normal operations the epoll private "ep->sem" will guarantee
* a greater scalability.
*/
*/
struct wake_task_node {
struct list_head llink;
- struct task_struct *task;
+ task_t *task;
wait_queue_head_t *wq;
};
int maxevents, long timeout);
static int eventpollfs_delete_dentry(struct dentry *dentry);
static struct inode *ep_eventpoll_inode(void);
-static int eventpollfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data, struct vfsmount *mnt);
+static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data);
/*
* This semaphore is used to serialize ep_free() and eventpoll_release_file().
*/
-static struct mutex epmutex;
+static struct semaphore epsem;
/* Safe wake up implementation */
static struct poll_safewake psw;
/* Slab cache used to allocate "struct epitem" */
-static kmem_cache_t *epi_cache __read_mostly;
+static kmem_cache_t *epi_cache;
/* Slab cache used to allocate "struct eppoll_entry" */
-static kmem_cache_t *pwq_cache __read_mostly;
+static kmem_cache_t *pwq_cache;
/* Virtual fs used to allocate inodes for eventpoll files */
-static struct vfsmount *eventpoll_mnt __read_mostly;
+static struct vfsmount *eventpoll_mnt;
/* File callbacks that implement the eventpoll file behaviour */
-static const struct file_operations eventpoll_fops = {
+static struct file_operations eventpoll_fops = {
.release = ep_eventpoll_close,
.poll = ep_eventpoll_poll
};
/* 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);
+ 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);
- rb_set_parent(n, n);
+ 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 rb_parent(n) != n;
+ return n->rb_parent != n;
}
/*
{
int wake_nests = 0;
unsigned long flags;
- struct task_struct *this_task = current;
+ task_t *this_task = current;
struct list_head *lsthead = &psw->wake_task_list, *lnk;
struct wake_task_node *tncur;
struct wake_task_node tnode;
}
+/* 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 "epmutex" because ep_remove() requires it when called
+ * "ep->sem" after "epsem" because ep_remove() requires it when called
* from anywhere but ep_free().
*/
- mutex_lock(&epmutex);
+ down(&epsem);
while (!list_empty(lsthead)) {
epi = list_entry(lsthead->next, struct epitem, fllink);
up_write(&ep->sem);
}
- mutex_unlock(&epmutex);
+ up(&epsem);
}
* 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 "epmutex" is sufficent here.
+ * holding "epsem" is sufficent here.
*/
- mutex_lock(&epmutex);
+ down(&epsem);
/*
* Walks through the whole tree by unregistering poll callbacks.
ep_remove(ep, epi);
}
- mutex_unlock(&epmutex);
+ up(&epsem);
}
/* Notify waiting tasks that events are available */
if (waitqueue_active(&ep->wq))
- __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE);
+ wake_up(&ep->wq);
if (waitqueue_active(&ep->poll_wait))
pwake++;
}
/* Notify waiting tasks that events are available */
if (waitqueue_active(&ep->wq))
- __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
- TASK_INTERRUPTIBLE);
+ wake_up(&ep->wq);
if (waitqueue_active(&ep->poll_wait))
pwake++;
}
eexit_1:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n",
- current, ep, epi->ffd.file, error));
+ current, ep, epi->file, error));
return error;
}
struct eventpoll *ep = epi->ep;
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
- current, epi->ffd.file, epi, ep));
+ current, epi->file, epi, ep));
write_lock_irqsave(&ep->lock, flags);
* wait list.
*/
if (waitqueue_active(&ep->wq))
- __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
- TASK_INTERRUPTIBLE);
+ wake_up(&ep->wq);
if (waitqueue_active(&ep->poll_wait))
pwake++;
* wait list.
*/
if (waitqueue_active(&ep->wq))
- __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
- TASK_INTERRUPTIBLE);
+ wake_up(&ep->wq);
if (waitqueue_active(&ep->poll_wait))
pwake++;
}
* ep_poll_callback() when events will become available.
*/
init_waitqueue_entry(&wait, current);
- __add_wait_queue(&ep->wq, &wait);
+ add_wait_queue(&ep->wq, &wait);
for (;;) {
/*
jtimeout = schedule_timeout(jtimeout);
write_lock_irqsave(&ep->lock, flags);
}
- __remove_wait_queue(&ep->wq, &wait);
+ remove_wait_queue(&ep->wq, &wait);
set_current_state(TASK_RUNNING);
}
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blksize = PAGE_SIZE;
return inode;
eexit_1:
}
-static int
+static struct super_block *
eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data, struct vfsmount *mnt)
+ const char *dev_name, void *data)
{
- return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC,
- mnt);
+ return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC);
}
{
int error;
- mutex_init(&epmutex);
+ init_MUTEX(&epsem);
/* Initialize the structure used to perform safe poll wait head wake ups */
ep_poll_safewake_init(&psw);