This is the io_getevents equivalent of ppoll/pselect and allows to properly mix signals and aio completions (especially with IOCB_CMD_POLL) and atomically executes the following sequence: sigset_t origmask; pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); ret = io_getevents(ctx, min_nr, nr, events, timeout); pthread_sigmask(SIG_SETMASK, &origmask, NULL); Note that unlike many other signal related calls we do not pass a sigmask size, as that would get us to 7 arguments, which aren't easily supported by the syscall infrastructure. It seems a lot less painful to just add a new syscall variant in the unlikely case we're going to increase the sigset size.
Unified · Split
| @@ -396,3 +396,4 @@ · 395 unmodified lines | ||
| 396 | 396 | 382 i386 pkey_free sys_pkey_free __ia32_sys_pkey_free |
| 397 | 397 | 383 i386 statx sys_statx __ia32_sys_statx |
| 398 | 398 | 384 i386 arch_prctl sys_arch_prctl __ia32_compat_sys_arch_prctl |
| 399 | +385 i386 io_pgetevents sys_io_pgetevents __ia32_compat_sys_io_pgetevents | |
| @@ -341,6 +341,7 @@ · 340 unmodified lines | ||
| 341 | 341 | 330 common pkey_alloc __x64_sys_pkey_alloc |
| 342 | 342 | 331 common pkey_free __x64_sys_pkey_free |
| 343 | 343 | 332 common statx __x64_sys_statx |
| 344 | +333 common io_pgetevents __x64_sys_io_pgetevents | |
| 344 | 345 | |
| 345 | 346 | # |
| 346 | 347 | # x32-specific system call numbers start at 512 to avoid cache impact |
| @@ -1303,10 +1303,6 @@ static long read_events(struct kioctx *ctx, long min_nr, long nr, · 1302 unmodified lines | ||
| 1303 | 1303 | wait_event_interruptible_hrtimeout(ctx->wait, |
| 1304 | 1304 | aio_read_events(ctx, min_nr, nr, event, &ret), |
| 1305 | 1305 | until); |
| 1306 | − | |
| 1307 | − if (!ret && signal_pending(current)) | |
| 1308 | − ret = -EINTR; | |
| 1309 | − | |
| 1310 | 1306 | return ret; |
| 1311 | 1307 | } |
| 1312 | 1308 | |
| @@ -1921,13 +1917,60 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id, · 608 unmodified lines | ||
| 1921 | 1917 | struct timespec __user *, timeout) |
| 1922 | 1918 | { |
| 1923 | 1919 | struct timespec64 ts; |
| 1920 | + int ret; | |
| 1921 | + | |
| 1922 | + if (timeout && unlikely(get_timespec64(&ts, timeout))) | |
| 1923 | + return -EFAULT; | |
| 1924 | + | |
| 1925 | + ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL); | |
| 1926 | + if (!ret && signal_pending(current)) | |
| 1927 | + ret = -EINTR; | |
| 1928 | + return ret; | |
| 1929 | +} | |
| 1924 | 1930 | |
| 1925 | − if (timeout) { | |
| 1926 | − if (unlikely(get_timespec64(&ts, timeout))) | |
| 1931 | +SYSCALL_DEFINE6(io_pgetevents, | |
| 1932 | + aio_context_t, ctx_id, | |
| 1933 | + long, min_nr, | |
| 1934 | + long, nr, | |
| 1935 | + struct io_event __user *, events, | |
| 1936 | + struct timespec __user *, timeout, | |
| 1937 | + const struct __aio_sigset __user *, usig) | |
| 1938 | +{ | |
| 1939 | + struct __aio_sigset ksig = { NULL, }; | |
| 1940 | + sigset_t ksigmask, sigsaved; | |
| 1941 | + struct timespec64 ts; | |
| 1942 | + int ret; | |
| 1943 | + | |
| 1944 | + if (timeout && unlikely(get_timespec64(&ts, timeout))) | |
| 1945 | + return -EFAULT; | |
| 1946 | + | |
| 1947 | + if (usig && copy_from_user(&ksig, usig, sizeof(ksig))) | |
| 1948 | + return -EFAULT; | |
| 1949 | + | |
| 1950 | + if (ksig.sigmask) { | |
| 1951 | + if (ksig.sigsetsize != sizeof(sigset_t)) | |
| 1952 | + return -EINVAL; | |
| 1953 | + if (copy_from_user(&ksigmask, ksig.sigmask, sizeof(ksigmask))) | |
| 1927 | 1954 | return -EFAULT; |
| 1955 | + sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | |
| 1956 | + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | |
| 1957 | + } | |
| 1958 | + | |
| 1959 | + ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL); | |
| 1960 | + if (signal_pending(current)) { | |
| 1961 | + if (ksig.sigmask) { | |
| 1962 | + current->saved_sigmask = sigsaved; | |
| 1963 | + set_restore_sigmask(); | |
| 1964 | + } | |
| 1965 | + | |
| 1966 | + if (!ret) | |
| 1967 | + ret = -ERESTARTNOHAND; | |
| 1968 | + } else { | |
| 1969 | + if (ksig.sigmask) | |
| 1970 | + sigprocmask(SIG_SETMASK, &sigsaved, NULL); | |
| 1928 | 1971 | } |
| 1929 | 1972 | |
| 1930 | − return do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL); | |
| 1973 | + return ret; | |
| 1931 | 1974 | } |
| 1932 | 1975 | |
| 1933 | 1976 | #ifdef CONFIG_COMPAT |
| @@ -1938,13 +1981,64 @@ COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id, · 4 unmodified lines | ||
| 1938 | 1981 | struct compat_timespec __user *, timeout) |
| 1939 | 1982 | { |
| 1940 | 1983 | struct timespec64 t; |
| 1984 | + int ret; | |
| 1985 | + | |
| 1986 | + if (timeout && compat_get_timespec64(&t, timeout)) | |
| 1987 | + return -EFAULT; | |
| 1988 | + | |
| 1989 | + ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL); | |
| 1990 | + if (!ret && signal_pending(current)) | |
| 1991 | + ret = -EINTR; | |
| 1992 | + return ret; | |
| 1993 | +} | |
| 1994 | + | |
| 1941 | 1995 | |
| 1942 | − if (timeout) { | |
| 1943 | − if (compat_get_timespec64(&t, timeout)) | |
| 1996 | +struct __compat_aio_sigset { | |
| 1997 | + compat_sigset_t __user *sigmask; | |
| 1998 | + compat_size_t sigsetsize; | |
| 1999 | +}; | |
| 2000 | + | |
| 2001 | +COMPAT_SYSCALL_DEFINE6(io_pgetevents, | |
| 2002 | + compat_aio_context_t, ctx_id, | |
| 2003 | + compat_long_t, min_nr, | |
| 2004 | + compat_long_t, nr, | |
| 2005 | + struct io_event __user *, events, | |
| 2006 | + struct compat_timespec __user *, timeout, | |
| 2007 | + const struct __compat_aio_sigset __user *, usig) | |
| 2008 | +{ | |
| 2009 | + struct __compat_aio_sigset ksig = { NULL, }; | |
| 2010 | + sigset_t ksigmask, sigsaved; | |
| 2011 | + struct timespec64 t; | |
| 2012 | + int ret; | |
| 2013 | + | |
| 2014 | + if (timeout && compat_get_timespec64(&t, timeout)) | |
| 2015 | + return -EFAULT; | |
| 2016 | + | |
| 2017 | + if (usig && copy_from_user(&ksig, usig, sizeof(ksig))) | |
| 2018 | + return -EFAULT; | |
| 2019 | + | |
| 2020 | + if (ksig.sigmask) { | |
| 2021 | + if (ksig.sigsetsize != sizeof(compat_sigset_t)) | |
| 2022 | + return -EINVAL; | |
| 2023 | + if (get_compat_sigset(&ksigmask, ksig.sigmask)) | |
| 1944 | 2024 | return -EFAULT; |
| 2025 | + sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | |
| 2026 | + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | |
| 2027 | + } | |
| 1945 | 2028 | |
| 2029 | + ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL); | |
| 2030 | + if (signal_pending(current)) { | |
| 2031 | + if (ksig.sigmask) { | |
| 2032 | + current->saved_sigmask = sigsaved; | |
| 2033 | + set_restore_sigmask(); | |
| 2034 | + } | |
| 2035 | + if (!ret) | |
| 2036 | + ret = -ERESTARTNOHAND; | |
| 2037 | + } else { | |
| 2038 | + if (ksig.sigmask) | |
| 2039 | + sigprocmask(SIG_SETMASK, &sigsaved, NULL); | |
| 1946 | 2040 | } |
| 1947 | 2041 | |
| 1948 | − return do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL); | |
| 2042 | + return ret; | |
| 1949 | 2043 | } |
| 1950 | 2044 | #endif |
| @@ -330,6 +330,7 @@ extern int put_compat_rusage(const struct rusage *, · 329 unmodified lines | ||
| 330 | 330 | struct compat_rusage __user *); |
| 331 | 331 | |
| 332 | 332 | struct compat_siginfo; |
| 333 | +struct __compat_aio_sigset; | |
| 333 | 334 | |
| 334 | 335 | struct compat_dirent { |
| 335 | 336 | u32 d_ino; |
| @@ -553,6 +554,12 @@ asmlinkage long compat_sys_io_getevents(compat_aio_context_t ctx_id, · 217 unmodified lines | ||
| 553 | 554 | compat_long_t nr, |
| 554 | 555 | struct io_event __user *events, |
| 555 | 556 | struct compat_timespec __user *timeout); |
| 557 | +asmlinkage long compat_sys_io_pgetevents(compat_aio_context_t ctx_id, | |
| 558 | + compat_long_t min_nr, | |
| 559 | + compat_long_t nr, | |
| 560 | + struct io_event __user *events, | |
| 561 | + struct compat_timespec __user *timeout, | |
| 562 | + const struct __compat_aio_sigset __user *usig); | |
| 556 | 563 | |
| 557 | 564 | /* fs/cookies.c */ |
| 558 | 565 | asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t); |
| @@ -290,6 +290,12 @@ asmlinkage long sys_io_getevents(aio_context_t ctx_id, · 289 unmodified lines | ||
| 290 | 290 | long nr, |
| 291 | 291 | struct io_event __user *events, |
| 292 | 292 | struct timespec __user *timeout); |
| 293 | +asmlinkage long sys_io_pgetevents(aio_context_t ctx_id, | |
| 294 | + long min_nr, | |
| 295 | + long nr, | |
| 296 | + struct io_event __user *events, | |
| 297 | + struct timespec __user *timeout, | |
| 298 | + const struct __aio_sigset *sig); | |
| 293 | 299 | |
| 294 | 300 | /* fs/xattr.c */ |
| 295 | 301 | asmlinkage long sys_setxattr(const char __user *path, const char __user *name, |
| @@ -732,9 +732,11 @@ __SYSCALL(__NR_pkey_alloc, sys_pkey_alloc) · 731 unmodified lines | ||
| 732 | 732 | __SYSCALL(__NR_pkey_free, sys_pkey_free) |
| 733 | 733 | #define __NR_statx 291 |
| 734 | 734 | __SYSCALL(__NR_statx, sys_statx) |
| 735 | +#define __NR_io_pgetevents 292 | |
| 736 | +__SC_COMP(__NR_io_pgetevents, sys_io_pgetevents, compat_sys_io_pgetevents) | |
| 735 | 737 | |
| 736 | 738 | #undef __NR_syscalls |
| 737 | −#define __NR_syscalls 292 | |
| 739 | +#define __NR_syscalls 293 | |
| 738 | 740 | |
| 739 | 741 | /* |
| 740 | 742 | * 32 bit systems traditionally used different |
| @@ -29,6 +29,7 @@ · 28 unmodified lines | ||
| 29 | 29 | |
| 30 | 30 | #include <linux/types.h> |
| 31 | 31 | #include <linux/fs.h> |
| 32 | +#include <linux/signal.h> | |
| 32 | 33 | #include <asm/byteorder.h> |
| 33 | 34 | |
| 34 | 35 | typedef __kernel_ulong_t aio_context_t; |
| @@ -108,5 +109,10 @@ struct iocb { · 73 unmodified lines | ||
| 108 | 109 | #undef IFBIG |
| 109 | 110 | #undef IFLITTLE |
| 110 | 111 | |
| 112 | +struct __aio_sigset { | |
| 113 | + sigset_t __user *sigmask; | |
| 114 | + size_t sigsetsize; | |
| 115 | +}; | |
| 116 | + | |
| 111 | 117 | #endif /* __LINUX__AIO_ABI_H */ |
| 112 | 118 | |
| @@ -43,7 +43,9 @@ COND_SYSCALL(io_submit); · 42 unmodified lines | ||
| 43 | 43 | COND_SYSCALL_COMPAT(io_submit); |
| 44 | 44 | COND_SYSCALL(io_cancel); |
| 45 | 45 | COND_SYSCALL(io_getevents); |
| 46 | +COND_SYSCALL(io_pgetevents); | |
| 46 | 47 | COND_SYSCALL_COMPAT(io_getevents); |
| 48 | +COND_SYSCALL_COMPAT(io_pgetevents); | |
| 47 | 49 | |
| 48 | 50 | /* fs/xattr.c */ |
| 49 | 51 | |