|
@@ -48,6 +48,7 @@
|
|
#include <linux/highmem.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/mm.h>
|
|
|
|
+#include <linux/eventpoll.h>
|
|
|
|
|
|
#include <net/sock.h> /* siocdevprivate_ioctl */
|
|
#include <net/sock.h> /* siocdevprivate_ioctl */
|
|
|
|
|
|
@@ -2235,3 +2236,102 @@ long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
|
|
return sys_ni_syscall();
|
|
return sys_ni_syscall();
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_EPOLL
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT
|
|
|
|
+asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd,
|
|
|
|
+ struct compat_epoll_event __user *event)
|
|
|
|
+{
|
|
|
|
+ long err = 0;
|
|
|
|
+ struct compat_epoll_event user;
|
|
|
|
+ struct epoll_event __user *kernel = NULL;
|
|
|
|
+
|
|
|
|
+ if (event) {
|
|
|
|
+ if (copy_from_user(&user, event, sizeof(user)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ kernel = compat_alloc_user_space(sizeof(struct epoll_event));
|
|
|
|
+ err |= __put_user(user.events, &kernel->events);
|
|
|
|
+ err |= __put_user(user.data, &kernel->data);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return err ? err : sys_epoll_ctl(epfd, op, fd, kernel);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+asmlinkage long compat_sys_epoll_wait(int epfd,
|
|
|
|
+ struct compat_epoll_event __user *events,
|
|
|
|
+ int maxevents, int timeout)
|
|
|
|
+{
|
|
|
|
+ long i, ret, err = 0;
|
|
|
|
+ struct epoll_event __user *kbuf;
|
|
|
|
+ struct epoll_event ev;
|
|
|
|
+
|
|
|
|
+ if ((maxevents <= 0) ||
|
|
|
|
+ (maxevents > (INT_MAX / sizeof(struct epoll_event))))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ kbuf = compat_alloc_user_space(sizeof(struct epoll_event) * maxevents);
|
|
|
|
+ ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout);
|
|
|
|
+ for (i = 0; i < ret; i++) {
|
|
|
|
+ err |= __get_user(ev.events, &kbuf[i].events);
|
|
|
|
+ err |= __get_user(ev.data, &kbuf[i].data);
|
|
|
|
+ err |= __put_user(ev.events, &events->events);
|
|
|
|
+ err |= __put_user_unaligned(ev.data, &events->data);
|
|
|
|
+ events++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return err ? -EFAULT: ret;
|
|
|
|
+}
|
|
|
|
+#endif /* CONFIG_HAS_COMPAT_EPOLL_EVENT */
|
|
|
|
+
|
|
|
|
+#ifdef TIF_RESTORE_SIGMASK
|
|
|
|
+asmlinkage long compat_sys_epoll_pwait(int epfd,
|
|
|
|
+ struct compat_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);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT
|
|
|
|
+ err = compat_sys_epoll_wait(epfd, events, maxevents, timeout);
|
|
|
|
+#else
|
|
|
|
+ err = sys_epoll_wait(epfd, events, maxevents, timeout);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * 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(¤t->saved_sigmask, &sigsaved,
|
|
|
|
+ sizeof(sigsaved));
|
|
|
|
+ set_thread_flag(TIF_RESTORE_SIGMASK);
|
|
|
|
+ } else
|
|
|
|
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+#endif /* TIF_RESTORE_SIGMASK */
|
|
|
|
+
|
|
|
|
+#endif /* CONFIG_EPOLL */
|