diff options
author | Davide Libenzi <davidel@xmailserver.org> | 2007-03-07 23:41:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-08 10:38:22 -0500 |
commit | f6dfb4fd7dd94429ef1d5233688aaed2a63f856b (patch) | |
tree | 81c29bfad51e187830ca059855aa285e350c9481 /fs | |
parent | b40df5743ee8aed8674edbbb77b8fd3c8c7a747f (diff) |
[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>
Diffstat (limited to 'fs')
-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 */ | ||