Skip to content

Commit 7a074e9

Browse files
author
Christoph Hellwig
committed
aio: implement io_pgetevents
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. Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Greg Kroah-Hartman <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]>
1 parent a3c0d43 commit 7a074e9

File tree

8 files changed

+130
-11
lines changed

8 files changed

+130
-11
lines changed

arch/x86/entry/syscalls/syscall_32.tbl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,4 @@
396396
382 i386 pkey_free sys_pkey_free __ia32_sys_pkey_free
397397
383 i386 statx sys_statx __ia32_sys_statx
398398
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

arch/x86/entry/syscalls/syscall_64.tbl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@
341341
330 common pkey_alloc __x64_sys_pkey_alloc
342342
331 common pkey_free __x64_sys_pkey_free
343343
332 common statx __x64_sys_statx
344+
333 common io_pgetevents __x64_sys_io_pgetevents
344345

345346
#
346347
# x32-specific system call numbers start at 512 to avoid cache impact

fs/aio.c

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,10 +1303,6 @@ static long read_events(struct kioctx *ctx, long min_nr, long nr,
13031303
wait_event_interruptible_hrtimeout(ctx->wait,
13041304
aio_read_events(ctx, min_nr, nr, event, &ret),
13051305
until);
1306-
1307-
if (!ret && signal_pending(current))
1308-
ret = -EINTR;
1309-
13101306
return ret;
13111307
}
13121308

@@ -1921,13 +1917,60 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
19211917
struct timespec __user *, timeout)
19221918
{
19231919
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+
}
19241930

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)))
19271954
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);
19281971
}
19291972

1930-
return do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
1973+
return ret;
19311974
}
19321975

19331976
#ifdef CONFIG_COMPAT
@@ -1938,13 +1981,64 @@ COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id,
19381981
struct compat_timespec __user *, timeout)
19391982
{
19401983
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+
19411995

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))
19442024
return -EFAULT;
2025+
sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
2026+
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
2027+
}
19452028

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);
19462040
}
19472041

1948-
return do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
2042+
return ret;
19492043
}
19502044
#endif

include/linux/compat.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ extern int put_compat_rusage(const struct rusage *,
330330
struct compat_rusage __user *);
331331

332332
struct compat_siginfo;
333+
struct __compat_aio_sigset;
333334

334335
struct compat_dirent {
335336
u32 d_ino;
@@ -553,6 +554,12 @@ asmlinkage long compat_sys_io_getevents(compat_aio_context_t ctx_id,
553554
compat_long_t nr,
554555
struct io_event __user *events,
555556
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);
556563

557564
/* fs/cookies.c */
558565
asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t);

include/linux/syscalls.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,12 @@ asmlinkage long sys_io_getevents(aio_context_t ctx_id,
290290
long nr,
291291
struct io_event __user *events,
292292
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);
293299

294300
/* fs/xattr.c */
295301
asmlinkage long sys_setxattr(const char __user *path, const char __user *name,

include/uapi/asm-generic/unistd.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,9 +732,11 @@ __SYSCALL(__NR_pkey_alloc, sys_pkey_alloc)
732732
__SYSCALL(__NR_pkey_free, sys_pkey_free)
733733
#define __NR_statx 291
734734
__SYSCALL(__NR_statx, sys_statx)
735+
#define __NR_io_pgetevents 292
736+
__SC_COMP(__NR_io_pgetevents, sys_io_pgetevents, compat_sys_io_pgetevents)
735737

736738
#undef __NR_syscalls
737-
#define __NR_syscalls 292
739+
#define __NR_syscalls 293
738740

739741
/*
740742
* 32 bit systems traditionally used different

include/uapi/linux/aio_abi.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include <linux/types.h>
3131
#include <linux/fs.h>
32+
#include <linux/signal.h>
3233
#include <asm/byteorder.h>
3334

3435
typedef __kernel_ulong_t aio_context_t;
@@ -108,5 +109,10 @@ struct iocb {
108109
#undef IFBIG
109110
#undef IFLITTLE
110111

112+
struct __aio_sigset {
113+
sigset_t __user *sigmask;
114+
size_t sigsetsize;
115+
};
116+
111117
#endif /* __LINUX__AIO_ABI_H */
112118

kernel/sys_ni.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ COND_SYSCALL(io_submit);
4343
COND_SYSCALL_COMPAT(io_submit);
4444
COND_SYSCALL(io_cancel);
4545
COND_SYSCALL(io_getevents);
46+
COND_SYSCALL(io_pgetevents);
4647
COND_SYSCALL_COMPAT(io_getevents);
48+
COND_SYSCALL_COMPAT(io_pgetevents);
4749

4850
/* fs/xattr.c */
4951

0 commit comments

Comments
 (0)