mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Jinjie Ruan <ruanjinjie@huawei.com>
To: Reinette Chatre <reinette.chatre@intel.com>,
	<tony.luck@intel.com>, <Dave.Martin@arm.com>,
	<james.morse@arm.com>, <babu.moger@amd.com>, <bp@alien8.de>,
	<tan.shaopeng@fujitsu.com>, <zengheng4@huawei.com>,
	<gshan@redhat.com>, <jic23@kernel.org>, <ben.horgan@arm.com>,
	<x86@kernel.org>, <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v4 3/3] fs/resctrl: Unmount resctrl with the CDP state it was mounted with
Date: Mon, 9 Nov 2026 19:48:53 +0800	[thread overview]
Message-ID: <dc148861-35cc-4029-835e-2e93c8b64f05@huawei.com> (raw)
In-Reply-To: <7163c46a-2abf-42d2-842a-8a43dafecaa3@intel.com>



在 2026/11/7 6:52, Reinette Chatre 写道:
> Hi Jinjie,

Hi Reinette,

> 
> On 11/4/26 11:09 PM, Jinjie Ruan wrote:
>> resctrl can be mounted without CDP, unmounted, and mounted again with
>> CDP enabled. A group's RMID is not returned to the free list when the
>> group is removed: it stays in limbo until the cache lines tagged with it
>> are evicted, and a limbo worker reads its occupancy counter in the
>> meantime. When resctrl is mounted again, the worker reads the RMIDs of
>> the groups removed by the unmount.
>>
>> On MPAM the counter is selected by the PARTID of the CLOSID that owned
>> the RMID. Without CDP, CLOSID c is PARTID c; with CDP it is PARTIDs 2c
>> and 2c+1. resctrl_unmount() clears the CDP state before it removes the
>> groups, so their monitor configuration is also removed with a different
>> CLOSID to PARTID mapping. With 5 PARTIDs:
>>
>>   mount                  CDP off, CLOSID c -> PARTID c
>>   mkdir g1..g4           CLOSIDs 1..4
>>   umount
>>     rdt_disable_ctx()    clear CDP
>>     remove g1..g4        RMIDs enter limbo with CLOSIDs 1..4
>>   mount -o cdp           CDP on, CLOSID c -> PARTIDs 2c, 2c+1
>>   limbo worker           reads CLOSID 2 as PARTID 5 > PARTID_MAX 4
>>                          MSC error interrupt, mpam_disable()
> 
> As I understand this issue goes both ways. If resctrl is first mounted

Right! it also have the same problem.

> with CDP the issue may even be worse since there is no error interrupt that
> draws attention to the problem that the wrong (albeit in range) RMID entries

Yes, there is no error irq.

> are tested. In such opposite scenario CDP is disabled on unmount causing
> the limbo handler that keeps running to immediately use the wrong index
> before resctrl is mounted again.

I agree.

> 
>>
>> The groups are removed after rdt_disable_ctx() clears CDP, so their
>> monitor configuration is cleared with a CLOSID to PARTID mapping that
>> differs from the one used to set it up.
> 
> hmmm .. this paragraph seems out of place after the limbo handler introduction.
> This looks to be a (very) high level description of counter reconfiguration done
> on unmount where MPAM also needs to translate a CLOSID into PARTID. This brief snippet
> seems to be what is connected to the patch subject, not the limbo handler, and
> describes the portion of the patch that moves rdt_disable_ctx() to be after
> resctrl_fs_teardown()? 

Yes, it does.

> 
> As I see it it the move of rdt_disable_ctx() has nothing to do with the limbo handler.
> In the spirit of separating logical changes, could you please separate this fix into
> its own patch? 

Will put it in a seperate patch, thank you!

> 
>>
>> Clear the CDP state after the groups are removed. While resctrl is
>> unmounted, don't read the RMIDs in limbo. When resctrl is mounted,
>> return the RMIDs freed under the other CDP state to the free list
>> without reading their counters, then restart the limbo worker unless it
>> is already queued. The RMIDs stay in limbo across the unmount so that a
>> quick remount does not give a new group an RMID that cache lines from
>> the removed group still carry.
>>
>> Only MPAM with CDP enabled through the cdp or cdpl2 mount option is
> 
> It is unexpected that a mount with cdpl2 impacts the limbo handler that
> only taked the L3 resource into account. (more later)
> 
>> affected; CDP depends on CONFIG_EXPERT. x86 is not affected as its RMID
>> does not depend on the CLOSID.
>>
>> Reproduced on QEMU with the sequence above:
>>
>> 	mpam:__mpam_irq_handler: error irq from msc:1 'MSMONCFG_ID_RANGE', partid:5, pmg: 0, ris: 0
>> 	mpam:mpam_disable: MPAM disabled due to hardware error interrupt
>>
>> With the change the sequence completes without an error.
>>
> 
> ...> ---
>>  fs/resctrl/internal.h |  1 +
>>  fs/resctrl/monitor.c  | 71 ++++++++++++++++++++++++++++++++++++++-----
>>  fs/resctrl/rdtgroup.c |  7 +++--
>>  3 files changed, 70 insertions(+), 9 deletions(-)
>>
>> diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
>> index 1c85e06f09bf..c95fa6ce62e6 100644
>> --- a/fs/resctrl/internal.h
>> +++ b/fs/resctrl/internal.h
>> @@ -373,6 +373,7 @@ void closid_free(int closid);
>>  int setup_rmid_lru_list(void);
>>  
>>  void free_rmid_lru_list(void);
>> +void resctrl_limbo_resume(void);
>>  
>>  int alloc_rmid(u32 closid);
>>  
>> diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
>> index ae9ddd380515..717c3888c2b5 100644
>> --- a/fs/resctrl/monitor.c
>> +++ b/fs/resctrl/monitor.c
>> @@ -70,6 +70,11 @@ static u32 *closid_num_dirty_rmid;
>>   */
>>  static unsigned int rmid_limbo_count;
>>  
>> +/*
>> + * @limbo_cdp - The CDP state under which the RMIDs in limbo were freed.
>> + */
>> +static bool limbo_cdp;
> 
> The variable is described as "The CDP state ..." but its type is a boolean.
> What does "true" mean? Could this be renamed limbo_cdp_enabled?
> 
> Looks like this is only set if CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID is set,
> please mention that in the comments.
> 
>> +
>>  /*
>>   * @rmid_entry - The entry in the limbo and free lists.
>>   */
>> @@ -852,6 +857,10 @@ void cqm_handle_limbo(struct work_struct *work)
>>  	 */
>>  	mutex_lock(&rdtgroup_mutex);
>>  
>> +	/* Don't read the RMIDs in limbo until a mount sets up the CDP state. */
>> +	if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID) && !resctrl_mounted)
>> +		goto out_unlock;
>> +
> 
> Is this IS_ENABLED() check needed? There are several flows managing the limbo handler
> yet just cqm_handle_limbo() and resctrl_limbo_resume() use this IS_ENABLED() check to manage
> the lifecycle in a unique way that I am concerned will trip people up in the future when
> trying to untangle the limbo worker lifecycle.
> 
> I understand that the IS_ENABLED() check is added to support MPAM specifically here but
> I think we should aim for as much as possible similar behavior across all architectures.

Yes, it is for mpam.

> To that end I do not see why limbo handler should not run on MPAM when resctrl fs is unmounted
> while on x86 it should. 

Is it because the CDP implementation of x86 is different from MPAM, and
MPAM is implemented through simulation?

> 
> Having the limbo handler only depend on resctrl_mounted here will make the behavior consistent
> across architectures while also matching the overflow handler. Keeping these behaviors similar
> just makes the code easier to understand and reason about. Having resctrl filesystem provide
> consistent flows across all architectures ensures the same flows are always tested.
> 
> Yes, x86 would lose the ability to drain RMIDs across an unmount, but nothing needs these
> RMIDs while resctrl is unmounted. This work ensures that the RMIDs are freed shortly
> after a mount when they will be needed.

I believe this behavior is also universal for x86.

> 
> Could you please separate out a patch that _only_ changes the limbo handler lifetime
> independent of architecture? This patch can introduce resctrl_limbo_resume() but not release

Will put it in a seperate patch, thank you!

> any RMIDs from it. Splitting the limbo worker lifecycle change that impacts both
> architectures from the MPAM specific change that releases RMIDs on mount would make
> the impact easier to describe to reviewers.
> 
>>  	/*
>>  	 * Ensure the worker is dedicated to a CPU as intended and not
>>  	 * relocated by workqueue subsystem as part of CPU going offline.
>> @@ -868,10 +877,12 @@ void cqm_handle_limbo(struct work_struct *work)
>>  	__check_limbo(d);
>>  
>>  	if (has_busy_rmid(d)) {
>> -		d->cqm_work_cpu = cpumask_any_housekeeping(&d->hdr.cpu_mask,
>> -							   RESCTRL_PICK_ANY_CPU);
>> -		schedule_delayed_work_on(d->cqm_work_cpu, &d->cqm_limbo,
>> -					 delay);
>> +		int cpu;
>> +
>> +		cpu = cpumask_any_housekeeping(&d->hdr.cpu_mask,
>> +					       RESCTRL_PICK_ANY_CPU);
>> +		if (schedule_delayed_work_on(cpu, &d->cqm_limbo, delay))
>> +			d->cqm_work_cpu = cpu;
>>  	}
>>  
>>  out_unlock:
>> @@ -893,10 +904,13 @@ void cqm_setup_limbo_handler(struct rdt_l3_mon_domain *dom, unsigned long delay_
>>  	int cpu;
>>  
>>  	cpu = cpumask_any_housekeeping(&dom->hdr.cpu_mask, exclude_cpu);
>> -	dom->cqm_work_cpu = cpu;
>> +	if (cpu >= nr_cpu_ids) {
>> +		dom->cqm_work_cpu = cpu;
>> +		return;
>> +	}
>>  
>> -	if (cpu < nr_cpu_ids)
>> -		schedule_delayed_work_on(cpu, &dom->cqm_limbo, delay);
>> +	if (schedule_delayed_work_on(cpu, &dom->cqm_limbo, delay))
>> +		dom->cqm_work_cpu = cpu;
>>  }
> 
> hmmm ... this cqm_work_cpu wrangling is a concern and surely looks like something that
> we will trip over later. Making it worse is that there is no justification or explanation
> for why this is needed. I *assume* that it is done with anticipation that
> schedule_delayed_work_on() may fail since limbo handler is already pending, but please

Yes, that it the reason.

> also keep in mind that the worker my already be running and blocked on rdtgroup_mutex.
> We just had to fix a similar issues in this area recently so I would like to avoid any new
> issues here.
> 
> Looks like sashiko also uncovered a few issues in this area:
> 	https://sashiko.dev/#/patchset/20261105070934.2258613-1-ruanjinjie%40huawei.com
> 
> Could this implementation not instead just ensure that the worker is not pending and then
> the above two hunks can be dropped? (more later)
> 
>>  
>>  void mbm_handle_overflow(struct work_struct *work)
>> @@ -1033,6 +1047,49 @@ int setup_rmid_lru_list(void)
>>  	return 0;
>>  }
>>  
>> +/**
>> + * resctrl_limbo_resume() - Resume RMID limbo handling after a mount.
>> + *
>> + * Release the RMIDs that were freed under another CDP state without
>> + * reading them, and restart the limbo handler.
>> + */
>> +void resctrl_limbo_resume(void)
>> +{
>> +	struct rdt_l3_mon_domain *d;
>> +	struct rdt_resource *r;
>> +	bool cdp;
>> +
>> +	if (!IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID) ||
> 
> Please drop this check from the core limbo handler resume code that
> should be done for all architectures. Instead just use it to gate whether
> release_limbo_rmids() is called or not.

OK.

> 
>> +	    !resctrl_arch_mon_capable())
>> +		return;
>> +
>> +	lockdep_assert_held(&rdtgroup_mutex);
> 
> Please move to beginning of function. How about lockdep_assert_cpus_held()?

OK.

> 
>> +
>> +	r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
>> +
>> +	cdp = resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L2) ||
>> +	      resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L3);
> 
> This is unexpected and looks to be leaking an MPAM quirk into
> the filesystem? I see there is a global "cdp_enabled" that guides
> MPAM internals but on the filesystem side it does not look right for
> the L2 CDP state to impact the limbo handler that only operates on
> L3 resource.

I will recheck this logic, Thank you!

> 
>> +
>> +	if (cdp != limbo_cdp) {
>> +		list_for_each_entry_rcu(d, &r->mon_domains, hdr.list,
>> +					lockdep_is_cpus_held()) {
>> +			if (d->rmid_busy_llc && has_busy_rmid(d))
> 
> How about calling cancel_delayed_work(&d->cqm_limbo) here? Could doing
> so eliminate the need for all that cqm_work_cpu wrangling?

Make sense, so we need not check whether it is running later.

> 
>> +				release_limbo_rmids(d);
>> +		}
>> +	}
>> +	limbo_cdp = cdp;
>> +
>> +	if (!resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID))
>> +		return;
> 
> Could this be moved to the top of the function? QOS_L3_OCCUP_EVENT_ID
> state cannot change between mounts and this is the event that determines
> whether limbo handler runs at all. Moving this check would also eliminate the 
> need for the "d->rmid_busy_llc" check above.

But limbo_cdp must be updated for next time check.

> 
>> +
>> +	list_for_each_entry_rcu(d, &r->mon_domains, hdr.list,
>> +				lockdep_is_cpus_held()) {
>> +		/* A queued worker will run, don't move its cqm_work_cpu. */
>> +		if (has_busy_rmid(d) && !delayed_work_pending(&d->cqm_limbo))
>> +			cqm_setup_limbo_handler(d, 0, RESCTRL_PICK_ANY_CPU);
>> +	}
>> +}
>> +
>>  void free_rmid_lru_list(void)
>>  {
>>  	if (!resctrl_arch_mon_capable())
>> diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
>> index 5d0351453c2f..e6b64a5c9302 100644
>> --- a/fs/resctrl/rdtgroup.c
>> +++ b/fs/resctrl/rdtgroup.c
>> @@ -3150,13 +3150,14 @@ static void resctrl_unmount(void)
>>  	cpus_read_lock();
>>  	mutex_lock(&rdtgroup_mutex);
>>  
>> -	rdt_disable_ctx();
>> -
>>  	/* Put everything back to default values. */
>>  	for_each_alloc_capable_rdt_resource(r)
>>  		resctrl_arch_reset_all_ctrls(r);
>>  
>>  	resctrl_fs_teardown();
>> +
>> +	/* Remove the groups under the CDP state they were set up with. */
> 
> This comment looks out of place as it documents what happens _before_
> rdt_disable_ctx(). It also only refers to removal of group while I believe

It should be moved before resctrl_fs_teardown().

> (when looking an MPAM's __config_cntr()) there is an issue with counter reset 
> also?
> 
> How about something like:
> 
> 	Clear the CDP state after the cleanup. The CDP state decides
> 	which hardware configuration a CLOSID refers to, so the teardown
> 	must run with the state the configuration was created under.

It looks a bit more complete, will update the comment as it.

> 
>> +	rdt_disable_ctx();
>>  	if (resctrl_arch_alloc_capable())
>>  		resctrl_arch_disable_alloc();
>>  	if (resctrl_arch_mon_capable())
>> @@ -3261,6 +3262,8 @@ static int rdt_get_tree(struct fs_context *fc)
>>  						   RESCTRL_PICK_ANY_CPU);
>>  	}
>>  
>> +	resctrl_limbo_resume();
>> +
>>  	/*
>>  	 * Ensure root remains accessible after mutex is unlocked so that
>>  	 * kernfs_kill_sb() can run safely if called by kernfs_get_tree()'s
> 
> Reinette

-- 
Best regards,
Jinjie


      reply	other threads:[~2026-11-09 11:48 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05  7:09 [PATCH v4 0/3] fs/resctrl: Fix RMID limbo handling Jinjie Ruan
2026-11-05  7:09 ` [PATCH v4 1/3] fs/resctrl: Report a temporary RMID shortage per CLOSID Jinjie Ruan
2026-11-05 11:26   ` Ben Horgan
2026-11-05  7:09 ` [PATCH v4 2/3] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
2026-11-05  7:09 ` [PATCH v4 3/3] fs/resctrl: Unmount resctrl with the CDP state it was mounted with Jinjie Ruan
2026-11-06 22:52   ` Reinette Chatre
2026-11-09 11:48     ` Jinjie Ruan [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=dc148861-35cc-4029-835e-2e93c8b64f05@huawei.com \
    --to=ruanjinjie@huawei.com \
    --cc=Dave.Martin@arm.com \
    --cc=babu.moger@amd.com \
    --cc=ben.horgan@arm.com \
    --cc=bp@alien8.de \
    --cc=gshan@redhat.com \
    --cc=james.morse@arm.com \
    --cc=jic23@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=reinette.chatre@intel.com \
    --cc=tan.shaopeng@fujitsu.com \
    --cc=tony.luck@intel.com \
    --cc=x86@kernel.org \
    --cc=zengheng4@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®