From: Ingo Molnar <mingo@kernel.org>
To: linux-kernel@vger.kernel.org
Cc: Andy Lutomirski <luto@amacapital.net>,
Dave Hansen <dave@sr71.net>, Brian Gerst <brgerst@gmail.com>,
Peter Zijlstra <peterz@infradead.org>,
Borislav Petkov <bp@alien8.de>, "H . Peter Anvin" <hpa@zytor.com>,
Linus Torvalds <torvalds@linux-foundation.org>,
Oleg Nesterov <oleg@redhat.com>,
Thomas Gleixner <tglx@linutronix.de>,
"Chang S . Bae" <chang.seok.bae@intel.com>,
Ingo Molnar <mingo@kernel.org>, Andy Lutomirski <luto@kernel.org>,
Fenghua Yu <fenghua.yu@intel.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
Uros Bizjak <ubizjak@gmail.com>
Subject: [PATCH 3/8] x86/fpu: Make task_struct::thread constant size
Date: Wed, 9 Apr 2025 23:11:22 +0200 [thread overview]
Message-ID: <20250409211127.3544993-4-mingo@kernel.org> (raw)
In-Reply-To: <20250409211127.3544993-1-mingo@kernel.org>
Turn thread.fpu into a pointer. Since most FPU code internals work by passing
around the FPU pointer already, the code generation impact is small.
This allows us to remove the old kludge of task_struct being variable size:
struct task_struct {
...
/*
* New fields for task_struct should be added above here, so that
* they are included in the randomized portion of task_struct.
*/
randomized_struct_fields_end
/* CPU-specific state of this task: */
struct thread_struct thread;
/*
* WARNING: on x86, 'thread_struct' contains a variable-sized
* structure. It *MUST* be at the end of 'task_struct'.
*
* Do not put anything below here!
*/
};
... which creates a number of problems, such as requiring thread_struct to be
the last member of the struct - not allowing it to be struct-randomized, etc.
But the primary motivation is to allow the decoupling of task_struct from
hardware details (<asm/processor.h> in particular), and to eventually allow
the per-task infrastructure:
DECLARE_PER_TASK(type, name);
...
per_task(current, name) = val;
... which requires task_struct to be a constant size struct.
The fpu_thread_struct_whitelist() quirk to hardened usercopy can be removed,
now that the FPU structure is not embedded in the task struct anymore, which
reduces text footprint a bit.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Fixed-by: Oleg Nesterov <oleg@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Uros Bizjak <ubizjak@gmail.com>
Link: https://lore.kernel.org/r/20240605083557.2051480-2-mingo@kernel.org
---
arch/x86/include/asm/processor.h | 20 +++++++++-----------
arch/x86/kernel/fpu/core.c | 23 ++++++++++++-----------
arch/x86/kernel/fpu/init.c | 17 ++++++++++-------
arch/x86/kernel/process.c | 2 +-
include/linux/sched.h | 15 ++++-----------
5 files changed, 36 insertions(+), 41 deletions(-)
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 2f631e0adea3..5ea7e5d2c4de 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -516,21 +516,19 @@ struct thread_struct {
#endif
/* Floating point and extended processor state */
- struct fpu fpu;
- /*
- * WARNING: 'fpu' is dynamically-sized. It *MUST* be at
- * the end.
- */
+ struct fpu *fpu;
};
-#define x86_task_fpu(task) (&(task)->thread.fpu)
-
-extern void fpu_thread_struct_whitelist(unsigned long *offset, unsigned long *size);
+#define x86_task_fpu(task) ((task)->thread.fpu)
-static inline void arch_thread_struct_whitelist(unsigned long *offset,
- unsigned long *size)
+/*
+ * X86 doesn't need any embedded-FPU-struct quirks:
+ */
+static inline void
+arch_thread_struct_whitelist(unsigned long *offset, unsigned long *size)
{
- fpu_thread_struct_whitelist(offset, size);
+ *offset = 0;
+ *size = 0;
}
static inline void
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index dc6d7f93c446..853a738fdf2d 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -593,8 +593,19 @@ static int update_fpu_shstk(struct task_struct *dst, unsigned long ssp)
int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal,
unsigned long ssp)
{
+ /*
+ * We allocate the new FPU structure right after the end of the task struct.
+ * task allocation size already took this into account.
+ *
+ * This is safe because task_struct size is a multiple of cacheline size.
+ */
struct fpu *src_fpu = x86_task_fpu(current);
- struct fpu *dst_fpu = x86_task_fpu(dst);
+ struct fpu *dst_fpu = (void *)dst + sizeof(*dst);
+
+ BUILD_BUG_ON(sizeof(*dst) % SMP_CACHE_BYTES != 0);
+ BUG_ON(!src_fpu);
+
+ dst->thread.fpu = dst_fpu;
/* The new task's FPU state cannot be valid in the hardware. */
dst_fpu->last_cpu = -1;
@@ -663,16 +674,6 @@ int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal,
return 0;
}
-/*
- * Whitelist the FPU register state embedded into task_struct for hardened
- * usercopy.
- */
-void fpu_thread_struct_whitelist(unsigned long *offset, unsigned long *size)
-{
- *offset = offsetof(struct thread_struct, fpu.__fpstate.regs);
- *size = fpu_kernel_cfg.default_size;
-}
-
/*
* Drops current FPU state: deactivates the fpregs and
* the fpstate. NOTE: it still leaves previous contents
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c
index ad5cb2943d37..848ea79886ba 100644
--- a/arch/x86/kernel/fpu/init.c
+++ b/arch/x86/kernel/fpu/init.c
@@ -71,8 +71,15 @@ static bool __init fpu__probe_without_cpuid(void)
return fsw == 0 && (fcw & 0x103f) == 0x003f;
}
+static struct fpu x86_init_fpu __attribute__ ((aligned (64))) __read_mostly;
+
static void __init fpu__init_system_early_generic(void)
{
+ fpstate_reset(&x86_init_fpu);
+ current->thread.fpu = &x86_init_fpu;
+ set_thread_flag(TIF_NEED_FPU_LOAD);
+ x86_init_fpu.last_cpu = -1;
+
if (!boot_cpu_has(X86_FEATURE_CPUID) &&
!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
if (fpu__probe_without_cpuid())
@@ -150,6 +157,8 @@ static void __init fpu__init_task_struct_size(void)
{
int task_size = sizeof(struct task_struct);
+ task_size += sizeof(struct fpu);
+
/*
* Subtract off the static size of the register state.
* It potentially has a bunch of padding.
@@ -164,14 +173,9 @@ static void __init fpu__init_task_struct_size(void)
/*
* We dynamically size 'struct fpu', so we require that
- * it be at the end of 'thread_struct' and that
- * 'thread_struct' be at the end of 'task_struct'. If
- * you hit a compile error here, check the structure to
- * see if something got added to the end.
+ * 'state' be at the end of 'it:
*/
CHECK_MEMBER_AT_END_OF(struct fpu, __fpstate);
- CHECK_MEMBER_AT_END_OF(struct thread_struct, fpu);
- CHECK_MEMBER_AT_END_OF(struct task_struct, thread);
arch_task_struct_size = task_size;
}
@@ -213,7 +217,6 @@ static void __init fpu__init_system_xstate_size_legacy(void)
*/
void __init fpu__init_system(void)
{
- fpstate_reset(x86_task_fpu(current));
fpu__init_system_early_generic();
/*
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 47694e391506..3ce4cce46f3f 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -103,7 +103,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
dst->thread.vm86 = NULL;
#endif
/* Drop the copied pointer to current's fpstate */
- x86_task_fpu(dst)->fpstate = NULL;
+ dst->thread.fpu = NULL;
return 0;
}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f96ac1982893..4ecc0c6b1cb0 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1646,22 +1646,15 @@ struct task_struct {
struct user_event_mm *user_event_mm;
#endif
- /*
- * New fields for task_struct should be added above here, so that
- * they are included in the randomized portion of task_struct.
- */
- randomized_struct_fields_end
-
/* CPU-specific state of this task: */
struct thread_struct thread;
/*
- * WARNING: on x86, 'thread_struct' contains a variable-sized
- * structure. It *MUST* be at the end of 'task_struct'.
- *
- * Do not put anything below here!
+ * New fields for task_struct should be added above here, so that
+ * they are included in the randomized portion of task_struct.
*/
-};
+ randomized_struct_fields_end
+} __attribute__ ((aligned (64)));
#define TASK_REPORT_IDLE (TASK_REPORT + 1)
#define TASK_REPORT_MAX (TASK_REPORT_IDLE << 1)
--
2.45.2
next prev parent reply other threads:[~2025-04-09 21:11 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-09 21:11 [PATCH -v5 0/8] sched: Make task_struct::thread constant size, x86/fpu: Remove thread::fpu Ingo Molnar
2025-04-09 21:11 ` [PATCH 1/8] x86/fpu: Introduce the x86_task_fpu() helper method Ingo Molnar
2025-04-14 7:34 ` [tip: x86/merge] " tip-bot2 for Ingo Molnar
2025-04-09 21:11 ` [PATCH 2/8] x86/fpu: Convert task_struct::thread.fpu accesses to use x86_task_fpu() Ingo Molnar
2025-04-14 7:34 ` [tip: x86/merge] " tip-bot2 for Ingo Molnar
2025-04-09 21:11 ` Ingo Molnar [this message]
2025-04-14 7:34 ` [tip: x86/merge] x86/fpu: Make task_struct::thread constant size tip-bot2 for Ingo Molnar
2025-04-09 21:11 ` [PATCH 4/8] x86/fpu: Remove the thread::fpu pointer Ingo Molnar
2025-04-10 7:39 ` Peter Zijlstra
2025-04-10 10:10 ` Ingo Molnar
2025-04-10 10:30 ` Peter Zijlstra
2025-04-10 10:54 ` [PATCH] x86/fpu: Clarify FPU context cacheline alignment Ingo Molnar
2025-04-14 7:34 ` [tip: x86/merge] " tip-bot2 for Ingo Molnar
2025-04-10 10:51 ` [PATCH 4/8] x86/fpu: Remove the thread::fpu pointer Ingo Molnar
2025-04-10 14:04 ` Oleg Nesterov
2025-04-14 7:34 ` [tip: x86/merge] " tip-bot2 for Ingo Molnar
2025-04-09 21:11 ` [PATCH 5/8] x86/fpu: Push 'fpu' pointer calculation into the fpu__drop() call Ingo Molnar
2025-04-14 7:34 ` [tip: x86/merge] " tip-bot2 for Ingo Molnar
2025-04-09 21:11 ` [PATCH 6/8] x86/fpu: Make sure x86_task_fpu() doesn't get called for PF_KTHREAD|PF_USER_WORKER tasks during exit Ingo Molnar
2025-04-11 15:22 ` Chang S. Bae
2025-04-12 8:37 ` Ingo Molnar
2025-04-14 7:34 ` [tip: x86/merge] " tip-bot2 for Ingo Molnar
2025-04-09 21:11 ` [PATCH 7/8] x86/fpu: Remove init_task FPU state dependencies, add debugging warning for PF_KTHREAD tasks Ingo Molnar
2025-04-14 7:34 ` [tip: x86/merge] " tip-bot2 for Ingo Molnar
2025-04-09 21:11 ` [PATCH 8/8] x86/fpu: Use 'fpstate' variable names consistently Ingo Molnar
2025-04-14 7:34 ` [tip: x86/merge] " tip-bot2 for Ingo Molnar
2025-04-22 16:11 ` [PATCH -v5 0/8] sched: Make task_struct::thread constant size, x86/fpu: Remove thread::fpu Oleg Nesterov
2025-04-22 20:09 ` Ingo Molnar
2025-04-22 17:01 ` question about switch_fpu_prepare/switch_fpu_finish Oleg Nesterov
2025-04-22 20:11 ` Ingo Molnar
2025-05-03 14:38 ` [PATCH tip/x86/fpu 1/6] x86/fpu: simplify the switch_fpu_prepare() + switch_fpu_finish() logic Oleg Nesterov
2025-05-04 8:54 ` [tip: x86/fpu] x86/fpu: Simplify " tip-bot2 for Oleg Nesterov
2025-05-03 14:38 ` [PATCH tip/x86/fpu 2/6] x86/fpu: kill x86_init_fpu Oleg Nesterov
2025-05-04 8:54 ` [tip: x86/fpu] x86/fpu: Remove x86_init_fpu tip-bot2 for Oleg Nesterov
2025-05-03 14:38 ` [PATCH tip/x86/fpu 3/6] x86/fpu: kill DEFINE_EVENT(x86_fpu, x86_fpu_copy_src) Oleg Nesterov
2025-05-04 8:54 ` [tip: x86/fpu] x86/fpu: Remove " tip-bot2 for Oleg Nesterov
2025-05-03 14:38 ` [PATCH tip/x86/fpu 4/6] x86/fpu: arch_dup_task_struct: always use memcpy_and_pad() Oleg Nesterov
2025-05-04 8:54 ` [tip: x86/fpu] x86/fpu: Always use memcpy_and_pad() in arch_dup_task_struct() tip-bot2 for Oleg Nesterov
2025-05-03 14:38 ` [PATCH tip/x86/fpu 5/6] x86/fpu: fpu__drop: check TIF_NEED_FPU_LOAD instead of PF_KTHREAD|PF_USER_WORKER Oleg Nesterov
2025-05-04 8:54 ` [tip: x86/fpu] x86/fpu: Check TIF_NEED_FPU_LOAD instead of PF_KTHREAD|PF_USER_WORKER in fpu__drop() tip-bot2 for Oleg Nesterov
2025-05-03 14:39 ` [PATCH tip/x86/fpu 6/6] x86/fpu: shift fpregs_assert_state_consistent() from arch_exit_work() to its caller Oleg Nesterov
2025-05-04 8:36 ` Ingo Molnar
2025-05-04 8:54 ` [tip: x86/fpu] x86/fpu: Shift " tip-bot2 for Oleg Nesterov
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=20250409211127.3544993-4-mingo@kernel.org \
--to=mingo@kernel.org \
--cc=bp@alien8.de \
--cc=brgerst@gmail.com \
--cc=chang.seok.bae@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=dave@sr71.net \
--cc=fenghua.yu@intel.com \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=luto@kernel.org \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
--cc=ubizjak@gmail.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.