Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a074e96 authored by Christoph Hellwig's avatar Christoph Hellwig
Browse files

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: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
parent a3c0d439
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -396,3 +396,4 @@
382	i386	pkey_free		sys_pkey_free			__ia32_sys_pkey_free
383	i386	statx			sys_statx			__ia32_sys_statx
384	i386	arch_prctl		sys_arch_prctl			__ia32_compat_sys_arch_prctl
385	i386	io_pgetevents		sys_io_pgetevents		__ia32_compat_sys_io_pgetevents
+1 −0
Original line number Diff line number Diff line
@@ -341,6 +341,7 @@
330	common	pkey_alloc		__x64_sys_pkey_alloc
331	common	pkey_free		__x64_sys_pkey_free
332	common	statx			__x64_sys_statx
333	common	io_pgetevents		__x64_sys_io_pgetevents

#
# x32-specific system call numbers start at 512 to avoid cache impact
+104 −10
Original line number Diff line number Diff line
@@ -1303,10 +1303,6 @@ static long read_events(struct kioctx *ctx, long min_nr, long nr,
		wait_event_interruptible_hrtimeout(ctx->wait,
				aio_read_events(ctx, min_nr, nr, event, &ret),
				until);

	if (!ret && signal_pending(current))
		ret = -EINTR;

	return ret;
}

@@ -1921,13 +1917,60 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
		struct timespec __user *, timeout)
{
	struct timespec64	ts;
	int			ret;

	if (timeout && unlikely(get_timespec64(&ts, timeout)))
		return -EFAULT;

	ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
	if (!ret && signal_pending(current))
		ret = -EINTR;
	return ret;
}

SYSCALL_DEFINE6(io_pgetevents,
		aio_context_t, ctx_id,
		long, min_nr,
		long, nr,
		struct io_event __user *, events,
		struct timespec __user *, timeout,
		const struct __aio_sigset __user *, usig)
{
	struct __aio_sigset	ksig = { NULL, };
	sigset_t		ksigmask, sigsaved;
	struct timespec64	ts;
	int ret;

	if (timeout) {
		if (unlikely(get_timespec64(&ts, timeout)))
	if (timeout && unlikely(get_timespec64(&ts, timeout)))
		return -EFAULT;

	if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
		return -EFAULT;

	if (ksig.sigmask) {
		if (ksig.sigsetsize != sizeof(sigset_t))
			return -EINVAL;
		if (copy_from_user(&ksigmask, ksig.sigmask, sizeof(ksigmask)))
			return -EFAULT;
		sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
	}

	return do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
	ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
	if (signal_pending(current)) {
		if (ksig.sigmask) {
			current->saved_sigmask = sigsaved;
			set_restore_sigmask();
		}

		if (!ret)
			ret = -ERESTARTNOHAND;
	} else {
		if (ksig.sigmask)
			sigprocmask(SIG_SETMASK, &sigsaved, NULL);
	}

	return ret;
}

#ifdef CONFIG_COMPAT
@@ -1938,13 +1981,64 @@ COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id,
		       struct compat_timespec __user *, timeout)
{
	struct timespec64 t;
	int ret;

	if (timeout) {
		if (compat_get_timespec64(&t, timeout))
	if (timeout && compat_get_timespec64(&t, timeout))
		return -EFAULT;

	ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
	if (!ret && signal_pending(current))
		ret = -EINTR;
	return ret;
}

	return do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);

struct __compat_aio_sigset {
	compat_sigset_t __user	*sigmask;
	compat_size_t		sigsetsize;
};

COMPAT_SYSCALL_DEFINE6(io_pgetevents,
		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,
		const struct __compat_aio_sigset __user *, usig)
{
	struct __compat_aio_sigset ksig = { NULL, };
	sigset_t ksigmask, sigsaved;
	struct timespec64 t;
	int ret;

	if (timeout && compat_get_timespec64(&t, timeout))
		return -EFAULT;

	if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
		return -EFAULT;

	if (ksig.sigmask) {
		if (ksig.sigsetsize != sizeof(compat_sigset_t))
			return -EINVAL;
		if (get_compat_sigset(&ksigmask, ksig.sigmask))
			return -EFAULT;
		sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
	}

	ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
	if (signal_pending(current)) {
		if (ksig.sigmask) {
			current->saved_sigmask = sigsaved;
			set_restore_sigmask();
		}
		if (!ret)
			ret = -ERESTARTNOHAND;
	} else {
		if (ksig.sigmask)
			sigprocmask(SIG_SETMASK, &sigsaved, NULL);
	}

	return ret;
}
#endif
+7 −0
Original line number Diff line number Diff line
@@ -330,6 +330,7 @@ extern int put_compat_rusage(const struct rusage *,
			     struct compat_rusage __user *);

struct compat_siginfo;
struct __compat_aio_sigset;

struct compat_dirent {
	u32		d_ino;
@@ -553,6 +554,12 @@ asmlinkage long compat_sys_io_getevents(compat_aio_context_t ctx_id,
					compat_long_t nr,
					struct io_event __user *events,
					struct compat_timespec __user *timeout);
asmlinkage long compat_sys_io_pgetevents(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,
					const struct __compat_aio_sigset __user *usig);

/* fs/cookies.c */
asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t);
+6 −0
Original line number Diff line number Diff line
@@ -290,6 +290,12 @@ asmlinkage long sys_io_getevents(aio_context_t ctx_id,
				long nr,
				struct io_event __user *events,
				struct timespec __user *timeout);
asmlinkage long sys_io_pgetevents(aio_context_t ctx_id,
				long min_nr,
				long nr,
				struct io_event __user *events,
				struct timespec __user *timeout,
				const struct __aio_sigset *sig);

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