In the generic entry code, the beginning of
syscall_exit_to_user_mode_work() can be reused on arm64 so it makes
sense to rework it.
In preparation for moving arm64 over to the generic entry
code, as nothing calls syscall_exit_to_user_mode_work() except for
syscall_exit_to_user_mode(), move local_irq_disable_exit_to_user() and
syscall_exit_to_user_mode_prepare() out from
syscall_exit_to_user_mode_work() to the only one caller.
Also update the comment and no functional changes.
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
include/linux/entry-common.h | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
index e4a8287af822..c4fea642d931 100644
--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -125,14 +125,14 @@ void syscall_exit_work(struct pt_regs *regs, unsigned long work);
* syscall_exit_to_user_mode_work - Handle work before returning to user mode
* @regs: Pointer to currents pt_regs
*
- * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
+ * Same as step 1 of syscall_exit_to_user_mode() but without calling
+ * local_irq_disable(), syscall_exit_to_user_mode_prepare() and
* exit_to_user_mode() to perform the final transition to user mode.
*
- * Calling convention is the same as for syscall_exit_to_user_mode() and it
- * returns with all work handled and interrupts disabled. The caller must
- * invoke exit_to_user_mode() before actually switching to user mode to
- * make the final state transitions. Interrupts must stay disabled between
- * return from this function and the invocation of exit_to_user_mode().
+ * Calling convention is the same as for syscall_exit_to_user_mode(). The
+ * caller must invoke local_irq_disable(), __exit_to_user_mode_prepare() and
+ * exit_to_user_mode() before actually switching to user mode to
+ * make the final state transitions.
*/
static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
{
@@ -155,8 +155,6 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
*/
if (unlikely(work & SYSCALL_WORK_EXIT))
syscall_exit_work(regs, work);
- local_irq_disable_exit_to_user();
- syscall_exit_to_user_mode_prepare(regs);
}
/**
@@ -192,6 +190,8 @@ static __always_inline void syscall_exit_to_user_mode(struct pt_regs *regs)
{
instrumentation_begin();
syscall_exit_to_user_mode_work(regs);
+ local_irq_disable_exit_to_user();
+ syscall_exit_to_user_mode_prepare(regs);
instrumentation_end();
exit_to_user_mode();
}
--
2.34.1
On 28/01/2026 04:19, Jinjie Ruan wrote:
> In the generic entry code, the beginning of
> syscall_exit_to_user_mode_work() can be reused on arm64 so it makes
> sense to rework it.
>
> In preparation for moving arm64 over to the generic entry
> code, as nothing calls syscall_exit_to_user_mode_work() except for
> syscall_exit_to_user_mode(), move local_irq_disable_exit_to_user() and
> syscall_exit_to_user_mode_prepare() out from
> syscall_exit_to_user_mode_work() to the only one caller.
>
> Also update the comment and no functional changes.
>
> Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
> Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
> ---
> include/linux/entry-common.h | 16 ++++++++--------
> 1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
> index e4a8287af822..c4fea642d931 100644
> --- a/include/linux/entry-common.h
> +++ b/include/linux/entry-common.h
> @@ -125,14 +125,14 @@ void syscall_exit_work(struct pt_regs *regs, unsigned long work);
> * syscall_exit_to_user_mode_work - Handle work before returning to user mode
> * @regs: Pointer to currents pt_regs
> *
> - * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
> + * Same as step 1 of syscall_exit_to_user_mode() but without calling
> + * local_irq_disable(), syscall_exit_to_user_mode_prepare() and
> * exit_to_user_mode() to perform the final transition to user mode.
> *
> - * Calling convention is the same as for syscall_exit_to_user_mode() and it
> - * returns with all work handled and interrupts disabled. The caller must
> - * invoke exit_to_user_mode() before actually switching to user mode to
> - * make the final state transitions. Interrupts must stay disabled between
> - * return from this function and the invocation of exit_to_user_mode().
> + * Calling convention is the same as for syscall_exit_to_user_mode(). The
> + * caller must invoke local_irq_disable(), __exit_to_user_mode_prepare() and
Shouldn't it be syscall_exit_to_user_mode_prepare() rather than
__exit_to_user_mode_prepare()? The former has extra calls (e.g. rseq).
- Kevin
> + * exit_to_user_mode() before actually switching to user mode to
> + * make the final state transitions.
> */
> static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
> {
> @@ -155,8 +155,6 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
> */
> if (unlikely(work & SYSCALL_WORK_EXIT))
> syscall_exit_work(regs, work);
> - local_irq_disable_exit_to_user();
> - syscall_exit_to_user_mode_prepare(regs);
> }
>
> /**
> @@ -192,6 +190,8 @@ static __always_inline void syscall_exit_to_user_mode(struct pt_regs *regs)
> {
> instrumentation_begin();
> syscall_exit_to_user_mode_work(regs);
> + local_irq_disable_exit_to_user();
> + syscall_exit_to_user_mode_prepare(regs);
> instrumentation_end();
> exit_to_user_mode();
> }
On 2026/1/29 20:06, Kevin Brodsky wrote:
> On 28/01/2026 04:19, Jinjie Ruan wrote:
>> In the generic entry code, the beginning of
>> syscall_exit_to_user_mode_work() can be reused on arm64 so it makes
>> sense to rework it.
>>
>> In preparation for moving arm64 over to the generic entry
>> code, as nothing calls syscall_exit_to_user_mode_work() except for
>> syscall_exit_to_user_mode(), move local_irq_disable_exit_to_user() and
>> syscall_exit_to_user_mode_prepare() out from
>> syscall_exit_to_user_mode_work() to the only one caller.
>>
>> Also update the comment and no functional changes.
>>
>> Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
>> Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
>> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
>> ---
>> include/linux/entry-common.h | 16 ++++++++--------
>> 1 file changed, 8 insertions(+), 8 deletions(-)
>>
>> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
>> index e4a8287af822..c4fea642d931 100644
>> --- a/include/linux/entry-common.h
>> +++ b/include/linux/entry-common.h
>> @@ -125,14 +125,14 @@ void syscall_exit_work(struct pt_regs *regs, unsigned long work);
>> * syscall_exit_to_user_mode_work - Handle work before returning to user mode
>> * @regs: Pointer to currents pt_regs
>> *
>> - * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
>> + * Same as step 1 of syscall_exit_to_user_mode() but without calling
>> + * local_irq_disable(), syscall_exit_to_user_mode_prepare() and
>> * exit_to_user_mode() to perform the final transition to user mode.
>> *
>> - * Calling convention is the same as for syscall_exit_to_user_mode() and it
>> - * returns with all work handled and interrupts disabled. The caller must
>> - * invoke exit_to_user_mode() before actually switching to user mode to
>> - * make the final state transitions. Interrupts must stay disabled between
>> - * return from this function and the invocation of exit_to_user_mode().
>> + * Calling convention is the same as for syscall_exit_to_user_mode(). The
>> + * caller must invoke local_irq_disable(), __exit_to_user_mode_prepare() and
>
> Shouldn't it be syscall_exit_to_user_mode_prepare() rather than
> __exit_to_user_mode_prepare()? The former has extra calls (e.g. rseq).
Perhaps we can just delete these comments — at present only generic
entry and arm64 use it, and nowhere else needs it; after the refactoring
the comments now seem rather unclear.
>
> - Kevin
>
>> + * exit_to_user_mode() before actually switching to user mode to
>> + * make the final state transitions.
>> */
>> static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
>> {
>> @@ -155,8 +155,6 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
>> */
>> if (unlikely(work & SYSCALL_WORK_EXIT))
>> syscall_exit_work(regs, work);
>> - local_irq_disable_exit_to_user();
>> - syscall_exit_to_user_mode_prepare(regs);
>> }
>>
>> /**
>> @@ -192,6 +190,8 @@ static __always_inline void syscall_exit_to_user_mode(struct pt_regs *regs)
>> {
>> instrumentation_begin();
>> syscall_exit_to_user_mode_work(regs);
>> + local_irq_disable_exit_to_user();
>> + syscall_exit_to_user_mode_prepare(regs);
>> instrumentation_end();
>> exit_to_user_mode();
>> }
>
On 29/01/2026 14:11, Jinjie Ruan wrote: >>> diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h >>> index e4a8287af822..c4fea642d931 100644 >>> --- a/include/linux/entry-common.h >>> +++ b/include/linux/entry-common.h >>> @@ -125,14 +125,14 @@ void syscall_exit_work(struct pt_regs *regs, unsigned long work); >>> * syscall_exit_to_user_mode_work - Handle work before returning to user mode >>> * @regs: Pointer to currents pt_regs >>> * >>> - * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling >>> + * Same as step 1 of syscall_exit_to_user_mode() but without calling >>> + * local_irq_disable(), syscall_exit_to_user_mode_prepare() and >>> * exit_to_user_mode() to perform the final transition to user mode. >>> * >>> - * Calling convention is the same as for syscall_exit_to_user_mode() and it >>> - * returns with all work handled and interrupts disabled. The caller must >>> - * invoke exit_to_user_mode() before actually switching to user mode to >>> - * make the final state transitions. Interrupts must stay disabled between >>> - * return from this function and the invocation of exit_to_user_mode(). >>> + * Calling convention is the same as for syscall_exit_to_user_mode(). The >>> + * caller must invoke local_irq_disable(), __exit_to_user_mode_prepare() and >> Shouldn't it be syscall_exit_to_user_mode_prepare() rather than >> __exit_to_user_mode_prepare()? The former has extra calls (e.g. rseq). > Perhaps we can just delete these comments — at present only generic > entry and arm64 use it, and nowhere else needs it; after the refactoring > the comments now seem rather unclear. Agreed, the comments are essentially describing what each function calls; considering how short they are, directly reading the code is probably easier. - Kevin
On Thu, Jan 29 2026 at 17:00, Kevin Brodsky wrote: > On 29/01/2026 14:11, Jinjie Ruan wrote: >>>> - * Calling convention is the same as for syscall_exit_to_user_mode() and it >>>> - * returns with all work handled and interrupts disabled. The caller must >>>> - * invoke exit_to_user_mode() before actually switching to user mode to >>>> - * make the final state transitions. Interrupts must stay disabled between >>>> - * return from this function and the invocation of exit_to_user_mode(). >>>> + * Calling convention is the same as for syscall_exit_to_user_mode(). The >>>> + * caller must invoke local_irq_disable(), __exit_to_user_mode_prepare() and >>> Shouldn't it be syscall_exit_to_user_mode_prepare() rather than >>> __exit_to_user_mode_prepare()? The former has extra calls (e.g. rseq). >> Perhaps we can just delete these comments — at present only generic >> entry and arm64 use it, and nowhere else needs it; after the refactoring >> the comments now seem rather unclear. > > Agreed, the comments are essentially describing what each function > calls; considering how short they are, directly reading the code is > probably easier. No. Please keep them. There is more information in them than just the pure 'what's' called.
On 30/01/2026 11:16, Thomas Gleixner wrote: > On Thu, Jan 29 2026 at 17:00, Kevin Brodsky wrote: >> On 29/01/2026 14:11, Jinjie Ruan wrote: >>>>> - * Calling convention is the same as for syscall_exit_to_user_mode() and it >>>>> - * returns with all work handled and interrupts disabled. The caller must >>>>> - * invoke exit_to_user_mode() before actually switching to user mode to >>>>> - * make the final state transitions. Interrupts must stay disabled between >>>>> - * return from this function and the invocation of exit_to_user_mode(). >>>>> + * Calling convention is the same as for syscall_exit_to_user_mode(). The >>>>> + * caller must invoke local_irq_disable(), __exit_to_user_mode_prepare() and >>>> Shouldn't it be syscall_exit_to_user_mode_prepare() rather than >>>> __exit_to_user_mode_prepare()? The former has extra calls (e.g. rseq). >>> Perhaps we can just delete these comments — at present only generic >>> entry and arm64 use it, and nowhere else needs it; after the refactoring >>> the comments now seem rather unclear. >> Agreed, the comments are essentially describing what each function >> calls; considering how short they are, directly reading the code is >> probably easier. > No. Please keep them. There is more information in them than just the > pure 'what's' called. That is true before this patch, where it made sense to highlight that exit_to_user_mode() must still be called after this function (without re-enabling interrupts). With this patch there is however much more that this function is lacking, and it feels very likely that comments will go out of sync with exactly what syscall_exit_to_user_mode() calls. I suppose we could simply point the reader to syscall_exit_to_user_mode() to find out what else is needed, and keep the comment about the calling convention being the same. - Kevin
On Fri, Jan 30 2026 at 14:27, Kevin Brodsky wrote:
> On 30/01/2026 11:16, Thomas Gleixner wrote:
>>> Agreed, the comments are essentially describing what each function
>>> calls; considering how short they are, directly reading the code is
>>> probably easier.
>> No. Please keep them. There is more information in them than just the
>> pure 'what's' called.
>
> That is true before this patch, where it made sense to highlight that
> exit_to_user_mode() must still be called after this function (without
> re-enabling interrupts). With this patch there is however much more that
> this function is lacking, and it feels very likely that comments will go
> out of sync with exactly what syscall_exit_to_user_mode() calls.
>
> I suppose we could simply point the reader to
> syscall_exit_to_user_mode() to find out what else is needed, and keep
> the comment about the calling convention being the same.
I've picked up _all_ four entry changes and reworked the comments and
changelogs already.
Those patches should have been bundled together at the start of the
series anyway so they can be picked up independently without going
through loops and hoops. When will people learn to think beyond the brim
of their architecture tea cup?
I'll go and apply them on top of 6.19-rc1 into core/entry and merge that
into the scheduler branch to resolve the resulting conflict.
ARM64 can either pull that branch or wait until the next rc1 comes out.
Thanks,
tglx
On 2026/1/30 23:01, Thomas Gleixner wrote: > On Fri, Jan 30 2026 at 14:27, Kevin Brodsky wrote: >> On 30/01/2026 11:16, Thomas Gleixner wrote: >>>> Agreed, the comments are essentially describing what each function >>>> calls; considering how short they are, directly reading the code is >>>> probably easier. >>> No. Please keep them. There is more information in them than just the >>> pure 'what's' called. >> >> That is true before this patch, where it made sense to highlight that >> exit_to_user_mode() must still be called after this function (without >> re-enabling interrupts). With this patch there is however much more that >> this function is lacking, and it feels very likely that comments will go >> out of sync with exactly what syscall_exit_to_user_mode() calls. >> >> I suppose we could simply point the reader to >> syscall_exit_to_user_mode() to find out what else is needed, and keep >> the comment about the calling convention being the same. > > I've picked up _all_ four entry changes and reworked the comments and > changelogs already. > > Those patches should have been bundled together at the start of the > series anyway so they can be picked up independently without going > through loops and hoops. When will people learn to think beyond the brim > of their architecture tea cup? I'll make sure to group related changes together from the start next time and keep the whole series in view, not just the architecture-specific parts. Thanks for taking the time to re-work them — much appreciated. > > I'll go and apply them on top of 6.19-rc1 into core/entry and merge that > into the scheduler branch to resolve the resulting conflict. > > ARM64 can either pull that branch or wait until the next rc1 comes out. Thanks for re-bundling the four entry patches and reworking the logs — that definitely makes the series easier to pick up. I'll rebase my remaining changes on top of 6.19-rc1 once the core/entry branch lands. Let me know if there’s anything I can do to simplify the logistics. Regards, Jinjie > > Thanks, > > tglx > >
On Fri, Jan 30 2026 at 16:01, Thomas Gleixner wrote:
> I'll go and apply them on top of 6.19-rc1 into core/entry and merge that
> into the scheduler branch to resolve the resulting conflict.
>
> ARM64 can either pull that branch or wait until the next rc1 comes out.
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git entry-for-arm64-26-01-31
Consider that tag immutable and consumable for ARM64 if you need it. I
did some massaging, but the ARM64 pile should still apply on top of it.
Thanks,
tglx
The following commit has been merged into the core/entry branch of tip:
Commit-ID: e1647100c22eb718e9833211722cbb78e339047c
Gitweb: https://git.kernel.org/tip/e1647100c22eb718e9833211722cbb78e339047c
Author: Jinjie Ruan <ruanjinjie@huawei.com>
AuthorDate: Wed, 28 Jan 2026 11:19:29 +08:00
Committer: Thomas Gleixner <tglx@kernel.org>
CommitterDate: Fri, 30 Jan 2026 15:38:09 +01:00
entry: Rework syscall_exit_to_user_mode_work() for architecture reuse
syscall_exit_to_user_mode_work() invokes local_irq_disable_exit_to_user()
and syscall_exit_to_user_mode_prepare() after handling pending syscall exit
work.
The conversion of ARM64 to the generic entry code requires this to be split
up, so move the invocations of local_irq_disable_exit_to_user() and
syscall_exit_to_user_mode_prepare() into the only caller.
No functional change intended.
[ tglx: Massaged changelog and comments ]
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://patch.msgid.link/20260128031934.3906955-10-ruanjinjie@huawei.com
---
include/linux/entry-common.h | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
index e4a8287..5316004 100644
--- a/include/linux/entry-common.h
+++ b/include/linux/entry-common.h
@@ -122,17 +122,12 @@ static __always_inline long syscall_enter_from_user_mode(struct pt_regs *regs, l
void syscall_exit_work(struct pt_regs *regs, unsigned long work);
/**
- * syscall_exit_to_user_mode_work - Handle work before returning to user mode
+ * syscall_exit_to_user_mode_work - Handle one time work before returning to user mode
* @regs: Pointer to currents pt_regs
*
- * Same as step 1 and 2 of syscall_exit_to_user_mode() but without calling
- * exit_to_user_mode() to perform the final transition to user mode.
+ * Step 1 of syscall_exit_to_user_mode() with the same calling convention.
*
- * Calling convention is the same as for syscall_exit_to_user_mode() and it
- * returns with all work handled and interrupts disabled. The caller must
- * invoke exit_to_user_mode() before actually switching to user mode to
- * make the final state transitions. Interrupts must stay disabled between
- * return from this function and the invocation of exit_to_user_mode().
+ * The caller must invoke steps 2-3 of syscall_exit_to_user_mode() afterwards.
*/
static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
{
@@ -155,15 +150,13 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
*/
if (unlikely(work & SYSCALL_WORK_EXIT))
syscall_exit_work(regs, work);
- local_irq_disable_exit_to_user();
- syscall_exit_to_user_mode_prepare(regs);
}
/**
* syscall_exit_to_user_mode - Handle work before returning to user mode
* @regs: Pointer to currents pt_regs
*
- * Invoked with interrupts enabled and fully valid regs. Returns with all
+ * Invoked with interrupts enabled and fully valid @regs. Returns with all
* work handled, interrupts disabled such that the caller can immediately
* switch to user mode. Called from architecture specific syscall and ret
* from fork code.
@@ -176,6 +169,7 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
* - ptrace (single stepping)
*
* 2) Preparatory work
+ * - Disable interrupts
* - Exit to user mode loop (common TIF handling). Invokes
* arch_exit_to_user_mode_work() for architecture specific TIF work
* - Architecture specific one time work arch_exit_to_user_mode_prepare()
@@ -184,14 +178,17 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs)
* 3) Final transition (lockdep, tracing, context tracking, RCU), i.e. the
* functionality in exit_to_user_mode().
*
- * This is a combination of syscall_exit_to_user_mode_work() (1,2) and
- * exit_to_user_mode(). This function is preferred unless there is a
- * compelling architectural reason to use the separate functions.
+ * This is a combination of syscall_exit_to_user_mode_work() (1), disabling
+ * interrupts followed by syscall_exit_to_user_mode_prepare() (2) and
+ * exit_to_user_mode() (3). This function is preferred unless there is a
+ * compelling architectural reason to invoke the functions separately.
*/
static __always_inline void syscall_exit_to_user_mode(struct pt_regs *regs)
{
instrumentation_begin();
syscall_exit_to_user_mode_work(regs);
+ local_irq_disable_exit_to_user();
+ syscall_exit_to_user_mode_prepare(regs);
instrumentation_end();
exit_to_user_mode();
}
© 2016 - 2026 Red Hat, Inc.