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

Babu Moger posted 16 patches 3 weeks, 4 days ago
[PATCH v2 13/16] fs/resctrl: Add write interface for kernel_mode_assignment
Posted by Babu Moger 3 weeks, 4 days ago
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