diff options
Diffstat (limited to 'fs/eventpoll.c')
-rw-r--r-- | fs/eventpoll.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 277cc38aeda5..deecc7294a67 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/atomic.h> | 40 | #include <linux/atomic.h> |
41 | #include <linux/proc_fs.h> | 41 | #include <linux/proc_fs.h> |
42 | #include <linux/seq_file.h> | 42 | #include <linux/seq_file.h> |
43 | #include <linux/compat.h> | ||
43 | 44 | ||
44 | /* | 45 | /* |
45 | * LOCKING: | 46 | * LOCKING: |
@@ -1998,6 +1999,52 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events, | |||
1998 | return error; | 1999 | return error; |
1999 | } | 2000 | } |
2000 | 2001 | ||
2002 | #ifdef CONFIG_COMPAT | ||
2003 | COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd, | ||
2004 | struct epoll_event __user *, events, | ||
2005 | int, maxevents, int, timeout, | ||
2006 | const compat_sigset_t __user *, sigmask, | ||
2007 | compat_size_t, sigsetsize) | ||
2008 | { | ||
2009 | long err; | ||
2010 | compat_sigset_t csigmask; | ||
2011 | sigset_t ksigmask, sigsaved; | ||
2012 | |||
2013 | /* | ||
2014 | * If the caller wants a certain signal mask to be set during the wait, | ||
2015 | * we apply it here. | ||
2016 | */ | ||
2017 | if (sigmask) { | ||
2018 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
2019 | return -EINVAL; | ||
2020 | if (copy_from_user(&csigmask, sigmask, sizeof(csigmask))) | ||
2021 | return -EFAULT; | ||
2022 | sigset_from_compat(&ksigmask, &csigmask); | ||
2023 | sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
2024 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
2025 | } | ||
2026 | |||
2027 | err = sys_epoll_wait(epfd, events, maxevents, timeout); | ||
2028 | |||
2029 | /* | ||
2030 | * If we changed the signal mask, we need to restore the original one. | ||
2031 | * In case we've got a signal while waiting, we do not restore the | ||
2032 | * signal mask yet, and we allow do_signal() to deliver the signal on | ||
2033 | * the way back to userspace, before the signal mask is restored. | ||
2034 | */ | ||
2035 | if (sigmask) { | ||
2036 | if (err == -EINTR) { | ||
2037 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
2038 | sizeof(sigsaved)); | ||
2039 | set_restore_sigmask(); | ||
2040 | } else | ||
2041 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
2042 | } | ||
2043 | |||
2044 | return err; | ||
2045 | } | ||
2046 | #endif | ||
2047 | |||
2001 | static int __init eventpoll_init(void) | 2048 | static int __init eventpoll_init(void) |
2002 | { | 2049 | { |
2003 | struct sysinfo si; | 2050 | struct sysinfo si; |