linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess
@ 2024-04-10 22:46 Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 01/50] selftests/timers/posix_timers: Simplify error handling Thomas Gleixner
                   ` (50 more replies)
  0 siblings, 51 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

This is the second attempt of cleaning this up. Version 1 can be found
here:

   https://lore.kernel.org/lkml/20230606132949.068951363@linutronix.de/

Last year I reread a 15 years old comment about the SIG_IGN problem:

 "FIXME: What we really want, is to stop this timer completely and restart
  it in case the SIG_IGN is removed. This is a non trivial change which
  involves sighand locking (sigh !), which we don't want to do late in the
  release cycle.  ...  A more complex fix which solves also another related
  inconsistency is already in the pipeline."

The embarrasing part was that I put that comment in back then. So I went
back and rumaged through old notes as I completely had forgotten why our
attempts to fix this back then failed.

It turned out that the comment is about right: sighand locking and life
time issues. So I sat down with the old notes and started to wrap my head
around this again.

The problem to solve:

Posix interval timers are not rearmed automatically by the kernel for
various reasons:

   1) To prevent DoS by extremly short intervals.
   2) To avoid timer overhead when a signal is pending and has not
      yet been delivered.

This is achieved by queueing the signal at timer expiry and rearming the
timer at signal delivery to user space. This puts the rearming basically
under scheduler control and the work happens in context of the task which
asked for the signal.

There is a problem with that vs. SIG_IGN. If a signal has SIG_IGN installed
as handler the related signals are discarded. So in case of posix interval
timers this means that such a timer is never rearmed even when SIG_IGN is
replaced later with a real handler (including SIG_DFL).

To work around that the kernel self rearms those timers and throttles them
when the interval is smaller than a tick to prevent a DoS.

That just keeps timers ticking, which obviously has effects on power and
just creates work for nothing.

So ideally these timers should be stopped and rearmed when SIG_IGN is
replaced, which aligns with the regular handling of posix timers.

Sounds trivial, but isn't:

  1) Lock ordering.

     The timer lock cannot be taken with sighand lock held which is
     problematic vs. the atomicity of sigaction().

  2) Life time rules

     The timer and the sigqueue are separate entities which requires a
     lookup of the timer ID in the signal rearm code. This can be handled,
     but the separate life time rules are not necessarily robust.

  3) Finding the relevant timers

     Obviosly it is possible to walk the posix timer list under sighand
     lock and handle it from there. That can be expensive especially in the
     case that there are no affected timers as the walk would just end up
     doing nothing.

The following series is a new and this time actually working attempt to
solve this. It addresses it by:

  1) Embedding the preallocated sigqueue into struct k_itimer, which makes
     the life time rules way simpler and just needs a trivial reference
     count.

  2) Having a separate list in task::signal on which ignored timers are
     queued.

     This avoids walking a potentially large timer list for nothing on a
     SIG_IGN to handler transition.

  3) Requeueing the timers signal in the relevant signal queue so the timer
     is rearmed when the signal is actually delivered

     That turned out to be the least complicated way to address the sighand
     lock vs. timer lock ordering issue.

With that timers which have their signal ignored are not longer self
rearmed and the relevant workarounds including throttling for DoS
prevention are removed.

Aside of the SIG_IGN issues it also addresses a few inconsistencies in
posix CPU timers and the general inconsistency of signal handling
vs. disarmed, reprogrammed and deleted timers.

To actually validate the fixes the posix timer self test has been expanded
with tests which cover not only the simple SIG IGN case but also more
complex scenarios which have never been handled correctly by the current
self rearming work around.

The series is based on:

    git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/urgent

and is also available from git:

    git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git timers/posix

Changes vs. V1:

    - Dropped the timer distribution check changes as that has been handled
      upstream differently (it's in timers/urgent and soon in Linus tree)

    - Split up patch 9 for the sake of easier review - Frederic

    - Addressed the review comments from Frederic

    - Picked up Reviewed-by tags where appropriate

Thanks,

	tglx
---
 arch/x86/kernel/signal_32.c                   |    2 
 arch/x86/kernel/signal_64.c                   |    2 
 drivers/power/supply/charger-manager.c        |    3 
 fs/proc/base.c                                |   10 
 fs/signalfd.c                                 |    4 
 fs/timerfd.c                                  |    4 
 include/linux/alarmtimer.h                    |   10 
 include/linux/posix-timers.h                  |   69 ++-
 include/linux/sched/signal.h                  |   11 
 include/uapi/asm-generic/siginfo.h            |    2 
 init/init_task.c                              |    5 
 kernel/fork.c                                 |    3 
 kernel/signal.c                               |  486 +++++++++++++---------
 kernel/time/alarmtimer.c                      |   82 ---
 kernel/time/itimer.c                          |   22 -
 kernel/time/posix-cpu-timers.c                |  231 ++++------
 kernel/time/posix-timers.c                    |  276 ++++++-------
 kernel/time/posix-timers.h                    |    9 
 net/netfilter/xt_IDLETIMER.c                  |    4 
 tools/testing/selftests/timers/posix_timers.c |  550 +++++++++++++++++++++-----
 20 files changed, 1092 insertions(+), 693 deletions(-)

^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 01/50] selftests/timers/posix_timers: Simplify error handling
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-12  7:35   ` Anna-Maria Behnsen
  2024-04-10 22:46 ` [patch V2 02/50] selftests/timers/posix_timers: Add SIG_IGN test Thomas Gleixner
                   ` (49 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

No point in returning to main() on fatal errors. Just exit right away.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 tools/testing/selftests/timers/posix_timers.c |  151 ++++++++------------------
 1 file changed, 52 insertions(+), 99 deletions(-)

--- a/tools/testing/selftests/timers/posix_timers.c
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -10,6 +10,7 @@
 #include <sys/time.h>
 #include <stdio.h>
 #include <signal.h>
+#include <string.h>
 #include <unistd.h>
 #include <time.h>
 #include <pthread.h>
@@ -19,6 +20,20 @@
 #define DELAY 2
 #define USECS_PER_SEC 1000000
 
+static void __fatal_error(const char *test, const char *name, const char *what)
+{
+	char buf[64];
+
+	strerror_r(errno, buf, sizeof(buf));
+
+	if (name && strlen(name))
+		ksft_exit_fail_msg("%s %s %s %s\n", test, name, what, buf);
+	else
+		ksft_exit_fail_msg("%s %s %s\n", test, what, buf);
+}
+
+#define fatal_error(name, what)	__fatal_error(__func__, name, what)
+
 static volatile int done;
 
 /* Busy loop in userspace to elapse ITIMER_VIRTUAL */
@@ -74,24 +89,13 @@ static int check_diff(struct timeval sta
 	return 0;
 }
 
-static int check_itimer(int which)
+static void check_itimer(int which, const char *name)
 {
-	const char *name;
-	int err;
 	struct timeval start, end;
 	struct itimerval val = {
 		.it_value.tv_sec = DELAY,
 	};
 
-	if (which == ITIMER_VIRTUAL)
-		name = "ITIMER_VIRTUAL";
-	else if (which == ITIMER_PROF)
-		name = "ITIMER_PROF";
-	else if (which == ITIMER_REAL)
-		name = "ITIMER_REAL";
-	else
-		return -1;
-
 	done = 0;
 
 	if (which == ITIMER_VIRTUAL)
@@ -101,17 +105,11 @@ static int check_itimer(int which)
 	else if (which == ITIMER_REAL)
 		signal(SIGALRM, sig_handler);
 
-	err = gettimeofday(&start, NULL);
-	if (err < 0) {
-		ksft_perror("Can't call gettimeofday()");
-		return -1;
-	}
+	if (gettimeofday(&start, NULL) < 0)
+		fatal_error(name, "gettimeofday()");
 
-	err = setitimer(which, &val, NULL);
-	if (err < 0) {
-		ksft_perror("Can't set timer");
-		return -1;
-	}
+	if (setitimer(which, &val, NULL) < 0)
+		fatal_error(name, "setitimer()");
 
 	if (which == ITIMER_VIRTUAL)
 		user_loop();
@@ -120,68 +118,41 @@ static int check_itimer(int which)
 	else if (which == ITIMER_REAL)
 		idle_loop();
 
-	err = gettimeofday(&end, NULL);
-	if (err < 0) {
-		ksft_perror("Can't call gettimeofday()");
-		return -1;
-	}
+	if (gettimeofday(&end, NULL) < 0)
+		fatal_error(name, "gettimeofday()");
 
 	ksft_test_result(check_diff(start, end) == 0, "%s\n", name);
-
-	return 0;
 }
 
-static int check_timer_create(int which)
+static void check_timer_create(int which, const char *name)
 {
-	const char *type;
-	int err;
-	timer_t id;
 	struct timeval start, end;
 	struct itimerspec val = {
 		.it_value.tv_sec = DELAY,
 	};
-
-	if (which == CLOCK_THREAD_CPUTIME_ID) {
-		type = "thread";
-	} else if (which == CLOCK_PROCESS_CPUTIME_ID) {
-		type = "process";
-	} else {
-		ksft_print_msg("Unknown timer_create() type %d\n", which);
-		return -1;
-	}
+	timer_t id;
 
 	done = 0;
-	err = timer_create(which, NULL, &id);
-	if (err < 0) {
-		ksft_perror("Can't create timer");
-		return -1;
-	}
-	signal(SIGALRM, sig_handler);
 
-	err = gettimeofday(&start, NULL);
-	if (err < 0) {
-		ksft_perror("Can't call gettimeofday()");
-		return -1;
-	}
+	if (timer_create(which, NULL, &id) < 0)
+		fatal_error(name, "timer_create()");
 
-	err = timer_settime(id, 0, &val, NULL);
-	if (err < 0) {
-		ksft_perror("Can't set timer");
-		return -1;
-	}
+	if (signal(SIGALRM, sig_handler) == SIG_ERR)
+		fatal_error(name, "signal()");
+
+	if (gettimeofday(&start, NULL) < 0)
+		fatal_error(name, "gettimeofday()");
+
+	if (timer_settime(id, 0, &val, NULL) < 0)
+		fatal_error(name, "timer_settime()");
 
 	user_loop();
 
-	err = gettimeofday(&end, NULL);
-	if (err < 0) {
-		ksft_perror("Can't call gettimeofday()");
-		return -1;
-	}
+	if (gettimeofday(&end, NULL) < 0)
+		fatal_error(name, "gettimeofday()");
 
 	ksft_test_result(check_diff(start, end) == 0,
-			 "timer_create() per %s\n", type);
-
-	return 0;
+			 "timer_create() per %s\n", name);
 }
 
 static pthread_t ctd_thread;
@@ -209,15 +180,14 @@ static void *ctd_thread_func(void *arg)
 
 	ctd_count = 100;
 	if (timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &id))
-		return "Can't create timer\n";
+		fatal_error(NULL, "timer_create()");
 	if (timer_settime(id, 0, &val, NULL))
-		return "Can't set timer\n";
-
+		fatal_error(NULL, "timer_settime()");
 	while (ctd_count > 0 && !ctd_failed)
 		;
 
 	if (timer_delete(id))
-		return "Can't delete timer\n";
+		fatal_error(NULL, "timer_delete()");
 
 	return NULL;
 }
@@ -225,19 +195,16 @@ static void *ctd_thread_func(void *arg)
 /*
  * Test that only the running thread receives the timer signal.
  */
-static int check_timer_distribution(void)
+static void check_timer_distribution(void)
 {
-	const char *errmsg;
-
-	signal(SIGALRM, ctd_sighandler);
+	if (signal(SIGALRM, ctd_sighandler) == SIG_ERR)
+		fatal_error(NULL, "signal()");
 
-	errmsg = "Can't create thread\n";
 	if (pthread_create(&ctd_thread, NULL, ctd_thread_func, NULL))
-		goto err;
+		fatal_error(NULL, "pthread_create()");
 
-	errmsg = "Can't join thread\n";
-	if (pthread_join(ctd_thread, (void **)&errmsg) || errmsg)
-		goto err;
+	if (pthread_join(ctd_thread, NULL))
+		fatal_error(NULL, "pthread_join()");
 
 	if (!ctd_failed)
 		ksft_test_result_pass("check signal distribution\n");
@@ -245,10 +212,6 @@ static int check_timer_distribution(void
 		ksft_test_result_fail("check signal distribution\n");
 	else
 		ksft_test_result_skip("check signal distribution (old kernel)\n");
-	return 0;
-err:
-	ksft_print_msg(errmsg);
-	return -1;
 }
 
 int main(int argc, char **argv)
@@ -259,17 +222,10 @@ int main(int argc, char **argv)
 	ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");
 	ksft_print_msg("based timers if other threads run on the CPU...\n");
 
-	if (check_itimer(ITIMER_VIRTUAL) < 0)
-		return ksft_exit_fail();
-
-	if (check_itimer(ITIMER_PROF) < 0)
-		return ksft_exit_fail();
-
-	if (check_itimer(ITIMER_REAL) < 0)
-		return ksft_exit_fail();
-
-	if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
-		return ksft_exit_fail();
+	check_itimer(ITIMER_VIRTUAL, "ITIMER_VIRTUAL");
+	check_itimer(ITIMER_PROF, "ITIMER_PROF");
+	check_itimer(ITIMER_REAL, "ITIMER_REAL");
+	check_timer_create(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
 
 	/*
 	 * It's unfortunately hard to reliably test a timer expiration
@@ -280,11 +236,8 @@ int main(int argc, char **argv)
 	 * to ensure true parallelism. So test only one thread until we
 	 * find a better solution.
 	 */
-	if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
-		return ksft_exit_fail();
-
-	if (check_timer_distribution() < 0)
-		return ksft_exit_fail();
+	check_timer_create(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
+	check_timer_distribution();
 
 	ksft_finished();
 }


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 02/50] selftests/timers/posix_timers: Add SIG_IGN test
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 01/50] selftests/timers/posix_timers: Simplify error handling Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 03/50] selftests/timers/posix_timers: Validate signal rules Thomas Gleixner
                   ` (48 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Add a test case to validate correct behaviour vs. SIG_IGN.

The posix specification states:

  "Setting a signal action to SIG_IGN for a signal that is pending shall
   cause the pending signal to be discarded, whether or not it is blocked."

The kernel implements this in the signal handling code, but due to the way
how posix timers are handling SIG_IGN for periodic timers, the behaviour
after installing a real handler again is inconsistent and suprising.

The following sequence is expected to deliver a signal:

  install_handler(SIG);
  block_signal(SIG);
  timer_create(...);	 <- Should send SIG
  timer_settime(value=100ms, interval=100ms);
  sleep(1);		 <- Timer expires and queues signal, timer is not rearmed
  			    as that should happen in the signal delivery path
  ignore_signal(SIG);	 <- Discards queued signal
  install_handler(SIG);  <- Restore handler, should rearm but does not
  sleep(1);
  unblock_signal(SIG);	 <- Should deliver one signal with overrun count
  			    set in siginfo

This fails because nothing rearms the timer when the signal handler is
restored. Add a test for this case which fails until the signal and posix
timer code is fixed.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 tools/testing/selftests/timers/posix_timers.c |  127 +++++++++++++++++++++++++-
 1 file changed, 125 insertions(+), 2 deletions(-)

--- a/tools/testing/selftests/timers/posix_timers.c
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -6,8 +6,9 @@
  *
  * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
  */
-
+#define _GNU_SOURCE
 #include <sys/time.h>
+#include <sys/types.h>
 #include <stdio.h>
 #include <signal.h>
 #include <string.h>
@@ -214,10 +215,129 @@ static void check_timer_distribution(voi
 		ksft_test_result_skip("check signal distribution (old kernel)\n");
 }
 
+struct tmrsig {
+	int	signals;
+	int	overruns;
+};
+
+static void siginfo_handler(int sig, siginfo_t *si, void *uc)
+{
+	struct tmrsig *tsig = si ? si->si_ptr : NULL;
+
+	if (tsig) {
+		tsig->signals++;
+		tsig->overruns += si->si_overrun;
+	}
+}
+
+static void *ignore_thread(void *arg)
+{
+	unsigned int *tid = arg;
+	sigset_t set;
+
+	sigemptyset(&set);
+	sigaddset(&set, SIGUSR1);
+	if (sigprocmask(SIG_BLOCK, &set, NULL))
+		fatal_error(NULL, "sigprocmask(SIG_BLOCK)");
+
+	*tid = gettid();
+	sleep(100);
+
+	if (sigprocmask(SIG_UNBLOCK, &set, NULL))
+		fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");
+	return NULL;
+}
+
+static void check_sig_ign(int thread)
+{
+	struct tmrsig tsig = { };
+	struct itimerspec its;
+	unsigned int tid = 0;
+	struct sigaction sa;
+	struct sigevent sev;
+	pthread_t pthread;
+	timer_t timerid;
+	sigset_t set;
+
+	if (thread) {
+		if (pthread_create(&pthread, NULL, ignore_thread, &tid))
+			fatal_error(NULL, "pthread_create()");
+		sleep(1);
+	}
+
+	sa.sa_flags = SA_SIGINFO;
+	sa.sa_sigaction = siginfo_handler;
+	sigemptyset(&sa.sa_mask);
+	if (sigaction(SIGUSR1, &sa, NULL))
+		fatal_error(NULL, "sigaction()");
+
+	/* Block the signal */
+	sigemptyset(&set);
+	sigaddset(&set, SIGUSR1);
+	if (sigprocmask(SIG_BLOCK, &set, NULL))
+		fatal_error(NULL, "sigprocmask(SIG_BLOCK)");
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL;
+	sev.sigev_signo = SIGUSR1;
+	sev.sigev_value.sival_ptr = &tsig;
+	if (thread) {
+		sev.sigev_notify = SIGEV_THREAD_ID;
+		sev._sigev_un._tid = tid;
+	}
+
+	if (timer_create(CLOCK_MONOTONIC, &sev, &timerid))
+		fatal_error(NULL, "timer_create()");
+
+	/* Start the timer to expire in 100ms and 100ms intervals */
+	its.it_value.tv_sec = 0;
+	its.it_value.tv_nsec = 100000000;
+	its.it_interval.tv_sec = 0;
+	its.it_interval.tv_nsec = 100000000;
+	timer_settime(timerid, 0, &its, NULL);
+
+	sleep(1);
+
+	/* Set the signal to be ignored */
+	if (signal(SIGUSR1, SIG_IGN) == SIG_ERR)
+		fatal_error(NULL, "signal(SIG_IGN)");
+
+	sleep(1);
+
+	if (thread) {
+		/* Stop the thread first. No signal should be delivered to it */
+		if (pthread_cancel(pthread))
+			fatal_error(NULL, "pthread_cancel()");
+		if (pthread_join(pthread, NULL))
+			fatal_error(NULL, "pthread_join()");
+	}
+
+	/* Restore the handler */
+	if (sigaction(SIGUSR1, &sa, NULL))
+		fatal_error(NULL, "sigaction()");
+
+	sleep(1);
+
+	/* Unblock it, which should deliver the signal in the !thread case*/
+	if (sigprocmask(SIG_UNBLOCK, &set, NULL))
+		fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");
+
+	if (timer_delete(timerid))
+		fatal_error(NULL, "timer_delete()");
+
+	if (!thread) {
+		ksft_test_result(tsig.signals == 1 && tsig.overruns == 29,
+				 "check_sig_ign SIGEV_SIGNAL\n");
+	} else {
+		ksft_test_result(tsig.signals == 0 && tsig.overruns == 0,
+				 "check_sig_ign SIGEV_THREAD_ID\n");
+	}
+}
+
 int main(int argc, char **argv)
 {
 	ksft_print_header();
-	ksft_set_plan(6);
+	ksft_set_plan(8);
 
 	ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");
 	ksft_print_msg("based timers if other threads run on the CPU...\n");
@@ -239,5 +359,8 @@ int main(int argc, char **argv)
 	check_timer_create(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
 	check_timer_distribution();
 
+	check_sig_ign(0);
+	check_sig_ign(1);
+
 	ksft_finished();
 }


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 03/50] selftests/timers/posix_timers: Validate signal rules
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 01/50] selftests/timers/posix_timers: Simplify error handling Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 02/50] selftests/timers/posix_timers: Add SIG_IGN test Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 04/50] selftests/timers/posix-timers: Validate SIGEV_NONE Thomas Gleixner
                   ` (47 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Add a test case to validate correct behaviour vs. timer reprogramming and
deletion.

The handling of queued signals in case of timer reprogramming or deletion
is inconsistent at best.

POSIX does not really specify the behaviour for that:

 - "The effect of disarming or resetting a timer with pending expiration
   notifications is unspecified."

 - "The disposition of pending signals for the deleted timer is
    unspecified."

In both cases it is reasonable to expect that pending signals are
discarded. Especially in the reprogramming case it does not make sense to
account for previous overruns or to deliver a signal for a timer which
has been disarmed.

Add tests to validate that no unexpected signals are delivered. They fail
for now until the signal and posix timer code is updated.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 tools/testing/selftests/timers/posix_timers.c |  108 +++++++++++++++++++++++++-
 1 file changed, 107 insertions(+), 1 deletion(-)

--- a/tools/testing/selftests/timers/posix_timers.c
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -334,10 +334,114 @@ static void check_sig_ign(int thread)
 	}
 }
 
+static void check_rearm(void)
+{
+	struct tmrsig tsig = { };
+	struct itimerspec its;
+	struct sigaction sa;
+	struct sigevent sev;
+	timer_t timerid;
+	sigset_t set;
+
+	sa.sa_flags = SA_SIGINFO;
+	sa.sa_sigaction = siginfo_handler;
+	sigemptyset(&sa.sa_mask);
+	if (sigaction(SIGUSR1, &sa, NULL))
+		fatal_error(NULL, "sigaction()");
+
+	/* Block the signal */
+	sigemptyset(&set);
+	sigaddset(&set, SIGUSR1);
+	if (sigprocmask(SIG_BLOCK, &set, NULL))
+		fatal_error(NULL, "sigprocmask(SIG_BLOCK)");
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL;
+	sev.sigev_signo = SIGUSR1;
+	sev.sigev_value.sival_ptr = &tsig;
+	if (timer_create(CLOCK_MONOTONIC, &sev, &timerid))
+		fatal_error(NULL, "timer_create()");
+
+	/* Start the timer to expire in 100ms and 100ms intervals */
+	its.it_value.tv_sec = 0;
+	its.it_value.tv_nsec = 100000000;
+	its.it_interval.tv_sec = 0;
+	its.it_interval.tv_nsec = 100000000;
+	if (timer_settime(timerid, 0, &its, NULL))
+		fatal_error(NULL, "timer_settime()");
+
+	sleep(1);
+
+	/* Reprogram the timer to single shot */
+	its.it_value.tv_sec = 10;
+	its.it_value.tv_nsec = 0;
+	its.it_interval.tv_sec = 0;
+	its.it_interval.tv_nsec = 0;
+	if (timer_settime(timerid, 0, &its, NULL))
+		fatal_error(NULL, "timer_settime()");
+
+	/* Unblock it, which should not deliver a signal */
+	if (sigprocmask(SIG_UNBLOCK, &set, NULL))
+		fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");
+
+	if (timer_delete(timerid))
+		fatal_error(NULL, "timer_delete()");
+
+	ksft_test_result(!tsig.signals, "check_rearm\n");
+}
+
+static void check_delete(void)
+{
+	struct tmrsig tsig = { };
+	struct itimerspec its;
+	struct sigaction sa;
+	struct sigevent sev;
+	timer_t timerid;
+	sigset_t set;
+
+	sa.sa_flags = SA_SIGINFO;
+	sa.sa_sigaction = siginfo_handler;
+	sigemptyset(&sa.sa_mask);
+	if (sigaction(SIGUSR1, &sa, NULL))
+		fatal_error(NULL, "sigaction()");
+
+	/* Block the signal */
+	sigemptyset(&set);
+	sigaddset(&set, SIGUSR1);
+	if (sigprocmask(SIG_BLOCK, &set, NULL))
+		fatal_error(NULL, "sigprocmask(SIG_BLOCK)");
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL;
+	sev.sigev_signo = SIGUSR1;
+	sev.sigev_value.sival_ptr = &tsig;
+	if (timer_create(CLOCK_MONOTONIC, &sev, &timerid))
+		fatal_error(NULL, "timer_create()");
+
+	/* Start the timer to expire in 100ms and 100ms intervals */
+	its.it_value.tv_sec = 0;
+	its.it_value.tv_nsec = 100000000;
+	its.it_interval.tv_sec = 0;
+	its.it_interval.tv_nsec = 100000000;
+	if (timer_settime(timerid, 0, &its, NULL))
+		fatal_error(NULL, "timer_settime()");
+
+	sleep(1);
+
+	if (timer_delete(timerid))
+		fatal_error(NULL, "timer_delete()");
+
+	/* Unblock it, which should not deliver a signal */
+	if (sigprocmask(SIG_UNBLOCK, &set, NULL))
+		fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");
+
+	ksft_test_result(!tsig.signals, "check_delete\n");
+}
+
 int main(int argc, char **argv)
 {
 	ksft_print_header();
-	ksft_set_plan(8);
+	ksft_set_plan(10);
 
 	ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");
 	ksft_print_msg("based timers if other threads run on the CPU...\n");
@@ -361,6 +465,8 @@ int main(int argc, char **argv)
 
 	check_sig_ign(0);
 	check_sig_ign(1);
+	check_rearm();
+	check_delete();
 
 	ksft_finished();
 }


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 04/50] selftests/timers/posix-timers: Validate SIGEV_NONE
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (2 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 03/50] selftests/timers/posix_timers: Validate signal rules Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 05/50] selftests/timers/posix-timers: Validate timer_gettime() Thomas Gleixner
                   ` (46 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Posix timers with a delivery mode of SIGEV_NONE deliver no signals but the
remaining expiry time must be readable via timer_gettime() for both one
shot and interval timers.

That's implemented correctly for regular posix timers but broken for posix
CPU timers.

Add a self test so the fixes can be verified.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 tools/testing/selftests/timers/posix_timers.c |   53 +++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

--- a/tools/testing/selftests/timers/posix_timers.c
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -11,6 +11,7 @@
 #include <sys/types.h>
 #include <stdio.h>
 #include <signal.h>
+#include <stdint.h>
 #include <string.h>
 #include <unistd.h>
 #include <time.h>
@@ -20,6 +21,7 @@
 
 #define DELAY 2
 #define USECS_PER_SEC 1000000
+#define NSECS_PER_SEC 1000000000
 
 static void __fatal_error(const char *test, const char *name, const char *what)
 {
@@ -438,10 +440,57 @@ static void check_delete(void)
 	ksft_test_result(!tsig.signals, "check_delete\n");
 }
 
+static inline int64_t calcdiff_ns(struct timespec t1, struct timespec t2)
+{
+	int64_t diff;
+
+	diff = NSECS_PER_SEC * (int64_t)((int) t1.tv_sec - (int) t2.tv_sec);
+	diff += ((int) t1.tv_nsec - (int) t2.tv_nsec);
+	return diff;
+}
+
+static void check_sigev_none(int which, const char *name)
+{
+	struct timespec start, now;
+	struct itimerspec its;
+	struct sigevent sev;
+	timer_t timerid;
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_NONE;
+
+	if (timer_create(which, &sev, &timerid))
+		fatal_error(name, "timer_create()");
+
+	/* Start the timer to expire in 100ms and 100ms intervals */
+	its.it_value.tv_sec = 0;
+	its.it_value.tv_nsec = 100000000;
+	its.it_interval.tv_sec = 0;
+	its.it_interval.tv_nsec = 100000000;
+	timer_settime(timerid, 0, &its, NULL);
+
+	if (clock_gettime(which, &start))
+		fatal_error(name, "clock_gettime()");
+
+	do {
+		if (clock_gettime(which, &now))
+			fatal_error(name, "clock_gettime()");
+	} while (calcdiff_ns(now, start) < NSECS_PER_SEC);
+
+	if (timer_gettime(timerid, &its))
+		fatal_error(name, "timer_gettime()");
+
+	if (timer_delete(timerid))
+		fatal_error(name, "timer_delete()");
+
+	ksft_test_result(its.it_value.tv_sec || its.it_value.tv_nsec,
+			 "check_sigev_none %s\n", name);
+}
+
 int main(int argc, char **argv)
 {
 	ksft_print_header();
-	ksft_set_plan(10);
+	ksft_set_plan(12);
 
 	ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");
 	ksft_print_msg("based timers if other threads run on the CPU...\n");
@@ -467,6 +516,8 @@ int main(int argc, char **argv)
 	check_sig_ign(1);
 	check_rearm();
 	check_delete();
+	check_sigev_none(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
+	check_sigev_none(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
 
 	ksft_finished();
 }


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 05/50] selftests/timers/posix-timers: Validate timer_gettime()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (3 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 04/50] selftests/timers/posix-timers: Validate SIGEV_NONE Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 06/50] selftests/timers/posix-timers: Validate overrun after unblock Thomas Gleixner
                   ` (45 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

timer_gettime() must return the correct expiry time for interval timers
even when the timer is not armed, which is the case when a signal is
pending but blocked.

Works correctly for regular posix timers, but not for posix CPU timers.

Add a selftest to validate the fixes.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 tools/testing/selftests/timers/posix_timers.c |   58 +++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

--- a/tools/testing/selftests/timers/posix_timers.c
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -487,10 +487,63 @@ static void check_sigev_none(int which,
 			 "check_sigev_none %s\n", name);
 }
 
+static void check_gettime(int which, const char *name)
+{
+	struct itimerspec its, prev;
+	struct timespec start, now;
+	struct sigevent sev;
+	timer_t timerid;
+	int wraps = 0;
+	sigset_t set;
+
+	/* Block the signal */
+	sigemptyset(&set);
+	sigaddset(&set, SIGUSR1);
+	if (sigprocmask(SIG_BLOCK, &set, NULL))
+		fatal_error(name, "sigprocmask(SIG_BLOCK)");
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL;
+	sev.sigev_signo = SIGUSR1;
+
+	if (timer_create(which, &sev, &timerid))
+		fatal_error(name, "timer_create()");
+
+	/* Start the timer to expire in 100ms and 100ms intervals */
+	its.it_value.tv_sec = 0;
+	its.it_value.tv_nsec = 100000000;
+	its.it_interval.tv_sec = 0;
+	its.it_interval.tv_nsec = 100000000;
+	if (timer_settime(timerid, 0, &its, NULL))
+		fatal_error(name, "timer_settime()");
+
+	if (timer_gettime(timerid, &prev))
+		fatal_error(name, "timer_gettime()");
+
+	if (clock_gettime(which, &start))
+		fatal_error(name, "clock_gettime()");
+
+	do {
+		if (clock_gettime(which, &now))
+			fatal_error(name, "clock_gettime()");
+		if (timer_gettime(timerid, &its))
+			fatal_error(name, "timer_gettime()");
+		if (its.it_value.tv_nsec > prev.it_value.tv_nsec)
+			wraps++;
+		prev = its;
+
+	} while (calcdiff_ns(now, start) < NSECS_PER_SEC);
+
+	if (timer_delete(timerid))
+		fatal_error(name, "timer_delete()");
+
+	ksft_test_result(wraps > 1, "check_gettime %s\n", name);
+}
+
 int main(int argc, char **argv)
 {
 	ksft_print_header();
-	ksft_set_plan(12);
+	ksft_set_plan(15);
 
 	ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");
 	ksft_print_msg("based timers if other threads run on the CPU...\n");
@@ -518,6 +571,9 @@ int main(int argc, char **argv)
 	check_delete();
 	check_sigev_none(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
 	check_sigev_none(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
+	check_gettime(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
+	check_gettime(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
+	check_gettime(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
 
 	ksft_finished();
 }


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 06/50] selftests/timers/posix-timers: Validate overrun after unblock
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (4 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 05/50] selftests/timers/posix-timers: Validate timer_gettime() Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get() Thomas Gleixner
                   ` (44 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

When a timer signal is blocked and later unblocked then one signal should
be delivered with the correct number of overruns since the timer was queued.

Validate that behaviour.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 tools/testing/selftests/timers/posix_timers.c |   61 +++++++++++++++++++++++++-
 1 file changed, 60 insertions(+), 1 deletion(-)

--- a/tools/testing/selftests/timers/posix_timers.c
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -540,10 +540,66 @@ static void check_gettime(int which, con
 	ksft_test_result(wraps > 1, "check_gettime %s\n", name);
 }
 
+static void check_overrun(int which, const char *name)
+{
+	struct timespec start, now;
+	struct tmrsig tsig = { };
+	struct itimerspec its;
+	struct sigaction sa;
+	struct sigevent sev;
+	timer_t timerid;
+	sigset_t set;
+
+	sa.sa_flags = SA_SIGINFO;
+	sa.sa_sigaction = siginfo_handler;
+	sigemptyset(&sa.sa_mask);
+	if (sigaction(SIGUSR1, &sa, NULL))
+		fatal_error(name, "sigaction()");
+
+	/* Block the signal */
+	sigemptyset(&set);
+	sigaddset(&set, SIGUSR1);
+	if (sigprocmask(SIG_BLOCK, &set, NULL))
+		fatal_error(name, "sigprocmask(SIG_BLOCK)");
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL;
+	sev.sigev_signo = SIGUSR1;
+	sev.sigev_value.sival_ptr = &tsig;
+	if (timer_create(which, &sev, &timerid))
+		fatal_error(name, "timer_create()");
+
+	/* Start the timer to expire in 100ms and 100ms intervals */
+	its.it_value.tv_sec = 0;
+	its.it_value.tv_nsec = 100000000;
+	its.it_interval.tv_sec = 0;
+	its.it_interval.tv_nsec = 100000000;
+	if (timer_settime(timerid, 0, &its, NULL))
+		fatal_error(name, "timer_settime()");
+
+	if (clock_gettime(which, &start))
+		fatal_error(name, "clock_gettime()");
+
+	do {
+		if (clock_gettime(which, &now))
+			fatal_error(name, "clock_gettime()");
+	} while (calcdiff_ns(now, start) < NSECS_PER_SEC);
+
+	/* Unblock it, which should deliver a signal */
+	if (sigprocmask(SIG_UNBLOCK, &set, NULL))
+		fatal_error(name, "sigprocmask(SIG_UNBLOCK)");
+
+	if (timer_delete(timerid))
+		fatal_error(name, "timer_delete()");
+
+	ksft_test_result(tsig.signals == 1 && tsig.overruns == 9,
+			 "check_overrun %s\n", name);
+}
+
 int main(int argc, char **argv)
 {
 	ksft_print_header();
-	ksft_set_plan(15);
+	ksft_set_plan(18);
 
 	ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");
 	ksft_print_msg("based timers if other threads run on the CPU...\n");
@@ -574,6 +630,9 @@ int main(int argc, char **argv)
 	check_gettime(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
 	check_gettime(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
 	check_gettime(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
+	check_overrun(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
+	check_overrun(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
+	check_overrun(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
 
 	ksft_finished();
 }


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (5 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 06/50] selftests/timers/posix-timers: Validate overrun after unblock Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-12  7:35   ` Anna-Maria Behnsen
                     ` (3 more replies)
  2024-04-10 22:46 ` [patch V2 08/50] posix-cpu-timers: Save interval only for armed timers Thomas Gleixner
                   ` (43 subsequent siblings)
  50 siblings, 4 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

In preparation for addressing issues in the timer_get() and timer_set()
functions of posix CPU timers.

No functional change.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Split out into new patch to make review simpler - Frederic
---
 kernel/time/posix-cpu-timers.c |   51 +++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 27 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -785,33 +785,9 @@ static int posix_cpu_timer_set(struct k_
 	return ret;
 }
 
-static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp)
+static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now)
 {
-	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
-	struct cpu_timer *ctmr = &timer->it.cpu;
-	u64 now, expires = cpu_timer_getexpires(ctmr);
-	struct task_struct *p;
-
-	rcu_read_lock();
-	p = cpu_timer_task_rcu(timer);
-	if (!p)
-		goto out;
-
-	/*
-	 * Easy part: convert the reload time.
-	 */
-	itp->it_interval = ktime_to_timespec64(timer->it_interval);
-
-	if (!expires)
-		goto out;
-
-	/*
-	 * Sample the clock to take the difference with the expiry time.
-	 */
-	if (CPUCLOCK_PERTHREAD(timer->it_clock))
-		now = cpu_clock_sample(clkid, p);
-	else
-		now = cpu_clock_sample_group(clkid, p, false);
+	u64 expires = cpu_timer_getexpires(&timer->it.cpu);
 
 	if (now < expires) {
 		itp->it_value = ns_to_timespec64(expires - now);
@@ -823,7 +799,28 @@ static void posix_cpu_timer_get(struct k
 		itp->it_value.tv_nsec = 1;
 		itp->it_value.tv_sec = 0;
 	}
-out:
+}
+
+static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp)
+{
+	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
+	struct task_struct *p;
+	u64 now;
+
+	rcu_read_lock();
+	p = cpu_timer_task_rcu(timer);
+	if (p) {
+		itp->it_interval = ktime_to_timespec64(timer->it_interval);
+
+		if (cpu_timer_getexpires(&timer->it.cpu)) {
+			if (CPUCLOCK_PERTHREAD(timer->it_clock))
+				now = cpu_clock_sample(clkid, p);
+			else
+				now = cpu_clock_sample_group(clkid, p, false);
+
+			__posix_cpu_timer_get(timer, itp, now);
+		}
+	}
 	rcu_read_unlock();
 }
 


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 08/50] posix-cpu-timers: Save interval only for armed timers
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (6 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get() Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-11 14:25   ` Anna-Maria Behnsen
  2024-04-10 22:46 ` [patch V2 09/50] posix-cpu-timers: Handle interval timers correctly in timer_get() Thomas Gleixner
                   ` (42 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

There is no point to return the interval for timers which have been
disarmed.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Split out into new patch to make review simpler - Frederic
---
 kernel/time/posix-cpu-timers.c |   14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -809,17 +809,15 @@ static void posix_cpu_timer_get(struct k
 
 	rcu_read_lock();
 	p = cpu_timer_task_rcu(timer);
-	if (p) {
+	if (p && cpu_timer_getexpires(&timer->it.cpu)) {
 		itp->it_interval = ktime_to_timespec64(timer->it_interval);
 
-		if (cpu_timer_getexpires(&timer->it.cpu)) {
-			if (CPUCLOCK_PERTHREAD(timer->it_clock))
-				now = cpu_clock_sample(clkid, p);
-			else
-				now = cpu_clock_sample_group(clkid, p, false);
+		if (CPUCLOCK_PERTHREAD(timer->it_clock))
+			now = cpu_clock_sample(clkid, p);
+		else
+			now = cpu_clock_sample_group(clkid, p, false);
 
-			__posix_cpu_timer_get(timer, itp, now);
-		}
+		__posix_cpu_timer_get(timer, itp, now);
 	}
 	rcu_read_unlock();
 }


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 09/50] posix-cpu-timers: Handle interval timers correctly in timer_get()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (7 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 08/50] posix-cpu-timers: Save interval only for armed timers Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-17 22:50   ` Frederic Weisbecker
  2024-04-10 22:46 ` [patch V2 10/50] posix-cpu-timers: Handle SIGEV_NONE " Thomas Gleixner
                   ` (41 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

timer_gettime() must return the remaining time to the next expiry of a
timer or 0 if the timer is not armed and no signal pending, but posix CPU
timers fail to forward a timer which is already expired.

Add the required logic to address that.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Split out into new patch to make review simpler - Frederic
---
 kernel/time/posix-cpu-timers.c |   18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -787,8 +787,24 @@ static int posix_cpu_timer_set(struct k_
 
 static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now)
 {
-	u64 expires = cpu_timer_getexpires(&timer->it.cpu);
+	u64 expires, iv = timer->it_interval;
 
+	/*
+	 * Make sure that interval timers are moved forward for the
+	 * following cases:
+	 *  - Timers which expired, but the signal has not yet been
+	 *    delivered
+	 */
+	if (iv && (timer->it_requeue_pending & REQUEUE_PENDING))
+		expires = bump_cpu_timer(timer, now);
+	else
+		expires = cpu_timer_getexpires(&timer->it.cpu);
+
+	/*
+	 * Expired interval timers cannot have a remaining time <= 0.
+	 * The kernel has to move them forward so that the next
+	 * timer expiry is > @now.
+	 */
 	if (now < expires) {
 		itp->it_value = ns_to_timespec64(expires - now);
 	} else {


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 10/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_get()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (8 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 09/50] posix-cpu-timers: Handle interval timers correctly in timer_get() Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-12 18:40   ` Eric W. Biederman
  2024-04-10 22:46 ` [patch V2 11/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_set() Thomas Gleixner
                   ` (40 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Expired SIGEV_NONE oneshot timers must return 0 nsec for the expiry time in
timer_get(), but the posix CPU timer implementation returns 1 nsec.

Add the missing conditional.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Split out into new patch to make review simpler - Frederic
---
 kernel/time/posix-cpu-timers.c |   14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -787,15 +787,17 @@ static int posix_cpu_timer_set(struct k_
 
 static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now)
 {
+	bool sigev_none = timer->it_sigev_notify == SIGEV_NONE;
 	u64 expires, iv = timer->it_interval;
 
 	/*
 	 * Make sure that interval timers are moved forward for the
 	 * following cases:
+	 *  - SIGEV_NONE timers which are never armed
 	 *  - Timers which expired, but the signal has not yet been
 	 *    delivered
 	 */
-	if (iv && (timer->it_requeue_pending & REQUEUE_PENDING))
+	if (iv && ((timer->it_requeue_pending & REQUEUE_PENDING) || sigev_none))
 		expires = bump_cpu_timer(timer, now);
 	else
 		expires = cpu_timer_getexpires(&timer->it.cpu);
@@ -809,11 +811,13 @@ static void __posix_cpu_timer_get(struct
 		itp->it_value = ns_to_timespec64(expires - now);
 	} else {
 		/*
-		 * The timer should have expired already, but the firing
-		 * hasn't taken place yet.  Say it's just about to expire.
+		 * A single shot SIGEV_NONE timer must return 0, when it is
+		 * expired! Timers which have a real signal delivery mode
+		 * must return a remaining time greater than 0 because the
+		 * signal has not yet been delivered.
 		 */
-		itp->it_value.tv_nsec = 1;
-		itp->it_value.tv_sec = 0;
+		if (!sigev_none)
+			itp->it_value.tv_nsec = 1;
 	}
 }
 


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 11/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_set()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (9 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 10/50] posix-cpu-timers: Handle SIGEV_NONE " Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-11 15:48   ` Anna-Maria Behnsen
  2024-04-10 22:46 ` [patch V2 12/50] posix-cpu-timers: Replace old expiry retrieval in posix_cpu_timer_set() Thomas Gleixner
                   ` (39 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Expired SIGEV_NONE oneshot timers must return 0 nsec for the expiry time in
timer_get(), but the posix CPU timer implementation returns 1 nsec.

Add the missing conditional.

This will be cleaned up in a follow up patch.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Split out into new patch to make review simpler - Frederic
---
 kernel/time/posix-cpu-timers.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -706,7 +706,16 @@ static int posix_cpu_timer_set(struct k_
 				old_expires = exp - val;
 				old->it_value = ns_to_timespec64(old_expires);
 			} else {
-				old->it_value.tv_nsec = 1;
+				/*
+				 * A single shot SIGEV_NONE timer must return 0, when it is
+				 * expired! Timers which have a real signal delivery mode
+				 * must return a remaining time greater than 0 because the
+				 * signal has not yet been delivered.
+				 */
+				if (sigev_none)
+					old->it_value.tv_nsec = 0;
+				else
+					old->it_value.tv_nsec = 1;
 				old->it_value.tv_sec = 0;
 			}
 		}


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 12/50] posix-cpu-timers: Replace old expiry retrieval in posix_cpu_timer_set()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (10 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 11/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_set() Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-15 14:03   ` Anna-Maria Behnsen
  2024-04-10 22:46 ` [patch V2 13/50] posix-cpu-timers: Do not arm SIGEV_NONE timers Thomas Gleixner
                   ` (38 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Reuse the split out __posix_cpu_timer_get() function which does already the
right thing.

No functional change.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Adopted to previous changes
---
 kernel/time/posix-cpu-timers.c |   36 ++++++------------------------------
 1 file changed, 6 insertions(+), 30 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -614,6 +614,8 @@ static void cpu_timer_fire(struct k_itim
 	}
 }
 
+static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now);
+
 /*
  * Guts of sys_timer_settime for CPU timers.
  * This is called with the timer locked and interrupts disabled.
@@ -688,37 +690,11 @@ static int posix_cpu_timer_set(struct k_
 	else
 		val = cpu_clock_sample_group(clkid, p, true);
 
+	/* Retrieve the previous expiry value if requested. */
 	if (old) {
-		if (old_expires == 0) {
-			old->it_value.tv_sec = 0;
-			old->it_value.tv_nsec = 0;
-		} else {
-			/*
-			 * Update the timer in case it has overrun already.
-			 * If it has, we'll report it as having overrun and
-			 * with the next reloaded timer already ticking,
-			 * though we are swallowing that pending
-			 * notification here to install the new setting.
-			 */
-			u64 exp = bump_cpu_timer(timer, val);
-
-			if (val < exp) {
-				old_expires = exp - val;
-				old->it_value = ns_to_timespec64(old_expires);
-			} else {
-				/*
-				 * A single shot SIGEV_NONE timer must return 0, when it is
-				 * expired! Timers which have a real signal delivery mode
-				 * must return a remaining time greater than 0 because the
-				 * signal has not yet been delivered.
-				 */
-				if (sigev_none)
-					old->it_value.tv_nsec = 0;
-				else
-					old->it_value.tv_nsec = 1;
-				old->it_value.tv_sec = 0;
-			}
-		}
+		old->it_value = (struct timespec64){ };
+		if (old_expires)
+			__posix_cpu_timer_get(timer, old, val);
 	}
 
 	if (unlikely(ret)) {


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 13/50] posix-cpu-timers: Do not arm SIGEV_NONE timers
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (11 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 12/50] posix-cpu-timers: Replace old expiry retrieval in posix_cpu_timer_set() Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-15 14:03   ` Anna-Maria Behnsen
  2024-04-10 22:46 ` [patch V2 14/50] posix-cpu-timers: Use @now instead of @val for clarity Thomas Gleixner
                   ` (37 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

There is no point in arming SIGEV_NONE timers as they never deliver a
signal. timer_gettime() is handling the expiry time correctly and that's
all SIGEV_NONE timers care about.

Prevent arming them and remove the expiry handler code which just disarms
them.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Split out into new patch to make review simpler - Frederic
---
 kernel/time/posix-cpu-timers.c |   29 +++++++++++++----------------
 1 file changed, 13 insertions(+), 16 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -584,12 +584,7 @@ static void cpu_timer_fire(struct k_itim
 {
 	struct cpu_timer *ctmr = &timer->it.cpu;
 
-	if ((timer->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) {
-		/*
-		 * User don't want any signal.
-		 */
-		cpu_timer_setexpires(ctmr, 0);
-	} else if (unlikely(timer->sigq == NULL)) {
+	if (unlikely(timer->sigq == NULL)) {
 		/*
 		 * This a special case for clock_nanosleep,
 		 * not a normal timer from sys_timer_create.
@@ -625,6 +620,7 @@ static void __posix_cpu_timer_get(struct
 static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
 			       struct itimerspec64 *new, struct itimerspec64 *old)
 {
+	bool sigev_none = timer->it_sigev_notify == SIGEV_NONE;
 	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
 	u64 old_expires, new_expires, old_incr, val;
 	struct cpu_timer *ctmr = &timer->it.cpu;
@@ -688,7 +684,7 @@ static int posix_cpu_timer_set(struct k_
 	if (CPUCLOCK_PERTHREAD(timer->it_clock))
 		val = cpu_clock_sample(clkid, p);
 	else
-		val = cpu_clock_sample_group(clkid, p, true);
+		val = cpu_clock_sample_group(clkid, p, !sigev_none);
 
 	/* Retrieve the previous expiry value if requested. */
 	if (old) {
@@ -708,19 +704,20 @@ static int posix_cpu_timer_set(struct k_
 		goto out;
 	}
 
-	if (new_expires != 0 && !(timer_flags & TIMER_ABSTIME)) {
+	/* Convert relative expiry time to absolute */
+	if (new_expires && !(timer_flags & TIMER_ABSTIME))
 		new_expires += val;
-	}
+
+	/* Set the new expiry time (might be 0) */
+	cpu_timer_setexpires(ctmr, new_expires);
 
 	/*
-	 * Install the new expiry time (or zero).
-	 * For a timer with no notification action, we don't actually
-	 * arm the timer (we'll just fake it for timer_gettime).
+	 * Arm the timer if it is not disabled, the new expiry value has
+	 * not yet expired and the timer requires signal delivery.
+	 * SIGEV_NONE timers are never armed.
 	 */
-	cpu_timer_setexpires(ctmr, new_expires);
-	if (new_expires != 0 && val < new_expires) {
+	if (!sigev_none && new_expires && val < new_expires)
 		arm_timer(timer, p);
-	}
 
 	unlock_task_sighand(p, &flags);
 	/*
@@ -739,7 +736,7 @@ static int posix_cpu_timer_set(struct k_
 	timer->it_overrun_last = 0;
 	timer->it_overrun = -1;
 
-	if (val >= new_expires) {
+	if (!sigev_none && val >= new_expires) {
 		if (new_expires != 0) {
 			/*
 			 * The designated time already passed, so we notify


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 14/50] posix-cpu-timers: Use @now instead of @val for clarity
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (12 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 13/50] posix-cpu-timers: Do not arm SIGEV_NONE timers Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 15/50] posix-cpu-timers: Remove incorrect comment in posix_cpu_timer_set() Thomas Gleixner
                   ` (36 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

posix_cpu_timer_set() uses @val as variable for the current time. That's
confusing at best.

Use @now as anywhere else and rewrite the confusing comment about clock
sampling.

No functional change.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 kernel/time/posix-cpu-timers.c |   22 +++++++++-------------
 1 file changed, 9 insertions(+), 13 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -622,7 +622,7 @@ static int posix_cpu_timer_set(struct k_
 {
 	bool sigev_none = timer->it_sigev_notify == SIGEV_NONE;
 	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
-	u64 old_expires, new_expires, old_incr, val;
+	u64 old_expires, new_expires, old_incr, now;
 	struct cpu_timer *ctmr = &timer->it.cpu;
 	struct sighand_struct *sighand;
 	struct task_struct *p;
@@ -674,23 +674,19 @@ static int posix_cpu_timer_set(struct k_
 	}
 
 	/*
-	 * We need to sample the current value to convert the new
-	 * value from to relative and absolute, and to convert the
-	 * old value from absolute to relative.  To set a process
-	 * timer, we need a sample to balance the thread expiry
-	 * times (in arm_timer).  With an absolute time, we must
-	 * check if it's already passed.  In short, we need a sample.
+	 * Sample the current clock for saving the previous setting
+	 * and for rearming the timer.
 	 */
 	if (CPUCLOCK_PERTHREAD(timer->it_clock))
-		val = cpu_clock_sample(clkid, p);
+		now = cpu_clock_sample(clkid, p);
 	else
-		val = cpu_clock_sample_group(clkid, p, !sigev_none);
+		now = cpu_clock_sample_group(clkid, p, !sigev_none);
 
 	/* Retrieve the previous expiry value if requested. */
 	if (old) {
 		old->it_value = (struct timespec64){ };
 		if (old_expires)
-			__posix_cpu_timer_get(timer, old, val);
+			__posix_cpu_timer_get(timer, old, now);
 	}
 
 	if (unlikely(ret)) {
@@ -706,7 +702,7 @@ static int posix_cpu_timer_set(struct k_
 
 	/* Convert relative expiry time to absolute */
 	if (new_expires && !(timer_flags & TIMER_ABSTIME))
-		new_expires += val;
+		new_expires += now;
 
 	/* Set the new expiry time (might be 0) */
 	cpu_timer_setexpires(ctmr, new_expires);
@@ -716,7 +712,7 @@ static int posix_cpu_timer_set(struct k_
 	 * not yet expired and the timer requires signal delivery.
 	 * SIGEV_NONE timers are never armed.
 	 */
-	if (!sigev_none && new_expires && val < new_expires)
+	if (!sigev_none && new_expires && now < new_expires)
 		arm_timer(timer, p);
 
 	unlock_task_sighand(p, &flags);
@@ -736,7 +732,7 @@ static int posix_cpu_timer_set(struct k_
 	timer->it_overrun_last = 0;
 	timer->it_overrun = -1;
 
-	if (!sigev_none && val >= new_expires) {
+	if (!sigev_none && now >= new_expires) {
 		if (new_expires != 0) {
 			/*
 			 * The designated time already passed, so we notify


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 15/50] posix-cpu-timers: Remove incorrect comment in posix_cpu_timer_set()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (13 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 14/50] posix-cpu-timers: Use @now instead of @val for clarity Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 16/50] posix-cpu-timers: Simplify posix_cpu_timer_set() Thomas Gleixner
                   ` (35 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

A leftover from historical code which describes fiction.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 kernel/time/posix-cpu-timers.c |    7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -689,13 +689,8 @@ static int posix_cpu_timer_set(struct k_
 			__posix_cpu_timer_get(timer, old, now);
 	}
 
+	/* Retry if the timer expiry is running concurrently */
 	if (unlikely(ret)) {
-		/*
-		 * We are colliding with the timer actually firing.
-		 * Punt after filling in the timer's old value, and
-		 * disable this firing since we are already reporting
-		 * it as an overrun (thanks to bump_cpu_timer above).
-		 */
 		unlock_task_sighand(p, &flags);
 		goto out;
 	}


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 16/50] posix-cpu-timers: Simplify posix_cpu_timer_set()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (14 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 15/50] posix-cpu-timers: Remove incorrect comment in posix_cpu_timer_set() Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-15 15:28   ` Anna-Maria Behnsen
  2024-04-10 22:46 ` [patch V2 17/50] posix-timers: Retrieve interval in common timer_settime() code Thomas Gleixner
                   ` (34 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Avoid the late sighand lock/unlock dance when a timer is not armed to
enforce reevaluation of the timer base so that the process wide CPU timer
sampling can be disabled.

Do it right at the point where the arming decision is made which already
has sighand locked.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/time/posix-cpu-timers.c |   44 +++++++++++++++--------------------------
 1 file changed, 17 insertions(+), 27 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -705,10 +705,16 @@ static int posix_cpu_timer_set(struct k_
 	/*
 	 * Arm the timer if it is not disabled, the new expiry value has
 	 * not yet expired and the timer requires signal delivery.
-	 * SIGEV_NONE timers are never armed.
+	 * SIGEV_NONE timers are never armed. In case the timer is not
+	 * armed, enforce the reevaluation of the timer base so that the
+	 * process wide cputime counter can be disabled eventually.
 	 */
-	if (!sigev_none && new_expires && now < new_expires)
-		arm_timer(timer, p);
+	if (likely(!sigev_none)) {
+		if (new_expires && now < new_expires)
+			arm_timer(timer, p);
+		else
+			trigger_base_recalc_expires(timer, p);
+	}
 
 	unlock_task_sighand(p, &flags);
 	/*
@@ -727,30 +733,14 @@ static int posix_cpu_timer_set(struct k_
 	timer->it_overrun_last = 0;
 	timer->it_overrun = -1;
 
-	if (!sigev_none && now >= new_expires) {
-		if (new_expires != 0) {
-			/*
-			 * The designated time already passed, so we notify
-			 * immediately, even if the thread never runs to
-			 * accumulate more time on this clock.
-			 */
-			cpu_timer_fire(timer);
-		}
-
-		/*
-		 * Make sure we don't keep around the process wide cputime
-		 * counter or the tick dependency if they are not necessary.
-		 */
-		sighand = lock_task_sighand(p, &flags);
-		if (!sighand)
-			goto out;
-
-		if (!cpu_timer_queued(ctmr))
-			trigger_base_recalc_expires(timer, p);
-
-		unlock_task_sighand(p, &flags);
-	}
- out:
+	/*
+	 * If the new expiry time was already in the past the timer was not
+	 * queued. Fire it immediately even if the thread never runs to
+	 * accumulate more time on this clock.
+	 */
+	if (!sigev_none && new_expires && now >= new_expires)
+		cpu_timer_fire(timer);
+out:
 	rcu_read_unlock();
 	if (old)
 		old->it_interval = ns_to_timespec64(old_incr);


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 17/50] posix-timers: Retrieve interval in common timer_settime() code
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (15 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 16/50] posix-cpu-timers: Simplify posix_cpu_timer_set() Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-15 15:43   ` Anna-Maria Behnsen
  2024-04-10 22:46 ` [patch V2 18/50] posix-timers: Clear overrun in common_timer_set() Thomas Gleixner
                   ` (33 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

No point in doing this all over the place.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Removed the timer_gettime() part - Frederic
---
 kernel/time/posix-cpu-timers.c |   10 ++--------
 kernel/time/posix-timers.c     |    5 ++++-
 2 files changed, 6 insertions(+), 9 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -622,8 +622,8 @@ static int posix_cpu_timer_set(struct k_
 {
 	bool sigev_none = timer->it_sigev_notify == SIGEV_NONE;
 	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
-	u64 old_expires, new_expires, old_incr, now;
 	struct cpu_timer *ctmr = &timer->it.cpu;
+	u64 old_expires, new_expires, now;
 	struct sighand_struct *sighand;
 	struct task_struct *p;
 	unsigned long flags;
@@ -660,10 +660,7 @@ static int posix_cpu_timer_set(struct k_
 		return -ESRCH;
 	}
 
-	/*
-	 * Disarm any old timer after extracting its expiry time.
-	 */
-	old_incr = timer->it_interval;
+	/* Retrieve the current expiry time before disarming the timer */
 	old_expires = cpu_timer_getexpires(ctmr);
 
 	if (unlikely(timer->it.cpu.firing)) {
@@ -742,9 +739,6 @@ static int posix_cpu_timer_set(struct k_
 		cpu_timer_fire(timer);
 out:
 	rcu_read_unlock();
-	if (old)
-		old->it_interval = ns_to_timespec64(old_incr);
-
 	return ret;
 }
 
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -904,7 +904,7 @@ static int do_timer_settime(timer_t time
 	const struct k_clock *kc;
 	struct k_itimer *timr;
 	unsigned long flags;
-	int error = 0;
+	int error;
 
 	if (!timespec64_valid(&new_spec64->it_interval) ||
 	    !timespec64_valid(&new_spec64->it_value))
@@ -918,6 +918,9 @@ static int do_timer_settime(timer_t time
 	if (!timr)
 		return -EINVAL;
 
+	if (old_spec64)
+		old_spec64->it_interval = ktime_to_timespec64(timr->it_interval);
+
 	kc = timr->kclock;
 	if (WARN_ON_ONCE(!kc || !kc->timer_set))
 		error = -EINVAL;


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 18/50] posix-timers: Clear overrun in common_timer_set()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (16 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 17/50] posix-timers: Retrieve interval in common timer_settime() code Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 19/50] posix-timers: Convert timer list to hlist Thomas Gleixner
                   ` (32 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Keeping the overrun count of the previous setup around is just wrong. The
new setting has nothing to do with the previous one and has to start from a
clean slate.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 kernel/time/posix-timers.c |    1 +
 1 file changed, 1 insertion(+)

--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -881,6 +881,7 @@ int common_timer_set(struct k_itimer *ti
 	timr->it_requeue_pending = (timr->it_requeue_pending + 2) &
 		~REQUEUE_PENDING;
 	timr->it_overrun_last = 0;
+	timr->it_overrun = -1LL;
 
 	/* Switch off the timer when it_value is zero */
 	if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec)


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 19/50] posix-timers: Convert timer list to hlist
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (17 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 18/50] posix-timers: Clear overrun in common_timer_set() Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 20/50] posix-timers: Consolidate timer setup Thomas Gleixner
                   ` (31 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

No requirement for a real list. Spare a few bytes.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 fs/proc/base.c               |    6 +++---
 include/linux/posix-timers.h |    2 +-
 include/linux/sched/signal.h |    2 +-
 init/init_task.c             |    2 +-
 kernel/fork.c                |    2 +-
 kernel/time/posix-timers.c   |   19 ++++++++-----------
 6 files changed, 15 insertions(+), 18 deletions(-)

--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2456,13 +2456,13 @@ static void *timers_start(struct seq_fil
 	if (!tp->sighand)
 		return ERR_PTR(-ESRCH);
 
-	return seq_list_start(&tp->task->signal->posix_timers, *pos);
+	return seq_hlist_start(&tp->task->signal->posix_timers, *pos);
 }
 
 static void *timers_next(struct seq_file *m, void *v, loff_t *pos)
 {
 	struct timers_private *tp = m->private;
-	return seq_list_next(v, &tp->task->signal->posix_timers, pos);
+	return seq_hlist_next(v, &tp->task->signal->posix_timers, pos);
 }
 
 static void timers_stop(struct seq_file *m, void *v)
@@ -2491,7 +2491,7 @@ static int show_timer(struct seq_file *m
 		[SIGEV_THREAD] = "thread",
 	};
 
-	timer = list_entry((struct list_head *)v, struct k_itimer, list);
+	timer = hlist_entry((struct hlist_node *)v, struct k_itimer, list);
 	notify = timer->it_sigev_notify;
 
 	seq_printf(m, "ID: %d\n", timer->it_id);
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -158,7 +158,7 @@ static inline void posix_cputimers_init_
  * @rcu:		RCU head for freeing the timer.
  */
 struct k_itimer {
-	struct list_head	list;
+	struct hlist_node	list;
 	struct hlist_node	t_hash;
 	spinlock_t		it_lock;
 	const struct k_clock	*kclock;
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -137,7 +137,7 @@ struct signal_struct {
 
 	/* POSIX.1b Interval Timers */
 	unsigned int		next_posix_timer_id;
-	struct list_head	posix_timers;
+	struct hlist_head	posix_timers;
 
 	/* ITIMER_REAL timer for the process */
 	struct hrtimer real_timer;
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -29,7 +29,7 @@ static struct signal_struct init_signals
 	.cred_guard_mutex = __MUTEX_INITIALIZER(init_signals.cred_guard_mutex),
 	.exec_update_lock = __RWSEM_INITIALIZER(init_signals.exec_update_lock),
 #ifdef CONFIG_POSIX_TIMERS
-	.posix_timers = LIST_HEAD_INIT(init_signals.posix_timers),
+	.posix_timers	= HLIST_HEAD_INIT,
 	.cputimer	= {
 		.cputime_atomic	= INIT_CPUTIME_ATOMIC,
 	},
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1876,7 +1876,7 @@ static int copy_signal(unsigned long clo
 	prev_cputime_init(&sig->prev_cputime);
 
 #ifdef CONFIG_POSIX_TIMERS
-	INIT_LIST_HEAD(&sig->posix_timers);
+	INIT_HLIST_HEAD(&sig->posix_timers);
 	hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	sig->real_timer.function = it_real_fn;
 #endif
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -515,7 +515,7 @@ static int do_timer_create(clockid_t whi
 	spin_lock_irq(&current->sighand->siglock);
 	/* This makes the timer valid in the hash table */
 	WRITE_ONCE(new_timer->it_signal, current->signal);
-	list_add(&new_timer->list, &current->signal->posix_timers);
+	hlist_add_head(&new_timer->list, &current->signal->posix_timers);
 	spin_unlock_irq(&current->sighand->siglock);
 	/*
 	 * After unlocking sighand::siglock @new_timer is subject to
@@ -1025,7 +1025,7 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
 	}
 
 	spin_lock(&current->sighand->siglock);
-	list_del(&timer->list);
+	hlist_del(&timer->list);
 	spin_unlock(&current->sighand->siglock);
 	/*
 	 * A concurrent lookup could check timer::it_signal lockless. It
@@ -1075,7 +1075,7 @@ static void itimer_delete(struct k_itime
 
 		goto retry_delete;
 	}
-	list_del(&timer->list);
+	hlist_del(&timer->list);
 
 	/*
 	 * Setting timer::it_signal to NULL is technically not required
@@ -1096,22 +1096,19 @@ static void itimer_delete(struct k_itime
  */
 void exit_itimers(struct task_struct *tsk)
 {
-	struct list_head timers;
-	struct k_itimer *tmr;
+	struct hlist_head timers;
 
-	if (list_empty(&tsk->signal->posix_timers))
+	if (hlist_empty(&tsk->signal->posix_timers))
 		return;
 
 	/* Protect against concurrent read via /proc/$PID/timers */
 	spin_lock_irq(&tsk->sighand->siglock);
-	list_replace_init(&tsk->signal->posix_timers, &timers);
+	hlist_move_list(&tsk->signal->posix_timers, &timers);
 	spin_unlock_irq(&tsk->sighand->siglock);
 
 	/* The timers are not longer accessible via tsk::signal */
-	while (!list_empty(&timers)) {
-		tmr = list_first_entry(&timers, struct k_itimer, list);
-		itimer_delete(tmr);
-	}
+	while (!hlist_empty(&timers))
+		itimer_delete(hlist_entry(timers.first, struct k_itimer, list));
 }
 
 SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 20/50] posix-timers: Consolidate timer setup
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (18 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 19/50] posix-timers: Convert timer list to hlist Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-16 16:12   ` Anna-Maria Behnsen
  2024-04-10 22:46 ` [patch V2 21/50] posix-cpu-timers: Make k_itimer::it_active consistent Thomas Gleixner
                   ` (30 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

hrtimer based and CPU timers have their own way to install the new interval
and to reset overrun and signal handling related data.

Create a helper function and do the same operation for all variants.

This also makes the handling of the interval consistent. It's only stored
when the timer is actually armed, i.e. timer->it_value != 0. Before that it
was stored unconditionally for posix CPU timers and conditionally for the
other posix timers.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/time/posix-cpu-timers.c |   15 +--------------
 kernel/time/posix-timers.c     |   25 +++++++++++++++++++------
 kernel/time/posix-timers.h     |    1 +
 3 files changed, 21 insertions(+), 20 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -714,21 +714,8 @@ static int posix_cpu_timer_set(struct k_
 	}
 
 	unlock_task_sighand(p, &flags);
-	/*
-	 * Install the new reload setting, and
-	 * set up the signal and overrun bookkeeping.
-	 */
-	timer->it_interval = timespec64_to_ktime(new->it_interval);
 
-	/*
-	 * This acts as a modification timestamp for the timer,
-	 * so any automatic reload attempt will punt on seeing
-	 * that we have reset the timer manually.
-	 */
-	timer->it_requeue_pending = (timer->it_requeue_pending + 2) &
-		~REQUEUE_PENDING;
-	timer->it_overrun_last = 0;
-	timer->it_overrun = -1;
+	posix_timer_set_common(timer, new);
 
 	/*
 	 * If the new expiry time was already in the past the timer was not
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -856,6 +856,23 @@ static struct k_itimer *timer_wait_runni
 	return lock_timer(timer_id, flags);
 }
 
+/*
+ * Set up the new interval and reset the signal delivery data
+ */
+void posix_timer_set_common(struct k_itimer *timer, struct itimerspec64 *new_setting)
+{
+	if (new_setting->it_value.tv_sec || new_setting->it_value.tv_nsec)
+		timer->it_interval = timespec64_to_ktime(new_setting->it_interval);
+	else
+		timer->it_interval = 0;
+
+	/* Prevent reloading in case there is a signal pending */
+	timer->it_requeue_pending = (timer->it_requeue_pending + 2) & ~REQUEUE_PENDING;
+	/* Reset overrun accounting */
+	timer->it_overrun_last = 0;
+	timer->it_overrun = -1LL;
+}
+
 /* Set a POSIX.1b interval timer. */
 int common_timer_set(struct k_itimer *timr, int flags,
 		     struct itimerspec64 *new_setting,
@@ -878,16 +895,12 @@ int common_timer_set(struct k_itimer *ti
 		return TIMER_RETRY;
 
 	timr->it_active = 0;
-	timr->it_requeue_pending = (timr->it_requeue_pending + 2) &
-		~REQUEUE_PENDING;
-	timr->it_overrun_last = 0;
-	timr->it_overrun = -1LL;
+	posix_timer_set_common(timr, new_setting);
 
-	/* Switch off the timer when it_value is zero */
+	/* Keep timer disarmed when it_value is zero */
 	if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec)
 		return 0;
 
-	timr->it_interval = timespec64_to_ktime(new_setting->it_interval);
 	expires = timespec64_to_ktime(new_setting->it_value);
 	if (flags & TIMER_ABSTIME)
 		expires = timens_ktime_to_host(timr->it_clock, expires);
--- a/kernel/time/posix-timers.h
+++ b/kernel/time/posix-timers.h
@@ -42,4 +42,5 @@ void common_timer_get(struct k_itimer *t
 int common_timer_set(struct k_itimer *timr, int flags,
 		     struct itimerspec64 *new_setting,
 		     struct itimerspec64 *old_setting);
+void posix_timer_set_common(struct k_itimer *timer, struct itimerspec64 *new_setting);
 int common_timer_del(struct k_itimer *timer);


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 21/50] posix-cpu-timers: Make k_itimer::it_active consistent
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (19 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 20/50] posix-timers: Consolidate timer setup Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-17 10:11   ` Anna-Maria Behnsen
  2024-04-10 22:46 ` [patch V2 22/50] posix-timers: Consolidate signal queueing Thomas Gleixner
                   ` (29 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Posix CPU timers are not updating k_itimer::it_active which makes it
impossible to base decisions in the common posix timer code on it.

Update it when queueing or dequeueing posix CPU timers.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Move the clearing to cpu_timer_fire() - Frederic
---
 kernel/time/posix-cpu-timers.c |    4 ++++
 1 file changed, 4 insertions(+)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -453,6 +453,7 @@ static void disarm_timer(struct k_itimer
 	struct cpu_timer *ctmr = &timer->it.cpu;
 	struct posix_cputimer_base *base;
 
+	timer->it_active = 0;
 	if (!cpu_timer_dequeue(ctmr))
 		return;
 
@@ -559,6 +560,7 @@ static void arm_timer(struct k_itimer *t
 	struct cpu_timer *ctmr = &timer->it.cpu;
 	u64 newexp = cpu_timer_getexpires(ctmr);
 
+	timer->it_active = 1;
 	if (!cpu_timer_enqueue(&base->tqhead, ctmr))
 		return;
 
@@ -584,6 +586,7 @@ static void cpu_timer_fire(struct k_itim
 {
 	struct cpu_timer *ctmr = &timer->it.cpu;
 
+	timer->it_active = 0;
 	if (unlikely(timer->sigq == NULL)) {
 		/*
 		 * This a special case for clock_nanosleep,
@@ -668,6 +671,7 @@ static int posix_cpu_timer_set(struct k_
 		ret = TIMER_RETRY;
 	} else {
 		cpu_timer_dequeue(ctmr);
+		timer->it_active = 0;
 	}
 
 	/*


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 22/50] posix-timers: Consolidate signal queueing
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (20 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 21/50] posix-cpu-timers: Make k_itimer::it_active consistent Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:46 ` [patch V2 23/50] signal: Remove task argument from dequeue_signal() Thomas Gleixner
                   ` (28 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Rename posix_timer_event() to posix_timer_queue_signal() as this is what
the function is about.

Consolidate the requeue pending and deactivation updates into that function
as there is no point in doing this in all incarnations of posix timers.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 kernel/time/alarmtimer.c       |    7 +------
 kernel/time/posix-cpu-timers.c |    4 ++--
 kernel/time/posix-timers.c     |   21 +++++++++++----------
 kernel/time/posix-timers.h     |    2 +-
 4 files changed, 15 insertions(+), 19 deletions(-)

--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -574,15 +574,10 @@ static enum alarmtimer_restart alarm_han
 					    it.alarm.alarmtimer);
 	enum alarmtimer_restart result = ALARMTIMER_NORESTART;
 	unsigned long flags;
-	int si_private = 0;
 
 	spin_lock_irqsave(&ptr->it_lock, flags);
 
-	ptr->it_active = 0;
-	if (ptr->it_interval)
-		si_private = ++ptr->it_requeue_pending;
-
-	if (posix_timer_event(ptr, si_private) && ptr->it_interval) {
+	if (posix_timer_queue_signal(ptr) && ptr->it_interval) {
 		/*
 		 * Handle ignored signals and rearm the timer. This will go
 		 * away once we handle ignored signals proper. Ensure that
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -598,9 +598,9 @@ static void cpu_timer_fire(struct k_itim
 		/*
 		 * One-shot timer.  Clear it as soon as it's fired.
 		 */
-		posix_timer_event(timer, 0);
+		posix_timer_queue_signal(timer);
 		cpu_timer_setexpires(ctmr, 0);
-	} else if (posix_timer_event(timer, ++timer->it_requeue_pending)) {
+	} else if (posix_timer_queue_signal(timer)) {
 		/*
 		 * The signal did not get queued because the signal
 		 * was ignored, so we won't get any callback to
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -277,10 +277,17 @@ void posixtimer_rearm(struct kernel_sigi
 	unlock_timer(timr, flags);
 }
 
-int posix_timer_event(struct k_itimer *timr, int si_private)
+int posix_timer_queue_signal(struct k_itimer *timr)
 {
+	int ret, si_private = 0;
 	enum pid_type type;
-	int ret;
+
+	lockdep_assert_held(&timr->it_lock);
+
+	timr->it_active = 0;
+	if (timr->it_interval)
+		si_private = ++timr->it_requeue_pending;
+
 	/*
 	 * FIXME: if ->sigq is queued we can race with
 	 * dequeue_signal()->posixtimer_rearm().
@@ -309,19 +316,13 @@ int posix_timer_event(struct k_itimer *t
  */
 static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
 {
+	struct k_itimer *timr = container_of(timer, struct k_itimer, it.real.timer);
 	enum hrtimer_restart ret = HRTIMER_NORESTART;
-	struct k_itimer *timr;
 	unsigned long flags;
-	int si_private = 0;
 
-	timr = container_of(timer, struct k_itimer, it.real.timer);
 	spin_lock_irqsave(&timr->it_lock, flags);
 
-	timr->it_active = 0;
-	if (timr->it_interval != 0)
-		si_private = ++timr->it_requeue_pending;
-
-	if (posix_timer_event(timr, si_private)) {
+	if (posix_timer_queue_signal(timr)) {
 		/*
 		 * The signal was not queued due to SIG_IGN. As a
 		 * consequence the timer is not going to be rearmed from
--- a/kernel/time/posix-timers.h
+++ b/kernel/time/posix-timers.h
@@ -36,7 +36,7 @@ extern const struct k_clock clock_proces
 extern const struct k_clock clock_thread;
 extern const struct k_clock alarm_clock;
 
-int posix_timer_event(struct k_itimer *timr, int si_private);
+int posix_timer_queue_signal(struct k_itimer *timr);
 
 void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting);
 int common_timer_set(struct k_itimer *timr, int flags,


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 23/50] signal: Remove task argument from dequeue_signal()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (21 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 22/50] posix-timers: Consolidate signal queueing Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-18 14:18   ` Oleg Nesterov
  2024-04-10 22:46 ` [patch V2 24/50] signal: Replace BUG_ON()s Thomas Gleixner
                   ` (27 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

The task pointer which is handed to dequeue_signal() is always current. The
argument along with the first comment about signalfd in that function is
confusing at best. Remove it and use current internally.

Update the stale comment for dequeue_signal() while at it.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 fs/signalfd.c                |    4 ++--
 include/linux/sched/signal.h |    5 ++---
 kernel/signal.c              |   23 ++++++++++-------------
 3 files changed, 14 insertions(+), 18 deletions(-)

--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -160,7 +160,7 @@ static ssize_t signalfd_dequeue(struct s
 	DECLARE_WAITQUEUE(wait, current);
 
 	spin_lock_irq(&current->sighand->siglock);
-	ret = dequeue_signal(current, &ctx->sigmask, info, &type);
+	ret = dequeue_signal(&ctx->sigmask, info, &type);
 	switch (ret) {
 	case 0:
 		if (!nonblock)
@@ -175,7 +175,7 @@ static ssize_t signalfd_dequeue(struct s
 	add_wait_queue(&current->sighand->signalfd_wqh, &wait);
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
-		ret = dequeue_signal(current, &ctx->sigmask, info, &type);
+		ret = dequeue_signal(&ctx->sigmask, info, &type);
 		if (ret != 0)
 			break;
 		if (signal_pending(current)) {
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -276,8 +276,7 @@ static inline void signal_set_stop_flags
 extern void flush_signals(struct task_struct *);
 extern void ignore_signals(struct task_struct *);
 extern void flush_signal_handlers(struct task_struct *, int force_default);
-extern int dequeue_signal(struct task_struct *task, sigset_t *mask,
-			  kernel_siginfo_t *info, enum pid_type *type);
+extern int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type);
 
 static inline int kernel_dequeue_signal(void)
 {
@@ -287,7 +286,7 @@ static inline int kernel_dequeue_signal(
 	int ret;
 
 	spin_lock_irq(&task->sighand->siglock);
-	ret = dequeue_signal(task, &task->blocked, &__info, &__type);
+	ret = dequeue_signal(&task->blocked, &__info, &__type);
 	spin_unlock_irq(&task->sighand->siglock);
 
 	return ret;
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -618,20 +618,18 @@ static int __dequeue_signal(struct sigpe
 }
 
 /*
- * Dequeue a signal and return the element to the caller, which is
- * expected to free it.
- *
- * All callers have to hold the siglock.
+ * Try to dequeue a signal. If a deliverable signal is found fill in the
+ * caller provided siginfo and return the signal number. Otherwise return
+ * 0.
  */
-int dequeue_signal(struct task_struct *tsk, sigset_t *mask,
-		   kernel_siginfo_t *info, enum pid_type *type)
+int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type)
 {
+	struct task_struct *tsk = current;
 	bool resched_timer = false;
 	int signr;
 
-	/* We only dequeue private signals from ourselves, we don't let
-	 * signalfd steal them
-	 */
+	lockdep_assert_held(&tsk->sighand->siglock);
+
 	*type = PIDTYPE_PID;
 	signr = __dequeue_signal(&tsk->pending, mask, info, &resched_timer);
 	if (!signr) {
@@ -2787,8 +2785,7 @@ bool get_signal(struct ksignal *ksig)
 		type = PIDTYPE_PID;
 		signr = dequeue_synchronous_signal(&ksig->info);
 		if (!signr)
-			signr = dequeue_signal(current, &current->blocked,
-					       &ksig->info, &type);
+			signr = dequeue_signal(&current->blocked, &ksig->info, &type);
 
 		if (!signr)
 			break; /* will return 0 */
@@ -3642,7 +3639,7 @@ static int do_sigtimedwait(const sigset_
 	signotset(&mask);
 
 	spin_lock_irq(&tsk->sighand->siglock);
-	sig = dequeue_signal(tsk, &mask, info, &type);
+	sig = dequeue_signal(&mask, info, &type);
 	if (!sig && timeout) {
 		/*
 		 * None ready, temporarily unblock those we're interested
@@ -3661,7 +3658,7 @@ static int do_sigtimedwait(const sigset_
 		spin_lock_irq(&tsk->sighand->siglock);
 		__set_task_blocked(tsk, &tsk->real_blocked);
 		sigemptyset(&tsk->real_blocked);
-		sig = dequeue_signal(tsk, &mask, info, &type);
+		sig = dequeue_signal(&mask, info, &type);
 	}
 	spin_unlock_irq(&tsk->sighand->siglock);
 


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 24/50] signal: Replace BUG_ON()s
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (22 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 23/50] signal: Remove task argument from dequeue_signal() Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-18 14:37   ` Oleg Nesterov
  2024-04-10 22:46 ` [patch V2 25/50] signal: Confine POSIX_TIMERS properly Thomas Gleixner
                   ` (26 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

These really can be handled gracefully without killing the machine.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 kernel/signal.c |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1940,10 +1940,11 @@ struct sigqueue *sigqueue_alloc(void)
 
 void sigqueue_free(struct sigqueue *q)
 {
-	unsigned long flags;
 	spinlock_t *lock = &current->sighand->siglock;
+	unsigned long flags;
 
-	BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
+	if (WARN_ON_ONCE(!(q->flags & SIGQUEUE_PREALLOC)))
+		return;
 	/*
 	 * We must hold ->siglock while testing q->list
 	 * to serialize with collect_signal() or with
@@ -1971,7 +1972,10 @@ int send_sigqueue(struct sigqueue *q, st
 	unsigned long flags;
 	int ret, result;
 
-	BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
+	if (WARN_ON_ONCE(!(q->flags & SIGQUEUE_PREALLOC)))
+		return 0;
+	if (WARN_ON_ONCE(q->info.si_code != SI_TIMER))
+		return 0;
 
 	ret = -1;
 	rcu_read_lock();
@@ -2006,7 +2010,6 @@ int send_sigqueue(struct sigqueue *q, st
 		 * If an SI_TIMER entry is already queue just increment
 		 * the overrun count.
 		 */
-		BUG_ON(q->info.si_code != SI_TIMER);
 		q->info.si_overrun++;
 		result = TRACE_SIGNAL_ALREADY_PENDING;
 		goto out;


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 25/50] signal: Confine POSIX_TIMERS properly
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (23 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 24/50] signal: Replace BUG_ON()s Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-17 12:09   ` Anna-Maria Behnsen
  2024-04-18 15:23   ` Oleg Nesterov
  2024-04-10 22:46 ` [patch V2 26/50] signal: Get rid of resched_timer logic Thomas Gleixner
                   ` (25 subsequent siblings)
  50 siblings, 2 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Move the itimer rearming out of the signal code and consolidate all posix
timer related functions in the signal code under one ifdef.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h |    5 +
 kernel/signal.c              |  125 +++++++++++++++----------------------------
 kernel/time/itimer.c         |   22 +++++++
 kernel/time/posix-timers.c   |   15 ++++-
 4 files changed, 82 insertions(+), 85 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -100,6 +100,8 @@ static inline void posix_cputimers_rt_wa
 {
 	pct->bases[CPUCLOCK_SCHED].nextevt = runtime;
 }
+void posixtimer_rearm_itimer(struct task_struct *p);
+void posixtimer_rearm(struct kernel_siginfo *info);
 
 /* Init task static initializer */
 #define INIT_CPU_TIMERBASE(b) {						\
@@ -122,6 +124,8 @@ struct cpu_timer { };
 static inline void posix_cputimers_init(struct posix_cputimers *pct) { }
 static inline void posix_cputimers_group_init(struct posix_cputimers *pct,
 					      u64 cpu_limit) { }
+static inline void posixtimer_rearm_itimer(struct task_struct *p) { }
+static inline void posixtimer_rearm(struct kernel_siginfo *info) { }
 #endif
 
 #ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK
@@ -196,5 +200,4 @@ void set_process_cpu_timer(struct task_s
 
 int update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
 
-void posixtimer_rearm(struct kernel_siginfo *info);
 #endif
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -478,42 +478,6 @@ void flush_signals(struct task_struct *t
 }
 EXPORT_SYMBOL(flush_signals);
 
-#ifdef CONFIG_POSIX_TIMERS
-static void __flush_itimer_signals(struct sigpending *pending)
-{
-	sigset_t signal, retain;
-	struct sigqueue *q, *n;
-
-	signal = pending->signal;
-	sigemptyset(&retain);
-
-	list_for_each_entry_safe(q, n, &pending->list, list) {
-		int sig = q->info.si_signo;
-
-		if (likely(q->info.si_code != SI_TIMER)) {
-			sigaddset(&retain, sig);
-		} else {
-			sigdelset(&signal, sig);
-			list_del_init(&q->list);
-			__sigqueue_free(q);
-		}
-	}
-
-	sigorsets(&pending->signal, &signal, &retain);
-}
-
-void flush_itimer_signals(void)
-{
-	struct task_struct *tsk = current;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tsk->sighand->siglock, flags);
-	__flush_itimer_signals(&tsk->pending);
-	__flush_itimer_signals(&tsk->signal->shared_pending);
-	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
-}
-#endif
-
 void ignore_signals(struct task_struct *t)
 {
 	int i;
@@ -636,31 +600,9 @@ int dequeue_signal(sigset_t *mask, kerne
 		*type = PIDTYPE_TGID;
 		signr = __dequeue_signal(&tsk->signal->shared_pending,
 					 mask, info, &resched_timer);
-#ifdef CONFIG_POSIX_TIMERS
-		/*
-		 * itimer signal ?
-		 *
-		 * itimers are process shared and we restart periodic
-		 * itimers in the signal delivery path to prevent DoS
-		 * attacks in the high resolution timer case. This is
-		 * compliant with the old way of self-restarting
-		 * itimers, as the SIGALRM is a legacy signal and only
-		 * queued once. Changing the restart behaviour to
-		 * restart the timer in the signal dequeue path is
-		 * reducing the timer noise on heavy loaded !highres
-		 * systems too.
-		 */
-		if (unlikely(signr == SIGALRM)) {
-			struct hrtimer *tmr = &tsk->signal->real_timer;
 
-			if (!hrtimer_is_queued(tmr) &&
-			    tsk->signal->it_real_incr != 0) {
-				hrtimer_forward(tmr, tmr->base->get_time(),
-						tsk->signal->it_real_incr);
-				hrtimer_restart(tmr);
-			}
-		}
-#endif
+		if (unlikely(signr == SIGALRM))
+			posixtimer_rearm_itimer(tsk);
 	}
 
 	recalc_sigpending();
@@ -682,22 +624,12 @@ int dequeue_signal(sigset_t *mask, kerne
 		 */
 		current->jobctl |= JOBCTL_STOP_DEQUEUED;
 	}
-#ifdef CONFIG_POSIX_TIMERS
-	if (resched_timer) {
-		/*
-		 * Release the siglock to ensure proper locking order
-		 * of timer locks outside of siglocks.  Note, we leave
-		 * irqs disabled here, since the posix-timers code is
-		 * about to disable them again anyway.
-		 */
-		spin_unlock(&tsk->sighand->siglock);
-		posixtimer_rearm(info);
-		spin_lock(&tsk->sighand->siglock);
 
-		/* Don't expose the si_sys_private value to userspace */
-		info->si_sys_private = 0;
+	if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
+		if (unlikely(resched_timer))
+			posixtimer_rearm(info);
 	}
-#endif
+
 	return signr;
 }
 EXPORT_SYMBOL_GPL(dequeue_signal);
@@ -1924,15 +1856,45 @@ int kill_pid(struct pid *pid, int sig, i
 }
 EXPORT_SYMBOL(kill_pid);
 
+#ifdef CONFIG_POSIX_TIMERS
 /*
- * These functions support sending signals using preallocated sigqueue
- * structures.  This is needed "because realtime applications cannot
- * afford to lose notifications of asynchronous events, like timer
- * expirations or I/O completions".  In the case of POSIX Timers
- * we allocate the sigqueue structure from the timer_create.  If this
- * allocation fails we are able to report the failure to the application
- * with an EAGAIN error.
+ * These functions handle POSIX timer signals. POSIX timers use
+ * preallocated sigqueue structs for sending signals.
  */
+static void __flush_itimer_signals(struct sigpending *pending)
+{
+	sigset_t signal, retain;
+	struct sigqueue *q, *n;
+
+	signal = pending->signal;
+	sigemptyset(&retain);
+
+	list_for_each_entry_safe(q, n, &pending->list, list) {
+		int sig = q->info.si_signo;
+
+		if (likely(q->info.si_code != SI_TIMER)) {
+			sigaddset(&retain, sig);
+		} else {
+			sigdelset(&signal, sig);
+			list_del_init(&q->list);
+			__sigqueue_free(q);
+		}
+	}
+
+	sigorsets(&pending->signal, &signal, &retain);
+}
+
+void flush_itimer_signals(void)
+{
+	struct task_struct *tsk = current;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tsk->sighand->siglock, flags);
+	__flush_itimer_signals(&tsk->pending);
+	__flush_itimer_signals(&tsk->signal->shared_pending);
+	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+}
+
 struct sigqueue *sigqueue_alloc(void)
 {
 	return __sigqueue_alloc(-1, current, GFP_KERNEL, 0, SIGQUEUE_PREALLOC);
@@ -2029,6 +1991,7 @@ int send_sigqueue(struct sigqueue *q, st
 	rcu_read_unlock();
 	return ret;
 }
+#endif /* CONFIG_POSIX_TIMERS */
 
 void do_notify_pidfd(struct task_struct *task)
 {
--- a/kernel/time/itimer.c
+++ b/kernel/time/itimer.c
@@ -151,7 +151,27 @@ COMPAT_SYSCALL_DEFINE2(getitimer, int, w
 #endif
 
 /*
- * The timer is automagically restarted, when interval != 0
+ * Invoked from dequeue_signal() when SIG_ALRM is delivered.
+ *
+ * Restart the ITIMER_REAL timer if it is armed as periodic timer.  Doing
+ * this in the signal delivery path instead of self rearming prevents a DoS
+ * with small increments in the high reolution timer case and reduces timer
+ * noise in general.
+ */
+void posixtimer_rearm_itimer(struct task_struct *tsk)
+{
+	struct hrtimer *tmr = &tsk->signal->real_timer;
+
+	if (!hrtimer_is_queued(tmr) && tsk->signal->it_real_incr != 0) {
+		hrtimer_forward(tmr, tmr->base->get_time(),
+				tsk->signal->it_real_incr);
+		hrtimer_restart(tmr);
+	}
+}
+
+/*
+ * Interval timers are restarted in the signal delivery path.  See
+ * posixtimer_rearm_itimer().
  */
 enum hrtimer_restart it_real_fn(struct hrtimer *timer)
 {
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -251,7 +251,7 @@ static void common_hrtimer_rearm(struct
 
 /*
  * This function is called from the signal delivery code if
- * info->si_sys_private is not zero, which indicates that the timer has to
+ * info::si_sys_private is not zero, which indicates that the timer has to
  * be rearmed. Restart the timer and update info::si_overrun.
  */
 void posixtimer_rearm(struct kernel_siginfo *info)
@@ -259,9 +259,15 @@ void posixtimer_rearm(struct kernel_sigi
 	struct k_itimer *timr;
 	unsigned long flags;
 
+	/*
+	 * Release siglock to ensure proper locking order versus
+	 * timr::it_lock. Keep interrupts disabled.
+	 */
+	spin_unlock(&current->sighand->siglock);
+
 	timr = lock_timer(info->si_tid, &flags);
 	if (!timr)
-		return;
+		goto out;
 
 	if (timr->it_interval && timr->it_requeue_pending == info->si_sys_private) {
 		timr->kclock->timer_rearm(timr);
@@ -275,6 +281,11 @@ void posixtimer_rearm(struct kernel_sigi
 	}
 
 	unlock_timer(timr, flags);
+out:
+	spin_lock(&current->sighand->siglock);
+
+	/* Don't expose the si_sys_private value to userspace */
+	info->si_sys_private = 0;
 }
 
 int posix_timer_queue_signal(struct k_itimer *timr)


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 26/50] signal: Get rid of resched_timer logic
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (24 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 25/50] signal: Confine POSIX_TIMERS properly Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-18 16:38   ` Oleg Nesterov
  2024-04-10 22:46 ` [patch V2 27/50] posix-timers: Cure si_sys_private race Thomas Gleixner
                   ` (24 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

There is no reason for handing the *resched pointer argument through
several functions just to check whether the signal is related to a self
rearming posix timer.

SI_TIMER is only used by the posix timer code and cannot be queued from
user space. The only extra check in collect_signal() to verify whether the
queued signal is preallocated is not really useful. Some other places
already check purely the SI_TIMER type.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/signal.c |   25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -526,8 +526,7 @@ bool unhandled_signal(struct task_struct
 	return !tsk->ptrace;
 }
 
-static void collect_signal(int sig, struct sigpending *list, kernel_siginfo_t *info,
-			   bool *resched_timer)
+static void collect_signal(int sig, struct sigpending *list, kernel_siginfo_t *info)
 {
 	struct sigqueue *q, *first = NULL;
 
@@ -549,12 +548,6 @@ static void collect_signal(int sig, stru
 still_pending:
 		list_del_init(&first->list);
 		copy_siginfo(info, &first->info);
-
-		*resched_timer =
-			(first->flags & SIGQUEUE_PREALLOC) &&
-			(info->si_code == SI_TIMER) &&
-			(info->si_sys_private);
-
 		__sigqueue_free(first);
 	} else {
 		/*
@@ -571,13 +564,12 @@ static void collect_signal(int sig, stru
 	}
 }
 
-static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
-			kernel_siginfo_t *info, bool *resched_timer)
+static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, kernel_siginfo_t *info)
 {
 	int sig = next_signal(pending, mask);
 
 	if (sig)
-		collect_signal(sig, pending, info, resched_timer);
+		collect_signal(sig, pending, info);
 	return sig;
 }
 
@@ -589,17 +581,15 @@ static int __dequeue_signal(struct sigpe
 int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type)
 {
 	struct task_struct *tsk = current;
-	bool resched_timer = false;
 	int signr;
 
 	lockdep_assert_held(&tsk->sighand->siglock);
 
 	*type = PIDTYPE_PID;
-	signr = __dequeue_signal(&tsk->pending, mask, info, &resched_timer);
+	signr = __dequeue_signal(&tsk->pending, mask, info);
 	if (!signr) {
 		*type = PIDTYPE_TGID;
-		signr = __dequeue_signal(&tsk->signal->shared_pending,
-					 mask, info, &resched_timer);
+		signr = __dequeue_signal(&tsk->signal->shared_pending, mask, info);
 
 		if (unlikely(signr == SIGALRM))
 			posixtimer_rearm_itimer(tsk);
@@ -626,7 +616,7 @@ int dequeue_signal(sigset_t *mask, kerne
 	}
 
 	if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
-		if (unlikely(resched_timer))
+		if (unlikely(info->si_code == SI_TIMER && info->si_sys_private))
 			posixtimer_rearm(info);
 	}
 
@@ -1011,6 +1001,9 @@ static int __send_signal_locked(int sig,
 
 	lockdep_assert_held(&t->sighand->siglock);
 
+	if (WARN_ON_ONCE(!is_si_special(info) && info->si_code == SI_TIMER))
+		return 0;
+
 	result = TRACE_SIGNAL_IGNORED;
 	if (!prepare_signal(sig, t, force))
 		goto ret;


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 27/50] posix-timers: Cure si_sys_private race
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (25 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 26/50] signal: Get rid of resched_timer logic Thomas Gleixner
@ 2024-04-10 22:46 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 28/50] signal: Allow POSIX timer signals to be dropped Thomas Gleixner
                   ` (23 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:46 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

The si_sys_private member of the siginfo which is embedded in the
preallocated sigqueue is used by the posix timer code to decide whether a
timer must be reprogrammed on signal delivery.

The handling of this is racy as a long standing comment in that code
documents. It is modified with the timer lock held, but without sighand
lock being held. The actual signal delivery code checks for it under
sighand lock without holding the timer lock.

Hand the new value to send_sigqueue() as argument and store it with sighand
lock held.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/sched/signal.h |    2 +-
 kernel/signal.c              |   10 +++++++++-
 kernel/time/posix-timers.c   |   15 +--------------
 3 files changed, 11 insertions(+), 16 deletions(-)

--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -339,7 +339,7 @@ extern int send_sig(int, struct task_str
 extern int zap_other_threads(struct task_struct *p);
 extern struct sigqueue *sigqueue_alloc(void);
 extern void sigqueue_free(struct sigqueue *);
-extern int send_sigqueue(struct sigqueue *, struct pid *, enum pid_type);
+extern int send_sigqueue(struct sigqueue *, struct pid *, enum pid_type, int si_private);
 extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
 
 static inline void clear_notify_signal(void)
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1919,7 +1919,7 @@ void sigqueue_free(struct sigqueue *q)
 		__sigqueue_free(q);
 }
 
-int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
+int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type, int si_private)
 {
 	int sig = q->info.si_signo;
 	struct sigpending *pending;
@@ -1954,6 +1954,14 @@ int send_sigqueue(struct sigqueue *q, st
 	if (!likely(lock_task_sighand(t, &flags)))
 		goto ret;
 
+	/*
+	 * Update @q::info::si_sys_private for posix timer signals with
+	 * sighand locked to prevent a race against dequeue_signal() which
+	 * decides based on si_sys_private whether to invoke
+	 * posixtimer_rearm() or not.
+	 */
+	q->info.si_sys_private = si_private;
+
 	ret = 1; /* the signal is ignored */
 	result = TRACE_SIGNAL_IGNORED;
 	if (!prepare_signal(sig, t, false))
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -299,21 +299,8 @@ int posix_timer_queue_signal(struct k_it
 	if (timr->it_interval)
 		si_private = ++timr->it_requeue_pending;
 
-	/*
-	 * FIXME: if ->sigq is queued we can race with
-	 * dequeue_signal()->posixtimer_rearm().
-	 *
-	 * If dequeue_signal() sees the "right" value of
-	 * si_sys_private it calls posixtimer_rearm().
-	 * We re-queue ->sigq and drop ->it_lock().
-	 * posixtimer_rearm() locks the timer
-	 * and re-schedules it while ->sigq is pending.
-	 * Not really bad, but not that we want.
-	 */
-	timr->sigq->info.si_sys_private = si_private;
-
 	type = !(timr->it_sigev_notify & SIGEV_THREAD_ID) ? PIDTYPE_TGID : PIDTYPE_PID;
-	ret = send_sigqueue(timr->sigq, timr->it_pid, type);
+	ret = send_sigqueue(timr->sigq, timr->it_pid, type, si_private);
 	/* If we failed to send the signal the timer stops. */
 	return ret > 0;
 }


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 28/50] signal: Allow POSIX timer signals to be dropped
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (26 preceding siblings ...)
  2024-04-10 22:46 ` [patch V2 27/50] posix-timers: Cure si_sys_private race Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 29/50] posix-timers: Drop signal if timer has been deleted or reprogrammed Thomas Gleixner
                   ` (22 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

In case that a timer was reprogrammed or deleted an already pending signal
is obsolete. Right now such signals are kept around and eventually
delivered. While POSIX is blury about this:

 - "The effect of disarming or resetting a timer with pending expiration
    notifications is unspecified."

 - "The disposition of pending signals for the deleted timer is
    unspecified."

it is reasonable in both cases to expect that pending signals are discarded
as they have no meaning anymore.

Prepare the signal code to allow dropping posix timer signals.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h |    5 +++--
 kernel/signal.c              |    7 +++++--
 kernel/time/posix-timers.c   |    3 ++-
 3 files changed, 10 insertions(+), 5 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -100,8 +100,9 @@ static inline void posix_cputimers_rt_wa
 {
 	pct->bases[CPUCLOCK_SCHED].nextevt = runtime;
 }
+
 void posixtimer_rearm_itimer(struct task_struct *p);
-void posixtimer_rearm(struct kernel_siginfo *info);
+bool posixtimer_deliver_signal(struct kernel_siginfo *info);
 
 /* Init task static initializer */
 #define INIT_CPU_TIMERBASE(b) {						\
@@ -125,7 +126,7 @@ static inline void posix_cputimers_init(
 static inline void posix_cputimers_group_init(struct posix_cputimers *pct,
 					      u64 cpu_limit) { }
 static inline void posixtimer_rearm_itimer(struct task_struct *p) { }
-static inline void posixtimer_rearm(struct kernel_siginfo *info) { }
+static inline bool posixtimer_deliver_signal(struct kernel_siginfo *info) { return false; }
 #endif
 
 #ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -585,6 +585,7 @@ int dequeue_signal(sigset_t *mask, kerne
 
 	lockdep_assert_held(&tsk->sighand->siglock);
 
+again:
 	*type = PIDTYPE_PID;
 	signr = __dequeue_signal(&tsk->pending, mask, info);
 	if (!signr) {
@@ -616,8 +617,10 @@ int dequeue_signal(sigset_t *mask, kerne
 	}
 
 	if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
-		if (unlikely(info->si_code == SI_TIMER && info->si_sys_private))
-			posixtimer_rearm(info);
+		if (unlikely(info->si_code == SI_TIMER && info->si_sys_private)) {
+			if (!posixtimer_deliver_signal(info))
+				goto again;
+		}
 	}
 
 	return signr;
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -254,7 +254,7 @@ static void common_hrtimer_rearm(struct
  * info::si_sys_private is not zero, which indicates that the timer has to
  * be rearmed. Restart the timer and update info::si_overrun.
  */
-void posixtimer_rearm(struct kernel_siginfo *info)
+bool posixtimer_deliver_signal(struct kernel_siginfo *info)
 {
 	struct k_itimer *timr;
 	unsigned long flags;
@@ -286,6 +286,7 @@ void posixtimer_rearm(struct kernel_sigi
 
 	/* Don't expose the si_sys_private value to userspace */
 	info->si_sys_private = 0;
+	return true;
 }
 
 int posix_timer_queue_signal(struct k_itimer *timr)


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 29/50] posix-timers: Drop signal if timer has been deleted or reprogrammed
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (27 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 28/50] signal: Allow POSIX timer signals to be dropped Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 30/50] posix-timers: Rename k_itimer::it_requeue_pending Thomas Gleixner
                   ` (21 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

No point in delivering a signal from the past. POSIX does not specify the
behaviour here:

 - "The effect of disarming or resetting a timer with pending expiration
    notifications is unspecified."

 - "The disposition of pending signals for the deleted timer is unspecified."

In both cases it is reasonable to expect that pending signals are
discarded. Especially in the reprogramming case it does not make sense to
account for previous overruns or to deliver a signal for a timer which has
been disarmed.

Drop the signal as that is conistent and understandable behaviour.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/time/posix-timers.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -250,14 +250,14 @@ static void common_hrtimer_rearm(struct
 }
 
 /*
- * This function is called from the signal delivery code if
- * info::si_sys_private is not zero, which indicates that the timer has to
- * be rearmed. Restart the timer and update info::si_overrun.
+ * This function is called from the signal delivery code. It decides
+ * whether the signal should be dropped and rearms interval timers.
  */
 bool posixtimer_deliver_signal(struct kernel_siginfo *info)
 {
 	struct k_itimer *timr;
 	unsigned long flags;
+	bool ret = false;
 
 	/*
 	 * Release siglock to ensure proper locking order versus
@@ -279,6 +279,7 @@ bool posixtimer_deliver_signal(struct ke
 
 		info->si_overrun = timer_overrun_to_int(timr, info->si_overrun);
 	}
+	ret = true;
 
 	unlock_timer(timr, flags);
 out:
@@ -286,7 +287,7 @@ bool posixtimer_deliver_signal(struct ke
 
 	/* Don't expose the si_sys_private value to userspace */
 	info->si_sys_private = 0;
-	return true;
+	return ret;
 }
 
 int posix_timer_queue_signal(struct k_itimer *timr)


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 30/50] posix-timers: Rename k_itimer::it_requeue_pending
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (28 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 29/50] posix-timers: Drop signal if timer has been deleted or reprogrammed Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 31/50] posix-timers: Add proper state tracking Thomas Gleixner
                   ` (20 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Prepare for using this struct member to do a proper reprogramming and
deletion accounting so that stale signals can be dropped.

No functional change.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h   |    5 ++---
 kernel/time/alarmtimer.c       |    2 +-
 kernel/time/posix-cpu-timers.c |    4 ++--
 kernel/time/posix-timers.c     |   12 ++++++------
 4 files changed, 11 insertions(+), 12 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -150,8 +150,7 @@ static inline void posix_cputimers_init_
  * @it_active:		Marker that timer is active
  * @it_overrun:		The overrun counter for pending signals
  * @it_overrun_last:	The overrun at the time of the last delivered signal
- * @it_requeue_pending:	Indicator that timer waits for being requeued on
- *			signal delivery
+ * @it_signal_seq:	Sequence count to control signal delivery
  * @it_sigev_notify:	The notify word of sigevent struct for signal delivery
  * @it_interval:	The interval for periodic timers
  * @it_signal:		Pointer to the creators signal struct
@@ -172,7 +171,7 @@ struct k_itimer {
 	int			it_active;
 	s64			it_overrun;
 	s64			it_overrun_last;
-	int			it_requeue_pending;
+	unsigned int		it_signal_seq;
 	int			it_sigev_notify;
 	ktime_t			it_interval;
 	struct signal_struct	*it_signal;
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -584,7 +584,7 @@ static enum alarmtimer_restart alarm_han
 		 * small intervals cannot starve the system.
 		 */
 		ptr->it_overrun += __alarm_forward_now(alarm, ptr->it_interval, true);
-		++ptr->it_requeue_pending;
+		++ptr->it_signal_seq;
 		ptr->it_active = 1;
 		result = ALARMTIMER_RESTART;
 	}
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -608,7 +608,7 @@ static void cpu_timer_fire(struct k_itim
 		 * ticking in case the signal is deliverable next time.
 		 */
 		posix_cpu_timer_rearm(timer);
-		++timer->it_requeue_pending;
+		++timer->it_signal_seq;
 	}
 }
 
@@ -745,7 +745,7 @@ static void __posix_cpu_timer_get(struct
 	 *  - Timers which expired, but the signal has not yet been
 	 *    delivered
 	 */
-	if (iv && ((timer->it_requeue_pending & REQUEUE_PENDING) || sigev_none))
+	if (iv && ((timer->it_signal_seq & REQUEUE_PENDING) || sigev_none))
 		expires = bump_cpu_timer(timer, now);
 	else
 		expires = cpu_timer_getexpires(&timer->it.cpu);
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -269,13 +269,13 @@ bool posixtimer_deliver_signal(struct ke
 	if (!timr)
 		goto out;
 
-	if (timr->it_interval && timr->it_requeue_pending == info->si_sys_private) {
+	if (timr->it_interval && timr->it_signal_seq == info->si_sys_private) {
 		timr->kclock->timer_rearm(timr);
 
 		timr->it_active = 1;
 		timr->it_overrun_last = timr->it_overrun;
 		timr->it_overrun = -1LL;
-		++timr->it_requeue_pending;
+		++timr->it_signal_seq;
 
 		info->si_overrun = timer_overrun_to_int(timr, info->si_overrun);
 	}
@@ -299,7 +299,7 @@ int posix_timer_queue_signal(struct k_it
 
 	timr->it_active = 0;
 	if (timr->it_interval)
-		si_private = ++timr->it_requeue_pending;
+		si_private = ++timr->it_signal_seq;
 
 	type = !(timr->it_sigev_notify & SIGEV_THREAD_ID) ? PIDTYPE_TGID : PIDTYPE_PID;
 	ret = send_sigqueue(timr->sigq, timr->it_pid, type, si_private);
@@ -366,7 +366,7 @@ static enum hrtimer_restart posix_timer_
 
 			timr->it_overrun += hrtimer_forward(timer, now, timr->it_interval);
 			ret = HRTIMER_RESTART;
-			++timr->it_requeue_pending;
+			++timr->it_signal_seq;
 			timr->it_active = 1;
 		}
 	}
@@ -667,7 +667,7 @@ void common_timer_get(struct k_itimer *t
 	 * is a SIGEV_NONE timer move the expiry time forward by intervals,
 	 * so expiry is > now.
 	 */
-	if (iv && (timr->it_requeue_pending & REQUEUE_PENDING || sig_none))
+	if (iv && (timr->it_signal_seq & REQUEUE_PENDING || sig_none))
 		timr->it_overrun += kc->timer_forward(timr, now);
 
 	remaining = kc->timer_remaining(timr, now);
@@ -868,7 +868,7 @@ void posix_timer_set_common(struct k_iti
 		timer->it_interval = 0;
 
 	/* Prevent reloading in case there is a signal pending */
-	timer->it_requeue_pending = (timer->it_requeue_pending + 2) & ~REQUEUE_PENDING;
+	timer->it_signal_seq = (timer->it_signal_seq + 2) & ~REQUEUE_PENDING;
 	/* Reset overrun accounting */
 	timer->it_overrun_last = 0;
 	timer->it_overrun = -1LL;


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 31/50] posix-timers: Add proper state tracking
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (29 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 30/50] posix-timers: Rename k_itimer::it_requeue_pending Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-17 13:40   ` Anna-Maria Behnsen
  2024-04-10 22:47 ` [patch V2 32/50] posix-timers: Make signal delivery consistent Thomas Gleixner
                   ` (19 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Right now the state tracking is done by two struct members:

 - it_active:
     A boolean which tracks armed/disarmed state

 - it_signal_seq:
     A sequence counter which is used to invalidate settings
     and prevent rearming

Replace it_active with it_status and keep properly track about the states
in one place.

This allows to reuse it_signal_seq to track reprogramming, disarm and
delete operations in order to drop signals which are related to the state
previous of those operations.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h   |    4 ++--
 kernel/time/alarmtimer.c       |    2 +-
 kernel/time/posix-cpu-timers.c |   15 ++++++++-------
 kernel/time/posix-timers.c     |   22 +++++++++++++---------
 kernel/time/posix-timers.h     |    6 ++++++
 5 files changed, 30 insertions(+), 19 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -147,7 +147,7 @@ static inline void posix_cputimers_init_
  * @kclock:		Pointer to the k_clock struct handling this timer
  * @it_clock:		The posix timer clock id
  * @it_id:		The posix timer id for identifying the timer
- * @it_active:		Marker that timer is active
+ * @it_status:		The status of the timer
  * @it_overrun:		The overrun counter for pending signals
  * @it_overrun_last:	The overrun at the time of the last delivered signal
  * @it_signal_seq:	Sequence count to control signal delivery
@@ -168,7 +168,7 @@ struct k_itimer {
 	const struct k_clock	*kclock;
 	clockid_t		it_clock;
 	timer_t			it_id;
-	int			it_active;
+	int			it_status;
 	s64			it_overrun;
 	s64			it_overrun_last;
 	unsigned int		it_signal_seq;
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -585,7 +585,7 @@ static enum alarmtimer_restart alarm_han
 		 */
 		ptr->it_overrun += __alarm_forward_now(alarm, ptr->it_interval, true);
 		++ptr->it_signal_seq;
-		ptr->it_active = 1;
+		ptr->it_status = POSIX_TIMER_ARMED;
 		result = ALARMTIMER_RESTART;
 	}
 	spin_unlock_irqrestore(&ptr->it_lock, flags);
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -453,7 +453,6 @@ static void disarm_timer(struct k_itimer
 	struct cpu_timer *ctmr = &timer->it.cpu;
 	struct posix_cputimer_base *base;
 
-	timer->it_active = 0;
 	if (!cpu_timer_dequeue(ctmr))
 		return;
 
@@ -494,11 +493,12 @@ static int posix_cpu_timer_del(struct k_
 		 */
 		WARN_ON_ONCE(ctmr->head || timerqueue_node_queued(&ctmr->node));
 	} else {
-		if (timer->it.cpu.firing)
+		if (timer->it.cpu.firing) {
 			ret = TIMER_RETRY;
-		else
+		} else {
 			disarm_timer(timer, p);
-
+			timer->it_status = POSIX_TIMER_DISARMED;
+		}
 		unlock_task_sighand(p, &flags);
 	}
 
@@ -560,7 +560,7 @@ static void arm_timer(struct k_itimer *t
 	struct cpu_timer *ctmr = &timer->it.cpu;
 	u64 newexp = cpu_timer_getexpires(ctmr);
 
-	timer->it_active = 1;
+	timer->it_status = POSIX_TIMER_ARMED;
 	if (!cpu_timer_enqueue(&base->tqhead, ctmr))
 		return;
 
@@ -586,7 +586,8 @@ static void cpu_timer_fire(struct k_itim
 {
 	struct cpu_timer *ctmr = &timer->it.cpu;
 
-	timer->it_active = 0;
+	timer->it_status = POSIX_TIMER_DISARMED;
+
 	if (unlikely(timer->sigq == NULL)) {
 		/*
 		 * This a special case for clock_nanosleep,
@@ -671,7 +672,7 @@ static int posix_cpu_timer_set(struct k_
 		ret = TIMER_RETRY;
 	} else {
 		cpu_timer_dequeue(ctmr);
-		timer->it_active = 0;
+		timer->it_status = POSIX_TIMER_DISARMED;
 	}
 
 	/*
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -272,7 +272,7 @@ bool posixtimer_deliver_signal(struct ke
 	if (timr->it_interval && timr->it_signal_seq == info->si_sys_private) {
 		timr->kclock->timer_rearm(timr);
 
-		timr->it_active = 1;
+		timr->it_status = POSIX_TIMER_ARMED;
 		timr->it_overrun_last = timr->it_overrun;
 		timr->it_overrun = -1LL;
 		++timr->it_signal_seq;
@@ -292,14 +292,17 @@ bool posixtimer_deliver_signal(struct ke
 
 int posix_timer_queue_signal(struct k_itimer *timr)
 {
+	enum posix_timer_state state = POSIX_TIMER_DISARMED;
 	int ret, si_private = 0;
 	enum pid_type type;
 
 	lockdep_assert_held(&timr->it_lock);
 
-	timr->it_active = 0;
-	if (timr->it_interval)
+	if (timr->it_interval) {
+		state = POSIX_TIMER_REQUEUE_PENDING;
 		si_private = ++timr->it_signal_seq;
+	}
+	timr->it_status = state;
 
 	type = !(timr->it_sigev_notify & SIGEV_THREAD_ID) ? PIDTYPE_TGID : PIDTYPE_PID;
 	ret = send_sigqueue(timr->sigq, timr->it_pid, type, si_private);
@@ -367,7 +370,7 @@ static enum hrtimer_restart posix_timer_
 			timr->it_overrun += hrtimer_forward(timer, now, timr->it_interval);
 			ret = HRTIMER_RESTART;
 			++timr->it_signal_seq;
-			timr->it_active = 1;
+			timr->it_status = POSIX_TIMER_ARMED;
 		}
 	}
 
@@ -647,10 +650,10 @@ void common_timer_get(struct k_itimer *t
 	/* interval timer ? */
 	if (iv) {
 		cur_setting->it_interval = ktime_to_timespec64(iv);
-	} else if (!timr->it_active) {
+	} else if (timr->it_status == POSIX_TIMER_DISARMED) {
 		/*
 		 * SIGEV_NONE oneshot timers are never queued and therefore
-		 * timr->it_active is always false. The check below
+		 * timr->it_status is always DISARMED. The check below
 		 * vs. remaining time will handle this case.
 		 *
 		 * For all other timers there is nothing to update here, so
@@ -895,7 +898,7 @@ int common_timer_set(struct k_itimer *ti
 	if (kc->timer_try_to_cancel(timr) < 0)
 		return TIMER_RETRY;
 
-	timr->it_active = 0;
+	timr->it_status = POSIX_TIMER_DISARMED;
 	posix_timer_set_common(timr, new_setting);
 
 	/* Keep timer disarmed when it_value is zero */
@@ -908,7 +911,8 @@ int common_timer_set(struct k_itimer *ti
 	sigev_none = timr->it_sigev_notify == SIGEV_NONE;
 
 	kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none);
-	timr->it_active = !sigev_none;
+	if (!sigev_none)
+		timr->it_status = POSIX_TIMER_ARMED;
 	return 0;
 }
 
@@ -1007,7 +1011,7 @@ int common_timer_del(struct k_itimer *ti
 	timer->it_interval = 0;
 	if (kc->timer_try_to_cancel(timer) < 0)
 		return TIMER_RETRY;
-	timer->it_active = 0;
+	timer->it_status = POSIX_TIMER_DISARMED;
 	return 0;
 }
 
--- a/kernel/time/posix-timers.h
+++ b/kernel/time/posix-timers.h
@@ -1,6 +1,12 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #define TIMER_RETRY 1
 
+enum posix_timer_state {
+	POSIX_TIMER_DISARMED,
+	POSIX_TIMER_ARMED,
+	POSIX_TIMER_REQUEUE_PENDING,
+};
+
 struct k_clock {
 	int	(*clock_getres)(const clockid_t which_clock,
 				struct timespec64 *tp);


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 32/50] posix-timers: Make signal delivery consistent
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (30 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 31/50] posix-timers: Add proper state tracking Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-18 10:29   ` Anna-Maria Behnsen
  2024-04-10 22:47 ` [patch V2 33/50] posix-timers: Make signal overrun accounting sensible Thomas Gleixner
                   ` (18 subsequent siblings)
  50 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Signals of timers which are reprogammed, disarmed or deleted can deliver
signals related to the past. The POSIX spec is blury about this:

 - "The effect of disarming or resetting a timer with pending expiration
   notifications is unspecified."

 - "The disposition of pending signals for the deleted timer is
    unspecified."

In both cases it is reasonable to expect that pending signals are
discarded. Especially in the reprogramming case it does not make sense to
account for previous overruns or to deliver a signal for a timer which has
been disarmed. This makes the behaviour consistent and understandable.

Remove the si_sys_private check from the signal delivery code and invoke
posix_timer_deliver_signal() unconditionally.

Change that function so it controls the actual signal delivery via the
return value. It now instructs the signal code to drop the signal when:

  1) The timer does not longer exist in the hash table

  2) The timer signal_seq value is not the same as the si_sys_private value
     which was set when the signal was queued.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h   |    2 --
 kernel/signal.c                |    2 +-
 kernel/time/posix-cpu-timers.c |    2 +-
 kernel/time/posix-timers.c     |   25 +++++++++++++++----------
 4 files changed, 17 insertions(+), 14 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -137,8 +137,6 @@ static inline void clear_posix_cputimers
 static inline void posix_cputimers_init_work(void) { }
 #endif
 
-#define REQUEUE_PENDING 1
-
 /**
  * struct k_itimer - POSIX.1b interval timer structure.
  * @list:		List head for binding the timer to signals->posix_timers
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -617,7 +617,7 @@ int dequeue_signal(sigset_t *mask, kerne
 	}
 
 	if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
-		if (unlikely(info->si_code == SI_TIMER && info->si_sys_private)) {
+		if (unlikely(info->si_code == SI_TIMER)) {
 			if (!posixtimer_deliver_signal(info))
 				goto again;
 		}
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -746,7 +746,7 @@ static void __posix_cpu_timer_get(struct
 	 *  - Timers which expired, but the signal has not yet been
 	 *    delivered
 	 */
-	if (iv && ((timer->it_signal_seq & REQUEUE_PENDING) || sigev_none))
+	if (iv && timer->it_status != POSIX_TIMER_ARMED)
 		expires = bump_cpu_timer(timer, now);
 	else
 		expires = cpu_timer_getexpires(&timer->it.cpu);
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -269,7 +269,10 @@ bool posixtimer_deliver_signal(struct ke
 	if (!timr)
 		goto out;
 
-	if (timr->it_interval && timr->it_signal_seq == info->si_sys_private) {
+	if (timr->it_signal_seq != info->si_sys_private)
+		goto out_unlock;
+
+	if (timr->it_interval && timr->it_status == POSIX_TIMER_REQUEUE_PENDING) {
 		timr->kclock->timer_rearm(timr);
 
 		timr->it_status = POSIX_TIMER_ARMED;
@@ -281,6 +284,7 @@ bool posixtimer_deliver_signal(struct ke
 	}
 	ret = true;
 
+out_unlock:
 	unlock_timer(timr, flags);
 out:
 	spin_lock(&current->sighand->siglock);
@@ -293,19 +297,19 @@ bool posixtimer_deliver_signal(struct ke
 int posix_timer_queue_signal(struct k_itimer *timr)
 {
 	enum posix_timer_state state = POSIX_TIMER_DISARMED;
-	int ret, si_private = 0;
 	enum pid_type type;
+	int ret;
 
 	lockdep_assert_held(&timr->it_lock);
 
 	if (timr->it_interval) {
+		timr->it_signal_seq++;
 		state = POSIX_TIMER_REQUEUE_PENDING;
-		si_private = ++timr->it_signal_seq;
 	}
 	timr->it_status = state;
 
 	type = !(timr->it_sigev_notify & SIGEV_THREAD_ID) ? PIDTYPE_TGID : PIDTYPE_PID;
-	ret = send_sigqueue(timr->sigq, timr->it_pid, type, si_private);
+	ret = send_sigqueue(timr->sigq, timr->it_pid, type, timr->it_signal_seq);
 	/* If we failed to send the signal the timer stops. */
 	return ret > 0;
 }
@@ -670,7 +674,7 @@ void common_timer_get(struct k_itimer *t
 	 * is a SIGEV_NONE timer move the expiry time forward by intervals,
 	 * so expiry is > now.
 	 */
-	if (iv && (timr->it_signal_seq & REQUEUE_PENDING || sig_none))
+	if (iv && timr->it_status != POSIX_TIMER_ARMED)
 		timr->it_overrun += kc->timer_forward(timr, now);
 
 	remaining = kc->timer_remaining(timr, now);
@@ -870,8 +874,6 @@ void posix_timer_set_common(struct k_iti
 	else
 		timer->it_interval = 0;
 
-	/* Prevent reloading in case there is a signal pending */
-	timer->it_signal_seq = (timer->it_signal_seq + 2) & ~REQUEUE_PENDING;
 	/* Reset overrun accounting */
 	timer->it_overrun_last = 0;
 	timer->it_overrun = -1LL;
@@ -889,8 +891,6 @@ int common_timer_set(struct k_itimer *ti
 	if (old_setting)
 		common_timer_get(timr, old_setting);
 
-	/* Prevent rearming by clearing the interval */
-	timr->it_interval = 0;
 	/*
 	 * Careful here. On SMP systems the timer expiry function could be
 	 * active and spinning on timr->it_lock.
@@ -940,6 +940,9 @@ static int do_timer_settime(timer_t time
 	if (old_spec64)
 		old_spec64->it_interval = ktime_to_timespec64(timr->it_interval);
 
+	/* Prevent signal delivery and rearming. */
+	timr->it_signal_seq++;
+
 	kc = timr->kclock;
 	if (WARN_ON_ONCE(!kc || !kc->timer_set))
 		error = -EINVAL;
@@ -1008,7 +1011,6 @@ int common_timer_del(struct k_itimer *ti
 {
 	const struct k_clock *kc = timer->kclock;
 
-	timer->it_interval = 0;
 	if (kc->timer_try_to_cancel(timer) < 0)
 		return TIMER_RETRY;
 	timer->it_status = POSIX_TIMER_DISARMED;
@@ -1036,6 +1038,9 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
 	if (!timer)
 		return -EINVAL;
 
+	/* Prevent signal delivery and rearming. */
+	timer->it_signal_seq++;
+
 	if (unlikely(timer_delete_hook(timer) == TIMER_RETRY)) {
 		/* Unlocks and relocks the timer if it still exists */
 		timer = timer_wait_running(timer, &flags);


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 33/50] posix-timers: Make signal overrun accounting sensible
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (31 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 32/50] posix-timers: Make signal delivery consistent Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 34/50] posix-cpu-timers: Use dedicated flag for CPU timer nanosleep Thomas Gleixner
                   ` (17 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

The handling of the timer overrun in the signal code is inconsistent as it
takes previous overruns into account. This is just wrong as after the
reprogramming of a timer the overrun count starts over from a clean state,
i.e. 0.

Make the accounting in send_sigqueue() consistent with that.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/signal.c |   34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1965,6 +1965,34 @@ int send_sigqueue(struct sigqueue *q, st
 	 */
 	q->info.si_sys_private = si_private;
 
+	/*
+	 * Set the overrun count to zero unconditionally. The posix timer
+	 * code does not self rearm periodic timers. They are rearmed from
+	 * dequeue_signal().
+	 *
+	 * But there is a situation where @q is already enqueued:
+	 *
+	 * 1) timer_settime()
+	 *      arm_timer()
+	 * 2) timer_expires()
+	 *      send_sigqueue(@q)
+	 *        enqueue(@q)
+	 * 3) timer_settime()
+	 *      arm_timer()
+	 * 4) timer_expires()
+	 *      send_sigqueue(@q) <- Observes @q already queued
+	 *
+	 * In this case incrementing si_overrun does not make sense because
+	 * there is no relationship between timer_settime() #1 and #2.
+	 *
+	 * The POSIX specification is useful as always: "The effect of
+	 * disarming or resetting a timer with pending expiration
+	 * notifications is unspecified."
+	 *
+	 * Just do the sensible thing and reset the overrun.
+	 */
+	q->info.si_overrun = 0;
+
 	ret = 1; /* the signal is ignored */
 	result = TRACE_SIGNAL_IGNORED;
 	if (!prepare_signal(sig, t, false))
@@ -1972,15 +2000,9 @@ int send_sigqueue(struct sigqueue *q, st
 
 	ret = 0;
 	if (unlikely(!list_empty(&q->list))) {
-		/*
-		 * If an SI_TIMER entry is already queue just increment
-		 * the overrun count.
-		 */
-		q->info.si_overrun++;
 		result = TRACE_SIGNAL_ALREADY_PENDING;
 		goto out;
 	}
-	q->info.si_overrun = 0;
 
 	signalfd_notify(t, sig);
 	pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 34/50] posix-cpu-timers: Use dedicated flag for CPU timer nanosleep
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (32 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 33/50] posix-timers: Make signal overrun accounting sensible Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 35/50] posix-timers: Add a refcount to struct k_itimer Thomas Gleixner
                   ` (16 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

POSIX CPU timer nanosleep creates a k_itimer on stack and uses the sigq
pointer to detect the nanosleep case in the expiry function.

Prepare for embedding sigqueue into struct k_itimer by using a dedicated
flag for nanosleep.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h   |    4 +++-
 kernel/time/posix-cpu-timers.c |    3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -42,6 +42,7 @@ static inline int clockid_to_fd(const cl
  * @pid:	Pointer to target task PID
  * @elist:	List head for the expiry list
  * @firing:	Timer is currently firing
+ * @nanosleep:	Timer is used for nanosleep and is not a regular posix-timer
  * @handling:	Pointer to the task which handles expiry
  */
 struct cpu_timer {
@@ -49,7 +50,8 @@ struct cpu_timer {
 	struct timerqueue_head		*head;
 	struct pid			*pid;
 	struct list_head		elist;
-	int				firing;
+	bool				firing;
+	bool				nanosleep;
 	struct task_struct __rcu	*handling;
 };
 
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -588,7 +588,7 @@ static void cpu_timer_fire(struct k_itim
 
 	timer->it_status = POSIX_TIMER_DISARMED;
 
-	if (unlikely(timer->sigq == NULL)) {
+	if (unlikely(ctmr->nanosleep)) {
 		/*
 		 * This a special case for clock_nanosleep,
 		 * not a normal timer from sys_timer_create.
@@ -1479,6 +1479,7 @@ static int do_cpu_nanosleep(const clocki
 	timer.it_overrun = -1;
 	error = posix_cpu_timer_create(&timer);
 	timer.it_process = current;
+	timer.it.cpu.nanosleep = true;
 
 	if (!error) {
 		static struct itimerspec64 zero_it;


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 35/50] posix-timers: Add a refcount to struct k_itimer
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (33 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 34/50] posix-cpu-timers: Use dedicated flag for CPU timer nanosleep Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 36/50] signal: Split up __sigqueue_alloc() Thomas Gleixner
                   ` (15 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

To cure the SIG_IGN handling for posix interval timers, the preallocated
sigqueue needs to be embedded into struct k_itimer to prevent life time
races of all sorts.

To make this work correctly this needs reference counting so that timer
deletion does not free the timer prematuraly when there is a signal queued
or delivered concurrently.

Add a rcuref to the posix timer part.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h |   14 ++++++++++++++
 kernel/time/posix-timers.c   |    7 ++++---
 2 files changed, 18 insertions(+), 3 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -6,11 +6,13 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/posix-timers_types.h>
+#include <linux/rcuref.h>
 #include <linux/spinlock.h>
 #include <linux/timerqueue.h>
 
 struct kernel_siginfo;
 struct task_struct;
+struct k_itimer;
 
 static inline clockid_t make_process_cpuclock(const unsigned int pid,
 		const clockid_t clock)
@@ -105,6 +107,7 @@ static inline void posix_cputimers_rt_wa
 
 void posixtimer_rearm_itimer(struct task_struct *p);
 bool posixtimer_deliver_signal(struct kernel_siginfo *info);
+void posixtimer_free_timer(struct k_itimer *timer);
 
 /* Init task static initializer */
 #define INIT_CPU_TIMERBASE(b) {						\
@@ -129,6 +132,7 @@ static inline void posix_cputimers_group
 					      u64 cpu_limit) { }
 static inline void posixtimer_rearm_itimer(struct task_struct *p) { }
 static inline bool posixtimer_deliver_signal(struct kernel_siginfo *info) { return false; }
+static inline void posixtimer_free_timer(struct k_itimer *timer) { }
 #endif
 
 #ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK
@@ -156,6 +160,7 @@ static inline void posix_cputimers_init_
  * @it_signal:		Pointer to the creators signal struct
  * @it_pid:		The pid of the process/task targeted by the signal
  * @it_process:		The task to wakeup on clock_nanosleep (CPU timers)
+ * @rcuref:		Reference count for life time management
  * @sigq:		Pointer to preallocated sigqueue
  * @it:			Union representing the various posix timer type
  *			internals.
@@ -180,6 +185,7 @@ struct k_itimer {
 		struct task_struct	*it_process;
 	};
 	struct sigqueue		*sigq;
+	rcuref_t		rcuref;
 	union {
 		struct {
 			struct hrtimer	timer;
@@ -200,4 +206,12 @@ void set_process_cpu_timer(struct task_s
 
 int update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
 
+#ifdef CONFIG_POSIX_TIMERS
+static inline void posixtimer_putref(struct k_itimer *tmr)
+{
+	if (rcuref_put(&tmr->rcuref))
+		posixtimer_free_timer(tmr);
+}
+#endif /* !CONFIG_POSIX_TIMERS */
+
 #endif
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -417,6 +417,7 @@ static struct k_itimer * alloc_posix_tim
 		return NULL;
 	}
 	clear_siginfo(&tmr->sigq->info);
+	rcuref_init(&tmr->rcuref, 1);
 	return tmr;
 }
 
@@ -427,7 +428,7 @@ static void k_itimer_rcu_free(struct rcu
 	kmem_cache_free(posix_timers_cache, tmr);
 }
 
-static void posix_timer_free(struct k_itimer *tmr)
+void posixtimer_free_timer(struct k_itimer *tmr)
 {
 	put_pid(tmr->it_pid);
 	sigqueue_free(tmr->sigq);
@@ -439,7 +440,7 @@ static void posix_timer_unhash_and_free(
 	spin_lock(&hash_lock);
 	hlist_del_rcu(&tmr->t_hash);
 	spin_unlock(&hash_lock);
-	posix_timer_free(tmr);
+	posixtimer_putref(tmr);
 }
 
 static int common_timer_create(struct k_itimer *new_timer)
@@ -474,7 +475,7 @@ static int do_timer_create(clockid_t whi
 	 */
 	new_timer_id = posix_timer_add(new_timer);
 	if (new_timer_id < 0) {
-		posix_timer_free(new_timer);
+		posixtimer_free_timer(new_timer);
 		return new_timer_id;
 	}
 


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 36/50] signal: Split up __sigqueue_alloc()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (34 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 35/50] posix-timers: Add a refcount to struct k_itimer Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 37/50] signal: Provide posixtimer_sigqueue_init() Thomas Gleixner
                   ` (14 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

To cure the SIG_IGN handling for posix interval timers, the preallocated
sigqueue needs to be embedded into struct k_itimer to prevent life time
races of all sorts.

Reorganize __sigqueue_alloc() so the ucounts retrieval and the
initialization can be used independently.

No functional change.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/signal.c |   52 +++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 35 insertions(+), 17 deletions(-)

--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -396,16 +396,9 @@ void task_join_group_stop(struct task_st
 	task_set_jobctl_pending(task, mask | JOBCTL_STOP_PENDING);
 }
 
-/*
- * allocate a new signal queue record
- * - this may be called without locks if and only if t == current, otherwise an
- *   appropriate lock must be held to stop the target task from exiting
- */
-static struct sigqueue *
-__sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags,
-		 int override_rlimit, const unsigned int sigqueue_flags)
+static struct ucounts *sig_get_ucounts(struct task_struct *t, int sig,
+				       int override_rlimit)
 {
-	struct sigqueue *q = NULL;
 	struct ucounts *ucounts;
 	long sigpending;
 
@@ -424,19 +417,44 @@ static struct sigqueue *
 	if (!sigpending)
 		return NULL;
 
-	if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
-		q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);
-	} else {
+	if (unlikely(!override_rlimit && sigpending > task_rlimit(t, RLIMIT_SIGPENDING))) {
+		dec_rlimit_put_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING);
 		print_dropped_signal(sig);
+		return NULL;
 	}
 
-	if (unlikely(q == NULL)) {
+	return ucounts;
+}
+
+static void __sigqueue_init(struct sigqueue *q, struct ucounts *ucounts,
+			    const unsigned int sigqueue_flags)
+{
+	INIT_LIST_HEAD(&q->list);
+	q->flags = sigqueue_flags;
+	q->ucounts = ucounts;
+}
+
+/*
+ * allocate a new signal queue record
+ * - this may be called without locks if and only if t == current, otherwise an
+ *   appropriate lock must be held to stop the target task from exiting
+ */
+static struct sigqueue *__sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags,
+					 int override_rlimit, const unsigned int sigqueue_flags)
+{
+	struct ucounts *ucounts = sig_get_ucounts(t, sig, override_rlimit);
+	struct sigqueue *q;
+
+	if (!ucounts)
+		return NULL;
+
+	q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);
+	if (!q) {
 		dec_rlimit_put_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING);
-	} else {
-		INIT_LIST_HEAD(&q->list);
-		q->flags = sigqueue_flags;
-		q->ucounts = ucounts;
+		return NULL;
 	}
+
+	__sigqueue_init(q, ucounts, sigqueue_flags);
 	return q;
 }
 


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 37/50] signal: Provide posixtimer_sigqueue_init()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (35 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 36/50] signal: Split up __sigqueue_alloc() Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 38/50] signal: Add sys_private_ptr to siginfo::_sifields::_timer Thomas Gleixner
                   ` (13 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

To cure the SIG_IGN handling for posix interval timers, the preallocated
sigqueue needs to be embedded into struct k_itimer to prevent life time
races of all sorts.

Provide a new function to initialize the embedded sigqueue to prepare for
that.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h |    2 ++
 kernel/signal.c              |   11 +++++++++++
 2 files changed, 13 insertions(+)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -12,6 +12,7 @@
 
 struct kernel_siginfo;
 struct task_struct;
+struct sigqueue;
 struct k_itimer;
 
 static inline clockid_t make_process_cpuclock(const unsigned int pid,
@@ -106,6 +107,7 @@ static inline void posix_cputimers_rt_wa
 }
 
 void posixtimer_rearm_itimer(struct task_struct *p);
+bool posixtimer_init_sigqueue(struct sigqueue *q);
 bool posixtimer_deliver_signal(struct kernel_siginfo *info);
 void posixtimer_free_timer(struct k_itimer *timer);
 
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1909,6 +1909,17 @@ void flush_itimer_signals(void)
 	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 }
 
+bool posixtimer_init_sigqueue(struct sigqueue *q)
+{
+	struct ucounts *ucounts = sig_get_ucounts(current, -1, 0);
+
+	if (!ucounts)
+		return false;
+	clear_siginfo(&q->info);
+	__sigqueue_init(q, ucounts, SIGQUEUE_PREALLOC);
+	return true;
+}
+
 struct sigqueue *sigqueue_alloc(void)
 {
 	return __sigqueue_alloc(-1, current, GFP_KERNEL, 0, SIGQUEUE_PREALLOC);


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 38/50] signal: Add sys_private_ptr to siginfo::_sifields::_timer
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (36 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 37/50] signal: Provide posixtimer_sigqueue_init() Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 39/50] posix-timers: Store PID type in the timer Thomas Gleixner
                   ` (12 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

On signal delivery collect_signal() copies the queued siginfo into a caller
provided siginfo struct. The posix timer signal delivery code then uses
siginfo::si_tid to lookup the timer in the hash table.

That's required today as the timer and the sigqueue are separate entities
and have different life time rules.

The sigqueue will be embedded into struct k_itimer to address a few issues
in the posix timer signal handling, which means the life time rules are
not longer separate, which can spare the lookup.

Due to locking rules posixtimer_deliver_signal() cannot be invoked from
collect_signal(). The timer pointer could be handed down from
collect_signal() to dequeue_signal(), but that's just overhead for the
non-posixtimer case.

There is room in the _sifields union for an extra pointer which will be
used later for storing the timer pointer. This field is copied with siginfo
and cleared before the info is delivered to userspace like the existing
si_sys_private field.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/kernel/signal_32.c        |    2 +-
 arch/x86/kernel/signal_64.c        |    2 +-
 include/uapi/asm-generic/siginfo.h |    2 ++
 kernel/time/posix-timers.c         |    4 +++-
 4 files changed, 7 insertions(+), 3 deletions(-)

--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -456,7 +456,7 @@ CHECK_SI_OFFSET(_timer);
 /* compat_siginfo_t doesn't have si_sys_private */
 CHECK_SI_SIZE  (_timer, 3*sizeof(int));
 #else
-CHECK_SI_SIZE  (_timer, 4*sizeof(int));
+CHECK_SI_SIZE  (_timer, 5*sizeof(int));
 #endif
 static_assert(offsetof(siginfo32_t, si_tid)     == 0x0C);
 static_assert(offsetof(siginfo32_t, si_overrun) == 0x10);
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -456,7 +456,7 @@ static_assert(offsetof(siginfo_t, si_pid
 static_assert(offsetof(siginfo_t, si_uid) == 0x14);
 
 CHECK_SI_OFFSET(_timer);
-CHECK_SI_SIZE  (_timer, 6*sizeof(int));
+CHECK_SI_SIZE  (_timer, 8*sizeof(int));
 static_assert(offsetof(siginfo_t, si_tid)     == 0x10);
 static_assert(offsetof(siginfo_t, si_overrun) == 0x14);
 static_assert(offsetof(siginfo_t, si_value)   == 0x18);
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -47,6 +47,7 @@ union __sifields {
 		int _overrun;		/* overrun count */
 		sigval_t _sigval;	/* same as below */
 		int _sys_private;       /* not to be passed to user */
+		void *_sys_privptr;	/* not to be passed to user */
 	} _timer;
 
 	/* POSIX.1b signals */
@@ -146,6 +147,7 @@ typedef struct siginfo {
 #define si_tid		_sifields._timer._tid
 #define si_overrun	_sifields._timer._overrun
 #define si_sys_private  _sifields._timer._sys_private
+#define si_sys_privptr  _sifields._timer._sys_privptr
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -289,8 +289,9 @@ bool posixtimer_deliver_signal(struct ke
 out:
 	spin_lock(&current->sighand->siglock);
 
-	/* Don't expose the si_sys_private value to userspace */
+	/* Don't expose the si_sys_priv* values to userspace */
 	info->si_sys_private = 0;
+	info->si_sys_privptr = NULL;
 	return ret;
 }
 
@@ -505,6 +506,7 @@ static int do_timer_create(clockid_t whi
 
 	new_timer->sigq->info.si_tid   = new_timer->it_id;
 	new_timer->sigq->info.si_code  = SI_TIMER;
+	new_timer->sigq->info.si_sys_privptr  = new_timer;
 
 	if (copy_to_user(created_timer_id, &new_timer_id, sizeof (new_timer_id))) {
 		error = -EFAULT;


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 39/50] posix-timers: Store PID type in the timer
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (37 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 38/50] signal: Add sys_private_ptr to siginfo::_sifields::_timer Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 40/50] signal: Refactor send_sigqueue() Thomas Gleixner
                   ` (11 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

instead of re-evaluating the signal delivery mode everywhere.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h |    2 ++
 kernel/time/posix-timers.c   |    9 ++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -5,6 +5,7 @@
 #include <linux/alarmtimer.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/pid.h>
 #include <linux/posix-timers_types.h>
 #include <linux/rcuref.h>
 #include <linux/spinlock.h>
@@ -180,6 +181,7 @@ struct k_itimer {
 	s64			it_overrun_last;
 	unsigned int		it_signal_seq;
 	int			it_sigev_notify;
+	enum pid_type		it_pid_type;
 	ktime_t			it_interval;
 	struct signal_struct	*it_signal;
 	union {
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -298,7 +298,6 @@ bool posixtimer_deliver_signal(struct ke
 int posix_timer_queue_signal(struct k_itimer *timr)
 {
 	enum posix_timer_state state = POSIX_TIMER_DISARMED;
-	enum pid_type type;
 	int ret;
 
 	lockdep_assert_held(&timr->it_lock);
@@ -309,8 +308,7 @@ int posix_timer_queue_signal(struct k_it
 	}
 	timr->it_status = state;
 
-	type = !(timr->it_sigev_notify & SIGEV_THREAD_ID) ? PIDTYPE_TGID : PIDTYPE_PID;
-	ret = send_sigqueue(timr->sigq, timr->it_pid, type, timr->it_signal_seq);
+	ret = send_sigqueue(timr->sigq, timr->it_pid, timr->it_pid_type, timr->it_signal_seq);
 	/* If we failed to send the signal the timer stops. */
 	return ret > 0;
 }
@@ -504,6 +502,11 @@ static int do_timer_create(clockid_t whi
 		new_timer->it_pid = get_pid(task_tgid(current));
 	}
 
+	if (new_timer->it_sigev_notify & SIGEV_THREAD_ID)
+		new_timer->it_pid_type = PIDTYPE_PID;
+	else
+		new_timer->it_pid_type = PIDTYPE_TGID;
+
 	new_timer->sigq->info.si_tid   = new_timer->it_id;
 	new_timer->sigq->info.si_code  = SI_TIMER;
 	new_timer->sigq->info.si_sys_privptr  = new_timer;


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 40/50] signal: Refactor send_sigqueue()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (38 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 39/50] posix-timers: Store PID type in the timer Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 41/50] posix-timers: Embed sigqueue in struct k_itimer Thomas Gleixner
                   ` (10 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

To handle posix timers which have their signal ignored via SIG_IGN properly
its required to requeue a ignored signal for delivery when SIG_IGN is
lifted so the timer gets rearmed.

Split the required code out of send_sigqueue() so it can be reused in
context of sigaction().

While at it rename send_sigqueue() to posixtimer_send_sigqueue() so its
clear what this is about.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h |    1 
 include/linux/sched/signal.h |    1 
 kernel/signal.c              |   73 ++++++++++++++++++++++++-------------------
 kernel/time/posix-timers.c   |    2 -
 4 files changed, 44 insertions(+), 33 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -109,6 +109,7 @@ static inline void posix_cputimers_rt_wa
 
 void posixtimer_rearm_itimer(struct task_struct *p);
 bool posixtimer_init_sigqueue(struct sigqueue *q);
+int posixtimer_send_sigqueue(struct k_itimer *tmr);
 bool posixtimer_deliver_signal(struct kernel_siginfo *info);
 void posixtimer_free_timer(struct k_itimer *timer);
 
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -339,7 +339,6 @@ extern int send_sig(int, struct task_str
 extern int zap_other_threads(struct task_struct *p);
 extern struct sigqueue *sigqueue_alloc(void);
 extern void sigqueue_free(struct sigqueue *);
-extern int send_sigqueue(struct sigqueue *, struct pid *, enum pid_type, int si_private);
 extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
 
 static inline void clear_notify_signal(void)
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1951,38 +1951,53 @@ void sigqueue_free(struct sigqueue *q)
 		__sigqueue_free(q);
 }
 
-int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type, int si_private)
+static void posixtimer_queue_sigqueue(struct sigqueue *q, struct task_struct *t, enum pid_type type)
 {
-	int sig = q->info.si_signo;
 	struct sigpending *pending;
+	int sig = q->info.si_signo;
+
+	signalfd_notify(t, sig);
+	pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
+	list_add_tail(&q->list, &pending->list);
+	sigaddset(&pending->signal, sig);
+	complete_signal(sig, t, type);
+}
+
+/*
+ * This function is used by POSIX timers to deliver a timer signal.
+ * Where type is PIDTYPE_PID (such as for timers with SIGEV_THREAD_ID
+ * set), the signal must be delivered to the specific thread (queues
+ * into t->pending).
+ *
+ * Where type is not PIDTYPE_PID, signals must be delivered to the
+ * process. In this case, prefer to deliver to current if it is in
+ * the same thread group as the target process, which avoids
+ * unnecessarily waking up a potentially idle task.
+ */
+static inline struct task_struct *posixtimer_get_target(struct k_itimer *tmr)
+{
+	struct task_struct *t = pid_task(tmr->it_pid, tmr->it_pid_type);
+
+	if (t && tmr->it_pid_type != PIDTYPE_PID && same_thread_group(t, current))
+		t = current;
+	return t;
+}
+
+int posixtimer_send_sigqueue(struct k_itimer *tmr)
+{
+	struct sigqueue *q = tmr->sigq;
+	int sig = q->info.si_signo;
 	struct task_struct *t;
 	unsigned long flags;
 	int ret, result;
 
-	if (WARN_ON_ONCE(!(q->flags & SIGQUEUE_PREALLOC)))
-		return 0;
-	if (WARN_ON_ONCE(q->info.si_code != SI_TIMER))
-		return 0;
-
 	ret = -1;
 	rcu_read_lock();
 
-	/*
-	 * This function is used by POSIX timers to deliver a timer signal.
-	 * Where type is PIDTYPE_PID (such as for timers with SIGEV_THREAD_ID
-	 * set), the signal must be delivered to the specific thread (queues
-	 * into t->pending).
-	 *
-	 * Where type is not PIDTYPE_PID, signals must be delivered to the
-	 * process. In this case, prefer to deliver to current if it is in
-	 * the same thread group as the target process, which avoids
-	 * unnecessarily waking up a potentially idle task.
-	 */
-	t = pid_task(pid, type);
+	t = posixtimer_get_target(tmr);
 	if (!t)
 		goto ret;
-	if (type != PIDTYPE_PID && same_thread_group(t, current))
-		t = current;
+
 	if (!likely(lock_task_sighand(t, &flags)))
 		goto ret;
 
@@ -1992,7 +2007,7 @@ int send_sigqueue(struct sigqueue *q, st
 	 * decides based on si_sys_private whether to invoke
 	 * posixtimer_rearm() or not.
 	 */
-	q->info.si_sys_private = si_private;
+	q->info.si_sys_private = tmr->it_signal_seq;
 
 	/*
 	 * Set the overrun count to zero unconditionally. The posix timer
@@ -2023,24 +2038,20 @@ int send_sigqueue(struct sigqueue *q, st
 	q->info.si_overrun = 0;
 
 	ret = 1; /* the signal is ignored */
-	result = TRACE_SIGNAL_IGNORED;
-	if (!prepare_signal(sig, t, false))
+	if (!prepare_signal(sig, t, false)) {
+		result = TRACE_SIGNAL_IGNORED;
 		goto out;
+	}
 
 	ret = 0;
 	if (unlikely(!list_empty(&q->list))) {
 		result = TRACE_SIGNAL_ALREADY_PENDING;
 		goto out;
 	}
-
-	signalfd_notify(t, sig);
-	pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
-	list_add_tail(&q->list, &pending->list);
-	sigaddset(&pending->signal, sig);
-	complete_signal(sig, t, type);
+	posixtimer_queue_sigqueue(q, t, tmr->it_pid_type);
 	result = TRACE_SIGNAL_DELIVERED;
 out:
-	trace_signal_generate(sig, &q->info, t, type != PIDTYPE_PID, result);
+	trace_signal_generate(sig, &q->info, t, tmr->it_pid_type != PIDTYPE_PID, result);
 	unlock_task_sighand(t, &flags);
 ret:
 	rcu_read_unlock();
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -308,7 +308,7 @@ int posix_timer_queue_signal(struct k_it
 	}
 	timr->it_status = state;
 
-	ret = send_sigqueue(timr->sigq, timr->it_pid, timr->it_pid_type, timr->it_signal_seq);
+	ret = posixtimer_send_sigqueue(timr);
 	/* If we failed to send the signal the timer stops. */
 	return ret > 0;
 }


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 41/50] posix-timers: Embed sigqueue in struct k_itimer
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (39 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 40/50] signal: Refactor send_sigqueue() Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 42/50] signal: Cleanup unused posix-timer leftovers Thomas Gleixner
                   ` (9 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

To cure the SIG_IGN handling for posix interval timers, the preallocated
sigqueue needs to be embedded into struct k_itimer to prevent life time
races of all sorts.

Now that the prerequisites are in place, embed the sigqueue into struct
k_itimer and fixup the relevant usage sites.

Aside of preparing for proper SIG_IGN handling, this spares an extra
allocation.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 fs/proc/base.c               |    4 +-
 include/linux/posix-timers.h |   23 +++++++++++++++-
 kernel/signal.c              |   12 +++++++-
 kernel/time/posix-timers.c   |   59 ++++++++++++++++++++++++++-----------------
 4 files changed, 69 insertions(+), 29 deletions(-)

--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2496,8 +2496,8 @@ static int show_timer(struct seq_file *m
 
 	seq_printf(m, "ID: %d\n", timer->it_id);
 	seq_printf(m, "signal: %d/%px\n",
-		   timer->sigq->info.si_signo,
-		   timer->sigq->info.si_value.sival_ptr);
+		   timer->sigq.info.si_signo,
+		   timer->sigq.info.si_value.sival_ptr);
 	seq_printf(m, "notify: %s/%s.%d\n",
 		   nstr[notify & ~SIGEV_THREAD_ID],
 		   (notify & SIGEV_THREAD_ID) ? "tid" : "pid",
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -39,6 +39,8 @@ static inline int clockid_to_fd(const cl
 
 #ifdef CONFIG_POSIX_TIMERS
 
+#include <linux/signal_types.h>
+
 /**
  * cpu_timer - Posix CPU timer representation for k_itimer
  * @node:	timerqueue node to queue in the task/sig
@@ -165,7 +167,7 @@ static inline void posix_cputimers_init_
  * @it_pid:		The pid of the process/task targeted by the signal
  * @it_process:		The task to wakeup on clock_nanosleep (CPU timers)
  * @rcuref:		Reference count for life time management
- * @sigq:		Pointer to preallocated sigqueue
+ * @sigq:		Embedded sigqueue
  * @it:			Union representing the various posix timer type
  *			internals.
  * @rcu:		RCU head for freeing the timer.
@@ -189,7 +191,7 @@ struct k_itimer {
 		struct pid		*it_pid;
 		struct task_struct	*it_process;
 	};
-	struct sigqueue		*sigq;
+	struct sigqueue		sigq;
 	rcuref_t		rcuref;
 	union {
 		struct {
@@ -217,6 +219,23 @@ static inline void posixtimer_putref(str
 	if (rcuref_put(&tmr->rcuref))
 		posixtimer_free_timer(tmr);
 }
+
+static inline void posixtimer_sigqueue_getref(struct sigqueue *q)
+{
+	struct k_itimer *tmr = container_of(q, struct k_itimer, sigq);
+
+	WARN_ON_ONCE(!rcuref_get(&tmr->rcuref));
+}
+
+static inline void posixtimer_sigqueue_putref(struct sigqueue *q)
+{
+	struct k_itimer *tmr = container_of(q, struct k_itimer, sigq);
+
+	posixtimer_putref(tmr);
+}
+#else  /* CONFIG_POSIX_TIMERS */
+static inline void posixtimer_sigqueue_getref(struct sigqueue *q) { }
+static inline void posixtimer_sigqueue_putref(struct sigqueue *q) { }
 #endif /* !CONFIG_POSIX_TIMERS */
 
 #endif
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -566,7 +566,12 @@ static void collect_signal(int sig, stru
 still_pending:
 		list_del_init(&first->list);
 		copy_siginfo(info, &first->info);
-		__sigqueue_free(first);
+		/*
+		 * Do not drop the reference count for posix timer
+		 * signals. That's done in posix_timer_deliver_signal().
+		 */
+		if (info->si_code != SI_TIMER)
+			__sigqueue_free(first);
 	} else {
 		/*
 		 * Ok, it wasn't in the queue.  This must be
@@ -1985,7 +1990,7 @@ static inline struct task_struct *posixt
 
 int posixtimer_send_sigqueue(struct k_itimer *tmr)
 {
-	struct sigqueue *q = tmr->sigq;
+	struct sigqueue *q = &tmr->sigq;
 	int sig = q->info.si_signo;
 	struct task_struct *t;
 	unsigned long flags;
@@ -2045,9 +2050,12 @@ int posixtimer_send_sigqueue(struct k_it
 
 	ret = 0;
 	if (unlikely(!list_empty(&q->list))) {
+		/* This holds a reference count already */
 		result = TRACE_SIGNAL_ALREADY_PENDING;
 		goto out;
 	}
+
+	posixtimer_sigqueue_getref(q);
 	posixtimer_queue_sigqueue(q, t, tmr->it_pid_type);
 	result = TRACE_SIGNAL_DELIVERED;
 out:
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -251,12 +251,13 @@ static void common_hrtimer_rearm(struct
 
 /*
  * This function is called from the signal delivery code. It decides
- * whether the signal should be dropped and rearms interval timers.
+ * whether the signal should be dropped and rearms interval timers.  The
+ * timer can be unconditionally accessed as there is a reference held on
+ * it.
  */
 bool posixtimer_deliver_signal(struct kernel_siginfo *info)
 {
-	struct k_itimer *timr;
-	unsigned long flags;
+	struct k_itimer *timr = info->si_sys_privptr;
 	bool ret = false;
 
 	/*
@@ -264,12 +265,14 @@ bool posixtimer_deliver_signal(struct ke
 	 * timr::it_lock. Keep interrupts disabled.
 	 */
 	spin_unlock(&current->sighand->siglock);
+	spin_lock(&timr->it_lock);
 
-	timr = lock_timer(info->si_tid, &flags);
-	if (!timr)
-		goto out;
-
-	if (timr->it_signal_seq != info->si_sys_private)
+	/*
+	 * Check if the timer is still alive or whether it got modified
+	 * since the signal was queued. In either case, don't rearm and
+	 * drop the signal.
+	 */
+	if (!timr->it_signal || timr->it_signal_seq != info->si_sys_private)
 		goto out_unlock;
 
 	if (timr->it_interval && timr->it_status == POSIX_TIMER_REQUEUE_PENDING) {
@@ -285,8 +288,10 @@ bool posixtimer_deliver_signal(struct ke
 	ret = true;
 
 out_unlock:
-	unlock_timer(timr, flags);
-out:
+	spin_unlock(&timr->it_lock);
+	/* Drop the reference which was acquired when the signal was queued */
+	posixtimer_putref(timr);
+
 	spin_lock(&current->sighand->siglock);
 
 	/* Don't expose the si_sys_priv* values to userspace */
@@ -405,17 +410,17 @@ static struct pid *good_sigevent(sigeven
 	}
 }
 
-static struct k_itimer * alloc_posix_timer(void)
+static struct k_itimer *alloc_posix_timer(void)
 {
 	struct k_itimer *tmr = kmem_cache_zalloc(posix_timers_cache, GFP_KERNEL);
 
 	if (!tmr)
 		return tmr;
-	if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
+
+	if (unlikely(!posixtimer_init_sigqueue(&tmr->sigq))) {
 		kmem_cache_free(posix_timers_cache, tmr);
 		return NULL;
 	}
-	clear_siginfo(&tmr->sigq->info);
 	rcuref_init(&tmr->rcuref, 1);
 	return tmr;
 }
@@ -430,7 +435,8 @@ static void k_itimer_rcu_free(struct rcu
 void posixtimer_free_timer(struct k_itimer *tmr)
 {
 	put_pid(tmr->it_pid);
-	sigqueue_free(tmr->sigq);
+	if (tmr->sigq.ucounts)
+		dec_rlimit_put_ucounts(tmr->sigq.ucounts, UCOUNT_RLIMIT_SIGPENDING);
 	call_rcu(&tmr->rcu, k_itimer_rcu_free);
 }
 
@@ -492,13 +498,13 @@ static int do_timer_create(clockid_t whi
 			goto out;
 		}
 		new_timer->it_sigev_notify     = event->sigev_notify;
-		new_timer->sigq->info.si_signo = event->sigev_signo;
-		new_timer->sigq->info.si_value = event->sigev_value;
+		new_timer->sigq.info.si_signo = event->sigev_signo;
+		new_timer->sigq.info.si_value = event->sigev_value;
 	} else {
 		new_timer->it_sigev_notify     = SIGEV_SIGNAL;
-		new_timer->sigq->info.si_signo = SIGALRM;
-		memset(&new_timer->sigq->info.si_value, 0, sizeof(sigval_t));
-		new_timer->sigq->info.si_value.sival_int = new_timer->it_id;
+		new_timer->sigq.info.si_signo = SIGALRM;
+		memset(&new_timer->sigq.info.si_value, 0, sizeof(sigval_t));
+		new_timer->sigq.info.si_value.sival_int = new_timer->it_id;
 		new_timer->it_pid = get_pid(task_tgid(current));
 	}
 
@@ -507,9 +513,9 @@ static int do_timer_create(clockid_t whi
 	else
 		new_timer->it_pid_type = PIDTYPE_TGID;
 
-	new_timer->sigq->info.si_tid   = new_timer->it_id;
-	new_timer->sigq->info.si_code  = SI_TIMER;
-	new_timer->sigq->info.si_sys_privptr  = new_timer;
+	new_timer->sigq.info.si_tid = new_timer->it_id;
+	new_timer->sigq.info.si_code = SI_TIMER;
+	new_timer->sigq.info.si_sys_privptr = new_timer;
 
 	if (copy_to_user(created_timer_id, &new_timer_id, sizeof (new_timer_id))) {
 		error = -EFAULT;
@@ -593,7 +599,14 @@ static struct k_itimer *__lock_timer(tim
 	 *  1) Set timr::it_signal to NULL with timr::it_lock held
 	 *  2) Release timr::it_lock
 	 *  3) Remove from the hash under hash_lock
-	 *  4) Call RCU for removal after the grace period
+	 *  4) Put the reference count.
+	 *
+	 * The reference count might not drop to zero if timr::sigq is
+	 * queued. In that case the signal delivery or flush will put the
+	 * last reference count.
+	 *
+	 * When the reference count reaches zero, the timer is scheduled
+	 * for RCU removal after the grace period.
 	 *
 	 * Holding rcu_read_lock() accross the lookup ensures that
 	 * the timer cannot be freed.


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 42/50] signal: Cleanup unused posix-timer leftovers
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (40 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 41/50] posix-timers: Embed sigqueue in struct k_itimer Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 43/50] signal: Add task argument to flush_sigqueue_mask() Thomas Gleixner
                   ` (8 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Remove the leftovers of sigqueue preallocation as it's not longer used.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/sched/signal.h |    2 --
 kernel/signal.c              |   43 +++++++------------------------------------
 2 files changed, 7 insertions(+), 38 deletions(-)

--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -337,8 +337,6 @@ extern void force_fatal_sig(int);
 extern void force_exit_sig(int);
 extern int send_sig(int, struct task_struct *, int);
 extern int zap_other_threads(struct task_struct *p);
-extern struct sigqueue *sigqueue_alloc(void);
-extern void sigqueue_free(struct sigqueue *);
 extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
 
 static inline void clear_notify_signal(void)
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -439,8 +439,8 @@ static void __sigqueue_init(struct sigqu
  * - this may be called without locks if and only if t == current, otherwise an
  *   appropriate lock must be held to stop the target task from exiting
  */
-static struct sigqueue *__sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags,
-					 int override_rlimit, const unsigned int sigqueue_flags)
+static struct sigqueue *sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags,
+				       int override_rlimit)
 {
 	struct ucounts *ucounts = sig_get_ucounts(t, sig, override_rlimit);
 	struct sigqueue *q;
@@ -454,14 +454,16 @@ static struct sigqueue *__sigqueue_alloc
 		return NULL;
 	}
 
-	__sigqueue_init(q, ucounts, sigqueue_flags);
+	__sigqueue_init(q, ucounts, 0);
 	return q;
 }
 
 static void __sigqueue_free(struct sigqueue *q)
 {
-	if (q->flags & SIGQUEUE_PREALLOC)
+	if (q->flags & SIGQUEUE_PREALLOC) {
+		posixtimer_sigqueue_putref(q);
 		return;
+	}
 	if (q->ucounts) {
 		dec_rlimit_put_ucounts(q->ucounts, UCOUNT_RLIMIT_SIGPENDING);
 		q->ucounts = NULL;
@@ -1065,7 +1067,7 @@ static int __send_signal_locked(int sig,
 	else
 		override_rlimit = 0;
 
-	q = __sigqueue_alloc(sig, t, GFP_ATOMIC, override_rlimit, 0);
+	q = sigqueue_alloc(sig, t, GFP_ATOMIC, override_rlimit);
 
 	if (q) {
 		list_add_tail(&q->list, &pending->list);
@@ -1925,37 +1927,6 @@ bool posixtimer_init_sigqueue(struct sig
 	return true;
 }
 
-struct sigqueue *sigqueue_alloc(void)
-{
-	return __sigqueue_alloc(-1, current, GFP_KERNEL, 0, SIGQUEUE_PREALLOC);
-}
-
-void sigqueue_free(struct sigqueue *q)
-{
-	spinlock_t *lock = &current->sighand->siglock;
-	unsigned long flags;
-
-	if (WARN_ON_ONCE(!(q->flags & SIGQUEUE_PREALLOC)))
-		return;
-	/*
-	 * We must hold ->siglock while testing q->list
-	 * to serialize with collect_signal() or with
-	 * __exit_signal()->flush_sigqueue().
-	 */
-	spin_lock_irqsave(lock, flags);
-	q->flags &= ~SIGQUEUE_PREALLOC;
-	/*
-	 * If it is queued it will be freed when dequeued,
-	 * like the "regular" sigqueue.
-	 */
-	if (!list_empty(&q->list))
-		q = NULL;
-	spin_unlock_irqrestore(lock, flags);
-
-	if (q)
-		__sigqueue_free(q);
-}
-
 static void posixtimer_queue_sigqueue(struct sigqueue *q, struct task_struct *t, enum pid_type type)
 {
 	struct sigpending *pending;


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 43/50] signal: Add task argument to flush_sigqueue_mask()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (41 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 42/50] signal: Cleanup unused posix-timer leftovers Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 44/50] signal: Provide ignored_posix_timers list Thomas Gleixner
                   ` (7 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

To prepare for handling posix timer signals on sigaction(SIG_IGN) properly,
add a task argument to flush_sigqueue_mask() and fixup all call sites.

This argument will be used in a later step to enqueue posix timers on an
ignored list, so their signal can be requeued when SIG_IGN is lifted later
on.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/signal.c |   19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -724,11 +724,10 @@ void signal_wake_up_state(struct task_st
 
 /*
  * Remove signals in mask from the pending set and queue.
- * Returns 1 if any signals were found.
  *
  * All callers must be holding the siglock.
  */
-static void flush_sigqueue_mask(sigset_t *mask, struct sigpending *s)
+static void flush_sigqueue_mask(sigset_t *mask, struct sigpending *s, struct task_struct *ptmr_tsk)
 {
 	struct sigqueue *q, *n;
 	sigset_t m;
@@ -866,18 +865,18 @@ static bool prepare_signal(int sig, stru
 		 * This is a stop signal.  Remove SIGCONT from all queues.
 		 */
 		siginitset(&flush, sigmask(SIGCONT));
-		flush_sigqueue_mask(&flush, &signal->shared_pending);
+		flush_sigqueue_mask(&flush, &signal->shared_pending, NULL);
 		for_each_thread(p, t)
-			flush_sigqueue_mask(&flush, &t->pending);
+			flush_sigqueue_mask(&flush, &t->pending, NULL);
 	} else if (sig == SIGCONT) {
 		unsigned int why;
 		/*
 		 * Remove all stop signals from all queues, wake all threads.
 		 */
 		siginitset(&flush, SIG_KERNEL_STOP_MASK);
-		flush_sigqueue_mask(&flush, &signal->shared_pending);
+		flush_sigqueue_mask(&flush, &signal->shared_pending, NULL);
 		for_each_thread(p, t) {
-			flush_sigqueue_mask(&flush, &t->pending);
+			flush_sigqueue_mask(&flush, &t->pending, NULL);
 			task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING);
 			if (likely(!(t->ptrace & PT_SEIZED))) {
 				t->jobctl &= ~JOBCTL_STOPPED;
@@ -4155,8 +4154,8 @@ void kernel_sigaction(int sig, __sighand
 		sigemptyset(&mask);
 		sigaddset(&mask, sig);
 
-		flush_sigqueue_mask(&mask, &current->signal->shared_pending);
-		flush_sigqueue_mask(&mask, &current->pending);
+		flush_sigqueue_mask(&mask, &current->signal->shared_pending, NULL);
+		flush_sigqueue_mask(&mask, &current->pending, NULL);
 		recalc_sigpending();
 	}
 	spin_unlock_irq(&current->sighand->siglock);
@@ -4223,9 +4222,9 @@ int do_sigaction(int sig, struct k_sigac
 		if (sig_handler_ignored(sig_handler(p, sig), sig)) {
 			sigemptyset(&mask);
 			sigaddset(&mask, sig);
-			flush_sigqueue_mask(&mask, &p->signal->shared_pending);
+			flush_sigqueue_mask(&mask, &p->signal->shared_pending, NULL);
 			for_each_thread(p, t)
-				flush_sigqueue_mask(&mask, &t->pending);
+				flush_sigqueue_mask(&mask, &t->pending, NULL);
 		}
 	}
 


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 44/50] signal: Provide ignored_posix_timers list
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (42 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 43/50] signal: Add task argument to flush_sigqueue_mask() Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 45/50] posix-timers: Handle ignored list on delete and exit Thomas Gleixner
                   ` (6 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

To prepare for handling posix timer signals on sigaction(SIG_IGN) properly,
add a list to task::signal.

This list will be used to queue posix timers so their signal can be
requeued when SIG_IGN is lifted later.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/sched/signal.h |    1 +
 init/init_task.c             |    5 +++--
 kernel/fork.c                |    1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -138,6 +138,7 @@ struct signal_struct {
 	/* POSIX.1b Interval Timers */
 	unsigned int		next_posix_timer_id;
 	struct hlist_head	posix_timers;
+	struct hlist_head	ignored_posix_timers;
 
 	/* ITIMER_REAL timer for the process */
 	struct hrtimer real_timer;
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -29,8 +29,9 @@ static struct signal_struct init_signals
 	.cred_guard_mutex = __MUTEX_INITIALIZER(init_signals.cred_guard_mutex),
 	.exec_update_lock = __RWSEM_INITIALIZER(init_signals.exec_update_lock),
 #ifdef CONFIG_POSIX_TIMERS
-	.posix_timers	= HLIST_HEAD_INIT,
-	.cputimer	= {
+	.posix_timers		= HLIST_HEAD_INIT,
+	.ignored_posix_timers	= HLIST_HEAD_INIT,
+	.cputimer		= {
 		.cputime_atomic	= INIT_CPUTIME_ATOMIC,
 	},
 #endif
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1877,6 +1877,7 @@ static int copy_signal(unsigned long clo
 
 #ifdef CONFIG_POSIX_TIMERS
 	INIT_HLIST_HEAD(&sig->posix_timers);
+	INIT_HLIST_HEAD(&sig->ignored_posix_timers);
 	hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	sig->real_timer.function = it_real_fn;
 #endif


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 45/50] posix-timers: Handle ignored list on delete and exit
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (43 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 44/50] signal: Provide ignored_posix_timers list Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 46/50] signal: Handle ignored signals in do_sigaction(action != SIG_IGN) Thomas Gleixner
                   ` (5 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

To handle posix timer signals on sigaction(SIG_IGN) properly, the timers
will be queued on a separate ignored list.

Add the necessary cleanup code for timer_delete() and exit_itimers().

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h |    4 +++-
 kernel/time/posix-timers.c   |   20 ++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -151,7 +151,8 @@ static inline void posix_cputimers_init_
 
 /**
  * struct k_itimer - POSIX.1b interval timer structure.
- * @list:		List head for binding the timer to signals->posix_timers
+ * @list:		List node for binding the timer to tsk::signal::posix_timers
+ * @ignored_list:	List node for tracking ignored timers in tsk::signal::ignored_posix_timers
  * @t_hash:		Entry in the posix timer hash table
  * @it_lock:		Lock protecting the timer
  * @kclock:		Pointer to the k_clock struct handling this timer
@@ -174,6 +175,7 @@ static inline void posix_cputimers_init_
  */
 struct k_itimer {
 	struct hlist_node	list;
+	struct hlist_node	ignored_list;
 	struct hlist_node	t_hash;
 	spinlock_t		it_lock;
 	const struct k_clock	*kclock;
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -1036,6 +1036,18 @@ int common_timer_del(struct k_itimer *ti
 	return 0;
 }
 
+/*
+ * If the deleted timer is on the ignored list, remove it and
+ * drop the associated reference.
+ */
+static inline void posix_timer_cleanup_ignored(struct k_itimer *tmr)
+{
+	if (!hlist_unhashed(&tmr->ignored_list)) {
+		hlist_del_init(&tmr->ignored_list);
+		posixtimer_putref(tmr);
+	}
+}
+
 static inline int timer_delete_hook(struct k_itimer *timer)
 {
 	const struct k_clock *kc = timer->kclock;
@@ -1068,6 +1080,7 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
 
 	spin_lock(&current->sighand->siglock);
 	hlist_del(&timer->list);
+	posix_timer_cleanup_ignored(timer);
 	spin_unlock(&current->sighand->siglock);
 	/*
 	 * A concurrent lookup could check timer::it_signal lockless. It
@@ -1119,6 +1132,8 @@ static void itimer_delete(struct k_itime
 	}
 	hlist_del(&timer->list);
 
+	posix_timer_cleanup_ignored(timer);
+
 	/*
 	 * Setting timer::it_signal to NULL is technically not required
 	 * here as nothing can access the timer anymore legitimately via
@@ -1151,6 +1166,11 @@ void exit_itimers(struct task_struct *ts
 	/* The timers are not longer accessible via tsk::signal */
 	while (!hlist_empty(&timers))
 		itimer_delete(hlist_entry(timers.first, struct k_itimer, list));
+
+	/* Mop up timers which are on the ignored list */
+	hlist_move_list(&tsk->signal->ignored_posix_timers, &timers);
+	while (!hlist_empty(&timers))
+		posix_timer_cleanup_ignored(hlist_entry(timers.first, struct k_itimer, list));
 }
 
 SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 46/50] signal: Handle ignored signals in do_sigaction(action != SIG_IGN)
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (44 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 45/50] posix-timers: Handle ignored list on delete and exit Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 47/50] signal: Queue ignored posixtimers on ignore list Thomas Gleixner
                   ` (4 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

When a real handler (including SIG_DFL) is installed for a signal, which
had previously SIG_IGN set, then the list of ignored posix timers has to be
checked for timers which are affected by this change.

Add a list walk function which checks for the matching signal number and if
found requeues the timers signal, so the timer is rearmed on signal
delivery.

Rearming the timer right away is not possible because that requires to drop
sighand lock.

No functional change as the counter part which queues the timers on the
ignored list is still missing.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/signal.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 53 insertions(+), 1 deletion(-)

--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2035,7 +2035,55 @@ int posixtimer_send_sigqueue(struct k_it
 	rcu_read_unlock();
 	return ret;
 }
-#endif /* CONFIG_POSIX_TIMERS */
+
+static void posixtimer_sig_unignore(struct task_struct *tsk, int sig)
+{
+	struct hlist_head *head = &tsk->signal->ignored_posix_timers;
+	struct hlist_node *tmp;
+	struct k_itimer *tmr;
+
+	if (likely(hlist_empty(head)))
+		return;
+
+	/*
+	 * Rearming a timer with sighand lock held is not possible due to
+	 * lock ordering vs. tmr::it_lock. Just stick the sigqueue back and
+	 * let the signal delivery path deal with it whether it needs to be
+	 * rearmed or not. This cannot be decided here w/o dropping sighand
+	 * lock and creating a loop retry horror show.
+	 */
+	hlist_for_each_entry_safe(tmr, tmp , head, ignored_list) {
+		struct task_struct *target;
+
+		/*
+		 * tmr::sigq.info.si_signo is immutable, so accessing it
+		 * without holding tmr::it_lock is safe.
+		 */
+		if (tmr->sigq.info.si_signo != sig)
+			continue;
+
+		hlist_del_init(&tmr->ignored_list);
+
+		/* This should never happen and leaks a reference count */
+		if (WARN_ON_ONCE(!list_empty(&tmr->sigq.list)))
+			continue;
+
+		/*
+		 * Get the target for the signal. If target is a thread and
+		 * has exited by now, drop the reference count.
+		 */
+		rcu_read_lock();
+		target = posixtimer_get_target(tmr);
+		if (target)
+			posixtimer_queue_sigqueue(&tmr->sigq, target, tmr->it_pid_type);
+		else
+			posixtimer_putref(tmr);
+		rcu_read_unlock();
+	}
+}
+#else /* CONFIG_POSIX_TIMERS */
+static inline void posixtimer_sig_unignore(struct task_struct *tsk, int sig) { }
+#endif /* !CONFIG_POSIX_TIMERS */
 
 void do_notify_pidfd(struct task_struct *task)
 {
@@ -4205,6 +4253,8 @@ int do_sigaction(int sig, struct k_sigac
 	sigaction_compat_abi(act, oact);
 
 	if (act) {
+		bool was_ignored = k->sa.sa_handler == SIG_IGN;
+
 		sigdelsetmask(&act->sa.sa_mask,
 			      sigmask(SIGKILL) | sigmask(SIGSTOP));
 		*k = *act;
@@ -4225,6 +4275,8 @@ int do_sigaction(int sig, struct k_sigac
 			flush_sigqueue_mask(&mask, &p->signal->shared_pending, NULL);
 			for_each_thread(p, t)
 				flush_sigqueue_mask(&mask, &t->pending, NULL);
+		} else if (was_ignored) {
+			posixtimer_sig_unignore(p, sig);
 		}
 	}
 


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 47/50] signal: Queue ignored posixtimers on ignore list
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (45 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 46/50] signal: Handle ignored signals in do_sigaction(action != SIG_IGN) Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 48/50] posix-timers: Cleanup SIG_IGN workaround leftovers Thomas Gleixner
                   ` (3 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Queue posixtimers which have their signal ignored on the ignored list:

   1) When the timer fires and the signal has SIG_IGN set

   2) When SIG_IGN is installed via sigaction() and a timer signal
      is queued

This completes the SIG_IGN handling and such timers are not longer self
rearmed which avoids pointless wakeups.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/signal.c |   44 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 8 deletions(-)

--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -722,6 +722,16 @@ void signal_wake_up_state(struct task_st
 		kick_process(t);
 }
 
+static inline void posixtimer_sig_ignore(struct task_struct *tsk, struct sigqueue *q);
+
+static void sigqueue_free_ignored(struct task_struct *ptmr_tsk, struct sigqueue *q)
+{
+	if (likely(!ptmr_tsk || q->info.si_code != SI_TIMER))
+		__sigqueue_free(q);
+	else
+		posixtimer_sig_ignore(ptmr_tsk, q);
+}
+
 /*
  * Remove signals in mask from the pending set and queue.
  *
@@ -740,7 +750,7 @@ static void flush_sigqueue_mask(sigset_t
 	list_for_each_entry_safe(q, n, &s->list, list) {
 		if (sigismember(mask, q->info.si_signo)) {
 			list_del_init(&q->list);
-			__sigqueue_free(q);
+			sigqueue_free_ignored(ptmr_tsk, q);
 		}
 	}
 }
@@ -1964,9 +1974,8 @@ int posixtimer_send_sigqueue(struct k_it
 	int sig = q->info.si_signo;
 	struct task_struct *t;
 	unsigned long flags;
-	int ret, result;
+	int result;
 
-	ret = -1;
 	rcu_read_lock();
 
 	t = posixtimer_get_target(tmr);
@@ -2012,13 +2021,24 @@ int posixtimer_send_sigqueue(struct k_it
 	 */
 	q->info.si_overrun = 0;
 
-	ret = 1; /* the signal is ignored */
 	if (!prepare_signal(sig, t, false)) {
 		result = TRACE_SIGNAL_IGNORED;
+
+		/* Paranoia check. Try to survive. */
+		if (WARN_ON_ONCE(!list_empty(&q->list)))
+			goto out;
+
+		if (hlist_unhashed(&tmr->ignored_list)) {
+			hlist_add_head(&tmr->ignored_list, &t->signal->ignored_posix_timers);
+			posixtimer_sigqueue_getref(q);
+		}
 		goto out;
 	}
 
-	ret = 0;
+	/* This should never happen and leaks a reference count */
+	if (WARN_ON_ONCE(!hlist_unhashed(&tmr->ignored_list)))
+		hlist_del_init(&tmr->ignored_list);
+
 	if (unlikely(!list_empty(&q->list))) {
 		/* This holds a reference count already */
 		result = TRACE_SIGNAL_ALREADY_PENDING;
@@ -2033,7 +2053,14 @@ int posixtimer_send_sigqueue(struct k_it
 	unlock_task_sighand(t, &flags);
 ret:
 	rcu_read_unlock();
-	return ret;
+	return 0;
+}
+
+static inline void posixtimer_sig_ignore(struct task_struct *tsk, struct sigqueue *q)
+{
+	struct k_itimer *tmr = container_of(q, struct k_itimer, sigq);
+
+	hlist_add_head(&tmr->ignored_list, &tsk->signal->ignored_posix_timers);
 }
 
 static void posixtimer_sig_unignore(struct task_struct *tsk, int sig)
@@ -2082,6 +2109,7 @@ static void posixtimer_sig_unignore(stru
 	}
 }
 #else /* CONFIG_POSIX_TIMERS */
+static inline void posixtimer_sig_ignore(struct task_struct *tsk, struct sigqueue *q) { }
 static inline void posixtimer_sig_unignore(struct task_struct *tsk, int sig) { }
 #endif /* !CONFIG_POSIX_TIMERS */
 
@@ -4272,9 +4300,9 @@ int do_sigaction(int sig, struct k_sigac
 		if (sig_handler_ignored(sig_handler(p, sig), sig)) {
 			sigemptyset(&mask);
 			sigaddset(&mask, sig);
-			flush_sigqueue_mask(&mask, &p->signal->shared_pending, NULL);
+			flush_sigqueue_mask(&mask, &p->signal->shared_pending, p);
 			for_each_thread(p, t)
-				flush_sigqueue_mask(&mask, &t->pending, NULL);
+				flush_sigqueue_mask(&mask, &t->pending, p);
 		} else if (was_ignored) {
 			posixtimer_sig_unignore(p, sig);
 		}


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 48/50] posix-timers: Cleanup SIG_IGN workaround leftovers
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (46 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 47/50] signal: Queue ignored posixtimers on ignore list Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 49/50] alarmtimers: Remove the throttle mechanism from alarm_forward_now() Thomas Gleixner
                   ` (2 subsequent siblings)
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Now that ignored posix timer signals are requeued and the timers are
rearmed on signal delivery the workaround to keep such timers alive and
self rearm them is not longer required.

Remove the relevant hacks and the not longer required return values from
the related functions. The alarm timer workarounds will be cleaned up in a
separate step.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/posix-timers.h   |    2 -
 kernel/signal.c                |    3 -
 kernel/time/alarmtimer.c       |   37 +++---------------------
 kernel/time/posix-cpu-timers.c |   18 ++---------
 kernel/time/posix-timers.c     |   63 +++--------------------------------------
 kernel/time/posix-timers.h     |    2 -
 6 files changed, 18 insertions(+), 107 deletions(-)

--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -111,7 +111,7 @@ static inline void posix_cputimers_rt_wa
 
 void posixtimer_rearm_itimer(struct task_struct *p);
 bool posixtimer_init_sigqueue(struct sigqueue *q);
-int posixtimer_send_sigqueue(struct k_itimer *tmr);
+void posixtimer_send_sigqueue(struct k_itimer *tmr);
 bool posixtimer_deliver_signal(struct kernel_siginfo *info);
 void posixtimer_free_timer(struct k_itimer *timer);
 
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1968,7 +1968,7 @@ static inline struct task_struct *posixt
 	return t;
 }
 
-int posixtimer_send_sigqueue(struct k_itimer *tmr)
+void posixtimer_send_sigqueue(struct k_itimer *tmr)
 {
 	struct sigqueue *q = &tmr->sigq;
 	int sig = q->info.si_signo;
@@ -2053,7 +2053,6 @@ int posixtimer_send_sigqueue(struct k_it
 	unlock_task_sighand(t, &flags);
 ret:
 	rcu_read_unlock();
-	return 0;
 }
 
 static inline void posixtimer_sig_ignore(struct task_struct *tsk, struct sigqueue *q)
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -198,27 +198,16 @@ static enum hrtimer_restart alarmtimer_f
 	struct alarm *alarm = container_of(timer, struct alarm, timer);
 	struct alarm_base *base = &alarm_bases[alarm->type];
 	unsigned long flags;
-	int ret = HRTIMER_NORESTART;
-	int restart = ALARMTIMER_NORESTART;
 
 	spin_lock_irqsave(&base->lock, flags);
 	alarmtimer_dequeue(base, alarm);
 	spin_unlock_irqrestore(&base->lock, flags);
 
 	if (alarm->function)
-		restart = alarm->function(alarm, base->get_ktime());
-
-	spin_lock_irqsave(&base->lock, flags);
-	if (restart != ALARMTIMER_NORESTART) {
-		hrtimer_set_expires(&alarm->timer, alarm->node.expires);
-		alarmtimer_enqueue(base, alarm);
-		ret = HRTIMER_RESTART;
-	}
-	spin_unlock_irqrestore(&base->lock, flags);
+		alarm->function(alarm, base->get_ktime());
 
 	trace_alarmtimer_fired(alarm, base->get_ktime());
-	return ret;
-
+	return HRTIMER_NORESTART;
 }
 
 ktime_t alarm_expires_remaining(const struct alarm *alarm)
@@ -567,30 +556,16 @@ static enum alarmtimer_type clock2alarm(
  *
  * Return: whether the timer is to be restarted
  */
-static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
-							ktime_t now)
+static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, ktime_t now)
 {
-	struct k_itimer *ptr = container_of(alarm, struct k_itimer,
-					    it.alarm.alarmtimer);
-	enum alarmtimer_restart result = ALARMTIMER_NORESTART;
+	struct k_itimer *ptr = container_of(alarm, struct k_itimer, it.alarm.alarmtimer);
 	unsigned long flags;
 
 	spin_lock_irqsave(&ptr->it_lock, flags);
-
-	if (posix_timer_queue_signal(ptr) && ptr->it_interval) {
-		/*
-		 * Handle ignored signals and rearm the timer. This will go
-		 * away once we handle ignored signals proper. Ensure that
-		 * small intervals cannot starve the system.
-		 */
-		ptr->it_overrun += __alarm_forward_now(alarm, ptr->it_interval, true);
-		++ptr->it_signal_seq;
-		ptr->it_status = POSIX_TIMER_ARMED;
-		result = ALARMTIMER_RESTART;
-	}
+	posix_timer_queue_signal(ptr);
 	spin_unlock_irqrestore(&ptr->it_lock, flags);
 
-	return result;
+	return ALARMTIMER_NORESTART;
 }
 
 /**
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -595,21 +595,11 @@ static void cpu_timer_fire(struct k_itim
 		 */
 		wake_up_process(timer->it_process);
 		cpu_timer_setexpires(ctmr, 0);
-	} else if (!timer->it_interval) {
-		/*
-		 * One-shot timer.  Clear it as soon as it's fired.
-		 */
+	} else {
 		posix_timer_queue_signal(timer);
-		cpu_timer_setexpires(ctmr, 0);
-	} else if (posix_timer_queue_signal(timer)) {
-		/*
-		 * The signal did not get queued because the signal
-		 * was ignored, so we won't get any callback to
-		 * reload the timer.  But we need to keep it
-		 * ticking in case the signal is deliverable next time.
-		 */
-		posix_cpu_timer_rearm(timer);
-		++timer->it_signal_seq;
+		/* Disable oneshot timers */
+		if (!timer->it_interval)
+			cpu_timer_setexpires(ctmr, 0);
 	}
 }
 
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -300,10 +300,9 @@ bool posixtimer_deliver_signal(struct ke
 	return ret;
 }
 
-int posix_timer_queue_signal(struct k_itimer *timr)
+void posix_timer_queue_signal(struct k_itimer *timr)
 {
 	enum posix_timer_state state = POSIX_TIMER_DISARMED;
-	int ret;
 
 	lockdep_assert_held(&timr->it_lock);
 
@@ -313,9 +312,7 @@ int posix_timer_queue_signal(struct k_it
 	}
 	timr->it_status = state;
 
-	ret = posixtimer_send_sigqueue(timr);
-	/* If we failed to send the signal the timer stops. */
-	return ret > 0;
+	posixtimer_send_sigqueue(timr);
 }
 
 /*
@@ -328,62 +325,12 @@ int posix_timer_queue_signal(struct k_it
 static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
 {
 	struct k_itimer *timr = container_of(timer, struct k_itimer, it.real.timer);
-	enum hrtimer_restart ret = HRTIMER_NORESTART;
 	unsigned long flags;
 
 	spin_lock_irqsave(&timr->it_lock, flags);
-
-	if (posix_timer_queue_signal(timr)) {
-		/*
-		 * The signal was not queued due to SIG_IGN. As a
-		 * consequence the timer is not going to be rearmed from
-		 * the signal delivery path. But as a real signal handler
-		 * can be installed later the timer must be rearmed here.
-		 */
-		if (timr->it_interval != 0) {
-			ktime_t now = hrtimer_cb_get_time(timer);
-
-			/*
-			 * FIXME: What we really want, is to stop this
-			 * timer completely and restart it in case the
-			 * SIG_IGN is removed. This is a non trivial
-			 * change to the signal handling code.
-			 *
-			 * For now let timers with an interval less than a
-			 * jiffie expire every jiffie and recheck for a
-			 * valid signal handler.
-			 *
-			 * This avoids interrupt starvation in case of a
-			 * very small interval, which would expire the
-			 * timer immediately again.
-			 *
-			 * Moving now ahead of time by one jiffie tricks
-			 * hrtimer_forward() to expire the timer later,
-			 * while it still maintains the overrun accuracy
-			 * for the price of a slight inconsistency in the
-			 * timer_gettime() case. This is at least better
-			 * than a timer storm.
-			 *
-			 * Only required when high resolution timers are
-			 * enabled as the periodic tick based timers are
-			 * automatically aligned to the next tick.
-			 */
-			if (IS_ENABLED(CONFIG_HIGH_RES_TIMERS)) {
-				ktime_t kj = TICK_NSEC;
-
-				if (timr->it_interval < kj)
-					now = ktime_add(now, kj);
-			}
-
-			timr->it_overrun += hrtimer_forward(timer, now, timr->it_interval);
-			ret = HRTIMER_RESTART;
-			++timr->it_signal_seq;
-			timr->it_status = POSIX_TIMER_ARMED;
-		}
-	}
-
-	unlock_timer(timr, flags);
-	return ret;
+	posix_timer_queue_signal(timr);
+	spin_unlock_irqrestore(&timr->it_lock, flags);
+	return HRTIMER_NORESTART;
 }
 
 static struct pid *good_sigevent(sigevent_t * event)
--- a/kernel/time/posix-timers.h
+++ b/kernel/time/posix-timers.h
@@ -42,7 +42,7 @@ extern const struct k_clock clock_proces
 extern const struct k_clock clock_thread;
 extern const struct k_clock alarm_clock;
 
-int posix_timer_queue_signal(struct k_itimer *timr);
+void posix_timer_queue_signal(struct k_itimer *timr);
 
 void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting);
 int common_timer_set(struct k_itimer *timr, int flags,


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 49/50] alarmtimers: Remove the throttle mechanism from alarm_forward_now()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (47 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 48/50] posix-timers: Cleanup SIG_IGN workaround leftovers Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-10 22:47 ` [patch V2 50/50] alarmtimers: Remove return value from alarm functions Thomas Gleixner
  2024-04-15 12:30 ` [PATCH] posix-timers: Handle returned errors poperly in [i]timer_delete() Anna-Maria Behnsen
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Now that ignored posix timer signals are requeued and the timers are
rearmed on signal delivery the workaround to keep such timers alive and
self rearm them is not longer required.

Remove the unused alarm timer parts.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/time/alarmtimer.c |   28 ++--------------------------
 1 file changed, 2 insertions(+), 26 deletions(-)
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -469,35 +469,11 @@ u64 alarm_forward(struct alarm *alarm, k
 }
 EXPORT_SYMBOL_GPL(alarm_forward);
 
-static u64 __alarm_forward_now(struct alarm *alarm, ktime_t interval, bool throttle)
+u64 alarm_forward_now(struct alarm *alarm, ktime_t interval)
 {
 	struct alarm_base *base = &alarm_bases[alarm->type];
-	ktime_t now = base->get_ktime();
-
-	if (IS_ENABLED(CONFIG_HIGH_RES_TIMERS) && throttle) {
-		/*
-		 * Same issue as with posix_timer_fn(). Timers which are
-		 * periodic but the signal is ignored can starve the system
-		 * with a very small interval. The real fix which was
-		 * promised in the context of posix_timer_fn() never
-		 * materialized, but someone should really work on it.
-		 *
-		 * To prevent DOS fake @now to be 1 jiffie out which keeps
-		 * the overrun accounting correct but creates an
-		 * inconsistency vs. timer_gettime(2).
-		 */
-		ktime_t kj = NSEC_PER_SEC / HZ;
 
-		if (interval < kj)
-			now = ktime_add(now, kj);
-	}
-
-	return alarm_forward(alarm, now, interval);
-}
-
-u64 alarm_forward_now(struct alarm *alarm, ktime_t interval)
-{
-	return __alarm_forward_now(alarm, interval, false);
+	return alarm_forward(alarm, base->get_ktime(), interval);
 }
 EXPORT_SYMBOL_GPL(alarm_forward_now);
 


^ permalink raw reply	[flat|nested] 91+ messages in thread

* [patch V2 50/50] alarmtimers: Remove return value from alarm functions
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (48 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 49/50] alarmtimers: Remove the throttle mechanism from alarm_forward_now() Thomas Gleixner
@ 2024-04-10 22:47 ` Thomas Gleixner
  2024-04-15 12:30 ` [PATCH] posix-timers: Handle returned errors poperly in [i]timer_delete() Anna-Maria Behnsen
  50 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-10 22:47 UTC (permalink / raw)
  To: LKML
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Oleg Nesterov

Now that the SIG_IGN problem is solved in the core code, the alarmtimer
callbacks do not require a return value anymore.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 drivers/power/supply/charger-manager.c |    3 +--
 fs/timerfd.c                           |    4 +---
 include/linux/alarmtimer.h             |   10 ++--------
 kernel/time/alarmtimer.c               |   16 +++++-----------
 net/netfilter/xt_IDLETIMER.c           |    4 +---
 5 files changed, 10 insertions(+), 27 deletions(-)

--- a/drivers/power/supply/charger-manager.c
+++ b/drivers/power/supply/charger-manager.c
@@ -1412,10 +1412,9 @@ static inline struct charger_desc *cm_ge
 	return dev_get_platdata(&pdev->dev);
 }
 
-static enum alarmtimer_restart cm_timer_func(struct alarm *alarm, ktime_t now)
+static void cm_timer_func(struct alarm *alarm, ktime_t now)
 {
 	cm_timer_set = false;
-	return ALARMTIMER_NORESTART;
 }
 
 static int charger_manager_probe(struct platform_device *pdev)
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -79,13 +79,11 @@ static enum hrtimer_restart timerfd_tmrp
 	return HRTIMER_NORESTART;
 }
 
-static enum alarmtimer_restart timerfd_alarmproc(struct alarm *alarm,
-	ktime_t now)
+static void timerfd_alarmproc(struct alarm *alarm, ktime_t now)
 {
 	struct timerfd_ctx *ctx = container_of(alarm, struct timerfd_ctx,
 					       t.alarm);
 	timerfd_triggered(ctx);
-	return ALARMTIMER_NORESTART;
 }
 
 /*
--- a/include/linux/alarmtimer.h
+++ b/include/linux/alarmtimer.h
@@ -20,12 +20,6 @@ enum alarmtimer_type {
 	ALARM_BOOTTIME_FREEZER,
 };
 
-enum alarmtimer_restart {
-	ALARMTIMER_NORESTART,
-	ALARMTIMER_RESTART,
-};
-
-
 #define ALARMTIMER_STATE_INACTIVE	0x00
 #define ALARMTIMER_STATE_ENQUEUED	0x01
 
@@ -42,14 +36,14 @@ enum alarmtimer_restart {
 struct alarm {
 	struct timerqueue_node	node;
 	struct hrtimer		timer;
-	enum alarmtimer_restart	(*function)(struct alarm *, ktime_t now);
+	void			(*function)(struct alarm *, ktime_t now);
 	enum alarmtimer_type	type;
 	int			state;
 	void			*data;
 };
 
 void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
-		enum alarmtimer_restart (*function)(struct alarm *, ktime_t));
+		void (*function)(struct alarm *, ktime_t));
 void alarm_start(struct alarm *alarm, ktime_t start);
 void alarm_start_relative(struct alarm *alarm, ktime_t start);
 void alarm_restart(struct alarm *alarm);
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -323,7 +323,7 @@ static int alarmtimer_resume(struct devi
 
 static void
 __alarm_init(struct alarm *alarm, enum alarmtimer_type type,
-	     enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
+	     void (*function)(struct alarm *, ktime_t))
 {
 	timerqueue_init(&alarm->node);
 	alarm->timer.function = alarmtimer_fired;
@@ -339,7 +339,7 @@ static void
  * @function: callback that is run when the alarm fires
  */
 void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
-		enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
+		void (*function)(struct alarm *, ktime_t))
 {
 	hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid,
 		     HRTIMER_MODE_ABS);
@@ -532,7 +532,7 @@ static enum alarmtimer_type clock2alarm(
  *
  * Return: whether the timer is to be restarted
  */
-static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, ktime_t now)
+static void alarm_handle_timer(struct alarm *alarm, ktime_t now)
 {
 	struct k_itimer *ptr = container_of(alarm, struct k_itimer, it.alarm.alarmtimer);
 	unsigned long flags;
@@ -540,8 +540,6 @@ static enum alarmtimer_restart alarm_han
 	spin_lock_irqsave(&ptr->it_lock, flags);
 	posix_timer_queue_signal(ptr);
 	spin_unlock_irqrestore(&ptr->it_lock, flags);
-
-	return ALARMTIMER_NORESTART;
 }
 
 /**
@@ -702,18 +700,14 @@ static int alarm_timer_create(struct k_i
  * @now: time at the timer expiration
  *
  * Wakes up the task that set the alarmtimer
- *
- * Return: ALARMTIMER_NORESTART
  */
-static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm,
-								ktime_t now)
+static void alarmtimer_nsleep_wakeup(struct alarm *alarm, ktime_t now)
 {
 	struct task_struct *task = alarm->data;
 
 	alarm->data = NULL;
 	if (task)
 		wake_up_process(task);
-	return ALARMTIMER_NORESTART;
 }
 
 /**
@@ -765,7 +759,7 @@ static int alarmtimer_do_nsleep(struct a
 
 static void
 alarm_init_on_stack(struct alarm *alarm, enum alarmtimer_type type,
-		    enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
+		    void (*function)(struct alarm *, ktime_t))
 {
 	hrtimer_init_on_stack(&alarm->timer, alarm_bases[type].base_clockid,
 			      HRTIMER_MODE_ABS);
--- a/net/netfilter/xt_IDLETIMER.c
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -107,14 +107,12 @@ static void idletimer_tg_expired(struct
 	schedule_work(&timer->work);
 }
 
-static enum alarmtimer_restart idletimer_tg_alarmproc(struct alarm *alarm,
-							  ktime_t now)
+static void idletimer_tg_alarmproc(struct alarm *alarm, ktime_t now)
 {
 	struct idletimer_tg *timer = alarm->data;
 
 	pr_debug("alarm %s expired\n", timer->attr.attr.name);
 	schedule_work(&timer->work);
-	return ALARMTIMER_NORESTART;
 }
 
 static int idletimer_check_sysfs_name(const char *name, unsigned int size)


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 08/50] posix-cpu-timers: Save interval only for armed timers
  2024-04-10 22:46 ` [patch V2 08/50] posix-cpu-timers: Save interval only for armed timers Thomas Gleixner
@ 2024-04-11 14:25   ` Anna-Maria Behnsen
  2024-04-11 22:00     ` Thomas Gleixner
  0 siblings, 1 reply; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-11 14:25 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> There is no point to return the interval for timers which have been
> disarmed.
>

common_timer_get() returns/updates interval unconditionally - so
behavior then differs.

Thanks,

	Anna-Maria

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 11/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_set()
  2024-04-10 22:46 ` [patch V2 11/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_set() Thomas Gleixner
@ 2024-04-11 15:48   ` Anna-Maria Behnsen
  2024-04-11 22:02     ` Thomas Gleixner
  0 siblings, 1 reply; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-11 15:48 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> Expired SIGEV_NONE oneshot timers must return 0 nsec for the expiry time in
> timer_get(), but the posix CPU timer implementation returns 1 nsec.

copy paste error (get/set) ?

> Add the missing conditional.
>
> This will be cleaned up in a follow up patch.

I'm confused. Why do you want to cleanup the conditional in a follow up
patch?

Thanks,

	Anna-Maria


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 08/50] posix-cpu-timers: Save interval only for armed timers
  2024-04-11 14:25   ` Anna-Maria Behnsen
@ 2024-04-11 22:00     ` Thomas Gleixner
  0 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-11 22:00 UTC (permalink / raw)
  To: Anna-Maria Behnsen, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

On Thu, Apr 11 2024 at 16:25, Anna-Maria Behnsen wrote:

> Thomas Gleixner <tglx@linutronix.de> writes:
>
>> There is no point to return the interval for timers which have been
>> disarmed.
>>
> common_timer_get() returns/updates interval unconditionally - so
> behavior then differs.

Good catch! We really want to make this consistent.

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 11/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_set()
  2024-04-11 15:48   ` Anna-Maria Behnsen
@ 2024-04-11 22:02     ` Thomas Gleixner
  2024-04-17 23:04       ` Frederic Weisbecker
  0 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-11 22:02 UTC (permalink / raw)
  To: Anna-Maria Behnsen, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

On Thu, Apr 11 2024 at 17:48, Anna-Maria Behnsen wrote:

> Thomas Gleixner <tglx@linutronix.de> writes:
>
>> Expired SIGEV_NONE oneshot timers must return 0 nsec for the expiry time in
>> timer_get(), but the posix CPU timer implementation returns 1 nsec.
>
> copy paste error (get/set) ?

Yes.

>> Add the missing conditional.
>>
>> This will be cleaned up in a follow up patch.
>
> I'm confused. Why do you want to cleanup the conditional in a follow up
> patch?

This patch is to fix the issue. The next one consolidates the code, but
I can see why the "this will be ..." part of the changelog does not make
sense.

Thanks,

        tglx

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 01/50] selftests/timers/posix_timers: Simplify error handling
  2024-04-10 22:46 ` [patch V2 01/50] selftests/timers/posix_timers: Simplify error handling Thomas Gleixner
@ 2024-04-12  7:35   ` Anna-Maria Behnsen
  0 siblings, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-12  7:35 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> No point in returning to main() on fatal errors. Just exit right away.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
  2024-04-10 22:46 ` [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get() Thomas Gleixner
@ 2024-04-12  7:35   ` Anna-Maria Behnsen
  2024-04-12 18:25   ` Eric W. Biederman
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-12  7:35 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> In preparation for addressing issues in the timer_get() and timer_set()
> functions of posix CPU timers.
>
> No functional change.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
  2024-04-10 22:46 ` [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get() Thomas Gleixner
  2024-04-12  7:35   ` Anna-Maria Behnsen
@ 2024-04-12 18:25   ` Eric W. Biederman
  2024-04-12 19:48     ` Thomas Gleixner
  2024-04-16 14:44   ` Oleg Nesterov
  2024-04-17 20:33   ` Frederic Weisbecker
  3 siblings, 1 reply; 91+ messages in thread
From: Eric W. Biederman @ 2024-04-12 18:25 UTC (permalink / raw)
  To: Thomas Flexing
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> In preparation for addressing issues in the timer_get() and timer_set()
> functions of posix CPU timers.

To see that this was safe I had to lookup and see that
cpu_timer_getexpires is a truly trivial function.

static inline u64 cpu_timer_getexpires(struct cpu_timer *ctmr)
{
	return ctmr->node.expires;
}

I am a bit confused by the purpose of this function in
posix-cpu-timers.c.  In some places this helper is used (like below),
and in other places like bump_cpu_timer the expires member is
accessed directly.

It isn't really a problem, but it is something that might be
worth making consistent in the code to make it easier to read.

Eric

> No functional change.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> V2: Split out into new patch to make review simpler - Frederic
> ---
>  kernel/time/posix-cpu-timers.c |   51 +++++++++++++++++++----------------------
>  1 file changed, 24 insertions(+), 27 deletions(-)
>
> --- a/kernel/time/posix-cpu-timers.c
> +++ b/kernel/time/posix-cpu-timers.c
> @@ -785,33 +785,9 @@ static int posix_cpu_timer_set(struct k_
>  	return ret;
>  }
>  
> -static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp)
> +static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now)
>  {
> -	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
> -	struct cpu_timer *ctmr = &timer->it.cpu;
> -	u64 now, expires = cpu_timer_getexpires(ctmr);
> -	struct task_struct *p;
> -
> -	rcu_read_lock();
> -	p = cpu_timer_task_rcu(timer);
> -	if (!p)
> -		goto out;
> -
> -	/*
> -	 * Easy part: convert the reload time.
> -	 */
> -	itp->it_interval = ktime_to_timespec64(timer->it_interval);
> -
> -	if (!expires)
> -		goto out;
> -
> -	/*
> -	 * Sample the clock to take the difference with the expiry time.
> -	 */
> -	if (CPUCLOCK_PERTHREAD(timer->it_clock))
> -		now = cpu_clock_sample(clkid, p);
> -	else
> -		now = cpu_clock_sample_group(clkid, p, false);
> +	u64 expires = cpu_timer_getexpires(&timer->it.cpu);
>  
>  	if (now < expires) {
>  		itp->it_value = ns_to_timespec64(expires - now);
> @@ -823,7 +799,28 @@ static void posix_cpu_timer_get(struct k
>  		itp->it_value.tv_nsec = 1;
>  		itp->it_value.tv_sec = 0;
>  	}
> -out:
> +}
> +
> +static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp)
> +{
> +	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
> +	struct task_struct *p;
> +	u64 now;
> +
> +	rcu_read_lock();
> +	p = cpu_timer_task_rcu(timer);
> +	if (p) {
> +		itp->it_interval = ktime_to_timespec64(timer->it_interval);
> +
> +		if (cpu_timer_getexpires(&timer->it.cpu)) {
> +			if (CPUCLOCK_PERTHREAD(timer->it_clock))
> +				now = cpu_clock_sample(clkid, p);
> +			else
> +				now = cpu_clock_sample_group(clkid, p, false);
> +
> +			__posix_cpu_timer_get(timer, itp, now);
> +		}
> +	}
>  	rcu_read_unlock();
>  }
>  

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 10/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_get()
  2024-04-10 22:46 ` [patch V2 10/50] posix-cpu-timers: Handle SIGEV_NONE " Thomas Gleixner
@ 2024-04-12 18:40   ` Eric W. Biederman
  2024-04-12 19:49     ` Thomas Gleixner
  0 siblings, 1 reply; 91+ messages in thread
From: Eric W. Biederman @ 2024-04-12 18:40 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> Expired SIGEV_NONE oneshot timers must return 0 nsec for the expiry time in
> timer_get(), but the posix CPU timer implementation returns 1 nsec.
>
> Add the missing conditional.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> V2: Split out into new patch to make review simpler - Frederic
> ---
>  kernel/time/posix-cpu-timers.c |   14 +++++++++-----
>  1 file changed, 9 insertions(+), 5 deletions(-)
>
> --- a/kernel/time/posix-cpu-timers.c
> +++ b/kernel/time/posix-cpu-timers.c
> @@ -787,15 +787,17 @@ static int posix_cpu_timer_set(struct k_
>  
>  static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now)
>  {
> +	bool sigev_none = timer->it_sigev_notify == SIGEV_NONE;
>  	u64 expires, iv = timer->it_interval;
>  
>  	/*
>  	 * Make sure that interval timers are moved forward for the
>  	 * following cases:
> +	 *  - SIGEV_NONE timers which are never armed
>  	 *  - Timers which expired, but the signal has not yet been
>  	 *    delivered
>  	 */
> -	if (iv && (timer->it_requeue_pending & REQUEUE_PENDING))
> +	if (iv && ((timer->it_requeue_pending & REQUEUE_PENDING) || sigev_none))
>  		expires = bump_cpu_timer(timer, now);
>  	else
>  		expires = cpu_timer_getexpires(&timer->it.cpu);
> @@ -809,11 +811,13 @@ static void __posix_cpu_timer_get(struct
>  		itp->it_value = ns_to_timespec64(expires - now);
>  	} else {
Why not make this else condition?
	} else if (!sigev_none) {
And not need to change the rest of the code?
>  		/*
> -		 * The timer should have expired already, but the firing
> -		 * hasn't taken place yet.  Say it's just about to expire.
> +		 * A single shot SIGEV_NONE timer must return 0, when it is
> +		 * expired! Timers which have a real signal delivery mode
> +		 * must return a remaining time greater than 0 because the
> +		 * signal has not yet been delivered.
>  		 */
> -		itp->it_value.tv_nsec = 1;
> -		itp->it_value.tv_sec = 0;
> +		if (!sigev_none)
> +			itp->it_value.tv_nsec = 1;

Do you perhaps need a comment somewhere that itp is zeroed in
do_timer_gettime?  The code now depends upon that for setting
itp->it_value when it did not used to, making it look at first
glance like you have created an uninitialized variable.

Probably just something in the description of the change would be
sufficient.

>  	}
>  }
>  

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
  2024-04-12 18:25   ` Eric W. Biederman
@ 2024-04-12 19:48     ` Thomas Gleixner
  0 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-12 19:48 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Oleg Nesterov

On Fri, Apr 12 2024 at 13:25, Eric W. Biederman wrote:
> Thomas Gleixner <tglx@linutronix.de> writes:
>> In preparation for addressing issues in the timer_get() and timer_set()
>> functions of posix CPU timers.
>
> To see that this was safe I had to lookup and see that
> cpu_timer_getexpires is a truly trivial function.
>
> static inline u64 cpu_timer_getexpires(struct cpu_timer *ctmr)
> {
> 	return ctmr->node.expires;
> }
>
> I am a bit confused by the purpose of this function in
> posix-cpu-timers.c.

I added that back then when I converted the code over to use a
timerqueue instead of a linked list mostly because I did not want to
fiddle in the inwars of timerqueue.

> In some places this helper is used (like below), and in other places
> like bump_cpu_timer the expires member is accessed directly.
>
> It isn't really a problem, but it is something that might be
> worth making consistent in the code to make it easier to read.

Yes, that's definitely inconsistent. I'll have a look.

Thanks,

        tglx

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 10/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_get()
  2024-04-12 18:40   ` Eric W. Biederman
@ 2024-04-12 19:49     ` Thomas Gleixner
  0 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-12 19:49 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Oleg Nesterov

On Fri, Apr 12 2024 at 13:40, Eric W. Biederman wrote:
> Thomas Gleixner <tglx@linutronix.de> writes:
>> -	if (iv && (timer->it_requeue_pending & REQUEUE_PENDING))
>> +	if (iv && ((timer->it_requeue_pending & REQUEUE_PENDING) || sigev_none))
>>  		expires = bump_cpu_timer(timer, now);
>>  	else
>>  		expires = cpu_timer_getexpires(&timer->it.cpu);
>> @@ -809,11 +811,13 @@ static void __posix_cpu_timer_get(struct
>>  		itp->it_value = ns_to_timespec64(expires - now);
>>  	} else {
> Why not make this else condition?
> 	} else if (!sigev_none) {
> And not need to change the rest of the code?

Duh, yes.
  		/*
>> -		 * The timer should have expired already, but the firing
>> -		 * hasn't taken place yet.  Say it's just about to expire.
>> +		 * A single shot SIGEV_NONE timer must return 0, when it is
>> +		 * expired! Timers which have a real signal delivery mode
>> +		 * must return a remaining time greater than 0 because the
>> +		 * signal has not yet been delivered.
>>  		 */
>> -		itp->it_value.tv_nsec = 1;
>> -		itp->it_value.tv_sec = 0;
>> +		if (!sigev_none)
>> +			itp->it_value.tv_nsec = 1;
>
> Do you perhaps need a comment somewhere that itp is zeroed in
> do_timer_gettime?  The code now depends upon that for setting
> itp->it_value when it did not used to, making it look at first
> glance like you have created an uninitialized variable.
>
> Probably just something in the description of the change would be
> sufficient.

Fair enough.

Thanks,

        tglx

^ permalink raw reply	[flat|nested] 91+ messages in thread

* [PATCH] posix-timers: Handle returned errors poperly in [i]timer_delete()
  2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
                   ` (49 preceding siblings ...)
  2024-04-10 22:47 ` [patch V2 50/50] alarmtimers: Remove return value from alarm functions Thomas Gleixner
@ 2024-04-15 12:30 ` Anna-Maria Behnsen
  2024-04-15 13:00   ` Oleg Nesterov
  50 siblings, 1 reply; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-15 12:30 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

timer_delete_hook() returns -EINVAL when the clock or the timer_del
callback of the clock does not exist. This return value is not handled by
the callsites timer_delete() and itimer_delete().

Therefore add proper error handling.

Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
---
When having a look at the posix timer code during reviewing the queue, I
stumbled over this inconsitency. Maybe you want to have it in your
cleanup queue. Patch applies on top of your queue.

 kernel/time/posix-timers.c |   14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -1009,6 +1009,7 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
 {
 	struct k_itimer *timer;
 	unsigned long flags;
+	int ret;
 
 	timer = lock_timer(timer_id, &flags);
 
@@ -1019,7 +1020,11 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
 	/* Prevent signal delivery and rearming. */
 	timer->it_signal_seq++;
 
-	if (unlikely(timer_delete_hook(timer) == TIMER_RETRY)) {
+	ret = timer_delete_hook(timer);
+	if (ret < 0)
+		return ret;
+
+	if (unlikely(ret == TIMER_RETRY)) {
 		/* Unlocks and relocks the timer if it still exists */
 		timer = timer_wait_running(timer, &flags);
 		goto retry_delete;
@@ -1047,6 +1052,7 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
 static void itimer_delete(struct k_itimer *timer)
 {
 	unsigned long flags;
+	int ret;
 
 	/*
 	 * irqsave is required to make timer_wait_running() work.
@@ -1054,13 +1060,17 @@ static void itimer_delete(struct k_itime
 	spin_lock_irqsave(&timer->it_lock, flags);
 
 retry_delete:
+	ret = timer_delete_hook(timer);
+	if (WARN_ON_ONCE(ret < 0))
+		return;
+
 	/*
 	 * Even if the timer is not longer accessible from other tasks
 	 * it still might be armed and queued in the underlying timer
 	 * mechanism. Worse, that timer mechanism might run the expiry
 	 * function concurrently.
 	 */
-	if (timer_delete_hook(timer) == TIMER_RETRY) {
+	if (ret == TIMER_RETRY) {
 		/*
 		 * Timer is expired concurrently, prevent livelocks
 		 * and pointless spinning on RT.

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] posix-timers: Handle returned errors poperly in [i]timer_delete()
  2024-04-15 12:30 ` [PATCH] posix-timers: Handle returned errors poperly in [i]timer_delete() Anna-Maria Behnsen
@ 2024-04-15 13:00   ` Oleg Nesterov
  2024-04-15 14:15     ` Anna-Maria Behnsen
  0 siblings, 1 reply; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-15 13:00 UTC (permalink / raw)
  To: Anna-Maria Behnsen
  Cc: Thomas Gleixner, LKML, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On 04/15, Anna-Maria Behnsen wrote:
>
> timer_delete_hook() returns -EINVAL when the clock or the timer_del
> callback of the clock does not exist. This return value is not handled by
> the callsites timer_delete() and itimer_delete().

IIUC this shouldn't happen? timer_delete_hook() WARN()s in this case,
not sure we need to return this error to userspace...

> --- a/kernel/time/posix-timers.c
> +++ b/kernel/time/posix-timers.c
> @@ -1009,6 +1009,7 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
>  {
>  	struct k_itimer *timer;
>  	unsigned long flags;
> +	int ret;
>  
>  	timer = lock_timer(timer_id, &flags);
>  
> @@ -1019,7 +1020,11 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
>  	/* Prevent signal delivery and rearming. */
>  	timer->it_signal_seq++;
>  
> -	if (unlikely(timer_delete_hook(timer) == TIMER_RETRY)) {
> +	ret = timer_delete_hook(timer);
> +	if (ret < 0)
> +		return ret;

unlock_timer() ?

>  static void itimer_delete(struct k_itimer *timer)
>  {
>  	unsigned long flags;
> +	int ret;
>  
>  	/*
>  	 * irqsave is required to make timer_wait_running() work.
> @@ -1054,13 +1060,17 @@ static void itimer_delete(struct k_itime
>  	spin_lock_irqsave(&timer->it_lock, flags);
>  
>  retry_delete:
> +	ret = timer_delete_hook(timer);
> +	if (WARN_ON_ONCE(ret < 0))
> +		return;

the same.

Oleg.


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 12/50] posix-cpu-timers: Replace old expiry retrieval in posix_cpu_timer_set()
  2024-04-10 22:46 ` [patch V2 12/50] posix-cpu-timers: Replace old expiry retrieval in posix_cpu_timer_set() Thomas Gleixner
@ 2024-04-15 14:03   ` Anna-Maria Behnsen
  0 siblings, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-15 14:03 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> Reuse the split out __posix_cpu_timer_get() function which does already the
> right thing.
>
> No functional change.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 13/50] posix-cpu-timers: Do not arm SIGEV_NONE timers
  2024-04-10 22:46 ` [patch V2 13/50] posix-cpu-timers: Do not arm SIGEV_NONE timers Thomas Gleixner
@ 2024-04-15 14:03   ` Anna-Maria Behnsen
  0 siblings, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-15 14:03 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> There is no point in arming SIGEV_NONE timers as they never deliver a
> signal. timer_gettime() is handling the expiry time correctly and that's
> all SIGEV_NONE timers care about.
>
> Prevent arming them and remove the expiry handler code which just disarms
> them.
>

Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] posix-timers: Handle returned errors poperly in [i]timer_delete()
  2024-04-15 13:00   ` Oleg Nesterov
@ 2024-04-15 14:15     ` Anna-Maria Behnsen
  2024-04-15 16:27       ` Oleg Nesterov
  0 siblings, 1 reply; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-15 14:15 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Thomas Gleixner, LKML, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

Oleg Nesterov <oleg@redhat.com> writes:

> On 04/15, Anna-Maria Behnsen wrote:
>>
>> timer_delete_hook() returns -EINVAL when the clock or the timer_del
>> callback of the clock does not exist. This return value is not handled by
>> the callsites timer_delete() and itimer_delete().
>
> IIUC this shouldn't happen? timer_delete_hook() WARN()s in this case,
> not sure we need to return this error to userspace...

This shouldn't happen, right.

Even if we do not return this error to userspace, is it valid to proceed
with the rest of the callsites? When it is fine to just ignore the
-EINVAL return, then I would propose just to add a comment to the code.

>> --- a/kernel/time/posix-timers.c
>> +++ b/kernel/time/posix-timers.c
>> @@ -1009,6 +1009,7 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
>>  {
>>  	struct k_itimer *timer;
>>  	unsigned long flags;
>> +	int ret;
>>  
>>  	timer = lock_timer(timer_id, &flags);
>>  
>> @@ -1019,7 +1020,11 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t
>>  	/* Prevent signal delivery and rearming. */
>>  	timer->it_signal_seq++;
>>  
>> -	if (unlikely(timer_delete_hook(timer) == TIMER_RETRY)) {
>> +	ret = timer_delete_hook(timer);
>> +	if (ret < 0)
>> +		return ret;
>
> unlock_timer() ?
>

bah... was done in a hurry...

Thanks,

	Anna-Maria


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 16/50] posix-cpu-timers: Simplify posix_cpu_timer_set()
  2024-04-10 22:46 ` [patch V2 16/50] posix-cpu-timers: Simplify posix_cpu_timer_set() Thomas Gleixner
@ 2024-04-15 15:28   ` Anna-Maria Behnsen
  0 siblings, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-15 15:28 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> Avoid the late sighand lock/unlock dance when a timer is not armed to
> enforce reevaluation of the timer base so that the process wide CPU timer
> sampling can be disabled.
>
> Do it right at the point where the arming decision is made which already
> has sighand locked.
>

Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 17/50] posix-timers: Retrieve interval in common timer_settime() code
  2024-04-10 22:46 ` [patch V2 17/50] posix-timers: Retrieve interval in common timer_settime() code Thomas Gleixner
@ 2024-04-15 15:43   ` Anna-Maria Behnsen
  0 siblings, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-15 15:43 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> No point in doing this all over the place.
>

Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [PATCH] posix-timers: Handle returned errors poperly in [i]timer_delete()
  2024-04-15 14:15     ` Anna-Maria Behnsen
@ 2024-04-15 16:27       ` Oleg Nesterov
  0 siblings, 0 replies; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-15 16:27 UTC (permalink / raw)
  To: Anna-Maria Behnsen
  Cc: Thomas Gleixner, LKML, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

Anna-Maria, I can't really answer, I don't understand this code today ;)
That said, let me try to explain my opinion,

On 04/15, Anna-Maria Behnsen wrote:
>
> Oleg Nesterov <oleg@redhat.com> writes:
>
> > On 04/15, Anna-Maria Behnsen wrote:
> >>
> >> timer_delete_hook() returns -EINVAL when the clock or the timer_del
> >> callback of the clock does not exist. This return value is not handled by
> >> the callsites timer_delete() and itimer_delete().
> >
> > IIUC this shouldn't happen? timer_delete_hook() WARN()s in this case,
> > not sure we need to return this error to userspace...
>
> This shouldn't happen, right.
>
> Even if we do not return this error to userspace, is it valid to proceed
> with the rest of the callsites?

Well, I'd say that nothing is safe after we hit the kernel problem.

But lets suppose we return EINVAL and skip list_del(&timer->list)/etc.
How can this help? What can userspace do to resolve this problem? Is it
better to "leak" this timer? I dunno.

> When it is fine to just ignore the
> -EINVAL return, then I would propose just to add a comment to the code.

Agreed!

Oleg.


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
  2024-04-10 22:46 ` [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get() Thomas Gleixner
  2024-04-12  7:35   ` Anna-Maria Behnsen
  2024-04-12 18:25   ` Eric W. Biederman
@ 2024-04-16 14:44   ` Oleg Nesterov
  2024-04-17  9:21     ` Anna-Maria Behnsen
  2024-04-17 20:33   ` Frederic Weisbecker
  3 siblings, 1 reply; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-16 14:44 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On 04/11, Thomas Gleixner wrote:
>
> In preparation for addressing issues in the timer_get() and timer_set()
> functions of posix CPU timers.

Cough... I must have missed something, but posix_cpu_timer_get()
doesn't look right with or without this trivial patch.

It doesn't initialize itp->it_value if cpu_timer_getexpires() == 0,
this means that sys_timer_gettime() will copy the uninitialized
cur_setting->it_value on the stack to userspace?

Oleg.


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 20/50] posix-timers: Consolidate timer setup
  2024-04-10 22:46 ` [patch V2 20/50] posix-timers: Consolidate timer setup Thomas Gleixner
@ 2024-04-16 16:12   ` Anna-Maria Behnsen
  2024-04-23 19:38     ` Thomas Gleixner
  0 siblings, 1 reply; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-16 16:12 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> hrtimer based and CPU timers have their own way to install the new interval
> and to reset overrun and signal handling related data.
>
> Create a helper function and do the same operation for all variants.
>
> This also makes the handling of the interval consistent. It's only stored
> when the timer is actually armed, i.e. timer->it_value != 0. Before that it
> was stored unconditionally for posix CPU timers and conditionally for the
> other posix timers.

Shouldn't we do this similar to the gettime() and set it_interval
unconditionally?

Thanks,

	Anna-Maria


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
  2024-04-16 14:44   ` Oleg Nesterov
@ 2024-04-17  9:21     ` Anna-Maria Behnsen
  2024-04-17 11:08       ` Oleg Nesterov
  0 siblings, 1 reply; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-17  9:21 UTC (permalink / raw)
  To: Oleg Nesterov, Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, John Stultz, Peter Zijlstra,
	Ingo Molnar, Stephen Boyd, Eric Biederman

Oleg Nesterov <oleg@redhat.com> writes:

> On 04/11, Thomas Gleixner wrote:
>>
>> In preparation for addressing issues in the timer_get() and timer_set()
>> functions of posix CPU timers.
>
> Cough... I must have missed something, but posix_cpu_timer_get()
> doesn't look right with or without this trivial patch.
>
> It doesn't initialize itp->it_value if cpu_timer_getexpires() == 0,
> this means that sys_timer_gettime() will copy the uninitialized
> cur_setting->it_value on the stack to userspace?

The initialization of itp is already done by the callsites.
do_timer_settime() in posix-timers.c as well as do_cpu_nanosleep() in
posix-cpu-timers.c execute a memset before calling
posix_cpu_timer_get(). So this should be fine - or did I miss something
here?

Thanks,

	Anna-Maria


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 21/50] posix-cpu-timers: Make k_itimer::it_active consistent
  2024-04-10 22:46 ` [patch V2 21/50] posix-cpu-timers: Make k_itimer::it_active consistent Thomas Gleixner
@ 2024-04-17 10:11   ` Anna-Maria Behnsen
  0 siblings, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-17 10:11 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> Posix CPU timers are not updating k_itimer::it_active which makes it
> impossible to base decisions in the common posix timer code on it.
>
> Update it when queueing or dequeueing posix CPU timers.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> V2: Move the clearing to cpu_timer_fire() - Frederic
> ---
>  kernel/time/posix-cpu-timers.c |    4 ++++
>  1 file changed, 4 insertions(+)
>
> --- a/kernel/time/posix-cpu-timers.c
> +++ b/kernel/time/posix-cpu-timers.c
> @@ -453,6 +453,7 @@ static void disarm_timer(struct k_itimer
>  	struct cpu_timer *ctmr = &timer->it.cpu;
>  	struct posix_cputimer_base *base;
>  
> +	timer->it_active = 0;
>  	if (!cpu_timer_dequeue(ctmr))
>  		return;
>  
> @@ -559,6 +560,7 @@ static void arm_timer(struct k_itimer *t
>  	struct cpu_timer *ctmr = &timer->it.cpu;
>  	u64 newexp = cpu_timer_getexpires(ctmr);
>  
> +	timer->it_active = 1;
>  	if (!cpu_timer_enqueue(&base->tqhead, ctmr))
>  		return;
>  
> @@ -584,6 +586,7 @@ static void cpu_timer_fire(struct k_itim
>  {
>  	struct cpu_timer *ctmr = &timer->it.cpu;
>  
> +	timer->it_active = 0;
>  	if (unlikely(timer->sigq == NULL)) {
>  		/*
>  		 * This a special case for clock_nanosleep,
> @@ -668,6 +671,7 @@ static int posix_cpu_timer_set(struct k_
>  		ret = TIMER_RETRY;
>  	} else {
>  		cpu_timer_dequeue(ctmr);
> +		timer->it_active = 0;

NIT: you could change the order of the above two commands, then it is in
the same order as the others.

with or without changing the NIT:
Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
  2024-04-17  9:21     ` Anna-Maria Behnsen
@ 2024-04-17 11:08       ` Oleg Nesterov
  0 siblings, 0 replies; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-17 11:08 UTC (permalink / raw)
  To: Anna-Maria Behnsen
  Cc: Thomas Gleixner, LKML, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On 04/17, Anna-Maria Behnsen wrote:
>
> Oleg Nesterov <oleg@redhat.com> writes:
>
> > On 04/11, Thomas Gleixner wrote:
> >>
> >> In preparation for addressing issues in the timer_get() and timer_set()
> >> functions of posix CPU timers.
> >
> > Cough... I must have missed something, but posix_cpu_timer_get()
> > doesn't look right with or without this trivial patch.
> >
> > It doesn't initialize itp->it_value if cpu_timer_getexpires() == 0,
> > this means that sys_timer_gettime() will copy the uninitialized
> > cur_setting->it_value on the stack to userspace?
>
> The initialization of itp is already done by the callsites.
> do_timer_settime() in posix-timers.c as well as do_cpu_nanosleep() in
> posix-cpu-timers.c execute a memset before calling
> posix_cpu_timer_get().

Indeed. Somehow I missed this memset(). Even if I tried to read the
simple do_timer_gettime/posix_cpu_timer_get functions several times ;)

Thanks for correcting me!

Oleg.


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 25/50] signal: Confine POSIX_TIMERS properly
  2024-04-10 22:46 ` [patch V2 25/50] signal: Confine POSIX_TIMERS properly Thomas Gleixner
@ 2024-04-17 12:09   ` Anna-Maria Behnsen
  2024-04-18 15:23   ` Oleg Nesterov
  1 sibling, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-17 12:09 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> Move the itimer rearming out of the signal code and consolidate all posix
> timer related functions in the signal code under one ifdef.

It would be easier to read, when it is splitted. But I made it :)

With the typo fix below feel free to add:

Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>


> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
>  include/linux/posix-timers.h |    5 +
>  kernel/signal.c              |  125 +++++++++++++++----------------------------
>  kernel/time/itimer.c         |   22 +++++++
>  kernel/time/posix-timers.c   |   15 ++++-
>  4 files changed, 82 insertions(+), 85 deletions(-)
>
> --- a/include/linux/posix-timers.h
> +++ b/include/linux/posix-timers.h

[...]

> @@ -151,7 +151,27 @@ COMPAT_SYSCALL_DEFINE2(getitimer, int, w
>  #endif
>  
>  /*
> - * The timer is automagically restarted, when interval != 0
> + * Invoked from dequeue_signal() when SIG_ALRM is delivered.

s/SIG_ALRM/SIGALRM


> + *
> + * Restart the ITIMER_REAL timer if it is armed as periodic timer.  Doing
> + * this in the signal delivery path instead of self rearming prevents a DoS
> + * with small increments in the high reolution timer case and reduces timer
> + * noise in general.
> + */
> +void posixtimer_rearm_itimer(struct task_struct *tsk)
> +{
> +	struct hrtimer *tmr = &tsk->signal->real_timer;
> +
> +	if (!hrtimer_is_queued(tmr) && tsk->signal->it_real_incr != 0) {
> +		hrtimer_forward(tmr, tmr->base->get_time(),
> +				tsk->signal->it_real_incr);
> +		hrtimer_restart(tmr);
> +	}
> +}
> +
> +/*
> + * Interval timers are restarted in the signal delivery path.  See
> + * posixtimer_rearm_itimer().
>   */
>  enum hrtimer_restart it_real_fn(struct hrtimer *timer)
>  {

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 31/50] posix-timers: Add proper state tracking
  2024-04-10 22:47 ` [patch V2 31/50] posix-timers: Add proper state tracking Thomas Gleixner
@ 2024-04-17 13:40   ` Anna-Maria Behnsen
  0 siblings, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-17 13:40 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> Right now the state tracking is done by two struct members:
>
>  - it_active:
>      A boolean which tracks armed/disarmed state
>
>  - it_signal_seq:
>      A sequence counter which is used to invalidate settings
>      and prevent rearming
>
> Replace it_active with it_status and keep properly track about the states
> in one place.
>
> This allows to reuse it_signal_seq to track reprogramming, disarm and
> delete operations in order to drop signals which are related to the state
> previous of those operations.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

[...]

> --- a/kernel/time/posix-cpu-timers.c
> +++ b/kernel/time/posix-cpu-timers.c
> @@ -453,7 +453,6 @@ static void disarm_timer(struct k_itimer
>  	struct cpu_timer *ctmr = &timer->it.cpu;
>  	struct posix_cputimer_base *base;
>  
> -	timer->it_active = 0;
>  	if (!cpu_timer_dequeue(ctmr))
>  		return;
>  
> @@ -494,11 +493,12 @@ static int posix_cpu_timer_del(struct k_
>  		 */
>  		WARN_ON_ONCE(ctmr->head || timerqueue_node_queued(&ctmr->node));
>  	} else {
> -		if (timer->it.cpu.firing)
> +		if (timer->it.cpu.firing) {
>  			ret = TIMER_RETRY;
> -		else
> +		} else {
>  			disarm_timer(timer, p);
> -
> +			timer->it_status = POSIX_TIMER_DISARMED;
> +		}
>  		unlock_task_sighand(p, &flags);
>  	}

Why do you move the update of the it_status here and do not reuse the
place where you added the it_active in patch 21 "posix-cpu-timers: Make
k_itimer::it_active consistent"? Then the update of the state would
still be next to cpu_timer_dequeue().

[...]

> @@ -647,10 +650,10 @@ void common_timer_get(struct k_itimer *t
>  	/* interval timer ? */
>  	if (iv) {
>  		cur_setting->it_interval = ktime_to_timespec64(iv);
> -	} else if (!timr->it_active) {
> +	} else if (timr->it_status == POSIX_TIMER_DISARMED) {
>  		/*
>  		 * SIGEV_NONE oneshot timers are never queued and therefore
> -		 * timr->it_active is always false. The check below
> +		 * timr->it_status is always DISARMED. The check below

s/DISARMED/POSIX_TIMER_DISARMED/

This change would help when using grep.

>  		 * vs. remaining time will handle this case.
>  		 *
>  		 * For all other timers there is nothing to update here, so


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
  2024-04-10 22:46 ` [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get() Thomas Gleixner
                     ` (2 preceding siblings ...)
  2024-04-16 14:44   ` Oleg Nesterov
@ 2024-04-17 20:33   ` Frederic Weisbecker
  3 siblings, 0 replies; 91+ messages in thread
From: Frederic Weisbecker @ 2024-04-17 20:33 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, John Stultz, Peter Zijlstra,
	Ingo Molnar, Stephen Boyd, Eric Biederman, Oleg Nesterov

Le Thu, Apr 11, 2024 at 12:46:24AM +0200, Thomas Gleixner a écrit :
> In preparation for addressing issues in the timer_get() and timer_set()
> functions of posix CPU timers.
> 
> No functional change.
> 
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Reviewed-by: Frederic Weisbecker <frederic@kernel.org>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 09/50] posix-cpu-timers: Handle interval timers correctly in timer_get()
  2024-04-10 22:46 ` [patch V2 09/50] posix-cpu-timers: Handle interval timers correctly in timer_get() Thomas Gleixner
@ 2024-04-17 22:50   ` Frederic Weisbecker
  0 siblings, 0 replies; 91+ messages in thread
From: Frederic Weisbecker @ 2024-04-17 22:50 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, John Stultz, Peter Zijlstra,
	Ingo Molnar, Stephen Boyd, Eric Biederman, Oleg Nesterov

Le Thu, Apr 11, 2024 at 12:46:27AM +0200, Thomas Gleixner a écrit :
> timer_gettime() must return the remaining time to the next expiry of a
> timer or 0 if the timer is not armed and no signal pending, but posix CPU
> timers fail to forward a timer which is already expired.
> 
> Add the required logic to address that.
> 
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Reviewed-by: Frederic Weisbecker <frederic@kernel.org>

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 11/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_set()
  2024-04-11 22:02     ` Thomas Gleixner
@ 2024-04-17 23:04       ` Frederic Weisbecker
  0 siblings, 0 replies; 91+ messages in thread
From: Frederic Weisbecker @ 2024-04-17 23:04 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Anna-Maria Behnsen, LKML, John Stultz, Peter Zijlstra,
	Ingo Molnar, Stephen Boyd, Eric Biederman, Oleg Nesterov

Le Fri, Apr 12, 2024 at 12:02:28AM +0200, Thomas Gleixner a écrit :
> On Thu, Apr 11 2024 at 17:48, Anna-Maria Behnsen wrote:
> 
> > Thomas Gleixner <tglx@linutronix.de> writes:
> >
> >> Expired SIGEV_NONE oneshot timers must return 0 nsec for the expiry time in
> >> timer_get(), but the posix CPU timer implementation returns 1 nsec.
> >
> > copy paste error (get/set) ?
> 
> Yes.
> 
> >> Add the missing conditional.
> >>
> >> This will be cleaned up in a follow up patch.
> >
> > I'm confused. Why do you want to cleanup the conditional in a follow up
> > patch?
> 
> This patch is to fix the issue. The next one consolidates the code, but
> I can see why the "this will be ..." part of the changelog does not make
> sense.

But please keep it cut that way. FWIW it's much easier to review than the
previous take. That way we aren't missing subtle changes.

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 32/50] posix-timers: Make signal delivery consistent
  2024-04-10 22:47 ` [patch V2 32/50] posix-timers: Make signal delivery consistent Thomas Gleixner
@ 2024-04-18 10:29   ` Anna-Maria Behnsen
  0 siblings, 0 replies; 91+ messages in thread
From: Anna-Maria Behnsen @ 2024-04-18 10:29 UTC (permalink / raw)
  To: Thomas Gleixner, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

Thomas Gleixner <tglx@linutronix.de> writes:

> Signals of timers which are reprogammed, disarmed or deleted can deliver
> signals related to the past. The POSIX spec is blury about this:
>
>  - "The effect of disarming or resetting a timer with pending expiration
>    notifications is unspecified."
>
>  - "The disposition of pending signals for the deleted timer is
>     unspecified."
>
> In both cases it is reasonable to expect that pending signals are
> discarded. Especially in the reprogramming case it does not make sense to
> account for previous overruns or to deliver a signal for a timer which has
> been disarmed. This makes the behaviour consistent and understandable.
>
> Remove the si_sys_private check from the signal delivery code and invoke
> posix_timer_deliver_signal() unconditionally.

s/posix_timer/posixtimer/ (or renaming the function when you introduced
it)

>
> Change that function so it controls the actual signal delivery via the
> return value. It now instructs the signal code to drop the signal when:
>
>   1) The timer does not longer exist in the hash table
>
>   2) The timer signal_seq value is not the same as the si_sys_private value
>      which was set when the signal was queued.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

[...]

> --- a/kernel/time/posix-timers.c
> +++ b/kernel/time/posix-timers.c
> @@ -293,19 +297,19 @@ bool posixtimer_deliver_signal(struct ke
>  int posix_timer_queue_signal(struct k_itimer *timr)
>  {
>  	enum posix_timer_state state = POSIX_TIMER_DISARMED;
> -	int ret, si_private = 0;
>  	enum pid_type type;
> +	int ret;
>  
>  	lockdep_assert_held(&timr->it_lock);
>  
>  	if (timr->it_interval) {
> +		timr->it_signal_seq++;
>  		state = POSIX_TIMER_REQUEUE_PENDING;
> -		si_private = ++timr->it_signal_seq;
>  	}
>  	timr->it_status = state;
>  
>  	type = !(timr->it_sigev_notify & SIGEV_THREAD_ID) ? PIDTYPE_TGID : PIDTYPE_PID;
> -	ret = send_sigqueue(timr->sigq, timr->it_pid, type, si_private);
> +	ret = send_sigqueue(timr->sigq, timr->it_pid, type, timr->it_signal_seq);
>  	/* If we failed to send the signal the timer stops. */
>  	return ret > 0;
>  }

posix_timer_queue_signal() is executed, when a
posix/posix-cpu/alarmtimer expires. There is the check for it_interval
set, to decide whether reprogramming takes place or not.

If I understood it correctly, a resetted or deleted timer should not get
a signal delivered so it should also do not requeue a timer. But when
the timer expires at the same time when trying to reset or delete it,
the above it_interval check reduces the chance that a timer is
nevertheless requeued. Right?

> @@ -889,8 +891,6 @@ int common_timer_set(struct k_itimer *ti
>  	if (old_setting)
>  		common_timer_get(timr, old_setting);
>  
> -	/* Prevent rearming by clearing the interval */
> -	timr->it_interval = 0;

But here the clearing of the interval is removed. So it is more likely,
that the timer is reamed, when expiring and resetting happens at the
same time. Same thing when deleting the timer (see next hunk). Is this
ok, that the behavior changes like this?

But keeping the clearing of the interval is also a problem here - if I'm
not totally on the wrong track. When an expiry and resetting of the
timer happens together and old_setting is set, then the
timr->it_interval is cleared and timer_try_to_cancel() will fail so
TIMER_RETRY is returend to do_timer_settime(). In do_timer_settime() the
timr->it_interval is written into the old_setting struct. But this is
then cleared even if it was set before... hmm...

>  	/*
>  	 * Careful here. On SMP systems the timer expiry function could be
>  	 * active and spinning on timr->it_lock.
> @@ -1008,7 +1011,6 @@ int common_timer_del(struct k_itimer *ti
>  {
>  	const struct k_clock *kc = timer->kclock;
>  
> -	timer->it_interval = 0;
>  	if (kc->timer_try_to_cancel(timer) < 0)
>  		return TIMER_RETRY;
>  	timer->it_status = POSIX_TIMER_DISARMED;

Thanks,

	Anna-Maria


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 23/50] signal: Remove task argument from dequeue_signal()
  2024-04-10 22:46 ` [patch V2 23/50] signal: Remove task argument from dequeue_signal() Thomas Gleixner
@ 2024-04-18 14:18   ` Oleg Nesterov
  0 siblings, 0 replies; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-18 14:18 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On 04/11, Thomas Gleixner wrote:
>
> The task pointer which is handed to dequeue_signal() is always current. The
> argument along with the first comment about signalfd in that function is
> confusing at best. Remove it and use current internally.
>
> Update the stale comment for dequeue_signal() while at it.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
> ---
>  fs/signalfd.c                |    4 ++--
>  include/linux/sched/signal.h |    5 ++---
>  kernel/signal.c              |   23 ++++++++++-------------

Reviewed-by: Oleg Nesterov <oleg@redhat.com>


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 24/50] signal: Replace BUG_ON()s
  2024-04-10 22:46 ` [patch V2 24/50] signal: Replace BUG_ON()s Thomas Gleixner
@ 2024-04-18 14:37   ` Oleg Nesterov
  0 siblings, 0 replies; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-18 14:37 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On 04/11, Thomas Gleixner wrote:
>
> These really can be handled gracefully without killing the machine.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
> ---
>  kernel/signal.c |   11 +++++++----
>  1 file changed, 7 insertions(+), 4 deletions(-)

Reviewed-by: Oleg Nesterov <oleg@redhat.com>


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 25/50] signal: Confine POSIX_TIMERS properly
  2024-04-10 22:46 ` [patch V2 25/50] signal: Confine POSIX_TIMERS properly Thomas Gleixner
  2024-04-17 12:09   ` Anna-Maria Behnsen
@ 2024-04-18 15:23   ` Oleg Nesterov
  2024-04-19  5:42     ` Thomas Gleixner
  1 sibling, 1 reply; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-18 15:23 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On 04/11, Thomas Gleixner wrote:
>
> Move the itimer rearming out of the signal code and consolidate all posix
> timer related functions in the signal code under one ifdef.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
>  include/linux/posix-timers.h |    5 +
>  kernel/signal.c              |  125 +++++++++++++++----------------------------
>  kernel/time/itimer.c         |   22 +++++++
>  kernel/time/posix-timers.c   |   15 ++++-
>  4 files changed, 82 insertions(+), 85 deletions(-)

Reviewed-by: Oleg Nesterov <oleg@redhat.com>


A minor nit below...

> --- a/include/linux/posix-timers.h
> +++ b/include/linux/posix-timers.h
...
> +static inline void posixtimer_rearm_itimer(struct task_struct *p) { }
> +static inline void posixtimer_rearm(struct kernel_siginfo *info) { }

Do we really need these 2 nops ? please see below.

...

> +		if (unlikely(signr == SIGALRM))
> +			posixtimer_rearm_itimer(tsk);

...

> +	if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
> +		if (unlikely(resched_timer))
> +			posixtimer_rearm(info);
>  	}

This looks a bit inconsistent to me.

Can't we change the callsite of posixtimer_rearm_itimer() to check
IS_ENABLED(CONFIG_POSIX_TIMERS) too,

		if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
			if (unlikely(signr == SIGALRM))
				posixtimer_rearm_itimer(tsk);
		}
?

This will make the code more symmetrical, and we can avoid the dumb
definitions of posixtimer_rearm_itimer/posixtimer_rearm.

Oleg.


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 26/50] signal: Get rid of resched_timer logic
  2024-04-10 22:46 ` [patch V2 26/50] signal: Get rid of resched_timer logic Thomas Gleixner
@ 2024-04-18 16:38   ` Oleg Nesterov
  2024-04-18 18:18     ` Oleg Nesterov
  0 siblings, 1 reply; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-18 16:38 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On 04/11, Thomas Gleixner wrote:
>
> There is no reason for handing the *resched pointer argument through
> several functions just to check whether the signal is related to a self
> rearming posix timer.

Agreed, these changes looks good to me.

But,

> SI_TIMER is only used by the posix timer code and cannot be queued from
> user space.

Why? I think sigqueueinfo() can certainly use si_code = SI_TIMER, so

> @@ -1011,6 +1001,9 @@ static int __send_signal_locked(int sig,
>  
>  	lockdep_assert_held(&t->sighand->siglock);
>  
> +	if (WARN_ON_ONCE(!is_si_special(info) && info->si_code == SI_TIMER))
> +		return 0;

this can be easily triggered by userspace and thus looks wrong.

Oleg.


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 26/50] signal: Get rid of resched_timer logic
  2024-04-18 16:38   ` Oleg Nesterov
@ 2024-04-18 18:18     ` Oleg Nesterov
  2024-04-19 11:06       ` Oleg Nesterov
  0 siblings, 1 reply; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-18 18:18 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On 04/18, Oleg Nesterov wrote:
>
> On 04/11, Thomas Gleixner wrote:
> >
> > There is no reason for handing the *resched pointer argument through
> > several functions just to check whether the signal is related to a self
> > rearming posix timer.
>
> Agreed, these changes looks good to me.

I meant the intent.

But this is not simple, collect_signal() checks SIGQUEUE_PREALLOC exactly
because (iiuc) we need to ensure that SI_TIMER didn't come from userspace.

perhaps we should disallow SI_TIMER with _sys_private != 0 from userspace,
I dunno...

And I don't really understand the "not to be passed to user" comment in
include/uapi/asm-generic/siginfo.h. copy_siginfo_to_user() just copies
the whole kernel_siginfo.

Confused.

> But,
> 
> > SI_TIMER is only used by the posix timer code and cannot be queued from
> > user space.
> 
> Why? I think sigqueueinfo() can certainly use si_code = SI_TIMER, so
> 
> > @@ -1011,6 +1001,9 @@ static int __send_signal_locked(int sig,
> >  
> >  	lockdep_assert_held(&t->sighand->siglock);
> >  
> > +	if (WARN_ON_ONCE(!is_si_special(info) && info->si_code == SI_TIMER))
> > +		return 0;
> 
> this can be easily triggered by userspace and thus looks wrong.
> 
> Oleg.


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 25/50] signal: Confine POSIX_TIMERS properly
  2024-04-18 15:23   ` Oleg Nesterov
@ 2024-04-19  5:42     ` Thomas Gleixner
  0 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-19  5:42 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On Thu, Apr 18 2024 at 17:23, Oleg Nesterov wrote:
> On 04/11, Thomas Gleixner wrote:
>> +static inline void posixtimer_rearm_itimer(struct task_struct *p) { }
>> +static inline void posixtimer_rearm(struct kernel_siginfo *info) { }
>
> Do we really need these 2 nops ? please see below.

>> +		if (unlikely(signr == SIGALRM))
>> +			posixtimer_rearm_itimer(tsk);
>
> ...
>
>> +	if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
>> +		if (unlikely(resched_timer))
>> +			posixtimer_rearm(info);
>>  	}
>
> This looks a bit inconsistent to me.
>
> Can't we change the callsite of posixtimer_rearm_itimer() to check
> IS_ENABLED(CONFIG_POSIX_TIMERS) too,
>
> 		if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
> 			if (unlikely(signr == SIGALRM))
> 				posixtimer_rearm_itimer(tsk);
> 		}
> ?
>
> This will make the code more symmetrical, and we can avoid the dumb
> definitions of posixtimer_rearm_itimer/posixtimer_rearm.

Yes, we just need to expose the actual function prototypes
unconditionally. Let me fix that.

Thanks,

        tglx



^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 26/50] signal: Get rid of resched_timer logic
  2024-04-18 18:18     ` Oleg Nesterov
@ 2024-04-19 11:06       ` Oleg Nesterov
  2024-04-23 21:18         ` Thomas Gleixner
  0 siblings, 1 reply; 91+ messages in thread
From: Oleg Nesterov @ 2024-04-19 11:06 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman

On 04/18, Oleg Nesterov wrote:
>
> On 04/18, Oleg Nesterov wrote:
> >
> > On 04/11, Thomas Gleixner wrote:
> > >
> > > There is no reason for handing the *resched pointer argument through
> > > several functions just to check whether the signal is related to a self
> > > rearming posix timer.
> >
> > Agreed, these changes looks good to me.
>
> I meant the intent.
>
> But this is not simple, collect_signal() checks SIGQUEUE_PREALLOC exactly
> because (iiuc) we need to ensure that SI_TIMER didn't come from userspace.
>
> perhaps we should disallow SI_TIMER with _sys_private != 0 from userspace,
> I dunno...
>
> And I don't really understand the "not to be passed to user" comment in
> include/uapi/asm-generic/siginfo.h. copy_siginfo_to_user() just copies
> the whole kernel_siginfo.

OK, si_sys_private is cleared in dequeue_signal() (or in posixtimer_rearm()
with this series).

In the past SI_TIMER was defined as __SI_CODE(__SI_TIMER,-2), it was > 0,
so it could not come from userspace (see the info->si_code >= 0 check in
do_rt_sigqueueinfo).

Today SI_TIMER < 0. We could introduce SI_TIMER_KERNEL > 0 with the minimal
changes, but this can't help because the commit 66dd34ad31e59 allows to send
any siginfo to itself.

Otoh, I have no idea how CRIU restores the posix timers. If a process has
a pending blocked SI_TIMER signal, then I guess it actually needs to enqueue
this signal at restore time, but resched_timer will be never true?

I got lost... Sorry for the noise.

> Confused.
>
> > But,
> >
> > > SI_TIMER is only used by the posix timer code and cannot be queued from
> > > user space.
> >
> > Why? I think sigqueueinfo() can certainly use si_code = SI_TIMER, so
> >
> > > @@ -1011,6 +1001,9 @@ static int __send_signal_locked(int sig,
> > >
> > >  	lockdep_assert_held(&t->sighand->siglock);
> > >
> > > +	if (WARN_ON_ONCE(!is_si_special(info) && info->si_code == SI_TIMER))
> > > +		return 0;
> >
> > this can be easily triggered by userspace and thus looks wrong.
> >
> > Oleg.


^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 20/50] posix-timers: Consolidate timer setup
  2024-04-16 16:12   ` Anna-Maria Behnsen
@ 2024-04-23 19:38     ` Thomas Gleixner
  0 siblings, 0 replies; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-23 19:38 UTC (permalink / raw)
  To: Anna-Maria Behnsen, LKML
  Cc: Frederic Weisbecker, John Stultz, Peter Zijlstra, Ingo Molnar,
	Stephen Boyd, Eric Biederman, Oleg Nesterov

On Tue, Apr 16 2024 at 18:12, Anna-Maria Behnsen wrote:
> Thomas Gleixner <tglx@linutronix.de> writes:
>
>> hrtimer based and CPU timers have their own way to install the new interval
>> and to reset overrun and signal handling related data.
>>
>> Create a helper function and do the same operation for all variants.
>>
>> This also makes the handling of the interval consistent. It's only stored
>> when the timer is actually armed, i.e. timer->it_value != 0. Before that it
>> was stored unconditionally for posix CPU timers and conditionally for the
>> other posix timers.
>
> Shouldn't we do this similar to the gettime() and set it_interval
> unconditionally?

No. If it_value = 0 then the timer is disarmed, so it_interval is
irrelevant and just should be 0 for sanity sake.

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 26/50] signal: Get rid of resched_timer logic
  2024-04-19 11:06       ` Oleg Nesterov
@ 2024-04-23 21:18         ` Thomas Gleixner
  2024-04-24  1:48           ` Thomas Gleixner
  0 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-23 21:18 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Andrei Vagin

On Fri, Apr 19 2024 at 13:06, Oleg Nesterov wrote:
> On 04/18, Oleg Nesterov wrote:
>> But this is not simple, collect_signal() checks SIGQUEUE_PREALLOC exactly
>> because (iiuc) we need to ensure that SI_TIMER didn't come from userspace.
>>
>> perhaps we should disallow SI_TIMER with _sys_private != 0 from userspace,
>> I dunno...
>>
>> And I don't really understand the "not to be passed to user" comment in
>> include/uapi/asm-generic/siginfo.h. copy_siginfo_to_user() just copies
>> the whole kernel_siginfo.
>
> OK, si_sys_private is cleared in dequeue_signal() (or in posixtimer_rearm()
> with this series).
>
> In the past SI_TIMER was defined as __SI_CODE(__SI_TIMER,-2), it was > 0,
> so it could not come from userspace (see the info->si_code >= 0 check in
> do_rt_sigqueueinfo).

Duh.

> Today SI_TIMER < 0. We could introduce SI_TIMER_KERNEL > 0 with the minimal
> changes, but this can't help because the commit 66dd34ad31e59 allows to send
> any siginfo to itself.

Well that predates the __SI_CODE() removal. So I doubt it's required
today, but what do I know about CRIU.

> Otoh, I have no idea how CRIU restores the posix timers. If a process has
> a pending blocked SI_TIMER signal, then I guess it actually needs to enqueue
> this signal at restore time, but resched_timer will be never true?

It can't restore the correct sys_si_private value because that is
nowhere exposed to user space.

There is no special treatment for SI_TIMER, so the signal restore might
just end up queueing a random extra SI_TIMER signal if there was one
pending.

I checked the CRIU source and it looks like this just "works" by
reconstructing and rearming the timer with the last expiry value. As
that is in the past it will fire immediately and queue the signal.

sys_si_private seems to be excluded from being set from user space in
compat mode, but in non-compat mode I can't find anything which prevents
that.

Let me stare more at this. 

Thanks,

        tglx

^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 26/50] signal: Get rid of resched_timer logic
  2024-04-23 21:18         ` Thomas Gleixner
@ 2024-04-24  1:48           ` Thomas Gleixner
  2024-04-25  7:22             ` Andrei Vagin
  0 siblings, 1 reply; 91+ messages in thread
From: Thomas Gleixner @ 2024-04-24  1:48 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: LKML, Anna-Maria Behnsen, Frederic Weisbecker, John Stultz,
	Peter Zijlstra, Ingo Molnar, Stephen Boyd, Eric Biederman,
	Andrei Vagin

On Tue, Apr 23 2024 at 23:18, Thomas Gleixner wrote:
> On Fri, Apr 19 2024 at 13:06, Oleg Nesterov wrote:
>> Otoh, I have no idea how CRIU restores the posix timers. If a process has
>> a pending blocked SI_TIMER signal, then I guess it actually needs to enqueue
>> this signal at restore time, but resched_timer will be never true?
>
> It can't restore the correct sys_si_private value because that is
> nowhere exposed to user space.

It is exposed via PTRACE_PEEKSIGINFO, but it's useless.

> There is no special treatment for SI_TIMER, so the signal restore might
> just end up queueing a random extra SI_TIMER signal if there was one
> pending.

It does. The sys_si_private value is not going to match the timer side
value and obviously the missing prealloc flag prevents it from trying to
rearm the timer.

> I checked the CRIU source and it looks like this just "works" by
> reconstructing and rearming the timer with the last expiry value. As
> that is in the past it will fire immediately and queue the signal.

It's not necessarily in the past, but it will fire eventually and in the
case of a blocked signal there will be two SI_TIMER signals queued.

So the patch is not completely wrong except that there is nothing which
prevents setting sys_si_private via rt_sigqueueinfo(), but that's
obviously a solvable problem. With that solved the condition:

                *resched_timer =
                        (first->flags & SIGQUEUE_PREALLOC) &&
                        (info->si_code == SI_TIMER) &&
                        (info->si_sys_private);
          
really can be reduced to:

       info->code == SI_TIMER && info->si_sys_private

In fact it makes a lot of sense _not_ to allow user space to set
info->si_sys_private because that's a kernel internal value and should
never be exposed to user space in the first place.

Let me look what it needs or if this can be solved slightly differently.



^ permalink raw reply	[flat|nested] 91+ messages in thread

* Re: [patch V2 26/50] signal: Get rid of resched_timer logic
  2024-04-24  1:48           ` Thomas Gleixner
@ 2024-04-25  7:22             ` Andrei Vagin
  0 siblings, 0 replies; 91+ messages in thread
From: Andrei Vagin @ 2024-04-25  7:22 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Oleg Nesterov, LKML, Anna-Maria Behnsen, Frederic Weisbecker,
	John Stultz, Peter Zijlstra, Ingo Molnar, Stephen Boyd,
	Eric Biederman

On Tue, Apr 23, 2024 at 6:48 PM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> On Tue, Apr 23 2024 at 23:18, Thomas Gleixner wrote:
> > On Fri, Apr 19 2024 at 13:06, Oleg Nesterov wrote:
> >> Today SI_TIMER < 0. We could introduce SI_TIMER_KERNEL > 0 with the minimal
> >> changes, but this can't help because the commit 66dd34ad31e59 allows to send
> >> any siginfo to itself.
>
> Well that predates the __SI_CODE() removal. So I doubt it's required
> today, but what do I know about CRIU.

CRIU needs to restore siginfo-s of pending signals so that a task sees
the same siginfo in a signal handler as it would be without
checkpoint/restore. CRIU will not be affected, if rt_sigqueueinfo denies
any non-negative si_code that is never reported by the kernel.

> >> Otoh, I have no idea how CRIU restores the posix timers. If a process has
> >> a pending blocked SI_TIMER signal, then I guess it actually needs to enqueue
> >> this signal at restore time, but resched_timer will be never true?
> >
> > It can't restore the correct sys_si_private value because that is
> > nowhere exposed to user space.

We are open to ideas how it can be restored properly.

>
> It is exposed via PTRACE_PEEKSIGINFO, but it's useless.

When PTRACE_PEEKSIGINFO was added, it didn't expose it.  Then it was
changed by cc731525f26a ("signal: Remove kernel internal si_code magic").

The idea of PTRACE_PEEKSIGINFO is to get a siginfo that a process would
see in a signal handler.

>
> > There is no special treatment for SI_TIMER, so the signal restore might
> > just end up queueing a random extra SI_TIMER signal if there was one
> > pending.
>
> It does. The sys_si_private value is not going to match the timer side
> value and obviously the missing prealloc flag prevents it from trying to
> rearm the timer.
>
> > I checked the CRIU source and it looks like this just "works" by
> > reconstructing and rearming the timer with the last expiry value. As
> > that is in the past it will fire immediately and queue the signal.
>
> It's not necessarily in the past, but it will fire eventually and in the
> case of a blocked signal there will be two SI_TIMER signals queued.
>
> So the patch is not completely wrong except that there is nothing which
> prevents setting sys_si_private via rt_sigqueueinfo(), but that's
> obviously a solvable problem. With that solved the condition:
>
>                 *resched_timer =
>                         (first->flags & SIGQUEUE_PREALLOC) &&
>                         (info->si_code == SI_TIMER) &&
>                         (info->si_sys_private);
>
> really can be reduced to:
>
>        info->code == SI_TIMER && info->si_sys_private
>
> In fact it makes a lot of sense _not_ to allow user space to set
> info->si_sys_private because that's a kernel internal value and should
> never be exposed to user space in the first place.

We can zero out all of them in rt_sigqueueinfo.

Thanks,
Andrei

^ permalink raw reply	[flat|nested] 91+ messages in thread

end of thread, other threads:[~2024-04-25  7:22 UTC | newest]

Thread overview: 91+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-10 22:46 [patch V2 00/50] posix-timers: Cure inconsistencies and the SIG_IGN mess Thomas Gleixner
2024-04-10 22:46 ` [patch V2 01/50] selftests/timers/posix_timers: Simplify error handling Thomas Gleixner
2024-04-12  7:35   ` Anna-Maria Behnsen
2024-04-10 22:46 ` [patch V2 02/50] selftests/timers/posix_timers: Add SIG_IGN test Thomas Gleixner
2024-04-10 22:46 ` [patch V2 03/50] selftests/timers/posix_timers: Validate signal rules Thomas Gleixner
2024-04-10 22:46 ` [patch V2 04/50] selftests/timers/posix-timers: Validate SIGEV_NONE Thomas Gleixner
2024-04-10 22:46 ` [patch V2 05/50] selftests/timers/posix-timers: Validate timer_gettime() Thomas Gleixner
2024-04-10 22:46 ` [patch V2 06/50] selftests/timers/posix-timers: Validate overrun after unblock Thomas Gleixner
2024-04-10 22:46 ` [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get() Thomas Gleixner
2024-04-12  7:35   ` Anna-Maria Behnsen
2024-04-12 18:25   ` Eric W. Biederman
2024-04-12 19:48     ` Thomas Gleixner
2024-04-16 14:44   ` Oleg Nesterov
2024-04-17  9:21     ` Anna-Maria Behnsen
2024-04-17 11:08       ` Oleg Nesterov
2024-04-17 20:33   ` Frederic Weisbecker
2024-04-10 22:46 ` [patch V2 08/50] posix-cpu-timers: Save interval only for armed timers Thomas Gleixner
2024-04-11 14:25   ` Anna-Maria Behnsen
2024-04-11 22:00     ` Thomas Gleixner
2024-04-10 22:46 ` [patch V2 09/50] posix-cpu-timers: Handle interval timers correctly in timer_get() Thomas Gleixner
2024-04-17 22:50   ` Frederic Weisbecker
2024-04-10 22:46 ` [patch V2 10/50] posix-cpu-timers: Handle SIGEV_NONE " Thomas Gleixner
2024-04-12 18:40   ` Eric W. Biederman
2024-04-12 19:49     ` Thomas Gleixner
2024-04-10 22:46 ` [patch V2 11/50] posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_set() Thomas Gleixner
2024-04-11 15:48   ` Anna-Maria Behnsen
2024-04-11 22:02     ` Thomas Gleixner
2024-04-17 23:04       ` Frederic Weisbecker
2024-04-10 22:46 ` [patch V2 12/50] posix-cpu-timers: Replace old expiry retrieval in posix_cpu_timer_set() Thomas Gleixner
2024-04-15 14:03   ` Anna-Maria Behnsen
2024-04-10 22:46 ` [patch V2 13/50] posix-cpu-timers: Do not arm SIGEV_NONE timers Thomas Gleixner
2024-04-15 14:03   ` Anna-Maria Behnsen
2024-04-10 22:46 ` [patch V2 14/50] posix-cpu-timers: Use @now instead of @val for clarity Thomas Gleixner
2024-04-10 22:46 ` [patch V2 15/50] posix-cpu-timers: Remove incorrect comment in posix_cpu_timer_set() Thomas Gleixner
2024-04-10 22:46 ` [patch V2 16/50] posix-cpu-timers: Simplify posix_cpu_timer_set() Thomas Gleixner
2024-04-15 15:28   ` Anna-Maria Behnsen
2024-04-10 22:46 ` [patch V2 17/50] posix-timers: Retrieve interval in common timer_settime() code Thomas Gleixner
2024-04-15 15:43   ` Anna-Maria Behnsen
2024-04-10 22:46 ` [patch V2 18/50] posix-timers: Clear overrun in common_timer_set() Thomas Gleixner
2024-04-10 22:46 ` [patch V2 19/50] posix-timers: Convert timer list to hlist Thomas Gleixner
2024-04-10 22:46 ` [patch V2 20/50] posix-timers: Consolidate timer setup Thomas Gleixner
2024-04-16 16:12   ` Anna-Maria Behnsen
2024-04-23 19:38     ` Thomas Gleixner
2024-04-10 22:46 ` [patch V2 21/50] posix-cpu-timers: Make k_itimer::it_active consistent Thomas Gleixner
2024-04-17 10:11   ` Anna-Maria Behnsen
2024-04-10 22:46 ` [patch V2 22/50] posix-timers: Consolidate signal queueing Thomas Gleixner
2024-04-10 22:46 ` [patch V2 23/50] signal: Remove task argument from dequeue_signal() Thomas Gleixner
2024-04-18 14:18   ` Oleg Nesterov
2024-04-10 22:46 ` [patch V2 24/50] signal: Replace BUG_ON()s Thomas Gleixner
2024-04-18 14:37   ` Oleg Nesterov
2024-04-10 22:46 ` [patch V2 25/50] signal: Confine POSIX_TIMERS properly Thomas Gleixner
2024-04-17 12:09   ` Anna-Maria Behnsen
2024-04-18 15:23   ` Oleg Nesterov
2024-04-19  5:42     ` Thomas Gleixner
2024-04-10 22:46 ` [patch V2 26/50] signal: Get rid of resched_timer logic Thomas Gleixner
2024-04-18 16:38   ` Oleg Nesterov
2024-04-18 18:18     ` Oleg Nesterov
2024-04-19 11:06       ` Oleg Nesterov
2024-04-23 21:18         ` Thomas Gleixner
2024-04-24  1:48           ` Thomas Gleixner
2024-04-25  7:22             ` Andrei Vagin
2024-04-10 22:46 ` [patch V2 27/50] posix-timers: Cure si_sys_private race Thomas Gleixner
2024-04-10 22:47 ` [patch V2 28/50] signal: Allow POSIX timer signals to be dropped Thomas Gleixner
2024-04-10 22:47 ` [patch V2 29/50] posix-timers: Drop signal if timer has been deleted or reprogrammed Thomas Gleixner
2024-04-10 22:47 ` [patch V2 30/50] posix-timers: Rename k_itimer::it_requeue_pending Thomas Gleixner
2024-04-10 22:47 ` [patch V2 31/50] posix-timers: Add proper state tracking Thomas Gleixner
2024-04-17 13:40   ` Anna-Maria Behnsen
2024-04-10 22:47 ` [patch V2 32/50] posix-timers: Make signal delivery consistent Thomas Gleixner
2024-04-18 10:29   ` Anna-Maria Behnsen
2024-04-10 22:47 ` [patch V2 33/50] posix-timers: Make signal overrun accounting sensible Thomas Gleixner
2024-04-10 22:47 ` [patch V2 34/50] posix-cpu-timers: Use dedicated flag for CPU timer nanosleep Thomas Gleixner
2024-04-10 22:47 ` [patch V2 35/50] posix-timers: Add a refcount to struct k_itimer Thomas Gleixner
2024-04-10 22:47 ` [patch V2 36/50] signal: Split up __sigqueue_alloc() Thomas Gleixner
2024-04-10 22:47 ` [patch V2 37/50] signal: Provide posixtimer_sigqueue_init() Thomas Gleixner
2024-04-10 22:47 ` [patch V2 38/50] signal: Add sys_private_ptr to siginfo::_sifields::_timer Thomas Gleixner
2024-04-10 22:47 ` [patch V2 39/50] posix-timers: Store PID type in the timer Thomas Gleixner
2024-04-10 22:47 ` [patch V2 40/50] signal: Refactor send_sigqueue() Thomas Gleixner
2024-04-10 22:47 ` [patch V2 41/50] posix-timers: Embed sigqueue in struct k_itimer Thomas Gleixner
2024-04-10 22:47 ` [patch V2 42/50] signal: Cleanup unused posix-timer leftovers Thomas Gleixner
2024-04-10 22:47 ` [patch V2 43/50] signal: Add task argument to flush_sigqueue_mask() Thomas Gleixner
2024-04-10 22:47 ` [patch V2 44/50] signal: Provide ignored_posix_timers list Thomas Gleixner
2024-04-10 22:47 ` [patch V2 45/50] posix-timers: Handle ignored list on delete and exit Thomas Gleixner
2024-04-10 22:47 ` [patch V2 46/50] signal: Handle ignored signals in do_sigaction(action != SIG_IGN) Thomas Gleixner
2024-04-10 22:47 ` [patch V2 47/50] signal: Queue ignored posixtimers on ignore list Thomas Gleixner
2024-04-10 22:47 ` [patch V2 48/50] posix-timers: Cleanup SIG_IGN workaround leftovers Thomas Gleixner
2024-04-10 22:47 ` [patch V2 49/50] alarmtimers: Remove the throttle mechanism from alarm_forward_now() Thomas Gleixner
2024-04-10 22:47 ` [patch V2 50/50] alarmtimers: Remove return value from alarm functions Thomas Gleixner
2024-04-15 12:30 ` [PATCH] posix-timers: Handle returned errors poperly in [i]timer_delete() Anna-Maria Behnsen
2024-04-15 13:00   ` Oleg Nesterov
2024-04-15 14:15     ` Anna-Maria Behnsen
2024-04-15 16:27       ` Oleg Nesterov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).