Skip to contentSkip to conversation

x86/resctrl: Add kernel-mode (e.g., PLZA) support to the resctrl subsystem

PATCH Superseded Babu Moger 6 participants 67 messages Apr 30 – Jun 29

Subsystems (4)

v3 of 7 Superseded Latest is v7 →

lore
Share & tools
lore

Babu Moger

author reviewer
#0 lore raw

v3 cover x86/resctrl: Add kernel-mode (e.g., PLZA) support to the resctrl subsystem

Hi,

This series adds support for AMD's Privilege-Level Zero Association (PLZA) so kernel work can be assigned to a resctrl group, and wires it up through a small generic "kernel mode" (kmode) layer in fs/resctrl so future architectures can plug in without touching core resctrl.

The features are documented in:

AMD64 Zen6 Platform Quality of Service (PQOS) Extensions, Publication # 69193 Revision 1.00, Issue Date March 2026

available at https://bugzilla.kernel.org/show_bug.cgi?id=206537

The patches are based on top of commit (7.1.0-rc1)
Commit 3382329a309d Merge branch into tip/master: 'timers/clocksource'.

Background
==========

Customers have identified an issue while using the QoS resource Control feature. If a memory bandwidth associated with a CLOSID is aggressively throttled, and it moves into Kernel mode, the Kernel operations are also aggressively throttled. This can stall forward progress and eventually degrade overall system performance.

Privilege-Level Zero Association (PLZA) allows the user to specify a CLOSID and/or RMID associated with execution in Privilege-Level Zero. When enabled on a HW thread, when the thread enters Privilege-Level Zero, transactions associated with that thread will be associated with the PLZA CLOSID and/or RMID. Otherwise, the HW thread will be associated with the CLOSID and RMID identified by PQR_ASSOC.

Design
======

A new sysfs file, info/kernel_mode, holds a single global policy that selects what kernel work is steered and which rdtgroup it is steered to. Reads describe the supported modes and the currently-active binding; writes change the policy or rebind to a different group. Look at the thread below for design discussion.
https://lore.kernel.org/lkml/[email protected]/

Per-rdtgroup files kmode_cpus and kmode_cpus_list scope the binding to a subset of online CPUs without unbind/rebind churn. They are visible only on the group that is currently the active kernel-mode binding.

The arch hooks (resctrl_arch_get_kmode_support, resctrl_arch_configure_kmode) keep the fs/resctrl layer arch-neutral. Only AMD PLZA is wired up here; Intel and ARM can add their own support later by implementing the hooks.

Layout
======

01-02 x86: PLZA CPU feature + MSR/data-structure plumbing. 03-05 fs/resctrl + x86: kmode data structures, arch hooks, and
population of supported modes.
06-08 fs/resctrl: global kmode config, info/kernel_mode read/write
and documentation.
09 fs/resctrl: reset the binding when the bound rdtgroup is
removed.
10-12 fs/resctrl: per-rdtgroup kmode_cpus[_list] - expose, gate
visibility on the bound group, and allow incremental writes.

Examples
========

(See Documentation/filesystems/resctrl.rst, "kernel_mode" and "kmode_cpus" sections, for the full UAPI.)

# Mount resctrl

  # mount -t resctrl resctrl /sys/fs/resctrl
  # cd /sys/fs/resctrl

# Read the supported modes. The active mode is bracketed and reports

  # the bound "<ctrl>/<mon>/" group; other supported modes report
  # ":group=none" because nothing is bound to them.
  # cat info/kernel_mode
  [inherit_ctrl_and_mon:group=//]
  global_assign_ctrl_inherit_mon_per_cpu:group=none
  global_assign_ctrl_assign_mon_per_cpu:group=none

# Create a CTRL_MON group plus a MON child and bind both the kernel # CLOSID and RMID to them.

  # mkdir ctrl1
  # mkdir ctrl1/mon_groups/mon1
  # echo "global_assign_ctrl_assign_mon_per_cpu:group=ctrl1/mon1/" \
          > info/kernel_mode
  # cat info/kernel_mode
  inherit_ctrl_and_mon:group=none
  global_assign_ctrl_inherit_mon_per_cpu:group=none
  [global_assign_ctrl_assign_mon_per_cpu:group=ctrl1/mon1/]
  # kmode_cpus and kmode_cpus_list are visible only on the bound group.
  # ls ctrl1/kmode_cpus*
  ctrl1/kmode_cpus  ctrl1/kmode_cpus_list

# Restrict the binding to a CPU subset; the write is incremental.

  # echo 0-3 > ctrl1/kmode_cpus_list
  # cat ctrl1/kmode_cpus
  f
  # cat ctrl1/kmode_cpus_list
  0-3

# Empty masks are rejected; use info/kernel_mode to reset to # "every online CPU".

  # echo "" > ctrl1/kmode_cpus_list
  bash: echo: write error: Invalid argument
  # cat info/last_cmd_status
  Empty mask not allowed; use info/kernel_mode to unbind

# Disable kernel-mode steering (back to inherit, default group).

  # echo "inherit_ctrl_and_mon" > info/kernel_mode

Tested on AMD with PLZA; the generic bits build clean on x86 without PLZA support and are no-ops at runtime.

Changelog
=========

v3:
- Generalise the layer beyond AMD: rename "PLZA mode" to "kernel mode" (kmode) in code, sysfs, and Documentation. The public interface is now info/kernel_mode and per-group kmode_cpus[_list].
- info/kernel_mode UAPI cleanups: ":group=none" instead of ":group=uninitialized"; designated initialisers + static_assert for the mode-name table; strim() the input; clearer error messages via last_cmd_status.
- kmode_cpus / kmode_cpus_list:
* 0010 exposes them read-only on every group.
* 0011 toggles their visibility via kernfs_show() so they appear only on the rdtgroup currently bound to the active kernel mode.
* 0012 (new) makes them writable: incremental enable/disable deltas via resctrl_arch_configure_kmode(), empty masks rejected with -EINVAL ("use info/kernel_mode to unbind"), offline CPUs rejected, defensive -EBUSY for stale fds opened before an info/kernel_mode rebind.
- 0009: reset the binding when the bound rdtgroup is removed, instead of leaving stale state.
- Kerneldoc/comment cleanups across the series; Documentation updated alongside the UAPI changes.

v2:
This is similar to RFC with new proposal. Names of the some interfaces are not final. Lets fix that later as we move forward.

Separated the two features: Global Bandwidth Enforcement (GLBE) and Privilege Level Zero Association (PLZA).

This series only adds support for PLZA.

Used the name of the feature as kmode instead of PLZA. That can be changed as well.

Tony suggested using global variables to store the kernel mode CLOSID and RMID. However, the kernel mode CLOSID and RMID are coming from rdtgroup structure with the new interface. Accessing them requires holding the associated lock, which would make the context switch path unnecessarily expensive. So, dropped the idea.
https://lore.kernel.org/lkml/aXuxVSbk1GR2ttzF@agluck-desk3/
Let me know if there are other ways to optimize this.

Patch 1: Data structures and arch hook: Add resctrl_kmode,
resctrl_kmode_cfg, kernel-mode bits, and resctrl_arch_get_kmode_cfg() for generic resctrl kernel mode (e.g. PLZA).

Patch 2: Implement resctrl_arch_get_kmode_cfg() on x86, add global resctrl_kcfg
and resctrl_kmode_init() to set default kmode.

Patch 3: Add info/kernel_mode and resctrl_kernel_mode_show() to list supported
kernel modes and show the current one in brackets.

Patch 4: Add x86 PLZA support and boot option rdt=plza.

Patch 5: Add supported modes from CPUID.

Patch 6: Add rdt_kmode_enable_key and arch enable/disable helpers so PLZA only
touches fast paths when enabled.

Patch 7: Add MSR_IA32_PQR_PLZA_ASSOC, bit defines, and union qos_pqr_plza_assoc
for programming PLZA.

Patch 8: Add Per-CPU and per-task state.

Patch 9: Add resctrl_arch_configure_kmode() and resctrl_arch_set_kmode()
to program PLZA per domain and set/clear it on a CPU.

Patch 10: In the sched-in path, program MSR_IA32_PQR_PLZA_ASSOC from task or
per-CPU kmode; only write when kmode changes; guard with rdt_kmode_enable_key.

Patch 11: Add write handler so the current kernel mode can be set by name.

Patch 12: Add info/kernel_mode_assignment and show which rdtgroup is assigned
for kernel mode in CTRL_MON/MON/ form.

Patch 13: Add write handler to assign/clear the group used for kernel mode;
enforce single assignment and clear on rmdir.

Patch 14: Update per-CPU PLZA state when its cpu_mask changes (add/remove CPUs)
via cpus_write_kmode() and helpers.

Patch 15: Refactor so task list respects t->kmode when the group has kmode (PLZA),
so tasks are shown correctly.

v2: https://lore.kernel.org/lkml/[email protected]/
v1: https://lore.kernel.org/lkml/[email protected]/

Babu Moger (12):
x86/resctrl: Support Privilege-Level Zero Association (PLZA) x86/resctrl: Add data structures and definitions for PLZA configuration fs/resctrl: Add kernel mode (kmode) data structures and arch hook x86,fs/resctrl: Program PLZA through kmode arch hooks x86/resctrl: Initialize supported kernel modes for PLZA fs/resctrl: Initialize the global kernel-mode policy at subsystem init fs/resctrl: Add info/kernel_mode for kernel-mode policy introspection fs/resctrl: Make info/kernel_mode writable and identify the bound group fs/resctrl: Reset kernel-mode binding when its rdtgroup goes away fs/resctrl: Expose kmode_cpus / kmode_cpus_list per rdtgroup
resctrl: Hide kmode_cpus[_list] on groups not bound to kernel-mode fs/resctrl: Allow user space to write kmode_cpus / kmode_cpus_list

 Documentation/filesystems/resctrl.rst        |  ...
 arch/x86/kernel/cpu/resctrl/...              |  ...
 fs/resctrl/...                               |  ...
 include/linux/resctrl.h                      |  ...
 include/linux/resctrl_types.h                |  ...

N files changed, X insertions(+), Y deletions(-)

Signature · 34 lines
2.43.0

Babu Moger (12):
  x86/resctrl: Support Privilege-Level Zero Association (PLZA)
  x86/resctrl: Add data structures and definitions for PLZA
    configuration
  fs/resctrl: Add kernel mode (kmode) data structures and arch hook
  x86,fs/resctrl: Program PLZA through kmode arch hooks
  x86/resctrl: Initialize supported kernel modes for PLZA
  fs/resctrl: Initialize the global kernel-mode policy at subsystem init
  fs/resctrl: Add info/kernel_mode for kernel-mode policy introspection
  fs/resctrl: Make info/kernel_mode writable and identify the bound
    group
  fs/resctrl: Reset kernel-mode binding when its rdtgroup goes away
  fs/resctrl: Expose kmode_cpus / kmode_cpus_list per rdtgroup
  resctrl: Hide kmode_cpus[_list] on groups not bound to kernel-mode
  fs/resctrl: Allow user space to write kmode_cpus / kmode_cpus_list

 .../admin-guide/kernel-parameters.txt         |   2 +-
 Documentation/filesystems/resctrl.rst         |  84 ++
 arch/x86/include/asm/cpufeatures.h            |   1 +
 arch/x86/include/asm/msr-index.h              |   7 +
 arch/x86/kernel/cpu/resctrl/core.c            |  17 +
 arch/x86/kernel/cpu/resctrl/ctrlmondata.c     |  35 +
 arch/x86/kernel/cpu/resctrl/internal.h        |  27 +
 arch/x86/kernel/cpu/scattered.c               |   1 +
 fs/resctrl/internal.h                         |   6 +
 fs/resctrl/rdtgroup.c                         | 784 ++++++++++++++++++
 include/linux/resctrl.h                       |  23 +
 include/linux/resctrl_types.h                 |  46 +
 12 files changed, 1032 insertions(+), 1 deletion(-)

-- 
2.43.0
author reviewer
#1 lore raw

PATCH v3 1/12 x86/resctrl: Support Privilege-Level Zero Association (PLZA)

Customers have identified an issue while using the QoS resource Control feature. If a memory bandwidth associated with a CLOSID is aggressively throttled, and it moves into Kernel mode, the Kernel operations are also aggressively throttled. This can stall forward progress and eventually degrade overall system performance. AMD hardware supports a feature Privilege-Level Zero Association (PLZA) to change the association of the thread as soon as it begins executing.

Privilege-Level Zero Association (PLZA) allows the user to specify a CLOSID and/or RMID associated with execution in Privilege-Level Zero. When enabled on a HW thread, when the thread enters Privilege-Level Zero, transactions associated with that thread will be associated with the PLZA CLOSID and/or RMID. Otherwise, the HW thread will be associated with the CLOSID and RMID identified by PQR_ASSOC.

Add PLZA support to resctrl and introduce a kernel parameter that allows enabling or disabling the feature at boot time.

The GLBE feature details are documented in:

AMD64 Zen6 Platform Quality of Service (PQOS) Extensions:
Publication # 69193 Revision: 1.00, Issue Date: March 2026

available at https://bugzilla.kernel.org/show_bug.cgi?id=206537

---
v3: Code did not change. Patch order cahnged.
Added documentation link.

v2: Rebased on top of the latest tip.

---
 Documentation/admin-guide/kernel-parameters.txt | 2 +-
 arch/x86/include/asm/cpufeatures.h              | 1 +
 arch/x86/kernel/cpu/resctrl/core.c              | 2 ++
 arch/x86/kernel/cpu/scattered.c                 | 1 +
 4 files changed, 5 insertions(+), 1 deletion(-)
Documentation/admin-guide/kernel-parameters.txt +1 -1
index f2ce1f4975c1..3021c920f3e1 100644
@@ -6463,7 +6463,7 @@ Kernel parameters
 	rdt=		[HW,X86,RDT]
 			Turn on/off individual RDT features. List is:
 			cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, l2cdp,
-			mba, smba, bmec, abmc, sdciae, energy[:guid],
+			mba, smba, bmec, abmc, sdciae, plza, energy[:guid],
 			perf[:guid].
 			E.g. to turn on cmt and turn off mba use:
 				rdt=cmt,!mba
arch/x86/include/asm/cpufeatures.h +1 -0
index 86d17b195e79..5739281bd4c7 100644
@@ -515,6 +515,7 @@
 						      * and purposes if CLEAR_CPU_BUF_VM is set).
 						      */
 #define X86_FEATURE_X2AVIC_EXT		(21*32+20) /* AMD SVM x2AVIC support for 4k vCPUs */
+#define X86_FEATURE_PLZA		(21*32+21) /* Privilege-Level Zero Association */
 
 /*
  * BUG word(s)
arch/x86/kernel/cpu/resctrl/core.c +2 -0
index 7667cf7c4e94..4a8717157e3e 100644
@@ -799,6 +799,7 @@ enum {
 	RDT_FLAG_BMEC,
 	RDT_FLAG_ABMC,
 	RDT_FLAG_SDCIAE,
+	RDT_FLAG_PLZA,
 };
 
 #define RDT_OPT(idx, n, f)	\
@@ -826,6 +827,7 @@ static struct rdt_options rdt_options[]  __ro_after_init = {
 	RDT_OPT(RDT_FLAG_BMEC,	    "bmec",	X86_FEATURE_BMEC),
 	RDT_OPT(RDT_FLAG_ABMC,	    "abmc",	X86_FEATURE_ABMC),
 	RDT_OPT(RDT_FLAG_SDCIAE,    "sdciae",	X86_FEATURE_SDCIAE),
+	RDT_OPT(RDT_FLAG_PLZA,	    "plza",	X86_FEATURE_PLZA),
 };
 #define NUM_RDT_OPTIONS ARRAY_SIZE(rdt_options)
 
arch/x86/kernel/cpu/scattered.c +1 -0
index 837d6a4b0c28..630afb233194 100644
@@ -60,6 +60,7 @@ static const struct cpuid_bit cpuid_bits[] = {
 	{ X86_FEATURE_BMEC,			CPUID_EBX,  3, 0x80000020, 0 },
 	{ X86_FEATURE_ABMC,			CPUID_EBX,  5, 0x80000020, 0 },
 	{ X86_FEATURE_SDCIAE,			CPUID_EBX,  6, 0x80000020, 0 },
+	{ X86_FEATURE_PLZA,			CPUID_EBX,  9, 0x80000020, 0 },
 	{ X86_FEATURE_TSA_SQ_NO,		CPUID_ECX,  1, 0x80000021, 0 },
 	{ X86_FEATURE_TSA_L1_NO,		CPUID_ECX,  2, 0x80000021, 0 },
 	{ X86_FEATURE_AMD_WORKLOAD_CLASS,	CPUID_EAX, 22, 0x80000021, 0 },
Signature · 1 line
2.43.0
maintainer
#2 lore raw

Re: [PATCH v3 01/12] x86/resctrl: Support Privilege-Level Zero Association (PLZA)

Hi Babu,

Quoted 1 line · Babu Moger

Customers have identified an issue while using the QoS resource Control

"Control" -> "control"?

Quoted 1 line

feature. If a memory bandwidth associated with a CLOSID is aggressively

"a memory bandwidth" -> "memory bandwidth"?

Quoted 1 line

throttled, and it moves into Kernel mode, the Kernel operations are also

What does "it" refer to here? From text it seems to be the "CLOSID" but that does not sound right? Should "it" instead be something like "a task with that CLOSID"?

"Kernel" -> "kernel"?

Quoted 4 lines

aggressively throttled. This can stall forward progress and eventually degrade overall system performance. AMD hardware supports a feature Privilege-Level Zero Association (PLZA) to change the association of the thread as soon as it begins executing.

"change the association of the thread as soon as it begins executing." I am not able to parse this.

Quoted 4 lines

Privilege-Level Zero Association (PLZA) allows the user to specify a CLOSID and/or RMID associated with execution in Privilege-Level Zero. When enabled on a HW thread, when the thread enters Privilege-Level Zero, transactions

Could you please use consistent terminology throughout this series? This patch uses "HW thread"/"thread", the next patch then switches to "logical processor", and then by patch #4 the term seems to settle on "CPU". Could this just be "CPU" from here and throughout series to be consistent and easier to read?

What is meant with "transactions"? Is this just about memory transactions? Using this term combined with earlier "memory bandwidth" related problem description hints that this feature just impacts memory bandwidth allocation but from what I understand this impacts all allocation (CLOSID of all resources) and monitoring.

Could "transactions" be replaced with "allocation and monitoring" and be more accurate?

Quoted 8 lines

associated with that thread will be associated with the PLZA CLOSID and/or RMID. Otherwise, the HW thread will be associated with the CLOSID and RMID identified by PQR_ASSOC.

Add PLZA support to resctrl and introduce a kernel parameter that allows enabling or disabling the feature at boot time.

The GLBE feature details are documented in:

"GLBE" -> "PLZA"?

Quoted 5 lines

AMD64 Zen6 Platform Quality of Service (PQOS) Extensions:
Publication # 69193 Revision: 1.00, Issue Date: March 2026

available at https://bugzilla.kernel.org/show_bug.cgi?id=206537

Please follow same style as what you used in the assignable counter enabling where this URL is provided via a "Link:" tag and then the text can refer to it. Specifically,

	Link: https://bugzilla.kernel.org/show_bug.cgi?id=206537 # [1]
Quoted 6 lines

---
v3: Code did not change. Patch order cahnged.
Added documentation link.

Quoted 6 lines

v2: Rebased on top of the latest tip.

---
 Documentation/admin-guide/kernel-parameters.txt | 2 +-
 arch/x86/include/asm/cpufeatures.h              | 1 +
 arch/x86/kernel/cpu/resctrl/core.c              | 2 ++
 arch/x86/kernel/cpu/scattered.c                 | 1 +

Please split changes to other subsystems and make these changes obvious with their own subject prefix to avoid sneaking changes into other subsystems via resctrl.

Reinette

#3 lore raw

Re: [PATCH v3 01/12] x86/resctrl: Support Privilege-Level Zero Association (PLZA)

Hi Reinette,

Quoted 7 lines · Reinette Chatre

Hi Babu,

Quoted 1 line · Babu Moger

Customers have identified an issue while using the QoS resource Control

"Control" -> "control"?

ack

Quoted 3 lines
Quoted 1 line

feature. If a memory bandwidth associated with a CLOSID is aggressively

"a memory bandwidth" -> "memory bandwidth"?

ack.

Quoted 6 lines
Quoted 2 lines

throttled, and it moves into Kernel mode, the Kernel operations are also

What does "it" refer to here? From text it seems to be the "CLOSID" but that does not sound right? Should "it" instead be something like "a task with that CLOSID"?

sure.

Quoted 2 lines

"Kernel" -> "kernel"?

ack.

Quoted 8 lines
Quoted 5 lines

aggressively throttled. This can stall forward progress and eventually degrade overall system performance. AMD hardware supports a feature Privilege-Level Zero Association (PLZA) to change the association of the thread as soon as it begins executing.

"change the association of the thread as soon as it begins executing." I am not able to parse this.

How about ?

Customers have identified an issue while using the QoS resource Control
feature. If memory bandwidth associated with a CLOSID is aggressively
throttled, and a task with that CLOSID moves into kernel mode, the kernel operations are also aggressively throttled. This can stall forward progress and eventually degrade overall system performance. AMD hardware supports a feature Privilege-Level Zero Association (PLZA)
to change the CPU association at the user-to-kernel transition, so the kernel execution can use a different association than user mode.

Privilege-Level Zero Association (PLZA) allows the user to specify a CLOSID and/or RMID associated with execution in Privilege-Level Zero. When enabled on a CPU, as the CPU enters Privilege-Level Zero, allocation and monitoring for that CPU will be associated with the PLZA CLOSID and/or RMID. Otherwise, the CPU will be associated with the CLOSID and RMID given by PQR_ASSOC.

Quoted 22 lines
Quoted 4 lines

Privilege-Level Zero Association (PLZA) allows the user to specify a CLOSID and/or RMID associated with execution in Privilege-Level Zero. When enabled on a HW thread, when the thread enters Privilege-Level Zero, transactions

Could you please use consistent terminology throughout this series? This patch uses "HW thread"/"thread", the next patch then switches to "logical processor", and then by patch #4 the term seems to settle on "CPU". Could this just be "CPU" from here and throughout series to be consistent and easier to read?

What is meant with "transactions"? Is this just about memory transactions? Using this term combined with earlier "memory bandwidth" related problem description hints that this feature just impacts memory bandwidth allocation but from what I understand this impacts all allocation (CLOSID of all resources) and monitoring.

Could "transactions" be replaced with "allocation and monitoring" and be more accurate?

Quoted 4 lines

associated with that thread will be associated with the PLZA CLOSID and/or RMID. Otherwise, the HW thread will be associated with the CLOSID and RMID identified by PQR_ASSOC.

Quoted 7 lines
Quoted 4 lines

Add PLZA support to resctrl and introduce a kernel parameter that allows enabling or disabling the feature at boot time.

The GLBE feature details are documented in:

"GLBE" -> "PLZA"?

ack.

Quoted 10 lines
Quoted 5 lines

AMD64 Zen6 Platform Quality of Service (PQOS) Extensions:

   Publication # 69193 Revision: 1.00, Issue Date: March 2026

available at https://bugzilla.kernel.org/show_bug.cgi?id=206537

Please follow same style as what you used in the assignable counter enabling where this URL is provided via a "Link:" tag and then the text can refer to it. Specifically,

	Link: https://bugzilla.kernel.org/show_bug.cgi?id=206537 # [1]

Sure.

Quoted 13 lines
Quoted 6 lines

---
v3: Code did not change. Patch order cahnged.
Added documentation link.

Quoted 6 lines

v2: Rebased on top of the latest tip.

---
  Documentation/admin-guide/kernel-parameters.txt | 2 +-
  arch/x86/include/asm/cpufeatures.h              | 1 +
  arch/x86/kernel/cpu/resctrl/core.c              | 2 ++
  arch/x86/kernel/cpu/scattered.c                 | 1 +
Quoted 4 lines

Please split changes to other subsystems and make these changes obvious with their own subject prefix to avoid sneaking changes into other subsystems via resctrl.

Ok. Will be two patches.
1. For Documentation/admin-guide/kernel-parameters.txt
2. arch/x86/include/asm/cpufeatures.h arch/x86/kernel/cpu/resctrl/core.c arch/x86/kernel/cpu/scattered.c

thanks
Babu

#4 lore raw

Re: [PATCH v3 01/12] x86/resctrl: Support Privilege-Level Zero Association (PLZA)

Hi Reinette,

Missed typo again.

Quoted 38 lines · Babu

Hi Reinette,

Quoted 7 lines · Reinette Chatre

Hi Babu,

Quoted 1 line · Babu Moger

Customers have identified an issue while using the QoS resource Control

"Control" -> "control"?

ack

Quoted 3 lines
Quoted 1 line

feature. If a memory bandwidth associated with a CLOSID is aggressively

"a memory bandwidth" -> "memory bandwidth"?

ack.

Quoted 6 lines
Quoted 2 lines

throttled, and it moves into Kernel mode, the Kernel operations are also

What does "it" refer to here? From text it seems to be the "CLOSID" but that does not sound right? Should "it" instead be something like "a task with that CLOSID"?

sure.

Quoted 2 lines

"Kernel" -> "kernel"?

ack.

Quoted 6 lines
Quoted 5 lines

aggressively throttled. This can stall forward progress and eventually degrade overall system performance. AMD hardware supports a feature Privilege-Level Zero Association (PLZA) to change the association of the thread as soon as it begins executing.

Quoted 6 lines
Quoted 2 lines

"change the association of the thread as soon as it begins executing." I am not able to parse this.

How about ?

Customers have identified an issue while using the QoS resource Control

Control > control

Thanks

Babu

maintainer
#5 lore raw

Re: [PATCH v3 01/12] x86/resctrl: Support Privilege-Level Zero Association (PLZA)

In reply to Moger, Babu

Hi Babu,

Quoted 41 lines · Babu

Hi Reinette,

Quoted 7 lines · Reinette Chatre

Hi Babu,

Quoted 1 line · Babu Moger

Customers have identified an issue while using the QoS resource Control

"Control" -> "control"?

ack

Quoted 3 lines
Quoted 1 line

feature. If a memory bandwidth associated with a CLOSID is aggressively

"a memory bandwidth" -> "memory bandwidth"?

ack.

Quoted 6 lines
Quoted 2 lines

throttled, and it moves into Kernel mode, the Kernel operations are also

What does "it" refer to here? From text it seems to be the "CLOSID" but that does not sound right? Should "it" instead be something like "a task with that CLOSID"?

sure.

Quoted 2 lines

"Kernel" -> "kernel"?

ack.

Quoted 8 lines
Quoted 5 lines

aggressively throttled. This can stall forward progress and eventually degrade overall system performance. AMD hardware supports a feature Privilege-Level Zero Association (PLZA) to change the association of the thread as soon as it begins executing.

"change the association of the thread as soon as it begins executing." I am not able to parse this.

Quoted 7 lines

How about ?

Customers have identified an issue while using the QoS resource Control
feature. If memory bandwidth associated with a CLOSID is aggressively
throttled, and a task with that CLOSID moves into kernel mode, the kernel operations are also aggressively throttled. This can stall forward progress and eventually degrade overall system performance. AMD hardware supports a feature Privilege-Level Zero Association (PLZA)
to change the CPU association at the user-to-kernel transition, so the kernel execution can use a different association than user mode.

"change the CPU association at the user-to-kernel transition" -> What is this trying to describe? CPU association of what?

"a different association"? What does this mean?

Quoted 6 lines

Privilege-Level Zero Association (PLZA) allows the user to specify a> CLOSID and/or RMID associated with execution in Privilege-Level Zero. When enabled on a CPU, as the CPU enters Privilege-Level Zero,
allocation and monitoring for that CPU will be associated with the
PLZA CLOSID and/or RMID. Otherwise, the CPU will be associated with
the CLOSID and RMID given by PQR_ASSOC.

Sounds like this is vague because MSR_IA32_PQR_PLZA_ASSOC has not been introduced yet. Could it help to introduce MSR_IA32_PQR_PLZA_ASSOC as part of this patch and then the changelog can be specific about PLZA feature introducing this new MSR and how it complements MSR_IA32_PQR_ASSOC?

...

Quoted 10 lines
Quoted 9 lines
Quoted 4 lines

  Documentation/admin-guide/kernel-parameters.txt | 2 +- arch/x86/include/asm/cpufeatures.h              | 1 + arch/x86/kernel/cpu/resctrl/core.c              | 2 ++ arch/x86/kernel/cpu/scattered.c                 | 1 +

Please split changes to other subsystems and make these changes obvious with their own subject prefix to avoid sneaking changes into other subsystems via resctrl.

Quoted 5 lines

Ok. Will be two patches.
1. For Documentation/admin-guide/kernel-parameters.txt 2.  arch/x86/include/asm/cpufeatures.h arch/x86/kernel/cpu/resctrl/core.c arch/x86/kernel/cpu/scattered.c

The resctrl changes found in (2) would be documented in (1)? That does not look right. Why not just split the resctrl changes from the cpufeatures changes? This would be similar to how you did ABMC enabling.

Reinette

author reviewer
#6 lore raw

Re: [PATCH v3 01/12] x86/resctrl: Support Privilege-Level Zero Association (PLZA)

Hi Reinette,

Quoted 52 lines · Reinette Chatre

Hi Babu,

Quoted 41 lines · Babu

Hi Reinette,

Quoted 7 lines · Reinette Chatre

Hi Babu,

Quoted 1 line · Babu Moger

Customers have identified an issue while using the QoS resource Control

"Control" -> "control"?

ack

Quoted 3 lines
Quoted 1 line

feature. If a memory bandwidth associated with a CLOSID is aggressively

"a memory bandwidth" -> "memory bandwidth"?

ack.

Quoted 6 lines
Quoted 2 lines

throttled, and it moves into Kernel mode, the Kernel operations are also

What does "it" refer to here? From text it seems to be the "CLOSID" but that does not sound right? Should "it" instead be something like "a task with that CLOSID"?

sure.

Quoted 2 lines

"Kernel" -> "kernel"?

ack.

Quoted 8 lines
Quoted 5 lines

aggressively throttled. This can stall forward progress and eventually degrade overall system performance. AMD hardware supports a feature Privilege-Level Zero Association (PLZA) to change the association of the thread as soon as it begins executing.

"change the association of the thread as soon as it begins executing." I am not able to parse this.

Quoted 7 lines

How about ?

Customers have identified an issue while using the QoS resource Control
feature. If memory bandwidth associated with a CLOSID is aggressively
throttled, and a task with that CLOSID moves into kernel mode, the kernel operations are also aggressively throttled. This can stall forward progress and eventually degrade overall system performance. AMD hardware supports a feature Privilege-Level Zero Association (PLZA)
to change the CPU association at the user-to-kernel transition, so the kernel execution can use a different association than user mode.

Quoted 5 lines

"change the CPU association at the user-to-kernel transition" -> What is this trying to describe? CPU association of what?

"a different association"? What does this mean?

Will change it to:

AMD hardware supports a feature Privilege-Level Zero Association (PLZA),
which allows the CPU’s CLOSID association to be changed during the transition from user mode to kernel mode. This enables the kernel to operate with a different CLOSID than the user mode.

Quoted 8 lines
Quoted 6 lines

Privilege-Level Zero Association (PLZA) allows the user to specify a> CLOSID and/or RMID associated with execution in Privilege-Level Zero. When enabled on a CPU, as the CPU enters Privilege-Level Zero,
allocation and monitoring for that CPU will be associated with the
PLZA CLOSID and/or RMID. Otherwise, the CPU will be associated with
the CLOSID and RMID given by PQR_ASSOC.

Quoted 4 lines

Sounds like this is vague because MSR_IA32_PQR_PLZA_ASSOC has not been introduced yet. Could it help to introduce MSR_IA32_PQR_PLZA_ASSOC as part of this patch and then the changelog can be specific about PLZA feature introducing this new MSR and how it complements MSR_IA32_PQR_ASSOC?

Its probably better to remove the second paragraph. This text can go with the patch which introduces MSR_IA32_PQR_PLZA_ASSOC.

With splitting the patch, this will only have cpufeatures changes.

Quoted 19 lines

...

Quoted 10 lines
Quoted 9 lines
Quoted 4 lines
   Documentation/admin-guide/kernel-parameters.txt | 2 +-
   arch/x86/include/asm/cpufeatures.h              | 1 +
   arch/x86/kernel/cpu/resctrl/core.c              | 2 ++
   arch/x86/kernel/cpu/scattered.c                 | 1 +

Please split changes to other subsystems and make these changes obvious with their own subject prefix to avoid sneaking changes into other subsystems via resctrl.

Quoted 5 lines

Ok. Will be two patches.
1. For Documentation/admin-guide/kernel-parameters.txt 2.  arch/x86/include/asm/cpufeatures.h arch/x86/kernel/cpu/resctrl/core.c arch/x86/kernel/cpu/scattered.c

Quoted 4 lines

The resctrl changes found in (2) would be documented in (1)? That does not look right. Why not just split the resctrl changes from the cpufeatures changes? This would be similar to how you did ABMC enabling.

Sounds good.

Thanks
Babu

author reviewer
#7 lore raw

PATCH v3 2/12 x86/resctrl: Add data structures and definitions for PLZA configuration

In reply to Babu Moger

Privilege Level Zero Association (PLZA) is configured per logical processor via MSR_IA32_PQR_PLZA_ASSOC (0xc00003fc). Software must program RMID and CLOSID association fields and their enable bits using the layout defined for the MSR.

Define MSR_IA32_PQR_PLZA_ASSOC and the RMID_EN, CLOSID_EN, and PLZA_EN bit masks in asm/msr-index.h. Add union msr_pqr_plza_assoc in arch resctrl internal.h

---
v3: No code changes. Patch order cahnged. Improved changelog.

v2: No changes. Just rebasing on top of the latest tip branch.

---
 arch/x86/include/asm/msr-index.h       |  7 +++++++
 arch/x86/kernel/cpu/resctrl/internal.h | 27 ++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)
arch/x86/include/asm/msr-index.h +7 -0
index 9dc6b610e4e2..623628d3c643 100644
@@ -1287,10 +1287,17 @@
 /* - AMD: */
 #define MSR_IA32_MBA_BW_BASE		0xc0000200
 #define MSR_IA32_SMBA_BW_BASE		0xc0000280
+#define MSR_IA32_PQR_PLZA_ASSOC		0xc00003fc
 #define MSR_IA32_L3_QOS_ABMC_CFG	0xc00003fd
 #define MSR_IA32_L3_QOS_EXT_CFG		0xc00003ff
 #define MSR_IA32_EVT_CFG_BASE		0xc0000400
 
+/* Lower 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define RMID_EN				BIT(31)
+/* Upper 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define CLOSID_EN			BIT(15)
+#define PLZA_EN				BIT(31)
+
 /* AMD-V MSRs */
 #define MSR_VM_CR                       0xc0010114
 #define MSR_VM_IGNNE                    0xc0010115
arch/x86/kernel/cpu/resctrl/internal.h +27 -0
index e3cfa0c10e92..1c2f87ffb0ea 100644
@@ -222,6 +222,33 @@ union l3_qos_abmc_cfg {
 	unsigned long full;
 };
 
+/*
+ * PLZA is programmed by writing to MSR_IA32_PQR_PLZA_ASSOC. Bitfield
+ * layout for MSR_IA32_PQR_PLZA_ASSOC (Privilege Level Zero Association).
+ *
+ * @rmid		: The RMID to be configured for PLZA.
+ * @reserved1		: Reserved.
+ * @rmid_en		: Associate RMID or not.
+ * @closid		: The CLOSID to be configured for PLZA.
+ * @reserved2		: Reserved.
+ * @closid_en		: Associate CLOSID or not.
+ * @reserved3		: Reserved.
+ * @plza_en		: Configure PLZA or not.
+ */
+union msr_pqr_plza_assoc {
+	struct {
+		unsigned long rmid	:12,
+			      reserved1	:19,
+			      rmid_en	: 1,
+			      closid	: 4,
+			      reserved2	:11,
+			      closid_en	: 1,
+			      reserved3	:15,
+			      plza_en	: 1;
+	} split;
+	unsigned long full;
+};
+
 void rdt_ctrl_update(void *arg);
 
 int rdt_get_l3_mon_config(struct rdt_resource *r);
Signature · 1 line
2.43.0
maintainer
#8 lore raw

Re: [PATCH v3 02/12] x86/resctrl: Add data structures and definitions for PLZA configuration

Hi Babu,

Quoted 8 lines · Babu Moger

Privilege Level Zero Association (PLZA) is configured per logical processor via MSR_IA32_PQR_PLZA_ASSOC (0xc00003fc). Software must program RMID and CLOSID association fields and their enable bits using the layout defined for the MSR.

Define MSR_IA32_PQR_PLZA_ASSOC and the RMID_EN, CLOSID_EN, and PLZA_EN bit masks in asm/msr-index.h. Add union msr_pqr_plza_assoc in arch resctrl internal.h

Above paragraph captures what can be seen from the patch. Please check entire series for this since many changelogs in this series verbatim describes the code changes in patch without helping reader understand why those changes are made.

Quoted 13 lines

---

arch/x86/include/asm/msr-index.h +1 -0
index 9dc6b610e4e2..623628d3c643 100644
@@ -1287,10 +1287,17 @@
 /* - AMD: */
 #define MSR_IA32_MBA_BW_BASE		0xc0000200
 #define MSR_IA32_SMBA_BW_BASE		0xc0000280
+#define MSR_IA32_PQR_PLZA_ASSOC		0xc00003fc

arch/x86/include/asm/msr-index.h line 1300

Quoted 10 lines
arch/x86/include/asm/msr-index.h +6 -0
 #define MSR_IA32_L3_QOS_ABMC_CFG	0xc00003fd
 #define MSR_IA32_L3_QOS_EXT_CFG		0xc00003ff
 #define MSR_IA32_EVT_CFG_BASE		0xc0000400
 
+/* Lower 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define RMID_EN				BIT(31)
+/* Upper 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define CLOSID_EN			BIT(15)
+#define PLZA_EN				BIT(31)
+

This is unexpected. So far resctrl has only defined the MSR numbers in this file, not the individual fields. This seems a legitimate use of msr-index.h but creates inconsistency with how the fields of the other resctrl registers are defined. This may be ok so I am looking past this for now. Since I am not familiar with this use I am looking at other patterns of this and it seems that the register fields are usually defined right after the register to make this relationship clear and also use more verbose naming to establish this relationship ... I do not think such cryptic names should be used without context in such a global scope. Please compare with how other fields are defined at this scope.

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 227

Quoted 11 lines
arch/x86/kernel/cpu/resctrl/internal.h +3 -0
index e3cfa0c10e92..1c2f87ffb0ea 100644
@@ -222,6 +222,33 @@ union l3_qos_abmc_cfg {
 	unsigned long full;
 };
 
+/*
+ * PLZA is programmed by writing to MSR_IA32_PQR_PLZA_ASSOC. Bitfield
+ * layout for MSR_IA32_PQR_PLZA_ASSOC (Privilege Level Zero Association).

These comments are valuable to describe how resctrl should interact with this register so it would help to be specific and document any and all constraints.

For example, I seem to remember that all fields except PLZA_EN are required to be identical on all CPUs. Please document that and any other constraints here.

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 229

Quoted 2 lines
arch/x86/kernel/cpu/resctrl/internal.h +2 -0
+ *
+ * @rmid		: The RMID to be configured for PLZA.

What does "to be configured" mean? It seems to imply that when resctrl writes to @rmid then the setting does not take immediate effect but would take effect at some future "configure" time?

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 231

Quoted 2 lines
arch/x86/kernel/cpu/resctrl/internal.h +2 -0
+ * @reserved1		: Reserved.
+ * @rmid_en		: Associate RMID or not.

Please elaborate ... what is RMID associated with? What does "or not" imply? Here it will help to document relationship with MSR_IA32_PQR_ASSOC.

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 234

Quoted 3 lines
arch/x86/kernel/cpu/resctrl/internal.h +3 -0
+ * @closid		: The CLOSID to be configured for PLZA.
+ * @reserved2		: Reserved.
+ * @closid_en		: Associate CLOSID or not.

Same comments as for RMID

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 236

Quoted 2 lines
arch/x86/kernel/cpu/resctrl/internal.h +2 -0
+ * @reserved3		: Reserved.
+ * @plza_en		: Configure PLZA or not.

plza_en implies "enable" but the comment mentions "configure". Considering the other fields are "to be configured" there seems to be relationship but that is not documented at all. For example, if @plza_en is 1 and resctrl modifies @rmid should resctrl write "1" to @plza_en again to "configure" the new RMID?

Please add specific detail to help understand how best to interact with this register.

Quoted 8 lines
arch/x86/kernel/cpu/resctrl/internal.h +8 -0
+ */
+union msr_pqr_plza_assoc {
+	struct {
+		unsigned long rmid	:12,
+			      reserved1	:19,
+			      rmid_en	: 1,
+			      closid	: 4,
+			      reserved2	:11,

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 254

Quoted 10 lines
arch/x86/kernel/cpu/resctrl/internal.h +7 -0
+			      closid_en	: 1,
+			      reserved3	:15,
+			      plza_en	: 1;
+	} split;
+	unsigned long full;
+};
+
 void rdt_ctrl_update(void *arg);
 
 int rdt_get_l3_mon_config(struct rdt_resource *r);

Reinette

maintainer
#9 lore raw

RE: [PATCH v3 02/12] x86/resctrl: Add data structures and definitions for PLZA configuration

Quoted 13 lines
Quoted 13 lines
arch/x86/include/asm/msr-index.h +1 -0
index 9dc6b610e4e2..623628d3c643 100644
@@ -1287,10 +1287,17 @@
 /* - AMD: */
 #define MSR_IA32_MBA_BW_BASE               0xc0000200
 #define MSR_IA32_SMBA_BW_BASE              0xc0000280
+#define MSR_IA32_PQR_PLZA_ASSOC            0xc00003fc
 #define MSR_IA32_L3_QOS_ABMC_CFG   0xc00003fd
 #define MSR_IA32_L3_QOS_EXT_CFG            0xc00003ff
 #define MSR_IA32_EVT_CFG_BASE              0xc0000400
 
Quoted 15 lines

arch/x86/include/asm/msr-index.h line 1300

Quoted 6 lines
arch/x86/include/asm/msr-index.h +6 -0
+/* Lower 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define RMID_EN                            BIT(31)
+/* Upper 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define CLOSID_EN                  BIT(15)
+#define PLZA_EN                            BIT(31)
+

This is unexpected. So far resctrl has only defined the MSR numbers in this file, not the individual fields. This seems a legitimate use of msr-index.h but creates inconsistency with how the fields of the other resctrl registers are defined. This may be ok so I am looking past this for now. Since I am not familiar with this use I am looking at other patterns of this and it seems that the register fields are usually defined right after the register to make this relationship clear and also use more verbose naming to establish this relationship ... I do not think such cryptic names should be used without context in such a global scope. Please compare with how other fields are defined at this scope.

There's also patches in flight to treat MSRs as a single "u64" and move away from the low level implementation detail that the RDMSR/WRMSR instructions split into upper/lower halves.

All the kernel interfaces are moving to rdmsrq() and wrmsrq() (together with related functions).

So maybe:

#define PQR_PLZA_RMID_EN        BIT_ULL(31)
#define PQR_PLZA_CLOSID_EN      BIT_ULL(47)
#define PQR_PLZA_PLZA_EN        BIT_ULL(63)

[modify with whatever addition prefix characters seem necessary]

-Tony

#10 lore raw

Re: RE: [PATCH v3 02/12] x86/resctrl: Add data structures and definitions for PLZA configuration

Hi Tony,

Quoted 29 lines · Tony
Quoted 13 lines
Quoted 13 lines
arch/x86/include/asm/msr-index.h +1 -0
index 9dc6b610e4e2..623628d3c643 100644
@@ -1287,10 +1287,17 @@
  /* - AMD: */
  #define MSR_IA32_MBA_BW_BASE               0xc0000200
  #define MSR_IA32_SMBA_BW_BASE              0xc0000280
+#define MSR_IA32_PQR_PLZA_ASSOC            0xc00003fc
  #define MSR_IA32_L3_QOS_ABMC_CFG   0xc00003fd
  #define MSR_IA32_L3_QOS_EXT_CFG            0xc00003ff
  #define MSR_IA32_EVT_CFG_BASE              0xc0000400
 
Quoted 15 lines

arch/x86/include/asm/msr-index.h line 1300

Quoted 6 lines
arch/x86/include/asm/msr-index.h +6 -0
+/* Lower 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define RMID_EN                            BIT(31)
+/* Upper 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define CLOSID_EN                  BIT(15)
+#define PLZA_EN                            BIT(31)
+

This is unexpected. So far resctrl has only defined the MSR numbers in this file, not the individual fields. This seems a legitimate use of msr-index.h but creates inconsistency with how the fields of the other resctrl registers are defined. This may be ok so I am looking past this for now. Since I am not familiar with this use I am looking at other patterns of this and it seems that the register fields are usually defined right after the register to make this relationship clear and also use more verbose naming to establish this relationship ... I do not think such cryptic names should be used without context in such a global scope. Please compare with how other fields are defined at this scope.

Quoted 6 lines

There's also patches in flight to treat MSRs as a single "u64" and move away from the low level implementation detail that the RDMSR/WRMSR instructions split into upper/lower halves.

All the kernel interfaces are moving to rdmsrq() and wrmsrq() (together with related functions).

Ack.

Quoted 9 lines

So maybe:

#define PQR_PLZA_RMID_EN        BIT_ULL(31)
#define PQR_PLZA_CLOSID_EN      BIT_ULL(47)
#define PQR_PLZA_PLZA_EN        BIT_ULL(63)

[modify with whatever addition prefix characters seem necessary]

Actually, I don’t need these changes anymore—they were carried over from a previous version. Thanks for making the updates, though.

Thanks
Babu

#11 lore raw

Re: [PATCH v3 02/12] x86/resctrl: Add data structures and definitions for PLZA configuration

In reply to Reinette Chatre

Hi Reinette,

Quoted 8 lines · Reinette Chatre

Hi Babu,

Quoted 5 lines · Babu Moger

Privilege Level Zero Association (PLZA) is configured per logical processor via MSR_IA32_PQR_PLZA_ASSOC (0xc00003fc). Software must program RMID and CLOSID association fields and their enable bits using the layout defined for the MSR.

Quoted 8 lines
Quoted 3 lines

Define MSR_IA32_PQR_PLZA_ASSOC and the RMID_EN, CLOSID_EN, and PLZA_EN bit masks in asm/msr-index.h. Add union msr_pqr_plza_assoc in arch resctrl internal.h

Above paragraph captures what can be seen from the patch. Please check entire series for this since many changelogs in this series verbatim describes the code changes in patch without helping reader understand why those changes are made.

Sure. Will rewrite the changelog. And will check other patches also.

Quoted 18 lines
Quoted 18 lines

---

arch/x86/include/asm/msr-index.h +1 -0
index 9dc6b610e4e2..623628d3c643 100644
@@ -1287,10 +1287,17 @@
  /* - AMD: */
  #define MSR_IA32_MBA_BW_BASE		0xc0000200
  #define MSR_IA32_SMBA_BW_BASE		0xc0000280
+#define MSR_IA32_PQR_PLZA_ASSOC		0xc00003fc
  #define MSR_IA32_L3_QOS_ABMC_CFG	0xc00003fd
  #define MSR_IA32_L3_QOS_EXT_CFG		0xc00003ff
  #define MSR_IA32_EVT_CFG_BASE		0xc0000400
 
Quoted 15 lines

arch/x86/include/asm/msr-index.h line 1300

Quoted 6 lines
arch/x86/include/asm/msr-index.h +6 -0
+/* Lower 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define RMID_EN				BIT(31)
+/* Upper 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define CLOSID_EN			BIT(15)
+#define PLZA_EN				BIT(31)
+

This is unexpected. So far resctrl has only defined the MSR numbers in this file, not the individual fields. This seems a legitimate use of msr-index.h but creates inconsistency with how the fields of the other resctrl registers are defined. This may be ok so I am looking past this for now. Since I am not familiar with this use I am looking at other patterns of this and it seems that the register fields are usually defined right after the register to make this relationship clear and also use more verbose naming to establish this relationship ... I do not think such cryptic names should be used without context in such a global scope. Please compare with how other fields are defined at this scope.

Sure. Will use the names tony suggested.
https://lore.kernel.org/lkml/SJ1PR11MB6083C069F99FAB8A0BEB8518FC182@SJ1PR11MB6083.namprd11.prod.outlook.com/

Also will moving the register "MSR_IA32_PQR_PLZA_ASSOC" together with BIT definition. It will break the sorting order. Hope that is not a problem.

Quoted 42 lines

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 227

Quoted 12 lines
arch/x86/kernel/cpu/resctrl/internal.h +3 -0
index e3cfa0c10e92..1c2f87ffb0ea 100644
@@ -222,6 +222,33 @@ union l3_qos_abmc_cfg {
  	unsigned long full;
  };
 
+/*
+ * PLZA is programmed by writing to MSR_IA32_PQR_PLZA_ASSOC. Bitfield
+ * layout for MSR_IA32_PQR_PLZA_ASSOC (Privilege Level Zero Association).

These comments are valuable to describe how resctrl should interact with this register so it would help to be specific and document any and all constraints.

For example, I seem to remember that all fields except PLZA_EN are required to be identical on all CPUs. Please document that and any other constraints here.

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 229

Quoted 2 lines
arch/x86/kernel/cpu/resctrl/internal.h +2 -0
+ *
+ * @rmid		: The RMID to be configured for PLZA.

What does "to be configured" mean? It seems to imply that when resctrl writes to @rmid then the setting does not take immediate effect but would take effect at some future "configure" time?

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 231

Quoted 2 lines
arch/x86/kernel/cpu/resctrl/internal.h +2 -0
+ * @reserved1		: Reserved.
+ * @rmid_en		: Associate RMID or not.

Please elaborate ... what is RMID associated with? What does "or not" imply? Here it will help to document relationship with MSR_IA32_PQR_ASSOC.

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 234

Quoted 3 lines
arch/x86/kernel/cpu/resctrl/internal.h +3 -0
+ * @closid		: The CLOSID to be configured for PLZA.
+ * @reserved2		: Reserved.
+ * @closid_en		: Associate CLOSID or not.

Same comments as for RMID

arch/x86/kernel/cpu/resctrl/internal.h union l3_qos_abmc_cfg { · line 236

Quoted 2 lines
arch/x86/kernel/cpu/resctrl/internal.h +2 -0
+ * @reserved3		: Reserved.
+ * @plza_en		: Configure PLZA or not.
Quoted 7 lines

plza_en implies "enable" but the comment mentions "configure". Considering the other fields are "to be configured" there seems to be relationship but that is not documented at all. For example, if @plza_en is 1 and resctrl modifies @rmid should resctrl write "1" to @plza_en again to "configure" the new RMID?

Please add specific detail to help understand how best to interact with this register.

Sure. Will re-write this whole comments.

Thanks
Babu

#12 lore raw

Re: [PATCH v3 02/12] x86/resctrl: Add data structures and definitions for PLZA configuration

Hi Reinette,

Quoted 55 lines · Babu

Hi Reinette,

Quoted 8 lines · Reinette Chatre

Hi Babu,

Quoted 5 lines · Babu Moger

Privilege Level Zero Association (PLZA) is configured per logical processor via MSR_IA32_PQR_PLZA_ASSOC (0xc00003fc). Software must program RMID and CLOSID association fields and their enable bits using the layout defined for the MSR.

Quoted 8 lines
Quoted 3 lines

Define MSR_IA32_PQR_PLZA_ASSOC and the RMID_EN, CLOSID_EN, and PLZA_EN bit masks in asm/msr-index.h. Add union msr_pqr_plza_assoc in arch resctrl internal.h

Above paragraph captures what can be seen from the patch. Please check entire series for this since many changelogs in this series verbatim describes the code changes in patch without helping reader understand why those changes are made.

Sure. Will rewrite the changelog. And will check other patches also.

Quoted 24 lines
Quoted 13 lines

---

arch/x86/include/asm/msr-index.h +0 -0
index 9dc6b610e4e2..623628d3c643 100644
@@ -1287,10 +1287,17 @@
   /* - AMD: */
   #define MSR_IA32_MBA_BW_BASE        0xc0000200
   #define MSR_IA32_SMBA_BW_BASE        0xc0000280

arch/x86/include/asm/msr-index.h line 1299

Quoted 10 lines
arch/x86/include/asm/msr-index.h +7 -0
+#define MSR_IA32_PQR_PLZA_ASSOC        0xc00003fc
   #define MSR_IA32_L3_QOS_ABMC_CFG    0xc00003fd
   #define MSR_IA32_L3_QOS_EXT_CFG        0xc00003ff
   #define MSR_IA32_EVT_CFG_BASE        0xc0000400
+/* Lower 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define RMID_EN                BIT(31)
+/* Upper 32 bits of MSR_IA32_PQR_PLZA_ASSOC */
+#define CLOSID_EN            BIT(15)
+#define PLZA_EN                BIT(31)
+
Quoted 8 lines

This is unexpected. So far resctrl has only defined the MSR numbers in this file, not the individual fields. This seems a legitimate use of msr-index.h but creates inconsistency with how the fields of the other resctrl registers are defined. This may be ok so I am looking past this for now. Since I am not familiar with this use I am looking at other patterns of this and it seems that the register fields are usually defined right after the register to make this relationship clear and also use more verbose naming to establish this relationship ... I do not think such cryptic names should be used without context in such a global scope. Please compare with how other fields are defined at this scope.

Quoted 4 lines

Sure. Will use the names tony suggested.
https://lore.kernel.org/lkml/ SJ1PR11MB6083C069F99FAB8A0BEB8518FC182@SJ1PR11MB6083.namprd11.prod.outlook.com/

Also will moving the register "MSR_IA32_PQR_PLZA_ASSOC" together with BIT definition. It will break the sorting order. Hope that is not a problem.

Never mind. I don't need the bit definitions anymore. I don't need to move the register.

Thanks
Babu

author reviewer
#13 lore raw

PATCH v3 3/12 fs/resctrl: Add kernel mode (kmode) data structures and arch hook

In reply to Babu Moger

Privilege-Level Zero Association (PLZA) allows the user to specify a CLOSID and/or RMID associated with execution in Privilege-Level Zero. Introduce a generic enumeration so that architecture and generic code can agree on the available policies.

Introduce enum resctrl_kernel_modes with the following values:

- INHERIT_CTRL_AND_MON: kernel and user tasks share the same CLOSID and RMID. This is the default and matches today's resctrl behaviour.

- GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU: a CLOSID is assigned for kernel work while the RMID used for monitoring is inherited from the running user task. The default scope is all online CPUs and may be narrowed to a subset via the resctrl group interface. A CTRL_MON group can be bound to this mode.

- GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU: both CLOSID and RMID are assigned to kernel work. The default scope is all online CPUs and may be narrowed per CPU via the resctrl group interface. A CTRL_MON group can be bound to this mode.

- RESCTRL_KMODE_LAST: highest enumerator naming a policy mode.

- RESCTRL_NUM_KERNEL_MODES: number of policy modes; use this to size static tables indexed by mode.

Also add struct resctrl_kmode_cfg (the snapshot architecture code returns) in include/linux/resctrl_types.h, and declare resctrl_arch_get_kmode_support() in include/linux/resctrl.h so architecture code can advertise the supported modes.

---
v3: Removed resctrl_kmode definition.
Changed the kernel mode definitions to enum resctrl_kernel_modes. Used BIT() to set/test the features.
Added details to changelog.

v2: New patch to handle PLZA interfaces with /sys/fs/resctrl/info/ directory.

    https://lore.kernel.org/lkml/[email protected]/
---
 include/linux/resctrl.h       | 13 ++++++++++
 include/linux/resctrl_types.h | 46 +++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)
include/linux/resctrl.h +13 -0
index 006e57fd7ca5..ce28418df00f 100644
@@ -699,6 +699,19 @@ int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable);
  */
 bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r);
 
+/**
+ * resctrl_arch_get_kmode_support() - Advertise kernel-mode capabilities
+ * @kcfg:	Architecture ORs BIT() flags into @kcfg->kmode for each supported
+ *		&enum resctrl_kernel_modes value (see &struct resctrl_kmode_cfg).
+ *
+ * Used for optional features (for example PLZA on x86) that can assign CLOSID
+ * and/or RMID to kernel work separately from user tasks.  Generic code compares
+ * @kcfg->kmode with the effective @kcfg->kmode_cur; when a global-assign mode is
+ * active, @kcfg->k_rdtgrp identifies the active &struct rdtgroup. The default mode
+ * is INHERIT_CTRL_AND_MON and group is default group.
+ */
+void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg);
+
 extern unsigned int resctrl_rmid_realloc_threshold;
 extern unsigned int resctrl_rmid_realloc_limit;
 
include/linux/resctrl_types.h +46 -0

50 lines not on this page · raw message

Signature · 1 line
2.43.0
maintainer
#14 lore raw

Re: [PATCH v3 03/12] fs/resctrl: Add kernel mode (kmode) data structures and arch hook

Hi Babu,

Quoted 1 line · Babu Moger

Privilege-Level Zero Association (PLZA) allows the user to specify a CLOSID

Subject prefix makes it clear this is a resctrl fs patch so please take care to not mix architecture specific terms with resctrl fs generalized support.

Something that may help here is to consider all resctrl fs changes to be relevant from MPAM perspective. Please do so with all resctrl fs changes in this series.

Quoted 5 lines

and/or RMID associated with execution in Privilege-Level Zero. Introduce a generic enumeration so that architecture and generic code can agree on the available policies.

Introduce enum resctrl_kernel_modes with the following values:

Please make the enum name singular, "resctrl_kernel_modes" -> "resctrl_kernel_mode" Doing so will make its use in code easier to parse.

Quoted 3 lines

- INHERIT_CTRL_AND_MON: kernel and user tasks share the same CLOSID and RMID. This is the default and matches today's resctrl behaviour.

CLOSID and RMID are x86 terms where the meaning is not 1:1 with other architectures. Since this is a new resctrl fs interface it is expected to be usable by all architectures. Making this architecture specific is not appropriate.

These are the modes that are exposed to user space and user space has no insight into CLOSID and RMID (ignoring scenario of debugging). I see no reason for resctrl do dictate CLOSID/RMID assignment as part of these modes but instead what the modes mean should be explained. If it is helpful then any x86 specific details can be added by highlighting it is x86 specific. For example,

"Kernel work inherits the allocation and monitoring from the user space task.
On x86 this means that kernel work shares the same CLOSID and RMID as the user space task."

Quoted 6 lines

- GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU: a CLOSID is assigned for kernel work while the RMID used for monitoring is inherited from the running user task. The default scope is all online CPUs and may be narrowed to a subset via the resctrl group interface. A CTRL_MON group can be bound to this mode.

Is binding a CTRL_MON group optional? Consider, for example:

"A CTRL_MON group is bound to this mode."

Quoted 5 lines

- GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU: both CLOSID and RMID are assigned to kernel work. The default scope is all online CPUs and may be narrowed per CPU via the resctrl group interface. A CTRL_MON group can be bound to this mode.

It should be possible to bind a MON group also, no?

Quoted 5 lines

- RESCTRL_KMODE_LAST: highest enumerator naming a policy mode.

- RESCTRL_NUM_KERNEL_MODES: number of policy modes; use this to size static tables indexed by mode.

The last two can be dropped, this is clear from the patch.

Quoted 5 lines

Also add struct resctrl_kmode_cfg (the snapshot architecture code returns) in include/linux/resctrl_types.h, and declare resctrl_arch_get_kmode_support() in include/linux/resctrl.h so architecture code can advertise the supported modes.

Above mostly just describes what is clear from the patch. Instead this can summarize what the addition does: "Provide callback with which architecture can set the kernel modes supported by it". (not exactly what this patch does though, but more below ...)

Quoted 20 lines

---
v3: Removed resctrl_kmode definition.
Changed the kernel mode definitions to enum resctrl_kernel_modes. Used BIT() to set/test the features.
Added details to changelog.

v2: New patch to handle PLZA interfaces with /sys/fs/resctrl/info/ directory.

    https://lore.kernel.org/lkml/[email protected]/
---
 include/linux/resctrl.h       | 13 ++++++++++
 include/linux/resctrl_types.h | 46 +++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)
include/linux/resctrl.h +0 -0
index 006e57fd7ca5..ce28418df00f 100644

include/linux/resctrl.h int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable); · line 703

Quoted 5 lines
include/linux/resctrl.h +2 -0
@@ -699,6 +699,19 @@ int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable);
  */
 bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r);
 
+/**
+ * resctrl_arch_get_kmode_support() - Advertise kernel-mode capabilities

"Advertise" implies a "broadcast" while the function name is "get" that implies retrieval.

Why does resctrl query the support from the architecture? The typical resctrl initialization involves the architecture setting certain capabilities. This simplifies enabling since it does not require the addition of this feature to be accompanied with an implementation of this call by every architecture.

Instead, resctrl can just initialize the defaults and an architecture can make any adjustments using the optional callback. So, instead of resctrl_arch_get_kmode_support(), why not resctrl_set_kmode_support() that is implemented in resctrl fs and called by architecture?

When considering the x86 implementation of this it seems as though this implementation assumes that all architectures will support inherit_ctrl_and_mon but this is not enforced anywhere. Having any assumptions enforced/verified will help to make this more robust. The fs/arch separation depending on so many architectures "doing the right thing" seems risky.

include/linux/resctrl.h int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable); · line 710

Quoted 7 lines
include/linux/resctrl.h +7 -0
+ * @kcfg:	Architecture ORs BIT() flags into @kcfg->kmode for each supported
+ *		&enum resctrl_kernel_modes value (see &struct resctrl_kmode_cfg).
+ *
+ * Used for optional features (for example PLZA on x86) that can assign CLOSID
+ * and/or RMID to kernel work separately from user tasks.  Generic code compares
+ * @kcfg->kmode with the effective @kcfg->kmode_cur; when a global-assign mode is
+ * active, @kcfg->k_rdtgrp identifies the active &struct rdtgroup. The default mode

Does the architecture need to know these implementation details?

include/linux/resctrl.h int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable); · line 713

Quoted 3 lines
include/linux/resctrl.h +3 -0
+ * is INHERIT_CTRL_AND_MON and group is default group.
+ */
+void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg);

Why does architecture need to know the layout of struct resctrl_kmode_cfg? It only needs to share the modes it supports and need not be concerned with any of the internals - from what I can tell the hook to program the kernel mode does not use this structure either and this is the only "outside of resctrl fs" usage and it does not seem necessary.

include/linux/resctrl_types.h

Quoted 8 lines
include/linux/resctrl.h +1 -0
+
 extern unsigned int resctrl_rmid_realloc_threshold;
 extern unsigned int resctrl_rmid_realloc_limit;
 
include/linux/resctrl_types.h +0 -0
index a5f56faa18d2..3aba07764b99 100644

Please keep in mind that resctrl_types.h is reserved for those types that an architecture needs to use in its asm/resctrl.h ... it does not look like any of the types added here qualify.

include/linux/resctrl_types.h enum resctrl_event_id { · line 72

Quoted 6 lines
include/linux/resctrl_types.h +2 -0
@@ -68,4 +68,50 @@ enum resctrl_event_id {
 #define QOS_NUM_L3_MBM_EVENTS	(QOS_L3_MBM_LOCAL_EVENT_ID - QOS_L3_MBM_TOTAL_EVENT_ID + 1)
 #define MBM_STATE_IDX(evt)	((evt) - QOS_L3_MBM_TOTAL_EVENT_ID)
 
+/**
+ * enum resctrl_kernel_modes - Kernel versus user CLOSID/RMID policy

What does "versus user" mean? Can this be dropped?

include/linux/resctrl_types.h enum resctrl_event_id {

Quoted 3 lines
include/linux/resctrl_types.h +3 -0
+ *
+ * Enumeration values are contiguous indices from 0 through
+ * @RESCTRL_KMODE_LAST inclusive. 

Above sentence is not necessary.

Quoted 6 lines

Global-assign modes treat all online CPUs as
+ * in scope by default; a subset of CPUs may be selected by using resctrl
+ * group's interface.
+ *
+ * @INHERIT_CTRL_AND_MON:
+ * User and kernel tasks use the same CLOSID and RMID.

Similar comment as earlier. Since this is generic resctrl fs interface it needs to be applicable to all architectures. For example (same suggestion as earlier),
"Kernel work inherits the allocation and monitoring of the user space task.

Quoted 2 lines

+ * @GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:
+ * A CLOSID may be assigned for kernel work while RMID selection for

"may be assigned" - this is not optional, right? How about "A control group is assigned ..."

Quoted 5 lines

+ * monitoring follows the same inheritance rules as for user contexts.
+ * Default scope is all online CPUs: subset of CPUs may be selected by
+ * using resctrl group's interface.
+ * @GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU:
+ * A single resource group (CLOSID and RMID together) may be assigned to

"may be" -> "is" ?

Quoted 3 lines

+ * kernel work. Default scope is all online CPUs: subset of CPUs may be
+ * selected by using resctrl group's interface.
+ * @RESCTRL_KMODE_LAST:

Documenting @RESCTRL_KMODE_LAST is not necessary.

Quoted 2 lines

+ * Highest enumerator that names a policy mode. Use RESCTRL_NUM_KERNEL_MODES
+ * to size static tables indexed by mode.

No need to document this.

include/linux/resctrl_types.h enum resctrl_event_id { · line 104

Quoted 12 lines

+ */

include/linux/resctrl_types.h +11 -0
+enum resctrl_kernel_modes {
+	INHERIT_CTRL_AND_MON,
+	GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU,
+	GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU,
+	RESCTRL_KMODE_LAST = GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU,
+};
+
+#define RESCTRL_NUM_KERNEL_MODES (RESCTRL_KMODE_LAST + 1)
+
+/**
+ * struct resctrl_kmode_cfg - Kernel-mode policy snapshot from architecture

Only @kmode is initialized from the architecture. The rest is managed by resctrl fs. I do not see why architecture needs to know the structure details.

Quoted 3 lines

+ * @kmode: Hardware- or policy-supported modes: each enumerator from
+ * &enum resctrl_kernel_modes is represented by BIT(mode index).
+ * @kmode_cur: Effective mode(s) in the same BIT(index) form as @kmode.

"mode(s)" ... this is plural implying more than one mode can be active at a time? Should this not be just one mode and can thus have type "enum resctrl_kernel_mode" to make this obvious?

Quoted 2 lines

+ * @k_rdtgrp: Resource group backing global-assign modes when applicable;
+ * initialized to the default group at boot.

Why is this initialized to default group at boot? I believe inherit_ctrl_and_mon is the default mode and it does not have a group so should this not be NULL by default?

include/linux/resctrl_types.h enum resctrl_event_id { · line 114

Quoted 5 lines

+ */

include/linux/resctrl_types.h +4 -0
+struct resctrl_kmode_cfg {
+	u32 kmode;
+	u32 kmode_cur;
+	struct rdtgroup *k_rdtgrp;

Please align struct members in tabular fashion.

Not specific to this patch: After so many contributions to resctrl I am very surprised how this series does not respect Documentation/process/maintainer-tip.rst in many ways. For example, later patches at some point just stops writing changelogs in imperative tone and just documents what the code does, patches document locking requirements instead of using code like lockdep_assert_held(), variables are not declared in reverse fir, changelogs refer to other patches in series. Following Documentation/process/maintainer-tip.rst should be very familiar by now.

Reinette

author reviewer
#15 lore raw

Re: [PATCH v3 03/12] fs/resctrl: Add kernel mode (kmode) data structures and arch hook

Hi Reinette,

Quoted 11 lines · Reinette Chatre

Hi Babu,

Quoted 1 line · Babu Moger

Privilege-Level Zero Association (PLZA) allows the user to specify a CLOSID

Subject prefix makes it clear this is a resctrl fs patch so please take care to not mix architecture specific terms with resctrl fs generalized support.

Something that may help here is to consider all resctrl fs changes to be relevant from MPAM perspective. Please do so with all resctrl fs changes in this series.

Ok. Agreed.

Quoted 9 lines
Quoted 6 lines

and/or RMID associated with execution in Privilege-Level Zero. Introduce a generic enumeration so that architecture and generic code can agree on the available policies.

Introduce enum resctrl_kernel_modes with the following values:

Please make the enum name singular, "resctrl_kernel_modes" -> "resctrl_kernel_mode" Doing so will make its use in code easier to parse.

Ok. Sure.

Quoted 15 lines
Quoted 4 lines

- INHERIT_CTRL_AND_MON: kernel and user tasks share the same CLOSID and RMID. This is the default and matches today's resctrl behaviour.

CLOSID and RMID are x86 terms where the meaning is not 1:1 with other architectures. Since this is a new resctrl fs interface it is expected to be usable by all architectures. Making this architecture specific is not appropriate.

These are the modes that are exposed to user space and user space has no insight into CLOSID and RMID (ignoring scenario of debugging). I see no reason for resctrl do dictate CLOSID/RMID assignment as part of these modes but instead what the modes mean should be explained. If it is helpful then any x86 specific details can be added by highlighting it is x86 specific. For example,

Quoted 3 lines

"Kernel work inherits the allocation and monitoring from the user space task.
On x86 this means that kernel work shares the same CLOSID and RMID as the user space task."

Sure.

Quoted 10 lines
Quoted 9 lines

- GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU: a CLOSID is assigned for kernel work while the RMID used for monitoring is inherited from the running user task. The default scope is all online CPUs and may be narrowed to a subset via the resctrl group interface. A CTRL_MON group can be bound to this mode.

Quoted 4 lines

Is binding a CTRL_MON group optional? Consider, for example:

"A CTRL_MON group is bound to this mode."

Ok. Sure

Quoted 7 lines
Quoted 5 lines

- GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU: both CLOSID and RMID are assigned to kernel work. The default scope is all online CPUs and may be narrowed per CPU via the resctrl group interface. A CTRL_MON group can be bound to this mode.

It should be possible to bind a MON group also, no?

Yes. We can bind either CTRL_MON or MON group to this mode.

Here is the discussion about it.
https://lore.kernel.org/lkml/[email protected]/

GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU can be either CTRL_MON or MON group.

GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU can only be CTRL_MON.

"A CTRL_MON or MON group is bound to this mode."

Quoted 8 lines
Quoted 6 lines

- RESCTRL_KMODE_LAST: highest enumerator naming a policy mode.

- RESCTRL_NUM_KERNEL_MODES: number of policy modes; use this to size static tables indexed by mode.

The last two can be dropped, this is clear from the patch.

Ok.

Quoted 45 lines
Quoted 6 lines

Also add struct resctrl_kmode_cfg (the snapshot architecture code returns) in include/linux/resctrl_types.h, and declare resctrl_arch_get_kmode_support() in include/linux/resctrl.h so architecture code can advertise the supported modes.

Above mostly just describes what is clear from the patch. Instead this can summarize what the addition does: "Provide callback with which architecture can set the kernel modes supported by it". (not exactly what this patch does though, but more below ...)

Quoted 20 lines

---
v3: Removed resctrl_kmode definition.
Changed the kernel mode definitions to enum resctrl_kernel_modes. Used BIT() to set/test the features.
Added details to changelog.

v2: New patch to handle PLZA interfaces with /sys/fs/resctrl/info/ directory.

     https://lore.kernel.org/lkml/[email protected]/
---
  include/linux/resctrl.h       | 13 ++++++++++
  include/linux/resctrl_types.h | 46 +++++++++++++++++++++++++++++++++++
  2 files changed, 59 insertions(+)
include/linux/resctrl.h +0 -0
index 006e57fd7ca5..ce28418df00f 100644

include/linux/resctrl.h int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable); · line 703

Quoted 5 lines
include/linux/resctrl.h +2 -0
@@ -699,6 +699,19 @@ int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable);
   */
  bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r);
 
+/**
+ * resctrl_arch_get_kmode_support() - Advertise kernel-mode capabilities

"Advertise" implies a "broadcast" while the function name is "get" that implies retrieval.

Why does resctrl query the support from the architecture? The typical resctrl initialization involves the architecture setting certain capabilities. This simplifies enabling since it does not require the addition of this feature to be accompanied with an implementation of this call by every architecture.

Quoted 4 lines

Instead, resctrl can just initialize the defaults and an architecture can make any adjustments using the optional callback. So, instead of resctrl_arch_get_kmode_support(), why not resctrl_set_kmode_support() that is implemented in resctrl fs and called by architecture?

Yes. We can do that. We can add resctrl_set_kmode_support() in FS and call from architecture.

Quoted 6 lines

When considering the x86 implementation of this it seems as though this implementation assumes that all architectures will support inherit_ctrl_and_mon but this is not enforced anywhere. Having any assumptions enforced/verified will help to make this more robust. The fs/arch separation depending on so many architectures "doing the right thing" seems risky.

ok.

Quoted 11 lines

include/linux/resctrl.h int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable); · line 710

Quoted 9 lines
include/linux/resctrl.h +7 -0
+ * @kcfg:	Architecture ORs BIT() flags into @kcfg->kmode for each supported
+ *		&enum resctrl_kernel_modes value (see &struct resctrl_kmode_cfg).
+ *
+ * Used for optional features (for example PLZA on x86) that can assign CLOSID
+ * and/or RMID to kernel work separately from user tasks.  Generic code compares
+ * @kcfg->kmode with the effective @kcfg->kmode_cur; when a global-assign mode is
+ * active, @kcfg->k_rdtgrp identifies the active &struct rdtgroup. The default mode

Does the architecture need to know these implementation details?

Not required.

Quoted 6 lines

include/linux/resctrl.h int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable); · line 713

Quoted 4 lines
include/linux/resctrl.h +3 -0
+ * is INHERIT_CTRL_AND_MON and group is default group.
+ */
+void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg);

Why does architecture need to know the layout of struct resctrl_kmode_cfg? It only needs

Arch does not need to know the resctrl_kmode_cfg.

Quoted 3 lines

to share the modes it supports and need not be concerned with any of the internals - from what I can tell the hook to program the kernel mode does not use this structure either and this is the only "outside of resctrl fs" usage and it does not seem necessary.

We can just pass the modes to resctrl_set_kmode_support() from arch to set it.

Quoted 5 lines
Quoted 5 lines
include/linux/resctrl.h +1 -0
+
  extern unsigned int resctrl_rmid_realloc_threshold;
  extern unsigned int resctrl_rmid_realloc_limit;
 
Quoted 7 lines

include/linux/resctrl_types.h

Quoted 4 lines
include/linux/resctrl_types.h +0 -0
index a5f56faa18d2..3aba07764b99 100644

Please keep in mind that resctrl_types.h is reserved for those types that an architecture needs to use in its asm/resctrl.h ... it does not look like any of the types added here qualify.

I will move it to include/linux/resctrl.h ad both ARCH and FS need to know about these modes.

Quoted 9 lines

include/linux/resctrl_types.h enum resctrl_event_id { · line 72

Quoted 7 lines
include/linux/resctrl_types.h +2 -0
@@ -68,4 +68,50 @@ enum resctrl_event_id {
  #define QOS_NUM_L3_MBM_EVENTS	(QOS_L3_MBM_LOCAL_EVENT_ID - QOS_L3_MBM_TOTAL_EVENT_ID + 1)
  #define MBM_STATE_IDX(evt)	((evt) - QOS_L3_MBM_TOTAL_EVENT_ID)
 
+/**
+ * enum resctrl_kernel_modes - Kernel versus user CLOSID/RMID policy

What does "versus user" mean? Can this be dropped?

ok.

Quoted 6 lines

include/linux/resctrl_types.h enum resctrl_event_id {

Quoted 4 lines
include/linux/resctrl_types.h +3 -0
+ *
+ * Enumeration values are contiguous indices from 0 through
+ * @RESCTRL_KMODE_LAST inclusive.

Above sentence is not necessary.

ok.

Quoted 11 lines
Quoted 7 lines

Global-assign modes treat all online CPUs as
+ * in scope by default; a subset of CPUs may be selected by using resctrl
+ * group's interface.
+ *
+ * @INHERIT_CTRL_AND_MON:
+ * User and kernel tasks use the same CLOSID and RMID.

Similar comment as earlier. Since this is generic resctrl fs interface it needs to be applicable to all architectures. For example (same suggestion as earlier),
"Kernel work inherits the allocation and monitoring of the user space task.

ok.

Quoted 5 lines
Quoted 3 lines

+ * @GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:
+ * A CLOSID may be assigned for kernel work while RMID selection for

"may be assigned" - this is not optional, right? How about "A control group is assigned ..."

ok.

Quoted 9 lines
Quoted 7 lines

+ * monitoring follows the same inheritance rules as for user contexts.
+ * Default scope is all online CPUs: subset of CPUs may be selected by
+ * using resctrl group's interface.
+ * @GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU:
+ * A single resource group (CLOSID and RMID together) may be assigned to

"may be" -> "is" ?

ok.

Quoted 10 lines
Quoted 3 lines

+ * kernel work. Default scope is all online CPUs: subset of CPUs may be
+ * selected by using resctrl group's interface.
+ * @RESCTRL_KMODE_LAST:

Documenting @RESCTRL_KMODE_LAST is not necessary.

Quoted 2 lines

+ * Highest enumerator that names a policy mode. Use RESCTRL_NUM_KERNEL_MODES
+ * to size static tables indexed by mode.

No need to document this.

ok.

Quoted 16 lines

include/linux/resctrl_types.h enum resctrl_event_id { · line 104

Quoted 13 lines

+ */

include/linux/resctrl_types.h +11 -0
+enum resctrl_kernel_modes {
+	INHERIT_CTRL_AND_MON,
+	GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU,
+	GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU,
+	RESCTRL_KMODE_LAST = GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU,
+};
+
+#define RESCTRL_NUM_KERNEL_MODES (RESCTRL_KMODE_LAST + 1)
+
+/**
+ * struct resctrl_kmode_cfg - Kernel-mode policy snapshot from architecture

Only @kmode is initialized from the architecture. The rest is managed by resctrl fs. I do not see why architecture needs to know the structure details.

Correct. Will move this to FS.

Quoted 6 lines
Quoted 4 lines

+ * @kmode: Hardware- or policy-supported modes: each enumerator from
+ * &enum resctrl_kernel_modes is represented by BIT(mode index).
+ * @kmode_cur: Effective mode(s) in the same BIT(index) form as @kmode.

"mode(s)" ... this is plural implying more than one mode can be active at a time?

no.

Quoted 2 lines

Should this not be just one mode and can thus have type "enum resctrl_kernel_mode" to make this obvious?

Yes.

Quoted 6 lines
Quoted 3 lines

+ * @k_rdtgrp: Resource group backing global-assign modes when applicable;
+ * initialized to the default group at boot.

Why is this initialized to default group at boot? I believe inherit_ctrl_and_mon is the default mode and it does not have a group so should this not be NULL by default?

Yes. It should be NULL at boot. Will change it.

Quoted 9 lines

include/linux/resctrl_types.h enum resctrl_event_id { · line 114

Quoted 6 lines

+ */

include/linux/resctrl_types.h +4 -0
+struct resctrl_kmode_cfg {
+	u32 kmode;
+	u32 kmode_cur;
+	struct rdtgroup *k_rdtgrp;

Please align struct members in tabular fashion.

Quoted 7 lines

Not specific to this patch: After so many contributions to resctrl I am very surprised how this series does not respect Documentation/process/maintainer-tip.rst in many ways. For example, later patches at some point just stops writing changelogs in imperative tone and just documents what the code does, patches document locking requirements instead of using code like lockdep_assert_held(), variables are not declared in reverse fir, changelogs refer to other patches in series. Following Documentation/process/maintainer-tip.rst should be very familiar by now.

My bad. Yes. Will focus on process in next revision.

Thanks
Babu

author reviewer
#16 lore raw

PATCH v3 4/12 x86,fs/resctrl: Program PLZA through kmode arch hooks

In reply to Babu Moger

AMD Privilege Level Zero Association (PLZA) exposes kernel CLOSID/RMID association through MSR_IA32_PQR_PLZA_ASSOC. Generic resctrl already tracks supported and effective kernel-mode policy in struct resctrl_kmode_cfg, but the architecture layer needs a callable entry point that can push those values into per-CPU hardware on a chosen CPU mask.

Declare resctrl_arch_configure_kmode() in linux/resctrl.h with kernel-doc. Implement it on x86: add an SMP callback that writes MSR_IA32_PQR_PLZA_ASSOC on each targeted CPU, and use on_each_cpu_mask() for the broadcast.

The hook is unused in this patch; later patches in the series wire it into generic resctrl when an effective kernel-mode policy is selected or a CPU mask changes.

---
v3: Removed task based PLZA implementation so related changes are removed.
Removed handling of rmid_en as it is not required. The group type assigned will be different so the monitoring part is already taken care. Updated the change log with details.
Removed resctrl_arch_set_kmode() as arch only provides the modes supported. It is FS which decided which mode to apply.

v2: Updated the commit message to include the sequence of steps to enable PLZA.
Added mode code comments for clarity.
Added kmode to functin names to be generic.

---
 arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 35 +++++++++++++++++++++++
 include/linux/resctrl.h                   | 10 +++++++
 2 files changed, 45 insertions(+)
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +35 -0
index b20e705606b8..68f1cf503904 100644
@@ -131,3 +131,38 @@ int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
 
 	return 0;
 }
+
+/*
+ * SMP call-function callback: each CPU writes its own MSR_IA32_PQR_PLZA_ASSOC
+ * (AMD PLZA).  Invoked via on_each_cpu_mask() with wait=1 so the on-stack
+ * union pointed at by @arg is safe.
+ */
+static void resctrl_kmode_set_one_amd(void *arg)
+{
+	union msr_pqr_plza_assoc *plza = arg;
+
+	wrmsrl(MSR_IA32_PQR_PLZA_ASSOC, plza->full);
+}
+
+/**
+ * resctrl_arch_configure_kmode() - x86/AMD: program PLZA MSR on a CPU subset
+ * @cpu_mask:	CPUs to receive the update (see on_each_cpu_mask() for online subset).
+ * @closid:	CLOSID field written into the MSR with CLOSID_EN set.
+ * @rmid:	RMID field written into the MSR with RMID_EN set.
+ * @enable:	Value for the PLZA_EN split field.
+ *
+ * Context: Do not call with IRQs off or from IRQ context except as allowed for
+ * on_each_cpu_mask(); see kernel/smp.c.
+ */
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid, bool enable)
+{
+	union msr_pqr_plza_assoc plza = { 0 };
+
+	plza.split.rmid = rmid;
+	plza.split.rmid_en = 1;
+	plza.split.closid = closid;
+	plza.split.closid_en = 1;
+	plza.split.plza_en = enable;
+
+	on_each_cpu_mask(cpu_mask, resctrl_kmode_set_one_amd, &plza, 1);
+}
include/linux/resctrl.h +10 -0
index ce28418df00f..570918e57e24 100644
@@ -712,6 +712,16 @@ bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r);
  */
 void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg);
 
+/**
+ * resctrl_arch_configure_kmode() - Program MSR_IA32_PQR_PLZA_ASSOC on CPUs in @cpu_mask
+ * @cpu_mask:	Target CPUs; on_each_cpu_mask() applies the callback on the online subset.
+ * @closid:	CLOSID written to the MSR with CLOSID_EN set.
+ * @rmid:	RMID written to the MSR with RMID_EN set.
+ * @enable:	PLZA_EN field value for this update.
+ */
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid,
+				  bool enable);
+
 extern unsigned int resctrl_rmid_realloc_threshold;
 extern unsigned int resctrl_rmid_realloc_limit;
 
Signature · 1 line
2.43.0
maintainer
#17 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 162

Quoted 6 lines · Babu Moger
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +6 -0
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid, bool enable)
+{
+	union msr_pqr_plza_assoc plza = { 0 };
+
+	plza.split.rmid = rmid;
+	plza.split.rmid_en = 1;

Shouldn't there be a parameter for the value of rmid_en?

User asked for global_assign_ctrl_assign_mon_per_cpu set it to '1'

User asked for global_assign_ctrl_inherit_mon_per_cpu set it to '0'

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 168

Quoted 6 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +6 -0
+	plza.split.closid = closid;
+	plza.split.closid_en = 1;
+	plza.split.plza_en = enable;
+
+	on_each_cpu_mask(cpu_mask, resctrl_kmode_set_one_amd, &plza, 1);
+}

-Tony

author reviewer
#18 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

Hi Tony,

Quoted 9 lines · Tony

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 162

Quoted 6 lines · Babu Moger
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +6 -0
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid, bool enable)
+{
+	union msr_pqr_plza_assoc plza = { 0 };
+
+	plza.split.rmid = rmid;
+	plza.split.rmid_en = 1;

Shouldn't there be a parameter for the value of rmid_en?

I realized that behavior is not required—it was actually due to a mistake in my v2 series implementation.

Below are the relevant definitions:

GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:
The CLOSID is applied to kernel work, while the RMID used for monitoring is inherited from the currently running user task. No separate monitoring group is assigned for kernel work, so kernel execution naturally inherits the user-space RMID.

GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU:
Both CLOSID and RMID are explicitly assigned to kernel work.
This allows assigning a dedicated monitoring group for kernel execution and therefore requires a separate RMID.

Example: For GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:

# mount -t resctrl resctrl /sys/fs/resctrl
# cat /sys/fs/resctrl/info/kernel_mode
[inherit_ctrl_and_mon:group=//]
global_assign_ctrl_inherit_mon_per_cpu:group=none
global_assign_ctrl_assign_mon_per_cpu:group=none
# mkdir /sys/fs/resctrl/ctrl1   (PQR_ASSOC closid=1 rmid=1)

This configures all the CPU threads to use closid=1 and rmid=1 for both allocation and monitoring across user and kernel modes.

# echo "global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//" \
Quoted 1 line

/sys/fs/resctrl/info/kernel_mode

# cat /sys/fs/resctrl/info/kernel_mode
inherit_ctrl_and_mon:group=none
[global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//]
global_assign_ctrl_assign_mon_per_cpu:group=none

This overrides the previous configuration, and PQR_PLZA_ASSOC is written.

Possible options:

1. (closid=1, rmid_en=0, rmid=1)
Here, hardware uses closid=1 for kernel work, but RMID tracking is disabled for kernel mode.

As a result, reading RMID 1 reports only user-mode activity
This contradicts the definition of this mode, since kernel work is expected to inherit the user RMID for monitoring.

2. (closid=1, rmid_en=1, rmid=1)
In this case, RMID tracking is enabled for both user and kernel modes.

Reading RMID 1 reports combined user + kernel activity This aligns with the expected inherit_monitoring behavior

The preferred approach is to separate kernel monitoring by assigning it a dedicated monitoring group and updating PQR_PLZA_ASSOC to use a different RMID (e.g., closid=1, rmid_en=1, rmid=2). This is exactly the behavior implemented by GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU.

Thanks
Babu

maintainer
#19 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

Quoted 71 lines · Babu Moger

Hi Tony,

Quoted 9 lines · Tony

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 162

Quoted 6 lines · Babu Moger
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +6 -0
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid, bool enable)
+{
+	union msr_pqr_plza_assoc plza = { 0 };
+
+	plza.split.rmid = rmid;
+	plza.split.rmid_en = 1;

Shouldn't there be a parameter for the value of rmid_en?

I realized that behavior is not required—it was actually due to a mistake in my v2 series implementation.

Below are the relevant definitions:

GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:
The CLOSID is applied to kernel work, while the RMID used for monitoring is inherited from the currently running user task.
No separate monitoring group is assigned for kernel work, so kernel execution naturally inherits the user-space RMID.

GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU:
Both CLOSID and RMID are explicitly assigned to kernel work. This allows assigning a dedicated monitoring group for kernel execution and therefore requires a separate RMID.

Example: For GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:

# mount -t resctrl resctrl /sys/fs/resctrl
# cat /sys/fs/resctrl/info/kernel_mode
[inherit_ctrl_and_mon:group=//]
global_assign_ctrl_inherit_mon_per_cpu:group=none
global_assign_ctrl_assign_mon_per_cpu:group=none
# mkdir /sys/fs/resctrl/ctrl1   (PQR_ASSOC closid=1 rmid=1)

This configures all the CPU threads to use closid=1 and rmid=1 for both allocation and monitoring across user and kernel modes.

# echo "global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//" \
Quoted 1 line

/sys/fs/resctrl/info/kernel_mode

# cat /sys/fs/resctrl/info/kernel_mode
inherit_ctrl_and_mon:group=none
[global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//]
global_assign_ctrl_assign_mon_per_cpu:group=none

This overrides the previous configuration, and PQR_PLZA_ASSOC is written.

Possible options:

1. (closid=1, rmid_en=0, rmid=1)
Here, hardware uses closid=1 for kernel work, but RMID tracking is disabled for kernel mode.

As a result, reading RMID 1 reports only user-mode activity This contradicts the definition of this mode, since kernel work is expected to inherit the user RMID for monitoring.

2. (closid=1, rmid_en=1, rmid=1)
In this case, RMID tracking is enabled for both user and kernel modes.

Quoted 8 lines

Reading RMID 1 reports combined user + kernel activity This aligns with the expected inherit_monitoring behavior

The preferred approach is to separate kernel monitoring by assigning it a dedicated monitoring group and updating PQR_PLZA_ASSOC to use a different RMID (e.g., closid=1, rmid_en=1, rmid=2). This is exactly the behavior implemented by GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU.

So maybe I'm just confused by the name "global_assign_ctrl_inherit_mon_per_cpu"

That sounds like "Use the CLOSID from PLZA, but keep the RMID from legacy PQR_ASSOC.

So:

# mkdir ctrl1 # maybe gets CLOSID=1, RMID=1
# echo global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//" > info/kernel_mode
# mkdir ctrl2 # maybe gets CLOSID=2, RMID=2
# echo $$ > ctrl2/tasks

My shell, and all children run with CLOSID=2 and RMID=2 from ctrl2. But when they do system calls, take page faults or there is an interrupt I'd expect the code in the kernel to run with the CLOSID=1, while inheriting RMID=2.

To make that happen, I thing the PLZA MSR should have rmid_en = 0. But the only code I see that sets this always sets rmid_en=1.

Quoted 3 lines

Thanks
Babu

-Tony

#20 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

Hi Tony,

Quoted 81 lines · Tony
Quoted 71 lines · Babu Moger

Hi Tony,

Quoted 9 lines · Tony

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 162

Quoted 6 lines · Babu Moger
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +6 -0
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid, bool enable)
+{
+	union msr_pqr_plza_assoc plza = { 0 };
+
+	plza.split.rmid = rmid;
+	plza.split.rmid_en = 1;

Shouldn't there be a parameter for the value of rmid_en?

I realized that behavior is not required—it was actually due to a mistake in my v2 series implementation.

Below are the relevant definitions:

GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:
The CLOSID is applied to kernel work, while the RMID used for monitoring is inherited from the currently running user task.
No separate monitoring group is assigned for kernel work, so kernel execution naturally inherits the user-space RMID.

GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU:
Both CLOSID and RMID are explicitly assigned to kernel work. This allows assigning a dedicated monitoring group for kernel execution and therefore requires a separate RMID.

Example: For GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:

# mount -t resctrl resctrl /sys/fs/resctrl
# cat /sys/fs/resctrl/info/kernel_mode
[inherit_ctrl_and_mon:group=//]
global_assign_ctrl_inherit_mon_per_cpu:group=none
global_assign_ctrl_assign_mon_per_cpu:group=none
# mkdir /sys/fs/resctrl/ctrl1   (PQR_ASSOC closid=1 rmid=1)

This configures all the CPU threads to use closid=1 and rmid=1 for both allocation and monitoring across user and kernel modes.

# echo "global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//" \
Quoted 1 line

/sys/fs/resctrl/info/kernel_mode

# cat /sys/fs/resctrl/info/kernel_mode
inherit_ctrl_and_mon:group=none
[global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//]
global_assign_ctrl_assign_mon_per_cpu:group=none

This overrides the previous configuration, and PQR_PLZA_ASSOC is written.

Possible options:

1. (closid=1, rmid_en=0, rmid=1)
Here, hardware uses closid=1 for kernel work, but RMID tracking is disabled for kernel mode.

As a result, reading RMID 1 reports only user-mode activity This contradicts the definition of this mode, since kernel work is expected to inherit the user RMID for monitoring.

2. (closid=1, rmid_en=1, rmid=1)
In this case, RMID tracking is enabled for both user and kernel modes.

Quoted 8 lines

Reading RMID 1 reports combined user + kernel activity This aligns with the expected inherit_monitoring behavior

The preferred approach is to separate kernel monitoring by assigning it a dedicated monitoring group and updating PQR_PLZA_ASSOC to use a different RMID (e.g., closid=1, rmid_en=1, rmid=2). This is exactly the behavior implemented by GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU.

Quoted 4 lines

So maybe I'm just confused by the name "global_assign_ctrl_inherit_mon_per_cpu"

That sounds like "Use the CLOSID from PLZA, but keep the RMID from legacy PQR_ASSOC.

Yes. That is correct. We need to work on naming this correctly.

Quoted 5 lines

So:

# mkdir ctrl1 # maybe gets CLOSID=1, RMID=1
# echo global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//" > info/kernel_mode

This makes kernel mode run with CLOSID 1 and RMID 1(Use the same RMID as the user mode). [1]

Quoted 7 lines
# mkdir ctrl2 # maybe gets CLOSID=2, RMID=2
# echo $$ > ctrl2/tasks

My shell, and all children run with CLOSID=2 and RMID=2 from ctrl2. But when they do system calls, take page faults or there is an interrupt I'd expect the code in the kernel to run with the CLOSID=1, while inheriting RMID=2.

ctrl2 is not a PLZA group. So, RMID 2 is not connected to PLZA.

Quoted 3 lines

To make that happen, I thing the PLZA MSR should have rmid_en = 0. But the only code I see that sets this always sets rmid_en=1.

Setting rmid_en = 0 in [1] disables counting of kernel usage for RMID 1 (from ctrl1).

The key difference between the two modes is:

In one mode, user and kernel usage are counted together.
In the other mode, kernel usage is counted separately from user usage.

Please feel free to continue the discussion if anything is still unclear.

Thanks,
Babu

#21 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

Quoted 4 lines · Babu
Quoted 3 lines · Tony

So maybe I'm just confused by the name
"global_assign_ctrl_inherit_mon_per_cpu"

Quoted 8 lines
Quoted 5 lines

That sounds like "Use the CLOSID from PLZA, but keep the RMID from legacy PQR_ASSOC.

To make that happen, I thing the PLZA MSR should have rmid_en = 0. But the only code I see that sets this always sets rmid_en=1.

Setting rmid_en = 0 in [1] disables counting of kernel usage for RMID 1 (from ctrl1).

I've been reviewing these patches and went back to the AMD hardware manual (Publication #69193, Rev 1.00, March 2026) to understand the RMID_EN semantics.

The spec defines RMID_EN (bit 31 of PQR_PLZA_ASSOC, MSR C000_03FCh):

"RMID_EN (PLZA Resource Monitoring Identifier Association Enable)
- bit 31. When set and PLZA_EN is set, the Resource Monitoring Identifier (RMID) for this logical processor executing at CPL=0 is specified in the RMID field instead of PQR_ASSOC[RMID]."

Reading "instead of PQR_ASSOC[RMID]", my understanding is that when RMID_EN is clear, the hardware falls back to PQR_ASSOC[RMID] - the user process's RMID - rather than disabling monitoring entirely. If that reading is correct, RMID_EN would be a source selector between PLZA and PQR_ASSOC, not an on/off switch for counting.

Babu, could you confirm whether that is the intended hardware behavior?

Quoted 4 lines

The key difference between the two modes is:

In one mode, user and kernel usage are counted together.
In the other mode, kernel usage is counted separately from user usage.

If RMID_EN=0 does fall back to PQR_ASSOC[RMID], then the "counted together" behavior only holds when the user process happens to be in the same group as the PLZA-bound group. Taking Tony's example:

  # mkdir ctrl1   # CLOSID=1, RMID=1, bound to inherit_mon via PLZA
  # mkdir ctrl2   # CLOSID=2, RMID=2
  # echo $$ > ctrl2/tasks

With rmid_en=1 (current code): when the shell (in ctrl2, PQR_ASSOC RMID=2) enters kernel mode, kernel activity is counted under PLZA RMID=1. The user process's RMID is NOT inherited.

With rmid_en=0: kernel mode would fall back to PQR_ASSOC RMID=2, correctly inheriting the monitoring identity of the current user process - which seems to be what "inherit_mon" intends.

If this reading is right, Tony's suggestion of adding a parameter to control rmid_en based on the mode would be the right fix:

void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask,
u32 closid, u32 rmid, bool assign_rmid, bool enable)

where assign_rmid=true sets RMID_EN=1 (assign_mon) and assign_rmid=false sets RMID_EN=0 (inherit_mon).

---

Separately, I have a question about the group type constraint for global_assign_ctrl_assign_mon_per_cpu (assign_mon mode).

In patch 08/12 ("fs/resctrl: Make info/kernel_mode writable and identify the bound group"), resctrl_kernel_mode_write() enforces that assign_mon must bind to an RDTMON_GROUP:

  if (kmode == BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU) &&
      rdtgrp->type != RDTMON_GROUP) {

This forces the user to create a ctrl group plus a monitor sub-group. But since the kernel-mode group is dedicated to kernel work and no user tasks are assigned to it, the ctrl group's own RMID (allocated via alloc_rmid() at mkdir time) should be clean and usable. Requiring an extra monitor group seems to waste a scarce RMID.

Would it make sense to relax this constraint so that assign_mon also accepts an RDTCTRL_GROUP? The path infrastructure (rdtgroup_by_kmode_path and resctrl_kernel_mode_show) already handles the "<ctrl>//" form, so only the check above would need to change:

  mkdir /sys/fs/resctrl/kernel_ctrl
  echo "global_assign_ctrl_assign_mon_per_cpu:group=kernel_ctrl//" \
       > info/kernel_mode

Thanks,
Qinyun

author reviewer
#22 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

Hi Qinyun,

Thanks for reviewing the patches.

Quoted 25 lines · Qinyun Tan
Quoted 4 lines · Babu
Quoted 3 lines · Tony

So maybe I'm just confused by the name
"global_assign_ctrl_inherit_mon_per_cpu"

Quoted 8 lines
Quoted 5 lines

That sounds like "Use the CLOSID from PLZA, but keep the RMID from legacy PQR_ASSOC.

To make that happen, I thing the PLZA MSR should have rmid_en = 0. But the only code I see that sets this always sets rmid_en=1.

Setting rmid_en = 0 in [1] disables counting of kernel usage for RMID 1 (from ctrl1).

I've been reviewing these patches and went back to the AMD hardware manual (Publication #69193, Rev 1.00, March 2026) to understand the RMID_EN semantics.

The spec defines RMID_EN (bit 31 of PQR_PLZA_ASSOC, MSR C000_03FCh):

"RMID_EN (PLZA Resource Monitoring Identifier Association Enable)
- bit 31. When set and PLZA_EN is set, the Resource Monitoring Identifier (RMID) for this logical processor executing at CPL=0 is specified in the RMID field instead of PQR_ASSOC[RMID]."

Quoted 8 lines

Reading "instead of PQR_ASSOC[RMID]", my understanding is that when RMID_EN is clear, the hardware falls back to PQR_ASSOC[RMID] - the user process's RMID - rather than disabling monitoring entirely. If that reading is correct, RMID_EN would be a source selector between PLZA and PQR_ASSOC, not an on/off switch for counting.

Babu, could you confirm whether that is the intended hardware behavior?

Yes. That is correct. RMID_EN is a source selector.

Quoted 25 lines
Quoted 5 lines

The key difference between the two modes is:

In one mode, user and kernel usage are counted together.
In the other mode, kernel usage is counted separately from user usage.

If RMID_EN=0 does fall back to PQR_ASSOC[RMID], then the "counted together" behavior only holds when the user process happens to be in the same group as the PLZA-bound group. Taking Tony's example:

   # mkdir ctrl1   # CLOSID=1, RMID=1, bound to inherit_mon via PLZA
   # mkdir ctrl2   # CLOSID=2, RMID=2
   # echo $$ > ctrl2/tasks

With rmid_en=1 (current code): when the shell (in ctrl2, PQR_ASSOC RMID=2) enters kernel mode, kernel activity is counted under PLZA RMID=1. The user process's RMID is NOT inherited.

With rmid_en=0: kernel mode would fall back to PQR_ASSOC RMID=2, correctly inheriting the monitoring identity of the current user process - which seems to be what "inherit_mon" intends.

If this reading is right, Tony's suggestion of adding a parameter to control rmid_en based on the mode would be the right fix:

Quoted 6 lines

void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask,
u32 closid, u32 rmid, bool assign_rmid, bool enable)

where assign_rmid=true sets RMID_EN=1 (assign_mon) and assign_rmid=false sets RMID_EN=0 (inherit_mon).

Yes. You are right. I will fix it next revision.

Quoted 19 lines

---

Separately, I have a question about the group type constraint for global_assign_ctrl_assign_mon_per_cpu (assign_mon mode).

In patch 08/12 ("fs/resctrl: Make info/kernel_mode writable and identify the bound group"), resctrl_kernel_mode_write() enforces that assign_mon must bind to an RDTMON_GROUP:

   if (kmode == BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU) &&
       rdtgrp->type != RDTMON_GROUP) {

This forces the user to create a ctrl group plus a monitor sub-group. But since the kernel-mode group is dedicated to kernel work and no user tasks are assigned to it, the ctrl group's own RMID (allocated via alloc_rmid() at mkdir time) should be clean and usable. Requiring an extra monitor group seems to waste a scarce RMID.

Quoted 9 lines

Would it make sense to relax this constraint so that assign_mon also accepts an RDTCTRL_GROUP? The path infrastructure (rdtgroup_by_kmode_path and resctrl_kernel_mode_show) already handles the "<ctrl>//" form, so only the check above would need to change:

   mkdir /sys/fs/resctrl/kernel_ctrl
   echo "global_assign_ctrl_assign_mon_per_cpu:group=kernel_ctrl//" \
        > info/kernel_mode

Yes. That is reasonable.

assign_mon can be RDTMON_GROUP or RDTCTRL_GROUP.

inherit_mon can only be RDTCTRL_GROUP.

Thanks

Babu

#23 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

In reply to Moger, Babu

Hi Babu,

Quoted 22 lines · Babu

Hi Tony,

Quoted 18 lines · Tony
Quoted 17 lines · Babu Moger

Hi Tony,

Quoted 9 lines · Tony

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 162

Quoted 6 lines · Babu Moger
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +6 -0
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid, bool enable)
+{
+  union msr_pqr_plza_assoc plza = { 0 };
+
+  plza.split.rmid = rmid;
+  plza.split.rmid_en = 1;

Shouldn't there be a parameter for the value of rmid_en?

I realized that behavior is not required—it was actually due to a mistake in my v2 series implementation.

Really? This is in fact the only behavior we wanted:

https://lore.kernel.org/lkml/CABPqkBSq=cgn-am4qorA_VN0vsbpbfDePSi7gubicpROB1=djw@mail.gmail.com/

-Peter

Quoted 106 lines
Quoted 63 lines
Quoted 54 lines

Below are the relevant definitions:

GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:
The CLOSID is applied to kernel work, while the RMID used for monitoring is inherited from the currently running user task.
No separate monitoring group is assigned for kernel work, so kernel execution naturally inherits the user-space RMID.

GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU:
Both CLOSID and RMID are explicitly assigned to kernel work. This allows assigning a dedicated monitoring group for kernel execution and therefore requires a separate RMID.

Example: For GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU:

# mount -t resctrl resctrl /sys/fs/resctrl
# cat /sys/fs/resctrl/info/kernel_mode
[inherit_ctrl_and_mon:group=//]
global_assign_ctrl_inherit_mon_per_cpu:group=none
global_assign_ctrl_assign_mon_per_cpu:group=none
# mkdir /sys/fs/resctrl/ctrl1   (PQR_ASSOC closid=1 rmid=1)

This configures all the CPU threads to use closid=1 and rmid=1 for both allocation and monitoring across user and kernel modes.

# echo "global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//" \
Quoted 1 line

/sys/fs/resctrl/info/kernel_mode

# cat /sys/fs/resctrl/info/kernel_mode
inherit_ctrl_and_mon:group=none
[global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//]
global_assign_ctrl_assign_mon_per_cpu:group=none

This overrides the previous configuration, and PQR_PLZA_ASSOC is written.

Possible options:

1. (closid=1, rmid_en=0, rmid=1)
Here, hardware uses closid=1 for kernel work, but RMID tracking is disabled for kernel mode.

As a result, reading RMID 1 reports only user-mode activity This contradicts the definition of this mode, since kernel work is expected to inherit the user RMID for monitoring.

2. (closid=1, rmid_en=1, rmid=1)
In this case, RMID tracking is enabled for both user and kernel modes.

Quoted 8 lines

Reading RMID 1 reports combined user + kernel activity This aligns with the expected inherit_monitoring behavior

The preferred approach is to separate kernel monitoring by assigning it a dedicated monitoring group and updating PQR_PLZA_ASSOC to use a different RMID (e.g., closid=1, rmid_en=1, rmid=2). This is exactly the behavior implemented by GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU.

Quoted 4 lines

So maybe I'm just confused by the name "global_assign_ctrl_inherit_mon_per_cpu"

That sounds like "Use the CLOSID from PLZA, but keep the RMID from legacy PQR_ASSOC.

Yes. That is correct. We need to work on naming this correctly.

Quoted 5 lines

So:

# mkdir ctrl1 # maybe gets CLOSID=1, RMID=1
# echo global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//" > info/kernel_mode

This makes kernel mode run with CLOSID 1 and RMID 1(Use the same RMID as the user mode). [1]

Quoted 7 lines
# mkdir ctrl2 # maybe gets CLOSID=2, RMID=2
# echo $$ > ctrl2/tasks

My shell, and all children run with CLOSID=2 and RMID=2 from ctrl2. But when they do system calls, take page faults or there is an interrupt I'd expect the code in the kernel to run with the CLOSID=1, while inheriting RMID=2.

ctrl2 is not a PLZA group. So, RMID 2 is not connected to PLZA.

Quoted 3 lines

To make that happen, I thing the PLZA MSR should have rmid_en = 0. But the only code I see that sets this always sets rmid_en=1.

Setting rmid_en = 0 in [1] disables counting of kernel usage for RMID 1 (from ctrl1).

The key difference between the two modes is:

In one mode, user and kernel usage are counted together.
In the other mode, kernel usage is counted separately from user usage.

Please feel free to continue the discussion if anything is still unclear.

Thanks,
Babu

author reviewer
#24 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

Hi Peter,

Quoted 23 lines · Peter Newman

Hi Babu,

Quoted 20 lines · Babu

Hi Tony,

Quoted 16 lines · Tony
Quoted 15 lines · Babu Moger

Hi Tony,

Quoted 9 lines · Tony

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 162

Quoted 6 lines · Babu Moger
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +6 -0
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid, bool enable)
+{
+  union msr_pqr_plza_assoc plza = { 0 };
+
+  plza.split.rmid = rmid;
+  plza.split.rmid_en = 1;

Shouldn't there be a parameter for the value of rmid_en?

Quoted 6 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

I realized that behavior is not required—it was actually due to a mistake in my v2 series implementation.

Really? This is in fact the only behavior we wanted:

https://lore.kernel.org/lkml/CABPqkBSq=cgn-am4qorA_VN0vsbpbfDePSi7gubicpROB1=djw@mail.gmail.com/

I have responded to similar comment already.

https://lore.kernel.org/lkml/[email protected]/

You are right—we should not set rmid_en = 1 in all cases.

For the "inherit_mon" mode, rmid_en will be 0, so the monitoring counts will remain unaffected. This represents the generic use case.

For the "assign_mon" mode, rmid_en will be 1. In this case, the kernel monitoring counts will be separate from the user’s.

So, we have both the options. I hope this addresses your concerns.

Thanks

Babu

maintainer
#25 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

In reply to Babu Moger

Hi Babu,

Quoted 10 lines · Babu Moger

AMD Privilege Level Zero Association (PLZA) exposes kernel CLOSID/RMID association through MSR_IA32_PQR_PLZA_ASSOC. Generic resctrl already tracks supported and effective kernel-mode policy in struct resctrl_kmode_cfg, but the architecture layer needs a callable entry point that can push those values into per-CPU hardware on a chosen CPU mask.

Declare resctrl_arch_configure_kmode() in linux/resctrl.h with kernel-doc. Implement it on x86: add an SMP callback that writes MSR_IA32_PQR_PLZA_ASSOC on each targeted CPU, and use on_each_cpu_mask() for the broadcast.

Above is clear from the patch. Please start with focus on why this patch is needed.

Quoted 2 lines

The hook is unused in this patch; later patches in the series wire it into

Similar to previous work: write changelog in imperative tone and do not refer to patches in series but instead let each patch stand on its own.

Quoted 21 lines

generic resctrl when an effective kernel-mode policy is selected or a CPU mask changes.

---

---
 arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 35 +++++++++++++++++++++++
 include/linux/resctrl.h                   | 10 +++++++
 2 files changed, 45 insertions(+)
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +1 -0
index b20e705606b8..68f1cf503904 100644
@@ -131,3 +131,38 @@ int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
 
 	return 0;
 }
+

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 144

Quoted 10 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +10 -0
+/*
+ * SMP call-function callback: each CPU writes its own MSR_IA32_PQR_PLZA_ASSOC
+ * (AMD PLZA).  Invoked via on_each_cpu_mask() with wait=1 so the on-stack
+ * union pointed at by @arg is safe.
+ */
+static void resctrl_kmode_set_one_amd(void *arg)
+{
+	union msr_pqr_plza_assoc *plza = arg;
+
+	wrmsrl(MSR_IA32_PQR_PLZA_ASSOC, plza->full);

fyi ...
commit 2232959db26d ("x86/msr: Switch wrmsrl() users to wrmsrq()") commit b5884070f9da ("x86/msr: Remove wrmsrl()")

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 149

Quoted 5 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +5 -0
+}
+
+/**
+ * resctrl_arch_configure_kmode() - x86/AMD: program PLZA MSR on a CPU subset
+ * @cpu_mask:	CPUs to receive the update (see on_each_cpu_mask() for online subset).

Why is the caveat added? Will resctrl ever provide offline CPUs in the mask?

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 152

Quoted 3 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +3 -0
+ * @closid:	CLOSID field written into the MSR with CLOSID_EN set.
+ * @rmid:	RMID field written into the MSR with RMID_EN set.
+ * @enable:	Value for the PLZA_EN split field.

Please describe the meaning of the fields instead the mechanics of the code that are obvious.

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 155

Quoted 3 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +3 -0
+ *
+ * Context: Do not call with IRQs off or from IRQ context except as allowed for
+ * on_each_cpu_mask(); see kernel/smp.c.

Why is this context caveat needed?

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 157

Quoted 2 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +2 -0
+ */
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid, bool enable)

Please replace "cpumask_var_t cpu_mask" with "const struct cpumask *cpu_mask".

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 168

Quoted 11 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +11 -0
+{
+	union msr_pqr_plza_assoc plza = { 0 };
+
+	plza.split.rmid = rmid;
+	plza.split.rmid_en = 1;
+	plza.split.closid = closid;
+	plza.split.closid_en = 1;
+	plza.split.plza_en = enable;
+
+	on_each_cpu_mask(cpu_mask, resctrl_kmode_set_one_amd, &plza, 1);
+}

function self has been discussed already

Quoted 5 lines
include/linux/resctrl.h +0 -0
index ce28418df00f..570918e57e24 100644

include/linux/resctrl.h bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r); · line 720

Quoted 9 lines
include/linux/resctrl.h +6 -0
@@ -712,6 +712,16 @@ bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r);
  */
 void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg);
 
+/**
+ * resctrl_arch_configure_kmode() - Program MSR_IA32_PQR_PLZA_ASSOC on CPUs in @cpu_mask
+ * @cpu_mask:	Target CPUs; on_each_cpu_mask() applies the callback on the online subset.
+ * @closid:	CLOSID written to the MSR with CLOSID_EN set.
+ * @rmid:	RMID written to the MSR with RMID_EN set.
+ * @enable:	PLZA_EN field value for this update.

This is a resctrl fs API - please replace all the AMD architecture specific implementation details with what the parameters actually mean/represent.

include/linux/resctrl.h bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r); · line 727

Quoted 7 lines
include/linux/resctrl.h +4 -0
+ */
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid,
+				  bool enable);
+
 extern unsigned int resctrl_rmid_realloc_threshold;
 extern unsigned int resctrl_rmid_realloc_limit;
 

Reinette

#26 lore raw

Re: [PATCH v3 04/12] x86,fs/resctrl: Program PLZA through kmode arch hooks

Hi Reinette,

Quoted 14 lines · Reinette Chatre

Hi Babu,

Quoted 10 lines · Babu Moger

AMD Privilege Level Zero Association (PLZA) exposes kernel CLOSID/RMID association through MSR_IA32_PQR_PLZA_ASSOC. Generic resctrl already tracks supported and effective kernel-mode policy in struct resctrl_kmode_cfg, but the architecture layer needs a callable entry point that can push those values into per-CPU hardware on a chosen CPU mask.

Declare resctrl_arch_configure_kmode() in linux/resctrl.h with kernel-doc. Implement it on x86: add an SMP callback that writes MSR_IA32_PQR_PLZA_ASSOC on each targeted CPU, and use on_each_cpu_mask() for the broadcast.

Quoted 8 lines

Above is clear from the patch. Please start with focus on why this patch is needed.

Quoted 2 lines

The hook is unused in this patch; later patches in the series wire it into

Similar to previous work: write changelog in imperative tone and do not refer to patches in series but instead let each patch stand on its own.

Will rewrite the changelog.

Quoted 28 lines
Quoted 28 lines

generic resctrl when an effective kernel-mode policy is selected or a CPU mask changes.

---

---
  arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 35 +++++++++++++++++++++++
  include/linux/resctrl.h                   | 10 +++++++
  2 files changed, 45 insertions(+)
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +7 -0
index b20e705606b8..68f1cf503904 100644
@@ -131,3 +131,38 @@ int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
 
  	return 0;
  }
+
+/*
+ * SMP call-function callback: each CPU writes its own MSR_IA32_PQR_PLZA_ASSOC
+ * (AMD PLZA).  Invoked via on_each_cpu_mask() with wait=1 so the on-stack
+ * union pointed at by @arg is safe.
+ */
+static void resctrl_kmode_set_one_amd(void *arg)
Quoted 9 lines

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 144

Quoted 4 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +4 -0
+{
+	union msr_pqr_plza_assoc *plza = arg;
+
+	wrmsrl(MSR_IA32_PQR_PLZA_ASSOC, plza->full);

fyi ...
commit 2232959db26d ("x86/msr: Switch wrmsrl() users to wrmsrq()") commit b5884070f9da ("x86/msr: Remove wrmsrl()")

Yes. Saw that. Will change it to wrmsrq.

Quoted 7 lines

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 149

Quoted 5 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +5 -0
+}
+
+/**
+ * resctrl_arch_configure_kmode() - x86/AMD: program PLZA MSR on a CPU subset
+ * @cpu_mask:	CPUs to receive the update (see on_each_cpu_mask() for online subset).

Why is the caveat added? Will resctrl ever provide offline CPUs in the mask?

No. Offline CPUs will not be provided. I am not sure why I added that caveat. Probably came from AI review. Will remove.

Quoted 7 lines

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 152

Quoted 4 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +3 -0
+ * @closid:	CLOSID field written into the MSR with CLOSID_EN set.
+ * @rmid:	RMID field written into the MSR with RMID_EN set.
+ * @enable:	Value for the PLZA_EN split field.

Please describe the meaning of the fields instead the mechanics of the code that are obvious.

ok.

Quoted 6 lines

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 155

Quoted 4 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +3 -0
+ *
+ * Context: Do not call with IRQs off or from IRQ context except as allowed for
+ * on_each_cpu_mask(); see kernel/smp.c.

Why is this context caveat needed?

Again, Probably came from AI review. Does not look relevant. Will remove.

Quoted 5 lines

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 157

Quoted 3 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +2 -0
+ */
+void resctrl_arch_configure_kmode(cpumask_var_t cpu_mask, u32 closid, u32 rmid, bool enable)

Please replace "cpumask_var_t cpu_mask" with "const struct cpumask *cpu_mask".

Sure.

Quoted 23 lines

arch/x86/kernel/cpu/resctrl/ctrlmondata.c int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) · line 168

Quoted 12 lines
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +11 -0
+{
+	union msr_pqr_plza_assoc plza = { 0 };
+
+	plza.split.rmid = rmid;
+	plza.split.rmid_en = 1;
+	plza.split.closid = closid;
+	plza.split.closid_en = 1;
+	plza.split.plza_en = enable;
+
+	on_each_cpu_mask(cpu_mask, resctrl_kmode_set_one_amd, &plza, 1);
+}

function self has been discussed already

Quoted 8 lines
include/linux/resctrl.h +0 -0
index ce28418df00f..570918e57e24 100644
@@ -712,6 +712,16 @@ bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r);
   */
  void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg);
 
Quoted 9 lines

include/linux/resctrl.h bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r); · line 720

Quoted 6 lines
include/linux/resctrl.h +6 -0
+/**
+ * resctrl_arch_configure_kmode() - Program MSR_IA32_PQR_PLZA_ASSOC on CPUs in @cpu_mask
+ * @cpu_mask:	Target CPUs; on_each_cpu_mask() applies the callback on the online subset.
+ * @closid:	CLOSID written to the MSR with CLOSID_EN set.
+ * @rmid:	RMID written to the MSR with RMID_EN set.
+ * @enable:	PLZA_EN field value for this update.

This is a resctrl fs API - please replace all the AMD architecture specific implementation details with what the parameters actually mean/represent.

Sure. Will rewrite it.

Thanks

Babu

author reviewer
#27 lore raw

PATCH v3 5/12 x86/resctrl: Initialize supported kernel modes for PLZA

In reply to Babu Moger

Resctrl subsystem tracks which kernel-mode CLOSID/RMID policies the platform can offer via struct resctrl_kmode_cfg and resctrl_arch_get_kmode_support(). AMD PLZA (Privilege Level Zero Association) is the x86 feature that allows kernel traffic to use an assigned CLOSID alone or CLOSID and RMID together.

Report the available kernel-modes when x86 PLZA is enabled.

---
v3: New patch to report all the supported kernel mode by arch.

---
 arch/x86/kernel/cpu/resctrl/core.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
arch/x86/kernel/cpu/resctrl/core.c +15 -0
index 4a8717157e3e..699d8bb82875 100644
@@ -894,6 +894,21 @@ bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
 	}
 }
 
+/**
+ * resctrl_arch_get_kmode_support() - x86: record which kernel-mode policies hardware supports
+ * @kcfg:	Cumulative snapshot; OR bits into @kcfg->kmode (see &struct resctrl_kmode_cfg).
+ *
+ * When PLZA is present (CPUID X86_FEATURE_PLZA), the kernel may assign a CLOSID
+ * for kernel work alone or assign CLOSID and RMID together.  Advertise both
+ * assign-style modes in @kcfg->kmode using &enum resctrl_kernel_modes indices.
+ */
+void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg)
+{
+	if (rdt_cpu_has(X86_FEATURE_PLZA))
+		kcfg->kmode |= BIT(GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU) |
+				BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU);
+}
+
 static __init bool get_mem_config(void)
 {
 	struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_MBA];
Signature · 1 line
2.43.0
maintainer
#28 lore raw

Re: [PATCH v3 05/12] x86/resctrl: Initialize supported kernel modes for PLZA

Hi Babu,

Quoted 20 lines · Babu Moger

Resctrl subsystem tracks which kernel-mode CLOSID/RMID policies the platform can offer via struct resctrl_kmode_cfg and resctrl_arch_get_kmode_support(). AMD PLZA (Privilege Level Zero Association) is the x86 feature that allows kernel traffic to use an assigned CLOSID alone or CLOSID and RMID together.

Report the available kernel-modes when x86 PLZA is enabled.

---
v3: New patch to report all the supported kernel mode by arch.

---
 arch/x86/kernel/cpu/resctrl/core.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
arch/x86/kernel/cpu/resctrl/core.c +0 -0
index 4a8717157e3e..699d8bb82875 100644

arch/x86/kernel/cpu/resctrl/core.c bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt) · line 899

Quoted 6 lines
arch/x86/kernel/cpu/resctrl/core.c +3 -0
@@ -894,6 +894,21 @@ bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
 	}
 }
 
+/**
+ * resctrl_arch_get_kmode_support() - x86: record which kernel-mode policies hardware supports
+ * @kcfg:	Cumulative snapshot; OR bits into @kcfg->kmode (see &struct resctrl_kmode_cfg).

If this is intended to be a cumulative snapshot this is a very subtle requirement for architectures to "do the right thing" here. To make this more robust I think it will be simpler if resctrl fs boots with resctrl_kcfg initialized to expected defaults. Instead of this callback resctrl can add resctrl_set_kmode_support(u32 kmodes) that the architecture *may* use to further initialize the kmodes supported by it. This function is implemented by resctrl fs, instead of architecture, and it can fail if architecture does not support INHERIT_CTRL_AND_MON. This will help to keep struct resctrl_kmode_cfg private to resctrl fs while enforcing any assumptions about which modes are required to be supported.

Quoted 5 lines
arch/x86/kernel/cpu/resctrl/core.c +5 -0
+ *
+ * When PLZA is present (CPUID X86_FEATURE_PLZA), the kernel may assign a CLOSID
+ * for kernel work alone or assign CLOSID and RMID together.  Advertise both
+ * assign-style modes in @kcfg->kmode using &enum resctrl_kernel_modes indices.
+ */

arch/x86/kernel/cpu/resctrl/core.c bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt) · line 914

Quoted 10 lines
arch/x86/kernel/cpu/resctrl/core.c +7 -0
+void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg)
+{
+	if (rdt_cpu_has(X86_FEATURE_PLZA))
+		kcfg->kmode |= BIT(GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU) |
+				BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU);
+}
+
 static __init bool get_mem_config(void)
 {
 	struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_MBA];

Reinette

author reviewer
#29 lore raw

Re: [PATCH v3 05/12] x86/resctrl: Initialize supported kernel modes for PLZA

Hi Reinette,

Quoted 26 lines · Reinette Chatre

Hi Babu,

Quoted 23 lines · Babu Moger

Resctrl subsystem tracks which kernel-mode CLOSID/RMID policies the platform can offer via struct resctrl_kmode_cfg and resctrl_arch_get_kmode_support(). AMD PLZA (Privilege Level Zero Association) is the x86 feature that allows kernel traffic to use an assigned CLOSID alone or CLOSID and RMID together.

Report the available kernel-modes when x86 PLZA is enabled.

---
v3: New patch to report all the supported kernel mode by arch.

---
  arch/x86/kernel/cpu/resctrl/core.c | 15 +++++++++++++++
  1 file changed, 15 insertions(+)
arch/x86/kernel/cpu/resctrl/core.c +0 -0
index 4a8717157e3e..699d8bb82875 100644
@@ -894,6 +894,21 @@ bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
  	}
  }
 
Quoted 13 lines

arch/x86/kernel/cpu/resctrl/core.c bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt) · line 899

Quoted 3 lines
arch/x86/kernel/cpu/resctrl/core.c +3 -0
+/**
+ * resctrl_arch_get_kmode_support() - x86: record which kernel-mode policies hardware supports
+ * @kcfg:	Cumulative snapshot; OR bits into @kcfg->kmode (see &struct resctrl_kmode_cfg).

If this is intended to be a cumulative snapshot this is a very subtle requirement for architectures to "do the right thing" here. To make this more robust I think it will be simpler if resctrl fs boots with resctrl_kcfg initialized to expected defaults. Instead of this callback resctrl can add resctrl_set_kmode_support(u32 kmodes) that the architecture *may* use to further initialize the kmodes supported by it. This function is implemented by resctrl fs, instead of architecture, and it can fail if architecture does not support INHERIT_CTRL_AND_MON. This will help to keep struct resctrl_kmode_cfg private to resctrl fs while enforcing any assumptions about which modes are required to be supported.

Yes, agreed. I will move resctrl_set_kmode_support() to the FS layer and have the architecture code invoke it when setting the kmodes.

That will make the struct resctrl_kmode_cfg private to FS layer.

Thanks
Babu

author reviewer
#30 lore raw

PATCH v3 6/12 fs/resctrl: Initialize the global kernel-mode policy at subsystem init

In reply to Babu Moger

kernel_mode feature needs to add the interface that lets user space choose between INHERIT_CTRL_AND_MON, GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU and GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU. Both the generic resctrl code and the architecture layer need a single shared snapshot of the supported and effective policy plus the resource group that backs the global-assign modes; that snapshot is struct resctrl_kmode_cfg.

Add the file-local resctrl_kcfg and a helper resctrl_kmode_init() that:

- Adds kmode and kmode_cur with BIT(INHERIT_CTRL_AND_MON), the

    universally supported mode and today's behaviour;
  - points k_rdtgrp at rdtgroup_default so global-assign modes have a
    valid backing group from boot;

- calls resctrl_arch_get_kmode_support() so each architecture ORs BIT(<mode>) into kmode for the policies its hardware supports (on x86, AMD PLZA contributes the two global-assign modes).

resctrl_kmode_init() runs from resctrl_init() once the default group has been set up. No user-visible behaviour changes yet; later patches expose kmode_cur via sysfs and act on changes.

---
v3: Moved all the changes to resctrl FS.
Updated changelog.
Arch code only provides supported modes and FS decides which mode to be supported.

v2: New patch to handle PLZA interfaces with /sys/fs/resctrl/info/ directory.

    https://lore.kernel.org/lkml/[email protected]/
---
 fs/resctrl/rdtgroup.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
fs/resctrl/rdtgroup.c +26 -0
index 5dfdaa6f9d8f..a7bfc74897cc 100644
@@ -76,6 +76,13 @@ static void rdtgroup_destroy_root(void);
 
 struct dentry *debugfs_resctrl;
 
+/*
+ * Global kernel-mode resctrl policy: hardware-supported and effective modes
+ * (see struct resctrl_kmode_cfg) and the rdtgroup backing global-assign modes.
+ * Initialized from resctrl_kmode_init() during resctrl_init().
+ */
+static struct resctrl_kmode_cfg resctrl_kcfg;
+
 /*
  * Memory bandwidth monitoring event to use for the default CTRL_MON group
  * and each new CTRL_MON group created by the user.  Only relevant when
@@ -2206,6 +2213,23 @@ static void io_alloc_init(void)
 	}
 }
 
+/*
+ * Baseline the global kernel-mode resctrl configuration at boot.
+ *
+ * Initialise both the supported (kmode) and effective (kmode_cur) policy
+ * with BIT(INHERIT_CTRL_AND_MON), point k_rdtgrp at the default resource
+ * group, and let the arch hook OR in any additional modes the platform
+ * advertises (e.g. on x86, AMD PLZA adds the two global-assign modes).
+ */
+static void resctrl_kmode_init(void)
+{
+	resctrl_kcfg.kmode = BIT(INHERIT_CTRL_AND_MON);
+	resctrl_kcfg.kmode_cur = BIT(INHERIT_CTRL_AND_MON);
+	resctrl_kcfg.k_rdtgrp = &rdtgroup_default;
+
+	resctrl_arch_get_kmode_support(&resctrl_kcfg);
+}
+
 void resctrl_file_fflags_init(const char *config, unsigned long fflags)
 {
 	struct rftype *rft;
@@ -4560,6 +4584,8 @@ int resctrl_init(void)
 
 	io_alloc_init();
 
+	resctrl_kmode_init();
+
 	ret = resctrl_l3_mon_resource_init();
 	if (ret)
 		return ret;
Signature · 1 line
2.43.0
maintainer
#31 lore raw

Re: [PATCH v3 06/12] fs/resctrl: Initialize the global kernel-mode policy at subsystem init

Hi Babu,

Quoted 6 lines · Babu Moger

kernel_mode feature needs to add the interface that lets user space choose between INHERIT_CTRL_AND_MON, GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU and GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU. Both the generic resctrl code and the architecture layer need a single shared snapshot of the supported and effective policy plus the resource group that backs the global-assign modes; that snapshot is struct resctrl_kmode_cfg.

This does not seem to match implementation since this implementation does not actually share struct resctrl_kmode_cfg as described above. Only resctrl_arch_get_kmode_support() exchanges this struct between fs and arch and as already mentioned that usage looks unnecessary. The other arch/fs touch points use either individual members or their properties (like closid/rmid).

As described in response to previous patch I think this can be simplified while also making it more robust.

Quoted 7 lines

Add the file-local resctrl_kcfg and a helper resctrl_kmode_init() that:

- Adds kmode and kmode_cur with BIT(INHERIT_CTRL_AND_MON), the

    universally supported mode and today's behaviour;
  - points k_rdtgrp at rdtgroup_default so global-assign modes have a
    valid backing group from boot;

If the default mode is INHERIT_CTRL_AND_MON then should the default group not be NULL?

Quoted 5 lines

- calls resctrl_arch_get_kmode_support() so each architecture ORs BIT(<mode>) into kmode for the policies its hardware supports (on x86, AMD PLZA contributes the two global-assign modes).

resctrl_kmode_init() runs from resctrl_init() once the default group

resctrl_kmode_init() can be dropped after changes described in response to previous patch. Apart from no longer being necessary I also find that having the kernel mode fully initialized *before* the hotplug handlers run to be simpler.

Quoted 1 line

has been set up. No user-visible behaviour changes yet; later patches

(drop "later patches ...")

Quoted 3 lines

expose kmode_cur via sysfs and act on changes.

Reinette

author reviewer
#32 lore raw

Re: [PATCH v3 06/12] fs/resctrl: Initialize the global kernel-mode policy at subsystem init

Hi Reinette,

Quoted 17 lines · Reinette Chatre

Hi Babu,

Quoted 6 lines · Babu Moger

kernel_mode feature needs to add the interface that lets user space choose between INHERIT_CTRL_AND_MON, GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU and GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU. Both the generic resctrl code and the architecture layer need a single shared snapshot of the supported and effective policy plus the resource group that backs the global-assign modes; that snapshot is struct resctrl_kmode_cfg.

This does not seem to match implementation since this implementation does not actually share struct resctrl_kmode_cfg as described above. Only resctrl_arch_get_kmode_support() exchanges this struct between fs and arch and as already mentioned that usage looks unnecessary. The other arch/fs touch points use either individual members or their properties (like closid/rmid).

Quoted 3 lines

As described in response to previous patch I think this can be simplified while also making it more robust.

Ack.

Quoted 10 lines
Quoted 7 lines

Add the file-local resctrl_kcfg and a helper resctrl_kmode_init() that:

- Adds kmode and kmode_cur with BIT(INHERIT_CTRL_AND_MON), the

     universally supported mode and today's behaviour;
   - points k_rdtgrp at rdtgroup_default so global-assign modes have a
     valid backing group from boot;

If the default mode is INHERIT_CTRL_AND_MON then should the default group not be NULL?

It will be initialized to NULL.

Quoted 11 lines
Quoted 6 lines

- calls resctrl_arch_get_kmode_support() so each architecture ORs BIT(<mode>) into kmode for the policies its hardware supports (on x86, AMD PLZA contributes the two global-assign modes).

resctrl_kmode_init() runs from resctrl_init() once the default group

resctrl_kmode_init() can be dropped after changes described in response to previous patch. Apart from no longer being necessary I also find that having the kernel mode fully initialized *before* the hotplug handlers run to be simpler.

That means resctrl_set_kmode_support() will be called from the architecture layer, likely from core.c within get_rdt_alloc_resources().

The resctrl_set_kmode_support() handler would need to initialize both the default mode and all supported modes.

I see that this is where the hotplug handler gets registered. Therefore, the modes are already initialized before the hotplug handler is set up.

Quoted 5 lines
Quoted 2 lines

has been set up. No user-visible behaviour changes yet; later patches

(drop "later patches ...")

Sure.

Thanks
Babi

maintainer
#33 lore raw

Re: [PATCH v3 06/12] fs/resctrl: Initialize the global kernel-mode policy at subsystem init

Hi Babu,

Quoted 10 lines · Babu Moger
Quoted 9 lines · Reinette Chatre
Quoted 5 lines · Babu Moger

   - calls resctrl_arch_get_kmode_support() so each architecture ORs BIT(<mode>) into kmode for the policies its hardware supports (on x86, AMD PLZA contributes the two global-assign modes).

resctrl_kmode_init() runs from resctrl_init() once the default group

Quoted 8 lines
Quoted 4 lines

resctrl_kmode_init() can be dropped after changes described in response to previous patch. Apart from no longer being necessary I also find that having the kernel mode fully initialized *before* the hotplug handlers run to be simpler.

That means resctrl_set_kmode_support() will be called from the architecture layer, likely from core.c within get_rdt_alloc_resources().

The resctrl_set_kmode_support() handler would need to initialize both the default mode and all supported modes.

I see this differently. Since resctrl_set_kmode_support() is optional for an architecture resctrl fs can just statically initialize the defaults. resctrl_set_kmode_support() would expand the defaults to also accommodate what the architecture supports.

Reinette

author reviewer
#34 lore raw

Re: [PATCH v3 06/12] fs/resctrl: Initialize the global kernel-mode policy at subsystem init

Hi Reinette,

Quoted 18 lines · Reinette Chatre

Hi Babu,

Quoted 15 lines · Babu Moger
Quoted 13 lines · Reinette Chatre
Quoted 5 lines · Babu Moger

   - calls resctrl_arch_get_kmode_support() so each architecture ORs BIT(<mode>) into kmode for the policies its hardware supports (on x86, AMD PLZA contributes the two global-assign modes).

resctrl_kmode_init() runs from resctrl_init() once the default group

resctrl_kmode_init() can be dropped after changes described in response to previous patch. Apart from no longer being necessary I also find that having the kernel mode fully initialized *before* the hotplug handlers run to be simpler.

Quoted 8 lines
Quoted 3 lines

That means resctrl_set_kmode_support() will be called from the architecture layer, likely from core.c within get_rdt_alloc_resources().

The resctrl_set_kmode_support() handler would need to initialize both the default mode and all supported modes.

I see this differently. Since resctrl_set_kmode_support() is optional for an architecture resctrl fs can just statically initialize the defaults. resctrl_set_kmode_support() would expand the defaults to also accommodate what the architecture supports.

Yes. We can do that.

thanks
Babu

author reviewer
#35 lore raw

PATCH v3 7/12 fs/resctrl: Add info/kernel_mode for kernel-mode policy introspection

In reply to Babu Moger

There is no user-visible way today to see which kernel-mode CLOSID/RMID policies the running kernel supports, which one is active, or which resctrl group currently owns the kernel CLOSID/RMID.

Add a read-only top-level sysfs file, info/kernel_mode. It emits one line per mode advertised in resctrl_kcfg.kmode, in stable lowercase spelling derived from enum resctrl_kernel_modes, e.g.:

[inherit_ctrl_and_mon:group=//] global_assign_ctrl_inherit_mon_per_cpu:group=none global_assign_ctrl_assign_mon_per_cpu:group=none

The effective policy (resctrl_kcfg.kmode_cur) is wrapped in square brackets and its :group= suffix names the resctrl group currently bound to the kernel CLOSID/RMID (resctrl_kcfg.k_rdtgrp), formatted as <ctrl>/<mon>/ with empty components left blank. Inactive modes are reported as :group=none.

rdtgroup_mutex is held while printing, matching other info/ show paths.

---
v3: New patch to handle the changed interface file info/kernel_mode.
Changed the group name to "none" if kmode binding is not done. Reinette suggested "uninitialized". "none" seemed more relevent.

---
 fs/resctrl/rdtgroup.c | 74 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)
fs/resctrl/rdtgroup.c +74 -0
index a7bfc74897cc..9cdcfa64c4a2 100644
@@ -988,6 +988,73 @@ static int rdt_last_cmd_status_show(struct kernfs_open_file *of,
 	return 0;
 }
 
+/* Sysfs lines for info/kernel_mode; indexed by &enum resctrl_kernel_modes */
+static const char * const resctrl_mode_str[] = {
+	[INHERIT_CTRL_AND_MON]			= "inherit_ctrl_and_mon",
+	[GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU] = "global_assign_ctrl_inherit_mon_per_cpu",
+	[GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU]	= "global_assign_ctrl_assign_mon_per_cpu",
+};
+
+static_assert(ARRAY_SIZE(resctrl_mode_str) == RESCTRL_NUM_KERNEL_MODES);
+
+/**
+ * resctrl_kernel_mode_show() - Enumerate supported and effective kernel-mode policies
+ * @of: kernfs open file
+ * @seq: output seq_file
+ * @v: unused
+ *
+ * Emits one line per mode advertised in resctrl_kcfg.kmode (each mode is one
+ * BIT(index) per &enum resctrl_kernel_modes).  Every line carries a
+ * ":group=<name>" suffix:
+ *
+ *   - The effective policy (whose BIT matches resctrl_kcfg.kmode_cur) is
+ *     wrapped in square brackets and <name> is the resctrl group that
+ *     currently owns the kernel CLOSID/RMID (resctrl_kcfg.k_rdtgrp),
+ *     formatted as "<ctrl>/<mon>/".  A component is left empty when it
+ *     does not apply: an RDTCTRL_GROUP emits "<ctrl>//", an RDTMON_GROUP
+ *     under the default control group emits "/<mon>/", and an RDTMON_GROUP
+ *     under a named control group emits "<ctrl>/<mon>/".
+ *
+ *   - Other supported but inactive modes are emitted without brackets and
+ *     <name> is reported as "none".
+ *
+ * Context: Called under rdtgroup_mutex like other resctrl sysfs show paths.
+ */
+static int resctrl_kernel_mode_show(struct kernfs_open_file *of,
+				    struct seq_file *seq, void *v)
+{
+	struct rdtgroup *rdtgrp;
+	const char *ctrl, *mon;
+	int i;
+
+	mutex_lock(&rdtgroup_mutex);
+	for (i = 0; i < RESCTRL_NUM_KERNEL_MODES; i++) {
+		if (!(resctrl_kcfg.kmode & BIT(i)))
+			continue;
+
+		if (resctrl_kcfg.kmode_cur != BIT(i)) {
+			seq_printf(seq, "%s:group=none\n",
+				   resctrl_mode_str[i]);
+			continue;
+		}
+
+		rdtgrp = resctrl_kcfg.k_rdtgrp;
+		ctrl = "";
+		mon = "";
+		if (rdtgrp->type == RDTMON_GROUP) {
+			if (rdtgrp->mon.parent != &rdtgroup_default)
+				ctrl = rdtgrp->mon.parent->kn->name;
+			mon = rdtgrp->kn->name;
+		} else {
+			ctrl = rdtgrp->kn->name;
+		}
+		seq_printf(seq, "[%s:group=%s/%s/]\n",
+			   resctrl_mode_str[i], ctrl, mon);
+	}
+	mutex_unlock(&rdtgroup_mutex);
+	return 0;
+}
+
 void *rdt_kn_parent_priv(struct kernfs_node *kn)
 {
 	/*
@@ -1891,6 +1958,13 @@ static struct rftype res_common_files[] = {
 		.seq_show	= rdt_last_cmd_status_show,
 		.fflags		= RFTYPE_TOP_INFO,
 	},
+	{
+		.name		= "kernel_mode",
+		.mode		= 0444,
+		.kf_ops		= &rdtgroup_kf_single_ops,
+		.seq_show	= resctrl_kernel_mode_show,
+		.fflags		= RFTYPE_TOP_INFO,
+	},
 	{
 		.name		= "mbm_assign_on_mkdir",
 		.mode		= 0644,
Signature · 1 line
2.43.0
maintainer
#36 lore raw

Re: [PATCH v3 07/12] fs/resctrl: Add info/kernel_mode for kernel-mode policy introspection

Hi Babu,

How should "introspection" as used in subject be interpreted? This just displays the supported and active kernel modes to user space, no?

Quoted 3 lines · Babu Moger

There is no user-visible way today to see which kernel-mode CLOSID/RMID policies the running kernel supports, which one is active, or which resctrl group currently owns the kernel CLOSID/RMID.

Why should there be? This is a new feature being added in this series. No need to write this as a bugfix.

Quoted 4 lines

Add a read-only top-level sysfs file, info/kernel_mode. It emits one line per mode advertised in resctrl_kcfg.kmode, in stable lowercase spelling derived from enum resctrl_kernel_modes, e.g.:

All these changelogs feel so strange ... as though they are written by somebody who simultaneously has no and full knowledge of resctrl. These verbatim descriptions of what the code does is not necessary. Please start with why the patch is needed.

Quoted 2 lines

[inherit_ctrl_and_mon:group=//]

This is unexpected. There should be no group associated with this default mode. This is how I interpreted our previous discussion ending:
https://lore.kernel.org/lkml/[email protected]/

Quoted 4 lines

global_assign_ctrl_inherit_mon_per_cpu:group=none global_assign_ctrl_assign_mon_per_cpu:group=none

The effective policy (resctrl_kcfg.kmode_cur) is wrapped in square

(needs imperative - please check all changelogs)

Quoted 6 lines

brackets and its :group= suffix names the resctrl group currently bound to the kernel CLOSID/RMID (resctrl_kcfg.k_rdtgrp), formatted as <ctrl>/<mon>/ with empty components left blank. Inactive modes are reported as :group=none.

rdtgroup_mutex is held while printing, matching other info/ show paths.

No need to describe details that can be seen from patch.

Quoted 15 lines

---
v3: New patch to handle the changed interface file info/kernel_mode.
Changed the group name to "none" if kmode binding is not done. Reinette suggested "uninitialized". "none" seemed more relevent.

---
 fs/resctrl/rdtgroup.c | 74 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)
fs/resctrl/rdtgroup.c +0 -0
index a7bfc74897cc..9cdcfa64c4a2 100644

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 995

Quoted 8 lines
fs/resctrl/rdtgroup.c +5 -0
@@ -988,6 +988,73 @@ static int rdt_last_cmd_status_show(struct kernfs_open_file *of,
 	return 0;
 }
 
+/* Sysfs lines for info/kernel_mode; indexed by &enum resctrl_kernel_modes */
+static const char * const resctrl_mode_str[] = {
+	[INHERIT_CTRL_AND_MON]			= "inherit_ctrl_and_mon",
+	[GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU] = "global_assign_ctrl_inherit_mon_per_cpu",
+	[GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU]	= "global_assign_ctrl_assign_mon_per_cpu",

Please make alignment consistent.

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1001

Quoted 6 lines
fs/resctrl/rdtgroup.c +6 -0
+};
+
+static_assert(ARRAY_SIZE(resctrl_mode_str) == RESCTRL_NUM_KERNEL_MODES);
+
+/**
+ * resctrl_kernel_mode_show() - Enumerate supported and effective kernel-mode policies

"Enumerate" -> "Display"?

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1007

Quoted 6 lines
fs/resctrl/rdtgroup.c +6 -0
+ * @of: kernfs open file
+ * @seq: output seq_file
+ * @v: unused
+ *
+ * Emits one line per mode advertised in resctrl_kcfg.kmode (each mode is one
+ * BIT(index) per &enum resctrl_kernel_modes).  Every line carries a

Above is clear from the code. Please instead describe what this means.

Quoted 4 lines
fs/resctrl/rdtgroup.c +4 -0
+ * ":group=<name>" suffix:
+ *
+ *   - The effective policy (whose BIT matches resctrl_kcfg.kmode_cur) is
+ *     wrapped in square brackets and <name> is the resctrl group that

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1021

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+ *     currently owns the kernel CLOSID/RMID (resctrl_kcfg.k_rdtgrp),
+ *     formatted as "<ctrl>/<mon>/".  A component is left empty when it
+ *     does not apply: an RDTCTRL_GROUP emits "<ctrl>//", an RDTMON_GROUP
+ *     under the default control group emits "/<mon>/", and an RDTMON_GROUP
+ *     under a named control group emits "<ctrl>/<mon>/".
+ *
+ *   - Other supported but inactive modes are emitted without brackets and
+ *     <name> is reported as "none".
+ *
+ * Context: Called under rdtgroup_mutex like other resctrl sysfs show paths.

This does not look accurate since it is not called with mutex held but instead takes the mutex itself. Also no need to refer to what other code does.

Quoted 15 lines
fs/resctrl/rdtgroup.c +15 -0
+ */
+static int resctrl_kernel_mode_show(struct kernfs_open_file *of,
+				    struct seq_file *seq, void *v)
+{
+	struct rdtgroup *rdtgrp;
+	const char *ctrl, *mon;
+	int i;
+
+	mutex_lock(&rdtgroup_mutex);
+	for (i = 0; i < RESCTRL_NUM_KERNEL_MODES; i++) {
+		if (!(resctrl_kcfg.kmode & BIT(i)))
+			continue;
+
+		if (resctrl_kcfg.kmode_cur != BIT(i)) {
+			seq_printf(seq, "%s:group=none\n",

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1046

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+				   resctrl_mode_str[i]);
+			continue;
+		}
+
+		rdtgrp = resctrl_kcfg.k_rdtgrp;
+		ctrl = "";
+		mon = "";
+		if (rdtgrp->type == RDTMON_GROUP) {
+			if (rdtgrp->mon.parent != &rdtgroup_default)
+				ctrl = rdtgrp->mon.parent->kn->name;

Isn't default group's kn->name is initialized correctly via rdtgroup_setup_root()->kernfs_create_root()->__kernfs_new_node(root, NULL, "", ...) ?

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1050

Quoted 4 lines
fs/resctrl/rdtgroup.c +4 -0
+			mon = rdtgrp->kn->name;
+		} else {
+			ctrl = rdtgrp->kn->name;
+		}

Can the names not just be initialized directly from kn->name?

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1052

Quoted 2 lines
fs/resctrl/rdtgroup.c +2 -0
+		seq_printf(seq, "[%s:group=%s/%s/]\n",
+			   resctrl_mode_str[i], ctrl, mon);

This is not where I understood our discussion landed. I expected that the display will reflect what can/should be assigned in a mode. For example, mode "inherit_ctrl_and_mon" does not have an associated resource group and should thus not display one, "global_assign_ctrl_inherit_mon_per_cpu" can only be assigned a control group and should thus not display a monitor group also.

Quoted 12 lines
fs/resctrl/rdtgroup.c +5 -0
+	}
+	mutex_unlock(&rdtgroup_mutex);
+	return 0;
+}
+
 void *rdt_kn_parent_priv(struct kernfs_node *kn)
 {
 	/*
@@ -1891,6 +1958,13 @@ static struct rftype res_common_files[] = {
 		.seq_show	= rdt_last_cmd_status_show,
 		.fflags		= RFTYPE_TOP_INFO,
 	},

fs/resctrl/rdtgroup.c static struct rftype res_common_files[] = { · line 1970

Quoted 10 lines
fs/resctrl/rdtgroup.c +7 -0
+	{
+		.name		= "kernel_mode",
+		.mode		= 0444,
+		.kf_ops		= &rdtgroup_kf_single_ops,
+		.seq_show	= resctrl_kernel_mode_show,
+		.fflags		= RFTYPE_TOP_INFO,
+	},
 	{
 		.name		= "mbm_assign_on_mkdir",
 		.mode		= 0644,

Reinette

author reviewer
#37 lore raw

Re: [PATCH v3 07/12] fs/resctrl: Add info/kernel_mode for kernel-mode policy introspection

Hi Reinette,

Quoted 4 lines · Reinette Chatre

Hi Babu,

How should "introspection" as used in subject be interpreted? This just displays the supported and active kernel modes to user space, no?

Yes. Will change it.

Quoted 9 lines · Babu Moger
Quoted 3 lines

There is no user-visible way today to see which kernel-mode CLOSID/RMID policies the running kernel supports, which one is active, or which resctrl group currently owns the kernel CLOSID/RMID.

Why should there be? This is a new feature being added in this series. No need to write this as a bugfix.

Sure.

Quoted 9 lines
Quoted 4 lines

Add a read-only top-level sysfs file, info/kernel_mode. It emits one line per mode advertised in resctrl_kcfg.kmode, in stable lowercase spelling derived from enum resctrl_kernel_modes, e.g.:

All these changelogs feel so strange ... as though they are written by somebody who simultaneously has no and full knowledge of resctrl. These verbatim descriptions of what the code does is not necessary. Please start with why the patch is needed.

Sure. My bad. Will re-write it.

Quoted 7 lines
Quoted 3 lines

   [inherit_ctrl_and_mon:group=//]

This is unexpected. There should be no group associated with this default mode. This is how I interpreted our previous discussion ending:
https://lore.kernel.org/lkml/[email protected]/

Ack.

Quoted 7 lines
Quoted 5 lines

global_assign_ctrl_inherit_mon_per_cpu:group=none global_assign_ctrl_assign_mon_per_cpu:group=none

The effective policy (resctrl_kcfg.kmode_cur) is wrapped in square

(needs imperative - please check all changelogs)

Sure.

Quoted 9 lines
Quoted 7 lines

brackets and its :group= suffix names the resctrl group currently bound to the kernel CLOSID/RMID (resctrl_kcfg.k_rdtgrp), formatted as <ctrl>/<mon>/ with empty components left blank. Inactive modes are reported as :group=none.

rdtgroup_mutex is held while printing, matching other info/ show paths.

No need to describe details that can be seen from patch.

ok.

Quoted 19 lines
Quoted 19 lines

---
v3: New patch to handle the changed interface file info/kernel_mode.
Changed the group name to "none" if kmode binding is not done. Reinette suggested "uninitialized". "none" seemed more relevent.

---
  fs/resctrl/rdtgroup.c | 74 +++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 74 insertions(+)
fs/resctrl/rdtgroup.c +0 -0
index a7bfc74897cc..9cdcfa64c4a2 100644
@@ -988,6 +988,73 @@ static int rdt_last_cmd_status_show(struct kernfs_open_file *of,
  	return 0;
  }
 
Quoted 8 lines

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 995

Quoted 5 lines
fs/resctrl/rdtgroup.c +5 -0
+/* Sysfs lines for info/kernel_mode; indexed by &enum resctrl_kernel_modes */
+static const char * const resctrl_mode_str[] = {
+	[INHERIT_CTRL_AND_MON]			= "inherit_ctrl_and_mon",
+	[GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU] = "global_assign_ctrl_inherit_mon_per_cpu",
+	[GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU]	= "global_assign_ctrl_assign_mon_per_cpu",

Please make alignment consistent.

Sure.

Quoted 8 lines

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1001

Quoted 6 lines
fs/resctrl/rdtgroup.c +6 -0
+};
+
+static_assert(ARRAY_SIZE(resctrl_mode_str) == RESCTRL_NUM_KERNEL_MODES);
+
+/**
+ * resctrl_kernel_mode_show() - Enumerate supported and effective kernel-mode policies

"Enumerate" -> "Display"?

sure.

Quoted 9 lines

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1007

Quoted 7 lines
fs/resctrl/rdtgroup.c +6 -0
+ * @of: kernfs open file
+ * @seq: output seq_file
+ * @v: unused
+ *
+ * Emits one line per mode advertised in resctrl_kcfg.kmode (each mode is one
+ * BIT(index) per &enum resctrl_kernel_modes).  Every line carries a

Above is clear from the code. Please instead describe what this means.

Sure.

Quoted 16 lines
Quoted 5 lines
fs/resctrl/rdtgroup.c +4 -0
+ * ":group=<name>" suffix:
+ *
+ *   - The effective policy (whose BIT matches resctrl_kcfg.kmode_cur) is
+ *     wrapped in square brackets and <name> is the resctrl group that

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1021

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+ *     currently owns the kernel CLOSID/RMID (resctrl_kcfg.k_rdtgrp),
+ *     formatted as "<ctrl>/<mon>/".  A component is left empty when it
+ *     does not apply: an RDTCTRL_GROUP emits "<ctrl>//", an RDTMON_GROUP
+ *     under the default control group emits "/<mon>/", and an RDTMON_GROUP
+ *     under a named control group emits "<ctrl>/<mon>/".
+ *
+ *   - Other supported but inactive modes are emitted without brackets and
+ *     <name> is reported as "none".
+ *
+ * Context: Called under rdtgroup_mutex like other resctrl sysfs show paths.
Quoted 2 lines

This does not look accurate since it is not called with mutex held but instead takes the mutex itself. Also no need to refer to what other code does.

ok.

Quoted 21 lines
Quoted 21 lines
fs/resctrl/rdtgroup.c +20 -0
+ */
+static int resctrl_kernel_mode_show(struct kernfs_open_file *of,
+				    struct seq_file *seq, void *v)
+{
+	struct rdtgroup *rdtgrp;
+	const char *ctrl, *mon;
+	int i;
+
+	mutex_lock(&rdtgroup_mutex);
+	for (i = 0; i < RESCTRL_NUM_KERNEL_MODES; i++) {
+		if (!(resctrl_kcfg.kmode & BIT(i)))
+			continue;
+
+		if (resctrl_kcfg.kmode_cur != BIT(i)) {
+			seq_printf(seq, "%s:group=none\n",
+				   resctrl_mode_str[i]);
+			continue;
+		}
+
+		rdtgrp = resctrl_kcfg.k_rdtgrp;
Quoted 8 lines

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1046

Quoted 5 lines
fs/resctrl/rdtgroup.c +5 -0
+		ctrl = "";
+		mon = "";
+		if (rdtgrp->type == RDTMON_GROUP) {
+			if (rdtgrp->mon.parent != &rdtgroup_default)
+				ctrl = rdtgrp->mon.parent->kn->name;

Isn't default group's kn->name is initialized correctly via rdtgroup_setup_root()->kernfs_create_root()->__kernfs_new_node(root, NULL, "", ...) ?

Yes. that is correct. I will remove the check.

Quoted 7 lines

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1050

Quoted 5 lines
fs/resctrl/rdtgroup.c +4 -0
+			mon = rdtgrp->kn->name;
+		} else {
+			ctrl = rdtgrp->kn->name;
+		}

Can the names not just be initialized directly from kn->name?

Yes. I think so. But I need to know if this is a control group or mon group to make it generic. Let me see if I can optimize this section.

Quoted 8 lines

fs/resctrl/rdtgroup.c static int rdt_last_cmd_status_show(struct kernfs_open_file *of, · line 1052

Quoted 4 lines
fs/resctrl/rdtgroup.c +2 -0
+		seq_printf(seq, "[%s:group=%s/%s/]\n",
+			   resctrl_mode_str[i], ctrl, mon);

This is not where I understood our discussion landed. I expected that the display will reflect what can/should be assigned in a mode. For example, mode "inherit_ctrl_and_mon" does not have an associated resource group and should thus not display one,

Correct.

Quoted 2 lines

"global_assign_ctrl_inherit_mon_per_cpu" can only be assigned a control group and should thus not display a monitor group also.

Yes. True. In that case "mon" is empty. It will print correctly. Let me see if I can optimize this section.

Thanks
Babu

author reviewer
#38 lore raw

PATCH v3 8/12 fs/resctrl: Make info/kernel_mode writable and identify the bound group

In reply to Babu Moger

info/kernel_mode lists the kernel-mode CLOSID/RMID policies the kernel supports and the one currently active, but user space has no way to switch policies or rebind to a different rdtgroup, and the file does not name the group that owns the kernel CLOSID/RMID.

Make info/kernel_mode writable. The format used by both read and write is one line per mode:

inherit_ctrl_and_mon:group=none [global_assign_ctrl_inherit_mon_per_cpu:group=g1//] global_assign_ctrl_assign_mon_per_cpu:group=none

The active mode is wrapped in "[...]" and ":group=<ctrl>/<mon>/" names the bound rdtgroup ("//" for the default control group). Inactive modes report ":group=none". Documented in Documentation/filesystems/resctrl.rst.

The write path strims input, strips the optional "[...]", validates the mode against resctrl_kcfg.kmode, and resolves the optional ":group=" suffix via the new helper rdtgroup_by_kmode_path(). An omitted suffix or an INHERIT-mode write binds to the default group. On success, rdtgroup_config_kmode_clear() tears down the previous binding and rdtgroup_config_kmode() programs the new one before resctrl_kcfg.k_rdtgrp and resctrl_kcfg.kmode_cur are updated under rdtgroup_mutex. Allocation failures in the helpers are propagated so the write fails atomically.

Add struct rdtgroup fields kmode and kmode_cpu_mask to track the per-group binding.

---
v3: New patch to handle the changed interface file info/kernel_mode.

---
 Documentation/filesystems/resctrl.rst |  51 ++++
 fs/resctrl/internal.h                 |   6 +
 fs/resctrl/rdtgroup.c                 | 375 +++++++++++++++++++++++++-
 3 files changed, 431 insertions(+), 1 deletion(-)
Documentation/filesystems/resctrl.rst +51 -0
index b003bed339fd..89fbf8b4fb2a 100644
@@ -522,6 +522,57 @@ conveyed in the error returns from file operations. E.g.
 	# cat info/last_cmd_status
 	mask f7 has non-consecutive 1-bits
 
+"kernel_mode":
+	In the top level of the "info" directory, "kernel_mode" controls how
+	resource allocation and monitoring work in kernel mode. This is used on
+	some platforms to assign a dedicated CLOSID and/or RMID to kernel threads.
+
+	Reading the file lists supported kernel modes, one per line.  Each line
+	carries a ":group=<spec>" suffix that identifies the resctrl group that
+	owns the kernel CLOSID/RMID for that mode.  The currently active mode is
+	wrapped in square brackets and reports the bound group as
+	"<ctrl>/<mon>/", with empty components when they do not apply (a control
+	group emits "<ctrl>//", a monitor group under the default control group
+	emits "/<mon>/").  Other supported modes are shown without brackets and
+	report "none" because no group is bound to them.  Example::
+
+	  # cat info/kernel_mode
+	  [inherit_ctrl_and_mon:group=//]
+	  global_assign_ctrl_inherit_mon_per_cpu:group=none
+	  global_assign_ctrl_assign_mon_per_cpu:group=none
+
+	Writing one line (terminated by a newline) selects the active mode and
+	binds it to a resctrl group.  The line uses the same format that the
+	read path emits, "<mode>[:group=<ctrl>/<mon>/]", and a surrounding
+	"[...]" pair (as printed for the active line) is accepted and stripped.
+	The ":group=<spec>" suffix is optional; when omitted the default group
+	is used.  The mode must match one of the supported names exactly,
+	and modes not advertised by the platform cannot be set.  The display-only
+	"group=none" form is rejected.  Errors are reported in
+	"info/last_cmd_status".  Example::
+
+	  # echo "global_assign_ctrl_assign_mon_per_cpu:group=ctrl/mon1/" \
+	         > info/kernel_mode
+	  # cat info/kernel_mode
+	  inherit_ctrl_and_mon:group=none
+	  global_assign_ctrl_inherit_mon_per_cpu:group=none
+	  [global_assign_ctrl_assign_mon_per_cpu:group=ctrl1/mon1/]
+
+	  # echo "inherit_ctrl_and_mon" > info/kernel_mode
+	  # cat info/kernel_mode
+	  [inherit_ctrl_and_mon:group=//]
+	  global_assign_ctrl_inherit_mon_per_cpu:group=none
+	  global_assign_ctrl_assign_mon_per_cpu:group=none
+
+	Modes:
+
+	- "inherit_ctrl_and_mon": Kernel uses the same CLOSID and RMID as the
+	  current user-space task (default).
+	- "global_assign_ctrl_inherit_mon_per_cpu": One CLOSID is assigned for all
+	  kernel work; RMID is still inherited from user space.
+	- "global_assign_ctrl_assign_mon_per_cpu": One resource group (CLOSID and RMID)
+	  is assigned for all kernel work.
+
 Resource alloc and monitor groups
 =================================
 
fs/resctrl/internal.h +6 -0
index 1a9b29119f88..9435ce663f54 100644
@@ -216,6 +216,10 @@ struct mongroup {
  * @mon:			mongroup related data
  * @mode:			mode of resource group
  * @mba_mbps_event:		input monitoring event id when mba_sc is enabled
+ * @kmode:			true if this group is currently bound as the kernel-mode
+ *				CLOSID/RMID owner (resctrl_kcfg.k_rdtgrp)
+ * @kmode_cpu_mask:		CPUs scoped for this group's kernel-mode binding;
+ *				when empty, all online CPUs are used
  * @plr:			pseudo-locked region
  */
 struct rdtgroup {
@@ -229,6 +233,8 @@ struct rdtgroup {
 	struct mongroup			mon;
 	enum rdtgrp_mode		mode;
 	enum resctrl_event_id		mba_mbps_event;
+	bool				kmode;
+	struct cpumask			kmode_cpu_mask;
 	struct pseudo_lock_region	*plr;
 };
 
fs/resctrl/rdtgroup.c +374 -1

389 lines not on this page · raw message

Signature · 1 line
2.43.0
maintainer
#39 lore raw

Re: [PATCH v3 08/12] fs/resctrl: Make info/kernel_mode writable and identify the bound group

Hi Babu,

Quoted 1 line · Babu Moger

info/kernel_mode lists the kernel-mode CLOSID/RMID policies the kernel

(also here please drop the x86 specific details and consider the resctrl fs changes to be valid from MPAM perspective also)

Quoted 3 lines

supports and the one currently active, but user space has no way to switch policies or rebind to a different rdtgroup, and the file does not name the group that owns the kernel CLOSID/RMID.

This adds a new feature. No need to describe this change as a bugfix.

Quoted 3 lines

Make info/kernel_mode writable. The format used by both read and write is one line per mode:

This sounds like multiple modes can be written to the file as long as they are separated by newline? I do not think it should be needed to support write of more than one mode at a time.

Quoted 9 lines

inherit_ctrl_and_mon:group=none [global_assign_ctrl_inherit_mon_per_cpu:group=g1//] global_assign_ctrl_assign_mon_per_cpu:group=none

The active mode is wrapped in "[...]" and ":group=<ctrl>/<mon>/" names the bound rdtgroup ("//" for the default control group). Inactive modes report ":group=none". Documented in Documentation/filesystems/resctrl.rst.

Above describes the output of the file. This changelog can just focus on what needs to be supported when user space writes to the file.

Quoted 2 lines

The write path strims input, strips the optional "[...]", validates

strims?

Wait, why support the brackets as input? This seems unnecessary.

Quoted 8 lines

the mode against resctrl_kcfg.kmode, and resolves the optional ":group=" suffix via the new helper rdtgroup_by_kmode_path(). An omitted suffix or an INHERIT-mode write binds to the default group. On success, rdtgroup_config_kmode_clear() tears down the previous binding and rdtgroup_config_kmode() programs the new one before resctrl_kcfg.k_rdtgrp and resctrl_kcfg.kmode_cur are updated under rdtgroup_mutex. Allocation failures in the helpers are propagated so the write fails atomically.

This also reads like it just describes the code.

Quoted 3 lines

Add struct rdtgroup fields kmode and kmode_cpu_mask to track the per-group binding.

Please do not just describe the code but *why* this change is needed and what it means and how it is used.

Quoted 15 lines

---
v3: New patch to handle the changed interface file info/kernel_mode.

---
 Documentation/filesystems/resctrl.rst |  51 ++++
 fs/resctrl/internal.h                 |   6 +
 fs/resctrl/rdtgroup.c                 | 375 +++++++++++++++++++++++++-
 3 files changed, 431 insertions(+), 1 deletion(-)
Documentation/filesystems/resctrl.rst +0 -0
index b003bed339fd..89fbf8b4fb2a 100644

Documentation/filesystems/resctrl.rst conveyed in the error returns from file operations. E.g. · line 525

Quoted 4 lines
Documentation/filesystems/resctrl.rst +1 -0
@@ -522,6 +522,57 @@ conveyed in the error returns from file operations. E.g.
 	# cat info/last_cmd_status
 	mask f7 has non-consecutive 1-bits
 
+"kernel_mode":

(dropping the documentation here since I believe earlier comments apply)

...

fs/resctrl/internal.h struct mongroup { · line 220

Quoted 10 lines
fs/resctrl/internal.h +2 -0
index 1a9b29119f88..9435ce663f54 100644
@@ -216,6 +216,10 @@ struct mongroup {
  * @mon:			mongroup related data
  * @mode:			mode of resource group
  * @mba_mbps_event:		input monitoring event id when mba_sc is enabled
+ * @kmode:			true if this group is currently bound as the kernel-mode
+ *				CLOSID/RMID owner (resctrl_kcfg.k_rdtgrp)

(drop CLOSID/RMID)

fs/resctrl/internal.h struct mongroup { · line 222

Quoted 2 lines
fs/resctrl/internal.h +2 -0
+ * @kmode_cpu_mask:		CPUs scoped for this group's kernel-mode binding;
+ *				when empty, all online CPUs are used

Why does "empty" signify "all online CPUs"? This complicates implementation and creates different interface from existing CPUs interface of resource groups.

Quoted 17 lines
fs/resctrl/internal.h +2 -0
  * @plr:			pseudo-locked region
  */
 struct rdtgroup {
@@ -229,6 +233,8 @@ struct rdtgroup {
 	struct mongroup			mon;
 	enum rdtgrp_mode		mode;
 	enum resctrl_event_id		mba_mbps_event;
+	bool				kmode;
+	struct cpumask			kmode_cpu_mask;
 	struct pseudo_lock_region	*plr;
 };
 
fs/resctrl/rdtgroup.c +0 -0
index 9cdcfa64c4a2..5383b4eb23ed 100644

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1063

Quoted 9 lines
fs/resctrl/rdtgroup.c +6 -0
@@ -1055,6 +1055,378 @@ static int resctrl_kernel_mode_show(struct kernfs_open_file *of,
 	return 0;
 }
 
+/**
+ * rdtgroup_config_kmode() - Push @rdtgrp's kernel CLOSID/RMID to hardware
+ * @rdtgrp:	Resctrl group whose CLOSID/RMID should be programmed.
+ *
+ * Derives CLOSID/RMID from @rdtgrp->type:
+ *   - RDTMON_GROUP: parent control group's CLOSID with the monitor group's RMID.

This seem unnecessary since when a monitor group is created it's closid is inherited from it's control group?

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1074

Quoted 11 lines
fs/resctrl/rdtgroup.c +11 -0
+ *   - RDTCTRL_GROUP: the control group's own CLOSID and default RMID.
+ *
+ * Calls resctrl_arch_configure_kmode() with the kernel-mode binding enabled
+ * on the online subset of @rdtgrp->kmode_cpu_mask (or all online CPUs when
+ * that mask is empty), and disabled on the complementary online CPUs so
+ * stale enable bits from a previously bound group are cleared in the same
+ * reprogram step.  The caller (resctrl_kernel_mode_write()) is responsible
+ * for validating that the (kmode, group type) pair is permitted before
+ * invoking this helper.
+ *
+ * Context: Caller must hold rdtgroup_mutex.

Please use lockdep_assert_held(&rdtgroup_mutex) instead. See "Documenting locking requirements" in Documentation/process/maintainer-tip.rst

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1083

Quoted 9 lines
fs/resctrl/rdtgroup.c +9 -0
+ *
+ * Return: 0 on success, -EINVAL for a pseudo-locked group, -ENOMEM if
+ * cpumask allocation fails.
+ */
+static int rdtgroup_config_kmode(struct rdtgroup *rdtgrp)
+{
+	cpumask_var_t enable_mask, disable_mask;
+	u32 closid, rmid;
+	bool need_disable;

(needs reverse fir)

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1093

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+
+	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
+		rdt_last_cmd_puts("Resource group is pseudo-locked\n");
+		return -EINVAL;
+	}
+
+	if (!zalloc_cpumask_var(&enable_mask, GFP_KERNEL))
+		return -ENOMEM;
+
+	need_disable = !cpumask_empty(&rdtgrp->kmode_cpu_mask);

As I understand rdtgroup_config_kmode() is called when the kernel mode is switched. Also, earlier patches made it explicit that "Default scope is all online CPUs".

It is not clear to me how kmode_cpu_mask is initialized here ... it almost seems as though if a resource was associated with a mode at some point and received some CPU changes then when the mode switches between some other resource groups and then back to the original then the old cpu_mask will be used on the mode switch. Should the resource group's cpu_mask not be re-initialized to all online CPUs? If done then all of this cpu_mask wrangling seems unnecessary to me, just use all online CPUs?

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1105

Quoted 12 lines
fs/resctrl/rdtgroup.c +12 -0
+	if (need_disable && !zalloc_cpumask_var(&disable_mask, GFP_KERNEL)) {
+		free_cpumask_var(enable_mask);
+		return -ENOMEM;
+	}
+
+	if (rdtgrp->type == RDTMON_GROUP) {
+		closid = rdtgrp->mon.parent->closid;
+		rmid = rdtgrp->mon.rmid;
+	} else {
+		closid = rdtgrp->closid;
+		rmid = rdtgrp->mon.rmid;
+	}

Considering MON group inherits the CLOSID if its parent, can above be simplified to just be?

	closid = rdtgrp->closid;
	rmid = rdtgrp->mon.rmid;
Quoted 66 lines
fs/resctrl/rdtgroup.c +66 -0
+
+	/*
+	 * Empty kmode_cpu_mask: enable on every online CPU.  Otherwise enable
+	 * only CPUs in the group mask and explicitly clear on other online CPUs
+	 * so a previously bound group's enable bits don't linger.
+	 */
+	if (!need_disable) {
+		cpumask_copy(enable_mask, cpu_online_mask);
+	} else {
+		cpumask_copy(enable_mask, &rdtgrp->kmode_cpu_mask);
+		cpumask_andnot(disable_mask, cpu_online_mask, &rdtgrp->kmode_cpu_mask);
+	}
+
+	if (!cpumask_empty(enable_mask))
+		resctrl_arch_configure_kmode(enable_mask, closid, rmid, true);
+
+	if (need_disable && !cpumask_empty(disable_mask))
+		resctrl_arch_configure_kmode(disable_mask, closid, rmid, false);
+
+	rdtgrp->kmode = true;
+
+	free_cpumask_var(enable_mask);
+	if (need_disable)
+		free_cpumask_var(disable_mask);
+
+	return 0;
+}
+
+/**
+ * rdtgroup_config_kmode_clear() - Tear down the kernel-mode binding on @rdtgrp
+ * @rdtgrp:	Resctrl group whose kernel-mode binding is being released.
+ *		May be %NULL when no group is currently bound, in which case
+ *		this is a no-op.
+ * @kmode:	Kernel-mode policy currently active on @rdtgrp, as a
+ *		BIT(&enum resctrl_kernel_modes) value.  When this is
+ *		BIT(INHERIT_CTRL_AND_MON) the hardware tear-down is skipped
+ *		because no MSR was previously programmed.
+ *
+ * Disables the kernel-mode binding on the CPUs @rdtgrp covers (its
+ * @kmode_cpu_mask, or all online CPUs when that mask is empty) and resets
+ * the per-group bookkeeping (@kmode and @kmode_cpu_mask).  This is the
+ * disable counterpart of rdtgroup_config_kmode() and exists so that a write
+ * that transitions the active mode to BIT(INHERIT_CTRL_AND_MON) -- which
+ * skips rdtgroup_config_kmode() entirely -- still tears down the previously
+ * bound group instead of leaving stale enable bits behind.
+ *
+ * On allocation failure the function returns -ENOMEM and leaves both the
+ * hardware state and @rdtgrp's bookkeeping unchanged so the caller can fail
+ * the operation atomically and last_cmd_status reflects reality.
+ *
+ * Context: Caller must hold rdtgroup_mutex.
+ *
+ * Return: 0 on success (including the @rdtgrp == %NULL and INHERIT cases),
+ * -ENOMEM if cpumask allocation fails.
+ */
+static int rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
+{
+	cpumask_var_t disable_mask;
+	u32 closid, rmid;
+
+	if (!rdtgrp)
+		return 0;
+
+	if (kmode == BIT(INHERIT_CTRL_AND_MON))
+		goto out_clear;
+

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1181

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+	if (!zalloc_cpumask_var(&disable_mask, GFP_KERNEL))
+		return -ENOMEM;
+
+	if (rdtgrp->type == RDTMON_GROUP) {
+		closid = rdtgrp->mon.parent->closid;
+		rmid = rdtgrp->mon.rmid;
+	} else {
+		closid = rdtgrp->closid;
+		rmid = rdtgrp->mon.rmid;
+	}

Same comment as above ... but actually, why is closid/rmid needed at all? This function is intended to *reset* the kernel mode so needing a valid/active closid and rmid does not look right.

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1186

Quoted 5 lines
fs/resctrl/rdtgroup.c +5 -0
+
+	if (cpumask_empty(&rdtgrp->kmode_cpu_mask))
+		cpumask_copy(disable_mask, cpu_online_mask);
+	else
+		cpumask_copy(disable_mask, &rdtgrp->kmode_cpu_mask);

Having kmode_cpu_mask accurately reflect the online CPUs will simplify this to not need any of this wrangling and kmode_cpu_mask can just be used directly.

Quoted 12 lines
fs/resctrl/rdtgroup.c +12 -0
+
+	resctrl_arch_configure_kmode(disable_mask, closid, rmid, false);
+	free_cpumask_var(disable_mask);
+
+out_clear:
+	cpumask_clear(&rdtgrp->kmode_cpu_mask);
+	rdtgrp->kmode = false;
+	return 0;
+}
+
+/**
+ * rdtgroup_by_kmode_path() - Resolve a "<ctrl>/<mon>/" path to an rdtgroup

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1208

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+ * @ctrl_name:	Control-group name, or "" for the default control group.
+ * @mon_name:	Monitor-group name, or "" to select the control group itself.
+ *
+ * Matches the path syntax emitted by resctrl_kernel_mode_show():
+ *   "//"            - the default control group
+ *   "<ctrl>//"      - control group @ctrl_name
+ *   "/<mon>/"       - monitor group @mon_name under the default control group
+ *   "<ctrl>/<mon>/" - monitor group @mon_name under control group @ctrl_name
+ *
+ * Context: Caller must hold rdtgroup_mutex.

(lockdep)

Quoted 84 lines
fs/resctrl/rdtgroup.c +84 -0
+ *
+ * Return: Pointer to the matching rdtgroup, &rdtgroup_default when both
+ * names are empty (the show form "//"), or NULL if no such group exists.
+ */
+static struct rdtgroup *rdtgroup_by_kmode_path(const char *ctrl_name,
+					       const char *mon_name)
+{
+	struct rdtgroup *rdtg, *parent = NULL, *crg;
+
+	/* Show emits "//" for the default control group; round-trip it here. */
+	if (!*ctrl_name && !*mon_name)
+		return &rdtgroup_default;
+
+	/* Control-group-only form: "<ctrl>//". */
+	if (!*mon_name) {
+		list_for_each_entry(rdtg, &rdt_all_groups, rdtgroup_list) {
+			if (rdtg->type != RDTCTRL_GROUP)
+				continue;
+			if (!strcmp(rdt_kn_name(rdtg->kn), ctrl_name))
+				return rdtg;
+		}
+		return NULL;
+	}
+
+	/* Monitor-group form: locate the parent control group first. */
+	if (!*ctrl_name) {
+		parent = &rdtgroup_default;
+	} else {
+		list_for_each_entry(rdtg, &rdt_all_groups, rdtgroup_list) {
+			if (rdtg->type != RDTCTRL_GROUP)
+				continue;
+			if (!strcmp(rdt_kn_name(rdtg->kn), ctrl_name)) {
+				parent = rdtg;
+				break;
+			}
+		}
+		if (!parent)
+			return NULL;
+	}
+
+	list_for_each_entry(crg, &parent->mon.crdtgrp_list, mon.crdtgrp_list)
+		if (!strcmp(rdt_kn_name(crg->kn), mon_name))
+			return crg;
+	return NULL;
+}
+
+/**
+ * resctrl_kernel_mode_write() - Select kernel mode and bind group via info/kernel_mode
+ * @of:		kernfs file handle.
+ * @buf:	One line in the same format emitted by resctrl_kernel_mode_show(),
+ *		i.e. "<mode>[:group=<ctrl>/<mon>/]" with an optional surrounding
+ *		"[...]"; must end with a newline.  The ":group=<spec>" suffix is
+ *		optional -- when omitted the default control group
+ *		(&rdtgroup_default) is used.
+ * @nbytes:	Length of @buf.
+ * @off:	File offset (unused).
+ *
+ * Parses @buf, validates that <mode> is listed in resctrl_mode_str[] and is
+ * supported by the platform (resctrl_kcfg.kmode), resolves <ctrl>/<mon>/ to
+ * an existing rdtgroup (or picks &rdtgroup_default if no group was specified
+ * or if the new mode is INHERIT), clears any previous binding via
+ * rdtgroup_config_kmode_clear(), programs hardware via
+ * rdtgroup_config_kmode() when @kmode is not BIT(INHERIT_CTRL_AND_MON), and
+ * on success updates resctrl_kcfg.k_rdtgrp and resctrl_kcfg.kmode_cur.  The
+ * display-only "group=none" form produced by show for inactive modes is
+ * rejected.  Errors are reported in last_cmd_status.
+ *
+ * Return: @nbytes on success, negative errno with last_cmd_status set on error.
+ */
+static ssize_t resctrl_kernel_mode_write(struct kernfs_open_file *of,
+					 char *buf, size_t nbytes, loff_t off)
+{
+	char *mode_str, *group_str, *slash;
+	const char *ctrl_name, *mon_name;
+	struct rdtgroup *rdtgrp;
+	int ret = 0;
+	size_t len;
+	u32 kmode;
+	int i;
+
+	if (nbytes == 0 || buf[nbytes - 1] != '\n')
+		return -EINVAL;
+	buf[nbytes - 1] = '\0';
+

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1302

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+	/* Tolerate surrounding whitespace before the bracket/mode parsing. */
+	buf = strim(buf);
+	len = strlen(buf);
+
+	/* Strip the optional "[...]" that show uses to mark the active line. */
+	if (len >= 2 && buf[0] == '[' && buf[len - 1] == ']') {
+		buf[len - 1] = '\0';
+		buf++;
+		len -= 2;
+	}

I do not think the brackets should be valid input.

Quoted 21 lines
fs/resctrl/rdtgroup.c +21 -0
+
+	/*
+	 * Split "<mode>:group=<spec>"; the ":group=<spec>" suffix is optional
+	 * and when omitted the default control group (&rdtgroup_default) is used.
+	 */
+	group_str = strstr(buf, ":group=");
+	if (group_str) {
+		*group_str = '\0';
+		group_str += strlen(":group=");
+	}
+	mode_str = buf;
+
+	mutex_lock(&rdtgroup_mutex);
+	rdt_last_cmd_clear();
+
+	for (i = 0; i < RESCTRL_NUM_KERNEL_MODES; i++)
+		if (!strcmp(mode_str, resctrl_mode_str[i]))
+			break;
+	if (i == RESCTRL_NUM_KERNEL_MODES) {
+		rdt_last_cmd_puts("Unknown kernel mode\n");
+		ret = -EINVAL;

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1333

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+		goto out_unlock;
+	}
+
+	if (!(resctrl_kcfg.kmode & BIT(i))) {
+		rdt_last_cmd_puts("Kernel mode not available\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	kmode = BIT(i);

Can kmode be of enum type to be assigned the actual enum value to avoid all these BIT(enum value) usages?

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1344

Quoted 11 lines
fs/resctrl/rdtgroup.c +11 -0
+
+	if (!group_str) {
+		/* No ":group=" suffix: fall back to the default control group. */
+		rdtgrp = &rdtgroup_default;
+	} else if (!strcmp(group_str, "none")) {
+		/* Display-only placeholder emitted by show; not selectable. */
+		rdt_last_cmd_puts("Cannot bind to 'none' group\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	} else {
+		/* Require exactly "<ctrl>/<mon>/" - two '/' with the second terminating. */

User should not be expected to provide monitor group when the monitoring is inherited.

Quoted 22 lines
fs/resctrl/rdtgroup.c +22 -0
+		slash = strchr(group_str, '/');
+		if (!slash) {
+			rdt_last_cmd_puts("Group must be <ctrl>/<mon>/\n");
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+		*slash = '\0';
+		ctrl_name = group_str;
+		mon_name = slash + 1;
+		slash = strchr(mon_name, '/');
+		if (!slash || slash[1] != '\0') {
+			rdt_last_cmd_puts("Group must be <ctrl>/<mon>/\n");
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+		*slash = '\0';
+
+		rdtgrp = rdtgroup_by_kmode_path(ctrl_name, mon_name);
+		if (!rdtgrp) {
+			rdt_last_cmd_puts("Group not found\n");
+			ret = -EINVAL;
+			goto out_unlock;

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1376

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+		}
+	}
+
+	/*
+	 * INHERIT mode binds nothing; force the bound group to the default so
+	 * round-trips with show (which prints "group=//") are stable and any
+	 * user-supplied :group= suffix is silently normalised.
+	 */
+	if (kmode == BIT(INHERIT_CTRL_AND_MON))
+		rdtgrp = &rdtgroup_default;

rdtgrp = NULL ?

Quoted 31 lines
fs/resctrl/rdtgroup.c +31 -0
+
+	/* No-op if the same mode is already active on the same group. */
+	if (resctrl_kcfg.kmode_cur == kmode && resctrl_kcfg.k_rdtgrp == rdtgrp)
+		goto out_unlock;
+
+	/*
+	 * global_assign_ctrl_assign_mon_per_cpu binds one CLOSID and RMID for
+	 * all kernel work (Documentation/filesystems/resctrl.rst uses
+	 * "<ctrl>/<mon>/", i.e. an RDTMON_GROUP).
+	 *
+	 * global_assign_ctrl_inherit_mon_per_cpu assigns one CLOSID globally
+	 * while leaving RMID inheritance to user contexts; that uses the
+	 * control group's CLOSID slot only, i.e. an RDTCTRL_GROUP.
+	 */
+	if (kmode == BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU) &&
+	    rdtgrp->type != RDTMON_GROUP) {
+		rdt_last_cmd_puts("global_assign_ctrl_assign_mon_per_cpu requires a monitor group\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+	if (kmode == BIT(GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU) &&
+	    rdtgrp->type != RDTCTRL_GROUP) {
+		rdt_last_cmd_puts("global_assign_ctrl_inherit_mon_per_cpu requires a control group\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	/* Switching to a different group: release the old binding first. */
+	if (resctrl_kcfg.k_rdtgrp != rdtgrp) {
+		ret = rdtgroup_config_kmode_clear(resctrl_kcfg.k_rdtgrp,
+						  resctrl_kcfg.kmode_cur);

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1417

Quoted 10 lines
fs/resctrl/rdtgroup.c +10 -0
+		if (ret) {
+			rdt_last_cmd_puts("Failed to release previous kernel-mode binding\n");
+			goto out_unlock;
+		}
+	}
+
+	if (kmode != BIT(INHERIT_CTRL_AND_MON)) {
+		ret = rdtgroup_config_kmode(rdtgrp);
+		if (ret) {
+			rdt_last_cmd_puts("Kernel mode change failed\n");

If it fails here then previous binding was released successfully but new binding failed. What is state of system?

Quoted 17 lines
fs/resctrl/rdtgroup.c +12 -0
+			goto out_unlock;
+		}
+	}
+
+	resctrl_kcfg.k_rdtgrp = rdtgrp;
+	resctrl_kcfg.kmode_cur = kmode;
+
+out_unlock:
+	mutex_unlock(&rdtgroup_mutex);
+	return ret ?: nbytes;
+}
+
 void *rdt_kn_parent_priv(struct kernfs_node *kn)
 {
 	/*
@@ -1960,9 +2332,10 @@ static struct rftype res_common_files[] = {
 	},

fs/resctrl/rdtgroup.c static struct rftype res_common_files[] = { · line 2341

Quoted 10 lines
fs/resctrl/rdtgroup.c +2 -1
 	{
 		.name		= "kernel_mode",
-		.mode		= 0444,
+		.mode		= 0644,
 		.kf_ops		= &rdtgroup_kf_single_ops,
 		.seq_show	= resctrl_kernel_mode_show,
+		.write		= resctrl_kernel_mode_write,
 		.fflags		= RFTYPE_TOP_INFO,
 	},
 	{

Reinette

author reviewer
#40 lore raw

Re: [PATCH v3 08/12] fs/resctrl: Make info/kernel_mode writable and identify the bound group

Hi Reinette,

Quoted 7 lines · Reinette Chatre

Hi Babu,

Quoted 1 line · Babu Moger

info/kernel_mode lists the kernel-mode CLOSID/RMID policies the kernel

(also here please drop the x86 specific details and consider the resctrl fs changes to be valid from MPAM perspective also)

Sure.

Quoted 6 lines
Quoted 4 lines

supports and the one currently active, but user space has no way to switch policies or rebind to a different rdtgroup, and the file does not name the group that owns the kernel CLOSID/RMID.

This adds a new feature. No need to describe this change as a bugfix.

ok.

Quoted 8 lines
Quoted 4 lines

Make info/kernel_mode writable. The format used by both read and write is one line per mode:

This sounds like multiple modes can be written to the file as long as they are separated by newline? I do not think it should be needed to support write of more than one mode at a time.

Will change it.

Quoted 15 lines
Quoted 10 lines

   inherit_ctrl_and_mon:group=none
   [global_assign_ctrl_inherit_mon_per_cpu:group=g1//]
   global_assign_ctrl_assign_mon_per_cpu:group=none

The active mode is wrapped in "[...]" and ":group=<ctrl>/<mon>/" names the bound rdtgroup ("//" for the default control group). Inactive modes report ":group=none". Documented in Documentation/filesystems/resctrl.rst.

Above describes the output of the file. This changelog can just focus on what needs to be supported when user space writes to the file.

Quoted 1 line
Quoted 5 lines
Quoted 1 line

The write path strims input, strips the optional "[...]", validates

strims?

Wait, why support the brackets as input? This seems unnecessary.

Will remove it.

Quoted 10 lines
Quoted 9 lines

the mode against resctrl_kcfg.kmode, and resolves the optional ":group=" suffix via the new helper rdtgroup_by_kmode_path(). An omitted suffix or an INHERIT-mode write binds to the default group. On success, rdtgroup_config_kmode_clear() tears down the previous binding and rdtgroup_config_kmode() programs the new one before resctrl_kcfg.k_rdtgrp and resctrl_kcfg.kmode_cur are updated under rdtgroup_mutex. Allocation failures in the helpers are propagated so the write fails atomically.

Quoted 2 lines

This also reads like it just describes the code.

Will re-write it.

Quoted 6 lines
Quoted 3 lines

Add struct rdtgroup fields kmode and kmode_cpu_mask to track the per-group binding.

Please do not just describe the code but *why* this change is needed and what it means and how it is used.

ok.

Quoted 19 lines
Quoted 19 lines

---
v3: New patch to handle the changed interface file info/kernel_mode.

---
  Documentation/filesystems/resctrl.rst |  51 ++++
  fs/resctrl/internal.h                 |   6 +
  fs/resctrl/rdtgroup.c                 | 375 +++++++++++++++++++++++++-
  3 files changed, 431 insertions(+), 1 deletion(-)
Documentation/filesystems/resctrl.rst +0 -0
index b003bed339fd..89fbf8b4fb2a 100644
@@ -522,6 +522,57 @@ conveyed in the error returns from file operations. E.g.
  	# cat info/last_cmd_status
  	mask f7 has non-consecutive 1-bits
 
Quoted 3 lines

Documentation/filesystems/resctrl.rst conveyed in the error returns from file operations. E.g. · line 525

Quoted 1 line
Documentation/filesystems/resctrl.rst +1 -0
+"kernel_mode":

(dropping the documentation here since I believe earlier comments apply)

Will rewrite the documentation. Will drop the x86 specific details.

Quoted 15 lines

...

fs/resctrl/internal.h struct mongroup { · line 220

Quoted 10 lines
fs/resctrl/internal.h +2 -0
index 1a9b29119f88..9435ce663f54 100644
@@ -216,6 +216,10 @@ struct mongroup {
   * @mon:			mongroup related data
   * @mode:			mode of resource group
   * @mba_mbps_event:		input monitoring event id when mba_sc is enabled
+ * @kmode:			true if this group is currently bound as the kernel-mode
+ *				CLOSID/RMID owner (resctrl_kcfg.k_rdtgrp)

(drop CLOSID/RMID)

ack.

Quoted 6 lines

fs/resctrl/internal.h struct mongroup { · line 222

Quoted 3 lines
fs/resctrl/internal.h +2 -0
+ * @kmode_cpu_mask:		CPUs scoped for this group's kernel-mode binding;
+ *				when empty, all online CPUs are used

Why does "empty" signify "all online CPUs"? This complicates implementation and creates different interface from existing CPUs interface of resource groups.

Will change it. It will display all the bound CPUs.

Quoted 21 lines
Quoted 21 lines
fs/resctrl/internal.h +2 -0
   * @plr:			pseudo-locked region
   */
  struct rdtgroup {
@@ -229,6 +233,8 @@ struct rdtgroup {
  	struct mongroup			mon;
  	enum rdtgrp_mode		mode;
  	enum resctrl_event_id		mba_mbps_event;
+	bool				kmode;
+	struct cpumask			kmode_cpu_mask;
  	struct pseudo_lock_region	*plr;
  };
 
fs/resctrl/rdtgroup.c +0 -0
index 9cdcfa64c4a2..5383b4eb23ed 100644
@@ -1055,6 +1055,378 @@ static int resctrl_kernel_mode_show(struct kernfs_open_file *of,
  	return 0;
  }
 
Quoted 9 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1063

Quoted 6 lines
fs/resctrl/rdtgroup.c +6 -0
+/**
+ * rdtgroup_config_kmode() - Push @rdtgrp's kernel CLOSID/RMID to hardware
+ * @rdtgrp:	Resctrl group whose CLOSID/RMID should be programmed.
+ *
+ * Derives CLOSID/RMID from @rdtgrp->type:
+ *   - RDTMON_GROUP: parent control group's CLOSID with the monitor group's RMID.

This seem unnecessary since when a monitor group is created it's closid is inherited from it's control group?

ok.

Quoted 13 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1074

Quoted 12 lines
fs/resctrl/rdtgroup.c +11 -0
+ *   - RDTCTRL_GROUP: the control group's own CLOSID and default RMID.
+ *
+ * Calls resctrl_arch_configure_kmode() with the kernel-mode binding enabled
+ * on the online subset of @rdtgrp->kmode_cpu_mask (or all online CPUs when
+ * that mask is empty), and disabled on the complementary online CPUs so
+ * stale enable bits from a previously bound group are cleared in the same
+ * reprogram step.  The caller (resctrl_kernel_mode_write()) is responsible
+ * for validating that the (kmode, group type) pair is permitted before
+ * invoking this helper.
+ *
+ * Context: Caller must hold rdtgroup_mutex.
Quoted 2 lines

Please use lockdep_assert_held(&rdtgroup_mutex) instead. See "Documenting locking requirements" in Documentation/process/maintainer-tip.rst

ok. Sure.

Quoted 12 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1083

Quoted 10 lines
fs/resctrl/rdtgroup.c +9 -0
+ *
+ * Return: 0 on success, -EINVAL for a pseudo-locked group, -ENOMEM if
+ * cpumask allocation fails.
+ */
+static int rdtgroup_config_kmode(struct rdtgroup *rdtgrp)
+{
+	cpumask_var_t enable_mask, disable_mask;
+	u32 closid, rmid;
+	bool need_disable;

(needs reverse fir)

Sure.

Quoted 15 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1093

Quoted 11 lines
fs/resctrl/rdtgroup.c +10 -0
+
+	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
+		rdt_last_cmd_puts("Resource group is pseudo-locked\n");
+		return -EINVAL;
+	}
+
+	if (!zalloc_cpumask_var(&enable_mask, GFP_KERNEL))
+		return -ENOMEM;
+
+	need_disable = !cpumask_empty(&rdtgrp->kmode_cpu_mask);

As I understand rdtgroup_config_kmode() is called when the kernel mode is switched. Also, earlier patches made it explicit that "Default scope is all online CPUs".

Quoted 7 lines

It is not clear to me how kmode_cpu_mask is initialized here ... it almost seems as though if a resource was associated with a mode at some point and received some CPU changes then when the mode switches between some other resource groups and then back to the original then the old cpu_mask will be used on the mode switch. Should the resource group's cpu_mask not be re-initialized to all online CPUs? If done then all of this cpu_mask wrangling seems unnecessary to me, just use all online CPUs?

Yes. That is correct. It needs to be changed.

Quoted 16 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1105

Quoted 13 lines
fs/resctrl/rdtgroup.c +12 -0
+	if (need_disable && !zalloc_cpumask_var(&disable_mask, GFP_KERNEL)) {
+		free_cpumask_var(enable_mask);
+		return -ENOMEM;
+	}
+
+	if (rdtgrp->type == RDTMON_GROUP) {
+		closid = rdtgrp->mon.parent->closid;
+		rmid = rdtgrp->mon.rmid;
+	} else {
+		closid = rdtgrp->closid;
+		rmid = rdtgrp->mon.rmid;
+	}

Considering MON group inherits the CLOSID if its parent, can above be simplified to just be?

Quoted 3 lines
	closid = rdtgrp->closid;
	rmid = rdtgrp->mon.rmid;

Yes.

Quoted 68 lines
Quoted 68 lines
fs/resctrl/rdtgroup.c +68 -0
+
+	/*
+	 * Empty kmode_cpu_mask: enable on every online CPU.  Otherwise enable
+	 * only CPUs in the group mask and explicitly clear on other online CPUs
+	 * so a previously bound group's enable bits don't linger.
+	 */
+	if (!need_disable) {
+		cpumask_copy(enable_mask, cpu_online_mask);
+	} else {
+		cpumask_copy(enable_mask, &rdtgrp->kmode_cpu_mask);
+		cpumask_andnot(disable_mask, cpu_online_mask, &rdtgrp->kmode_cpu_mask);
+	}
+
+	if (!cpumask_empty(enable_mask))
+		resctrl_arch_configure_kmode(enable_mask, closid, rmid, true);
+
+	if (need_disable && !cpumask_empty(disable_mask))
+		resctrl_arch_configure_kmode(disable_mask, closid, rmid, false);
+
+	rdtgrp->kmode = true;
+
+	free_cpumask_var(enable_mask);
+	if (need_disable)
+		free_cpumask_var(disable_mask);
+
+	return 0;
+}
+
+/**
+ * rdtgroup_config_kmode_clear() - Tear down the kernel-mode binding on @rdtgrp
+ * @rdtgrp:	Resctrl group whose kernel-mode binding is being released.
+ *		May be %NULL when no group is currently bound, in which case
+ *		this is a no-op.
+ * @kmode:	Kernel-mode policy currently active on @rdtgrp, as a
+ *		BIT(&enum resctrl_kernel_modes) value.  When this is
+ *		BIT(INHERIT_CTRL_AND_MON) the hardware tear-down is skipped
+ *		because no MSR was previously programmed.
+ *
+ * Disables the kernel-mode binding on the CPUs @rdtgrp covers (its
+ * @kmode_cpu_mask, or all online CPUs when that mask is empty) and resets
+ * the per-group bookkeeping (@kmode and @kmode_cpu_mask).  This is the
+ * disable counterpart of rdtgroup_config_kmode() and exists so that a write
+ * that transitions the active mode to BIT(INHERIT_CTRL_AND_MON) -- which
+ * skips rdtgroup_config_kmode() entirely -- still tears down the previously
+ * bound group instead of leaving stale enable bits behind.
+ *
+ * On allocation failure the function returns -ENOMEM and leaves both the
+ * hardware state and @rdtgrp's bookkeeping unchanged so the caller can fail
+ * the operation atomically and last_cmd_status reflects reality.
+ *
+ * Context: Caller must hold rdtgroup_mutex.
+ *
+ * Return: 0 on success (including the @rdtgrp == %NULL and INHERIT cases),
+ * -ENOMEM if cpumask allocation fails.
+ */
+static int rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
+{
+	cpumask_var_t disable_mask;
+	u32 closid, rmid;
+
+	if (!rdtgrp)
+		return 0;
+
+	if (kmode == BIT(INHERIT_CTRL_AND_MON))
+		goto out_clear;
+
+	if (!zalloc_cpumask_var(&disable_mask, GFP_KERNEL))
+		return -ENOMEM;
Quoted 9 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1105

Quoted 8 lines
fs/resctrl/rdtgroup.c +8 -0
+
+	if (rdtgrp->type == RDTMON_GROUP) {
+		closid = rdtgrp->mon.parent->closid;
+		rmid = rdtgrp->mon.rmid;
+	} else {
+		closid = rdtgrp->closid;
+		rmid = rdtgrp->mon.rmid;
+	}

I can directly use it like below. I dont need to check for RDTMON_GROUP.

	closid = rdtgrp->closid;

rmid = rdtgrp->mon.rmid;

Quoted 3 lines

Same comment as above ... but actually, why is closid/rmid needed at all? This function is intended to *reset* the kernel mode so needing a valid/active closid and rmid does not look right.

This is a bit tricky. I may need CLOSID/RMID in resctrl_arch_configure_kmode(). According to the specification, only the PLZA_EN field is allowed to differ across CPUs where PLZA is enabled; all other fields must remain consistent across CPUs within the same domain. If CLOSID/RMID are not passed, it could result in inconsistent values across CPUs.

Quoted 9 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1186

Quoted 6 lines
fs/resctrl/rdtgroup.c +5 -0
+
+	if (cpumask_empty(&rdtgrp->kmode_cpu_mask))
+		cpumask_copy(disable_mask, cpu_online_mask);
+	else
+		cpumask_copy(disable_mask, &rdtgrp->kmode_cpu_mask);

Having kmode_cpu_mask accurately reflect the online CPUs will simplify this to not need any of this wrangling and kmode_cpu_mask can just be used directly.

Agree.

Quoted 17 lines
Quoted 17 lines
fs/resctrl/rdtgroup.c +16 -0
+
+	resctrl_arch_configure_kmode(disable_mask, closid, rmid, false);
+	free_cpumask_var(disable_mask);
+
+out_clear:
+	cpumask_clear(&rdtgrp->kmode_cpu_mask);
+	rdtgrp->kmode = false;
+	return 0;
+}
+
+/**
+ * rdtgroup_by_kmode_path() - Resolve a "<ctrl>/<mon>/" path to an rdtgroup
+ * @ctrl_name:	Control-group name, or "" for the default control group.
+ * @mon_name:	Monitor-group name, or "" to select the control group itself.
+ *
+ * Matches the path syntax emitted by resctrl_kernel_mode_show():
Quoted 9 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1208

Quoted 6 lines
fs/resctrl/rdtgroup.c +6 -0
+ *   "//"            - the default control group
+ *   "<ctrl>//"      - control group @ctrl_name
+ *   "/<mon>/"       - monitor group @mon_name under the default control group
+ *   "<ctrl>/<mon>/" - monitor group @mon_name under control group @ctrl_name
+ *
+ * Context: Caller must hold rdtgroup_mutex.

(lockdep)

Sure.

Quoted 88 lines
Quoted 88 lines
fs/resctrl/rdtgroup.c +88 -0
+ *
+ * Return: Pointer to the matching rdtgroup, &rdtgroup_default when both
+ * names are empty (the show form "//"), or NULL if no such group exists.
+ */
+static struct rdtgroup *rdtgroup_by_kmode_path(const char *ctrl_name,
+					       const char *mon_name)
+{
+	struct rdtgroup *rdtg, *parent = NULL, *crg;
+
+	/* Show emits "//" for the default control group; round-trip it here. */
+	if (!*ctrl_name && !*mon_name)
+		return &rdtgroup_default;
+
+	/* Control-group-only form: "<ctrl>//". */
+	if (!*mon_name) {
+		list_for_each_entry(rdtg, &rdt_all_groups, rdtgroup_list) {
+			if (rdtg->type != RDTCTRL_GROUP)
+				continue;
+			if (!strcmp(rdt_kn_name(rdtg->kn), ctrl_name))
+				return rdtg;
+		}
+		return NULL;
+	}
+
+	/* Monitor-group form: locate the parent control group first. */
+	if (!*ctrl_name) {
+		parent = &rdtgroup_default;
+	} else {
+		list_for_each_entry(rdtg, &rdt_all_groups, rdtgroup_list) {
+			if (rdtg->type != RDTCTRL_GROUP)
+				continue;
+			if (!strcmp(rdt_kn_name(rdtg->kn), ctrl_name)) {
+				parent = rdtg;
+				break;
+			}
+		}
+		if (!parent)
+			return NULL;
+	}
+
+	list_for_each_entry(crg, &parent->mon.crdtgrp_list, mon.crdtgrp_list)
+		if (!strcmp(rdt_kn_name(crg->kn), mon_name))
+			return crg;
+	return NULL;
+}
+
+/**
+ * resctrl_kernel_mode_write() - Select kernel mode and bind group via info/kernel_mode
+ * @of:		kernfs file handle.
+ * @buf:	One line in the same format emitted by resctrl_kernel_mode_show(),
+ *		i.e. "<mode>[:group=<ctrl>/<mon>/]" with an optional surrounding
+ *		"[...]"; must end with a newline.  The ":group=<spec>" suffix is
+ *		optional -- when omitted the default control group
+ *		(&rdtgroup_default) is used.
+ * @nbytes:	Length of @buf.
+ * @off:	File offset (unused).
+ *
+ * Parses @buf, validates that <mode> is listed in resctrl_mode_str[] and is
+ * supported by the platform (resctrl_kcfg.kmode), resolves <ctrl>/<mon>/ to
+ * an existing rdtgroup (or picks &rdtgroup_default if no group was specified
+ * or if the new mode is INHERIT), clears any previous binding via
+ * rdtgroup_config_kmode_clear(), programs hardware via
+ * rdtgroup_config_kmode() when @kmode is not BIT(INHERIT_CTRL_AND_MON), and
+ * on success updates resctrl_kcfg.k_rdtgrp and resctrl_kcfg.kmode_cur.  The
+ * display-only "group=none" form produced by show for inactive modes is
+ * rejected.  Errors are reported in last_cmd_status.
+ *
+ * Return: @nbytes on success, negative errno with last_cmd_status set on error.
+ */
+static ssize_t resctrl_kernel_mode_write(struct kernfs_open_file *of,
+					 char *buf, size_t nbytes, loff_t off)
+{
+	char *mode_str, *group_str, *slash;
+	const char *ctrl_name, *mon_name;
+	struct rdtgroup *rdtgrp;
+	int ret = 0;
+	size_t len;
+	u32 kmode;
+	int i;
+
+	if (nbytes == 0 || buf[nbytes - 1] != '\n')
+		return -EINVAL;
+	buf[nbytes - 1] = '\0';
+
+	/* Tolerate surrounding whitespace before the bracket/mode parsing. */
+	buf = strim(buf);
+	len = strlen(buf);
+
Quoted 8 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1302

Quoted 6 lines
fs/resctrl/rdtgroup.c +6 -0
+	/* Strip the optional "[...]" that show uses to mark the active line. */
+	if (len >= 2 && buf[0] == '[' && buf[len - 1] == ']') {
+		buf[len - 1] = '\0';
+		buf++;
+		len -= 2;
+	}

I do not think the brackets should be valid input.

Sure.

Quoted 26 lines
Quoted 26 lines
fs/resctrl/rdtgroup.c +25 -0
+
+	/*
+	 * Split "<mode>:group=<spec>"; the ":group=<spec>" suffix is optional
+	 * and when omitted the default control group (&rdtgroup_default) is used.
+	 */
+	group_str = strstr(buf, ":group=");
+	if (group_str) {
+		*group_str = '\0';
+		group_str += strlen(":group=");
+	}
+	mode_str = buf;
+
+	mutex_lock(&rdtgroup_mutex);
+	rdt_last_cmd_clear();
+
+	for (i = 0; i < RESCTRL_NUM_KERNEL_MODES; i++)
+		if (!strcmp(mode_str, resctrl_mode_str[i]))
+			break;
+	if (i == RESCTRL_NUM_KERNEL_MODES) {
+		rdt_last_cmd_puts("Unknown kernel mode\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	if (!(resctrl_kcfg.kmode & BIT(i))) {
Quoted 8 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1333

Quoted 6 lines
fs/resctrl/rdtgroup.c +6 -0
+		rdt_last_cmd_puts("Kernel mode not available\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	kmode = BIT(i);

Can kmode be of enum type to be assigned the actual enum value to avoid all these BIT(enum value) usages?

You mean?

enum resctrl_kernel_modes {
	INHERIT_CTRL_AND_MON		= 1U << 0,  /* 1 */
	GLOBAL_ASSIGN_CTRL_INHERIT_MON	= 1U << 1,  /* 2 */
	GLOBAL_ASSIGN_CTRL_ASSIGN_MON	= 1U << 2,  /* 4 */
};

#define RESCTRL_NUM_KERNEL_MODES 3

Quoted 14 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1344

Quoted 12 lines
fs/resctrl/rdtgroup.c +11 -0
+
+	if (!group_str) {
+		/* No ":group=" suffix: fall back to the default control group. */
+		rdtgrp = &rdtgroup_default;
+	} else if (!strcmp(group_str, "none")) {
+		/* Display-only placeholder emitted by show; not selectable. */
+		rdt_last_cmd_puts("Cannot bind to 'none' group\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	} else {
+		/* Require exactly "<ctrl>/<mon>/" - two '/' with the second terminating. */

User should not be expected to provide monitor group when the monitoring is inherited.

Yes. Will add that check later. I will update the comment here.

Quoted 27 lines
Quoted 27 lines
fs/resctrl/rdtgroup.c +26 -0
+		slash = strchr(group_str, '/');
+		if (!slash) {
+			rdt_last_cmd_puts("Group must be <ctrl>/<mon>/\n");
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+		*slash = '\0';
+		ctrl_name = group_str;
+		mon_name = slash + 1;
+		slash = strchr(mon_name, '/');
+		if (!slash || slash[1] != '\0') {
+			rdt_last_cmd_puts("Group must be <ctrl>/<mon>/\n");
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+		*slash = '\0';
+
+		rdtgrp = rdtgroup_by_kmode_path(ctrl_name, mon_name);
+		if (!rdtgrp) {
+			rdt_last_cmd_puts("Group not found\n");
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+	}
+
+	/*
Quoted 9 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1376

Quoted 6 lines
fs/resctrl/rdtgroup.c +6 -0
+	 * INHERIT mode binds nothing; force the bound group to the default so
+	 * round-trips with show (which prints "group=//") are stable and any
+	 * user-supplied :group= suffix is silently normalised.
+	 */
+	if (kmode == BIT(INHERIT_CTRL_AND_MON))
+		rdtgrp = &rdtgroup_default;

rdtgrp = NULL ?

Yes.

Quoted 36 lines
Quoted 36 lines
fs/resctrl/rdtgroup.c +36 -0
+
+	/* No-op if the same mode is already active on the same group. */
+	if (resctrl_kcfg.kmode_cur == kmode && resctrl_kcfg.k_rdtgrp == rdtgrp)
+		goto out_unlock;
+
+	/*
+	 * global_assign_ctrl_assign_mon_per_cpu binds one CLOSID and RMID for
+	 * all kernel work (Documentation/filesystems/resctrl.rst uses
+	 * "<ctrl>/<mon>/", i.e. an RDTMON_GROUP).
+	 *
+	 * global_assign_ctrl_inherit_mon_per_cpu assigns one CLOSID globally
+	 * while leaving RMID inheritance to user contexts; that uses the
+	 * control group's CLOSID slot only, i.e. an RDTCTRL_GROUP.
+	 */
+	if (kmode == BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU) &&
+	    rdtgrp->type != RDTMON_GROUP) {
+		rdt_last_cmd_puts("global_assign_ctrl_assign_mon_per_cpu requires a monitor group\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+	if (kmode == BIT(GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU) &&
+	    rdtgrp->type != RDTCTRL_GROUP) {
+		rdt_last_cmd_puts("global_assign_ctrl_inherit_mon_per_cpu requires a control group\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	/* Switching to a different group: release the old binding first. */
+	if (resctrl_kcfg.k_rdtgrp != rdtgrp) {
+		ret = rdtgroup_config_kmode_clear(resctrl_kcfg.k_rdtgrp,
+						  resctrl_kcfg.kmode_cur);
+		if (ret) {
+			rdt_last_cmd_puts("Failed to release previous kernel-mode binding\n");
+			goto out_unlock;
+		}
+	}
Quoted 8 lines

fs/resctrl/rdtgroup.c static int resctrl_kernel_mode_show(struct kernfs_open_file *of, · line 1417

Quoted 5 lines
fs/resctrl/rdtgroup.c +5 -0
+
+	if (kmode != BIT(INHERIT_CTRL_AND_MON)) {
+		ret = rdtgroup_config_kmode(rdtgrp);
+		if (ret) {
+			rdt_last_cmd_puts("Kernel mode change failed\n");

If it fails here then previous binding was released successfully but new binding failed. What is state of system?

Yea. Need to change this one. Will use Qinyun Tan patch.

Thanks
Babu

maintainer
#41 lore raw

Re: [PATCH v3 08/12] fs/resctrl: Make info/kernel_mode writable and identify the bound group

Hi Babu,

Quoted 2 lines · Babu Moger
Quoted 1 line · Reinette Chatre

On 4/30/26 4:24 PM, Babu Moger wrote:

...

Quoted 60 lines
Quoted 40 lines
Quoted 40 lines
fs/resctrl/rdtgroup.c +40 -0
+/**
+ * rdtgroup_config_kmode_clear() - Tear down the kernel-mode binding on @rdtgrp
+ * @rdtgrp:    Resctrl group whose kernel-mode binding is being released.
+ *        May be %NULL when no group is currently bound, in which case
+ *        this is a no-op.
+ * @kmode:    Kernel-mode policy currently active on @rdtgrp, as a
+ *        BIT(&enum resctrl_kernel_modes) value.  When this is
+ *        BIT(INHERIT_CTRL_AND_MON) the hardware tear-down is skipped
+ *        because no MSR was previously programmed.
+ *
+ * Disables the kernel-mode binding on the CPUs @rdtgrp covers (its
+ * @kmode_cpu_mask, or all online CPUs when that mask is empty) and resets
+ * the per-group bookkeeping (@kmode and @kmode_cpu_mask).  This is the
+ * disable counterpart of rdtgroup_config_kmode() and exists so that a write
+ * that transitions the active mode to BIT(INHERIT_CTRL_AND_MON) -- which
+ * skips rdtgroup_config_kmode() entirely -- still tears down the previously
+ * bound group instead of leaving stale enable bits behind.
+ *
+ * On allocation failure the function returns -ENOMEM and leaves both the
+ * hardware state and @rdtgrp's bookkeeping unchanged so the caller can fail
+ * the operation atomically and last_cmd_status reflects reality.
+ *
+ * Context: Caller must hold rdtgroup_mutex.
+ *
+ * Return: 0 on success (including the @rdtgrp == %NULL and INHERIT cases),
+ * -ENOMEM if cpumask allocation fails.
+ */
+static int rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
+{
+    cpumask_var_t disable_mask;
+    u32 closid, rmid;
+
+    if (!rdtgrp)
+        return 0;
+
+    if (kmode == BIT(INHERIT_CTRL_AND_MON))
+        goto out_clear;
+
+    if (!zalloc_cpumask_var(&disable_mask, GFP_KERNEL))
+        return -ENOMEM;
Quoted 9 lines
Quoted 8 lines

+
+    if (rdtgrp->type == RDTMON_GROUP) {
+        closid = rdtgrp->mon.parent->closid;
+        rmid = rdtgrp->mon.rmid;
+    } else {
+        closid = rdtgrp->closid;
+        rmid = rdtgrp->mon.rmid;
+    }

I can directly use it like below. I dont need to check for RDTMON_GROUP.

    closid = rdtgrp->closid;
     rmid = rdtgrp->mon.rmid;

Quoted 3 lines

Same comment as above ... but actually, why is closid/rmid needed at all? This function is intended to *reset* the kernel mode so needing a valid/active closid and rmid does not look right.

Quoted 6 lines

This is a bit tricky. I may need CLOSID/RMID in resctrl_arch_configure_kmode(). According to the specification, only the PLZA_EN field is allowed to differ across CPUs where PLZA is enabled; all other fields must remain consistent across CPUs within the same domain. If CLOSID/RMID are not passed, it could result in inconsistent values across CPUs.

I see. Let's revisit this in next version. It is not quite clear to me how the rework of cpu_mask wrangling will impact the resctrl_arch_configure_kmode() calls. To simplify this for now resctrl could continue to provide closid and rmid to architecture (with the API documentation in include/linux/resctrl.h documenting why it is provided and that it may be unused by architecture).

Quoted 36 lines
Quoted 25 lines
Quoted 25 lines
fs/resctrl/rdtgroup.c +25 -0
+
+    /*
+     * Split "<mode>:group=<spec>"; the ":group=<spec>" suffix is optional
+     * and when omitted the default control group (&rdtgroup_default) is used.
+     */
+    group_str = strstr(buf, ":group=");
+    if (group_str) {
+        *group_str = '\0';
+        group_str += strlen(":group=");
+    }
+    mode_str = buf;
+
+    mutex_lock(&rdtgroup_mutex);
+    rdt_last_cmd_clear();
+
+    for (i = 0; i < RESCTRL_NUM_KERNEL_MODES; i++)
+        if (!strcmp(mode_str, resctrl_mode_str[i]))
+            break;
+    if (i == RESCTRL_NUM_KERNEL_MODES) {
+        rdt_last_cmd_puts("Unknown kernel mode\n");
+        ret = -EINVAL;
+        goto out_unlock;
+    }
+
+    if (!(resctrl_kcfg.kmode & BIT(i))) {
Quoted 8 lines
Quoted 6 lines

+        rdt_last_cmd_puts("Kernel mode not available\n"); +        ret = -EINVAL;
+        goto out_unlock;
+    }
+
+    kmode = BIT(i);

Can kmode be of enum type to be assigned the actual enum value to avoid all these BIT(enum value) usages?

You mean?

Quoted 7 lines

enum resctrl_kernel_modes {
    INHERIT_CTRL_AND_MON        = 1U << 0,  /* 1 */ GLOBAL_ASSIGN_CTRL_INHERIT_MON    = 1U << 1,  /* 2 */ GLOBAL_ASSIGN_CTRL_ASSIGN_MON    = 1U << 2,  /* 4 */ };

#define RESCTRL_NUM_KERNEL_MODES  3

No. I mean:

	enum resctrl_kernel_mode kmode;

... with a change like this code like below can be simplified:

Quoted 1 line
Quoted 1 line
Quoted 1 line

+    if (kmode == BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU) &&

	kmode == GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

+        rdtgrp->type != RDTMON_GROUP) {
+        rdt_last_cmd_puts("global_assign_ctrl_assign_mon_per_cpu requires a monitor group\n"); +        ret = -EINVAL;
+        goto out_unlock;
+    }
+    if (kmode == BIT(GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU) &&

	kmode == GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

+        rdtgrp->type != RDTCTRL_GROUP) {
+        rdt_last_cmd_puts("global_assign_ctrl_inherit_mon_per_cpu requires a control group\n"); +        ret = -EINVAL;
+        goto out_unlock;
+    }
+

Reinette

author reviewer
#42 lore raw

Re: [PATCH v3 08/12] fs/resctrl: Make info/kernel_mode writable and identify the bound group

Hi Reinette,

Quoted 76 lines · Reinette Chatre

Hi Babu,

Quoted 2 lines · Babu Moger
Quoted 1 line · Reinette Chatre

On 4/30/26 4:24 PM, Babu Moger wrote:

...

Quoted 60 lines
Quoted 40 lines
Quoted 40 lines
fs/resctrl/rdtgroup.c +40 -0
+/**
+ * rdtgroup_config_kmode_clear() - Tear down the kernel-mode binding on @rdtgrp
+ * @rdtgrp:    Resctrl group whose kernel-mode binding is being released.
+ *        May be %NULL when no group is currently bound, in which case
+ *        this is a no-op.
+ * @kmode:    Kernel-mode policy currently active on @rdtgrp, as a
+ *        BIT(&enum resctrl_kernel_modes) value.  When this is
+ *        BIT(INHERIT_CTRL_AND_MON) the hardware tear-down is skipped
+ *        because no MSR was previously programmed.
+ *
+ * Disables the kernel-mode binding on the CPUs @rdtgrp covers (its
+ * @kmode_cpu_mask, or all online CPUs when that mask is empty) and resets
+ * the per-group bookkeeping (@kmode and @kmode_cpu_mask).  This is the
+ * disable counterpart of rdtgroup_config_kmode() and exists so that a write
+ * that transitions the active mode to BIT(INHERIT_CTRL_AND_MON) -- which
+ * skips rdtgroup_config_kmode() entirely -- still tears down the previously
+ * bound group instead of leaving stale enable bits behind.
+ *
+ * On allocation failure the function returns -ENOMEM and leaves both the
+ * hardware state and @rdtgrp's bookkeeping unchanged so the caller can fail
+ * the operation atomically and last_cmd_status reflects reality.
+ *
+ * Context: Caller must hold rdtgroup_mutex.
+ *
+ * Return: 0 on success (including the @rdtgrp == %NULL and INHERIT cases),
+ * -ENOMEM if cpumask allocation fails.
+ */
+static int rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
+{
+    cpumask_var_t disable_mask;
+    u32 closid, rmid;
+
+    if (!rdtgrp)
+        return 0;
+
+    if (kmode == BIT(INHERIT_CTRL_AND_MON))
+        goto out_clear;
+
+    if (!zalloc_cpumask_var(&disable_mask, GFP_KERNEL))
+        return -ENOMEM;
Quoted 9 lines
Quoted 8 lines

+
+    if (rdtgrp->type == RDTMON_GROUP) {
+        closid = rdtgrp->mon.parent->closid;
+        rmid = rdtgrp->mon.rmid;
+    } else {
+        closid = rdtgrp->closid;
+        rmid = rdtgrp->mon.rmid;
+    }

I can directly use it like below. I dont need to check for RDTMON_GROUP.

    closid = rdtgrp->closid;
     rmid = rdtgrp->mon.rmid;

Quoted 3 lines

Same comment as above ... but actually, why is closid/rmid needed at all? This function is intended to *reset* the kernel mode so needing a valid/active closid and rmid does not look right.

Quoted 6 lines

This is a bit tricky. I may need CLOSID/RMID in resctrl_arch_configure_kmode(). According to the specification, only the PLZA_EN field is allowed to differ across CPUs where PLZA is enabled; all other fields must remain consistent across CPUs within the same domain. If CLOSID/RMID are not passed, it could result in inconsistent values across CPUs.

Quoted 6 lines

I see. Let's revisit this in next version. It is not quite clear to me how the rework of cpu_mask wrangling will impact the resctrl_arch_configure_kmode() calls. To simplify this for now resctrl could continue to provide closid and rmid to architecture (with the API documentation in include/linux/resctrl.h documenting why it is provided and that it may be unused by architecture).

Sounds good. Lets revisit this again.

Quoted 46 lines
Quoted 38 lines
Quoted 27 lines
Quoted 27 lines
fs/resctrl/rdtgroup.c +25 -0
+
+    /*
+     * Split "<mode>:group=<spec>"; the ":group=<spec>" suffix is optional
+     * and when omitted the default control group (&rdtgroup_default) is used.
+     */
+    group_str = strstr(buf, ":group=");
+    if (group_str) {
+        *group_str = '\0';
+        group_str += strlen(":group=");
+    }
+    mode_str = buf;
+
+    mutex_lock(&rdtgroup_mutex);
+    rdt_last_cmd_clear();
+
+    for (i = 0; i < RESCTRL_NUM_KERNEL_MODES; i++)
+        if (!strcmp(mode_str, resctrl_mode_str[i]))
+            break;
+    if (i == RESCTRL_NUM_KERNEL_MODES) {
+        rdt_last_cmd_puts("Unknown kernel mode\n");
+        ret = -EINVAL;
+        goto out_unlock;
+    }
+
+    if (!(resctrl_kcfg.kmode & BIT(i))) {
Quoted 8 lines
Quoted 6 lines

+        rdt_last_cmd_puts("Kernel mode not available\n"); +        ret = -EINVAL;
+        goto out_unlock;
+    }
+
+    kmode = BIT(i);

Can kmode be of enum type to be assigned the actual enum value to avoid all these BIT(enum value) usages?

You mean?

Quoted 7 lines

enum resctrl_kernel_modes {
    INHERIT_CTRL_AND_MON        = 1U << 0,  /* 1 */ GLOBAL_ASSIGN_CTRL_INHERIT_MON    = 1U << 1,  /* 2 */ GLOBAL_ASSIGN_CTRL_ASSIGN_MON    = 1U << 2,  /* 4 */
};

#define RESCTRL_NUM_KERNEL_MODES  3

Quoted 7 lines

No. I mean:

	enum resctrl_kernel_mode kmode;

... with a change like this code like below can be simplified:

Quoted 1 line
Quoted 1 line
Quoted 1 line

+    if (kmode == BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU) &&

	kmode == GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU

Sure. Will do.

Thanks
Babu

author reviewer
#43 lore raw

PATCH v3 9/12 fs/resctrl: Reset kernel-mode binding when its rdtgroup goes away

In reply to Babu Moger

resctrl_kcfg.k_rdtgrp records which rdtgroup currently owns the kernel CLOSID/RMID, but nothing cleared that snapshot when the group was removed. rmdir of a control or monitor group, or unmount of the resctrl filesystem, left kernel mode enabled on the CPUs the group covered and left k_rdtgrp pointing at freed memory; the next read or write of info/kernel_mode would dereference a stale rdtgroup under rdtgroup_mutex.

Add rdtgroup_config_kmode_delete() as the disable counterpart of rdtgroup_config_kmode(). It clears the kernel-mode binding on the group's kmode_cpu_mask (or all online CPUs when that mask is empty), drops the per-group kmode/kmode_cpu_mask bookkeeping, and if @rdtgrp was the bound, resets resctrl_kcfg to &rdtgroup_default, BIT(INHERIT_CTRL_AND_MON)) so subsequent sysfs operations resolve to a live group.

Call it from rdtgroup_rmdir_mon(), rdtgroup_rmdir_ctrl(), and resctrl_fs_teardown(); each call site is gated on rdtgrp->kmode so groups that never participated in kernel mode pay nothing.

---
v3: New patch to handle the kernel_mode clean up.

---
 fs/resctrl/rdtgroup.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
fs/resctrl/rdtgroup.c +39 -0
index 5383b4eb23ed..faf390893109 100644
@@ -1194,6 +1194,40 @@ static int rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
 	return 0;
 }
 
+/**
+ * rdtgroup_config_kmode_delete() - Drop @rdtgrp's kernel-mode binding
+ * @rdtgrp:	Resctrl group whose kernel-mode binding is being removed (e.g.
+ *		because the group is about to be rmdir'd or the filesystem is
+ *		being torn down).  No-op when %NULL or when @rdtgrp never
+ *		carried a kernel-mode binding.
+ *
+ * Wraps rdtgroup_config_kmode_clear() to disable the hardware programming
+ * and reset the per-group bookkeeping.  When @rdtgrp is the group currently
+ * bound in @resctrl_kcfg, the snapshot is also reset to
+ * (&rdtgroup_default, BIT(INHERIT_CTRL_AND_MON)) so subsequent show/write
+ * paths do not dereference @rdtgrp after the caller frees it.
+ *
+ * If the underlying tear-down fails (cpumask allocation), the snapshot is
+ * still reset because @rdtgrp is about to disappear; stale enable bits on
+ * those CPUs are reported via pr_warn() and will be cleared by the next
+ * non-INHERIT reprogram.
+ *
+ * Context: Caller must hold rdtgroup_mutex.
+ */
+static void rdtgroup_config_kmode_delete(struct rdtgroup *rdtgrp)
+{
+	if (!rdtgrp || !rdtgrp->kmode)
+		return;
+
+	if (rdtgroup_config_kmode_clear(rdtgrp, resctrl_kcfg.kmode_cur))
+		pr_warn("resctrl: kernel-mode disable failed; stale enable bits may persist\n");
+
+	if (resctrl_kcfg.k_rdtgrp == rdtgrp) {
+		resctrl_kcfg.k_rdtgrp = &rdtgroup_default;
+		resctrl_kcfg.kmode_cur = BIT(INHERIT_CTRL_AND_MON);
+	}
+}
+
 /**
  * rdtgroup_by_kmode_path() - Resolve a "<ctrl>/<mon>/" path to an rdtgroup
  * @ctrl_name:	Control-group name, or "" for the default control group.
@@ -3635,6 +3669,7 @@ static void resctrl_fs_teardown(void)
 	mon_put_kn_priv();
 	rdt_pseudo_lock_release();
 	rdtgroup_default.mode = RDT_MODE_SHAREABLE;
+	rdtgroup_config_kmode_delete(&rdtgroup_default);
 	closid_exit();
 	schemata_list_destroy();
 	rdtgroup_destroy_root();
@@ -4432,6 +4467,8 @@ static int rdtgroup_rmdir_mon(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask)
 	u32 closid, rmid;
 	int cpu;
 
+	rdtgroup_config_kmode_delete(rdtgrp);
+
 	/* Give any tasks back to the parent group */
 	rdt_move_group_tasks(rdtgrp, prdtgrp, tmpmask);
 
@@ -4482,6 +4519,8 @@ static int rdtgroup_rmdir_ctrl(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask)
 	u32 closid, rmid;
 	int cpu;
 
+	rdtgroup_config_kmode_delete(rdtgrp);
+
 	/* Give any tasks back to the default group */
 	rdt_move_group_tasks(rdtgrp, &rdtgroup_default, tmpmask);
 
Signature · 1 line
2.43.0
maintainer
#44 lore raw

Re: [PATCH v3 09/12] fs/resctrl: Reset kernel-mode binding when its rdtgroup goes away

Hi Babu,

Quoted 6 lines · Babu Moger

resctrl_kcfg.k_rdtgrp records which rdtgroup currently owns the kernel CLOSID/RMID, but nothing cleared that snapshot when the group was removed. rmdir of a control or monitor group, or unmount of the resctrl filesystem, left kernel mode enabled on the CPUs the group covered and left k_rdtgrp pointing at freed memory; the next read or write of info/kernel_mode would dereference a stale rdtgroup under rdtgroup_mutex.

Please do not word the enabling as bugfixes.

Quoted 8 lines

Add rdtgroup_config_kmode_delete() as the disable counterpart of rdtgroup_config_kmode(). It clears the kernel-mode binding on the group's kmode_cpu_mask (or all online CPUs when that mask is empty), drops the per-group kmode/kmode_cpu_mask bookkeeping, and if @rdtgrp was the bound, resets resctrl_kcfg to &rdtgroup_default, BIT(INHERIT_CTRL_AND_MON)) so subsequent sysfs operations resolve to a live group.

Could you please reword these code descriptions to describe why this patch is needed?

Quoted 4 lines

Call it from rdtgroup_rmdir_mon(), rdtgroup_rmdir_ctrl(), and resctrl_fs_teardown(); each call site is gated on rdtgrp->kmode so groups that never participated in kernel mode pay nothing.

Does this handle the non-default resource groups removed on unmount? (see rmdir_all_sub() called from resctrl_fs_teardown())

(please refer to earlier comments that apply to this patch also)

Reinette

author reviewer
#45 lore raw

Re: [PATCH v3 09/12] fs/resctrl: Reset kernel-mode binding when its rdtgroup goes away

Hi Reinette,

Quoted 11 lines · Reinette Chatre

Hi Babu,

Quoted 6 lines · Babu Moger

resctrl_kcfg.k_rdtgrp records which rdtgroup currently owns the kernel CLOSID/RMID, but nothing cleared that snapshot when the group was removed. rmdir of a control or monitor group, or unmount of the resctrl filesystem, left kernel mode enabled on the CPUs the group covered and left k_rdtgrp pointing at freed memory; the next read or write of info/kernel_mode would dereference a stale rdtgroup under rdtgroup_mutex.

Please do not word the enabling as bugfixes.

Sure.

Quoted 10 lines
Quoted 9 lines

Add rdtgroup_config_kmode_delete() as the disable counterpart of rdtgroup_config_kmode(). It clears the kernel-mode binding on the group's kmode_cpu_mask (or all online CPUs when that mask is empty), drops the per-group kmode/kmode_cpu_mask bookkeeping, and if @rdtgrp was the bound, resets resctrl_kcfg to &rdtgroup_default, BIT(INHERIT_CTRL_AND_MON)) so subsequent sysfs operations resolve to a live group.

Quoted 3 lines

Could you please reword these code descriptions to describe why this patch is needed?

Sure.

Quoted 9 lines
Quoted 4 lines

Call it from rdtgroup_rmdir_mon(), rdtgroup_rmdir_ctrl(), and resctrl_fs_teardown(); each call site is gated on rdtgrp->kmode so groups that never participated in kernel mode pay nothing.

Does this handle the non-default resource groups removed on unmount? (see rmdir_all_sub() called from resctrl_fs_teardown())

(please refer to earlier comments that apply to this patch also)

Yea. I missed free_all_child_rdtgrp() and rmdir_all_sub(). Will fix that.

Thanks
Babu

author reviewer
#46 lore raw

PATCH v3 10/12 fs/resctrl: Expose kmode_cpus / kmode_cpus_list per rdtgroup

In reply to Babu Moger

rdtgrp->kmode_cpu_mask selects which CPUs of a group have the kernel-mode binding programmed, but the mask is not visible from the resctrl filesystem; user space has no way to verify the result of a write to info/kernel_mode without reading kernel memory.

Add two read-only files alongside cpus / cpus_list in every rdtgroup:

kmode_cpus - bitmap form of rdtgrp->kmode_cpu_mask
kmode_cpus_list - range-list form of the same mask

The handler returns -ENOENT for a deleted group and -ENODEV for a pseudo-locked group, mirroring rdtgroup_cpus_show(). An empty mask reads back as a bare newline, matching the "all online CPUs" semantics rdtgroup_config_kmode() applies to an empty kmode_cpu_mask.

---
v3: New patch to add "kmode_cpus" and "kmode_cpus_list" to support
kernel_modes.

---
 fs/resctrl/rdtgroup.c | 53 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
fs/resctrl/rdtgroup.c +53 -0
index faf390893109..e155160ba2b1 100644
@@ -387,6 +387,44 @@ static int rdtgroup_cpus_show(struct kernfs_open_file *of,
 	return ret;
 }
 
+/*
+ * Show the per-rdtgroup kmode_cpu_mask, the set of CPUs scoped for this
+ * group's kernel-mode binding.  Backs both the "kmode_cpus" (bitmap) and
+ * "kmode_cpus_list" (range list) files; the format is selected by
+ * is_cpu_list() based on the file's RFTYPE_FLAGS_CPUS_LIST flag.
+ *
+ * An empty mask is emitted as a bare newline.  rdtgroup_config_kmode()
+ * treats an empty kmode_cpu_mask as "all online CPUs", so reading just
+ * "\n" means the binding is applied group-wide rather than restricted
+ * to a subset.
+ *
+ * Returns -ENOENT if the group has been deleted, and -ENODEV for
+ * pseudo-locked groups -- which cannot host a kernel-mode binding, so
+ * reporting an empty mask would be misleading (the empty form elsewhere
+ * means "all online CPUs").  Mirrors rdtgroup_cpus_show() for parity.
+ */
+static int rdtgroup_kmode_cpus_show(struct kernfs_open_file *of, struct seq_file *s, void *v)
+{
+	struct rdtgroup *rdtgrp;
+	int ret = 0;
+
+	rdtgrp = rdtgroup_kn_lock_live(of->kn);
+
+	if (rdtgrp) {
+		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
+			ret = -ENODEV;
+		} else {
+			seq_printf(s, is_cpu_list(of) ? "%*pbl\n" : "%*pb\n",
+				   cpumask_pr_args(&rdtgrp->kmode_cpu_mask));
+		}
+	} else {
+		ret = -ENOENT;
+	}
+	rdtgroup_kn_unlock(of->kn);
+
+	return ret;
+}
+
 /*
  * Update the PGR_ASSOC MSR on all cpus in @cpu_mask,
  *
@@ -2547,6 +2585,21 @@ static struct rftype res_common_files[] = {
 		.flags		= RFTYPE_FLAGS_CPUS_LIST,
 		.fflags		= RFTYPE_BASE,
 	},
+	{
+		.name		= "kmode_cpus",
+		.mode		= 0444,
+		.kf_ops		= &rdtgroup_kf_single_ops,
+		.seq_show	= rdtgroup_kmode_cpus_show,
+		.fflags		= RFTYPE_BASE,
+	},
+	{
+		.name		= "kmode_cpus_list",
+		.mode		= 0444,
+		.kf_ops		= &rdtgroup_kf_single_ops,
+		.seq_show	= rdtgroup_kmode_cpus_show,
+		.flags		= RFTYPE_FLAGS_CPUS_LIST,
+		.fflags		= RFTYPE_BASE,
+	},
 	{
 		.name		= "tasks",
 		.mode		= 0644,
Signature · 1 line
2.43.0
author reviewer
#47 lore raw

PATCH v3 11/12 resctrl: Hide kmode_cpus[_list] on groups not bound to kernel-mode

In reply to Babu Moger

The kmode_cpus and kmode_cpus_list files control the CPU scope of the kernel-mode binding owned by resctrl_kcfg.k_rdtgrp. On any other group they appeared as stub files, and writing to them reprogrammed hardware as if the binding were active -- corrupting the real binding.

Hide both files via kernfs_show() on every rdtgroup that does not currently own the binding. The kernel-mode lifecycle hooks toggle
visibility: hidden at mount on rdtgroup_default, hidden at mkdir for new groups, shown by rdtgroup_config_kmode() on the group it binds, and hidden again by rdtgroup_config_kmode_clear() (and through it, rdtgroup_config_kmode_delete()) when the binding is released.

---
v3: New patch to hide/show "kmode_cpus" and "kmode_cpus_list" when kernel modes
binding changes.

---
 fs/resctrl/rdtgroup.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
fs/resctrl/rdtgroup.c +40 -0
index e155160ba2b1..cff306d28e79 100644
@@ -1093,6 +1093,38 @@ static int resctrl_kernel_mode_show(struct kernfs_open_file *of,
 	return 0;
 }
 
+/**
+ * resctrl_kmode_files_set_visible() - Toggle visibility of the per-group
+ * kernel-mode CPU files under @rdtgrp.
+ * @rdtgrp:	Resctrl group whose "kmode_cpus" / "kmode_cpus_list" files
+ *		should be hidden or shown.
+ * @visible:	%true to expose the files, %false to hide them via
+ *		kernfs_show().
+ *
+ * Each file is looked up independently as a sibling under @rdtgrp->kn.
+ * kernfs_find_and_get() failures are intentionally ignored: this helper
+ * is invoked early on rdtgroup_default before its rftype files have been
+ * populated, and is robust against any future rdtgroup variant whose
+ * kernfs tree does not include these files.
+ *
+ * Context: Caller must hold rdtgroup_mutex.
+ */
+static void resctrl_kmode_files_set_visible(struct rdtgroup *rdtgrp, bool visible)
+{
+	/* Keep in sync with res_common_files[] entries for these files. */
+	static const char * const files[] = { "kmode_cpus", "kmode_cpus_list" };
+	struct kernfs_node *kn;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(files); i++) {
+		kn = kernfs_find_and_get(rdtgrp->kn, files[i]);
+		if (!kn)
+			continue;
+		kernfs_show(kn, visible);
+		kernfs_put(kn);
+	}
+}
+
 /**
  * rdtgroup_config_kmode() - Push @rdtgrp's kernel CLOSID/RMID to hardware
  * @rdtgrp:	Resctrl group whose CLOSID/RMID should be programmed.
@@ -1161,6 +1193,7 @@ static int rdtgroup_config_kmode(struct rdtgroup *rdtgrp)
 		resctrl_arch_configure_kmode(disable_mask, closid, rmid, false);
 
 	rdtgrp->kmode = true;
+	resctrl_kmode_files_set_visible(rdtgrp, true);
 
 	free_cpumask_var(enable_mask);
 	if (need_disable)
@@ -1228,6 +1261,7 @@ static int rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
 
 out_clear:
 	cpumask_clear(&rdtgrp->kmode_cpu_mask);
+	resctrl_kmode_files_set_visible(rdtgrp, false);
 	rdtgrp->kmode = false;
 	return 0;
 }
@@ -3387,6 +3421,8 @@ static int rdt_get_tree(struct fs_context *fc)
 	if (ret)
 		goto out_closid_exit;
 
+	/* Hide before activate; the kernfs hidden flag survives kernfs_activate(). */
+	resctrl_kmode_files_set_visible(&rdtgroup_default, false);
 	kernfs_activate(rdtgroup_default.kn);
 
 	ret = rdtgroup_create_info_dir(rdtgroup_default.kn);
@@ -4411,6 +4447,8 @@ static int rdtgroup_mkdir_mon(struct kernfs_node *parent_kn,
 		goto out_unlock;
 	}
 
+	/* Hide before activate; the kernfs hidden flag survives kernfs_activate(). */
+	resctrl_kmode_files_set_visible(rdtgrp, false);
 	kernfs_activate(rdtgrp->kn);
 
 	/*
@@ -4455,6 +4493,8 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
 	if (ret)
 		goto out_closid_free;
 
+	/* Hide before activate; the kernfs hidden flag survives kernfs_activate(). */
+	resctrl_kmode_files_set_visible(rdtgrp, false);
 	kernfs_activate(rdtgrp->kn);
 
 	ret = rdtgroup_init_alloc(rdtgrp);
Signature · 1 line
2.43.0
author reviewer
#48 lore raw

PATCH v3 12/12 fs/resctrl: Allow user space to write kmode_cpus / kmode_cpus_list

In reply to Babu Moger

The kmode_cpus and kmode_cpus_list files are read-only, so adjusting the per-group CPU scope after a bind requires a full unbind/rebind via info/kernel_mode -- reprogramming hardware on every online CPU even for a single-CPU change.

Make both files writable (mode 0644). The handler validates the input (rejecting pseudo-locked groups and offline CPUs), computes the delta between rdtgrp->kmode_cpu_mask and the new mask, and reprograms hardware incrementally: only the CPUs whose enable state changes hit resctrl_arch_configure_kmode(). The new mask is then stored in rdtgrp->kmode_cpu_mask so the next rdtgroup_config_kmode() at re-bind sees it.

Documentation/filesystems/resctrl.rst is updated alongside.

---
v3: New patch to add "kmode_cpus" and "kmode_cpus_list" to support
kernel_modes.

---
 Documentation/filesystems/resctrl.rst |  33 +++++
 fs/resctrl/rdtgroup.c                 | 183 +++++++++++++++++++++++++-
 2 files changed, 214 insertions(+), 2 deletions(-)
Documentation/filesystems/resctrl.rst +33 -0
index 89fbf8b4fb2a..aebd9a649773 100644
@@ -636,6 +636,39 @@ All groups contain the following files:
 "cpus_list":
 	Just like "cpus", only using ranges of CPUs instead of bitmasks.
 
+"kmode_cpus":
+	Visible only on the rdtgroup currently bound to the active kernel
+	mode (see "info/kernel_mode"); hidden on every other rdtgroup,
+	including the default group while INHERIT_CTRL_AND_MON is active.
+
+	Bitmask of the logical CPUs scoped for this group's kernel-mode
+	binding (PLZA on x86).  An empty mask is reported as a bare newline
+	and is interpreted by the bind path as "every online CPU".
+
+	Writing a mask reprograms the binding incrementally: it enables on
+	the CPUs newly added by the write and disables on the CPUs dropped
+	from the previous mask.  The mask must be non-empty and contain only
+	online CPUs; empty masks and masks naming offline CPUs are rejected
+	with -EINVAL.  To reset the binding to "every online CPU", use
+	info/kernel_mode to unbind and rebind the group rather than writing
+	here.  Writes to a group that is not the active kernel-mode binding
+	are rejected with -EBUSY.  Reading returns -ENODEV for a
+	pseudo-locked group and -ENOENT for a deleted group; writes to
+	pseudo-locked or pseudo-lock-setup groups are rejected with
+	-EINVAL.  Errors are reported in "info/last_cmd_status".  Example::
+
+	  # mkdir ctrl1
+	  # echo "global_assign_ctrl_inherit_mon_per_cpu:group=ctrl1//" \
+	        > info/kernel_mode
+	  # echo 0-3 > ctrl1/kmode_cpus_list
+	  # cat ctrl1/kmode_cpus
+	  f
+	  # cat ctrl1/kmode_cpus_list
+	  0-3
+
+"kmode_cpus_list":
+	Just like "kmode_cpus", only using ranges of CPUs instead of bitmasks.
+
 
 When control is enabled all CTRL_MON groups will also contain:
 
fs/resctrl/rdtgroup.c +181 -2

202 lines not on this page · raw message

Signature · 1 line
2.43.0
#49 lore raw
In reply to Babu Moger

Hi Babu,

While reviewing this series I noticed two cross-architecture issues.

1) aarch64 allyesconfig link failure

resctrl_arch_configure_kmode() and resctrl_arch_get_kmode_support() are declared in include/linux/resctrl.h:

     void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg);
     void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask,
                                       u32 closid, u32 rmid, bool enable);

but only implemented under arch/x86/. ARM MPAM selects CONFIG_RESCTRL_FS, so fs/resctrl/rdtgroup.c is compiled on aarch64 and the linker fails:

ld: fs/resctrl/rdtgroup.o: in function `rdtgroup_config_kmode_clear':
rdtgroup.c: undefined reference to `resctrl_arch_configure_kmode'
ld: fs/resctrl/rdtgroup.o: in function `resctrl_init':
rdtgroup.c: undefined reference to `resctrl_arch_get_kmode_support'

Other arch-specific functions already have empty stubs in drivers/resctrl/mpam_resctrl.c, e.g.:

     int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
     {
             return -EOPNOTSUPP;
     }

Adding the same for the two kmode functions would fix the build.

2) info/kernel_mode visible on non-PLZA platforms

The "kernel_mode" entry is registered with fflags = RFTYPE_TOP_INFO:

     {
             .name           = "kernel_mode",
             .mode           = 0644,
             ...
             .fflags         = RFTYPE_TOP_INFO,
     },

This makes the file appear unconditionally under info/ -- even on platforms without PLZA (ARM MPAM, older AMD/Intel without X86_FEATURE_PLZA). On those platforms the file only shows the default inherit_ctrl_and_mon mode, which is confusing since there are no other modes to switch to.

The io_alloc file handles this by starting with fflags = 0 and enabling it conditionally:

     /* io_alloc: fflags defaults to 0 (hidden) */

     static void io_alloc_init(void)
     {
             if (r->cache.io_alloc_capable) {
                     resctrl_file_fflags_init("io_alloc", ...);
             }
     }

The same pattern could work for kernel_mode: set fflags = 0 and call resctrl_file_fflags_init("kernel_mode", RFTYPE_TOP_INFO) in resctrl_kmode_init() only when resctrl_arch_get_kmode_support() registers modes beyond INHERIT_CTRL_AND_MON.

Thanks,
Qinyun

author reviewer
#50 lore raw

Hi Qinyun,

Quoted 25 lines · Qinyun Tan

Hi Babu,

While reviewing this series I noticed two cross-architecture issues.

1) aarch64 allyesconfig link failure

resctrl_arch_configure_kmode() and resctrl_arch_get_kmode_support() are declared in include/linux/resctrl.h:

void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg); void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask,
u32 closid, u32 rmid, bool enable);

but only implemented under arch/x86/. ARM MPAM selects CONFIG_RESCTRL_FS, so fs/resctrl/rdtgroup.c is compiled on aarch64 and the linker fails:

ld: fs/resctrl/rdtgroup.o: in function `rdtgroup_config_kmode_clear':
rdtgroup.c: undefined reference to `resctrl_arch_configure_kmode'
ld: fs/resctrl/rdtgroup.o: in function `resctrl_init':
rdtgroup.c: undefined reference to `resctrl_arch_get_kmode_support'

Other arch-specific functions already have empty stubs in drivers/resctrl/mpam_resctrl.c, e.g.:

Quoted 6 lines

int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable) {
return -EOPNOTSUPP;
}

Adding the same for the two kmode functions would fix the build.

Good catch. Will add in empty stubs in next revision for these 3 functions.

Quoted 12 lines

2) info/kernel_mode visible on non-PLZA platforms

The "kernel_mode" entry is registered with fflags = RFTYPE_TOP_INFO:

{
.name = "kernel_mode",
.mode = 0644,
...
.fflags = RFTYPE_TOP_INFO,
},

Quoted 5 lines

This makes the file appear unconditionally under info/ -- even on platforms without PLZA (ARM MPAM, older AMD/Intel without X86_FEATURE_PLZA). On those platforms the file only shows the default inherit_ctrl_and_mon mode, which is confusing since there are no other modes to switch to.

This is expected. We intended to expose the info/kernel_mode file for all architectures, and it will display the default mode inherit_ctrl_and_mon.

This approach was also suggested by Reinette.
https://lore.kernel.org/lkml/[email protected]/

Thanks
Babu

#51 lore raw
Quoted 1 line · Babu Moger

Good catch. Will add in empty stubs in next revision for these 3 functions.

Thanks.

Quoted 4 lines

This is expected. We intended to expose the info/kernel_mode file for all architectures, and it will display the default mode inherit_ctrl_and_mon.

This approach was also suggested by Reinette.
https://lore.kernel.org/lkml/2ab556af-095b-422b-9396- [email protected]/

Got it, makes sense. Thanks for the pointer to Reinette's suggestion.

Qinyun

#52 lore raw

PATCH 1/4 resctrl: Add kmode arch stubs for ARM MPAM and hide kernel_mode on non-PLZA platforms

In reply to Babu Moger

fs/resctrl/rdtgroup.c calls resctrl_arch_get_kmode_support() and resctrl_arch_configure_kmode() which are only implemented under arch/x86/. ARM MPAM enables CONFIG_RESCTRL_FS but has no PLZA hardware, causing link failures on aarch64 allyesconfig:

undefined reference to resctrl_arch_configure_kmode' undefined reference to resctrl_arch_get_kmode_support'

Add empty stubs in drivers/resctrl/mpam_resctrl.c, following the same pattern used for resctrl_arch_io_alloc_enable().

Additionally, the kernel_mode file under info/ was unconditionally visible (fflags = RFTYPE_TOP_INFO). On platforms without PLZA (ARM MPAM, older AMD/Intel), the file shows only inherit_ctrl_and_mon with no other options, which is unnecessary. Set the initial fflags to 0 and dynamically enable the file in resctrl_kmode_init() only when resctrl_arch_get_kmode_support() registers additional modes, matching the io_alloc pattern.

---
 drivers/resctrl/mpam_resctrl.c | 9 +++++++++
 fs/resctrl/rdtgroup.c          | 5 ++++-
 2 files changed, 13 insertions(+), 1 deletion(-)
drivers/resctrl/mpam_resctrl.c +9 -0
index 1dd3bbd0772cd..fc2b3f508c039 100644
@@ -161,6 +161,15 @@ bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r)
 	return false;
 }
 
+void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg)
+{
+}
+
+void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask, u32 closid,
+				  u32 rmid, bool enable)
+{
+}
+
 void resctrl_arch_pre_mount(void)
 {
 }
fs/resctrl/rdtgroup.c +4 -1
index dd9c4da836983..0b2606f10e2e9 100644
@@ -2602,7 +2602,7 @@ static struct rftype res_common_files[] = {
 		.kf_ops		= &rdtgroup_kf_single_ops,
 		.seq_show	= resctrl_kernel_mode_show,
 		.write		= resctrl_kernel_mode_write,
-		.fflags		= RFTYPE_TOP_INFO,
+		.fflags		= 0,
 	},
 	{
 		.name		= "mbm_assign_on_mkdir",
@@ -2968,6 +2968,9 @@ static void resctrl_kmode_init(void)
 	resctrl_kcfg.k_rdtgrp = &rdtgroup_default;
 
 	resctrl_arch_get_kmode_support(&resctrl_kcfg);
+
+	if (resctrl_kcfg.kmode != BIT(INHERIT_CTRL_AND_MON))
+		resctrl_file_fflags_init("kernel_mode", RFTYPE_TOP_INFO);
 }
 
 void resctrl_file_fflags_init(const char *config, unsigned long fflags)
Signature · 1 line
2.43.7
#53 lore raw

PATCH v2 1/4 resctrl: Add kmode arch stubs for ARM MPAM

fs/resctrl/rdtgroup.c calls resctrl_arch_get_kmode_support() and resctrl_arch_configure_kmode() which are only implemented under arch/x86/. ARM MPAM enables CONFIG_RESCTRL_FS but has no PLZA hardware, causing link failures on aarch64:

undefined reference to resctrl_arch_configure_kmode' undefined reference to resctrl_arch_get_kmode_support'

Add empty stubs in drivers/resctrl/mpam_resctrl.c, following the same pattern used for resctrl_arch_io_alloc_enable().

---
v2: Drop the "hide info/kernel_mode on non-PLZA platforms" change that
v1 folded in. Babu clarified that exposing info/kernel_mode on all architectures (showing the default inherit_ctrl_and_mon) is intended, as also suggested by Reinette [1]. This patch therefore only adds the ARM MPAM arch stubs, i.e. the aarch64 link-failure fix.

[1] https://lore.kernel.org/lkml/[email protected]/

 drivers/resctrl/mpam_resctrl.c | 9 +++++++++
 1 file changed, 9 insertions(+)
drivers/resctrl/mpam_resctrl.c +9 -0
index 1dd3bbd0772cd..fc2b3f508c039 100644
@@ -161,6 +161,15 @@ bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r)
 	return false;
 }
 
+void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg)
+{
+}
+
+void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask, u32 closid,
+				  u32 rmid, bool enable)
+{
+}
+
 void resctrl_arch_pre_mount(void)
 {
 }
Signature · 1 line
2.43.7
#54 lore raw

PATCH 2/4 resctrl: Fix PLZA RMID_EN to be mode-based and relax RDTMON_GROUP constraint for assign_mon

In reply to Babu Moger

Two issues identified during review of the upstream v3 PLZA patches, confirmed by the patch author (Babu Moger):

1) resctrl_arch_configure_kmode() hardcodes rmid_en=1 for both inherit_mon and assign_mon modes. Per the AMD hardware manual (Publication #69193), RMID_EN is a source selector: when set, CPL=0 uses the PLZA RMID; when clear, CPL=0 falls back to PQR_ASSOC[RMID] (the user process's RMID). With rmid_en=1 in inherit_mon mode, kernel-mode traffic is always counted under the PLZA group's RMID, defeating the "inherit" semantics.

Add a bool assign_rmid parameter to resctrl_arch_configure_kmode(). Set rmid_en=1 only for assign_mon (GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU), and rmid_en=0 for inherit_mon (GLOBAL_ASSIGN_CTRL_INHERIT_MON_PER_CPU) so that kernel-mode RMID correctly inherits from PQR_ASSOC.

The assign_rmid value is derived from the active kmode in all three call sites: rdtgroup_config_kmode(), rdtgroup_config_kmode_clear(), and kmode_cpus_write().

2) global_assign_ctrl_assign_mon_per_cpu (assign_mon) forces binding to an RDTMON_GROUP, requiring users to create an extra monitor sub-group. Since the kernel-mode group is dedicated (no user tasks), the ctrl group's own RMID is clean and usable. The extra monitor group wastes a scarce RMID for no benefit.

Remove the RDTMON_GROUP constraint for assign_mon so it accepts both RDTCTRL_GROUP and RDTMON_GROUP. The RDTCTRL_GROUP constraint for inherit_mon is kept (it needs only a CLOSID, not a separate RMID).

Upstream confirmation:
https://lore.kernel.org/all/[email protected]/

---
 arch/x86/kernel/cpu/resctrl/ctrlmondata.c |  9 ++--
 drivers/resctrl/mpam_resctrl.c            |  2 +-
 fs/resctrl/rdtgroup.c                     | 55 ++++++++++++++---------
 include/linux/resctrl.h                   |  8 ++--
 4 files changed, 45 insertions(+), 29 deletions(-)
arch/x86/kernel/cpu/resctrl/ctrlmondata.c +6 -3
index 5de02a45b58e2..98bc079024219 100644
@@ -234,18 +234,21 @@ static void resctrl_kmode_set_one_amd(void *arg)
  * resctrl_arch_configure_kmode() - x86/AMD: program PLZA MSR on a CPU subset
  * @cpu_mask:	CPUs to receive the update (see on_each_cpu_mask() for online subset).
  * @closid:	CLOSID field written into the MSR with CLOSID_EN set.
- * @rmid:	RMID field written into the MSR with RMID_EN set.
+ * @rmid:	RMID field written into the MSR (only used when @assign_rmid is true).
+ * @assign_rmid: When true, set RMID_EN so CPL=0 uses the PLZA RMID; when false,
+ *		clear RMID_EN so CPL=0 inherits RMID from PQR_ASSOC.
  * @enable:	Value for the PLZA_EN split field.
  *
  * Context: Do not call with IRQs off or from IRQ context except as allowed for
  * on_each_cpu_mask(); see kernel/smp.c.
  */
-void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask, u32 closid, u32 rmid, bool enable)
+void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask, u32 closid,
+				  u32 rmid, bool assign_rmid, bool enable)
 {
 	union msr_pqr_plza_assoc plza = { 0 };
 
 	plza.split.rmid = rmid;
-	plza.split.rmid_en = 1;
+	plza.split.rmid_en = assign_rmid ? 1 : 0;
 	plza.split.closid = closid;
 	plza.split.closid_en = 1;
 	plza.split.plza_en = enable;
drivers/resctrl/mpam_resctrl.c +1 -1
index fc2b3f508c039..dcf0339d92e5b 100644
@@ -166,7 +166,7 @@ void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg)
 }
 
 void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask, u32 closid,
-				  u32 rmid, bool enable)
+				  u32 rmid, bool assign_rmid, bool enable)
 {
 }
 
fs/resctrl/rdtgroup.c +33 -22

141 lines not on this page · raw message

include/linux/resctrl.h +5 -3
index e2135f0d42506..256449a0c92ff 100644
@@ -724,11 +724,13 @@ void resctrl_arch_get_kmode_support(struct resctrl_kmode_cfg *kcfg);
  * resctrl_arch_configure_kmode() - Program MSR_IA32_PQR_PLZA_ASSOC on CPUs in @cpu_mask
  * @cpu_mask:	Target CPUs; on_each_cpu_mask() applies the callback on the online subset.
  * @closid:	CLOSID written to the MSR with CLOSID_EN set.
- * @rmid:	RMID written to the MSR with RMID_EN set.
+ * @rmid:	RMID written to the MSR (only used when @assign_rmid is true).
+ * @assign_rmid: When true, set RMID_EN so CPL=0 uses the PLZA RMID; when false,
+ *		clear RMID_EN so CPL=0 inherits RMID from PQR_ASSOC.
  * @enable:	PLZA_EN field value for this update.
  */
-void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask, u32 closid, u32 rmid,
-				  bool enable);
+void resctrl_arch_configure_kmode(const struct cpumask *cpu_mask, u32 closid,
+				  u32 rmid, bool assign_rmid, bool enable);
 
 extern unsigned int resctrl_rmid_realloc_threshold;
 extern unsigned int resctrl_rmid_realloc_limit;
Signature · 1 line
2.43.7
#55 lore raw

cover x86,fs/resctrl: kernel-mode (PLZA) fixes found during review

In reply to Babu Moger

Hi Babu,

While reviewing this v3 series I found a few issues in the kernel-mode (PLZA) support and wrote a fix for each.
I'm sending them as a small follow-up set on top of v3 so they are easy to fold into the next revision, or to take as separate patches -- whichever you prefer. The patches are ordered by dependency (build fix -> semantic fix -> the two binding fixes) so the series is bisectable on top of v3.

Patch 1 (ARM MPAM build fix): fs/resctrl now calls resctrl_arch_get_kmode_support()/resctrl_arch_configure_kmode(), which are only implemented on x86, so an aarch64 allyesconfig (MPAM) fails to link. Add empty arch stubs, and hide info/kernel_mode on platforms that advertise no mode beyond inherit_ctrl_and_mon.

Patch 2 (RMID_EN + RDTMON_GROUP): RMID_EN is hardcoded to 1, so inherit_mon counts kernel-mode traffic under the PLZA RMID instead of inheriting from PQR_ASSOC; and assign_mon is forced to bind an RDTMON_GROUP, wasting an RMID. Make RMID_EN mode-based and let assign_mon also accept a control group. This is the issue we discussed earlier and you confirmed; this is the patch for it.

Patch 3 (atomic switch): resctrl_kernel_mode_write() releases the previous binding before it programs the new one. If programming the new binding fails (-ENOMEM, or a pseudo-locked target group), the old, working binding is already gone -- a user who only tried to switch loses the original configuration too. Make the switch atomic: all fallible work is done before the old binding is released, so a failed switch is a no-op.

Patch 4 (CPU online): the PLZA MSR is per-CPU and is only written over the CPUs that are online at bind time / mask change; nothing reprograms a CPU that comes online afterwards. A hot-added vCPU, or a CPU that was offline at bind time, then runs with PLZA off although it is in scope, while info/kernel_mode still reports the binding as active. Drive the per-CPU state from resctrl_online_cpu() so it is synced idempotently on every online (and stale enable bits are cleared for a CPU that left the scope while offline).

Concretely, the patch 4 failure mode is: offline a CPU, bind a global-assign mode while it is absent, then online it -- the onlined CPU is left with PLZA_EN=0 although it is in scope, while a CPU that was present at bind time has PLZA_EN=1, so its CPL0 traffic is not accounted to the bound kernel-mode group.

I'd appreciate your view on whether these match your intent for the design.

Qinyun Tan (4):
resctrl: Add kmode arch stubs for ARM MPAM and hide kernel_mode on
non-PLZA platforms
resctrl: Fix PLZA RMID_EN to be mode-based and relax RDTMON_GROUP
constraint for assign_mon
fs/resctrl: make a failed kernel-mode switch a no-op fs/resctrl: program PLZA on a CPU that comes online under a binding

 arch/x86/kernel/cpu/resctrl/ctrlmondata.c |   9 +-
 drivers/resctrl/mpam_resctrl.c            |   9 +
 fs/resctrl/rdtgroup.c                     | 235 ++++++++++++++--------
 include/linux/resctrl.h                   |   8 +-
 4 files changed, 171 insertions(+), 90 deletions(-)
Signature · 1 line
2.43.7
author reviewer
#56 lore raw

Re: [PATCH 0/4] x86,fs/resctrl: kernel-mode (PLZA) fixes found during review

Hi Qinyun,

Quoted 49 lines · Qinyun Tan

Hi Babu,

While reviewing this v3 series I found a few issues in the kernel-mode (PLZA) support and wrote a fix for each.
I'm sending them as a small follow-up set on top of v3 so they are easy to fold into the next revision, or to take as separate patches -- whichever you prefer. The patches are ordered by dependency (build fix -> semantic fix -> the two binding fixes) so the series is bisectable on top of v3.

Patch 1 (ARM MPAM build fix): fs/resctrl now calls resctrl_arch_get_kmode_support()/resctrl_arch_configure_kmode(), which are only implemented on x86, so an aarch64 allyesconfig (MPAM) fails to link. Add empty arch stubs, and hide info/kernel_mode on platforms that advertise no mode beyond inherit_ctrl_and_mon.

Patch 2 (RMID_EN + RDTMON_GROUP): RMID_EN is hardcoded to 1, so inherit_mon counts kernel-mode traffic under the PLZA RMID instead of inheriting from PQR_ASSOC; and assign_mon is forced to bind an RDTMON_GROUP, wasting an RMID. Make RMID_EN mode-based and let assign_mon also accept a control group. This is the issue we discussed earlier and you confirmed; this is the patch for it.

Patch 3 (atomic switch): resctrl_kernel_mode_write() releases the previous binding before it programs the new one. If programming the new binding fails (-ENOMEM, or a pseudo-locked target group), the old, working binding is already gone -- a user who only tried to switch loses the original configuration too. Make the switch atomic: all fallible work is done before the old binding is released, so a failed switch is a no-op.

Patch 4 (CPU online): the PLZA MSR is per-CPU and is only written over the CPUs that are online at bind time / mask change; nothing reprograms a CPU that comes online afterwards. A hot-added vCPU, or a CPU that was offline at bind time, then runs with PLZA off although it is in scope, while info/kernel_mode still reports the binding as active. Drive the per-CPU state from resctrl_online_cpu() so it is synced idempotently on every online (and stale enable bits are cleared for a CPU that left the scope while offline).

Concretely, the patch 4 failure mode is: offline a CPU, bind a global-assign mode while it is absent, then online it -- the onlined CPU is left with PLZA_EN=0 although it is in scope, while a CPU that was present at bind time has PLZA_EN=1, so its CPL0 traffic is not accounted to the bound kernel-mode group.

I'd appreciate your view on whether these match your intent for the design.

Quoted 7 lines

Qinyun Tan (4):
resctrl: Add kmode arch stubs for ARM MPAM and hide kernel_mode on
non-PLZA platforms
resctrl: Fix PLZA RMID_EN to be mode-based and relax RDTMON_GROUP
constraint for assign_mon
fs/resctrl: make a failed kernel-mode switch a no-op fs/resctrl: program PLZA on a CPU that comes online under a binding

I have gone thru all your patches. Patches look good to me. I also ran some basic tests to make sure it works as expected.

Note the I am still waiting for comments from maintainer (Reinette).

I will fold your changes in v4 whenever that happens.

Thanks for the review and changes.

Thanks
Babu

#57 lore raw

PATCH 3/4 fs/resctrl: make a failed kernel-mode switch a no-op

In reply to Babu Moger

resctrl_kernel_mode_write() used to tear down the previous kernel-mode (PLZA) binding via rdtgroup_config_kmode_clear() before programming the new one with rdtgroup_config_kmode(). When programming the new binding failed (e.g. -ENOMEM on cpumask allocation, or -EINVAL for a pseudo-locked target group), the old binding had already been disabled in hardware (PLZA_EN cleared on its CPUs, the old group's kmode bookkeeping reset and its kmode_cpus files hidden).

This is unacceptable from a user's point of view: a user who merely tries to switch an already-working kernel_mode configuration to a new one ends up losing the original configuration as well once the new switch fails. A failed mode switch must be a no-op and leave the existing binding untouched.

Make the switch atomic by performing all fallible work up front, before the old binding is released:

- Move the pseudo-locked group check into resctrl_kernel_mode_write() so it runs before the old binding is torn down.
- Pre-allocate the enable/disable cpumasks in the writer and pass them to rdtgroup_config_kmode(), which then can no longer fail and is turned into a void function.
- Turn rdtgroup_config_kmode_clear() into a void function as well: the arch hook resctrl_arch_configure_kmode() takes a const cpumask and the CPUs to disable are always a ready-made set (the group's kmode_cpu_mask, or cpu_online_mask when it is empty), so the temporary cpumask it used to allocate is unnecessary and is removed, eliminating its only failure point.

After this change rdtgroup_config_kmode_clear() (release of the old binding) is only reached once everything needed to program the new binding is already in hand, so the subsequent programming step cannot fail. On any error the function returns with hardware and resctrl_kcfg left exactly as they were, preserving the user's existing configuration.

---
 fs/resctrl/rdtgroup.c | 132 +++++++++++++++++++++---------------------
 1 file changed, 66 insertions(+), 66 deletions(-)
fs/resctrl/rdtgroup.c +66 -66
index 1d9bd34eb9cdd..cef6ab75c2b57 100644
@@ -1315,6 +1315,11 @@ static void resctrl_kmode_files_set_visible(struct rdtgroup *rdtgrp, bool visibl
  *		the RMID_EN setting: BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU)
  *		sets RMID_EN so CPL=0 uses the PLZA RMID; other modes clear it
  *		so CPL=0 inherits the user process's RMID from PQR_ASSOC.
+ * @enable_mask:	Caller-provided scratch cpumask used to compute the set of
+ *		CPUs to enable.  Pre-allocated by the caller so this function
+ *		cannot fail after the previous binding has been torn down.
+ * @disable_mask: Caller-provided scratch cpumask used to compute the set of
+ *		CPUs to disable.  Same rationale as @enable_mask.
  *
  * Derives CLOSID/RMID from @rdtgrp->type:
  *   - RDTMON_GROUP: parent control group's CLOSID with the monitor group's RMID.
@@ -1326,30 +1331,22 @@ static void resctrl_kmode_files_set_visible(struct rdtgroup *rdtgrp, bool visibl
  * stale enable bits from a previously bound group are cleared in the same
  * reprogram step.
  *
- * Context: Caller must hold rdtgroup_mutex.
+ * All fallible work (pseudo-lock validation and cpumask allocation) is done
+ * by the caller before the previous binding is released, so this function
+ * never fails and is therefore void: a failed mode switch can leave the
+ * existing configuration untouched.
  *
- * Return: 0 on success, -EINVAL for a pseudo-locked group, -ENOMEM if
- * cpumask allocation fails.
+ * Context: Caller must hold rdtgroup_mutex.  @rdtgrp must not be
+ * pseudo-locked (validated by the caller).
  */
-static int rdtgroup_config_kmode(struct rdtgroup *rdtgrp, u32 kmode)
+static void rdtgroup_config_kmode(struct rdtgroup *rdtgrp, u32 kmode,
+				  struct cpumask *enable_mask,
+				  struct cpumask *disable_mask)
 {
-	cpumask_var_t enable_mask, disable_mask;
 	u32 closid, rmid;
 	bool need_disable, assign_rmid;
 
-	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
-		rdt_last_cmd_puts("Resource group is pseudo-locked\n");
-		return -EINVAL;
-	}
-
-	if (!zalloc_cpumask_var(&enable_mask, GFP_KERNEL))
-		return -ENOMEM;
-
 	need_disable = !cpumask_empty(&rdtgrp->kmode_cpu_mask);
-	if (need_disable && !zalloc_cpumask_var(&disable_mask, GFP_KERNEL)) {
-		free_cpumask_var(enable_mask);
-		return -ENOMEM;
-	}
 
 	if (rdtgrp->type == RDTMON_GROUP) {
 		closid = rdtgrp->mon.parent->closid;
@@ -1383,12 +1380,6 @@ static int rdtgroup_config_kmode(struct rdtgroup *rdtgrp, u32 kmode)
 
 	rdtgrp->kmode = true;
 	resctrl_kmode_files_set_visible(rdtgrp, true);
-
-	free_cpumask_var(enable_mask);
-	if (need_disable)
-		free_cpumask_var(disable_mask);
-
-	return 0;
 }
 
 /**
@@ -1409,30 +1400,24 @@ static int rdtgroup_config_kmode(struct rdtgroup *rdtgrp, u32 kmode)
  * skips rdtgroup_config_kmode() entirely -- still tears down the previously
  * bound group instead of leaving stale enable bits behind.
  *
- * On allocation failure the function returns -ENOMEM and leaves both the
- * hardware state and @rdtgrp's bookkeeping unchanged so the caller can fail
- * the operation atomically and last_cmd_status reflects reality.
+ * The arch hook reads the CPU mask without modifying it, so the CPUs to
+ * disable are passed directly (the group's @kmode_cpu_mask, or cpu_online_mask
+ * when that mask is empty) without needing a temporary cpumask.  The function
+ * therefore cannot fail.
  *
  * Context: Caller must hold rdtgroup_mutex.
- *
- * Return: 0 on success (including the @rdtgrp == %NULL and INHERIT cases),
- * -ENOMEM if cpumask allocation fails.
  */
-static int rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
+static void rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
 {
-	cpumask_var_t disable_mask;
 	bool assign_rmid;
 	u32 closid, rmid;
 
 	if (!rdtgrp)
-		return 0;
+		return;
 
 	if (kmode == BIT(INHERIT_CTRL_AND_MON))
 		goto out_clear;
 
-	if (!zalloc_cpumask_var(&disable_mask, GFP_KERNEL))
-		return -ENOMEM;
-
 	if (rdtgrp->type == RDTMON_GROUP) {
 		closid = rdtgrp->mon.parent->closid;
 		rmid = rdtgrp->mon.rmid;
@@ -1443,20 +1428,14 @@ static int rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
 
 	assign_rmid = (kmode == BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU));
 
-	if (cpumask_empty(&rdtgrp->kmode_cpu_mask))
-		cpumask_copy(disable_mask, cpu_online_mask);
-	else
-		cpumask_copy(disable_mask, &rdtgrp->kmode_cpu_mask);
-
-	resctrl_arch_configure_kmode(disable_mask, closid, rmid,
-				     assign_rmid, false);
-	free_cpumask_var(disable_mask);
+	resctrl_arch_configure_kmode(cpumask_empty(&rdtgrp->kmode_cpu_mask) ?
+				     cpu_online_mask : &rdtgrp->kmode_cpu_mask,
+				     closid, rmid, assign_rmid, false);
 
 out_clear:
 	cpumask_clear(&rdtgrp->kmode_cpu_mask);
 	resctrl_kmode_files_set_visible(rdtgrp, false);
 	rdtgrp->kmode = false;
-	return 0;
 }
 
 /**
@@ -1472,11 +1451,6 @@ static int rdtgroup_config_kmode_clear(struct rdtgroup *rdtgrp, int kmode)
  * (&rdtgroup_default, BIT(INHERIT_CTRL_AND_MON)) so subsequent show/write
  * paths do not dereference @rdtgrp after the caller frees it.
  *
- * If the underlying tear-down fails (cpumask allocation), the snapshot is
- * still reset because @rdtgrp is about to disappear; stale enable bits on
- * those CPUs are reported via pr_warn() and will be cleared by the next
- * non-INHERIT reprogram.
- *
  * Context: Caller must hold rdtgroup_mutex.
  */
 static void rdtgroup_config_kmode_delete(struct rdtgroup *rdtgrp)
@@ -1484,8 +1458,7 @@ static void rdtgroup_config_kmode_delete(struct rdtgroup *rdtgrp)
 	if (!rdtgrp || !rdtgrp->kmode)
 		return;
 
-	if (rdtgroup_config_kmode_clear(rdtgrp, resctrl_kcfg.kmode_cur))
-		pr_warn("resctrl: kernel-mode disable failed; stale enable bits may persist\n");
+	rdtgroup_config_kmode_clear(rdtgrp, resctrl_kcfg.kmode_cur);
 
 	if (resctrl_kcfg.k_rdtgrp == rdtgrp) {
 		resctrl_kcfg.k_rdtgrp = &rdtgroup_default;
@@ -1565,12 +1538,15 @@ static struct rdtgroup *rdtgroup_by_kmode_path(const char *ctrl_name,
  * Parses @buf, validates that <mode> is listed in resctrl_mode_str[] and is
  * supported by the platform (resctrl_kcfg.kmode), resolves <ctrl>/<mon>/ to
  * an existing rdtgroup (or picks &rdtgroup_default if no group was specified
- * or if the new mode is INHERIT), clears any previous binding via
- * rdtgroup_config_kmode_clear(), programs hardware via
+ * or if the new mode is INHERIT).  All fallible validation and cpumask
+ * allocation are performed before the previous binding is released via
+ * rdtgroup_config_kmode_clear(); hardware is then programmed via
  * rdtgroup_config_kmode() when @kmode is not BIT(INHERIT_CTRL_AND_MON), and
- * on success updates resctrl_kcfg.k_rdtgrp and resctrl_kcfg.kmode_cur.  The
- * display-only "group=none" form produced by show for inactive modes is
- * rejected.  Errors are reported in last_cmd_status.
+ * resctrl_kcfg.k_rdtgrp / resctrl_kcfg.kmode_cur are updated.  Because every
+ * failure is detected up front, a failed switch is a no-op that leaves the
+ * user's existing configuration intact.  The display-only "group=none" form
+ * produced by show for inactive modes is rejected.  Errors are reported in
+ * last_cmd_status.
  *
  * Return: @nbytes on success, negative errno with last_cmd_status set on error.
  */
@@ -1580,6 +1556,8 @@ static ssize_t resctrl_kernel_mode_write(struct kernfs_open_file *of,
 	char *mode_str, *group_str, *slash;
 	const char *ctrl_name, *mon_name;
 	struct rdtgroup *rdtgrp;
+	cpumask_var_t enable_mask, disable_mask;
+	bool masks_allocated = false;
 	int ret = 0;
 	size_t len;
 	u32 kmode;
@@ -1696,25 +1674,47 @@ static ssize_t resctrl_kernel_mode_write(struct kernfs_open_file *of,
 		goto out_unlock;
 	}
 
-	/* Release the old binding first. */
-	ret = rdtgroup_config_kmode_clear(resctrl_kcfg.k_rdtgrp, resctrl_kcfg.kmode_cur);
-	if (ret) {
-		rdt_last_cmd_puts("Failed to release previous kernel-mode binding\n");
-		goto out_unlock;
-	}
-
+	/*
+	 * Validate and acquire everything that can fail BEFORE the old
+	 * binding is released, so a failed mode switch is a true no-op and
+	 * the user's existing (working) configuration is left intact.
+	 */
 	if (kmode != BIT(INHERIT_CTRL_AND_MON)) {
-		ret = rdtgroup_config_kmode(rdtgrp, kmode);
-		if (ret) {
-			rdt_last_cmd_puts("Kernel mode change failed\n");
+		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
+			rdt_last_cmd_puts("Resource group is pseudo-locked\n");
+			ret = -EINVAL;
 			goto out_unlock;
 		}
+		if (!zalloc_cpumask_var(&enable_mask, GFP_KERNEL)) {
+			ret = -ENOMEM;
+			goto out_unlock;
+		}
+		if (!zalloc_cpumask_var(&disable_mask, GFP_KERNEL)) {
+			free_cpumask_var(enable_mask);
+			ret = -ENOMEM;
+			goto out_unlock;
+		}
+		masks_allocated = true;
 	}
 
+	/*
+	 * Past this point nothing can fail: the old binding is released (a
+	 * void operation) and the new one is programmed with the pre-allocated
+	 * masks, so the switch is atomic.
+	 */
+	rdtgroup_config_kmode_clear(resctrl_kcfg.k_rdtgrp, resctrl_kcfg.kmode_cur);
+
+	if (masks_allocated)
+		rdtgroup_config_kmode(rdtgrp, kmode, enable_mask, disable_mask);
+
 	resctrl_kcfg.k_rdtgrp = rdtgrp;
 	resctrl_kcfg.kmode_cur = kmode;
 
 out_unlock:
+	if (masks_allocated) {
+		free_cpumask_var(enable_mask);
+		free_cpumask_var(disable_mask);
+	}
 	mutex_unlock(&rdtgroup_mutex);
 	cpus_read_unlock();
 	return ret ?: nbytes;
Signature · 1 line
2.43.7
#58 lore raw

PATCH 4/4 fs/resctrl: program PLZA on a CPU that comes online under a binding

In reply to Babu Moger

The kernel-mode (PLZA) MSR (MSR_IA32_PQR_PLZA_ASSOC) is per-CPU and is only written when a binding is configured via info/kernel_mode or when a group's kmode_cpus mask is changed. Both paths only touch the CPUs that are online at that moment, and the CPU hotplug online callback does not reprogram it.

As a result, a CPU that comes online *after* a binding is in place -- a hot-added vCPU, or a CPU that was offline at bind time -- runs with PLZA disabled even though an empty kmode_cpu_mask ("all online CPUs") or an explicit mask says it is in scope. Its CPL0 traffic then uses the default PQR_ASSOC CLOSID/RMID instead of the bound kernel-mode group, so the kernel-mode protection is silently off on that CPU while info/kernel_mode still reports the binding as active.

Make resctrl_online_cpu() the single authoritative sync point: on every CPU online, idempotently drive the CPU to the state it should have under the current binding -- enable PLZA with the bound CLOSID/RMID when the CPU is in scope, otherwise explicitly clear it so stale enable bits left on a CPU that was offline while it was removed from the scope are cleared too (offline CPUs are skipped by the IPI-based reprogram paths and the MSR is not reset by a soft offline). Bail out early on platforms without kernel-mode support so the MSR is never touched there.

offline needs no counterpart: a CPU's PLZA state is fully determined by this online-time sync.

---
 fs/resctrl/rdtgroup.c | 53 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
fs/resctrl/rdtgroup.c +53 -0
index cef6ab75c2b57..35cc0083d1b2f 100644
@@ -5336,11 +5336,64 @@ int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *hdr
 	return err;
 }
 
+/*
+ * resctrl_kmode_online_cpu() - Sync a freshly onlined CPU to its PLZA state
+ * @cpu: The CPU that just came online.
+ *
+ * The kernel-mode (PLZA) MSR is per-CPU and is only written when a binding is
+ * configured or its kmode_cpus mask is changed; nothing reprograms it for a
+ * CPU that comes online afterwards.  Make the online callback the single
+ * authoritative sync point: idempotently drive @cpu to the state it should
+ * have under the current binding.  This both programs a CPU that is onlined
+ * after a binding is in place (e.g. a hot-added vCPU, or a CPU that was
+ * offline at bind time) and clears stale enable bits left on a CPU that was
+ * offline while it was removed from the scope (offline CPUs are skipped by
+ * the IPI-based reprogram paths and the MSR is not reset by a soft offline).
+ *
+ * Scope: an empty kmode_cpu_mask means "all online CPUs" (so @cpu is always
+ * included), a non-empty mask means only the CPUs explicitly listed there.
+ *
+ * Context: Caller must hold rdtgroup_mutex.  Runs on @cpu during the CPU
+ * hotplug online callback, so the MSR write lands on the right CPU and no
+ * cross-CPU IPI is needed.
+ */
+static void resctrl_kmode_online_cpu(unsigned int cpu)
+{
+	struct rdtgroup *rdtgrp = resctrl_kcfg.k_rdtgrp;
+	u32 closid = 0, rmid = 0;
+	bool assign_rmid = false;
+	bool enable = false;
+
+	/* Platform without kernel-mode (PLZA) support: never touch the MSR. */
+	if (!(resctrl_kcfg.kmode & ~BIT(INHERIT_CTRL_AND_MON)))
+		return;
+
+	/* Compute this CPU's correct state under the active binding. */
+	if (resctrl_kcfg.kmode_cur != BIT(INHERIT_CTRL_AND_MON) && rdtgrp &&
+	    (cpumask_empty(&rdtgrp->kmode_cpu_mask) ||
+	     cpumask_test_cpu(cpu, &rdtgrp->kmode_cpu_mask))) {
+		if (rdtgrp->type == RDTMON_GROUP) {
+			closid = rdtgrp->mon.parent->closid;
+			rmid = rdtgrp->mon.rmid;
+		} else {
+			closid = rdtgrp->closid;
+			rmid = rdtgrp->mon.rmid;
+		}
+		assign_rmid = (resctrl_kcfg.kmode_cur == BIT(GLOBAL_ASSIGN_CTRL_ASSIGN_MON_PER_CPU));
+		enable = true;
+	}
+
+	/* Idempotent sync: enable when in scope, otherwise clear stale bits. */
+	resctrl_arch_configure_kmode(cpumask_of(cpu), closid, rmid, assign_rmid, enable);
+}
+
 void resctrl_online_cpu(unsigned int cpu)
 {
 	mutex_lock(&rdtgroup_mutex);
 	/* The CPU is set in default rdtgroup after online. */
 	cpumask_set_cpu(cpu, &rdtgroup_default.cpu_mask);
+	/* Restore the kernel-mode (PLZA) binding on a CPU that just came online. */
+	resctrl_kmode_online_cpu(cpu);
 	mutex_unlock(&rdtgroup_mutex);
 }
 
Signature · 1 line
2.43.7
maintainer
#59 lore raw
In reply to Babu Moger

Hi Babu,

Quoted 5 lines · Babu Moger

Design
======

A new sysfs file, info/kernel_mode, holds a single global policy that selects what kernel work is steered and which rdtgroup it is steered

How should "selects *what* kernel work is steered" be interpreted? Do these modes not all apply to *all* kernel work?

Quoted 5 lines

to. Reads describe the supported modes and the currently-active binding; writes change the policy or rebind to a different group. Look at the thread below for design discussion.
https://lore.kernel.org/lkml/[email protected]/

...

Quoted 7 lines

Examples
========

(See Documentation/filesystems/resctrl.rst, "kernel_mode" and "kmode_cpus" sections, for the full UAPI.)

# Mount resctrl

Quoted 8 lines
  # mount -t resctrl resctrl /sys/fs/resctrl
  # cd /sys/fs/resctrl

# Read the supported modes. The active mode is bracketed and reports

  # the bound "<ctrl>/<mon>/" group; other supported modes report
  # ":group=none" because nothing is bound to them.
  # cat info/kernel_mode
  [inherit_ctrl_and_mon:group=//]

This is unexpected since associating a group to this mode implies that this group is used to manage allocations and monitoring of kernel work but this is not true, right? From what I understand there should be no group associated with this default "inherit_ctrl_and_mon" mode.

Quoted 2 lines

global_assign_ctrl_inherit_mon_per_cpu:group=none global_assign_ctrl_assign_mon_per_cpu:group=none

nit: "none" does not reflect state as clearly as "unset"/"uninitialized"/"NA"

Quoted 12 lines

# Create a CTRL_MON group plus a MON child and bind both the kernel # CLOSID and RMID to them.

  # mkdir ctrl1
  # mkdir ctrl1/mon_groups/mon1
  # echo "global_assign_ctrl_assign_mon_per_cpu:group=ctrl1/mon1/" \
          > info/kernel_mode
  # cat info/kernel_mode
  inherit_ctrl_and_mon:group=none
  global_assign_ctrl_inherit_mon_per_cpu:group=none
  [global_assign_ctrl_assign_mon_per_cpu:group=ctrl1/mon1/]
Quoted 3 lines
  # kmode_cpus and kmode_cpus_list are visible only on the bound group.
  # ls ctrl1/kmode_cpus*
  ctrl1/kmode_cpus  ctrl1/kmode_cpus_list

Since it is ctrl1/mon1 that was bound, should these CPU files not appear in ctrl1/mon_groups/mon1 ?

Quoted 2 lines

# Restrict the binding to a CPU subset; the write is incremental.

Does "incremental" mean that if the file contains CPUs 0-3 then writing "4" would set the CPUs to 0-4? This does not sound right since it is expected that user space can remove CPUs also?

Quoted 6 lines
  # echo 0-3 > ctrl1/kmode_cpus_list
  # cat ctrl1/kmode_cpus
  f
  # cat ctrl1/kmode_cpus_list
  0-3
Quoted 6 lines

# Empty masks are rejected; use info/kernel_mode to reset to # "every online CPU".

  # echo "" > ctrl1/kmode_cpus_list
  bash: echo: write error: Invalid argument
  # cat info/last_cmd_status
  Empty mask not allowed; use info/kernel_mode to unbind

Why are empty masks rejected/not allowed?

Quoted 2 lines

# Disable kernel-mode steering (back to inherit, default group).

This sounds like kernel work is steered to default group which I do not think is accurate for the "inherit_ctrl_and_mon" mode.

Quoted 4 lines
  # echo "inherit_ctrl_and_mon" > info/kernel_mode

Tested on AMD with PLZA; the generic bits build clean on x86 without PLZA support and are no-ops at runtime.

Reinette

#60 lore raw
Quoted 11 lines · Reinette Chatre

Hi Babu,

Quoted 5 lines · Babu Moger

Design
======

A new sysfs file, info/kernel_mode, holds a single global policy that selects what kernel work is steered and which rdtgroup it is steered

How should "selects *what* kernel work is steered" be interpreted? Do these modes not all apply to *all* kernel work?

How about?

A new sysfs file, info/kernel_mode, holds a single global policy for kernel contexts and the rdtgroup associated with the policy.

Quoted 25 lines
Quoted 6 lines

to. Reads describe the supported modes and the currently-active binding; writes change the policy or rebind to a different group. Look at the thread below for design discussion.
https://lore.kernel.org/lkml/[email protected]/

...

Quoted 7 lines

Examples
========

(See Documentation/filesystems/resctrl.rst, "kernel_mode" and "kmode_cpus" sections, for the full UAPI.)

# Mount resctrl

Quoted 8 lines
   # mount -t resctrl resctrl /sys/fs/resctrl
   # cd /sys/fs/resctrl

# Read the supported modes. The active mode is bracketed and reports

   # the bound "<ctrl>/<mon>/" group; other supported modes report
   # ":group=none" because nothing is bound to them.
   # cat info/kernel_mode
   [inherit_ctrl_and_mon:group=//]
Quoted 4 lines

This is unexpected since associating a group to this mode implies that this group is used to manage allocations and monitoring of kernel work but this is not true, right? From what I understand there should be no group associated with this default "inherit_ctrl_and_mon" mode.

The default mode is "inherit_ctrl_and_mon", where both user mode and kernel mode share the same CLOSID and RMID. This is current mode (without this series).

I thought we are going to set the default mode with the default group when system boots up. No?

Quoted 5 lines
Quoted 3 lines

global_assign_ctrl_inherit_mon_per_cpu:group=none global_assign_ctrl_assign_mon_per_cpu:group=none

nit: "none" does not reflect state as clearly as "unset"/"uninitialized"/"NA"

Lets go with "uninitialized".

Quoted 13 lines
Quoted 13 lines

# Create a CTRL_MON group plus a MON child and bind both the kernel # CLOSID and RMID to them.

   # mkdir ctrl1
   # mkdir ctrl1/mon_groups/mon1
   # echo "global_assign_ctrl_assign_mon_per_cpu:group=ctrl1/mon1/" \
           > info/kernel_mode
   # cat info/kernel_mode
   inherit_ctrl_and_mon:group=none
   global_assign_ctrl_inherit_mon_per_cpu:group=none
   [global_assign_ctrl_assign_mon_per_cpu:group=ctrl1/mon1/]
Quoted 6 lines
Quoted 3 lines
   # kmode_cpus and kmode_cpus_list are visible only on the bound group.
   # ls ctrl1/kmode_cpus*
   ctrl1/kmode_cpus  ctrl1/kmode_cpus_list

Since it is ctrl1/mon1 that was bound, should these CPU files not appear in ctrl1/mon_groups/mon1 ?

Correct. Will fix it.

Quoted 6 lines
Quoted 2 lines

# Restrict the binding to a CPU subset; the write is incremental.

Does "incremental" mean that if the file contains CPUs 0-3 then writing "4" would set the CPUs to 0-4? This does not sound right since it is expected that user space can remove CPUs also?

Will remove incremental. Writing "4" will remove 0-3 and keep only 4.

Quoted 7 lines
Quoted 7 lines
   # echo 0-3 > ctrl1/kmode_cpus_list
   # cat ctrl1/kmode_cpus
   f
   # cat ctrl1/kmode_cpus_list
   0-3
Quoted 8 lines
Quoted 6 lines

# Empty masks are rejected; use info/kernel_mode to reset to # "every online CPU".

   # echo "" > ctrl1/kmode_cpus_list
   bash: echo: write error: Invalid argument
   # cat info/last_cmd_status
   Empty mask not allowed; use info/kernel_mode to unbind

Why are empty masks rejected/not allowed?

No specific reason.

When the mode is switched, we discussed earlier to globally apply the mode to all the online CPUs.

At this point reading "kmode_cpus_list" will still report empty.

Users can change it to selectively apply the mode by writing to "kmode_cpus_list".

I was not sure what was the action when empty masks are written.

Should the empty mask apply the mode to all the online CPUs?

Quoted 6 lines
Quoted 3 lines

# Disable kernel-mode steering (back to inherit, default group).

This sounds like kernel work is steered to default group which I do not think is accurate for the "inherit_ctrl_and_mon" mode.

How about ?

Drop the kernel-mode binding and restore inherit_ctrl_and_mon on the default group.

thanks
Babu

maintainer
#61 lore raw

Hi Babu,

Quoted 12 lines · Babu
Quoted 9 lines · Reinette Chatre

Hi Babu,

Quoted 5 lines · Babu Moger

Design
======

A new sysfs file, info/kernel_mode, holds a single global policy that selects what kernel work is steered and which rdtgroup it is steered

Quoted 7 lines
Quoted 2 lines

How should "selects *what* kernel work is steered" be interpreted? Do these modes not all apply to *all* kernel work?

How about?

A new sysfs file, info/kernel_mode, holds a single global policy for kernel contexts and the rdtgroup associated with the policy.

What does "kernel contexts" mean here?
Also, since rdtgroup refers more to "struct rdtgroup" that is internal to resctrl I would suggest "resource group" be used instead.
Consider, for example (this is just something to get started, please do not just copy&paste):

A new resctrl file, info/kernel_mode, holds the global policy for resource allocation and monitoring of kernel work and the resource group (when applicable) associated with the policy.

Quoted 24 lines
Quoted 24 lines
Quoted 5 lines

to.  Reads describe the supported modes and the currently-active binding; writes change the policy or rebind to a different group. Look at the thread below for design discussion.
https://lore.kernel.org/lkml/[email protected]/

...

Quoted 15 lines

Examples
========

(See Documentation/filesystems/resctrl.rst, "kernel_mode" and "kmode_cpus" sections, for the full UAPI.)

   # Mount resctrl

   # mount -t resctrl resctrl /sys/fs/resctrl
   # cd /sys/fs/resctrl

   # Read the supported modes.  The active mode is bracketed and reports

   # the bound "<ctrl>/<mon>/" group; other supported modes report
   # ":group=none" because nothing is bound to them.
   # cat info/kernel_mode
   [inherit_ctrl_and_mon:group=//]
Quoted 8 lines
Quoted 4 lines

This is unexpected since associating a group to this mode implies that this group is used to manage allocations and monitoring of kernel work but this is not true, right? From what I understand there should be no group associated with this default "inherit_ctrl_and_mon" mode.

The default mode is "inherit_ctrl_and_mon", where both user mode and kernel mode share the same CLOSID and RMID. This is current mode (without this series).

I thought we are going to set the default mode with the default group when system boots up. No?

As I have it, the end of our discussion on this topic is at:
https://lore.kernel.org/lkml/[email protected]/

Based on that discussion there is no resource group associated with the default inherit_ctrl_and_mon.
I find the above output confusing to user space since adding the default group as the only group to this mode implies that kernel work inherits resource allocation and monitoring from the default group but that is not correct.

Your answer seems to refer to other discussions about what group should be used for a mode when switching to a new mode and user space has not set the resource group. If not, could you please point me to which discussion you are referring to?

Quoted 9 lines
Quoted 7 lines
Quoted 5 lines

   global_assign_ctrl_inherit_mon_per_cpu:group=none global_assign_ctrl_assign_mon_per_cpu:group=none

nit: "none" does not reflect state as clearly as "unset"/"uninitialized"/"NA"

Lets go with "uninitialized".

ok

...

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
   # echo 0-3 > ctrl1/kmode_cpus_list
   # cat ctrl1/kmode_cpus
   f
   # cat ctrl1/kmode_cpus_list
   0-3

   # Empty masks are rejected; use info/kernel_mode to reset to # "every online CPU".

   # echo "" > ctrl1/kmode_cpus_list
   bash: echo: write error: Invalid argument
   # cat info/last_cmd_status
   Empty mask not allowed; use info/kernel_mode to unbind
Quoted 5 lines
Quoted 1 line

Why are empty masks rejected/not allowed?

No specific reason.

When the mode is switched, we discussed earlier to globally apply the mode to all the online CPUs.

Right. I did not see this being done in this implementation though. As I mentioned in my response to patch #8 it appears that it uses old data from the resource group's kmode_cpu_mask. I do think that applying it to all the online CPUs matches the intention and would make the code much simpler.

Quoted 2 lines

At this point reading "kmode_cpus_list" will still report empty.

I do not think resctrl should do this. This is not accurate and conflicts with the existing cpus resctrl files. It should be simple to just present the actual and accurate data to user space, especially after incorporating Qinyun Tan's contributions.

Quoted 6 lines

Users can change it to selectively apply the mode by writing to "kmode_cpus_list".

I was not sure what was the action when empty masks are written.

Should the empty mask apply the mode to all the online CPUs?

Users are used to being able to use an empty write to remove all CPUs from a resource group. It thus seems intuitive that an empty write to the kmode_cpus file behave similarly. Sounds like this could mean that if user space sets the kmode to global_assign_ctrl_inherit_mon_per_cpu or global_assign_ctrl_assign_mon_per_cpu and then writes an empty mask to kmode_cpus then it would essentially be setting inherit_ctrl_and_mon mode? This still seems ok since if disabling one of the "global" modes on a CPU results in that CPU inheriting from PQR_ASSOC then it seems reasonable to extend to when that mode is disabled for all CPUs.

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

   # Disable kernel-mode steering (back to inherit, default group).

This sounds like kernel work is steered to default group which I do not think is accurate for the "inherit_ctrl_and_mon" mode.

How about ?

Drop the kernel-mode binding and restore inherit_ctrl_and_mon on the default group.

No. There is no "inherit_ctrl_and_mon on the default group". There is nothing special about the default group when it comes to inherit_ctrl_and_mon mode ... or am I missing something?
This could be something like: "Activate inherit_ctrl_and_mon mode to let kernel work inherit the resource allocation and monitoring from the user space task." (and drop the default group from the output associated with inherit_ctrl_and_mon)

Reinette

author reviewer
#62 lore raw

Hi Reinette,

Quoted 29 lines · Reinette Chatre

Hi Babu,

Quoted 12 lines · Babu
Quoted 9 lines · Reinette Chatre

Hi Babu,

Quoted 5 lines · Babu Moger

Design
======

A new sysfs file, info/kernel_mode, holds a single global policy that selects what kernel work is steered and which rdtgroup it is steered

Quoted 7 lines
Quoted 2 lines

How should "selects *what* kernel work is steered" be interpreted? Do these modes not all apply to *all* kernel work?

How about?

A new sysfs file, info/kernel_mode, holds a single global policy for kernel contexts and the rdtgroup associated with the policy.

What does "kernel contexts" mean here?
Also, since rdtgroup refers more to "struct rdtgroup" that is internal to resctrl I would suggest "resource group" be used instead.
Consider, for example (this is just something to get started, please do not just copy&paste):

Quoted 3 lines

A new resctrl file, info/kernel_mode, holds the global policy for resource allocation and monitoring of kernel work and the resource group (when applicable) associated with the policy.

Sounds good.

Quoted 35 lines
Quoted 26 lines
Quoted 26 lines
Quoted 7 lines

to.  Reads describe the supported modes and the currently-active binding; writes change the policy or rebind to a different group. Look at the thread below for design discussion.
https://lore.kernel.org/lkml/[email protected]/

...

Quoted 15 lines

Examples
========

(See Documentation/filesystems/resctrl.rst, "kernel_mode" and "kmode_cpus" sections, for the full UAPI.)

   # Mount resctrl

    # mount -t resctrl resctrl /sys/fs/resctrl
    # cd /sys/fs/resctrl

   # Read the supported modes.  The active mode is bracketed and reports

    # the bound "<ctrl>/<mon>/" group; other supported modes report
    # ":group=none" because nothing is bound to them.
    # cat info/kernel_mode
    [inherit_ctrl_and_mon:group=//]
Quoted 8 lines
Quoted 4 lines

This is unexpected since associating a group to this mode implies that this group is used to manage allocations and monitoring of kernel work but this is not true, right? From what I understand there should be no group associated with this default "inherit_ctrl_and_mon" mode.

The default mode is "inherit_ctrl_and_mon", where both user mode and kernel mode share the same CLOSID and RMID. This is current mode (without this series).

I thought we are going to set the default mode with the default group when system boots up. No?

Quoted 8 lines

As I have it, the end of our discussion on this topic is at:
https://lore.kernel.org/lkml/[email protected]/

Based on that discussion there is no resource group associated with the default inherit_ctrl_and_mon.
I find the above output confusing to user space since adding the default group as the only group to this mode implies that kernel work inherits resource allocation and monitoring from the default group but that is not correct.

Ah, I misunderstood earlier.

The display will look like this when the system boots up.

# cat info/kernel_mode
  inherit_ctrl_and_mon:
  global_assign_ctrl_assign_mon_per_cpu:group=uninitialized
  global_assign_ctrl_assign_mon_per_cpu:group=uninitialized

There will not be any group associated with "inherit_ctrl_and_mon". It is only used to switch from other two modes.

Quoted 33 lines

Your answer seems to refer to other discussions about what group should be used for a mode when switching to a new mode and user space has not set the resource group. If not, could you please point me to which discussion you are referring to?

Quoted 9 lines
Quoted 7 lines
Quoted 5 lines

   global_assign_ctrl_inherit_mon_per_cpu:group=none global_assign_ctrl_assign_mon_per_cpu:group=none

nit: "none" does not reflect state as clearly as "unset"/"uninitialized"/"NA"

Lets go with "uninitialized".

ok

...

Quoted 15 lines
Quoted 14 lines
Quoted 6 lines
    # echo 0-3 > ctrl1/kmode_cpus_list
    # cat ctrl1/kmode_cpus
    f
    # cat ctrl1/kmode_cpus_list
    0-3
Quoted 6 lines

   # Empty masks are rejected; use info/kernel_mode to reset to # "every online CPU".

    # echo "" > ctrl1/kmode_cpus_list
    bash: echo: write error: Invalid argument
    # cat info/last_cmd_status
    Empty mask not allowed; use info/kernel_mode to unbind

Why are empty masks rejected/not allowed?

Quoted 8 lines
Quoted 3 lines

No specific reason.

When the mode is switched, we discussed earlier to globally apply the mode to all the online CPUs.

Right. I did not see this being done in this implementation though. As I mentioned in my response to patch #8 it appears that it uses old data from the resource group's kmode_cpu_mask. I do think that applying it to all the online CPUs matches the intention and would make the code much simpler.

Yes. Sure.

Quoted 7 lines
Quoted 3 lines

At this point reading "kmode_cpus_list" will still report empty.

I do not think resctrl should do this. This is not accurate and conflicts with the existing cpus resctrl files. It should be simple to just present the actual and accurate data to user space, especially after incorporating Qinyun Tan's contributions.

Sure. Will do

Quoted 10 lines
Quoted 7 lines

Users can change it to selectively apply the mode by writing to "kmode_cpus_list".

I was not sure what was the action when empty masks are written.

Should the empty mask apply the mode to all the online CPUs?

Users are used to being able to use an empty write to remove all CPUs from a resource group. It thus seems intuitive that an empty write to the kmode_cpus file

Ok, That seems reasonable. Lets keep the same behavior as we update other cpu_lists.

Quoted 6 lines

behave similarly. Sounds like this could mean that if user space sets the kmode to global_assign_ctrl_inherit_mon_per_cpu or global_assign_ctrl_assign_mon_per_cpu and then writes an empty mask to kmode_cpus then it would essentially be setting inherit_ctrl_and_mon mode? This still seems ok since if disabling one of the "global" modes on a CPU results in that CPU inheriting from PQR_ASSOC then it seems reasonable to extend to when that mode is disabled for all CPUs.

Yes. That is correct.

Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Quoted 2 lines

   # Disable kernel-mode steering (back to inherit, default group).

This sounds like kernel work is steered to default group which I do not think is accurate for the "inherit_ctrl_and_mon" mode.

Quoted 7 lines
Quoted 3 lines

How about ?

Drop the kernel-mode binding and restore inherit_ctrl_and_mon on the default group.

No. There is no "inherit_ctrl_and_mon on the default group". There is nothing special about the default group when it comes to inherit_ctrl_and_mon mode ... or am I missing something?

You are right. There is nothing special about inherit_ctrl_and_mon on the default group.

Quoted 4 lines

This could be something like: "Activate inherit_ctrl_and_mon mode to let kernel work inherit the resource allocation and monitoring from the user space task." (and drop the default group from the output associated with inherit_ctrl_and_mon)

Sure.

Thanks
Babu

maintainer
#63 lore raw

Hi Babu,

Quoted 10 lines · Babu Moger

The display will look like this when the system boots up.

# cat info/kernel_mode
  inherit_ctrl_and_mon:
  global_assign_ctrl_assign_mon_per_cpu:group=uninitialized
  global_assign_ctrl_assign_mon_per_cpu:group=uninitialized

There will not be any group associated with "inherit_ctrl_and_mon". It is only used to switch from other two modes.

Just two nitpicks (adding the "[]" to indicate effective mode and fixing the copy&paste duplicate mode names) to confirm that I think you actually intended to write:

# cat info/kernel_mode
  [inherit_ctrl_and_mon:]
  global_assign_ctrl_inherit_mon_per_cpu:group=uninitialized
  global_assign_ctrl_assign_mon_per_cpu:group=uninitialized

I would like to propose that the user documentation contains something like "the kernel mode is followed by a semi-colon separated list of properties" This implementation does not require more than one property associated with a mode so this does not need any code changes but adding that flexibility to the user interface should help if some future kernel mode needs more than one property. What do you think?

Reinette

author reviewer
#64 lore raw

Hi Reinette,

Quoted 11 lines · Reinette Chatre

Hi Babu,

Quoted 8 lines · Babu Moger

The display will look like this when the system boots up.

# cat info/kernel_mode
   inherit_ctrl_and_mon:
   global_assign_ctrl_assign_mon_per_cpu:group=uninitialized
   global_assign_ctrl_assign_mon_per_cpu:group=uninitialized
Quoted 6 lines
Quoted 2 lines

There will not be any group associated with "inherit_ctrl_and_mon". It is only used to switch from other two modes.

Just two nitpicks (adding the "[]" to indicate effective mode and fixing the copy&paste duplicate mode names) to confirm that I think you actually intended to write:

Yes. Thanks for the correction.

Quoted 6 lines
# cat info/kernel_mode
   [inherit_ctrl_and_mon:]
   global_assign_ctrl_inherit_mon_per_cpu:group=uninitialized
   global_assign_ctrl_assign_mon_per_cpu:group=uninitialized
Quoted 6 lines

I would like to propose that the user documentation contains something like "the kernel mode is followed by a semi-colon separated list of properties" This implementation does not require more than one property associated with a mode so this does not need any code changes but adding that flexibility to the user interface should help if some future kernel mode needs more than one property. What do you think?

Sounds good.

Thanks
Babu

maintainer
#65 lore raw
In reply to Babu Moger
Quoted 10 lines · Babu Moger

Hi,

This series adds support for AMD's Privilege-Level Zero Association (PLZA) so kernel work can be assigned to a resctrl group, and wires it up through a small generic "kernel mode" (kmode) layer in fs/resctrl so future architectures can plug in without touching core resctrl.

The features are documented in:

Quoted 7 lines

AMD64 Zen6 Platform Quality of Service (PQOS) Extensions, Publication # 69193 Revision 1.00, Issue Date March 2026

available at https://bugzilla.kernel.org/show_bug.cgi?id=206537

The patches are based on top of commit (7.1.0-rc1)
Commit 3382329a309d Merge branch into tip/master: 'timers/clocksource'.

Hi Babu,

Have you had any thoughts about a resctrl selftest for PLZA?

I'm not sure there are any easy ways to show that PLZA is effective for MBA control (as most normal system calls don't do enough to easily detect whether the kernel CLOSID is applied). But perhaps you have some ideas for this?

A test that sets global_assign_ctrl_assign_mon_per_cpu mode with a dedicated RMID to track kernel memory traffic would easily show MBM and llc_occupancy numbers for kernel activity.

-Tony

#66 lore raw

Hi Tony,

Quoted 23 lines · Tony
Quoted 10 lines · Babu Moger

Hi,

This series adds support for AMD's Privilege-Level Zero Association (PLZA) so kernel work can be assigned to a resctrl group, and wires it up through a small generic "kernel mode" (kmode) layer in fs/resctrl so future architectures can plug in without touching core resctrl.

The features are documented in:

Quoted 7 lines

AMD64 Zen6 Platform Quality of Service (PQOS) Extensions, Publication # 69193 Revision 1.00, Issue Date March 2026

available at https://bugzilla.kernel.org/show_bug.cgi?id=206537

The patches are based on top of commit (7.1.0-rc1)
Commit 3382329a309d Merge branch into tip/master: 'timers/clocksource'.

Hi Babu,

Have you had any thoughts about a resctrl selftest for PLZA?

Quoted 8 lines

I'm not sure there are any easy ways to show that PLZA is effective for MBA control (as most normal system calls don't do enough to easily detect whether the kernel CLOSID is applied). But perhaps you have some ideas for this?

A test that sets global_assign_ctrl_assign_mon_per_cpu mode with a dedicated RMID to track kernel memory traffic would easily show MBM and llc_occupancy numbers for kernel activity.

The AMD selftests are already somewhat broken—or at least incomplete. We should get back to the earlier patch series:
https://lore.kernel.org/lkml/[email protected]/

I’ll start by looking into that. Afterward, I’ll consider what can be done for PLZA.

At the moment, I don’t have a clear idea for PLZA selftests. Thanks for the reminder—I’ll give it some thought. Thanks
Babu