diff options
Diffstat (limited to 'fs/compat.c')
| -rw-r--r-- | fs/compat.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/fs/compat.c b/fs/compat.c index 0ec70e3cee0a..040a8be38a48 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #include <linux/highmem.h> | 48 | #include <linux/highmem.h> |
| 49 | #include <linux/poll.h> | 49 | #include <linux/poll.h> |
| 50 | #include <linux/mm.h> | 50 | #include <linux/mm.h> |
| 51 | #include <linux/eventpoll.h> | ||
| 51 | 52 | ||
| 52 | #include <net/sock.h> /* siocdevprivate_ioctl */ | 53 | #include <net/sock.h> /* siocdevprivate_ioctl */ |
| 53 | 54 | ||
| @@ -2235,3 +2236,102 @@ long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2) | |||
| 2235 | return sys_ni_syscall(); | 2236 | return sys_ni_syscall(); |
| 2236 | } | 2237 | } |
| 2237 | #endif | 2238 | #endif |
| 2239 | |||
| 2240 | #ifdef CONFIG_EPOLL | ||
| 2241 | |||
| 2242 | #ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT | ||
| 2243 | asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd, | ||
| 2244 | struct compat_epoll_event __user *event) | ||
| 2245 | { | ||
| 2246 | long err = 0; | ||
| 2247 | struct compat_epoll_event user; | ||
| 2248 | struct epoll_event __user *kernel = NULL; | ||
| 2249 | |||
| 2250 | if (event) { | ||
| 2251 | if (copy_from_user(&user, event, sizeof(user))) | ||
| 2252 | return -EFAULT; | ||
| 2253 | kernel = compat_alloc_user_space(sizeof(struct epoll_event)); | ||
| 2254 | err |= __put_user(user.events, &kernel->events); | ||
| 2255 | err |= __put_user(user.data, &kernel->data); | ||
| 2256 | } | ||
| 2257 | |||
| 2258 | return err ? err : sys_epoll_ctl(epfd, op, fd, kernel); | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | |||
| 2262 | asmlinkage long compat_sys_epoll_wait(int epfd, | ||
| 2263 | struct compat_epoll_event __user *events, | ||
| 2264 | int maxevents, int timeout) | ||
| 2265 | { | ||
| 2266 | long i, ret, err = 0; | ||
| 2267 | struct epoll_event __user *kbuf; | ||
| 2268 | struct epoll_event ev; | ||
| 2269 | |||
| 2270 | if ((maxevents <= 0) || | ||
| 2271 | (maxevents > (INT_MAX / sizeof(struct epoll_event)))) | ||
| 2272 | return -EINVAL; | ||
| 2273 | kbuf = compat_alloc_user_space(sizeof(struct epoll_event) * maxevents); | ||
| 2274 | ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout); | ||
| 2275 | for (i = 0; i < ret; i++) { | ||
| 2276 | err |= __get_user(ev.events, &kbuf[i].events); | ||
| 2277 | err |= __get_user(ev.data, &kbuf[i].data); | ||
| 2278 | err |= __put_user(ev.events, &events->events); | ||
| 2279 | err |= __put_user_unaligned(ev.data, &events->data); | ||
| 2280 | events++; | ||
| 2281 | } | ||
| 2282 | |||
| 2283 | return err ? -EFAULT: ret; | ||
| 2284 | } | ||
| 2285 | #endif /* CONFIG_HAS_COMPAT_EPOLL_EVENT */ | ||
| 2286 | |||
| 2287 | #ifdef TIF_RESTORE_SIGMASK | ||
| 2288 | asmlinkage long compat_sys_epoll_pwait(int epfd, | ||
| 2289 | struct compat_epoll_event __user *events, | ||
| 2290 | int maxevents, int timeout, | ||
| 2291 | const compat_sigset_t __user *sigmask, | ||
| 2292 | compat_size_t sigsetsize) | ||
| 2293 | { | ||
| 2294 | long err; | ||
| 2295 | compat_sigset_t csigmask; | ||
| 2296 | sigset_t ksigmask, sigsaved; | ||
| 2297 | |||
| 2298 | /* | ||
| 2299 | * If the caller wants a certain signal mask to be set during the wait, | ||
| 2300 | * we apply it here. | ||
| 2301 | */ | ||
| 2302 | if (sigmask) { | ||
| 2303 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
| 2304 | return -EINVAL; | ||
| 2305 | if (copy_from_user(&csigmask, sigmask, sizeof(csigmask))) | ||
| 2306 | return -EFAULT; | ||
| 2307 | sigset_from_compat(&ksigmask, &csigmask); | ||
| 2308 | sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
| 2309 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
| 2310 | } | ||
| 2311 | |||
| 2312 | #ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT | ||
| 2313 | err = compat_sys_epoll_wait(epfd, events, maxevents, timeout); | ||
| 2314 | #else | ||
| 2315 | err = sys_epoll_wait(epfd, events, maxevents, timeout); | ||
| 2316 | #endif | ||
| 2317 | |||
| 2318 | /* | ||
| 2319 | * If we changed the signal mask, we need to restore the original one. | ||
| 2320 | * In case we've got a signal while waiting, we do not restore the | ||
| 2321 | * signal mask yet, and we allow do_signal() to deliver the signal on | ||
| 2322 | * the way back to userspace, before the signal mask is restored. | ||
| 2323 | */ | ||
| 2324 | if (sigmask) { | ||
| 2325 | if (err == -EINTR) { | ||
| 2326 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
| 2327 | sizeof(sigsaved)); | ||
| 2328 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 2329 | } else | ||
| 2330 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
| 2331 | } | ||
| 2332 | |||
| 2333 | return err; | ||
| 2334 | } | ||
| 2335 | #endif /* TIF_RESTORE_SIGMASK */ | ||
| 2336 | |||
| 2337 | #endif /* CONFIG_EPOLL */ | ||
