* [PATCH 0/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains
@ 2025-11-26 17:16 Aaron Tomlin
2025-11-26 17:16 ` [PATCH 1/3] fs/resctrl: Add helpers to check io_alloc support and enabled state Aaron Tomlin
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Aaron Tomlin @ 2025-11-26 17:16 UTC (permalink / raw)
To: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
tglx, mingo, bp, dave.hansen
Cc: dave.martin, atomlin, sean, linux-kernel
Hi Babu, Tony, Reinette,
This series was rebased on tip/x86/cache since commit ac7de456a37f
("fs/resctrl: Update bit_usage to reflect io_alloc"). It is instead to be
merged after the inclusion of "[PATCH v12 00/10] x86,fs/resctrl: Support L3
Smart Data Cache Injection Allocation Enforcement (SDCIAE)" series [1].
As previously discussed [2], a special domain ID selector "*" has been
introduced for io_alloc_cbm that allows setting the CBM of each cache
domain to its minimum number of consecutive bits in a single operation. For
example, writing "*=0" to /sys/fs/resctrl/info/L3/io_alloc_cbm programs
each domain's CBM to the hardware-defined minimum, greatly simplifying
automation and management tasks. The user is required to specify the
correct minimum stored in /sys/fs/resctrl/info/L3/min_cbm_bits.
Please let me know your thoughts.
[1]: https://lore.kernel.org/lkml/cover.1762995456.git.babu.moger@amd.com/
[2]: https://lore.kernel.org/lkml/7e117908-41ae-4f42-8863-1361101c33ab@amd.com/
Aaron Tomlin (3):
fs/resctrl: Add helpers to check io_alloc support and enabled state
fs/resctrl: Return -EINVAL for a missing seq_show implementation
x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all
domains
Documentation/filesystems/resctrl.rst | 10 ++
arch/x86/kernel/cpu/resctrl/core.c | 2 +-
arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 23 +--
fs/resctrl/ctrlmondata.c | 182 +++++++++++++++++-----
fs/resctrl/internal.h | 13 ++
fs/resctrl/rdtgroup.c | 5 +-
include/linux/resctrl.h | 30 +++-
7 files changed, 211 insertions(+), 54 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] fs/resctrl: Add helpers to check io_alloc support and enabled state
2025-11-26 17:16 [PATCH 0/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains Aaron Tomlin
@ 2025-11-26 17:16 ` Aaron Tomlin
2025-12-05 19:35 ` Moger, Babu
2025-11-26 17:16 ` [PATCH 2/3] fs/resctrl: Return -EINVAL for a missing seq_show implementation Aaron Tomlin
2025-11-26 17:16 ` [PATCH 3/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains Aaron Tomlin
2 siblings, 1 reply; 8+ messages in thread
From: Aaron Tomlin @ 2025-11-26 17:16 UTC (permalink / raw)
To: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
tglx, mingo, bp, dave.hansen
Cc: dave.martin, atomlin, sean, linux-kernel
This patch introduces two helpers to validate io_alloc support and
whether it is enabled. This reduces code duplication, clarifies
intent, and preserves existing semantics and messages.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
fs/resctrl/ctrlmondata.c | 74 +++++++++++++++++++++++++++++-----------
1 file changed, 54 insertions(+), 20 deletions(-)
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index b2d178d3556e..5f6f96d70e4a 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -758,6 +758,50 @@ u32 resctrl_io_alloc_closid(struct rdt_resource *r)
return resctrl_arch_get_num_closid(r) - 1;
}
+/*
+ * check_io_alloc_support() - Establish if io_alloc is supported
+ *
+ * @s: resctrl resource schema.
+ *
+ * This function must be called under the cpu hotplug lock
+ * and rdtgroup mutex
+ *
+ * Return: 0 on success, negative error code otherwise.
+ */
+static int check_io_alloc_support(struct resctrl_schema *s)
+{
+ struct rdt_resource *r = s->res;
+
+ if (!r->cache.io_alloc.io_alloc_capable) {
+ rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * check_io_alloc_enabled() - Establish if io_alloc is enabled
+ *
+ * @s: resctrl resource schema
+ *
+ * This function must be called under the cpu hotplug lock
+ * and rdtgroup mutex
+ *
+ * Return: 0 on success, negative error code otherwise.
+ */
+static int check_io_alloc_enabled(struct resctrl_schema *s)
+{
+ struct rdt_resource *r = s->res;
+
+ if (!resctrl_arch_get_io_alloc_enabled(r)) {
+ rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf,
size_t nbytes, loff_t off)
{
@@ -777,11 +821,9 @@ ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf,
rdt_last_cmd_clear();
- if (!r->cache.io_alloc_capable) {
- rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
- ret = -ENODEV;
+ ret = check_io_alloc_support(s);
+ if (ret)
goto out_unlock;
- }
/* If the feature is already up to date, no action is needed. */
if (resctrl_arch_get_io_alloc_enabled(r) == enable)
@@ -839,17 +881,13 @@ int resctrl_io_alloc_cbm_show(struct kernfs_open_file *of, struct seq_file *seq,
rdt_last_cmd_clear();
- if (!r->cache.io_alloc_capable) {
- rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
- ret = -ENODEV;
+ ret = check_io_alloc_support(s);
+ if (ret)
goto out_unlock;
- }
- if (!resctrl_arch_get_io_alloc_enabled(r)) {
- rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name);
- ret = -EINVAL;
+ ret = check_io_alloc_enabled(s);
+ if (ret)
goto out_unlock;
- }
/*
* When CDP is enabled, the CBMs of the highest CLOSID of CDP_CODE and
@@ -928,17 +966,13 @@ ssize_t resctrl_io_alloc_cbm_write(struct kernfs_open_file *of, char *buf,
mutex_lock(&rdtgroup_mutex);
rdt_last_cmd_clear();
- if (!r->cache.io_alloc_capable) {
- rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
- ret = -ENODEV;
+ ret = check_io_alloc_support(s);
+ if (ret)
goto out_unlock;
- }
- if (!resctrl_arch_get_io_alloc_enabled(r)) {
- rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name);
- ret = -EINVAL;
+ ret = check_io_alloc_enabled(s);
+ if (ret)
goto out_unlock;
- }
io_alloc_closid = resctrl_io_alloc_closid(r);
--
2.51.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/3] fs/resctrl: Return -EINVAL for a missing seq_show implementation
2025-11-26 17:16 [PATCH 0/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains Aaron Tomlin
2025-11-26 17:16 ` [PATCH 1/3] fs/resctrl: Add helpers to check io_alloc support and enabled state Aaron Tomlin
@ 2025-11-26 17:16 ` Aaron Tomlin
2025-11-26 17:16 ` [PATCH 3/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains Aaron Tomlin
2 siblings, 0 replies; 8+ messages in thread
From: Aaron Tomlin @ 2025-11-26 17:16 UTC (permalink / raw)
To: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
tglx, mingo, bp, dave.hansen
Cc: dave.martin, atomlin, sean, linux-kernel
The rdtgroup_seqfile_show() function, which is the sequence file handler
for reading data from resctrl files, previously returned 0 (success) if
the file's associated rftype did not define a .seq_show implementation.
This behavior is incorrect and confusing, as a read operation that
does not define a display function should be treated as an error.
This patch change the function to return -EINVAL if the file type
handler (i.e., rft->seq_show) is NULL, providing proper feedback that
the operation is invalid for that file.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
fs/resctrl/rdtgroup.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 8e39dfda56bc..e1dc63b2218f 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -314,7 +314,8 @@ static int rdtgroup_seqfile_show(struct seq_file *m, void *arg)
if (rft->seq_show)
return rft->seq_show(of, m, arg);
- return 0;
+
+ return -EINVAL;
}
static ssize_t rdtgroup_file_write(struct kernfs_open_file *of, char *buf,
--
2.51.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains
2025-11-26 17:16 [PATCH 0/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains Aaron Tomlin
2025-11-26 17:16 ` [PATCH 1/3] fs/resctrl: Add helpers to check io_alloc support and enabled state Aaron Tomlin
2025-11-26 17:16 ` [PATCH 2/3] fs/resctrl: Return -EINVAL for a missing seq_show implementation Aaron Tomlin
@ 2025-11-26 17:16 ` Aaron Tomlin
2025-12-05 19:30 ` Moger, Babu
2 siblings, 1 reply; 8+ messages in thread
From: Aaron Tomlin @ 2025-11-26 17:16 UTC (permalink / raw)
To: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
tglx, mingo, bp, dave.hansen
Cc: dave.martin, atomlin, sean, linux-kernel
This patch introduces a special domain ID selector "*" for io_alloc_cbm
that allows setting the CBM of each cache domain to its minimum number
of consecutive bits in a single operation. For example, writing "*=0" to
/sys/fs/resctrl/info/L3/io_alloc_cbm programs each domain's CBM to the
hardware-defined minimum, greatly simplifying automation and management
tasks. The user is required to specify the correct minimum stored in
/sys/fs/resctrl/info/L3/min_cbm_bits.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
Documentation/filesystems/resctrl.rst | 10 ++
arch/x86/kernel/cpu/resctrl/core.c | 2 +-
arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 23 +++--
fs/resctrl/ctrlmondata.c | 108 +++++++++++++++++-----
fs/resctrl/internal.h | 13 +++
fs/resctrl/rdtgroup.c | 2 +-
include/linux/resctrl.h | 30 +++++-
7 files changed, 155 insertions(+), 33 deletions(-)
diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
index 8c8ce678148a..9c128c8fba86 100644
--- a/Documentation/filesystems/resctrl.rst
+++ b/Documentation/filesystems/resctrl.rst
@@ -215,6 +215,16 @@ related to allocation:
# cat /sys/fs/resctrl/info/L3/io_alloc_cbm
0=00ff;1=000f
+ Set each CBM to their minimum number of consecutive bits.
+
+ A special value "*" is required to represent all cache IDs.
+ The user should specify the correct minimum stored in
+ /sys/fs/resctrl/info/L3/min_cbm_bits.
+
+ Example::
+
+ # echo "*=0" > /sys/fs/resctrl/info/L3/io_alloc_cbm
+
When CDP is enabled "io_alloc_cbm" associated with the CDP_DATA and CDP_CODE
resources may reflect the same values. For example, values read from and
written to /sys/fs/resctrl/info/L3DATA/io_alloc_cbm may be reflected by
diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
index 3792ab4819dc..44aea6b534e0 100644
--- a/arch/x86/kernel/cpu/resctrl/core.c
+++ b/arch/x86/kernel/cpu/resctrl/core.c
@@ -276,7 +276,7 @@ static void rdt_get_cdp_config(int level)
static void rdt_set_io_alloc_capable(struct rdt_resource *r)
{
- r->cache.io_alloc_capable = true;
+ r->cache.io_alloc.io_alloc_capable = true;
}
static void rdt_get_cdp_l3_config(void)
diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
index b20e705606b8..0f051d848422 100644
--- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
+++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
@@ -57,14 +57,19 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
hw_dom = resctrl_to_arch_ctrl_dom(d);
msr_param.res = NULL;
for (t = 0; t < CDP_NUM_TYPES; t++) {
- cfg = &hw_dom->d_resctrl.staged_config[t];
- if (!cfg->have_new_ctrl)
- continue;
-
- idx = resctrl_get_config_index(closid, t);
- if (cfg->new_ctrl == hw_dom->ctrl_val[idx])
- continue;
- hw_dom->ctrl_val[idx] = cfg->new_ctrl;
+ if (resctrl_should_io_alloc_min_cbm(r)) {
+ idx = resctrl_get_config_index(closid, t);
+ hw_dom->ctrl_val[idx] = apply_io_alloc_min_cbm(r);
+ } else {
+ cfg = &hw_dom->d_resctrl.staged_config[t];
+ if (!cfg->have_new_ctrl)
+ continue;
+
+ idx = resctrl_get_config_index(closid, t);
+ if (cfg->new_ctrl == hw_dom->ctrl_val[idx])
+ continue;
+ hw_dom->ctrl_val[idx] = cfg->new_ctrl;
+ }
if (!msr_param.res) {
msr_param.low = idx;
@@ -123,7 +128,7 @@ int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
{
struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
- if (hw_res->r_resctrl.cache.io_alloc_capable &&
+ if (hw_res->r_resctrl.cache.io_alloc.io_alloc_capable &&
hw_res->sdciae_enabled != enable) {
_resctrl_sdciae_enable(r, enable);
hw_res->sdciae_enabled = enable;
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index 5f6f96d70e4a..b3abd781899f 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -688,7 +688,7 @@ int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, voi
mutex_lock(&rdtgroup_mutex);
- if (r->cache.io_alloc_capable) {
+ if (r->cache.io_alloc.io_alloc_capable) {
if (resctrl_arch_get_io_alloc_enabled(r))
seq_puts(seq, "enabled\n");
else
@@ -712,13 +712,31 @@ static bool resctrl_io_alloc_closid_supported(u32 io_alloc_closid)
return io_alloc_closid < closids_supported();
}
+/**
+ * resctrl_sync_cdp_peer - Mirror staged configuration to the CDP peer type
+ *
+ * @s: resctrl schema
+ * @d: resctrl control domain
+ *
+ * The caller must ensure CDP is enabled for the resource and must be
+ * called under the cpu hotplug lock and rdtgroup mutex
+ */
+static void resctrl_sync_cdp_peer(struct resctrl_schema *s, struct rdt_ctrl_domain *d)
+{
+ enum resctrl_conf_type peer_type;
+
+ peer_type = resctrl_peer_type(s->conf_type);
+ memcpy(&d->staged_config[peer_type],
+ &d->staged_config[s->conf_type],
+ sizeof(d->staged_config[0]));
+}
+
/*
* Initialize io_alloc CLOSID cache resource CBM with all usable (shared
* and unused) cache portions.
*/
static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid)
{
- enum resctrl_conf_type peer_type;
struct rdt_resource *r = s->res;
struct rdt_ctrl_domain *d;
int ret;
@@ -731,11 +749,8 @@ static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid)
/* Keep CDP_CODE and CDP_DATA of io_alloc CLOSID's CBM in sync. */
if (resctrl_arch_get_cdp_enabled(r->rid)) {
- peer_type = resctrl_peer_type(s->conf_type);
list_for_each_entry(d, &s->res->ctrl_domains, hdr.list)
- memcpy(&d->staged_config[peer_type],
- &d->staged_config[s->conf_type],
- sizeof(d->staged_config[0]));
+ resctrl_sync_cdp_peer(s, d);
}
ret = resctrl_arch_update_domains(r, closid);
@@ -903,29 +918,82 @@ int resctrl_io_alloc_cbm_show(struct kernfs_open_file *of, struct seq_file *seq,
return ret;
}
+/**
+ * parse_domain_cbm - Parse "domain=cbm" and return either side
+ *
+ * @line_ptr: Pointer to the input string
+ * @out_val: Output from parsed value (either domain ID or CDM)
+ * @which: Selector for which side to parse
+ *
+ * It is assumed that *line_ptr and *out_val are valid.
+ *
+ * Return: 0 on success and advance *line_ptr to point past the
+ * delimiter, EINVAL on parsing error
+ */
+static int parse_domain_cbm(char **line_ptr, unsigned long *out_val,
+ enum resctrl_kv_sel which)
+{
+ char *rhs, *lhs, *tok;
+ unsigned int base;
+
+ rhs = *line_ptr;
+
+ lhs = strsep(&rhs, "=");
+ if (!lhs || !rhs)
+ goto err;
+
+ if (which == RDT_PARSE_DOMAIN) {
+ tok = lhs;
+ base = 10;
+ } else {
+ tok = rhs;
+ base = 16;
+ }
+ tok = strim(tok);
+
+ if (kstrtoul(tok, base, out_val))
+ goto err;
+
+ *line_ptr = rhs;
+ return 0;
+err:
+ rdt_last_cmd_puts("Invalid domain=cbm: missing '=' or non-numeric value\n");
+ return -EINVAL;
+}
+
static int resctrl_io_alloc_parse_line(char *line, struct rdt_resource *r,
struct resctrl_schema *s, u32 closid)
{
- enum resctrl_conf_type peer_type;
struct rdt_parse_data data;
struct rdt_ctrl_domain *d;
- char *dom = NULL, *id;
- unsigned long dom_id;
+ char *dom = NULL;
+ unsigned long out_val;
+ int ret;
+
+ if (line[0] == '*') {
+ ret = parse_domain_cbm(&line, &out_val, RDT_PARSE_CBM);
+ if (ret)
+ return ret;
+ if (out_val == r->cache.min_cbm_bits) {
+ r->cache.io_alloc.io_alloc_min_cbm = true;
+ return 0;
+ }
+ rdt_last_cmd_puts("Invalid io_alloc min CBM\n");
+ return -EINVAL;
+ }
next:
if (!line || line[0] == '\0')
return 0;
dom = strsep(&line, ";");
- id = strsep(&dom, "=");
- if (!dom || kstrtoul(id, 10, &dom_id)) {
- rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
- return -EINVAL;
- }
+ ret = parse_domain_cbm(&line, &out_val, RDT_PARSE_DOMAIN);
+ if (ret)
+ return ret;
dom = strim(dom);
list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
- if (d->hdr.id == dom_id) {
+ if (d->hdr.id == out_val) {
data.buf = dom;
data.mode = RDT_MODE_SHAREABLE;
data.closid = closid;
@@ -935,12 +1003,8 @@ static int resctrl_io_alloc_parse_line(char *line, struct rdt_resource *r,
* Keep io_alloc CLOSID's CBM of CDP_CODE and CDP_DATA
* in sync.
*/
- if (resctrl_arch_get_cdp_enabled(r->rid)) {
- peer_type = resctrl_peer_type(s->conf_type);
- memcpy(&d->staged_config[peer_type],
- &d->staged_config[s->conf_type],
- sizeof(d->staged_config[0]));
- }
+ if (resctrl_arch_get_cdp_enabled(r->rid))
+ resctrl_sync_cdp_peer(s, d);
goto next;
}
}
@@ -982,6 +1046,8 @@ ssize_t resctrl_io_alloc_cbm_write(struct kernfs_open_file *of, char *buf,
goto out_clear_configs;
ret = resctrl_arch_update_domains(r, io_alloc_closid);
+ if (resctrl_should_io_alloc_min_cbm(r))
+ r->cache.io_alloc.io_alloc_min_cbm = false;
out_clear_configs:
rdt_staged_configs_clear();
diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
index bff4a54ae333..3846737992bb 100644
--- a/fs/resctrl/internal.h
+++ b/fs/resctrl/internal.h
@@ -143,6 +143,19 @@ enum rdt_group_type {
RDT_NUM_GROUP,
};
+/**
+ * enum resctrl_kv_sel - Selector for "domain=cbm" key/value parsing
+ * @RDT_PARSE_DOMAIN: Parse the left-hand side (domain ID)
+ * @RDT_PARSE_CBM: Parse the right-hand side (CBM value)
+ *
+ * Used by parsers of key/value pairs formatted as "domain=cbm" to indicate
+ * which token should be extracted and converted.
+ */
+enum resctrl_kv_sel {
+ RDT_PARSE_DOMAIN,
+ RDT_PARSE_CBM,
+};
+
/**
* enum rdtgrp_mode - Mode of a RDT resource group
* @RDT_MODE_SHAREABLE: This resource group allows sharing of its allocations
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index e1dc63b2218f..83ce3bafa5cb 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -2196,7 +2196,7 @@ static void io_alloc_init(void)
{
struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
- if (r->cache.io_alloc_capable) {
+ if (r->cache.io_alloc.io_alloc_capable) {
resctrl_file_fflags_init("io_alloc", RFTYPE_CTRL_INFO |
RFTYPE_RES_CACHE);
resctrl_file_fflags_init("io_alloc_cbm",
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 54701668b3df..9e75959565dc 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -215,7 +215,10 @@ struct resctrl_cache {
unsigned int shareable_bits;
bool arch_has_sparse_bitmasks;
bool arch_has_per_cpu_cfg;
- bool io_alloc_capable;
+ struct {
+ bool io_alloc_capable;
+ bool io_alloc_min_cbm;
+ } io_alloc;
};
/**
@@ -415,6 +418,31 @@ static inline bool resctrl_is_mbm_event(enum resctrl_event_id eventid)
eventid <= QOS_L3_MBM_LOCAL_EVENT_ID);
}
+/**
+ * apply_io_alloc_min_cbm() - Apply minimum io_alloc CBM
+ *
+ * @r: resctrl resource
+ *
+ * Return: Minimum number of consecutive io_alloc CBM bits to be set.
+ */
+static inline u32 apply_io_alloc_min_cbm(struct rdt_resource *r)
+{
+ return r->cache.min_cbm_bits;
+}
+
+/**
+ * resctrl_should_io_alloc_min_cbm() - Should the minimum io_alloc
+ * CBM be applied
+ * @r: resctrl resource
+ *
+ * Return: True if the minimum number of consecutive
+ * bits to be set in the io_alloc CBM should be applied.
+ */
+static inline bool resctrl_should_io_alloc_min_cbm(struct rdt_resource *r)
+{
+ return r->cache.io_alloc.io_alloc_min_cbm;
+}
+
u32 resctrl_get_mon_evt_cfg(enum resctrl_event_id eventid);
/* Iterate over all memory bandwidth events */
--
2.51.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains
2025-11-26 17:16 ` [PATCH 3/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains Aaron Tomlin
@ 2025-12-05 19:30 ` Moger, Babu
2025-12-15 22:50 ` Aaron Tomlin
0 siblings, 1 reply; 8+ messages in thread
From: Moger, Babu @ 2025-12-05 19:30 UTC (permalink / raw)
To: Aaron Tomlin, tony.luck, reinette.chatre, Dave.Martin,
james.morse, babu.moger, tglx, mingo, bp, dave.hansen
Cc: sean, linux-kernel
Hi Aaron,
On 11/26/2025 11:16 AM, Aaron Tomlin wrote:
> This patch introduces a special domain ID selector "*" for io_alloc_cbm
> that allows setting the CBM of each cache domain to its minimum number
> of consecutive bits in a single operation. For example, writing "*=0" to
> /sys/fs/resctrl/info/L3/io_alloc_cbm programs each domain's CBM to the
> hardware-defined minimum, greatly simplifying automation and management
> tasks. The user is required to specify the correct minimum stored in
> /sys/fs/resctrl/info/L3/min_cbm_bits.
>
> Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
> ---
> Documentation/filesystems/resctrl.rst | 10 ++
> arch/x86/kernel/cpu/resctrl/core.c | 2 +-
> arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 23 +++--
> fs/resctrl/ctrlmondata.c | 108 +++++++++++++++++-----
> fs/resctrl/internal.h | 13 +++
> fs/resctrl/rdtgroup.c | 2 +-
> include/linux/resctrl.h | 30 +++++-
> 7 files changed, 155 insertions(+), 33 deletions(-)
>
> diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
> index 8c8ce678148a..9c128c8fba86 100644
> --- a/Documentation/filesystems/resctrl.rst
> +++ b/Documentation/filesystems/resctrl.rst
> @@ -215,6 +215,16 @@ related to allocation:
> # cat /sys/fs/resctrl/info/L3/io_alloc_cbm
> 0=00ff;1=000f
>
> + Set each CBM to their minimum number of consecutive bits.
> +
> + A special value "*" is required to represent all cache IDs.
> + The user should specify the correct minimum stored in
> + /sys/fs/resctrl/info/L3/min_cbm_bits.
> +
> + Example::
> +
> + # echo "*=0" > /sys/fs/resctrl/info/L3/io_alloc_cbm
> +
> When CDP is enabled "io_alloc_cbm" associated with the CDP_DATA and CDP_CODE
> resources may reflect the same values. For example, values read from and
> written to /sys/fs/resctrl/info/L3DATA/io_alloc_cbm may be reflected by
> diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c
> index 3792ab4819dc..44aea6b534e0 100644
> --- a/arch/x86/kernel/cpu/resctrl/core.c
> +++ b/arch/x86/kernel/cpu/resctrl/core.c
> @@ -276,7 +276,7 @@ static void rdt_get_cdp_config(int level)
>
> static void rdt_set_io_alloc_capable(struct rdt_resource *r)
> {
> - r->cache.io_alloc_capable = true;
> + r->cache.io_alloc.io_alloc_capable = true;
> }
>
> static void rdt_get_cdp_l3_config(void)
> diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
> index b20e705606b8..0f051d848422 100644
> --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
> +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
> @@ -57,14 +57,19 @@ int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
> hw_dom = resctrl_to_arch_ctrl_dom(d);
> msr_param.res = NULL;
> for (t = 0; t < CDP_NUM_TYPES; t++) {
> - cfg = &hw_dom->d_resctrl.staged_config[t];
> - if (!cfg->have_new_ctrl)
> - continue;
> -
> - idx = resctrl_get_config_index(closid, t);
> - if (cfg->new_ctrl == hw_dom->ctrl_val[idx])
> - continue;
> - hw_dom->ctrl_val[idx] = cfg->new_ctrl;
> + if (resctrl_should_io_alloc_min_cbm(r)) {
> + idx = resctrl_get_config_index(closid, t);
> + hw_dom->ctrl_val[idx] = apply_io_alloc_min_cbm(r);
> + } else {
> + cfg = &hw_dom->d_resctrl.staged_config[t];
> + if (!cfg->have_new_ctrl)
> + continue;
> +
> + idx = resctrl_get_config_index(closid, t);
> + if (cfg->new_ctrl == hw_dom->ctrl_val[idx])
> + continue;
> + hw_dom->ctrl_val[idx] = cfg->new_ctrl;
> + }
>
> if (!msr_param.res) {
> msr_param.low = idx;
> @@ -123,7 +128,7 @@ int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
> {
> struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
>
> - if (hw_res->r_resctrl.cache.io_alloc_capable &&
> + if (hw_res->r_resctrl.cache.io_alloc.io_alloc_capable &&
> hw_res->sdciae_enabled != enable) {
> _resctrl_sdciae_enable(r, enable);
> hw_res->sdciae_enabled = enable;
> diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
> index 5f6f96d70e4a..b3abd781899f 100644
> --- a/fs/resctrl/ctrlmondata.c
> +++ b/fs/resctrl/ctrlmondata.c
> @@ -688,7 +688,7 @@ int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, voi
>
> mutex_lock(&rdtgroup_mutex);
>
> - if (r->cache.io_alloc_capable) {
> + if (r->cache.io_alloc.io_alloc_capable) {
> if (resctrl_arch_get_io_alloc_enabled(r))
> seq_puts(seq, "enabled\n");
> else
> @@ -712,13 +712,31 @@ static bool resctrl_io_alloc_closid_supported(u32 io_alloc_closid)
> return io_alloc_closid < closids_supported();
> }
>
> +/**
> + * resctrl_sync_cdp_peer - Mirror staged configuration to the CDP peer type
> + *
> + * @s: resctrl schema
> + * @d: resctrl control domain
> + *
> + * The caller must ensure CDP is enabled for the resource and must be
> + * called under the cpu hotplug lock and rdtgroup mutex
> + */
> +static void resctrl_sync_cdp_peer(struct resctrl_schema *s, struct rdt_ctrl_domain *d)
> +{
> + enum resctrl_conf_type peer_type;
> +
> + peer_type = resctrl_peer_type(s->conf_type);
> + memcpy(&d->staged_config[peer_type],
> + &d->staged_config[s->conf_type],
> + sizeof(d->staged_config[0]));
> +}
> +
> /*
> * Initialize io_alloc CLOSID cache resource CBM with all usable (shared
> * and unused) cache portions.
> */
> static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid)
> {
> - enum resctrl_conf_type peer_type;
> struct rdt_resource *r = s->res;
> struct rdt_ctrl_domain *d;
> int ret;
> @@ -731,11 +749,8 @@ static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid)
>
> /* Keep CDP_CODE and CDP_DATA of io_alloc CLOSID's CBM in sync. */
> if (resctrl_arch_get_cdp_enabled(r->rid)) {
> - peer_type = resctrl_peer_type(s->conf_type);
> list_for_each_entry(d, &s->res->ctrl_domains, hdr.list)
> - memcpy(&d->staged_config[peer_type],
> - &d->staged_config[s->conf_type],
> - sizeof(d->staged_config[0]));
> + resctrl_sync_cdp_peer(s, d);
> }
>
> ret = resctrl_arch_update_domains(r, closid);
> @@ -903,29 +918,82 @@ int resctrl_io_alloc_cbm_show(struct kernfs_open_file *of, struct seq_file *seq,
> return ret;
> }
>
> +/**
> + * parse_domain_cbm - Parse "domain=cbm" and return either side
> + *
> + * @line_ptr: Pointer to the input string
> + * @out_val: Output from parsed value (either domain ID or CDM)
> + * @which: Selector for which side to parse
> + *
> + * It is assumed that *line_ptr and *out_val are valid.
> + *
> + * Return: 0 on success and advance *line_ptr to point past the
> + * delimiter, EINVAL on parsing error
> + */
> +static int parse_domain_cbm(char **line_ptr, unsigned long *out_val,
> + enum resctrl_kv_sel which)
> +{
> + char *rhs, *lhs, *tok;
> + unsigned int base;
> +
> + rhs = *line_ptr;
> +
> + lhs = strsep(&rhs, "=");
> + if (!lhs || !rhs)
> + goto err;
> +
> + if (which == RDT_PARSE_DOMAIN) {
> + tok = lhs;
> + base = 10;
> + } else {
> + tok = rhs;
> + base = 16;
> + }
> + tok = strim(tok);
> +
> + if (kstrtoul(tok, base, out_val))
> + goto err;
> +
> + *line_ptr = rhs;
> + return 0;
> +err:
> + rdt_last_cmd_puts("Invalid domain=cbm: missing '=' or non-numeric value\n");
> + return -EINVAL;
> +}
> +
> static int resctrl_io_alloc_parse_line(char *line, struct rdt_resource *r,
> struct resctrl_schema *s, u32 closid)
> {
> - enum resctrl_conf_type peer_type;
> struct rdt_parse_data data;
> struct rdt_ctrl_domain *d;
> - char *dom = NULL, *id;
> - unsigned long dom_id;
> + char *dom = NULL;
> + unsigned long out_val;
> + int ret;
> +
> + if (line[0] == '*') {
> + ret = parse_domain_cbm(&line, &out_val, RDT_PARSE_CBM);
> + if (ret)
> + return ret;
>
> + if (out_val == r->cache.min_cbm_bits) {
> + r->cache.io_alloc.io_alloc_min_cbm = true;
> + return 0;
> + }
> + rdt_last_cmd_puts("Invalid io_alloc min CBM\n");
> + return -EINVAL;
> + }
> next:
> if (!line || line[0] == '\0')
> return 0;
>
> dom = strsep(&line, ";");
> - id = strsep(&dom, "=");
> - if (!dom || kstrtoul(id, 10, &dom_id)) {
> - rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
> - return -EINVAL;
> - }
> + ret = parse_domain_cbm(&line, &out_val, RDT_PARSE_DOMAIN);
> + if (ret)
> + return ret;
>
I feel this the lot of changes to take care of one extra character
change. I feel code can be simplified to just this function.
id = strim(id);
dom = strim(dom);
if (!strcmp(id, "*"))
all = true;
else if (kstrtoul(id, 10, &dom_id)) {
rdt_last_cmd_puts("Non-numeric domain\n");
return -EINVAL;
}
data.buf = dom;
data.mode = RDT_MODE_SHAREABLE;
data.closid = closid;
if (all)
apply the CBMs to all the doamins.
else
Apply the CBMs to just one domain.
Any problems with this approach?
Thanks
Babu
> dom = strim(dom);
> list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
> - if (d->hdr.id == dom_id) {
> + if (d->hdr.id == out_val) {
> data.buf = dom;
> data.mode = RDT_MODE_SHAREABLE;
> data.closid = closid;
> @@ -935,12 +1003,8 @@ static int resctrl_io_alloc_parse_line(char *line, struct rdt_resource *r,
> * Keep io_alloc CLOSID's CBM of CDP_CODE and CDP_DATA
> * in sync.
> */
> - if (resctrl_arch_get_cdp_enabled(r->rid)) {
> - peer_type = resctrl_peer_type(s->conf_type);
> - memcpy(&d->staged_config[peer_type],
> - &d->staged_config[s->conf_type],
> - sizeof(d->staged_config[0]));
> - }
> + if (resctrl_arch_get_cdp_enabled(r->rid))
> + resctrl_sync_cdp_peer(s, d);
> goto next;
> }
> }
> @@ -982,6 +1046,8 @@ ssize_t resctrl_io_alloc_cbm_write(struct kernfs_open_file *of, char *buf,
> goto out_clear_configs;
>
> ret = resctrl_arch_update_domains(r, io_alloc_closid);
> + if (resctrl_should_io_alloc_min_cbm(r))
> + r->cache.io_alloc.io_alloc_min_cbm = false;
>
> out_clear_configs:
> rdt_staged_configs_clear();
> diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
> index bff4a54ae333..3846737992bb 100644
> --- a/fs/resctrl/internal.h
> +++ b/fs/resctrl/internal.h
> @@ -143,6 +143,19 @@ enum rdt_group_type {
> RDT_NUM_GROUP,
> };
>
> +/**
> + * enum resctrl_kv_sel - Selector for "domain=cbm" key/value parsing
> + * @RDT_PARSE_DOMAIN: Parse the left-hand side (domain ID)
> + * @RDT_PARSE_CBM: Parse the right-hand side (CBM value)
> + *
> + * Used by parsers of key/value pairs formatted as "domain=cbm" to indicate
> + * which token should be extracted and converted.
> + */
> +enum resctrl_kv_sel {
> + RDT_PARSE_DOMAIN,
> + RDT_PARSE_CBM,
> +};
> +
> /**
> * enum rdtgrp_mode - Mode of a RDT resource group
> * @RDT_MODE_SHAREABLE: This resource group allows sharing of its allocations
> diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
> index e1dc63b2218f..83ce3bafa5cb 100644
> --- a/fs/resctrl/rdtgroup.c
> +++ b/fs/resctrl/rdtgroup.c
> @@ -2196,7 +2196,7 @@ static void io_alloc_init(void)
> {
> struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
>
> - if (r->cache.io_alloc_capable) {
> + if (r->cache.io_alloc.io_alloc_capable) {
> resctrl_file_fflags_init("io_alloc", RFTYPE_CTRL_INFO |
> RFTYPE_RES_CACHE);
> resctrl_file_fflags_init("io_alloc_cbm",
> diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
> index 54701668b3df..9e75959565dc 100644
> --- a/include/linux/resctrl.h
> +++ b/include/linux/resctrl.h
> @@ -215,7 +215,10 @@ struct resctrl_cache {
> unsigned int shareable_bits;
> bool arch_has_sparse_bitmasks;
> bool arch_has_per_cpu_cfg;
> - bool io_alloc_capable;
> + struct {
> + bool io_alloc_capable;
> + bool io_alloc_min_cbm;
> + } io_alloc;
> };
>
> /**
> @@ -415,6 +418,31 @@ static inline bool resctrl_is_mbm_event(enum resctrl_event_id eventid)
> eventid <= QOS_L3_MBM_LOCAL_EVENT_ID);
> }
>
> +/**
> + * apply_io_alloc_min_cbm() - Apply minimum io_alloc CBM
> + *
> + * @r: resctrl resource
> + *
> + * Return: Minimum number of consecutive io_alloc CBM bits to be set.
> + */
> +static inline u32 apply_io_alloc_min_cbm(struct rdt_resource *r)
> +{
> + return r->cache.min_cbm_bits;
> +}
> +
> +/**
> + * resctrl_should_io_alloc_min_cbm() - Should the minimum io_alloc
> + * CBM be applied
> + * @r: resctrl resource
> + *
> + * Return: True if the minimum number of consecutive
> + * bits to be set in the io_alloc CBM should be applied.
> + */
> +static inline bool resctrl_should_io_alloc_min_cbm(struct rdt_resource *r)
> +{
> + return r->cache.io_alloc.io_alloc_min_cbm;
> +}
> +
> u32 resctrl_get_mon_evt_cfg(enum resctrl_event_id eventid);
>
> /* Iterate over all memory bandwidth events */
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/3] fs/resctrl: Add helpers to check io_alloc support and enabled state
2025-11-26 17:16 ` [PATCH 1/3] fs/resctrl: Add helpers to check io_alloc support and enabled state Aaron Tomlin
@ 2025-12-05 19:35 ` Moger, Babu
2025-12-15 22:27 ` Aaron Tomlin
0 siblings, 1 reply; 8+ messages in thread
From: Moger, Babu @ 2025-12-05 19:35 UTC (permalink / raw)
To: Aaron Tomlin, tony.luck, reinette.chatre, Dave.Martin,
james.morse, babu.moger, tglx, mingo, bp, dave.hansen
Cc: sean, linux-kernel
Hi Aaron,
On 11/26/2025 11:16 AM, Aaron Tomlin wrote:
> This patch introduces two helpers to validate io_alloc support and
> whether it is enabled. This reduces code duplication, clarifies
> intent, and preserves existing semantics and messages.
>
> Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
> ---
> fs/resctrl/ctrlmondata.c | 74 +++++++++++++++++++++++++++++-----------
> 1 file changed, 54 insertions(+), 20 deletions(-)
>
> diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
> index b2d178d3556e..5f6f96d70e4a 100644
> --- a/fs/resctrl/ctrlmondata.c
> +++ b/fs/resctrl/ctrlmondata.c
> @@ -758,6 +758,50 @@ u32 resctrl_io_alloc_closid(struct rdt_resource *r)
> return resctrl_arch_get_num_closid(r) - 1;
> }
>
> +/*
> + * check_io_alloc_support() - Establish if io_alloc is supported
> + *
> + * @s: resctrl resource schema.
> + *
> + * This function must be called under the cpu hotplug lock
> + * and rdtgroup mutex
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +static int check_io_alloc_support(struct resctrl_schema *s)
For consistency, how about changing the name to
resctrl_io_alloc_supported() and
resctrl_io_alloc_enabled()
Thanks
Babu
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/3] fs/resctrl: Add helpers to check io_alloc support and enabled state
2025-12-05 19:35 ` Moger, Babu
@ 2025-12-15 22:27 ` Aaron Tomlin
0 siblings, 0 replies; 8+ messages in thread
From: Aaron Tomlin @ 2025-12-15 22:27 UTC (permalink / raw)
To: Moger, Babu
Cc: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
tglx, mingo, bp, dave.hansen, sean, linux-kernel
On Fri, Dec 05, 2025 at 01:35:37PM -0600, Moger, Babu wrote:
> For consistency, how about changing the name to
>
> resctrl_io_alloc_supported() and
>
> resctrl_io_alloc_enabled()
Hi Babu,
Acknowledged.
Kind regards,
--
Aaron Tomlin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains
2025-12-05 19:30 ` Moger, Babu
@ 2025-12-15 22:50 ` Aaron Tomlin
0 siblings, 0 replies; 8+ messages in thread
From: Aaron Tomlin @ 2025-12-15 22:50 UTC (permalink / raw)
To: Moger, Babu
Cc: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
tglx, mingo, bp, dave.hansen, sean, linux-kernel
On Fri, Dec 05, 2025 at 01:30:09PM -0600, Moger, Babu wrote:
> I feel this the lot of changes to take care of one extra character change. I
> feel code can be simplified to just this function.
>
Hi Babu,
Thank you very much for following up and for providing a suggested
simplification of the code.
I appreciate you taking the time to review the changes. While your proposed
approach is definitely concise and functional, I prefer to maintain the
current, more elaborate implementation. The purpose of this slightly more
detailed structure is to improve overall readability and facilitate further
possible enhancements down the line.
For your information, in a subsequent patch series, I have decided to
refactor the logic within the main loop entirely. Specifically, I am
replacing the goto statement with a standard while loop to further improve
control flow and maintainability.
Kind regards,
--
Aaron Tomlin
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-12-15 22:50 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-26 17:16 [PATCH 0/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains Aaron Tomlin
2025-11-26 17:16 ` [PATCH 1/3] fs/resctrl: Add helpers to check io_alloc support and enabled state Aaron Tomlin
2025-12-05 19:35 ` Moger, Babu
2025-12-15 22:27 ` Aaron Tomlin
2025-11-26 17:16 ` [PATCH 2/3] fs/resctrl: Return -EINVAL for a missing seq_show implementation Aaron Tomlin
2025-11-26 17:16 ` [PATCH 3/3] x86/resctrl: Add "*" shorthand to set minimum io_alloc CBM for all domains Aaron Tomlin
2025-12-05 19:30 ` Moger, Babu
2025-12-15 22:50 ` Aaron Tomlin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox