[PATCH v2 13/16] fs/resctrl: Add write interface for kernel_mode_assignment

Babu Moger
2026-03-12T20:39:13Z

Allow enabling kernel mode assignment (PLZA) for resctrl groups via the
kernel_mode_assignment sysfs file. Add a kmode flag to struct rdtgroup to
track the state, enforce that only one group has PLZA at a time, and clear
kmode when groups are removed or during rmdir_all_sub teardown.

Signed-off-by: Babu Moger <babu.moger@amd.com>
---
v2: New patch to handle PLZA interfaces with /sys/fs/resctrl/info/ directory.
https://lore.kernel.org/lkml/2ab556af-095b-422b-9396-f845c6fd0342@intel.com/
---
Documentation/filesystems/resctrl.rst | 35 ++++++
fs/resctrl/rdtgroup.c | 148 +++++++++++++++++++++++++-
2 files changed, 182 insertions(+), 1 deletion(-)

diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
index 2107dd4b3649..2b4beedd7207 100644
--- a/Documentation/filesystems/resctrl.rst
+++ b/Documentation/filesystems/resctrl.rst
@@ -548,6 +548,41 @@ conveyed in the error returns from file operations. E.g.
- "global_assign_ctrl_assign_mon": One resource group (CLOSID and RMID)
is assigned for all kernel work.

+"kernel_mode_assignment":
+ In the top level of the "info" directory, "kernel_mode_assignment" shows
+ and (when a global-assign kernel mode is active) sets which resctrl group
+ is used for kernel mode. It is only relevant when "kernel_mode" is not
+ "inherit_ctrl_and_mon".
+
+ Reading the file shows the currently assigned group in the form
+ "CTRL_MON/MON/" with a newline::
+
+ # cat info/kernel_mode_assignment
+ //
+
+ Possible read formats:
+
+ - "//": Default CTRL_MON group is assigned.
+ - "ctrl_name//": A CTRL_MON group named "ctrl_name" is assigned.
+ - "/mon_name/": A MON group named "mon_name" under the default CTRL_MON
+ group is assigned.
+ - "ctrl_name/mon_name/": A MON group named "mon_name" under the CTRL_MON
+ group "ctrl_name" is assigned.
+ - "Kmode is not configured": No group is assigned for kernel mode.
+
+ Writing assigns a group for kernel mode. The write is only allowed when
+ the current kernel mode is not "inherit_ctrl_and_mon". Input format is
+ one or more lines, each of the form "CTRL_MON/MON/" (same as the read
+ format). Examples::
+
+ # echo "//" > info/kernel_mode_assignment
+ # echo "mydir//" > info/kernel_mode_assignment
+ # echo "mydir/mon1/" > info/kernel_mode_assignment
+
+ An empty write (e.g. ``echo >> info/kernel_mode_assignment``) clears the
+ assignment. Only one group can be assigned at a time. Pseudo-locked
+ groups cannot be assigned. Errors are reported in "info/last_cmd_status".
+
Resource alloc and monitor groups
=================================

diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index c2d6d1995dff..23e610d59111 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -1156,6 +1156,137 @@ static int resctrl_kernel_mode_assignment_show(struct kernfs_open_file *of,
return 0;
}

+/**
+ * rdtgroup_find_grp_by_name() - Find an rdtgroup by type and parent/child names
+ * @rtype: RDTCTRL_GROUP or RDTMON_GROUP.
+ * @p_grp: Parent CTRL_MON group name, or "" for the default group.
+ * @c_grp: Child MON group name (only used when rtype is RDTMON_GROUP).
+ *
+ * Return: The rdtgroup, or NULL if not found.
+ */
+static struct rdtgroup *rdtgroup_find_grp_by_name(enum rdt_group_type rtype,
+ char *p_grp, char *c_grp)
+{
+ struct rdtgroup *rdtg, *crg;
+
+ if (rtype == RDTCTRL_GROUP && *p_grp == '\0') {
+ return &rdtgroup_default;
+ } else if (rtype == RDTCTRL_GROUP) {
+ list_for_each_entry(rdtg, &rdt_all_groups, rdtgroup_list)
+ if (rdtg->type == RDTCTRL_GROUP && !strcmp(p_grp, rdtg->kn->name))
+ return rdtg;
+ } else if (rtype == RDTMON_GROUP) {
+ list_for_each_entry(rdtg, &rdt_all_groups, rdtgroup_list) {
+ if (rdtg->type == RDTCTRL_GROUP && !strcmp(p_grp, rdtg->kn->name)) {
+ list_for_each_entry(crg, &rdtg->mon.crdtgrp_list,
+ mon.crdtgrp_list) {
+ if (!strcmp(c_grp, crg->kn->name))
+ return crg;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * resctrl_kernel_mode_assignment_write() - Set rdtgroup for kernel mode via info file
+ * @of: kernfs file handle.
+ * @buf: Input: "CTRL_MON/MON/" per line (e.g. "//" for default,
+ * "ctrl1//" or "ctrl1/mon1/"); empty string clears the assignment.
+ * @nbytes: Length of buf.
+ * @off: File offset (unused).
+ *
+ * Only valid when kernel mode is not inherit_ctrl_and_mon. Empty write clears
+ * the current assignment. Parses lines as "parent/child/"; empty child means
+ * CTRL_MON group. Errors are reported in last_cmd_status.
+ *
+ * Return: nbytes on success, or -EINVAL with last_cmd_status set on error.
+ */
+static ssize_t resctrl_kernel_mode_assignment_write(struct kernfs_open_file *of,
+ char *buf, size_t nbytes, loff_t off)
+{
+ struct rdtgroup *rdtgrp;
+ char *token, *cmon_grp, *mon_grp;
+ enum rdt_group_type rtype;
+ int ret = 0;
+
+ if (nbytes == 0 || buf[nbytes - 1] != '\n')
+ return -EINVAL;
+ buf[nbytes - 1] = '\0';
+ buf = strim(buf);
+
+ mutex_lock(&rdtgroup_mutex);
+ rdt_last_cmd_clear();
+
+ if (resctrl_kcfg.kmode_cur & INHERIT_CTRL_AND_MON) {
+ rdt_last_cmd_puts("Cannot change kmode in inherit_ctrl_and_mon\n");
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ /*
+ * Group can be deleted from Kmode by empty write: e.g.
+ * "echo >> /sys/fs/resctrl/info/kernel_mode_assignment"
+ */
+ if (*buf == '\0') {
+ if (resctrl_kcfg.k_rdtgrp) {
+ ret = rdtgroup_config_kmode(resctrl_kcfg.k_rdtgrp, false);
+ if (ret)
+ rdt_last_cmd_printf("Kernel mode disable failed on group %s\n",
+ rdt_kn_name(resctrl_kcfg.k_rdtgrp->kn));
+ }
+ goto out_unlock;
+ }
+
+ /* Only one group can be assigned for kernel mode at a time. */
+ if (resctrl_kcfg.k_rdtgrp) {
+ rdt_last_cmd_printf("Kernel mode already configured on group %s\n",
+ rdt_kn_name(resctrl_kcfg.k_rdtgrp->kn));
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ while ((token = strsep(&buf, "\n")) != NULL) {
+ /*
+ * Each line has the format "<CTRL_MON group>/<MON group>/".
+ * Extract the CTRL_MON group name.
+ */
+ cmon_grp = strsep(&token, "/");
+
+ /*
+ * Extract the MON_GROUP.
+ * strsep returns empty string for contiguous delimiters.
+ * Empty mon_grp here means it is a RDTCTRL_GROUP.
+ */
+ mon_grp = strsep(&token, "/");
+
+ if (*mon_grp == '\0')
+ rtype = RDTCTRL_GROUP;
+ else
+ rtype = RDTMON_GROUP;
+
+ rdtgrp = rdtgroup_find_grp_by_name(rtype, cmon_grp, mon_grp);
+
+ if (!rdtgrp) {
+ rdt_last_cmd_puts("Not a valid resctrl group\n");
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (!rdtgrp->kmode) {
+ ret = rdtgroup_config_kmode(rdtgrp, true);
+ if (ret)
+ break;
+ }
+ }
+
+out_unlock:
+ mutex_unlock(&rdtgroup_mutex);
+ return ret ?: nbytes;
+}
+
void *rdt_kn_parent_priv(struct kernfs_node *kn)
{
/*
@@ -2067,9 +2198,10 @@ static struct rftype res_common_files[] = {
},
{
.name = "kernel_mode_assignment",
- .mode = 0444,
+ .mode = 0644,
.kf_ops = &rdtgroup_kf_single_ops,
.seq_show = resctrl_kernel_mode_assignment_show,
+ .write = resctrl_kernel_mode_assignment_write,
.fflags = RFTYPE_TOP_INFO,
},
{
@@ -3248,6 +3380,10 @@ static void rmdir_all_sub(void)
rdt_move_group_tasks(NULL, &rdtgroup_default, NULL);

list_for_each_entry_safe(rdtgrp, tmp, &rdt_all_groups, rdtgroup_list) {
+ /* Disable Kmode if configured */
+ if (rdtgrp->kmode)
+ rdtgroup_config_kmode(rdtgrp, false);
+
/* Free any child rmids */
free_all_child_rdtgrp(rdtgrp);

@@ -3358,6 +3494,8 @@ static void resctrl_fs_teardown(void)
mon_put_kn_priv();
rdt_pseudo_lock_release();
rdtgroup_default.mode = RDT_MODE_SHAREABLE;
+ resctrl_kcfg.k_rdtgrp = NULL;
+ resctrl_kcfg.kmode_cur = INHERIT_CTRL_AND_MON;
closid_exit();
schemata_list_destroy();
rdtgroup_destroy_root();
@@ -4156,6 +4294,10 @@ static int rdtgroup_rmdir_mon(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask)
u32 closid, rmid;
int cpu;

+ /* Disable Kmode if configured */
+ if (rdtgrp->kmode)
+ rdtgroup_config_kmode(rdtgrp, false);
+
/* Give any tasks back to the parent group */
rdt_move_group_tasks(rdtgrp, prdtgrp, tmpmask);

@@ -4206,6 +4348,10 @@ static int rdtgroup_rmdir_ctrl(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask)
u32 closid, rmid;
int cpu;

+ /* Disable Kmode if configured */
+ if (rdtgrp->kmode)
+ rdtgroup_config_kmode(rdtgrp, false);
+
/* Give any tasks back to the default group */
rdt_move_group_tasks(rdtgrp, &rdtgroup_default, tmpmask);

--
2.43.0