Re: [PATCH v2 14/20] arm64: percpu: Implement preemptible read/write ops
David Laight <[email protected]> Wed, 5 Aug 2026 13:08:48 +0100
| Newsgroups | gmane.linux.kernel.stable,gmane.linux.ports.arm.kernel |
|---|---|
| Message-ID | <20260805130848.6d533293@pumpkin> |
On Wed, 5 Aug 2026 10:24:04 +0100 Ryan Roberts <[email protected]> wrote: > On 04/08/2026 18:04, Mark Rutland wrote: > > Use the PCPU GPR infrastructure to implement preemptible this_cpu_read() > > and this_cpu_write(). > > > > This change means that this_cpu_read() will always use a plain LDR, even > > in LTO configurations where READ_ONCE() will use LDA[P]R. Using plain > > LDR is preferable, given that the rationale for using LDA[P]R in > > READ_ONCE() was to retain address dependencies against values written by > > other CPUs, which isn't expected usage for this_cpu_read(). Using plain > > LDR will enforce fewer ordering constraints. > > > > Test case: > > > > | void outline_this_cpu_write_u64(u64 __percpu *p, u64 v) > > | { > > | this_cpu_write(*p, v); > > | } > > > > Generated code before this patch (v7.2-rc4): > > > > | <outline_this_cpu_write_u64>: > > | paciasp > > | stp x29, x30, [sp, #-16]! > > | mrs x2, sp_el0 > > | mov x29, sp > > | ldr w3, [x2, #8] > > | add w3, w3, #0x1 > > | str w3, [x2, #8] > > | mrs x3, tpidr_el1 > > | str x1, [x0, x3] > > | ldr x0, [x2, #8] > > | sub x0, x0, #0x1 > > | str w0, [x2, #8] > > | cbz x0, 1f > > | ldr x0, [x2, #8] > > | cbnz x0, 2f > > | 1: bl preempt_schedule_notrace > > | 2: ldp x29, x30, [sp], #16 > > | autiasp > > | ret > > > > Generated code after this patch: > > > > | <outline_this_cpu_write_u64>: > > | mrs x2, sp_el0 > > | mov w3, #0x7c60 > > | strh w3, [x2, #20] > > | mrs x3, tpidr_el1 > > | str x1, [x0, x3] > > | strh wzr, [x2, #20] > > | ret > > > > Signed-off-by: Mark Rutland <[email protected]> > > Cc: Ada Couprie Diaz <[email protected]> > > Cc: Ard Biesheuvel <[email protected]> > > Cc: Catalin Marinas <[email protected]> > > Cc: James Morse <[email protected]> > > Cc: Jinjie Ruan <[email protected]> > > Cc: Marc Zyngier <[email protected]> > > Cc: Peter Zijlstra <[email protected]> > > Cc: Vladimir Murzin <[email protected]> > > Cc: Will Deacon <[email protected]> > > Cc: Yang Shi <[email protected]> > > --- > FYI I'm seeing build warnings caused by this patch (with ftrace enabled - based > on the warnings, I'm guessing that's the key bit), using: > > aarch64-linux-gnu-gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44 > > I haven't investigated the cause. It'll be the earlier patch that changed the casts. The code is doing: this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid, FTRACE_PID_IGNORE); where the constant is -1. I suspect the warning messages are coming from the switch case that are optimised away because the size if wrong (ftrace_ignore_pid seems to be a pid number to ignore and is 32 bits. That does seem a long-winded way to access per-cpu data. To make any sense the code must be running with preemption disabled and be caching info in per-cpu memory. In which case it can just access it directly. OTOH it could save the 'global' address of the per-cpu data and then access it using the pointer so that access would be a normal one. David > > Thanks, > Ryan > > ---8<--- > In file included from linux/arch/arm64/include/asm/spectre.h:17, > from linux/arch/arm64/include/asm/processor.h:47, > from linux/include/linux/sched.h:13, > from linux/include/linux/ratelimit.h:6, > from linux/include/linux/dev_printk.h:16, > from linux/include/linux/device.h:15, > from linux/include/linux/node.h:18, > from linux/include/linux/cpu.h:17, > from linux/include/linux/stop_machine.h:5, > from linux/kernel/trace/ftrace.c:17: > linux/kernel/trace/ftrace.c: In function 'ftrace_filter_pid_sched_switch_probe': > linux/arch/arm64/include/asm/percpu.h:295:42: warning: conversion from 'long unsigned int' to 'u8' {aka 'unsigned char'} changes value from '18446744073709551615' to '255' [-Woverflow] > 295 | _pcp_wrap(__percpu_write_8, pcp, (unsigned long)(val)) > | ^~~~~~~~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:277:20: note: in definition of macro '_pcp_wrap' > 277 | op(&(pcp), __VA_ARGS__); \ > | ^~~~~~~~~~~ > linux/include/linux/percpu-defs.h:369:25: note: in expansion of macro 'this_cpu_write_1' > 369 | case 1: stem##1(variable, __VA_ARGS__);break; \ > | ^~~~ > linux/include/linux/percpu-defs.h:500:41: note: in expansion of macro '__pcpu_size_call' > 500 | #define this_cpu_write(pcp, val) __pcpu_size_call(this_cpu_write_, pcp, val) > | ^~~~~~~~~~~~~~~~ > linux/kernel/trace/ftrace.c:8628:17: note: in expansion of macro 'this_cpu_write' > 8628 | this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid, > | ^~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:297:43: warning: conversion from 'long unsigned int' to 'u16' {aka 'short unsigned int'} changes value from '18446744073709551615' to '65535' [-Woverflow] > 297 | _pcp_wrap(__percpu_write_16, pcp, (unsigned long)(val)) > | ^~~~~~~~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:277:20: note: in definition of macro '_pcp_wrap' > 277 | op(&(pcp), __VA_ARGS__); \ > | ^~~~~~~~~~~ > linux/include/linux/percpu-defs.h:370:25: note: in expansion of macro 'this_cpu_write_2' > 370 | case 2: stem##2(variable, __VA_ARGS__);break; \ > | ^~~~ > linux/include/linux/percpu-defs.h:500:41: note: in expansion of macro '__pcpu_size_call' > 500 | #define this_cpu_write(pcp, val) __pcpu_size_call(this_cpu_write_, pcp, val) > | ^~~~~~~~~~~~~~~~ > linux/kernel/trace/ftrace.c:8628:17: note: in expansion of macro 'this_cpu_write' > 8628 | this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid, > | ^~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:299:43: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709551615' to '4294967295' [-Woverflow] > 299 | _pcp_wrap(__percpu_write_32, pcp, (unsigned long)(val)) > | ^~~~~~~~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:277:20: note: in definition of macro '_pcp_wrap' > 277 | op(&(pcp), __VA_ARGS__); \ > | ^~~~~~~~~~~ > linux/include/linux/percpu-defs.h:371:25: note: in expansion of macro 'this_cpu_write_4' > 371 | case 4: stem##4(variable, __VA_ARGS__);break; \ > | ^~~~ > linux/include/linux/percpu-defs.h:500:41: note: in expansion of macro '__pcpu_size_call' > 500 | #define this_cpu_write(pcp, val) __pcpu_size_call(this_cpu_write_, pcp, val) > | ^~~~~~~~~~~~~~~~ > linux/kernel/trace/ftrace.c:8628:17: note: in expansion of macro 'this_cpu_write' > 8628 | this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid, > | ^~~~~~~~~~~~~~ > linux/kernel/trace/ftrace.c: In function 'ignore_task_cpu': > linux/arch/arm64/include/asm/percpu.h:295:42: warning: conversion from 'long unsigned int' to 'u8' {aka 'unsigned char'} changes value from '18446744073709551615' to '255' [-Woverflow] > 295 | _pcp_wrap(__percpu_write_8, pcp, (unsigned long)(val)) > | ^~~~~~~~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:277:20: note: in definition of macro '_pcp_wrap' > 277 | op(&(pcp), __VA_ARGS__); \ > | ^~~~~~~~~~~ > linux/include/linux/percpu-defs.h:369:25: note: in expansion of macro 'this_cpu_write_1' > 369 | case 1: stem##1(variable, __VA_ARGS__);break; \ > | ^~~~ > linux/include/linux/percpu-defs.h:500:41: note: in expansion of macro '__pcpu_size_call' > 500 | #define this_cpu_write(pcp, val) __pcpu_size_call(this_cpu_write_, pcp, val) > | ^~~~~~~~~~~~~~~~ > linux/kernel/trace/ftrace.c:8898:17: note: in expansion of macro 'this_cpu_write' > 8898 | this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid, > | ^~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:297:43: warning: conversion from 'long unsigned int' to 'u16' {aka 'short unsigned int'} changes value from '18446744073709551615' to '65535' [-Woverflow] > 297 | _pcp_wrap(__percpu_write_16, pcp, (unsigned long)(val)) > | ^~~~~~~~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:277:20: note: in definition of macro '_pcp_wrap' > 277 | op(&(pcp), __VA_ARGS__); \ > | ^~~~~~~~~~~ > linux/include/linux/percpu-defs.h:370:25: note: in expansion of macro 'this_cpu_write_2' > 370 | case 2: stem##2(variable, __VA_ARGS__);break; \ > | ^~~~ > linux/include/linux/percpu-defs.h:500:41: note: in expansion of macro '__pcpu_size_call' > 500 | #define this_cpu_write(pcp, val) __pcpu_size_call(this_cpu_write_, pcp, val) > | ^~~~~~~~~~~~~~~~ > linux/kernel/trace/ftrace.c:8898:17: note: in expansion of macro 'this_cpu_write' > 8898 | this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid, > | ^~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:299:43: warning: conversion from 'long unsigned int' to 'u32' {aka 'unsigned int'} changes value from '18446744073709551615' to '4294967295' [-Woverflow] > 299 | _pcp_wrap(__percpu_write_32, pcp, (unsigned long)(val)) > | ^~~~~~~~~~~~~~~~~~~~ > linux/arch/arm64/include/asm/percpu.h:277:20: note: in definition of macro '_pcp_wrap' > 277 | op(&(pcp), __VA_ARGS__); \ > | ^~~~~~~~~~~ > linux/include/linux/percpu-defs.h:371:25: note: in expansion of macro 'this_cpu_write_4' > 371 | case 4: stem##4(variable, __VA_ARGS__);break; \ > | ^~~~ > linux/include/linux/percpu-defs.h:500:41: note: in expansion of macro '__pcpu_size_call' > 500 | #define this_cpu_write(pcp, val) __pcpu_size_call(this_cpu_write_, pcp, val) > | ^~~~~~~~~~~~~~~~ > linux/kernel/trace/ftrace.c:8898:17: note: in expansion of macro 'this_cpu_write' > 8898 | this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid, > | ^~~~~~~~~~~~~~ > ---8<--- > >