[PATCH] arm64: syscall: unmask DAIF for tracing status
Guo Hui
guohui at uniontech.com
Tue Jun 6 22:31:19 PDT 2023
On 6/6/23 9:22 PM, Mark Rutland wrote:
> On Fri, May 26, 2023 at 10:47:15AM +0800, Guo Hui wrote:
>> The following code:
>> static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
>> const syscall_fn_t syscall_table[])
>> {
>> ...
>>
>> if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
>> local_daif_mask();
>> flags = read_thread_flags(); -------------------------------- A
>> if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP))
>> return;
>> local_daif_restore(DAIF_PROCCTX);
>> }
>>
>> trace_exit:
>> syscall_trace_exit(regs); ------- B
>> }
>>
>> 1. The flags in the if conditional statement should be used
>> in the same way as the flags in the function syscall_trace_exit,
>> because DAIF is not shielded in the function syscall_trace_exit,
>> so when the flags are obtained in line A of the code,
>> there is no need to shield DAIF.
>> Don't care about the modification of flags after line A.
>>
>> 2. Masking DAIF caused syscall performance to deteriorate by about 10%.
>> The Unixbench single core syscall performance data is as follows:
>>
>> Machine: Kunpeng 920
>>
>> Mask DAIF:
>> System Call Overhead 1172314.1 lps (10.0 s, 7 samples)
>>
>> System Benchmarks Partial Index BASELINE RESULT INDEX
>> System Call Overhead 15000.0 1172314.1 781.5
>> ========
>> System Benchmarks Index Score (Partial Only) 781.5
>>
>> Unmask DAIF:
>> System Call Overhead 1287944.6 lps (10.0 s, 7 samples)
>>
>> System Benchmarks Partial Index BASELINE RESULT INDEX
>> System Call Overhead 15000.0 1287944.6 858.6
>> ========
>> System Benchmarks Index Score (Partial Only) 858.6
>>
>> Signed-off-by: Guo Hui <guohui at uniontech.com>
> I was about to send a patch doing the same thing, so FWIW:
>
> Reviewed-by: Mark Rutland <mark.rutland at arm.com>
>
> As for why this is safe, rationale below.
>
> This masking is an artifact of the old "ret_fast_syscall" assembly that
> was converted to C in commit:
>
> f37099b6992a0b81 ("arm64: convert syscall trace logic to C")
>
> The assembly would mask DAIF, check the thread flags, and fall through
> to kernel_exit without unmasking if no tracing was needed. The
> conversion copied this masking into the C version, though this wasn't
> strictly necessary.
>
> As (in general) thread flags can be manipulated by other threads, it's
> not safe to manipulate the thread flags with plain reads and writes, and
> since commit:
>
> 342b3808786518ce ("arm64: Snapshot thread flags")
>
> ... we use read_thread_flags() to read the flags atomically.
>
> With this, there is no need to mask DAIF transiently around reading the
> flags, as we only decide whether to trace while DAIF is masked, and the
> actual tracing occurs with DAIF unmasked. When el0_svc_common() returns
> its caller will unconditionally mask DAIF via exit_to_user_mode(), so
> the masking is redundant.
>
> Mark.
>
Ok thanks, Mark, you are right.
>> ---
>> arch/arm64/kernel/syscall.c | 2 --
>> 1 file changed, 2 deletions(-)
>>
>> diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
>> index da84cf855c44..5a668d7f3c1f 100644
>> --- a/arch/arm64/kernel/syscall.c
>> +++ b/arch/arm64/kernel/syscall.c
>> @@ -147,11 +147,9 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
>> * exit regardless, as the old entry assembly did.
>> */
>> if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
>> - local_daif_mask();
>> flags = read_thread_flags();
>> if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP))
>> return;
>> - local_daif_restore(DAIF_PROCCTX);
>> }
>>
>> trace_exit:
>> --
>> 2.20.1
>>
More information about the linux-arm-kernel
mailing list