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 | 382 i386 pkey_free sys_pkey_free __ia32_sys_pkey_free | 396 | 382 i386 pkey_free sys_pkey_free __ia32_sys_pkey_free |
| 397 | 383 i386 statx sys_statx __ia32_sys_statx | 397 | 383 i386 statx sys_statx __ia32_sys_statx |
| 398 | 384 i386 arch_prctl sys_arch_prctl __ia32_compat_sys_arch_prctl | 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 | 330 common pkey_alloc __x64_sys_pkey_alloc | 341 | 330 common pkey_alloc __x64_sys_pkey_alloc |
| 342 | 331 common pkey_free __x64_sys_pkey_free | 342 | 331 common pkey_free __x64_sys_pkey_free |
| 343 | 332 common statx __x64_sys_statx | 343 | 332 common statx __x64_sys_statx |
| 344 | 333 common io_pgetevents __x64_sys_io_pgetevents | ||
| 344 | 345 | ||
| 345 | # | 346 | # |
| 346 | # x32-specific system call numbers start at 512 to avoid cache impact | 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 | wait_event_interruptible_hrtimeout(ctx->wait, | 1303 | wait_event_interruptible_hrtimeout(ctx->wait, |
| 1304 | aio_read_events(ctx, min_nr, nr, event, &ret), | 1304 | aio_read_events(ctx, min_nr, nr, event, &ret), |
| 1305 | until); | 1305 | until); |
| 1306 | |||
| 1307 | if (!ret && signal_pending(current)) | ||
| 1308 | ret = -EINTR; | ||
| 1309 | |||
| 1310 | return ret; | 1306 | return ret; |
| 1311 | } | 1307 | } |
| 1312 | 1308 | ||
| @@ -1921,13 +1917,60 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id, · 608 unmodified lines | |||
| 1921 | struct timespec __user *, timeout) | 1917 | struct timespec __user *, timeout) |
| 1922 | { | 1918 | { |
| 1923 | struct timespec64 ts; | 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) { | 1931 | SYSCALL_DEFINE6(io_pgetevents, |
| 1926 | if (unlikely(get_timespec64(&ts, timeout))) | 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 | return -EFAULT; | 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 | #ifdef CONFIG_COMPAT | 1976 | #ifdef CONFIG_COMPAT |
| @@ -1938,13 +1981,64 @@ COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id, · 4 unmodified lines | |||
| 1938 | struct compat_timespec __user *, timeout) | 1981 | struct compat_timespec __user *, timeout) |
| 1939 | { | 1982 | { |
| 1940 | struct timespec64 t; | 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) { | 1996 | struct __compat_aio_sigset { |
| 1943 | if (compat_get_timespec64(&t, timeout)) | 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 | return -EFAULT; | 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 | #endif | 2044 | #endif |
| @@ -330,6 +330,7 @@ extern int put_compat_rusage(const struct rusage *, · 329 unmodified lines | |||
| 330 | struct compat_rusage __user *); | 330 | struct compat_rusage __user *); |
| 331 | 331 | ||
| 332 | struct compat_siginfo; | 332 | struct compat_siginfo; |
| 333 | struct __compat_aio_sigset; | ||
| 333 | 334 | ||
| 334 | struct compat_dirent { | 335 | struct compat_dirent { |
| 335 | u32 d_ino; | 336 | u32 d_ino; |
| @@ -553,6 +554,12 @@ asmlinkage long compat_sys_io_getevents(compat_aio_context_t ctx_id, · 217 unmodified lines | |||
| 553 | compat_long_t nr, | 554 | compat_long_t nr, |
| 554 | struct io_event __user *events, | 555 | struct io_event __user *events, |
| 555 | struct compat_timespec __user *timeout); | 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 | /* fs/cookies.c */ | 564 | /* fs/cookies.c */ |
| 558 | asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t); | 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 | long nr, | 290 | long nr, |
| 291 | struct io_event __user *events, | 291 | struct io_event __user *events, |
| 292 | struct timespec __user *timeout); | 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 | /* fs/xattr.c */ | 300 | /* fs/xattr.c */ |
| 295 | asmlinkage long sys_setxattr(const char __user *path, const char __user *name, | 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 | __SYSCALL(__NR_pkey_free, sys_pkey_free) | 732 | __SYSCALL(__NR_pkey_free, sys_pkey_free) |
| 733 | #define __NR_statx 291 | 733 | #define __NR_statx 291 |
| 734 | __SYSCALL(__NR_statx, sys_statx) | 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 | #undef __NR_syscalls | 738 | #undef __NR_syscalls |
| 737 | #define __NR_syscalls 292 | 739 | #define __NR_syscalls 293 |
| 738 | 740 | ||
| 739 | /* | 741 | /* |
| 740 | * 32 bit systems traditionally used different | 742 | * 32 bit systems traditionally used different |
| @@ -29,6 +29,7 @@ · 28 unmodified lines | |||
| 29 | 29 | ||
| 30 | #include <linux/types.h> | 30 | #include <linux/types.h> |
| 31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
| 32 | #include <linux/signal.h> | ||
| 32 | #include <asm/byteorder.h> | 33 | #include <asm/byteorder.h> |
| 33 | 34 | ||
| 34 | typedef __kernel_ulong_t aio_context_t; | 35 | typedef __kernel_ulong_t aio_context_t; |
| @@ -108,5 +109,10 @@ struct iocb { · 73 unmodified lines | |||
| 108 | #undef IFBIG | 109 | #undef IFBIG |
| 109 | #undef IFLITTLE | 110 | #undef IFLITTLE |
| 110 | 111 | ||
| 112 | struct __aio_sigset { | ||
| 113 | sigset_t __user *sigmask; | ||
| 114 | size_t sigsetsize; | ||
| 115 | }; | ||
| 116 | |||
| 111 | #endif /* __LINUX__AIO_ABI_H */ | 117 | #endif /* __LINUX__AIO_ABI_H */ |
| 112 | 118 | ||
| @@ -43,7 +43,9 @@ COND_SYSCALL(io_submit); · 42 unmodified lines | |||
| 43 | COND_SYSCALL_COMPAT(io_submit); | 43 | COND_SYSCALL_COMPAT(io_submit); |
| 44 | COND_SYSCALL(io_cancel); | 44 | COND_SYSCALL(io_cancel); |
| 45 | COND_SYSCALL(io_getevents); | 45 | COND_SYSCALL(io_getevents); |
| 46 | COND_SYSCALL(io_pgetevents); | ||
| 46 | COND_SYSCALL_COMPAT(io_getevents); | 47 | COND_SYSCALL_COMPAT(io_getevents); |
| 48 | COND_SYSCALL_COMPAT(io_pgetevents); | ||
| 47 | 49 | ||
| 48 | /* fs/xattr.c */ | 50 | /* fs/xattr.c */ |
| 49 | 51 | ||