Skip to content

Commit 6c3118c

Browse files
ChangSeokBaehansendc
authored andcommitted
signal: Skip the altstack update when not needed
== Background == Support for large, "dynamic" fpstates was recently merged. This included code to ensure that sigaltstacks are sufficiently sized for these large states. A new lock was added to remove races between enabling large features and setting up sigaltstacks. == Problem == The new lock (sigaltstack_lock()) is acquired in the sigreturn path before restoring the old sigaltstack. Unfortunately, contention on the new lock causes a measurable signal handling performance regression [1]. However, the common case is that no *changes* are made to the sigaltstack state at sigreturn. == Solution == do_sigaltstack() acquires sigaltstack_lock() and is used for both sys_sigaltstack() and restoring the sigaltstack in sys_sigreturn(). Check for changes to the sigaltstack before taking the lock. If no changes were made, return before acquiring the lock. This removes lock contention from the common-case sigreturn path. [1] https://lore.kernel.org/lkml/20211207012128.GA16074@xsang-OptiPlex-9020/ Fixes: 3aac3eb ("x86/signal: Implement sigaltstack size validation") Reported-by: kernel test robot <[email protected]> Signed-off-by: Chang S. Bae <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent cabdc3a commit 6c3118c

File tree

1 file changed

+9
-0
lines changed

1 file changed

+9
-0
lines changed

kernel/signal.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4185,6 +4185,15 @@ do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp,
41854185
ss_mode != 0))
41864186
return -EINVAL;
41874187

4188+
/*
4189+
* Return before taking any locks if no actual
4190+
* sigaltstack changes were requested.
4191+
*/
4192+
if (t->sas_ss_sp == (unsigned long)ss_sp &&
4193+
t->sas_ss_size == ss_size &&
4194+
t->sas_ss_flags == ss_flags)
4195+
return 0;
4196+
41884197
sigaltstack_lock();
41894198
if (ss_mode == SS_DISABLE) {
41904199
ss_size = 0;

0 commit comments

Comments
 (0)