[PATCH v2 11/16] fs/resctrl: Add write handler for info/kernel_mode

Babu Moger posted 16 patches 3 weeks, 4 days ago
[PATCH v2 11/16] fs/resctrl: Add write handler for info/kernel_mode
Posted by Babu Moger 3 weeks, 4 days ago
Add resctrl_kernel_mode_write() so users can set the current kernel
mode by writing a mode name to info/kernel_mode. Unsupported or invalid
names are rejected; errors are reported in info/last_cmd_status.

Add rdtgroup_config_kmode() to assign or clear a group for kernel mode
(e.g. PLZA), and extend struct rdtgroup with a kmode flag. Update
Documentation/filesystems/resctrl.rst to describe the kernel_mode file.

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 |  34 +++++++++
 fs/resctrl/internal.h                 |   2 +
 fs/resctrl/rdtgroup.c                 | 101 +++++++++++++++++++++++++-
 3 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
index ba609f8d4de5..2107dd4b3649 100644
--- a/Documentation/filesystems/resctrl.rst
+++ b/Documentation/filesystems/resctrl.rst
@@ -514,6 +514,40 @@ 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. The
+	currently active mode is shown in square brackets; other modes supported
+	by the platform are shown without brackets. Example::
+
+	  # cat info/kernel_mode
+	  [inherit_ctrl_and_mon]
+	  global_assign_ctrl_inherit_mon
+	  global_assign_ctrl_assign_mon
+
+	Writing a mode name (followed by a newline) sets the current kernel mode.
+	The name must match one of the supported mode names exactly. Modes not
+	supported by the platform (e.g. not advertised when reading the file)
+	cannot be set. Errors are reported in "info/last_cmd_status". Example::
+
+	  # echo "global_assign_ctrl_assign_mon" > info/kernel_mode
+	  # cat info/kernel_mode
+	  inherit_ctrl_and_mon
+	  global_assign_ctrl_inherit_mon
+	  [global_assign_ctrl_assign_mon]
+
+	Modes:
+
+	- "inherit_ctrl_and_mon": Kernel uses the same CLOSID and RMID as the
+	  current user-space task (default).
+	- "global_assign_ctrl_inherit_mon": One CLOSID is assigned for all
+	  kernel work; RMID is still inherited from user space.
+	- "global_assign_ctrl_assign_mon": One resource group (CLOSID and RMID)
+	  is assigned for all kernel work.
+
 Resource alloc and monitor groups
 =================================
 
diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
index 1a9b29119f88..b5999d8079d6 100644
--- a/fs/resctrl/internal.h
+++ b/fs/resctrl/internal.h
@@ -216,6 +216,7 @@ 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 assigned for kernel mode (e.g. PLZA)
  * @plr:			pseudo-locked region
  */
 struct rdtgroup {
@@ -229,6 +230,7 @@ struct rdtgroup {
 	struct mongroup			mon;
 	enum rdtgrp_mode		mode;
 	enum resctrl_event_id		mba_mbps_event;
+	bool				kmode;
 	struct pseudo_lock_region	*plr;
 };
 
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index bb775afc78f5..6cd928fabaa2 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -1019,6 +1019,104 @@ static int resctrl_kernel_mode_show(struct kernfs_open_file *of,
 	return 0;
 }
 
+/**
+ * rdtgroup_config_kmode() - Enable or disable kernel mode (e.g. PLZA) for a group
+ * @rdtgrp:	The rdtgroup to assign or unassign for kernel work.
+ * @enable:	True to assign this group for kernel mode; false to clear.
+ *
+ * Programs arch state via resctrl_arch_configure_kmode() and
+ * resctrl_arch_set_kmode(), and updates resctrl_kcfg.k_rdtgrp. Only one group
+ * may have kmode at a time. Pseudo-locked groups cannot be used for kernel mode.
+ *
+ * Return: 0 on success, or -EINVAL if the group is pseudo-locked.
+ */
+static int rdtgroup_config_kmode(struct rdtgroup *rdtgrp, bool enable)
+{
+	struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
+	u32 closid;
+
+	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
+		rdt_last_cmd_puts("Resource group is pseudo-locked\n");
+		return -EINVAL;
+	}
+
+	if (rdtgrp->type == RDTMON_GROUP)
+		closid = rdtgrp->mon.parent->closid;
+	else
+		closid = rdtgrp->closid;
+
+	resctrl_arch_configure_kmode(r, &resctrl_kcfg, closid, rdtgrp->mon.rmid);
+
+	resctrl_arch_set_kmode(&rdtgrp->cpu_mask, &resctrl_kcfg, closid,
+			       rdtgrp->mon.rmid, enable);
+	rdtgrp->kmode = enable;
+	if (enable)
+		resctrl_kcfg.k_rdtgrp = rdtgrp;
+	else
+		resctrl_kcfg.k_rdtgrp = NULL;
+
+	return 0;
+}
+
+/**
+ * resctrl_kernel_mode_write() - Set current kernel mode via info/kernel_mode
+ * @of:	kernfs file handle.
+ * @buf:	Mode name string (e.g. "inherit_ctrl_and_mon"); must end with newline.
+ * @nbytes:	Length of buf.
+ * @off:	File offset (unused).
+ *
+ * Accepts one of the names in kmodes[]. The mode must be supported by the
+ * platform (resctrl_kcfg.kmode). On success updates resctrl_kcfg.kmode_cur.
+ * 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_write(struct kernfs_open_file *of,
+					 char *buf, size_t nbytes, loff_t off)
+{
+	int ret = 0;
+	u32 kmode;
+	int i;
+
+	if (nbytes == 0 || buf[nbytes - 1] != '\n')
+		return -EINVAL;
+	buf[nbytes - 1] = '\0';
+
+	mutex_lock(&rdtgroup_mutex);
+	rdt_last_cmd_clear();
+
+	for (i = 0; i < RESCTRL_KERNEL_MODES_NUM; i++) {
+		if (strcmp(buf, kmodes[i].name) != 0)
+			continue;
+		/* Mode name matched; reject if not supported by this platform. */
+		if (!(resctrl_kcfg.kmode & kmodes[i].val)) {
+			rdt_last_cmd_puts("Kernel mode not available\n");
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+		if (resctrl_kcfg.kmode_cur != kmodes[i].val) {
+			kmode = resctrl_kcfg.kmode_cur;
+			resctrl_kcfg.kmode_cur = kmodes[i].val;
+			if (resctrl_kcfg.k_rdtgrp) {
+				ret = rdtgroup_config_kmode(resctrl_kcfg.k_rdtgrp, true);
+				if (ret) {
+					/* Revert to the previous mode. */
+					resctrl_kcfg.kmode_cur = kmode;
+					rdt_last_cmd_puts("Kernel mode change failed\n");
+				}
+			}
+			goto out_unlock;
+		}
+	}
+
+	rdt_last_cmd_puts("Unknown or unsupported kernel mode\n");
+	ret = -EINVAL;
+
+out_unlock:
+	mutex_unlock(&rdtgroup_mutex);
+	return ret ?: nbytes;
+}
+
 void *rdt_kn_parent_priv(struct kernfs_node *kn)
 {
 	/*
@@ -1922,9 +2020,10 @@ static struct rftype res_common_files[] = {
 	},
 	{
 		.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,
 	},
 	{
-- 
2.43.0