Re: warning: cast removes address space '__percpu' of expression
From: Uros Bizjak
Date: Tue Apr 02 2024 - 05:43:25 EST
On Tue, Apr 2, 2024 at 9:56 AM Charlemagne Lasse
<charlemagnelasse@xxxxxxxxx> wrote:
>
> Am Mo., 1. Apr. 2024 um 21:16 Uhr schrieb Uros Bizjak <ubizjak@xxxxxxxxx>:
> > > I would even go as far as saying that 1ca3683cc6d2 ("x86/percpu:
> > > Enable named address spaces with known compiler version") together
> > > with 3a1d3829e193 ("x86/percpu: Avoid sparse warning with cast to
> > > named address space") triggered this problem
>
> I think 1ca3683cc6d2 was wrong and is the last working one.
>
>
> Just switch to 1ca3683cc6d2c2ce4204df519c4e4730d037905a and you won't
> see the messages.
>
> ```
> git reset --hard 1ca3683cc6d2c2ce4204df519c4e4730d037905a
> git clean -dfx
> make allnoconfig -j$(nproc)
> make kvm_guest.config
> make prepare -j$(nproc)
> touch include/linux/netdevice.h
> make C=1 net/core/dev.o CHECK="sparse -Wcast-from-as"
> ```
>
> Go to 9a462b9eafa6dda16ea8429b151edb1fb535d744 and cherry-pick
> 3a1d3829e193c091475ceab481c5f8deab385023 and you would see the error.
> On amd64 with 12.2.0, this would look like this:
>
> ```
> git reset --hard 9a462b9eafa6dda16ea8429b151edb1fb535d744
> git cherry-pick 3a1d3829e193c091475ceab481c5f8deab385023
> git clean -dfx
> make allnoconfig -j$(nproc)
> make kvm_guest.config
> make prepare -j$(nproc)
> touch include/linux/netdevice.h
> make C=1 net/core/dev.o CHECK="sparse -Wcast-from-as"
> ```
>
> I would recommend to use `-Wsparse-all` for testing but for this
> demonstration, it is easier to use `-Wcast-from-as` to reduce the
> amount of noise in the demonstrator.
Oh, I see the problem now. We *do* cast away from __percpu space, this
is how we switch between GCC's named address spaces [1]:
--q--
6.17.5 x86 Named Address Spaces
..
The respective segment base must be set via some method specific to
the operating system. Rather than require an expensive system call to
retrieve the segment base, these address spaces are not considered to
be subspaces of the generic (flat) address space. This means that
explicit casts are required to convert pointers between these address
spaces and the generic address space. In practice the application
should cast to uintptr_t and apply the segment base offset that it
installed previously.
--/q--
Please try the attached patch that informs sparse about this action.
BTW: Please also note recent discussion about different checks for
__percpu name space that can be implemented using GCC's named address
spaces feature [2].
[1] https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html
[2[ https://lore.kernel.org/lkml/87bk7ux4e9.ffs@tglx/#t
Thanks,
Uros.
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index 44958ebaf626..8fc8d236c255 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -70,7 +70,7 @@
unsigned long tcp_ptr__; \
tcp_ptr__ = __raw_cpu_read(, this_cpu_off); \
\
- tcp_ptr__ += (unsigned long)(ptr); \
+ tcp_ptr__ += (__force unsigned long)(ptr); \
(typeof(*(ptr)) __kernel __force *)tcp_ptr__; \
})
#else /* CONFIG_USE_X86_SEG_SUPPORT */
@@ -85,7 +85,7 @@
: "=r" (tcp_ptr__) \
: "m" (__my_cpu_var(this_cpu_off))); \
\
- tcp_ptr__ += (unsigned long)(ptr); \
+ tcp_ptr__ += (__force unsigned long)(ptr); \
(typeof(*(ptr)) __kernel __force *)tcp_ptr__; \
})
#endif /* CONFIG_USE_X86_SEG_SUPPORT */
@@ -102,8 +102,8 @@
#endif /* CONFIG_SMP */
#define __my_cpu_type(var) typeof(var) __percpu_seg_override
-#define __my_cpu_ptr(ptr) (__my_cpu_type(*ptr) *)(uintptr_t)(ptr)
-#define __my_cpu_var(var) (*__my_cpu_ptr(&var))
+#define __my_cpu_ptr(ptr) (__my_cpu_type(*ptr) *)(__force uintptr_t)(ptr)
+#define __my_cpu_var(var) (*__my_cpu_ptr(&(var)))
#define __percpu_arg(x) __percpu_prefix "%" #x
#define __force_percpu_arg(x) __force_percpu_prefix "%" #x