Signed-off-by: Arnd Bergmann arnd@arndb.de --- fs/aio.c | 54 +++++++++++++++++++++++++++++++++++------------- fs/compat.c | 24 --------------------- include/linux/syscalls.h | 2 +- 3 files changed, 41 insertions(+), 39 deletions(-)
diff --git a/fs/aio.c b/fs/aio.c index 480440f4701f..321212b9f4b6 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1250,20 +1250,9 @@ static bool aio_read_events(struct kioctx *ctx, long min_nr, long nr,
static long read_events(struct kioctx *ctx, long min_nr, long nr, struct io_event __user *event, - struct timespec __user *timeout) + ktime_t until) { - ktime_t until = { .tv64 = KTIME_MAX }; long ret = 0; - - if (timeout) { - struct timespec ts; - - if (unlikely(copy_from_user(&ts, timeout, sizeof(ts)))) - return -EFAULT; - - until = timespec_to_ktime(ts); - } - /* * Note that aio_read_events() is being called as the conditional - i.e. * we're calling it after prepare_to_wait() has set task state to @@ -1718,15 +1707,52 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id, long, min_nr, long, nr, struct io_event __user *, events, - struct timespec __user *, timeout) + struct __kernel_timespec __user *, timeout) +{ + struct kioctx *ioctx = lookup_ioctx(ctx_id); + ktime_t until = { .tv64 = KTIME_MAX }; + struct timespec64 ts; + long ret = -EINVAL; + + if (likely(ioctx)) { + if (timeout) { + if (unlikely(get_timespec64(&ts, timeout))) + return -EFAULT; + + until = timespec64_to_ktime(ts); + } + + if (likely(min_nr <= nr && min_nr >= 0)) + ret = read_events(ioctx, min_nr, nr, events, until); + percpu_ref_put(&ioctx->users); + } + return ret; +} + +#ifdef CONFIG_COMPAT_TIME +COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id, + compat_long_t, min_nr, + compat_long_t, nr, + struct io_event __user *, events, + struct compat_timespec __user *, timeout) { struct kioctx *ioctx = lookup_ioctx(ctx_id); + ktime_t until = { .tv64 = KTIME_MAX }; + struct timespec64 ts; long ret = -EINVAL;
if (likely(ioctx)) { + if (timeout) { + if (unlikely(compat_get_timespec64(&ts, timeout))) + return -EFAULT; + + until = timespec64_to_ktime(ts); + } + if (likely(min_nr <= nr && min_nr >= 0)) - ret = read_events(ioctx, min_nr, nr, events, timeout); + ret = read_events(ioctx, min_nr, nr, events, until); percpu_ref_put(&ioctx->users); } return ret; } +#endif diff --git a/fs/compat.c b/fs/compat.c index 78ffecce6379..b9e55d5de311 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -508,31 +508,7 @@ COMPAT_SYSCALL_DEFINE2(io_setup, unsigned, nr_reqs, u32 __user *, ctx32p) ret = put_user((u32) ctx64, ctx32p); return ret; } -#endif - -#ifdef CONFIG_COMPAT_TIME -COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id, - compat_long_t, min_nr, - compat_long_t, nr, - struct io_event __user *, events, - struct compat_timespec __user *, timeout) -{ - struct timespec t; - struct timespec __user *ut = NULL; - - if (timeout) { - if (compat_get_timespec(&t, timeout)) - return -EFAULT;
- ut = compat_alloc_user_space(sizeof(*ut)); - if (copy_to_user(ut, &t, sizeof(t)) ) - return -EFAULT; - } - return sys_io_getevents(ctx_id, min_nr, nr, events, ut); -} -#endif - -#ifdef CONFIG_COMPAT /* A write operation does a read from user space and vice versa */ #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 855897ee0c6d..4a8e7294ed2c 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -500,7 +500,7 @@ asmlinkage long sys_io_getevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event __user *events, - struct timespec __user *timeout); + struct __kernel_timespec __user *timeout); asmlinkage long sys_io_submit(aio_context_t, long, struct iocb __user * __user *); asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb,