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 --- 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 "//". + * 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