FAILED: patch "[PATCH] fs/resctrl: Fix use-after-free during unmount" failed to apply to 6.18-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x 52fce648607e0d6a76eeb443d78708c49df1c554
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026072028-reverence-sandy-7415@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 52fce648607e0d6a76eeb443d78708c49df1c554 Mon Sep 17 00:00:00 2001
From: Tony Luck <[email protected]>
Date: Mon, 6 Jul 2026 15:46:22 -0700
Subject: [PATCH] fs/resctrl: Fix use-after-free during unmount
During unmount or failure teardown all mon_data structures that contain monitoring event file private data are freed after which kernfs nodes are removed. However, the RDT_DELETED flag is never set for the statically allocated default resource group.
A concurrent reader of an event file associated with the default resource group may, after dropping kernfs active protection, block on rdtgroup_mutex while unmount proceeds to free the file private data and destroy the kernfs node without waiting for the reader.
When the mutex is released, the reader wakes up, observes that RDT_DELETED is not set for the default group, and dereferences the already-freed file private data.
The scenario can be depicted as follows:
CPU0 CPU1
/*
* Default resource group's
* monitoring data accessible via
* kernfs file with kernfs_node::priv
* pointing to a struct mon_data.
* User opens the file for reading.
*/
rdtgroup_mondata_show() /* arch encounters fatal error */
rdtgroup_kn_lock_live() resctrl_exit()
atomic_inc(&rdtgroup_default.waitcount) cpus_read_lock()
kernfs_break_active_protection(kn) mutex_lock(&rdtgroup_mutex)
cpus_read_lock() resctrl_fs_teardown()
mutex_lock(&rdtgroup_mutex) rmdir_all_sub()
mon_put_kn_priv()
/* Delete all mon_data structures */
rdtgroup_destroy_root()
kernfs_destroy_root()
rdtgroup_default.kn = NULL
mutex_unlock(&rdtgroup_mutex)
/*
* rdtgroup_default.flags is empty so
* rdtgroup_kn_lock_live() returns
* &rdtgroup_default
*/
md = of->kn->priv;
/* md points to freed mon_data */Set RDT_DELETED for the default group unconditionally since the flag does not lead to the freeing of this statically allocated group.
Do not allow a new resctrl mount if there are any waiters on default group of previous mount. A new mount will re-initialize the default group that would appear to waiters from previous mount as though the default group is accessible causing them to access the mon_data structures from the previous mount that have been removed.
fs/resctrl/rdtgroup.c +16 -2
@@ -587,14 +587,20 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,* * On resource group creation via a mkdir, an extra kernfs_node reference is * taken to ensure that the rdtgroup structure remains accessible for the -* rdtgroup_kn_unlock() calls where it is removed. +* rdtgroup_kn_unlock() calls where it is removed. The default group is +* statically allocated: it does not have an extra reference but will have +* RDT_DELETED set on unmount to support safe access to its associated files +* via rdtgroup_kn_lock_live/rdtgroup_kn_unlock(). * -* Drop the extra reference here, then free the rdtgroup structure. +* For all but the default group: drop the extra reference, then free the +* rdtgroup structure. * * Return: void */ static void rdtgroup_remove (struct rdtgroup *rdtgrp) { +if (rdtgrp == &rdtgroup_default) +return ;kernfs_put (rdtgrp->kn);kfree (rdtgrp); }
@@ -2814,6 +2820,12 @@ static int rdt_get_tree(struct fs_context *fc) goto out; } +/* Avoid races from pending operations from a previous mount */ +if (atomic_read (&rdtgroup_default.waitcount) !=0 ) { + ret = -EBUSY ; + goto out; + } + ret =setup_rmid_lru_list ();if (ret) goto out;
@@ -3177,6 +3189,7 @@ static void resctrl_fs_teardown(void)mon_put_kn_priv ();rdt_pseudo_lock_release (); rdtgroup_default.mode =RDT_MODE_SHAREABLE ; + rdtgroup_default.flags =RDT_DELETED ;closid_exit ();schemata_list_destroy ();rdtgroup_destroy_root ();
@@ -4277,6 +4290,7 @@ static int rdtgroup_setup_root(struct rdt_fs_context *ctx) ctx->kfc.root = rdt_root; rdtgroup_default.kn =kernfs_root_to_node (rdt_root); + rdtgroup_default.flags =0 ;return 0 ; }
Sasha Levin
maintainerPATCH 1/6 fs/resctrl: Split L3 dependent parts out of __mon_event_count()
From: Tony Luck <[email protected]>
[ Upstream commit ad5c2ff75e0c53d2588dfc10eb87458e759b6bbe ]
Carve out the L3 resource specific event reading code into a separate helper to support reading event data from a new monitoring resource.
Stable-dep-of: 52fce648607e ("fs/resctrl: Fix use-after-free during unmount")
--- fs/resctrl/monitor.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
fs/resctrl/monitor.c +12 -1
@@ -418,7 +418,7 @@ static void mbm_cntr_free(struct rdt_mon_domain *d, int cntr_id)memset (&d->cntr_cfg[cntr_id],0 ,sizeof (*d->cntr_cfg)); } -static int __mon_event_count (struct rdtgroup *rdtgrp,struct rmid_read *rr) +static int __l3_mon_event_count (struct rdtgroup *rdtgrp,struct rmid_read *rr) {int cpu =smp_processor_id ();u32 closid = rdtgrp->closid;
@@ -499,6 +499,17 @@ static int __mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)return ret; } +static int __mon_event_count (struct rdtgroup *rdtgrp,struct rmid_read *rr) +{ +switch (rr->r->rid) { +case RDT_RESOURCE_L3 : +return __l3_mon_event_count (rdtgrp, rr); +default : + rr->err = -EINVAL ; +return -EINVAL ; + } +} +/* * mbm_bw_count() - Update bw count from values previously read by * __mon_event_count().
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/6 x86,fs/resctrl: Rename struct rdt_mon_domain and rdt_hw_mon_domain
From: Tony Luck <[email protected]>
[ Upstream commit 4bc3ef46ff41d5e7ba557e56e9cd2031527cd7f8 ]
The upcoming telemetry event monitoring is not tied to the L3 resource and will have a new domain structure.
Rename the L3 resource specific domain data structures to include "l3_" in their names to avoid confusion between the different resource specific domain structures:rdt_mon_domain -> rdt_l3_mon_domainrdt_hw_mon_domain -> rdt_hw_l3_mon_domain
No functional change.
Stable-dep-of: 52fce648607e ("fs/resctrl: Fix use-after-free during unmount")
--- arch/x86/kernel/cpu/resctrl/core.c | 16 +++---- arch/x86/kernel/cpu/resctrl/internal.h | 16 +++---- arch/x86/kernel/cpu/resctrl/monitor.c | 34 +++++++------- fs/resctrl/ctrlmondata.c | 6 +-- fs/resctrl/internal.h | 12 ++--- fs/resctrl/monitor.c | 62 +++++++++++++------------- fs/resctrl/rdtgroup.c | 32 ++++++------- include/linux/resctrl.h | 28 ++++++------ 8 files changed, 103 insertions(+), 103 deletions(-)
arch/x86/kernel/cpu/resctrl/core.c +8 -8
@@ -363,7 +363,7 @@ static void ctrl_domain_free(struct rdt_hw_ctrl_domain *hw_dom)kfree (hw_dom); } -static void mon_domain_free (struct rdt_hw_mon_domain *hw_dom) +static void mon_domain_free (struct rdt_hw_l3_mon_domain *hw_dom) {int idx;
@@ -400,7 +400,7 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain ** @num_rmid: The size of the MBM counter array * @hw_dom: The domain that owns the allocated arrays */ -static int arch_domain_mbm_alloc (u32 num_rmid,struct rdt_hw_mon_domain *hw_dom) +static int arch_domain_mbm_alloc (u32 num_rmid,struct rdt_hw_l3_mon_domain *hw_dom) {size_t tsize =sizeof (*hw_dom->arch_mbm_states[0 ]);enum resctrl_event_id eventid;
@@ -499,9 +499,9 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) {int id =get_domain_id_from_scope (cpu, r->mon_scope);struct list_head *add_pos =NULL ; -struct rdt_hw_mon_domain *hw_dom; +struct rdt_hw_l3_mon_domain *hw_dom;struct rdt_domain_hdr *hdr; -struct rdt_mon_domain *d; +struct rdt_l3_mon_domain *d;struct cacheinfo *ci;int err;
@@ -517,7 +517,7 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)if (hdr) {if (WARN_ON_ONCE (hdr->type !=RESCTRL_MON_DOMAIN ))return ; - d = container_of(hdr, struct rdt_mon_domain, hdr); + d = container_of(hdr, struct rdt_l3_mon_domain, hdr);cpumask_set_cpu (cpu, &d->hdr.cpu_mask);/* Update the mbm_assign_mode state for the CPU if supported */
@@ -620,9 +620,9 @@ static void domain_remove_cpu_ctrl(int cpu, struct rdt_resource *r)static void domain_remove_cpu_mon (int cpu,struct rdt_resource *r) {int id =get_domain_id_from_scope (cpu, r->mon_scope); -struct rdt_hw_mon_domain *hw_dom; +struct rdt_hw_l3_mon_domain *hw_dom;struct rdt_domain_hdr *hdr; -struct rdt_mon_domain *d; +struct rdt_l3_mon_domain *d;lockdep_assert_held (&domain_list_lock);
@@ -642,7 +642,7 @@ static void domain_remove_cpu_mon(int cpu, struct rdt_resource *r)if (WARN_ON_ONCE (hdr->type !=RESCTRL_MON_DOMAIN ))return ; - d = container_of(hdr, struct rdt_mon_domain, hdr); + d = container_of(hdr, struct rdt_l3_mon_domain, hdr); hw_dom =resctrl_to_arch_mon_dom (d);cpumask_clear_cpu (cpu, &d->hdr.cpu_mask);
arch/x86/kernel/cpu/resctrl/internal.h +8 -8
@@ -63,17 +63,17 @@ struct rdt_hw_ctrl_domain { };/** -* struct rdt_hw_mon_domain - Arch private attributes of a set of CPUs that share -* a resource for a monitor function -* @d_resctrl: Properties exposed to the resctrl file system +* struct rdt_hw_l3_mon_domain - Arch private attributes of a set of CPUs sharing +* RDT_RESOURCE_L3 monitoring +* @d_resctrl: Properties exposed to the resctrl file system * @arch_mbm_states: Per-event pointer to the MBM event's saved state. * An MBM event's state is an array of struct arch_mbm_state * indexed by RMID on x86. * * Members of this structure are accessed via helpers that provide abstraction. */ -struct rdt_hw_mon_domain { -struct rdt_mon_domain d_resctrl; +struct rdt_hw_l3_mon_domain { +struct rdt_l3_mon_domain d_resctrl;struct arch_mbm_state *arch_mbm_states[QOS_NUM_L3_MBM_EVENTS ]; };
@@ -82,9 +82,9 @@ static inline struct rdt_hw_ctrl_domain *resctrl_to_arch_ctrl_dom(struct rdt_ctr return container_of(r, struct rdt_hw_ctrl_domain, d_resctrl); } -static inline struct rdt_hw_mon_domain *resctrl_to_arch_mon_dom (struct rdt_mon_domain *r) +static inline struct rdt_hw_l3_mon_domain *resctrl_to_arch_mon_dom (struct rdt_l3_mon_domain *r) { - return container_of(r, struct rdt_hw_mon_domain, d_resctrl); + return container_of(r, struct rdt_hw_l3_mon_domain, d_resctrl); }/**
@@ -138,7 +138,7 @@ static inline struct rdt_hw_resource *resctrl_to_arch_res(struct rdt_resource *rextern struct rdt_hw_resource rdt_resources_all[]; -void arch_mon_domain_online (struct rdt_resource *r,struct rdt_mon_domain *d); +void arch_mon_domain_online (struct rdt_resource *r,struct rdt_l3_mon_domain *d);/* CPUID.(EAX=10H, ECX=ResID=1).EAX */ union cpuid_0x10_1_eax {
arch/x86/kernel/cpu/resctrl/monitor.c +17 -17
@@ -109,7 +109,7 @@ static inline u64 get_corrected_mbm_count(u32 rmid, unsigned long val)* * In RMID sharing mode there are fewer "logical RMID" values available * to accumulate data ("physical RMIDs" are divided evenly between SNC -* nodes that share an L3 cache). Linux creates an rdt_mon_domain for +* nodes that share an L3 cache). Linux creates an rdt_l3_mon_domain for * each SNC node. * * The value loaded into IA32_PQR_ASSOC is the "logical RMID".
@@ -157,7 +157,7 @@ static int __rmid_read_phys(u32 prmid, enum resctrl_event_id eventid, u64 *val)return 0 ; } -static struct arch_mbm_state *get_arch_mbm_state (struct rdt_hw_mon_domain *hw_dom, +static struct arch_mbm_state *get_arch_mbm_state (struct rdt_hw_l3_mon_domain *hw_dom,u32 rmid,enum resctrl_event_id eventid) {
@@ -171,11 +171,11 @@ static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_mon_domain *hw_doreturn state ? &state[rmid] :NULL ; } -void resctrl_arch_reset_rmid (struct rdt_resource *r,struct rdt_mon_domain *d, +void resctrl_arch_reset_rmid (struct rdt_resource *r,struct rdt_l3_mon_domain *d,u32 unused,u32 rmid,enum resctrl_event_id eventid) { -struct rdt_hw_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d); +struct rdt_hw_l3_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d);int cpu =cpumask_any (&d->hdr.cpu_mask);struct arch_mbm_state *am;u32 prmid;
@@ -194,9 +194,9 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,* Assumes that hardware counters are also reset and thus that there is * no need to record initial non-zero counts. */ -void resctrl_arch_reset_rmid_all (struct rdt_resource *r,struct rdt_mon_domain *d) +void resctrl_arch_reset_rmid_all (struct rdt_resource *r,struct rdt_l3_mon_domain *d) { -struct rdt_hw_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d); +struct rdt_hw_l3_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d);enum resctrl_event_id eventid;int idx;
@@ -217,10 +217,10 @@ static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width)return chunks >> shift; } -static u64 get_corrected_val (struct rdt_resource *r,struct rdt_mon_domain *d, +static u64 get_corrected_val (struct rdt_resource *r,struct rdt_l3_mon_domain *d,u32 rmid,enum resctrl_event_id eventid,u64 msr_val) { -struct rdt_hw_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d); +struct rdt_hw_l3_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d);struct rdt_hw_resource *hw_res =resctrl_to_arch_res (r);struct arch_mbm_state *am;u64 chunks;
@@ -238,11 +238,11 @@ static u64 get_corrected_val(struct rdt_resource *r, struct rdt_mon_domain *d,return chunks * hw_res->mon_scale; } -int resctrl_arch_rmid_read (struct rdt_resource *r,struct rdt_mon_domain *d, +int resctrl_arch_rmid_read (struct rdt_resource *r,struct rdt_l3_mon_domain *d,u32 unused,u32 rmid,enum resctrl_event_id eventid,u64 *val,void *ignored) { -struct rdt_hw_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d); +struct rdt_hw_l3_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d);struct arch_mbm_state *am;u64 msr_val;u32 prmid;
@@ -308,11 +308,11 @@ static int __cntr_id_read(u32 cntr_id, u64 *val)return 0 ; } -void resctrl_arch_reset_cntr (struct rdt_resource *r,struct rdt_mon_domain *d, +void resctrl_arch_reset_cntr (struct rdt_resource *r,struct rdt_l3_mon_domain *d,u32 unused,u32 rmid,int cntr_id,enum resctrl_event_id eventid) { -struct rdt_hw_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d); +struct rdt_hw_l3_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d);struct arch_mbm_state *am; am =get_arch_mbm_state (hw_dom, rmid, eventid);
@@ -324,7 +324,7 @@ void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, } } -int resctrl_arch_cntr_read (struct rdt_resource *r,struct rdt_mon_domain *d, +int resctrl_arch_cntr_read (struct rdt_resource *r,struct rdt_l3_mon_domain *d,u32 unused,u32 rmid,int cntr_id,enum resctrl_event_id eventid,u64 *val) {
@@ -354,7 +354,7 @@ int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d,* must adjust RMID counter numbers based on SNC node. See * logical_rmid_to_physical_rmid() for code that does this. */ -void arch_mon_domain_online (struct rdt_resource *r,struct rdt_mon_domain *d) +void arch_mon_domain_online (struct rdt_resource *r,struct rdt_l3_mon_domain *d) {if (snc_nodes_per_l3_cache >1 )msr_clear_bit (MSR_RMID_SNC_CONFIG ,0 );
@@ -515,7 +515,7 @@ static void resctrl_abmc_set_one_amd(void *arg)*/ static void _resctrl_abmc_enable (struct rdt_resource *r,bool enable) { -struct rdt_mon_domain *d; +struct rdt_l3_mon_domain *d;lockdep_assert_cpus_held ();
@@ -554,11 +554,11 @@ static void resctrl_abmc_config_one_amd(void *info)/* * Send an IPI to the domain to assign the counter to RMID, event pair. */ -void resctrl_arch_config_cntr (struct rdt_resource *r,struct rdt_mon_domain *d, +void resctrl_arch_config_cntr (struct rdt_resource *r,struct rdt_l3_mon_domain *d,enum resctrl_event_id evtid,u32 rmid,u32 closid,u32 cntr_id,bool assign) { -struct rdt_hw_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d); +struct rdt_hw_l3_mon_domain *hw_dom =resctrl_to_arch_mon_dom (d);union l3_qos_abmc_cfg abmc_cfg = {0 };struct arch_mbm_state *am;
fs/resctrl/ctrlmondata.c +3 -3
@@ -547,7 +547,7 @@ struct rdt_domain_hdr *resctrl_find_domain(struct list_head *h, int id, }void mon_event_read (struct rmid_read *rr,struct rdt_resource *r, -struct rdt_mon_domain *d,struct rdtgroup *rdtgrp, +struct rdt_l3_mon_domain *d,struct rdtgroup *rdtgrp,cpumask_t *cpumask,int evtid,int first) {int cpu;
@@ -596,9 +596,9 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg)struct kernfs_open_file *of = m->private;enum resctrl_res_level resid;enum resctrl_event_id evtid; +struct rdt_l3_mon_domain *d;struct rdt_domain_hdr *hdr;struct rmid_read rr = {0 }; -struct rdt_mon_domain *d;struct rdtgroup *rdtgrp;int domid, cpu, ret =0 ;struct rdt_resource *r;
@@ -653,7 +653,7 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg) ret = -ENOENT ; goto out; } - d = container_of(hdr, struct rdt_mon_domain, hdr); + d = container_of(hdr, struct rdt_l3_mon_domain, hdr);mon_event_read (&rr, r, d, rdtgrp, &d->hdr.cpu_mask, evtid, false); }
fs/resctrl/internal.h +6 -6
@@ -123,7 +123,7 @@ struct mon_data {struct rmid_read {struct rdtgroup *rgrp;struct rdt_resource *r; -struct rdt_mon_domain *d; +struct rdt_l3_mon_domain *d;enum resctrl_event_id evtid;bool first;struct cacheinfo *ci;
@@ -362,12 +362,12 @@ void mon_event_count(void *info);int rdtgroup_mondata_show (struct seq_file *m,void *arg);void mon_event_read (struct rmid_read *rr,struct rdt_resource *r, -struct rdt_mon_domain *d,struct rdtgroup *rdtgrp, +struct rdt_l3_mon_domain *d,struct rdtgroup *rdtgrp,cpumask_t *cpumask,int evtid,int first);int resctrl_mon_resource_init (void ); -void mbm_setup_overflow_handler (struct rdt_mon_domain *dom, +void mbm_setup_overflow_handler (struct rdt_l3_mon_domain *dom,unsigned long delay_ms,int exclude_cpu);
@@ -375,14 +375,14 @@ void mbm_handle_overflow(struct work_struct *work);bool is_mba_sc (struct rdt_resource *r); -void cqm_setup_limbo_handler (struct rdt_mon_domain *dom,unsigned long delay_ms, +void cqm_setup_limbo_handler (struct rdt_l3_mon_domain *dom,unsigned long delay_ms,int exclude_cpu);void cqm_handle_limbo (struct work_struct *work); -bool has_busy_rmid (struct rdt_mon_domain *d); +bool has_busy_rmid (struct rdt_l3_mon_domain *d); -void __check_limbo (struct rdt_mon_domain *d,bool force_free); +void __check_limbo (struct rdt_l3_mon_domain *d,bool force_free);void resctrl_file_fflags_init (const char *config,unsigned long fflags);
fs/resctrl/monitor.c +31 -31
246 lines not on this page · raw message
fs/resctrl/rdtgroup.c +16 -16
@@ -1620,7 +1620,7 @@ static void mondata_config_read(struct resctrl_mon_config_info *mon_info)static int mbm_config_show (struct seq_file *s,struct rdt_resource *r,u32 evtid) {struct resctrl_mon_config_info mon_info; -struct rdt_mon_domain *dom; +struct rdt_l3_mon_domain *dom;bool sep = false;cpus_read_lock ();
@@ -1668,7 +1668,7 @@ static int mbm_local_bytes_config_show(struct kernfs_open_file *of, }static void mbm_config_write_domain (struct rdt_resource *r, -struct rdt_mon_domain *d,u32 evtid,u32 val) +struct rdt_l3_mon_domain *d,u32 evtid,u32 val) {struct resctrl_mon_config_info mon_info = {0 };
@@ -1710,7 +1710,7 @@ static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid) {char *dom_str =NULL , *id_str;unsigned long dom_id, val; -struct rdt_mon_domain *d; +struct rdt_l3_mon_domain *d;/* Walking r->domains, ensure it can't race with cpuhp */ lockdep_assert_cpus_held ();
@@ -2718,7 +2718,7 @@ static int rdt_get_tree(struct fs_context *fc) {struct rdt_fs_context *ctx =rdt_fc2context (fc);unsigned long flags =RFTYPE_CTRL_BASE ; -struct rdt_mon_domain *dom; +struct rdt_l3_mon_domain *dom;struct rdt_resource *r;int ret;
@@ -3169,7 +3169,7 @@ static void mon_rmdir_one_subdir(struct kernfs_node *pkn, char *name, char *subn* when last domain being summed is removed. */ static void rmdir_mondata_subdir_allrdtgrp (struct rdt_resource *r, -struct rdt_mon_domain *d) +struct rdt_l3_mon_domain *d) {struct rdtgroup *prgrp, *crgrp;char subname[32 ];
@@ -3189,7 +3189,7 @@ static void rmdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, } } -static int mon_add_all_files (struct kernfs_node *kn,struct rdt_mon_domain *d, +static int mon_add_all_files (struct kernfs_node *kn,struct rdt_l3_mon_domain *d,struct rdt_resource *r,struct rdtgroup *prgrp,bool do_sum) {
@@ -3218,7 +3218,7 @@ static int mon_add_all_files(struct kernfs_node *kn, struct rdt_mon_domain *d, }static int mkdir_mondata_subdir (struct kernfs_node *parent_kn, -struct rdt_mon_domain *d, +struct rdt_l3_mon_domain *d,struct rdt_resource *r,struct rdtgroup *prgrp) {struct kernfs_node *kn, *ckn;
@@ -3280,7 +3280,7 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn,* and "monitor" groups with given domain id. */ static void mkdir_mondata_subdir_allrdtgrp (struct rdt_resource *r, -struct rdt_mon_domain *d) +struct rdt_l3_mon_domain *d) {struct kernfs_node *parent_kn;struct rdtgroup *prgrp, *crgrp;
@@ -3302,7 +3302,7 @@ static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn,struct rdt_resource *r, struct rdtgroup *prgrp) { - struct rdt_mon_domain *dom; + struct rdt_l3_mon_domain *dom;int ret;/* Walking r->domains, ensure it can't race with cpuhp */
@@ -4170,7 +4170,7 @@ static void rdtgroup_setup_default(void)mutex_unlock (&rdtgroup_mutex); } -static void domain_destroy_mon_state (struct rdt_mon_domain *d) +static void domain_destroy_mon_state (struct rdt_l3_mon_domain *d) {int idx;
@@ -4192,7 +4192,7 @@ void resctrl_offline_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domainmutex_unlock (&rdtgroup_mutex); } -void resctrl_offline_mon_domain (struct rdt_resource *r,struct rdt_mon_domain *d) +void resctrl_offline_mon_domain (struct rdt_resource *r,struct rdt_l3_mon_domain *d) {mutex_lock (&rdtgroup_mutex);
@@ -4236,7 +4236,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d* * Returns 0 for success, or -ENOMEM. */ -static int domain_setup_mon_state (struct rdt_resource *r,struct rdt_mon_domain *d) +static int domain_setup_mon_state (struct rdt_resource *r,struct rdt_l3_mon_domain *d) {u32 idx_limit =resctrl_arch_system_num_rmid_idx ();size_t tsize =sizeof (*d->mbm_states[0 ]);
@@ -4292,7 +4292,7 @@ int resctrl_online_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *dreturn err; } -int resctrl_online_mon_domain (struct rdt_resource *r,struct rdt_mon_domain *d) +int resctrl_online_mon_domain (struct rdt_resource *r,struct rdt_l3_mon_domain *d) {int err;
@@ -4344,10 +4344,10 @@ static void clear_childcpus(struct rdtgroup *r, unsigned int cpu) } } -static struct rdt_mon_domain *get_mon_domain_from_cpu (int cpu, +static struct rdt_l3_mon_domain *get_mon_domain_from_cpu (int cpu,struct rdt_resource *r) { -struct rdt_mon_domain *d; +struct rdt_l3_mon_domain *d;lockdep_assert_cpus_held ();
@@ -4363,7 +4363,7 @@ static struct rdt_mon_domain *get_mon_domain_from_cpu(int cpu,void resctrl_offline_cpu (unsigned int cpu) {struct rdt_resource *l3 =resctrl_arch_get_resource (RDT_RESOURCE_L3 ); -struct rdt_mon_domain *d; +struct rdt_l3_mon_domain *d;struct rdtgroup *rdtgrp;mutex_lock (&rdtgroup_mutex);
include/linux/resctrl.h +14 -14
@@ -169,7 +169,7 @@ struct mbm_cntr_cfg { };/** -* struct rdt_mon_domain - group of CPUs sharing a resctrl monitor resource +* struct rdt_l3_mon_domain - group of CPUs sharing RDT_RESOURCE_L3 monitoring * @hdr: common header for different domain types * @ci_id: cache info id for this domain * @rmid_busy_llc: bitmap of which limbo RMIDs are above threshold
@@ -183,7 +183,7 @@ struct mbm_cntr_cfg {* @cntr_cfg: array of assignable counters' configuration (indexed * by counter ID) */ -struct rdt_mon_domain { +struct rdt_l3_mon_domain {struct rdt_domain_hdr hdr;unsigned int ci_id;unsigned long *rmid_busy_llc;
@@ -355,10 +355,10 @@ struct resctrl_cpu_defaults { };struct resctrl_mon_config_info { -struct rdt_resource *r; -struct rdt_mon_domain *d; -u32 evtid; -u32 mon_config; +struct rdt_resource *r; +struct rdt_l3_mon_domain *d; +u32 evtid; +u32 mon_config; };/**
@@ -495,9 +495,9 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,u32 resctrl_arch_get_config (struct rdt_resource *r,struct rdt_ctrl_domain *d,u32 closid,enum resctrl_conf_type type);int resctrl_online_ctrl_domain (struct rdt_resource *r,struct rdt_ctrl_domain *d); -int resctrl_online_mon_domain (struct rdt_resource *r,struct rdt_mon_domain *d); +int resctrl_online_mon_domain (struct rdt_resource *r,struct rdt_l3_mon_domain *d);void resctrl_offline_ctrl_domain (struct rdt_resource *r,struct rdt_ctrl_domain *d); -void resctrl_offline_mon_domain (struct rdt_resource *r,struct rdt_mon_domain *d); +void resctrl_offline_mon_domain (struct rdt_resource *r,struct rdt_l3_mon_domain *d);void resctrl_online_cpu (unsigned int cpu);void resctrl_offline_cpu (unsigned int cpu);
@@ -526,7 +526,7 @@ void resctrl_offline_cpu(unsigned int cpu);* Return: * 0 on success, or -EIO, -EINVAL etc on error. */ -int resctrl_arch_rmid_read (struct rdt_resource *r,struct rdt_mon_domain *d, +int resctrl_arch_rmid_read (struct rdt_resource *r,struct rdt_l3_mon_domain *d,u32 closid,u32 rmid,enum resctrl_event_id eventid,u64 *val,void *arch_mon_ctx);
@@ -573,7 +573,7 @@ struct rdt_domain_hdr *resctrl_find_domain(struct list_head *h, int id,* * This can be called from any CPU. */ -void resctrl_arch_reset_rmid (struct rdt_resource *r,struct rdt_mon_domain *d, +void resctrl_arch_reset_rmid (struct rdt_resource *r,struct rdt_l3_mon_domain *d,u32 closid,u32 rmid,enum resctrl_event_id eventid);
@@ -586,7 +586,7 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d,* * This can be called from any CPU. */ -void resctrl_arch_reset_rmid_all (struct rdt_resource *r,struct rdt_mon_domain *d); +void resctrl_arch_reset_rmid_all (struct rdt_resource *r,struct rdt_l3_mon_domain *d);/** * resctrl_arch_reset_all_ctrls() - Reset the control for each CLOSID to its
@@ -612,7 +612,7 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r);* * This can be called from any CPU. */ -void resctrl_arch_config_cntr (struct rdt_resource *r,struct rdt_mon_domain *d, +void resctrl_arch_config_cntr (struct rdt_resource *r,struct rdt_l3_mon_domain *d,enum resctrl_event_id evtid,u32 rmid,u32 closid,u32 cntr_id,bool assign);
@@ -635,7 +635,7 @@ void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,* Return: * 0 on success, or -EIO, -EINVAL etc on error. */ -int resctrl_arch_cntr_read (struct rdt_resource *r,struct rdt_mon_domain *d, +int resctrl_arch_cntr_read (struct rdt_resource *r,struct rdt_l3_mon_domain *d,u32 closid,u32 rmid,int cntr_id,enum resctrl_event_id eventid,u64 *val);
@@ -650,7 +650,7 @@ int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d,* * This can be called from any CPU. */ -void resctrl_arch_reset_cntr (struct rdt_resource *r,struct rdt_mon_domain *d, +void resctrl_arch_reset_cntr (struct rdt_resource *r,struct rdt_l3_mon_domain *d,u32 closid,u32 rmid,int cntr_id,enum resctrl_event_id eventid);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/6 x86,fs/resctrl: Rename some L3 specific functions
In reply to Sasha LevinFrom: Tony Luck <[email protected]>
[ Upstream commit 9c214d10c50990c7a61b95887493df9ae713eec5 ]
With the arrival of monitor events tied to new domains associated with a different resource it would be clearer if the L3 resource specific functions are more accurately named.
Rename three groups of functions:
Functions that allocate/free architecture per-RMID MBM state information:arch_domain_mbm_alloc() -> l3_mon_domain_mbm_alloc()mon_domain_free() -> l3_mon_domain_free()
Functions that allocate/free filesystem per-RMID MBM state information:domain_setup_mon_state() -> domain_setup_l3_mon_state()domain_destroy_mon_state() -> domain_destroy_l3_mon_state()
Initialization/exit:rdt_get_mon_l3_config() -> rdt_get_l3_mon_config()resctrl_mon_resource_init() -> resctrl_l3_mon_resource_init()resctrl_mon_resource_exit() -> resctrl_l3_mon_resource_exit()
Ensure kernel-doc descriptions of these functions' return values are present and correctly formatted.
Stable-dep-of: 52fce648607e ("fs/resctrl: Fix use-after-free during unmount")
--- arch/x86/kernel/cpu/resctrl/core.c | 20 +++++++++++--------- arch/x86/kernel/cpu/resctrl/internal.h | 2 +- arch/x86/kernel/cpu/resctrl/monitor.c | 2 +- fs/resctrl/internal.h | 6 +++--- fs/resctrl/monitor.c | 8 ++++---- fs/resctrl/rdtgroup.c | 24 ++++++++++++------------ 6 files changed, 32 insertions(+), 30 deletions(-)
arch/x86/kernel/cpu/resctrl/core.c +11 -9
@@ -363,7 +363,7 @@ static void ctrl_domain_free(struct rdt_hw_ctrl_domain *hw_dom)kfree (hw_dom); } -static void mon_domain_free (struct rdt_hw_l3_mon_domain *hw_dom) +static void l3_mon_domain_free (struct rdt_hw_l3_mon_domain *hw_dom) {int idx;
@@ -396,11 +396,13 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain * }/** -* arch_domain_mbm_alloc() - Allocate arch private storage for the MBM counters +* l3_mon_domain_mbm_alloc() - Allocate arch private storage for the MBM counters * @num_rmid: The size of the MBM counter array * @hw_dom: The domain that owns the allocated arrays +* +* Return: 0 for success, or -ENOMEM. */ -static int arch_domain_mbm_alloc (u32 num_rmid,struct rdt_hw_l3_mon_domain *hw_dom) +static int l3_mon_domain_mbm_alloc (u32 num_rmid,struct rdt_hw_l3_mon_domain *hw_dom) {size_t tsize =sizeof (*hw_dom->arch_mbm_states[0 ]);enum resctrl_event_id eventid;
@@ -536,7 +538,7 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) ci =get_cpu_cacheinfo_level (cpu,RESCTRL_L3_CACHE );if (!ci) {pr_warn_once ("Can't find L3 cache for CPU:%d resource %s\n" , cpu, r->name); -mon_domain_free (hw_dom); +l3_mon_domain_free (hw_dom);return ; } d->ci_id = ci->id;
@@ -548,8 +550,8 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)arch_mon_domain_online (r, d); -if (arch_domain_mbm_alloc (r->mon.num_rmid, hw_dom)) { -mon_domain_free (hw_dom); +if (l3_mon_domain_mbm_alloc (r->mon.num_rmid, hw_dom)) { +l3_mon_domain_free (hw_dom);return ; }
@@ -559,7 +561,7 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)if (err) {list_del_rcu (&d->hdr.list);synchronize_rcu (); -mon_domain_free (hw_dom); +l3_mon_domain_free (hw_dom); } }
@@ -650,7 +652,7 @@ static void domain_remove_cpu_mon(int cpu, struct rdt_resource *r)resctrl_offline_mon_domain (r, d);list_del_rcu (&d->hdr.list);synchronize_rcu (); -mon_domain_free (hw_dom); +l3_mon_domain_free (hw_dom);return ; }
@@ -897,7 +899,7 @@ static __init bool get_rdt_mon_resources(void)if (!ret)return false; -return !rdt_get_mon_l3_config (r); +return !rdt_get_l3_mon_config (r); }static __init void __check_quirks_intel (void )
arch/x86/kernel/cpu/resctrl/internal.h +1 -1
@@ -211,7 +211,7 @@ union l3_qos_abmc_cfg {void rdt_ctrl_update (void *arg); -int rdt_get_mon_l3_config (struct rdt_resource *r); +int rdt_get_l3_mon_config (struct rdt_resource *r);bool rdt_cpu_has (int flag);
arch/x86/kernel/cpu/resctrl/monitor.c +1 -1
@@ -423,7 +423,7 @@ static __init int snc_get_config(void)return ret; } -int __init rdt_get_mon_l3_config (struct rdt_resource *r) +int __init rdt_get_l3_mon_config (struct rdt_resource *r) {unsigned int mbm_offset = boot_cpu_data.x86_cache_mbm_width_offset;struct rdt_hw_resource *hw_res =resctrl_to_arch_res (r);
fs/resctrl/internal.h +3 -3
@@ -355,7 +355,9 @@ int alloc_rmid(u32 closid);void free_rmid (u32 closid,u32 rmid); -void resctrl_mon_resource_exit (void ); +int resctrl_l3_mon_resource_init (void ); + +void resctrl_l3_mon_resource_exit (void );void mon_event_count (void *info);
@@ -365,8 +367,6 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, struct rdt_l3_mon_domain *d, struct rdtgroup *rdtgrp, cpumask_t *cpumask, int evtid, int first); -int resctrl_mon_resource_init (void ); -void mbm_setup_overflow_handler (struct rdt_l3_mon_domain *dom,unsigned long delay_ms,int exclude_cpu);
fs/resctrl/monitor.c +4 -4
@@ -1758,7 +1758,7 @@ ssize_t mbm_L3_assignments_write(struct kernfs_open_file *of, char *buf, }/** -* resctrl_mon_resource_init() - Initialise global monitoring structures. +* resctrl_l3_mon_resource_init() - Initialise global monitoring structures. * * Allocate and initialise global monitor resources that do not belong to a * specific domain. i.e. the rmid_ptrs[] used for the limbo and free lists.
@@ -1767,9 +1767,9 @@ ssize_t mbm_L3_assignments_write(struct kernfs_open_file *of, char *buf,* Resctrl's cpuhp callbacks may be called before this point to bring a domain * online. * -* Returns 0 for success, or -ENOMEM. +* Return: 0 for success, or -ENOMEM. */ -int resctrl_mon_resource_init (void ) +int resctrl_l3_mon_resource_init (void ) {struct rdt_resource *r =resctrl_arch_get_resource (RDT_RESOURCE_L3 );int ret;
@@ -1819,7 +1819,7 @@ int resctrl_mon_resource_init(void)return 0 ; } -void resctrl_mon_resource_exit (void ) +void resctrl_l3_mon_resource_exit (void ) {struct rdt_resource *r =resctrl_arch_get_resource (RDT_RESOURCE_L3 );
fs/resctrl/rdtgroup.c +12 -12
@@ -4170,7 +4170,7 @@ static void rdtgroup_setup_default(void)mutex_unlock (&rdtgroup_mutex); } -static void domain_destroy_mon_state (struct rdt_l3_mon_domain *d) +static void domain_destroy_l3_mon_state (struct rdt_l3_mon_domain *d) {int idx;
@@ -4218,13 +4218,13 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_l3_mon_domaincancel_delayed_work (&d->cqm_limbo); } -domain_destroy_mon_state (d); +domain_destroy_l3_mon_state (d);mutex_unlock (&rdtgroup_mutex); }/** -* domain_setup_mon_state() - Initialise domain monitoring structures. +* domain_setup_l3_mon_state() - Initialise domain monitoring structures. * @r: The resource for the newly online domain. * @d: The newly online domain. *
@@ -4232,11 +4232,11 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_l3_mon_domain* Called when the first CPU of a domain comes online, regardless of whether * the filesystem is mounted. * During boot this may be called before global allocations have been made by -* resctrl_mon_resource_init(). +* resctrl_l3_mon_resource_init(). * -* Returns 0 for success, or -ENOMEM. +* Return: 0 for success, or -ENOMEM. */ -static int domain_setup_mon_state (struct rdt_resource *r,struct rdt_l3_mon_domain *d) +static int domain_setup_l3_mon_state (struct rdt_resource *r,struct rdt_l3_mon_domain *d) {u32 idx_limit =resctrl_arch_system_num_rmid_idx ();size_t tsize =sizeof (*d->mbm_states[0 ]);
@@ -4298,7 +4298,7 @@ int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_l3_mon_domain *mutex_lock (&rdtgroup_mutex); - err =domain_setup_mon_state (r, d); + err =domain_setup_l3_mon_state (r, d);if (err) goto out_unlock;
@@ -4413,13 +4413,13 @@ int resctrl_init(void)thread_throttle_mode_init (); - ret =resctrl_mon_resource_init (); + ret =resctrl_l3_mon_resource_init ();if (ret)return ret; ret =sysfs_create_mount_point (fs_kobj,"resctrl" );if (ret) { -resctrl_mon_resource_exit (); +resctrl_l3_mon_resource_exit ();return ret; }
@@ -4454,7 +4454,7 @@ int resctrl_init(void) cleanup_mountpoint:sysfs_remove_mount_point (fs_kobj,"resctrl" ); -resctrl_mon_resource_exit (); +resctrl_l3_mon_resource_exit ();return ret; }
@@ -4490,7 +4490,7 @@ static bool resctrl_online_domains_exist(void)* When called by the architecture code, all CPUs and resctrl domains must be * offline. This ensures the limbo and overflow handlers are not scheduled to * run, meaning the data structures they access can be freed by -* resctrl_mon_resource_exit(). +* resctrl_l3_mon_resource_exit(). * * After resctrl_exit() returns, the architecture code should return an * error from all resctrl_arch_ functions that can do this.
@@ -4517,5 +4517,5 @@ void resctrl_exit(void)* it can be used to umount resctrl. */ -resctrl_mon_resource_exit (); +resctrl_l3_mon_resource_exit (); }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/6 fs/resctrl: Move allocation/free of closid_num_dirty_rmid[]
In reply to Sasha LevinFrom: Tony Luck <[email protected]>
[ Upstream commit ee7f6af79f0916b6c49e15edd4cba020b3e4c4ac ]
closid_num_dirty_rmid[] and rmid_ptrs[] are allocated together during resctrl initialization and freed together during resctrl exit.
Telemetry events are enumerated on resctrl mount so only at resctrl mount will the number of RMID supported by all monitoring resources and needed as size for rmid_ptrs[] be known.
Separate closid_num_dirty_rmid[] and rmid_ptrs[] allocation and free in preparation for rmid_ptrs[] to be allocated on resctrl mount.
Keep the rdtgroup_mutex protection around the allocation and free of closid_num_dirty_rmid[] as ARM needs this to guarantee memory ordering.
Stable-dep-of: 52fce648607e ("fs/resctrl: Fix use-after-free during unmount")
--- fs/resctrl/monitor.c | 79 ++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 28 deletions(-)
fs/resctrl/monitor.c +51 -28
@@ -865,36 +865,14 @@ void mbm_setup_overflow_handler(struct rdt_l3_mon_domain *dom, unsigned long delstatic int dom_data_init (struct rdt_resource *r) {u32 idx_limit =resctrl_arch_system_num_rmid_idx (); -u32 num_closid =resctrl_arch_get_num_closid (r);struct rmid_entry *entry =NULL ;int err =0 , i;u32 idx;mutex_lock (&rdtgroup_mutex); -if (IS_ENABLED (CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID )) { -u32 *tmp; - -/* -* If the architecture hasn't provided a sanitised value here, -* this may result in larger arrays than necessary. Resctrl will -* use a smaller system wide value based on the resources in -* use. -*/ - tmp =kcalloc (num_closid,sizeof (*tmp),GFP_KERNEL ); -if (!tmp) { - err = -ENOMEM ; - goto out_unlock; - } - - closid_num_dirty_rmid = tmp; - } rmid_ptrs =kcalloc (idx_limit,sizeof (struct rmid_entry ),GFP_KERNEL );if (!rmid_ptrs) { -if (IS_ENABLED (CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID )) { -kfree (closid_num_dirty_rmid); - closid_num_dirty_rmid =NULL ; - } err = -ENOMEM ; goto out_unlock; }
@@ -930,11 +908,6 @@ static void dom_data_exit(struct rdt_resource *r)if (!r->mon_capable) goto out_unlock; -if (IS_ENABLED (CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID )) { -kfree (closid_num_dirty_rmid); - closid_num_dirty_rmid =NULL ; - } -kfree (rmid_ptrs); rmid_ptrs =NULL ;
@@ -1757,6 +1730,45 @@ ssize_t mbm_L3_assignments_write(struct kernfs_open_file *of, char *buf,return ret ?: nbytes; } +static int closid_num_dirty_rmid_alloc (struct rdt_resource *r) +{ +if (IS_ENABLED (CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID )) { +u32 num_closid =resctrl_arch_get_num_closid (r); +u32 *tmp; + +/* For ARM memory ordering access to closid_num_dirty_rmid */ +mutex_lock (&rdtgroup_mutex); + +/* +* If the architecture hasn't provided a sanitised value here, +* this may result in larger arrays than necessary. Resctrl will +* use a smaller system wide value based on the resources in +* use. +*/ + tmp =kcalloc (num_closid,sizeof (*tmp),GFP_KERNEL ); +if (!tmp) { +mutex_unlock (&rdtgroup_mutex); +return -ENOMEM ; + } + + closid_num_dirty_rmid = tmp; + +mutex_unlock (&rdtgroup_mutex); + } + +return 0 ; +} + +static void closid_num_dirty_rmid_free (void ) +{ +if (IS_ENABLED (CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID )) { +mutex_lock (&rdtgroup_mutex); +kfree (closid_num_dirty_rmid); + closid_num_dirty_rmid =NULL ; +mutex_unlock (&rdtgroup_mutex); + } +} +/** * resctrl_l3_mon_resource_init() - Initialise global monitoring structures. *
@@ -1777,10 +1789,16 @@ int resctrl_l3_mon_resource_init(void)if (!r->mon_capable)return 0 ; - ret =dom_data_init (r); + ret =closid_num_dirty_rmid_alloc (r);if (ret)return ret; + ret =dom_data_init (r); +if (ret) { +closid_num_dirty_rmid_free (); +return ret; + } +if (resctrl_arch_is_evt_configurable (QOS_L3_MBM_TOTAL_EVENT_ID )) { mon_event_all[QOS_L3_MBM_TOTAL_EVENT_ID ].configurable = true; resctrl_file_fflags_init("mbm_total_bytes_config",
@@ -1823,5 +1841,10 @@ void resctrl_l3_mon_resource_exit(void) {struct rdt_resource *r =resctrl_arch_get_resource (RDT_RESOURCE_L3 ); +if (!r->mon_capable) +return ; + +closid_num_dirty_rmid_free (); +dom_data_exit (r); }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/6 fs/resctrl: Move RMID initialization to first mount
In reply to Sasha LevinFrom: Tony Luck <[email protected]>
[ Upstream commit d0891647fbc6e931f27517364cbc4ee1811d76db ]
L3 monitor features are enumerated during resctrl initialization and rmid_ptrs[] that tracks all RMIDs and depends on the number of supported RMIDs is allocated during this time.
Telemetry monitor features are enumerated during first resctrl mount and may support a different number of RMIDs compared to L3 monitor features.
Delay allocation and initialization of rmid_ptrs[] until first mount. Since the number of RMIDs cannot change on later mounts, keep the same set of rmid_ptrs[] until resctrl_exit(). This is required because the limbo handler keeps running after resctrl is unmounted and needs to access rmid_ptrs[] as it keeps tracking busy RMIDs after unmount.
Rename routines to match what they now do:dom_data_init() -> setup_rmid_lru_list()dom_data_exit() -> free_rmid_lru_list()
Stable-dep-of: 52fce648607e ("fs/resctrl: Fix use-after-free during unmount")
--- fs/resctrl/internal.h | 4 ++++ fs/resctrl/monitor.c | 54 ++++++++++++++++++++----------------------- fs/resctrl/rdtgroup.c | 5 ++++ 3 files changed, 34 insertions(+), 29 deletions(-)
fs/resctrl/internal.h +4 -0
@@ -351,6 +351,10 @@ int closids_supported(void);void closid_free (int closid); +int setup_rmid_lru_list (void ); + +void free_rmid_lru_list (void ); +int alloc_rmid (u32 closid);void free_rmid (u32 closid,u32 rmid);
fs/resctrl/monitor.c +25 -29
100 lines not on this page · raw message
fs/resctrl/rdtgroup.c +5 -0
@@ -2732,6 +2732,10 @@ static int rdt_get_tree(struct fs_context *fc) goto out; } + ret =setup_rmid_lru_list (); +if (ret) + goto out; + ret =rdtgroup_setup_root (ctx);if (ret) goto out;
@@ -4518,4 +4522,5 @@ void resctrl_exit(void)*/ resctrl_l3_mon_resource_exit (); +free_rmid_lru_list (); }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 6/6 fs/resctrl: Fix use-after-free during unmount
In reply to Sasha LevinFrom: Tony Luck <[email protected]>
[ Upstream commit 52fce648607e0d6a76eeb443d78708c49df1c554 ]
During unmount or failure teardown all mon_data structures that contain monitoring event file private data are freed after which kernfs nodes are removed. However, the RDT_DELETED flag is never set for the statically allocated default resource group.
A concurrent reader of an event file associated with the default resource group may, after dropping kernfs active protection, block on rdtgroup_mutex while unmount proceeds to free the file private data and destroy the kernfs node without waiting for the reader.
When the mutex is released, the reader wakes up, observes that RDT_DELETED is not set for the default group, and dereferences the already-freed file private data.
The scenario can be depicted as follows:
CPU0 CPU1
/*
* Default resource group's
* monitoring data accessible via
* kernfs file with kernfs_node::priv
* pointing to a struct mon_data.
* User opens the file for reading.
*/
rdtgroup_mondata_show() /* arch encounters fatal error */
rdtgroup_kn_lock_live() resctrl_exit()
atomic_inc(&rdtgroup_default.waitcount) cpus_read_lock()
kernfs_break_active_protection(kn) mutex_lock(&rdtgroup_mutex)
cpus_read_lock() resctrl_fs_teardown()
mutex_lock(&rdtgroup_mutex) rmdir_all_sub()
mon_put_kn_priv()
/* Delete all mon_data structures */
rdtgroup_destroy_root()
kernfs_destroy_root()
rdtgroup_default.kn = NULL
mutex_unlock(&rdtgroup_mutex)
/*
* rdtgroup_default.flags is empty so
* rdtgroup_kn_lock_live() returns
* &rdtgroup_default
*/
md = of->kn->priv;
/* md points to freed mon_data */Set RDT_DELETED for the default group unconditionally since the flag does not lead to the freeing of this statically allocated group.
Do not allow a new resctrl mount if there are any waiters on default group of previous mount. A new mount will re-initialize the default group that would appear to waiters from previous mount as though the default group is accessible causing them to access the mon_data structures from the previous mount that have been removed.
--- fs/resctrl/rdtgroup.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
fs/resctrl/rdtgroup.c +16 -2
@@ -581,14 +581,20 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,* * On resource group creation via a mkdir, an extra kernfs_node reference is * taken to ensure that the rdtgroup structure remains accessible for the -* rdtgroup_kn_unlock() calls where it is removed. +* rdtgroup_kn_unlock() calls where it is removed. The default group is +* statically allocated: it does not have an extra reference but will have +* RDT_DELETED set on unmount to support safe access to its associated files +* via rdtgroup_kn_lock_live/rdtgroup_kn_unlock(). * -* Drop the extra reference here, then free the rdtgroup structure. +* For all but the default group: drop the extra reference, then free the +* rdtgroup structure. * * Return: void */ static void rdtgroup_remove (struct rdtgroup *rdtgrp) { +if (rdtgrp == &rdtgroup_default) +return ;kernfs_put (rdtgrp->kn);kfree (rdtgrp); }
@@ -2732,6 +2738,12 @@ static int rdt_get_tree(struct fs_context *fc) goto out; } +/* Avoid races from pending operations from a previous mount */ +if (atomic_read (&rdtgroup_default.waitcount) !=0 ) { + ret = -EBUSY ; + goto out; + } + ret =setup_rmid_lru_list ();if (ret) goto out;
@@ -3094,6 +3106,7 @@ static void resctrl_fs_teardown(void)mon_put_kn_priv ();rdt_pseudo_lock_release (); rdtgroup_default.mode =RDT_MODE_SHAREABLE ; + rdtgroup_default.flags =RDT_DELETED ;closid_exit ();schemata_list_destroy ();rdtgroup_destroy_root ();
@@ -4148,6 +4161,7 @@ static int rdtgroup_setup_root(struct rdt_fs_context *ctx) ctx->kfc.root = rdt_root; rdtgroup_default.kn =kernfs_root_to_node (rdt_root); + rdtgroup_default.flags =0 ;return 0 ; }
Signature · 1 line
2.53.0