[PATCH v2 8/8] powerpc: Enable Generic Entry/Exit for syscalls.

Mukesh Kumar Chaurasiya posted 8 patches 1 day, 18 hours ago
[PATCH v2 8/8] powerpc: Enable Generic Entry/Exit for syscalls.
Posted by Mukesh Kumar Chaurasiya 1 day, 18 hours ago
From: Mukesh Kumar Chaurasiya <mchauras@linux.ibm.com>

Convert the PowerPC syscall entry and exit paths to use the generic
entry/exit framework by selecting GENERIC_ENTRY and integrating with
the common syscall handling routines.

This change transitions PowerPC away from its custom syscall entry and
exit code to use the generic helpers such as:
 - syscall_enter_from_user_mode()
 - syscall_exit_to_user_mode()

As part of this migration:
 - The architecture now selects GENERIC_ENTRY in Kconfig.
 - Old tracing, seccomp, and audit handling in ptrace.c is removed in
   favor of generic entry infrastructure.
 - interrupt.c and syscall.c are simplified to delegate context
   management and user exit handling to the generic entry path.
 - The new pt_regs field `exit_flags` introduced earlier is now used
   to carry per-syscall exit state flags (e.g. _TIF_RESTOREALL).

This aligns PowerPC with the common entry code used by other
architectures and reduces duplicated logic around syscall tracing,
context tracking, and signal handling.

The performance benchmarks from perf bench basic syscall are below:

perf bench syscall usec/op

| Test            | With Patch | Without Patch | % Change |
| --------------- | ---------- | ------------- | -------- |
| getppid usec/op | 0.207795   | 0.210373      | -1.22%   |
| getpgid usec/op | 0.206282   | 0.211676      | -2.55%   |
| fork usec/op    | 833.986    | 814.809       | +2.35%   |
| execve usec/op  | 360.939    | 365.168       | -1.16%   |

perf bench syscall ops/sec

| Test            | With Patch | Without Patch | % Change |
| --------------- | ---------- | ------------- | -------- |
| getppid ops/sec | 48,12,433  | 47,53,459     | +1.24%   |
| getpgid ops/sec | 48,47,744  | 47,24,192     | +2.61%   |
| fork ops/sec    | 1,199      | 1,227         | -2.28%   |
| execve ops/sec  | 2,770      | 2,738         | +1.16%   |

IPI latency benchmark

| Metric                  | With Patch       | Without Patch    | % Change |
| ----------------------- | ---------------- | ---------------- | -------- |
| Dry-run (ns)            | 206,675.81       | 206,719.36       | -0.02%   |
| Self-IPI avg (ns)       | 1,939,991.00     | 1,976,116.15     | -1.83%   |
| Self-IPI max (ns)       | 3,533,718.93     | 3,582,650.33     | -1.37%   |
| Normal IPI avg (ns)     | 111,110,034.23   | 110,513,373.51   | +0.54%   |
| Normal IPI max (ns)     | 150,393,442.64   | 149,669,477.89   | +0.48%   |
| Broadcast IPI max (ns)  | 3,978,231,022.96 | 4,359,916,859.46 | -8.73%   |
| Broadcast lock max (ns) | 4,025,425,714.49 | 4,384,956,730.83 | -8.20%   |

Thats very close to performance earlier with arch specific handling.

Signed-off-by: Mukesh Kumar Chaurasiya <mchauras@linux.ibm.com>
---
 arch/powerpc/Kconfig                    |   1 +
 arch/powerpc/include/asm/entry-common.h |   5 +-
 arch/powerpc/kernel/interrupt.c         | 139 +++++++----------------
 arch/powerpc/kernel/ptrace/ptrace.c     | 141 ------------------------
 arch/powerpc/kernel/signal.c            |  10 +-
 arch/powerpc/kernel/syscall.c           | 119 +-------------------
 6 files changed, 49 insertions(+), 366 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index b0c602c3bbe1..a4330775b254 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -203,6 +203,7 @@ config PPC
 	select GENERIC_CPU_AUTOPROBE
 	select GENERIC_CPU_VULNERABILITIES	if PPC_BARRIER_NOSPEC
 	select GENERIC_EARLY_IOREMAP
+	select GENERIC_ENTRY
 	select GENERIC_GETTIMEOFDAY
 	select GENERIC_IDLE_POLL_SETUP
 	select GENERIC_IOREMAP
diff --git a/arch/powerpc/include/asm/entry-common.h b/arch/powerpc/include/asm/entry-common.h
index e2ae7416dee1..77129174f882 100644
--- a/arch/powerpc/include/asm/entry-common.h
+++ b/arch/powerpc/include/asm/entry-common.h
@@ -3,7 +3,7 @@
 #ifndef _ASM_PPC_ENTRY_COMMON_H
 #define _ASM_PPC_ENTRY_COMMON_H
 
-#ifdef CONFIG_GENERIC_IRQ_ENTRY
+#ifdef CONFIG_GENERIC_ENTRY
 
 #include <asm/cputime.h>
 #include <asm/interrupt.h>
@@ -217,9 +217,6 @@ static inline void arch_interrupt_enter_prepare(struct pt_regs *regs)
 
 	if (user_mode(regs)) {
 		kuap_lock();
-		CT_WARN_ON(ct_state() != CT_STATE_USER);
-		user_exit_irqoff();
-
 		account_cpu_user_entry();
 		account_stolen_time();
 	} else {
diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c
index 7f67f0b9d627..7d5cd4b5a610 100644
--- a/arch/powerpc/kernel/interrupt.c
+++ b/arch/powerpc/kernel/interrupt.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include <linux/context_tracking.h>
+#include <linux/entry-common.h>
 #include <linux/err.h>
 #include <linux/compat.h>
 #include <linux/rseq.h>
@@ -73,79 +74,6 @@ static notrace __always_inline bool prep_irq_for_enabled_exit(bool restartable)
 	return true;
 }
 
-static notrace unsigned long
-interrupt_exit_user_prepare_main(unsigned long ret, struct pt_regs *regs)
-{
-	unsigned long ti_flags;
-
-again:
-	ti_flags = read_thread_flags();
-	while (unlikely(ti_flags & (_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM))) {
-		local_irq_enable();
-		if (ti_flags & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY)) {
-			schedule();
-		} else {
-			/*
-			 * SIGPENDING must restore signal handler function
-			 * argument GPRs, and some non-volatiles (e.g., r1).
-			 * Restore all for now. This could be made lighter.
-			 */
-			if (ti_flags & _TIF_SIGPENDING)
-				ret |= _TIF_RESTOREALL;
-			do_notify_resume(regs, ti_flags);
-		}
-		local_irq_disable();
-		ti_flags = read_thread_flags();
-	}
-
-	if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && IS_ENABLED(CONFIG_PPC_FPU)) {
-		if (IS_ENABLED(CONFIG_PPC_TRANSACTIONAL_MEM) &&
-				unlikely((ti_flags & _TIF_RESTORE_TM))) {
-			restore_tm_state(regs);
-		} else {
-			unsigned long mathflags = MSR_FP;
-
-			if (cpu_has_feature(CPU_FTR_VSX))
-				mathflags |= MSR_VEC | MSR_VSX;
-			else if (cpu_has_feature(CPU_FTR_ALTIVEC))
-				mathflags |= MSR_VEC;
-
-			/*
-			 * If userspace MSR has all available FP bits set,
-			 * then they are live and no need to restore. If not,
-			 * it means the regs were given up and restore_math
-			 * may decide to restore them (to avoid taking an FP
-			 * fault).
-			 */
-			if ((regs->msr & mathflags) != mathflags)
-				restore_math(regs);
-		}
-	}
-
-	check_return_regs_valid(regs);
-
-	user_enter_irqoff();
-	if (!prep_irq_for_enabled_exit(true)) {
-		user_exit_irqoff();
-		local_irq_enable();
-		local_irq_disable();
-		goto again;
-	}
-
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-	local_paca->tm_scratch = regs->msr;
-#endif
-
-	booke_load_dbcr0();
-
-	account_cpu_user_exit();
-
-	/* Restore user access locks last */
-	kuap_user_restore(regs);
-
-	return ret;
-}
-
 /*
  * This should be called after a syscall returns, with r3 the return value
  * from the syscall. If this function returns non-zero, the system call
@@ -160,17 +88,12 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
 					   long scv)
 {
 	unsigned long ti_flags;
-	unsigned long ret = 0;
 	bool is_not_scv = !IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !scv;
 
-	CT_WARN_ON(ct_state() == CT_STATE_USER);
-
 	kuap_assert_locked();
 
 	regs->result = r3;
-
-	/* Check whether the syscall is issued inside a restartable sequence */
-	rseq_syscall(regs);
+	regs->exit_flags = 0;
 
 	ti_flags = read_thread_flags();
 
@@ -183,7 +106,7 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
 
 	if (unlikely(ti_flags & _TIF_PERSYSCALL_MASK)) {
 		if (ti_flags & _TIF_RESTOREALL)
-			ret = _TIF_RESTOREALL;
+			regs->exit_flags = _TIF_RESTOREALL;
 		else
 			regs->gpr[3] = r3;
 		clear_bits(_TIF_PERSYSCALL_MASK, &current_thread_info()->flags);
@@ -192,18 +115,28 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
 	}
 
 	if (unlikely(ti_flags & _TIF_SYSCALL_DOTRACE)) {
-		do_syscall_trace_leave(regs);
-		ret |= _TIF_RESTOREALL;
+		regs->exit_flags |= _TIF_RESTOREALL;
 	}
 
-	local_irq_disable();
-	ret = interrupt_exit_user_prepare_main(ret, regs);
+	syscall_exit_to_user_mode(regs);
+
+again:
+	user_enter_irqoff();
+	if (!prep_irq_for_enabled_exit(true)) {
+		user_exit_irqoff();
+		local_irq_enable();
+		local_irq_disable();
+		goto again;
+	}
+
+	/* Restore user access locks last */
+	kuap_user_restore(regs);
 
 #ifdef CONFIG_PPC64
-	regs->exit_result = ret;
+	regs->exit_result = regs->exit_flags;
 #endif
 
-	return ret;
+	return regs->exit_flags;
 }
 
 #ifdef CONFIG_PPC64
@@ -223,13 +156,16 @@ notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *reg
 	set_kuap(AMR_KUAP_BLOCKED);
 #endif
 
-	trace_hardirqs_off();
-	user_exit_irqoff();
-	account_cpu_user_entry();
-
-	BUG_ON(!user_mode(regs));
+again:
+	user_enter_irqoff();
+	if (!prep_irq_for_enabled_exit(true)) {
+		user_exit_irqoff();
+		local_irq_enable();
+		local_irq_disable();
+		goto again;
+	}
 
-	regs->exit_result = interrupt_exit_user_prepare_main(regs->exit_result, regs);
+	regs->exit_result |= regs->exit_flags;
 
 	return regs->exit_result;
 }
@@ -241,7 +177,6 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs)
 
 	BUG_ON(regs_is_unrecoverable(regs));
 	BUG_ON(regs_irqs_disabled(regs));
-	CT_WARN_ON(ct_state() == CT_STATE_USER);
 
 	/*
 	 * We don't need to restore AMR on the way back to userspace for KUAP.
@@ -250,8 +185,21 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs)
 	kuap_assert_locked();
 
 	local_irq_disable();
+	regs->exit_flags = 0;
+again:
+	check_return_regs_valid(regs);
+	user_enter_irqoff();
+	if (!prep_irq_for_enabled_exit(true)) {
+		user_exit_irqoff();
+		local_irq_enable();
+		local_irq_disable();
+		goto again;
+	}
+
+	/* Restore user access locks last */
+	kuap_user_restore(regs);
 
-	ret = interrupt_exit_user_prepare_main(0, regs);
+	ret = regs->exit_flags;
 
 #ifdef CONFIG_PPC64
 	regs->exit_result = ret;
@@ -293,8 +241,6 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs)
 		/* Returning to a kernel context with local irqs enabled. */
 		WARN_ON_ONCE(!(regs->msr & MSR_EE));
 again:
-		if (need_irq_preemption())
-			irqentry_exit_cond_resched();
 
 		check_return_regs_valid(regs);
 
@@ -364,7 +310,6 @@ notrace unsigned long interrupt_exit_user_restart(struct pt_regs *regs)
 #endif
 
 	trace_hardirqs_off();
-	user_exit_irqoff();
 	account_cpu_user_entry();
 
 	BUG_ON(!user_mode(regs));
diff --git a/arch/powerpc/kernel/ptrace/ptrace.c b/arch/powerpc/kernel/ptrace/ptrace.c
index 2134b6d155ff..316d4f5ead8e 100644
--- a/arch/powerpc/kernel/ptrace/ptrace.c
+++ b/arch/powerpc/kernel/ptrace/ptrace.c
@@ -21,9 +21,6 @@
 #include <asm/switch_to.h>
 #include <asm/debug.h>
 
-#define CREATE_TRACE_POINTS
-#include <trace/events/syscalls.h>
-
 #include "ptrace-decl.h"
 
 /*
@@ -195,144 +192,6 @@ long arch_ptrace(struct task_struct *child, long request,
 	return ret;
 }
 
-#ifdef CONFIG_SECCOMP
-static int do_seccomp(struct pt_regs *regs)
-{
-	if (!test_thread_flag(TIF_SECCOMP))
-		return 0;
-
-	/*
-	 * The ABI we present to seccomp tracers is that r3 contains
-	 * the syscall return value and orig_gpr3 contains the first
-	 * syscall parameter. This is different to the ptrace ABI where
-	 * both r3 and orig_gpr3 contain the first syscall parameter.
-	 */
-	regs->gpr[3] = -ENOSYS;
-
-	/*
-	 * We use the __ version here because we have already checked
-	 * TIF_SECCOMP. If this fails, there is nothing left to do, we
-	 * have already loaded -ENOSYS into r3, or seccomp has put
-	 * something else in r3 (via SECCOMP_RET_ERRNO/TRACE).
-	 */
-	if (__secure_computing())
-		return -1;
-
-	/*
-	 * The syscall was allowed by seccomp, restore the register
-	 * state to what audit expects.
-	 * Note that we use orig_gpr3, which means a seccomp tracer can
-	 * modify the first syscall parameter (in orig_gpr3) and also
-	 * allow the syscall to proceed.
-	 */
-	regs->gpr[3] = regs->orig_gpr3;
-
-	return 0;
-}
-#else
-static inline int do_seccomp(struct pt_regs *regs) { return 0; }
-#endif /* CONFIG_SECCOMP */
-
-/**
- * do_syscall_trace_enter() - Do syscall tracing on kernel entry.
- * @regs: the pt_regs of the task to trace (current)
- *
- * Performs various types of tracing on syscall entry. This includes seccomp,
- * ptrace, syscall tracepoints and audit.
- *
- * The pt_regs are potentially visible to userspace via ptrace, so their
- * contents is ABI.
- *
- * One or more of the tracers may modify the contents of pt_regs, in particular
- * to modify arguments or even the syscall number itself.
- *
- * It's also possible that a tracer can choose to reject the system call. In
- * that case this function will return an illegal syscall number, and will put
- * an appropriate return value in regs->r3.
- *
- * Return: the (possibly changed) syscall number.
- */
-long do_syscall_trace_enter(struct pt_regs *regs)
-{
-	u32 flags;
-
-	flags = read_thread_flags() & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE);
-
-	if (flags) {
-		int rc = ptrace_report_syscall_entry(regs);
-
-		if (unlikely(flags & _TIF_SYSCALL_EMU)) {
-			/*
-			 * A nonzero return code from
-			 * ptrace_report_syscall_entry() tells us to prevent
-			 * the syscall execution, but we are not going to
-			 * execute it anyway.
-			 *
-			 * Returning -1 will skip the syscall execution. We want
-			 * to avoid clobbering any registers, so we don't goto
-			 * the skip label below.
-			 */
-			return -1;
-		}
-
-		if (rc) {
-			/*
-			 * The tracer decided to abort the syscall. Note that
-			 * the tracer may also just change regs->gpr[0] to an
-			 * invalid syscall number, that is handled below on the
-			 * exit path.
-			 */
-			goto skip;
-		}
-	}
-
-	/* Run seccomp after ptrace; allow it to set gpr[3]. */
-	if (do_seccomp(regs))
-		return -1;
-
-	/* Avoid trace and audit when syscall is invalid. */
-	if (regs->gpr[0] >= NR_syscalls)
-		goto skip;
-
-	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
-		trace_sys_enter(regs, regs->gpr[0]);
-
-	if (!is_32bit_task())
-		audit_syscall_entry(regs->gpr[0], regs->gpr[3], regs->gpr[4],
-				    regs->gpr[5], regs->gpr[6]);
-	else
-		audit_syscall_entry(regs->gpr[0],
-				    regs->gpr[3] & 0xffffffff,
-				    regs->gpr[4] & 0xffffffff,
-				    regs->gpr[5] & 0xffffffff,
-				    regs->gpr[6] & 0xffffffff);
-
-	/* Return the possibly modified but valid syscall number */
-	return regs->gpr[0];
-
-skip:
-	/*
-	 * If we are aborting explicitly, or if the syscall number is
-	 * now invalid, set the return value to -ENOSYS.
-	 */
-	regs->gpr[3] = -ENOSYS;
-	return -1;
-}
-
-void do_syscall_trace_leave(struct pt_regs *regs)
-{
-	int step;
-
-	audit_syscall_exit(regs);
-
-	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
-		trace_sys_exit(regs, regs->result);
-
-	step = test_thread_flag(TIF_SINGLESTEP);
-	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
-		ptrace_report_syscall_exit(regs, step);
-}
-
 void __init pt_regs_check(void);
 
 /*
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 719930cf4ae1..9f1847b4742e 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -6,6 +6,7 @@
  *    Extracted from signal_32.c and signal_64.c
  */
 
+#include <linux/entry-common.h>
 #include <linux/resume_user_mode.h>
 #include <linux/signal.h>
 #include <linux/uprobes.h>
@@ -22,11 +23,6 @@
 
 #include "signal.h"
 
-/* This will be removed */
-#ifdef CONFIG_GENERIC_ENTRY
-#include <linux/entry-common.h>
-#endif /* CONFIG_GENERIC_ENTRY */
-
 #ifdef CONFIG_VSX
 unsigned long copy_fpr_to_user(void __user *to,
 			       struct task_struct *task)
@@ -374,11 +370,9 @@ void signal_fault(struct task_struct *tsk, struct pt_regs *regs,
 				   task_pid_nr(tsk), where, ptr, regs->nip, regs->link);
 }
 
-#ifdef CONFIG_GENERIC_ENTRY
 void arch_do_signal_or_restart(struct pt_regs *regs)
 {
 	BUG_ON(regs != current->thread.regs);
-	local_paca->generic_fw_flags |= GFW_RESTORE_ALL;
+	regs->exit_flags |= _TIF_RESTOREALL;
 	do_signal(current);
 }
-#endif /* CONFIG_GENERIC_ENTRY */
diff --git a/arch/powerpc/kernel/syscall.c b/arch/powerpc/kernel/syscall.c
index 9f03a6263fb4..df1c9a8d62bc 100644
--- a/arch/powerpc/kernel/syscall.c
+++ b/arch/powerpc/kernel/syscall.c
@@ -3,6 +3,7 @@
 #include <linux/compat.h>
 #include <linux/context_tracking.h>
 #include <linux/randomize_kstack.h>
+#include <linux/entry-common.h>
 
 #include <asm/interrupt.h>
 #include <asm/kup.h>
@@ -18,124 +19,10 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
 	long ret;
 	syscall_fn f;
 
-	kuap_lock();
-
 	add_random_kstack_offset();
+	r0 = syscall_enter_from_user_mode(regs, r0);
 
-	if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
-		BUG_ON(irq_soft_mask_return() != IRQS_ALL_DISABLED);
-
-	trace_hardirqs_off(); /* finish reconciling */
-
-	CT_WARN_ON(ct_state() == CT_STATE_KERNEL);
-	user_exit_irqoff();
-
-	BUG_ON(regs_is_unrecoverable(regs));
-	BUG_ON(!user_mode(regs));
-	BUG_ON(regs_irqs_disabled(regs));
-
-#ifdef CONFIG_PPC_PKEY
-	if (mmu_has_feature(MMU_FTR_PKEY)) {
-		unsigned long amr, iamr;
-		bool flush_needed = false;
-		/*
-		 * When entering from userspace we mostly have the AMR/IAMR
-		 * different from kernel default values. Hence don't compare.
-		 */
-		amr = mfspr(SPRN_AMR);
-		iamr = mfspr(SPRN_IAMR);
-		regs->amr  = amr;
-		regs->iamr = iamr;
-		if (mmu_has_feature(MMU_FTR_KUAP)) {
-			mtspr(SPRN_AMR, AMR_KUAP_BLOCKED);
-			flush_needed = true;
-		}
-		if (mmu_has_feature(MMU_FTR_BOOK3S_KUEP)) {
-			mtspr(SPRN_IAMR, AMR_KUEP_BLOCKED);
-			flush_needed = true;
-		}
-		if (flush_needed)
-			isync();
-	} else
-#endif
-		kuap_assert_locked();
-
-	booke_restore_dbcr0();
-
-	account_cpu_user_entry();
-
-	account_stolen_time();
-
-	/*
-	 * This is not required for the syscall exit path, but makes the
-	 * stack frame look nicer. If this was initialised in the first stack
-	 * frame, or if the unwinder was taught the first stack frame always
-	 * returns to user with IRQS_ENABLED, this store could be avoided!
-	 */
-	irq_soft_mask_regs_set_state(regs, IRQS_ENABLED);
-
-	/*
-	 * If system call is called with TM active, set _TIF_RESTOREALL to
-	 * prevent RFSCV being used to return to userspace, because POWER9
-	 * TM implementation has problems with this instruction returning to
-	 * transactional state. Final register values are not relevant because
-	 * the transaction will be aborted upon return anyway. Or in the case
-	 * of unsupported_scv SIGILL fault, the return state does not much
-	 * matter because it's an edge case.
-	 */
-	if (IS_ENABLED(CONFIG_PPC_TRANSACTIONAL_MEM) &&
-			unlikely(MSR_TM_TRANSACTIONAL(regs->msr)))
-		set_bits(_TIF_RESTOREALL, &current_thread_info()->flags);
-
-	/*
-	 * If the system call was made with a transaction active, doom it and
-	 * return without performing the system call. Unless it was an
-	 * unsupported scv vector, in which case it's treated like an illegal
-	 * instruction.
-	 */
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-	if (unlikely(MSR_TM_TRANSACTIONAL(regs->msr)) &&
-	    !trap_is_unsupported_scv(regs)) {
-		/* Enable TM in the kernel, and disable EE (for scv) */
-		hard_irq_disable();
-		mtmsr(mfmsr() | MSR_TM);
-
-		/* tabort, this dooms the transaction, nothing else */
-		asm volatile(".long 0x7c00071d | ((%0) << 16)"
-				:: "r"(TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT));
-
-		/*
-		 * Userspace will never see the return value. Execution will
-		 * resume after the tbegin. of the aborted transaction with the
-		 * checkpointed register state. A context switch could occur
-		 * or signal delivered to the process before resuming the
-		 * doomed transaction context, but that should all be handled
-		 * as expected.
-		 */
-		return -ENOSYS;
-	}
-#endif // CONFIG_PPC_TRANSACTIONAL_MEM
-
-	local_irq_enable();
-
-	if (unlikely(read_thread_flags() & _TIF_SYSCALL_DOTRACE)) {
-		if (unlikely(trap_is_unsupported_scv(regs))) {
-			/* Unsupported scv vector */
-			_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
-			return regs->gpr[3];
-		}
-		/*
-		 * We use the return value of do_syscall_trace_enter() as the
-		 * syscall number. If the syscall was rejected for any reason
-		 * do_syscall_trace_enter() returns an invalid syscall number
-		 * and the test against NR_syscalls will fail and the return
-		 * value to be used is in regs->gpr[3].
-		 */
-		r0 = do_syscall_trace_enter(regs);
-		if (unlikely(r0 >= NR_syscalls))
-			return regs->gpr[3];
-
-	} else if (unlikely(r0 >= NR_syscalls)) {
+	if (unlikely(r0 >= NR_syscalls)) {
 		if (unlikely(trap_is_unsupported_scv(regs))) {
 			/* Unsupported scv vector */
 			_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
-- 
2.52.0
Re: [PATCH v2 8/8] powerpc: Enable Generic Entry/Exit for syscalls.
Posted by Christophe Leroy (CS GROUP) an hour ago

Le 14/12/2025 à 14:02, Mukesh Kumar Chaurasiya a écrit :
> From: Mukesh Kumar Chaurasiya <mchauras@linux.ibm.com>
> 
> Convert the PowerPC syscall entry and exit paths to use the generic
> entry/exit framework by selecting GENERIC_ENTRY and integrating with
> the common syscall handling routines.
> 
> This change transitions PowerPC away from its custom syscall entry and
> exit code to use the generic helpers such as:
>   - syscall_enter_from_user_mode()
>   - syscall_exit_to_user_mode()
> 
> As part of this migration:
>   - The architecture now selects GENERIC_ENTRY in Kconfig.
>   - Old tracing, seccomp, and audit handling in ptrace.c is removed in
>     favor of generic entry infrastructure.
>   - interrupt.c and syscall.c are simplified to delegate context
>     management and user exit handling to the generic entry path.
>   - The new pt_regs field `exit_flags` introduced earlier is now used
>     to carry per-syscall exit state flags (e.g. _TIF_RESTOREALL).
> 
> This aligns PowerPC with the common entry code used by other
> architectures and reduces duplicated logic around syscall tracing,
> context tracking, and signal handling.
> 
> The performance benchmarks from perf bench basic syscall are below:
> 
> perf bench syscall usec/op
> 
> | Test            | With Patch | Without Patch | % Change |
> | --------------- | ---------- | ------------- | -------- |
> | getppid usec/op | 0.207795   | 0.210373      | -1.22%   |
> | getpgid usec/op | 0.206282   | 0.211676      | -2.55%   |
> | fork usec/op    | 833.986    | 814.809       | +2.35%   |
> | execve usec/op  | 360.939    | 365.168       | -1.16%   |
> 
> perf bench syscall ops/sec
> 
> | Test            | With Patch | Without Patch | % Change |
> | --------------- | ---------- | ------------- | -------- |
> | getppid ops/sec | 48,12,433  | 47,53,459     | +1.24%   |
> | getpgid ops/sec | 48,47,744  | 47,24,192     | +2.61%   |
> | fork ops/sec    | 1,199      | 1,227         | -2.28%   |
> | execve ops/sec  | 2,770      | 2,738         | +1.16%   |

I get about 2% degradation on powerpc 8xx, and it is quite stable over 
time when repeating the test.

'perf bench syscall all' on powerpc 8xx (usec per op):

| Test            | With Patch | Without Patch | % Change |
| --------------- | ---------- | ------------- | -------- |
| getppid usec/op | 2.63       | 2.63          | ~ 0%     |
| getpgid usec/op | 2.26       | 2.22          | +2,80%   |
| fork usec/op    | 15300      | 15000         | +2,00%   |
| execve usec/op  | 45700      | 45200         | +1.10%   |

Christophe
Re: [PATCH v2 8/8] powerpc: Enable Generic Entry/Exit for syscalls.
Posted by kernel test robot 11 hours ago
Hi Mukesh,

kernel test robot noticed the following build errors:

[auto build test ERROR on powerpc/next]
[also build test ERROR on powerpc/fixes linus/master v6.19-rc1 next-20251215]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Mukesh-Kumar-Chaurasiya/powerpc-rename-arch_irq_disabled_regs/20251214-210813
base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
patch link:    https://lore.kernel.org/r/20251214130245.43664-9-mkchauras%40linux.ibm.com
patch subject: [PATCH v2 8/8] powerpc: Enable Generic Entry/Exit for syscalls.
config: powerpc-randconfig-001-20251215 (https://download.01.org/0day-ci/archive/20251216/202512160453.iO9WNjrm-lkp@intel.com/config)
compiler: powerpc-linux-gcc (GCC) 9.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251216/202512160453.iO9WNjrm-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512160453.iO9WNjrm-lkp@intel.com/

All errors (new ones prefixed by >>):

   powerpc-linux-ld: init/main.o: in function `do_trace_event_raw_event_initcall_level':
   include/trace/events/initcall.h:10: undefined reference to `memcpy'
   powerpc-linux-ld: init/main.o: in function `repair_env_string':
   init/main.c:512: undefined reference to `memmove'
   powerpc-linux-ld: init/do_mounts.o: in function `do_mount_root':
   init/do_mounts.c:162: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/kernel/process.o: in function `start_thread':
   arch/powerpc/kernel/process.c:1919: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/kernel/process.o: in function `__set_breakpoint':
   arch/powerpc/kernel/process.c:880: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/process.o: in function `arch_dup_task_struct':
   arch/powerpc/kernel/process.c:1724: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/process.o: in function `copy_thread':
   arch/powerpc/kernel/process.c:1801: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/kernel/process.c:1812: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/signal.o: in function `do_signal':
   arch/powerpc/kernel/signal.c:247: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/kernel/time.o: in function `register_decrementer_clockevent':
>> arch/powerpc/kernel/time.c:834: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/time.o: in function `platform_device_register_resndata':
>> include/linux/platform_device.h:158: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/kernel/prom.o: in function `move_device_tree':
>> arch/powerpc/kernel/prom.c:134: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/setup-common.o: in function `probe_machine':
>> arch/powerpc/kernel/setup-common.c:646: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/ptrace/ptrace-view.o: in function `user_regset_copyin':
>> include/linux/regset.h:276: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/ptrace/ptrace-view.o: in function `membuf_write':
   include/linux/regset.h:42: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/ptrace/ptrace-view.o: in function `gpr_get':
>> arch/powerpc/kernel/ptrace/ptrace-view.c:230: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/ptrace/ptrace-view.o: in function `membuf_zero':
>> include/linux/regset.h:30: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/kernel/ptrace/ptrace-view.o: in function `gpr32_get_common':
   arch/powerpc/kernel/ptrace/ptrace-view.c:707: undefined reference to `memcpy'
>> powerpc-linux-ld: arch/powerpc/kernel/ptrace/ptrace-view.c:708: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/ptrace/ptrace-view.c:710: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/ptrace/ptrace-view.o: in function `membuf_zero':
>> include/linux/regset.h:30: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/kernel/ptrace/ptrace-novsx.o: in function `membuf_write':
   include/linux/regset.h:42: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/optprobes.o: in function `can_optimize':
>> arch/powerpc/kernel/optprobes.c:71: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/kernel/kvm.o: in function `kvm_map_magic_page':
>> arch/powerpc/kernel/kvm.c:407: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/kernel/kvm.o: in function `kvm_patch_ins_mtmsrd':
>> arch/powerpc/kernel/kvm.c:178: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/kvm.o: in function `kvm_patch_ins_mtmsr':
   arch/powerpc/kernel/kvm.c:231: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/kernel/kvm.o: in function `epapr_hypercall0_1':
>> arch/powerpc/include/asm/epapr_hcalls.h:511: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/mm/mem.o: in function `execmem_arch_setup':
>> arch/powerpc/mm/mem.c:423: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/mm/init-common.o: in function `ctor_15':
>> arch/powerpc/mm/init-common.c:81: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/mm/init-common.o: in function `ctor_14':
>> arch/powerpc/mm/init-common.c:81: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/mm/init-common.o: in function `ctor_13':
>> arch/powerpc/mm/init-common.c:81: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/mm/init-common.o:arch/powerpc/mm/init-common.c:81: more undefined references to `memset' follow
   powerpc-linux-ld: arch/powerpc/lib/pmem.o: in function `memcpy_flushcache':
>> arch/powerpc/lib/pmem.c:84: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/sysdev/fsl_mpic_err.o: in function `mpic_setup_error_int':
>> arch/powerpc/sysdev/fsl_mpic_err.c:70: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/platforms/8xx/pic.o: in function `irq_domain_create_linear':
>> include/linux/irqdomain.h:405: undefined reference to `memset'
   powerpc-linux-ld: arch/powerpc/platforms/8xx/cpm1.o: in function `cpm1_clk_setup':
   arch/powerpc/platforms/8xx/cpm1.c:251: undefined reference to `memcpy'
   powerpc-linux-ld: arch/powerpc/platforms/8xx/cpm1-ic.o: in function `irq_domain_create_linear':
   include/linux/irqdomain.h:405: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `do_trace_event_raw_event_task_newtask':
   include/trace/events/task.h:9: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/fork.o: in function `do_trace_event_raw_event_task_rename':
   include/trace/events/task.h:34: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/fork.o: in function `copy_struct_from_user':
   include/linux/uaccess.h:396: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `copy_clone_args_from_user':
   kernel/fork.c:2800: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `mm_init':
   kernel/fork.c:1044: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `bitmap_zero':
   include/linux/bitmap.h:238: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `pgd_alloc':
   arch/powerpc/include/asm/nohash/pgalloc.h:26: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/fork.o: in function `__kmem_cache_create':
   include/linux/slab.h:379: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `arch_dup_task_struct':
   kernel/fork.c:854: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/fork.o: in function `mm_alloc':
   kernel/fork.c:1120: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `replace_mm_exe_file':
   kernel/fork.c:1238: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `copy_process':
   kernel/fork.c:2030: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `posix_cputimers_init':
   include/linux/posix-timers.h:103: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `copy_sighand':
   kernel/fork.c:1618: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/fork.o: in function `copy_signal':
   kernel/fork.c:1687: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/fork.o: in function `dup_mm':
   kernel/fork.c:1483: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/fork.o: in function `create_io_thread':
   kernel/fork.c:2549: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `kernel_thread':
   kernel/fork.c:2661: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `user_mode_thread':
   kernel/fork.c:2678: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `sys_fork':
   kernel/fork.c:2692: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o: in function `sys_vfork':
   kernel/fork.c:2707: undefined reference to `memset'
   powerpc-linux-ld: kernel/fork.o:kernel/fork.c:2740: more undefined references to `memset' follow
   powerpc-linux-ld: kernel/softirq.o: in function `do_trace_event_raw_event_irq_handler_entry':
   include/trace/events/irq.h:53: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/resource.o: in function `find_next_iomem_res':
   kernel/resource.c:372: undefined reference to `memset'
   powerpc-linux-ld: kernel/resource.o: in function `__request_region_locked':
   kernel/resource.c:1261: undefined reference to `memset'
   powerpc-linux-ld: kernel/resource.o: in function `reserve_setup':
   kernel/resource.c:1757: undefined reference to `memset'
   powerpc-linux-ld: kernel/resource.c:1760: undefined reference to `memset'
   powerpc-linux-ld: kernel/sysctl.o: in function `proc_put_long':
   kernel/sysctl.c:339: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/sysctl.o: in function `_proc_do_string':
   kernel/sysctl.c:127: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/sysctl.o: in function `proc_get_long':
   kernel/sysctl.c:284: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/sysctl.o: in function `bitmap_copy':
   include/linux/bitmap.h:259: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/sysctl.o: in function `proc_do_static_key':
   kernel/sysctl.c:1433: undefined reference to `memset'
   powerpc-linux-ld: kernel/capability.o: in function `__do_sys_capset':
   kernel/capability.c:218: undefined reference to `memset'
   powerpc-linux-ld: kernel/ptrace.o: in function `syscall_set_arguments':
   arch/powerpc/include/asm/syscall.h:127: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/ptrace.o: in function `ptrace_get_syscall_info':
   kernel/ptrace.c:998: undefined reference to `memset'
   powerpc-linux-ld: kernel/ptrace.o: in function `copy_siginfo':
   include/linux/signal.h:18: undefined reference to `memcpy'
   powerpc-linux-ld: include/linux/signal.h:18: undefined reference to `memcpy'
   powerpc-linux-ld: include/linux/signal.h:18: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/user.o: in function `ratelimit_state_init':
   include/linux/ratelimit.h:12: undefined reference to `memset'
   powerpc-linux-ld: kernel/user.o: in function `__kmem_cache_create':
   include/linux/slab.h:379: undefined reference to `memset'
   powerpc-linux-ld: kernel/signal.o: in function `do_trace_event_raw_event_signal_generate':
   include/trace/events/signal.h:50: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/signal.o: in function `clear_siginfo':
   include/linux/signal.h:23: undefined reference to `memset'
   powerpc-linux-ld: kernel/signal.o: in function `copy_siginfo':
   include/linux/signal.h:18: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/signal.o: in function `do_sigaltstack':
   kernel/signal.c:4396: undefined reference to `memset'
   powerpc-linux-ld: kernel/signal.o: in function `copy_siginfo':
   include/linux/signal.h:18: undefined reference to `memcpy'
   powerpc-linux-ld: include/linux/signal.h:18: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/signal.o: in function `signals_init':
   kernel/signal.c:5011: undefined reference to `memset'
   powerpc-linux-ld: kernel/sys.o: in function `override_release':
   kernel/sys.c:1331: undefined reference to `memset'
   powerpc-linux-ld: kernel/sys.o: in function `__do_sys_newuname':
   kernel/sys.c:1356: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/sys.o: in function `__do_sys_uname':
   kernel/sys.c:1380: undefined reference to `memcpy'
   powerpc-linux-ld: kernel/sys.o: in function `prctl_set_auxv':


vim +18 include/linux/signal.h

^1da177e4c3f415 Linus Torvalds    2005-04-16  14  
ae7795bc6187a15 Eric W. Biederman 2018-09-25  15  static inline void copy_siginfo(kernel_siginfo_t *to,
ae7795bc6187a15 Eric W. Biederman 2018-09-25  16  				const kernel_siginfo_t *from)
ca9eb49aa9562ea James Hogan       2016-02-08  17  {
ca9eb49aa9562ea James Hogan       2016-02-08 @18  	memcpy(to, from, sizeof(*to));
ca9eb49aa9562ea James Hogan       2016-02-08  19  }
ca9eb49aa9562ea James Hogan       2016-02-08  20  
ae7795bc6187a15 Eric W. Biederman 2018-09-25  21  static inline void clear_siginfo(kernel_siginfo_t *info)
8c5dbf2ae00bb86 Eric W. Biederman 2017-07-24  22  {
8c5dbf2ae00bb86 Eric W. Biederman 2017-07-24 @23  	memset(info, 0, sizeof(*info));
8c5dbf2ae00bb86 Eric W. Biederman 2017-07-24  24  }
8c5dbf2ae00bb86 Eric W. Biederman 2017-07-24  25  
4ce5f9c9e754691 Eric W. Biederman 2018-09-25  26  #define SI_EXPANSION_SIZE (sizeof(struct siginfo) - sizeof(struct kernel_siginfo))
4ce5f9c9e754691 Eric W. Biederman 2018-09-25  27  
fa4751f454e6b51 Eric W. Biederman 2020-05-05  28  static inline void copy_siginfo_to_external(siginfo_t *to,
fa4751f454e6b51 Eric W. Biederman 2020-05-05  29  					    const kernel_siginfo_t *from)
fa4751f454e6b51 Eric W. Biederman 2020-05-05  30  {
fa4751f454e6b51 Eric W. Biederman 2020-05-05 @31  	memcpy(to, from, sizeof(*from));
fa4751f454e6b51 Eric W. Biederman 2020-05-05 @32  	memset(((char *)to) + sizeof(struct kernel_siginfo), 0,
fa4751f454e6b51 Eric W. Biederman 2020-05-05  33  		SI_EXPANSION_SIZE);
fa4751f454e6b51 Eric W. Biederman 2020-05-05  34  }
fa4751f454e6b51 Eric W. Biederman 2020-05-05  35  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH v2 8/8] powerpc: Enable Generic Entry/Exit for syscalls.
Posted by Segher Boessenkool 1 day, 15 hours ago
Hi!

On Sun, Dec 14, 2025 at 06:32:44PM +0530, Mukesh Kumar Chaurasiya wrote:
> 
> | Test            | With Patch | Without Patch | % Change |
> | --------------- | ---------- | ------------- | -------- |
> | fork usec/op    | 833.986    | 814.809       | +2.35%   |

What causes this regression, did you investigate?  Maybe there is
something simple you can do to avoid this degradation :-)  All other
numbers look just fine :-)

> | Test            | With Patch | Without Patch | % Change |
> | --------------- | ---------- | ------------- | -------- |
> | fork ops/sec    | 1,199      | 1,227         | -2.28%   |

(Same thing seen from another side)


Segher
Re: [PATCH v2 8/8] powerpc: Enable Generic Entry/Exit for syscalls.
Posted by Mukesh Kumar Chaurasiya 13 hours ago
On Sun, Dec 14, 2025 at 10:20:12AM -0600, Segher Boessenkool wrote:
> Hi!
> 
> On Sun, Dec 14, 2025 at 06:32:44PM +0530, Mukesh Kumar Chaurasiya wrote:
> > 
> > | Test            | With Patch | Without Patch | % Change |
> > | --------------- | ---------- | ------------- | -------- |
> > | fork usec/op    | 833.986    | 814.809       | +2.35%   |
> 
> What causes this regression, did you investigate?  Maybe there is
> something simple you can do to avoid this degradation :-)  All other
> numbers look just fine :-)
> 
Hey,

I ran this multiple times and took the average this time, below are the
results:
===========================================
Without patch
===========================================
╰─❯ perf bench syscall fork 
# Running 'syscall/fork' benchmark:
# Executed 10,000 fork() calls
     Total time: 8.514 [sec]

     851.415300 usecs/op
          1,174 ops/sec

╰─❯ perf bench syscall fork
# Running 'syscall/fork' benchmark:
# Executed 10,000 fork() calls
     Total time: 8.572 [sec]

     857.293600 usecs/op
          1,166 ops/sec

╰─❯ perf bench syscall fork 
# Running 'syscall/fork' benchmark:
# Executed 10,000 fork() calls
     Total time: 8.695 [sec]

     869.536500 usecs/op
          1,150 ops/sec
===========================================
With patch
===========================================
╰─❯ perf bench syscall fork 
# Running 'syscall/fork' benchmark:
# Executed 10,000 fork() calls
     Total time: 8.482 [sec]

     848.241300 usecs/op
          1,178 ops/sec

╰─❯ perf bench syscall fork 
# Running 'syscall/fork' benchmark:
# Executed 10,000 fork() calls
     Total time: 8.623 [sec]

     862.389000 usecs/op
          1,159 ops/sec

╰─❯ perf bench syscall fork 
# Running 'syscall/fork' benchmark:
# Executed 10,000 fork() calls
     Total time: 8.530 [sec]

     853.037200 usecs/op
          1,172 ops/sec
===========================================
Average:
===========================================
With Patch:
854.4964 usecs/op
1169 ops/sec

Without patch:
859.4151 usecs/op
1163 ops/sec

That's ~0.5% improvement when i take average through the runs.
This we can ignore as a standard deviation and consider that there are
no regression for these.

Regards,
Mukesh

> > | Test            | With Patch | Without Patch | % Change |
> > | --------------- | ---------- | ------------- | -------- |
> > | fork ops/sec    | 1,199      | 1,227         | -2.28%   |
> 
> (Same thing seen from another side)
> 
> 
> Segher