]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/eventpoll.c
Staging: rtl8192e: delete some dead cruft
[karo-tx-linux.git] / fs / eventpoll.c
index a3acf936c72af92e7316be81a3f5b4900a1fd518..deecc7294a672c3fa64cf3884c4ee28f4c7f80a7 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/atomic.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/compat.h>
 
 /*
  * LOCKING:
@@ -745,11 +746,15 @@ static void ep_free(struct eventpoll *ep)
         * point we are sure no poll callbacks will be lingering around, and also by
         * 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".
+        * We do not need to lock ep->mtx, either, we only do it to prevent
+        * a lockdep warning.
         */
+       mutex_lock(&ep->mtx);
        while ((rbp = rb_first(&ep->rbr)) != NULL) {
                epi = rb_entry(rbp, struct epitem, rbn);
                ep_remove(ep, epi);
        }
+       mutex_unlock(&ep->mtx);
 
        mutex_unlock(&epmutex);
        mutex_destroy(&ep->mtx);
@@ -768,6 +773,13 @@ static int ep_eventpoll_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static inline unsigned int ep_item_poll(struct epitem *epi, poll_table *pt)
+{
+       pt->_key = epi->event.events;
+
+       return epi->ffd.file->f_op->poll(epi->ffd.file, pt) & epi->event.events;
+}
+
 static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
                               void *priv)
 {
@@ -775,10 +787,9 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
        poll_table pt;
 
        init_poll_funcptr(&pt, NULL);
+
        list_for_each_entry_safe(epi, tmp, head, rdllink) {
-               pt._key = epi->event.events;
-               if (epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
-                   epi->event.events)
+               if (ep_item_poll(epi, &pt))
                        return POLLIN | POLLRDNORM;
                else {
                        /*
@@ -1203,7 +1214,7 @@ static noinline void ep_destroy_wakeup_source(struct epitem *epi)
 {
        struct wakeup_source *ws = ep_wakeup_source(epi);
 
-       rcu_assign_pointer(epi->ws, NULL);
+       RCU_INIT_POINTER(epi->ws, NULL);
 
        /*
         * wait for ep_pm_stay_awake_rcu to finish, synchronize_rcu is
@@ -1252,7 +1263,6 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
        /* Initialize the poll table using the queue callback */
        epq.epi = epi;
        init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);
-       epq.pt._key = event->events;
 
        /*
         * Attach the item to the poll hooks and get current event bits.
@@ -1261,7 +1271,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
         * this operation completes, the poll callback can start hitting
         * the new item.
         */
-       revents = tfile->f_op->poll(tfile, &epq.pt);
+       revents = ep_item_poll(epi, &epq.pt);
 
        /*
         * We have to check if something went wrong during the poll wait queue
@@ -1361,7 +1371,6 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
         * f_op->poll() call and the new event set registering.
         */
        epi->event.events = event->events; /* need barrier below */
-       pt._key = event->events;
        epi->event.data = event->data; /* protected by mtx */
        if (epi->event.events & EPOLLWAKEUP) {
                if (!ep_has_wakeup_source(epi))
@@ -1394,7 +1403,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->ffd.file->f_op->poll(epi->ffd.file, &pt);
+       revents = ep_item_poll(epi, &pt);
 
        /*
         * If the item is "hot" and it is not registered inside the ready
@@ -1462,9 +1471,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
 
                list_del_init(&epi->rdllink);
 
-               pt._key = epi->event.events;
-               revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
-                       epi->event.events;
+               revents = ep_item_poll(epi, &pt);
 
                /*
                 * If the event mask intersect the caller-requested one,
@@ -1992,6 +1999,52 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
        return error;
 }
 
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
+                       struct epoll_event __user *, events,
+                       int, maxevents, int, timeout,
+                       const compat_sigset_t __user *, sigmask,
+                       compat_size_t, sigsetsize)
+{
+       long err;
+       compat_sigset_t csigmask;
+       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(compat_sigset_t))
+                       return -EINVAL;
+               if (copy_from_user(&csigmask, sigmask, sizeof(csigmask)))
+                       return -EFAULT;
+               sigset_from_compat(&ksigmask, &csigmask);
+               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+       }
+
+       err = 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 (err == -EINTR) {
+                       memcpy(&current->saved_sigmask, &sigsaved,
+                              sizeof(sigsaved));
+                       set_restore_sigmask();
+               } else
+                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+       }
+
+       return err;
+}
+#endif
+
 static int __init eventpoll_init(void)
 {
        struct sysinfo si;