Re: [patch V4 28/36] rseq: Switch to fast path processing on exit to user

Thomas Gleixner
2025-09-11T16:47:34Z

On Thu, Sep 11 2025 at 10:44, Mathieu Desnoyers wrote:
> On 2025-09-08 17:32, Thomas Gleixner wrote:
>> void __rseq_signal_deliver(int sig, struct pt_regs *regs);
>> @@ -142,11 +148,16 @@ static inline void rseq_fork(struct task
>> } else {
>> t->rseq = current->rseq;
>> t->rseq.ids.cpu_cid = ~0ULL;
>
> As discussed earlier, do we really want to clear cpu_cid here, or
> copy from parent ? If we keep the parent's cached values, I suspect

Suspicion is not really a good engineering principle.

> we can skip the page fault on return from fork in many cases.

I doubt that it's many cases, see below.

>> + /*
>> + * If it has rseq, force it into the slow path right away
>> + * because it is guaranteed to fault.
>> + */
>> + t->rseq.event.slowpath = t->rseq.event.has_rseq;
>
> I think we can do better here. It's only guaranteed to fault if:
>
> - has_rseq is set, AND
> - cpu or cid has changed compared to the cached value OR
> - rseq_cs user pointer is non-NULL.
>
> Otherwise we should be able to handle the return from fork from the fast
> path just with loads from the rseq area, or am I missing something ?

The normal case is that the fault is pretty much guaranteed to happen
because the scheduler places the child on a different CPU and therefore
the CPU/MM IDs need to be updated anyway.

The only cases where this is not true, are when there is no capacity to
do so or on UP or the parent was affine to a single CPU, which is what
the child inherits.

Now for those cases the only time, where such an optimization would be
meaningful is when the child is so short lived, that it does not
schedule. Otherwise you just procrastinate the fault to a later point
in time.

The point is that it will fault in the vast majority of cases and then
the fault will happen in the fast path first, which means the exit code
has to go another round through the work loop instead of forcing the
fault right away on the first exit in the slowpath, where it can be
actually resolved.

> Thanks,
>
> Mathieu

Your method of ending a mail with a greeting and then continuing to
reply downwards is pretty annoying. I almost missed the below if I
wouldn't have tried to trim the reply.

>> }
>> }
>>
>> #else /* CONFIG_RSEQ */
>> -static inline void rseq_handle_notify_resume(struct ksignal *ksig, struct pt_regs *regs) { }
>> +static inline void rseq_handle_slowpath(struct pt_regs *regs) { }
>> static inline void rseq_signal_deliver(struct ksignal *ksig, struct pt_regs *regs) { }
>> static inline void rseq_sched_switch_event(struct task_struct *t) { }
>> static inline void rseq_sched_set_task_cpu(struct task_struct *t, unsigned int cpu) { }
>> --- a/init/Kconfig
>> +++ b/init/Kconfig
>> @@ -1911,7 +1911,7 @@ config RSEQ_DEBUG_DEFAULT_ENABLE
>> config DEBUG_RSEQ
>> default n
>> bool "Enable debugging of rseq() system call" if EXPERT
>> - depends on RSEQ && DEBUG_KERNEL
>> + depends on RSEQ && DEBUG_KERNEL && !GENERIC_ENTRY
>
> I'm confused about this hunk. Perhaps this belongs to a different
> commit ?

This is attached to wiring up the fast path in GENERIC_ENTRY, because
the fastpath, which does debug when enabled through the static key, is
at the end of the exit to user work loop and therefore the extra round
through the detached debug muck can be avoided.

While on !GENERIC_ENTRY architectures the processing happens always in
the TIF_NOTIFY_RESUME slowpath, so the extra debug muck is required, no?

> Mathieu

<TRIM pointless leftovers>

Can you please trim your replies?

</>

Thanks,

tglx