Re: [PATCH v3 2/6] compiler.h: Introduce TYPEOF_UNQUAL() macro

Uros Bizjak
2024-12-10T16:37:24Z

[-- Attachment #1: Type: text/plain, Size: 1659 bytes --]

On Mon, Dec 9, 2024 at 12:30 PM Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Sun, Dec 08, 2024 at 09:45:17PM +0100, Uros Bizjak wrote:
> > Define TYPEOF_UNQUAL() to use __typeof_unqual__() as typeof operator
> > when available, to return unqualified type of the expression.
> >
> > Current version of sparse doesn't know anything about __typeof_unqual__()
> > operator. Avoid the usage of __typeof_unqual__() when sparse checking
> > is active to prevent sparse errors with unknowing keyword.
>
> Ooooh, new toys.
>
> I suppose __unqual_scalar_typeof() wants to be using this when
> available?

Not only that, the new toy enables clang to check kernel's address
spaces in a generic way using address_space attribute.

Please find attached a follow-up patch that enables __percpu checks
for all targets, supported by clang. Clang is a little bit pickier
than gcc about named address space declarations (it warns for use of
duplicated address space attribute), so the patch in addition to the
obvious

+# define __percpu_qual __attribute__((address_space(3)))

also fixes a couple of macros that could result in a duplicated
address space attribute.

The patch, applied as a follow-up to the series, survives allyesconfig
compilation with clang-19 and produces a bootable kernel. The patch
was tested only for x86_64 target, for other targets a couple of
trivial fixes would be necessary (a cast or a substitution of typeof()
with TYPEOF_UNQUAL()).

AFAICS, the same approach using clang's address_space attribute can be
implemented to also check other address spaces: __user, __iommu and
__rcu.

Uros.

[-- Attachment #2: percpu-clang.diff.txt --]
[-- Type: text/plain, Size: 2238 bytes --]

diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index 02aeca21479a..4109d828a564 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -16,7 +16,12 @@
* space qualifier).
*/
#ifndef __percpu_qual
-# define __percpu_qual
+# if __has_attribute(address_space) && \
+ defined(CONFIG_CC_HAS_TYPEOF_UNQUAL) && !defined(__CHECKER__)
+# define __percpu_qual __attribute__((address_space(3)))
+# else
+# define __percpu_qual
+# endif
#endif

#ifdef CONFIG_SMP
diff --git a/include/linux/device.h b/include/linux/device.h
index 667cb6db9019..1d6a55d5250a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -431,9 +431,9 @@ static inline int __devm_add_action_or_reset(struct device *dev, void (*action)(
* RETURNS:
* Pointer to allocated memory on success, NULL on failure.
*/
-#define devm_alloc_percpu(dev, type) \
- ((typeof(type) __percpu *)__devm_alloc_percpu((dev), sizeof(type), \
- __alignof__(type)))
+#define devm_alloc_percpu(dev, type) \
+ ((TYPEOF_UNQUAL(type) __percpu *)__devm_alloc_percpu((dev), \
+ sizeof(type), __alignof__(type)))

void __percpu *__devm_alloc_percpu(struct device *dev, size_t size,
size_t align);
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 52b5ea663b9f..c3bf040aba66 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -148,13 +148,13 @@ extern void __percpu *pcpu_alloc_noprof(size_t size, size_t align, bool reserved
alloc_hooks(pcpu_alloc_noprof(_size, _align, true, GFP_KERNEL))

#define alloc_percpu_gfp(type, gfp) \
- (typeof(type) __percpu *)__alloc_percpu_gfp(sizeof(type), \
+ (TYPEOF_UNQUAL(type) __percpu *)__alloc_percpu_gfp(sizeof(type), \
__alignof__(type), gfp)
#define alloc_percpu(type) \
- (typeof(type) __percpu *)__alloc_percpu(sizeof(type), \
+ (TYPEOF_UNQUAL(type) __percpu *)__alloc_percpu(sizeof(type), \
__alignof__(type))
#define alloc_percpu_noprof(type) \
- ((typeof(type) __percpu *)pcpu_alloc_noprof(sizeof(type), \
+ ((TYPEOF_UNQUAL(type) __percpu *)pcpu_alloc_noprof(sizeof(type), \
__alignof__(type), false, GFP_KERNEL))

extern void free_percpu(void __percpu *__pdata);