git: b1f0b08d9320 - main - linux(4): Implement timerfd_settime64 syscall.

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Wed, 04 May 2022 10:08:16 UTC
The branch main has been updated by dchagin:

URL: https://cgit.FreeBSD.org/src/commit/?id=b1f0b08d932005a574411c829422e81223df14da

commit b1f0b08d932005a574411c829422e81223df14da
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2022-05-04 10:06:50 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2022-05-04 10:06:50 +0000

    linux(4): Implement timerfd_settime64 syscall.
    
    MFC after:              2weeks
---
 sys/amd64/linux32/linux32_dummy_machdep.c |  1 -
 sys/compat/linux/linux_event.c            | 84 ++++++++++++++++++++++---------
 sys/i386/linux/linux_dummy_machdep.c      |  1 -
 3 files changed, 60 insertions(+), 26 deletions(-)

diff --git a/sys/amd64/linux32/linux32_dummy_machdep.c b/sys/amd64/linux32/linux32_dummy_machdep.c
index 7dbc3352b07d..6b264e2891f1 100644
--- a/sys/amd64/linux32/linux32_dummy_machdep.c
+++ b/sys/amd64/linux32/linux32_dummy_machdep.c
@@ -69,7 +69,6 @@ DUMMY(arch_prctl);
 /* Linux 5.0: */
 DUMMY(clock_adjtime64);
 DUMMY(timerfd_gettime64);
-DUMMY(timerfd_settime64);
 DUMMY(io_pgetevents_time64);
 DUMMY(recvmmsg_time64);
 DUMMY(mq_timedsend_time64);
diff --git a/sys/compat/linux/linux_event.c b/sys/compat/linux/linux_event.c
index 08d52cd10fc3..09c6391f88d2 100644
--- a/sys/compat/linux/linux_event.c
+++ b/sys/compat/linux/linux_event.c
@@ -932,28 +932,20 @@ out:
 	return (error);
 }
 
-int
-linux_timerfd_settime(struct thread *td, struct linux_timerfd_settime_args *args)
+static int
+linux_timerfd_settime_common(struct thread *td, int fd, int flags,
+    struct itimerspec *nts, struct itimerspec *oval)
 {
-	struct l_itimerspec lots;
-	struct itimerspec nts, ots;
 	struct timespec cts, ts;
 	struct timerfd *tfd;
 	struct timeval tv;
 	struct file *fp;
 	int error;
 
-	if ((args->flags & ~LINUX_TFD_SETTIME_FLAGS) != 0)
+	if ((flags & ~LINUX_TFD_SETTIME_FLAGS) != 0)
 		return (EINVAL);
 
-	error = copyin(args->new_value, &lots, sizeof(lots));
-	if (error != 0)
-		return (error);
-	error = linux_to_native_itimerspec(&nts, &lots);
-	if (error != 0)
-		return (error);
-
-	error = fget(td, args->fd, &cap_write_rights, &fp);
+	error = fget(td, fd, &cap_write_rights, &fp);
 	if (error != 0)
 		return (error);
 	tfd = fp->f_data;
@@ -963,17 +955,17 @@ linux_timerfd_settime(struct thread *td, struct linux_timerfd_settime_args *args
 	}
 
 	mtx_lock(&tfd->tfd_lock);
-	if (!timespecisset(&nts.it_value))
-		timespecclear(&nts.it_interval);
-	if (args->old_value != NULL)
-		linux_timerfd_curval(tfd, &ots);
+	if (!timespecisset(&nts->it_value))
+		timespecclear(&nts->it_interval);
+	if (oval != NULL)
+		linux_timerfd_curval(tfd, oval);
 
-	tfd->tfd_time = nts;
+	bcopy(nts, &tfd->tfd_time, sizeof(*nts));
 	tfd->tfd_count = 0;
-	if (timespecisset(&nts.it_value)) {
+	if (timespecisset(&nts->it_value)) {
 		linux_timerfd_clocktime(tfd, &cts);
-		ts = nts.it_value;
-		if ((args->flags & LINUX_TFD_TIMER_ABSTIME) == 0) {
+		ts = nts->it_value;
+		if ((flags & LINUX_TFD_TIMER_ABSTIME) == 0) {
 			timespecadd(&tfd->tfd_time.it_value, &cts,
 				&tfd->tfd_time.it_value);
 		} else {
@@ -989,16 +981,60 @@ linux_timerfd_settime(struct thread *td, struct linux_timerfd_settime_args *args
 	}
 	mtx_unlock(&tfd->tfd_lock);
 
-	if (args->old_value != NULL) {
+out:
+	fdrop(fp, td);
+	return (error);
+}
+
+int
+linux_timerfd_settime(struct thread *td, struct linux_timerfd_settime_args *args)
+{
+	struct l_itimerspec lots;
+	struct itimerspec nts, ots, *pots;
+	int error;
+
+	error = copyin(args->new_value, &lots, sizeof(lots));
+	if (error != 0)
+		return (error);
+	error = linux_to_native_itimerspec(&nts, &lots);
+	if (error != 0)
+		return (error);
+	pots = (args->old_value != NULL ? &ots : NULL);
+	error = linux_timerfd_settime_common(td, args->fd, args->flags,
+	    &nts, pots);
+	if (error == 0 && args->old_value != NULL) {
 		error = native_to_linux_itimerspec(&lots, &ots);
 		if (error == 0)
 			error = copyout(&lots, args->old_value, sizeof(lots));
 	}
+	return (error);
+}
 
-out:
-	fdrop(fp, td);
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+int
+linux_timerfd_settime64(struct thread *td, struct linux_timerfd_settime64_args *args)
+{
+	struct l_itimerspec64 lots;
+	struct itimerspec nts, ots, *pots;
+	int error;
+
+	error = copyin(args->new_value, &lots, sizeof(lots));
+	if (error != 0)
+		return (error);
+	error = linux_to_native_itimerspec64(&nts, &lots);
+	if (error != 0)
+		return (error);
+	pots = (args->old_value != NULL ? &ots : NULL);
+	error = linux_timerfd_settime_common(td, args->fd, args->flags,
+	    &nts, pots);
+	if (error == 0 && args->old_value != NULL) {
+		error = native_to_linux_itimerspec64(&lots, &ots);
+		if (error == 0)
+			error = copyout(&lots, args->old_value, sizeof(lots));
+	}
 	return (error);
 }
+#endif
 
 static void
 linux_timerfd_expire(void *arg)
diff --git a/sys/i386/linux/linux_dummy_machdep.c b/sys/i386/linux/linux_dummy_machdep.c
index f4280da8df16..f5852e97ddae 100644
--- a/sys/i386/linux/linux_dummy_machdep.c
+++ b/sys/i386/linux/linux_dummy_machdep.c
@@ -71,7 +71,6 @@ DUMMY(arch_prctl);
 /* Linux 5.0: */
 DUMMY(clock_adjtime64);
 DUMMY(timerfd_gettime64);
-DUMMY(timerfd_settime64);
 DUMMY(io_pgetevents_time64);
 DUMMY(recvmmsg_time64);
 DUMMY(mq_timedsend_time64);