fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / eventpoll.c
index 1b4491c..3ae644e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  fs/eventpoll.c ( Efficent event polling implementation )
- *  Copyright (C) 2001,...,2003         Davide Libenzi
+ *  Copyright (C) 2001,...,2006         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
 /* Maximum msec timeout value storeable in a long int */
 #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
 
+#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
+
 
 struct epoll_filefd {
        struct file *file;
@@ -120,7 +122,7 @@ struct epoll_filefd {
  */
 struct wake_task_node {
        struct list_head llink;
-       task_t *task;
+       struct task_struct *task;
        wait_queue_head_t *wq;
 };
 
@@ -268,9 +270,9 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                   int maxevents, long timeout);
 static int eventpollfs_delete_dentry(struct dentry *dentry);
 static struct inode *ep_eventpoll_inode(void);
-static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
-                                             int flags, const char *dev_name,
-                                             void *data);
+static int eventpollfs_get_sb(struct file_system_type *fs_type,
+                             int flags, const char *dev_name,
+                             void *data, struct vfsmount *mnt);
 
 /*
  * This semaphore is used to serialize ep_free() and eventpoll_release_file().
@@ -281,10 +283,10 @@ static struct mutex epmutex;
 static struct poll_safewake psw;
 
 /* Slab cache used to allocate "struct epitem" */
-static kmem_cache_t *epi_cache __read_mostly;
+static struct kmem_cache *epi_cache __read_mostly;
 
 /* Slab cache used to allocate "struct eppoll_entry" */
-static kmem_cache_t *pwq_cache __read_mostly;
+static struct kmem_cache *pwq_cache __read_mostly;
 
 /* Virtual fs used to allocate inodes for eventpoll files */
 static struct vfsmount *eventpoll_mnt __read_mostly;
@@ -337,20 +339,20 @@ static inline int ep_cmp_ffd(struct epoll_filefd *p1,
 /* Special initialization for the rb-tree node to detect linkage */
 static inline void ep_rb_initnode(struct rb_node *n)
 {
-       n->rb_parent = n;
+       rb_set_parent(n, 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;
+       rb_set_parent(n, 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;
+       return rb_parent(n) != n;
 }
 
 /*
@@ -413,7 +415,7 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq)
 {
        int wake_nests = 0;
        unsigned long flags;
-       task_t *this_task = current;
+       struct task_struct *this_task = current;
        struct list_head *lsthead = &psw->wake_task_list, *lnk;
        struct wake_task_node *tncur;
        struct wake_task_node tnode;
@@ -497,7 +499,7 @@ void eventpoll_release_file(struct file *file)
  */
 asmlinkage long sys_epoll_create(int size)
 {
-       int error, fd;
+       int error, fd = -1;
        struct eventpoll *ep;
        struct inode *inode;
        struct file *file;
@@ -640,7 +642,6 @@ 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,7 +658,7 @@ 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 || maxevents > MAX_EVENTS)
+       if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
                return -EINVAL;
 
        /* Verify that the area passed by the user is writeable */
@@ -699,6 +700,55 @@ eexit_1:
 }
 
 
+#ifdef TIF_RESTORE_SIGMASK
+
+/*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_pwait(2).
+ */
+asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
+               int maxevents, int timeout, const sigset_t __user *sigmask,
+               size_t sigsetsize)
+{
+       int error;
+       sigset_t ksigmask, sigsaved;
+
+       /*
+        * If the caller wants a certain signal mask to be set during the wait,
+        * we apply it here.
+        */
+       if (sigmask) {
+               if (sigsetsize != sizeof(sigset_t))
+                       return -EINVAL;
+               if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
+                       return -EFAULT;
+               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+       }
+
+       error = sys_epoll_wait(epfd, events, maxevents, timeout);
+
+       /*
+        * If we changed the signal mask, we need to restore the original one.
+        * In case we've got a signal while waiting, we do not restore the
+        * signal mask yet, and we allow do_signal() to deliver the signal on
+        * the way back to userspace, before the signal mask is restored.
+        */
+       if (sigmask) {
+               if (error == -EINTR) {
+                       memcpy(&current->saved_sigmask, &sigsaved,
+                               sizeof(sigsaved));
+                       set_thread_flag(TIF_RESTORE_SIGMASK);
+               } else
+                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+       }
+
+       return error;
+}
+
+#endif /* #ifdef TIF_RESTORE_SIGMASK */
+
+
 /*
  * Creates the file descriptor to be used by the epoll interface.
  */
@@ -720,9 +770,10 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
 
        /* Allocates an inode from the eventpoll file system */
        inode = ep_eventpoll_inode();
-       error = PTR_ERR(inode);
-       if (IS_ERR(inode))
+       if (IS_ERR(inode)) {
+               error = PTR_ERR(inode);
                goto eexit_2;
+       }
 
        /* Allocates a free descriptor to plug the file onto */
        error = get_unused_fd();
@@ -744,8 +795,8 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
                goto eexit_4;
        dentry->d_op = &eventpollfs_dentry_operations;
        d_add(dentry, inode);
-       file->f_vfsmnt = mntget(eventpoll_mnt);
-       file->f_dentry = dentry;
+       file->f_path.mnt = mntget(eventpoll_mnt);
+       file->f_path.dentry = dentry;
        file->f_mapping = inode->i_mapping;
 
        file->f_pos = 0;
@@ -910,7 +961,7 @@ static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
        struct epitem *epi = ep_item_from_epqueue(pt);
        struct eppoll_entry *pwq;
 
-       if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, SLAB_KERNEL))) {
+       if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, GFP_KERNEL))) {
                init_waitqueue_func_entry(&pwq->wait, ep_poll_callback);
                pwq->whead = whead;
                pwq->base = epi;
@@ -953,7 +1004,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
        struct ep_pqueue epq;
 
        error = -ENOMEM;
-       if (!(epi = kmem_cache_alloc(epi_cache, SLAB_KERNEL)))
+       if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL)))
                goto eexit_1;
 
        /* Item initialization follow here ... */
@@ -1004,7 +1055,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 
                /* Notify waiting tasks that events are available */
                if (waitqueue_active(&ep->wq))
-                       wake_up(&ep->wq);
+                       __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE);
                if (waitqueue_active(&ep->poll_wait))
                        pwake++;
        }
@@ -1083,7 +1134,8 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
 
                                /* Notify waiting tasks that events are available */
                                if (waitqueue_active(&ep->wq))
-                                       wake_up(&ep->wq);
+                                       __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+                                                        TASK_INTERRUPTIBLE);
                                if (waitqueue_active(&ep->poll_wait))
                                        pwake++;
                        }
@@ -1167,7 +1219,7 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *epi)
 eexit_1:
 
        DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n",
-                    current, ep, epi->file, error));
+                    current, ep, epi->ffd.file, error));
 
        return error;
 }
@@ -1235,7 +1287,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
        struct eventpoll *ep = epi->ep;
 
        DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
-                    current, epi->file, epi, ep));
+                    current, epi->ffd.file, epi, ep));
 
        write_lock_irqsave(&ep->lock, flags);
 
@@ -1260,7 +1312,8 @@ is_linked:
         * wait list.
         */
        if (waitqueue_active(&ep->wq))
-               wake_up(&ep->wq);
+               __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+                                TASK_INTERRUPTIBLE);
        if (waitqueue_active(&ep->poll_wait))
                pwake++;
 
@@ -1444,7 +1497,8 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
                 * wait list.
                 */
                if (waitqueue_active(&ep->wq))
-                       wake_up(&ep->wq);
+                       __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+                                        TASK_INTERRUPTIBLE);
                if (waitqueue_active(&ep->poll_wait))
                        pwake++;
        }
@@ -1516,7 +1570,7 @@ retry:
                 * 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 (;;) {
                        /*
@@ -1536,7 +1590,7 @@ retry:
                        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);
        }
@@ -1587,7 +1641,6 @@ static struct inode *ep_eventpoll_inode(void)
        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:
@@ -1595,11 +1648,12 @@ eexit_1:
 }
 
 
-static struct super_block *
+static int
 eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
-                  const char *dev_name, void *data)
+                  const char *dev_name, void *data, struct vfsmount *mnt)
 {
-       return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC);
+       return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC,
+                            mnt);
 }