[PATCH] Add epoll compat_ code to fs/compat.c

IA64 and ARM-OABI are currently using their own version of epoll compat_
code.

An architecture needs epoll_event translation if alignof(u64) in 32 bit
mode is different from alignof(u64) in 64 bit mode. If an architecture
needs epoll_event translation, it must define struct compat_epoll_event in
asm/compat.h and set CONFIG_HAVE_COMPAT_EPOLL_EVENT and use
compat_sys_epoll_ctl and compat_sys_epoll_wait.

All 64 bit architecture should use compat_sys_epoll_pwait.

[sfr: restructure and move to fs/compat.c, remove MIPS version
of compat_sys_epoll_pwait, use __put_user_unaligned]

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: "Luck, Tony" <tony.luck@intel.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Davide Libenzi and committed by Linus Torvalds f6dfb4fd b40df574

+119 -46
-46
arch/mips/kernel/linux32.c
··· 564 564 return do_fork(clone_flags, newsp, &regs, 0, 565 565 parent_tidptr, child_tidptr); 566 566 } 567 - 568 - /* 569 - * Implement the event wait interface for the eventpoll file. It is the kernel 570 - * part of the user space epoll_pwait(2). 571 - */ 572 - asmlinkage long compat_sys_epoll_pwait(int epfd, 573 - struct epoll_event __user *events, int maxevents, int timeout, 574 - const compat_sigset_t __user *sigmask, size_t sigsetsize) 575 - { 576 - int error; 577 - sigset_t ksigmask, sigsaved; 578 - 579 - /* 580 - * If the caller wants a certain signal mask to be set during the wait, 581 - * we apply it here. 582 - */ 583 - if (sigmask) { 584 - if (sigsetsize != sizeof(sigset_t)) 585 - return -EINVAL; 586 - if (!access_ok(VERIFY_READ, sigmask, sizeof(ksigmask))) 587 - return -EFAULT; 588 - if (__copy_conv_sigset_from_user(&ksigmask, sigmask)) 589 - return -EFAULT; 590 - sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); 591 - sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); 592 - } 593 - 594 - error = sys_epoll_wait(epfd, events, maxevents, timeout); 595 - 596 - /* 597 - * If we changed the signal mask, we need to restore the original one. 598 - * In case we've got a signal while waiting, we do not restore the 599 - * signal mask yet, and we allow do_signal() to deliver the signal on 600 - * the way back to userspace, before the signal mask is restored. 601 - */ 602 - if (sigmask) { 603 - if (error == -EINTR) { 604 - memcpy(&current->saved_sigmask, &sigsaved, 605 - sizeof(sigsaved)); 606 - set_thread_flag(TIF_RESTORE_SIGMASK); 607 - } else 608 - sigprocmask(SIG_SETMASK, &sigsaved, NULL); 609 - } 610 - 611 - return error; 612 - }
+100
fs/compat.c
··· 48 48 #include <linux/highmem.h> 49 49 #include <linux/poll.h> 50 50 #include <linux/mm.h> 51 + #include <linux/eventpoll.h> 51 52 52 53 #include <net/sock.h> /* siocdevprivate_ioctl */ 53 54 ··· 2236 2235 return sys_ni_syscall(); 2237 2236 } 2238 2237 #endif 2238 + 2239 + #ifdef CONFIG_EPOLL 2240 + 2241 + #ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT 2242 + asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd, 2243 + struct compat_epoll_event __user *event) 2244 + { 2245 + long err = 0; 2246 + struct compat_epoll_event user; 2247 + struct epoll_event __user *kernel = NULL; 2248 + 2249 + if (event) { 2250 + if (copy_from_user(&user, event, sizeof(user))) 2251 + return -EFAULT; 2252 + kernel = compat_alloc_user_space(sizeof(struct epoll_event)); 2253 + err |= __put_user(user.events, &kernel->events); 2254 + err |= __put_user(user.data, &kernel->data); 2255 + } 2256 + 2257 + return err ? err : sys_epoll_ctl(epfd, op, fd, kernel); 2258 + } 2259 + 2260 + 2261 + asmlinkage long compat_sys_epoll_wait(int epfd, 2262 + struct compat_epoll_event __user *events, 2263 + int maxevents, int timeout) 2264 + { 2265 + long i, ret, err = 0; 2266 + struct epoll_event __user *kbuf; 2267 + struct epoll_event ev; 2268 + 2269 + if ((maxevents <= 0) || 2270 + (maxevents > (INT_MAX / sizeof(struct epoll_event)))) 2271 + return -EINVAL; 2272 + kbuf = compat_alloc_user_space(sizeof(struct epoll_event) * maxevents); 2273 + ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout); 2274 + for (i = 0; i < ret; i++) { 2275 + err |= __get_user(ev.events, &kbuf[i].events); 2276 + err |= __get_user(ev.data, &kbuf[i].data); 2277 + err |= __put_user(ev.events, &events->events); 2278 + err |= __put_user_unaligned(ev.data, &events->data); 2279 + events++; 2280 + } 2281 + 2282 + return err ? -EFAULT: ret; 2283 + } 2284 + #endif /* CONFIG_HAS_COMPAT_EPOLL_EVENT */ 2285 + 2286 + #ifdef TIF_RESTORE_SIGMASK 2287 + asmlinkage long compat_sys_epoll_pwait(int epfd, 2288 + struct compat_epoll_event __user *events, 2289 + int maxevents, int timeout, 2290 + const compat_sigset_t __user *sigmask, 2291 + compat_size_t sigsetsize) 2292 + { 2293 + long err; 2294 + compat_sigset_t csigmask; 2295 + sigset_t ksigmask, sigsaved; 2296 + 2297 + /* 2298 + * If the caller wants a certain signal mask to be set during the wait, 2299 + * we apply it here. 2300 + */ 2301 + if (sigmask) { 2302 + if (sigsetsize != sizeof(compat_sigset_t)) 2303 + return -EINVAL; 2304 + if (copy_from_user(&csigmask, sigmask, sizeof(csigmask))) 2305 + return -EFAULT; 2306 + sigset_from_compat(&ksigmask, &csigmask); 2307 + sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); 2308 + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); 2309 + } 2310 + 2311 + #ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT 2312 + err = compat_sys_epoll_wait(epfd, events, maxevents, timeout); 2313 + #else 2314 + err = sys_epoll_wait(epfd, events, maxevents, timeout); 2315 + #endif 2316 + 2317 + /* 2318 + * If we changed the signal mask, we need to restore the original one. 2319 + * In case we've got a signal while waiting, we do not restore the 2320 + * signal mask yet, and we allow do_signal() to deliver the signal on 2321 + * the way back to userspace, before the signal mask is restored. 2322 + */ 2323 + if (sigmask) { 2324 + if (err == -EINTR) { 2325 + memcpy(&current->saved_sigmask, &sigsaved, 2326 + sizeof(sigsaved)); 2327 + set_thread_flag(TIF_RESTORE_SIGMASK); 2328 + } else 2329 + sigprocmask(SIG_SETMASK, &sigsaved, NULL); 2330 + } 2331 + 2332 + return err; 2333 + } 2334 + #endif /* TIF_RESTORE_SIGMASK */ 2335 + 2336 + #endif /* CONFIG_EPOLL */
+19
include/linux/compat.h
··· 234 234 compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, 235 235 const compat_ulong_t __user *new_nodes); 236 236 237 + /* 238 + * epoll (fs/eventpoll.c) compat bits follow ... 239 + */ 240 + #ifndef CONFIG_HAS_COMPAT_EPOLL_EVENT 241 + struct epoll_event; 242 + #define compat_epoll_event epoll_event 243 + #else 244 + asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd, 245 + struct compat_epoll_event __user *event); 246 + asmlinkage long compat_sys_epoll_wait(int epfd, 247 + struct compat_epoll_event __user *events, 248 + int maxevents, int timeout); 249 + #endif 250 + asmlinkage long compat_sys_epoll_pwait(int epfd, 251 + struct compat_epoll_event __user *events, 252 + int maxevents, int timeout, 253 + const compat_sigset_t __user *sigmask, 254 + compat_size_t sigsetsize); 255 + 237 256 #endif /* CONFIG_COMPAT */ 238 257 #endif /* _LINUX_COMPAT_H */