Reduce the amount of code and shrink a .text section a bit: [linux]$ ./scripts/bloat-o-meter -t /tmp/vmlinux.o.{old,new} add/remove: 1/0 grow/shrink: 0/4 up/down: 284/-691 (-407) Function old new delta do_sys_ppoll - 284 +284 __x64_sys_ppoll 214 42 -172 __ia32_sys_ppoll 213 40 -173 __ia32_compat_sys_ppoll_time64 213 40 -173 __ia32_compat_sys_ppoll_time32 213 40 -173 Total: Before=13357557, After=13357150, chg -0.00% The downside is that "tsp" and "sigmask" parameters gets (void *), but it seems worth losing static type checking if there is only one line in syscall definition. Other way could be to add compat parameters in do_sys_ppoll(), but that trashes 2 more registers.. Signed-off-by: Dmitry Safonov <dima@xxxxxxxxxx> --- fs/select.c | 94 ++++++++++++++++++----------------------------------- 1 file changed, 32 insertions(+), 62 deletions(-) diff --git a/fs/select.c b/fs/select.c index 458f2a944318..262300e58370 100644 --- a/fs/select.c +++ b/fs/select.c @@ -1056,54 +1056,58 @@ SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds, return ret; } -SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, - struct __kernel_timespec __user *, tsp, const sigset_t __user *, sigmask, - size_t, sigsetsize) +static int do_sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, + void __user *tsp, const void __user *sigmask, + size_t sigsetsize, enum poll_time_type pt_type) { struct timespec64 ts, end_time, *to = NULL; int ret; if (tsp) { - if (get_timespec64(&ts, tsp)) - return -EFAULT; + switch (pt_type) { + case PT_TIMESPEC: + if (get_timespec64(&ts, tsp)) + return -EFAULT; + break; + case PT_OLD_TIMESPEC: + if (get_old_timespec32(&ts, tsp)) + return -EFAULT; + break; + default: + WARN_ON_ONCE(1); + return -ENOSYS; + } to = &end_time; if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) return -EINVAL; } - ret = set_user_sigmask(sigmask, sigsetsize); + if (!in_compat_syscall()) + ret = set_user_sigmask(sigmask, sigsetsize); + else + ret = set_compat_user_sigmask(sigmask, sigsetsize); + if (ret) return ret; ret = do_sys_poll(ufds, nfds, to); - return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret); + return poll_select_finish(&end_time, tsp, pt_type, ret); } -#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT) +SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, + struct __kernel_timespec __user *, tsp, const sigset_t __user *, sigmask, + size_t, sigsetsize) +{ + return do_sys_ppoll(ufds, nfds, tsp, sigmask, sigsetsize, PT_TIMESPEC); +} +#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT) SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds, struct old_timespec32 __user *, tsp, const sigset_t __user *, sigmask, size_t, sigsetsize) { - struct timespec64 ts, end_time, *to = NULL; - int ret; - - if (tsp) { - if (get_old_timespec32(&ts, tsp)) - return -EFAULT; - - to = &end_time; - if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) - return -EINVAL; - } - - ret = set_user_sigmask(sigmask, sigsetsize); - if (ret) - return ret; - - ret = do_sys_poll(ufds, nfds, to); - return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret); + return do_sys_ppoll(ufds, nfds, tsp, sigmask, sigsetsize, PT_OLD_TIMESPEC); } #endif @@ -1352,24 +1356,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds, struct old_timespec32 __user *, tsp, const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) { - struct timespec64 ts, end_time, *to = NULL; - int ret; - - if (tsp) { - if (get_old_timespec32(&ts, tsp)) - return -EFAULT; - - to = &end_time; - if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) - return -EINVAL; - } - - ret = set_compat_user_sigmask(sigmask, sigsetsize); - if (ret) - return ret; - - ret = do_sys_poll(ufds, nfds, to); - return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret); + return do_sys_ppoll(ufds, nfds, tsp, sigmask, sigsetsize, PT_OLD_TIMESPEC); } #endif @@ -1378,24 +1365,7 @@ COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds, unsigned int, nfds, struct __kernel_timespec __user *, tsp, const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) { - struct timespec64 ts, end_time, *to = NULL; - int ret; - - if (tsp) { - if (get_timespec64(&ts, tsp)) - return -EFAULT; - - to = &end_time; - if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) - return -EINVAL; - } - - ret = set_compat_user_sigmask(sigmask, sigsetsize); - if (ret) - return ret; - - ret = do_sys_poll(ufds, nfds, to); - return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret); + return do_sys_ppoll(ufds, nfds, tsp, sigmask, sigsetsize, PT_TIMESPEC); } #endif -- 2.23.0