From: Vineet Gupta <vineet.gupta@linux.dev>
To: dennis@kernel.org, tj@kernel.org, cl@gentwo.org,
peterz@infradead.org, mingo@redhat.com, will@kernel.org,
boqun@kernel.org
Cc: longman@redhat.com, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, bpf@vger.kernel.org,
ast@kernel.org, andrii@kernel.org, daniel@iogearbox.net,
acme@kernel.org, yonghong.song@linux.dev, eddyz87@gmail.com,
martin.lau@linux.dev, nathan@kernel.org, ndesaulniers@google.com,
morbo@google.com, justinstitt@google.com, llvm@lists.linux.dev,
Vineet Gupta <vineet.gupta@linux.dev>
Subject: [RFC PATCH 1/2] percpu: do not put btf_type_tag on per-cpu variable declarations
Date: Mon, 9 Nov 2026 17:22:34 -0800 [thread overview]
Message-ID: <20261110012235.1024461-2-vineet.gupta@linux.dev> (raw)
In-Reply-To: <20261110012235.1024461-1-vineet.gupta@linux.dev>
__percpu carries BTF_TYPE_TAG(percpu), which records that a pointer
points to per-cpu memory. __PCPU_ATTRS() applies __percpu to the per-cpu
variable itself, so DECLARE_PER_CPU() and DEFINE_PER_CPU() put the tag in
declaration specifier position on the variable's own type.
arch/x86/include/asm/processor.h has
DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
which an x86 defconfig preprocesses to
extern __seg_gs __attribute__((btf_type_tag("percpu")))
__attribute__((section(".data..percpu" "..read_mostly")))
__typeof__(struct cpuinfo_x86) cpu_info;
and GCC warns:
processor.h:232:36: warning: ignoring attributes applied to
'struct cpuinfo_x86' after definition [-Wattributes]
which -Werror turns into a build failure.
The message is confusing: this is a declaration, not a definition. But
the compiler is right to object to a type tag on the aggregate, and the
issue is fundamental: every variant of an aggregate shares one DIE, so
there is nowhere to put it. clang drops it silently and GCC warns.
The tag is meant to record that a pointer points to per-cpu memory, and
cpu_info is not a pointer.
And this gets worse: for a pointer-typed per-cpu variable GCC attaches
the tag to the pointee, so
static DEFINE_PER_CPU(struct bpf_hrtimer *, hrtimer_running);
comes out as PTR -> TYPE_TAG 'percpu' -> struct bpf_hrtimer. The truth
is the other way round: hrtimer_running lives in per-cpu memory and
points at ordinary memory, while that record says it is an ordinary
pointer to per-cpu memory. clang emits no tag there at all.
Add __percpu_var, which skips the btf tag (__percpu under sparse) and
use it in __PCPU_ATTRS(). The cpu_info declaration above becomes
extern __seg_gs
__attribute__((section(".data..percpu" "..read_mostly")))
__typeof__(struct cpuinfo_x86) cpu_info;
The pointer spelling, T __percpu *p, is unchanged and keeps its tag.
Before this patch the tag also qualified the variable's type, so &var
had type "T __percpu *", and a pointer does have a DIE of its own:
pahole emitted PTR -> TYPE_TAG 'percpu' -> T for each one.
this_cpu_ptr(&var) is that shape, and that is where the records came
from.
Those are the records an x86 defconfig built with clang loses: 280 BTF
types, 140 TYPE_TAG and the 140 pointers carrying them, with .BTF
shrinking from 6831660 to 6828300 bytes. They are the derived pointers
-- clang never recorded the declarations themselves. None of them were
reachable: a record points at a type only if something is declared with
it, and nothing is declared with these. The 794 places that do declare a
"T __percpu *" keep theirs -- the tags reached by a STRUCT, UNION,
ARRAY, FUNC_PROTO or another PTR number 117, 6, 3, 39 and 5 before and
after. .text is byte-identical.
Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev>
---
include/linux/compiler_types.h | 8 ++++++++
include/linux/percpu-defs.h | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index c5921f139007..0a18b3f10675 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -50,6 +50,7 @@
# define __user __attribute__((noderef, address_space(__user)))
# define __iomem __attribute__((noderef, address_space(__iomem)))
# define __percpu __attribute__((noderef, address_space(__percpu)))
+# define __percpu_var __percpu
# define __rcu __attribute__((noderef, address_space(__rcu)))
static inline void __chk_user_ptr(const volatile void __user *ptr) { }
static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
@@ -68,7 +69,14 @@ static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
# define __user BTF_TYPE_TAG(user)
# endif
# define __iomem
+/*
+ * btf_type_tag records "points to per-cpu memory", so it belongs on the
+ * pointer spelling only. Declaring the per-cpu variable itself puts the tag
+ * in declaration specifier position, where clang drops it and GCC attaches it
+ * to the wrong type, so __percpu_var leaves it out.
+ */
# define __percpu __percpu_qual BTF_TYPE_TAG(percpu)
+# define __percpu_var __percpu_qual
# define __rcu BTF_TYPE_TAG(rcu)
# define __chk_user_ptr(x) (void)0
diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h
index dbe3267a0a13..f53fc430aaad 100644
--- a/include/linux/percpu-defs.h
+++ b/include/linux/percpu-defs.h
@@ -45,7 +45,7 @@
* that section.
*/
#define __PCPU_ATTRS(sec) \
- __percpu __attribute__((section(PER_CPU_BASE_SECTION sec))) \
+ __percpu_var __attribute__((section(PER_CPU_BASE_SECTION sec))) \
PER_CPU_ATTRIBUTES
#define __PCPU_DUMMY_ATTRS \
--
2.53.0-Meta
next prev parent reply other threads:[~2026-11-10 1:22 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 1:22 [RFC PATCH 0/2] percpu, local_lock: drop btf_type_tag where no compiler records it Vineet Gupta
2026-11-10 1:22 ` Vineet Gupta [this message]
2026-11-10 1:22 ` [RFC PATCH 2/2] local_lock: do not put btf_type_tag on the lock guard type Vineet Gupta
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261110012235.1024461-2-vineet.gupta@linux.dev \
--to=vineet.gupta@linux.dev \
--cc=acme@kernel.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=boqun@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=cl@gentwo.org \
--cc=daniel@iogearbox.net \
--cc=dennis@kernel.org \
--cc=eddyz87@gmail.com \
--cc=justinstitt@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=llvm@lists.linux.dev \
--cc=longman@redhat.com \
--cc=martin.lau@linux.dev \
--cc=mingo@redhat.com \
--cc=morbo@google.com \
--cc=nathan@kernel.org \
--cc=ndesaulniers@google.com \
--cc=peterz@infradead.org \
--cc=tj@kernel.org \
--cc=will@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®