Linux Documentation
 help / color / mirror / Atom feed
* Re: [PATCH 5/5] types: Add standard __ob_trap and __ob_wrap scalar types
From: Kees Cook @ 2026-04-01 20:23 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Linus Torvalds, Justin Stitt, Miguel Ojeda, Nathan Chancellor,
	Andrew Morton, Andy Shevchenko, Arnd Bergmann, Mark Rutland,
	Matthew Wilcox (Oracle), Suren Baghdasaryan, Thomas Gleixner,
	Finn Thain, Geert Uytterhoeven, Thomas Weißschuh, llvm,
	Marco Elver, Jonathan Corbet, Nicolas Schier, Greg Kroah-Hartman,
	linux-kernel, kasan-dev, linux-hardening, linux-doc, linux-kbuild
In-Reply-To: <20260401085706.GU3738786@noisy.programming.kicks-ass.net>

On Wed, Apr 01, 2026 at 10:57:06AM +0200, Peter Zijlstra wrote:
> On Tue, Mar 31, 2026 at 01:31:16PM -0700, Kees Cook wrote:
> 
> > int func()
> > {
> > 	...
> > 	u8 __ob_trap product = 5;
> > 	...
> > 	product = a * b; // if store is truncated, goto __overflow
> > 	...
> > 	return product;
> > 
> > __overflow:
> > 	pr_info("%u\n", product); // shows "5"
> 
> I'm confused by this 'product is still 5' thing. It seems to me that
> making this happen will, in general, require more instructions/registers
> than allowing the old value to be clobbered and have product be the
> truncated result of whatever overflow.

Yeah, that's fair. That's what happens to "out" already with the existing
check_{op}_overflow(a, b, &out) builtins, and what happens right now
with the "while (var--)" exception (var will wrap even as an __ob_trap).

-- 
Kees Cook

^ permalink raw reply

* Re: [PATCH 3/5] compiler_attributes: Add overflow_behavior macros __ob_trap and __ob_wrap
From: Kees Cook @ 2026-04-01 20:21 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Justin Stitt, Miguel Ojeda, Marco Elver, Andrey Konovalov,
	Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda,
	Nathan Chancellor, kasan-dev, linux-doc, llvm, Linus Torvalds,
	Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton,
	linux-kernel, linux-hardening, linux-kbuild
In-Reply-To: <20260401090815.GV3738786@noisy.programming.kicks-ass.net>

On Wed, Apr 01, 2026 at 11:08:15AM +0200, Peter Zijlstra wrote:
> On Tue, Mar 31, 2026 at 12:52:10PM -0700, Kees Cook wrote:
> 
> > I think for this series, __ob_trap/__ob_wrap is what should be used.
> > 
> > And for other folks, the background here is that we originally wanted
> > to use macros for "__trap" and "__wrap", but the powerpc C compiler
> > (both Clang and GCC) have a builtin macro named "__trap" already. So
> > I switched to just using the Clang-native type qualifier. We can use
> > the attribute style too, but there was a lot of confusion during the
> > Clang development phases where people kept forgetting this was a type
> > qualifier, not an attribute (i.e. the attribute is an internal alias
> > for the qualifier, and the qualifier is a new type).
> 
> Since you mention qualifiers...
> 
> What is the result of __typeof_unqual__(int __ob_trap) ?

Hmm, it seems like "const" doesn't get peeled off. That can be fixed, if
that's needed?

'typeof_unqual(int)' (aka 'int')
'typeof_unqual(__ob_trap int)' (aka '__ob_trap int')
'typeof_unqual(const int)' (aka 'int')
'typeof_unqual(__ob_trap const int)' (aka '__ob_trap const int')

-Kees

-- 
Kees Cook

^ permalink raw reply

* Re: [PATCH v5] PCI: s390: Expose the UID as an arch specific PCI slot attribute
From: Randy Dunlap @ 2026-04-01 20:20 UTC (permalink / raw)
  To: Niklas Schnelle, Bjorn Helgaas, Jonathan Corbet, Lukas Wunner,
	Shuah Khan
  Cc: Alexander Gordeev, Christian Borntraeger, Gerald Schaefer,
	Gerd Bayer, Heiko Carstens, Julian Ruess, Matthew Rosato,
	Peter Oberparleiter, Ramesh Errabolu, Sven Schnelle,
	Vasily Gorbik, linux-doc, linux-kernel, linux-pci, linux-s390
In-Reply-To: <20260401-uid_slot-v5-1-e73036c74bf6@linux.ibm.com>



On 4/1/26 7:50 AM, Niklas Schnelle wrote:
> On s390, an individual PCI function can generally be identified by two
> identifiers, the FID and the UID. Which identifier is used depends on
> the scope and the platform configuration.
> 
> The first identifier, the FID, is always available and identifies a PCI
> device uniquely within a machine. The FID may be virtualized by
> hypervisors, but on the LPAR level, the machine scope makes it
> impossible to create the same configuration based on FIDs on two
> different LPARs of the same machine, and difficult to reuse across
> machines.
> 
> Such matching LPAR configurations are useful, though, allowing
> standardized setups and booting a Linux installation on different LPARs.
> To this end the UID, or user-defined identifier, was introduced. While
> it is only guaranteed to be unique within an LPAR and only if indicated
> by firmware, it allows users to replicate PCI device setups.
> 
> On s390, which uses a machine hypervisor, a per PCI function hotplug
> model is used. The shortcoming with the UID then is, that it is not
> visible to the user without first attaching the PCI function and
> accessing the "uid" device attribute. The FID, on the other hand, is
> used as the slot name and is thus known even with the PCI function in
> standby.
> 
> Remedy this shortcoming by providing the UID as an attribute on the slot
> allowing the user to identify a PCI function based on the UID without
> having to first attach it. Do this via a macro mechanism analogous to
> what was introduced by commit 265baca69a07 ("s390/pci: Stop usurping
> pdev->dev.groups") for the PCI device attributes.
> 
> Reviewed-by: Gerd Bayer <gbayer@linux.ibm.com>
> Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
> Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
> ---
> Note: I considered adding the UID as a generic slot index attribute
> analogous to the PCI device index attribute (SMBIOS index / s390 UID)
> but decided against it as this seems rather s390 specific.
> 
> v4->v5:
> - Rebase on v7.0-rc6
> - Reworded note
> - Add documentation for the new attribute
> - Link to v4: https://lore.kernel.org/r/20251217-uid_slot-v4-1-559ceb59ba69@linux.ibm.com
> 
> v3->v4:
> - Rebase on v6.19-rc1
> - Collect R-bs
> - Link to v3: https://lore.kernel.org/r/20251015-uid_slot-v3-1-44389895c1bb@linux.ibm.com
> ---
> 
> ---
>  Documentation/arch/s390/pci.rst |  7 +++++++
>  arch/s390/include/asm/pci.h     |  4 ++++
>  arch/s390/pci/pci_sysfs.c       | 20 ++++++++++++++++++++
>  drivers/pci/slot.c              | 13 ++++++++++++-
>  4 files changed, 43 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/arch/s390/pci.rst b/Documentation/arch/s390/pci.rst
> index d5755484d8e75c7bf67a350e61bbe04f0452a2fa..03afb57ece4df90a75597cb34c1f048c2e162b67 100644
> --- a/Documentation/arch/s390/pci.rst
> +++ b/Documentation/arch/s390/pci.rst
> @@ -55,6 +55,13 @@ Entries specific to zPCI functions and entries that hold zPCI information.
>  
>    - /sys/bus/pci/slots/XXXXXXXX/power
>  
> +  In addition to using the FID as the name of the slot the slot directory
> +  also contains the following s390 specific slot attributes

                                 s390-specific

Use a period (full stop, '.') at the end of the sentence above.

> +
> +  - uid
> +    The User-defined identifier (UID) of the function which may be configured
> +    by this slot. See also the corresponding attribute of the device.

These 3 lines are run together in html output. Maybe add a ':' or '-' after
uid?

> +>    A physical function that currently supports a virtual function cannot be
>    powered off until all virtual functions are removed with:
>    echo 0 > /sys/bus/pci/devices/XXXX:XX:XX.X/sriov_numvf


-- 
~Randy


^ permalink raw reply

* Re: [PATCH net-next V9 02/14] devlink: Add helpers to lock nested-in instances
From: Jacob Keller @ 2026-04-01 20:18 UTC (permalink / raw)
  To: Cosmin Ratiu, Tariq Toukan, kuba@kernel.org
  Cc: allison.henderson@oracle.com, jiri@resnulli.us, Moshe Shemesh,
	davem@davemloft.net, daniel.zahka@gmail.com,
	donald.hunter@gmail.com, netdev@vger.kernel.org,
	matttbe@kernel.org, pabeni@redhat.com, horms@kernel.org,
	Parav Pandit, corbet@lwn.net, razor@blackwall.org, Dragos Tatulea,
	linux-kernel@vger.kernel.org, willemb@google.com, Jiri Pirko,
	Adithya Jayachandran, Dan Jurgens, leon@kernel.org,
	kees@kernel.org, vadim.fedorenko@linux.dev, Saeed Mahameed,
	shuah@kernel.org, andrew+netdev@lunn.ch, Mark Bloch,
	Shahar Shitrit, Carolina Jubran, Nimrod Oren,
	daniel@iogearbox.net, minhquangbui99@gmail.com, dw@davidwei.uk,
	skhan@linuxfoundation.org, Petr Machata, edumazet@google.com,
	antonio@openvpn.net, mst@redhat.com,
	linux-kselftest@vger.kernel.org, linux-rdma@vger.kernel.org,
	Shay Drori, sdf@fomichev.me, chuck.lever@oracle.com, Gal Pressman,
	joe@dama.to, linux-doc@vger.kernel.org
In-Reply-To: <4fcbf36799b5bfd5c0b68b0127f4f67aef00fdde.camel@nvidia.com>

On 4/1/2026 3:22 AM, Cosmin Ratiu wrote:
> On Tue, 2026-03-31 at 16:55 -0700, Jacob Keller wrote:
>> On 3/31/2026 5:20 AM, Cosmin Ratiu wrote:
>>> On Mon, 2026-03-30 at 19:08 -0700, Jakub Kicinski wrote:
>>>> This is an AI-generated review of your patch. The human sending
>>>> this
>>>> email has considered the AI review valid, or at least plausible.
>>>> ---
>>>> devlink: Add helpers to lock nested-in instances
>>>>
>>>> Upcoming code will need to obtain a reference to locked nested-in
>>>> devlink instances. Add helpers to lock, obtain an already locked
>>>> reference and unlock/unref the nested-in instance.
>>>>
>>>>> diff --git a/net/devlink/core.c b/net/devlink/core.c
>>>>> index eeb6a71f5f56e..db11248df7120 100644
>>>>> --- a/net/devlink/core.c
>>>>> +++ b/net/devlink/core.c
>>>>
>>>> [ ... ]
>>>>
>>>>> +/* Returns the nested in devlink object and validates its lock
>>>>> is
>>>>> held. */
>>>>> +struct devlink *devlink_nested_in_get_locked(struct
>>>>> devlink_rel
>>>>> *rel)
>>>>> +{
>>>>> +	struct devlink *devlink;
>>>>> +	unsigned long index;
>>>>> +
>>>>> +	if (!rel)
>>>>> +		return NULL;
>>>>> +	index = rel->nested_in.devlink_index;
>>>>> +	devlink = xa_find(&devlinks, &index, index,
>>>>> DEVLINK_REGISTERED);
>>>>> +	if (devlink)
>>>>> +		devl_assert_locked(devlink);
>>>>
>>>> Can this dereference a freed pointer if the lock is not actually
>>>> held?
>>>>
>>>> xa_find() acquires and releases the RCU read lock internally.
>>>> When it
>>>> returns,
>>>> the devlink pointer is no longer protected by RCU or a reference
>>>> count.
>>>>
>>>> If a caller invokes this helper without holding the devlink lock
>>>> (which is the
>>>> exact scenario the assertion is designed to detect), another
>>>> thread
>>>> could
>>>> concurrently unregister and free the devlink.
>>>>
>>>> If the RCU grace period expires before the assertion executes,
>>>> devl_assert_locked() would dereference freed memory. Should the
>>>> lookup and
>>>> assertion be enclosed within an explicit rcu_read_lock() block to
>>>> safely
>>>> assert the lock?
>>>
>>> This function is meant to be invoked by callers already holding all
>>> locks from a given instance up the nesting tree. Calling it outside
>>> this context could indeed lead to a race as described, where
>>> another
>>> entity unregisters a devlink about-to-be-asserted on.
>>>
>>
>> Hmm. I'm struggling to follow this. If you already expect the parent
>> to
>> hold the nested devlink's lock, it must have a pointer to this
>> devlink
>> instance. In that case, why would you even need
>> devlink_nested_in_get_locked in the first place?
> 
> After some more intense staring, I realized that intermediate instances
> don't actually need to be locked, only the ancestor needs to. With that
> in mind, the code get simplified:
> - devlink_nested_in_get_locked and devlink_nested_in_put_unlock can be
> removed.
> - recursive unlocking in devl_rate_unlock is gone.
> 
That seems like it would be better, as long as we can prove correctness
of every access. Thanks!

-Jake

^ permalink raw reply

* [linux-next:master 1471/11049] htmldocs: Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
From: kernel test robot @ 2026-04-01 20:14 UTC (permalink / raw)
  To: Svyatoslav Ryhel; +Cc: oe-kbuild-all, Mark Brown, Rob Herring (Arm), linux-doc

Hi Svyatoslav,

FYI, the error/warning still remains.

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
head:   bd0f139e5fc11182777b81cefc3893ea508544ec
commit: 5a8ffc5dca9c096fe9c8879fa3a2faff723fbb8a [1471/11049] regulator: dt-bindings: cpcap-regulator: convert to DT schema
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
docutils: docutils (Docutils 0.21.2, Python 3.13.5, on linux)
reproduce: (https://download.01.org/0day-ci/archive/20260401/202604012234.rkuyW7h8-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604012234.rkuyW7h8-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
   Warning: Documentation/devicetree/bindings/mfd/motorola-cpcap.txt references a file that doesn't exist: Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
>> Warning: Documentation/devicetree/bindings/regulator/motorola,cpcap-regulator.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
   Warning: Documentation/devicetree/bindings/regulator/siliconmitus,sm5703-regulator.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/siliconmitus,sm5703.yaml
   Warning: Documentation/devicetree/bindings/rtc/motorola,cpcap-rtc.yaml references a file that doesn't exist: Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
   Warning: Documentation/doc-guide/parse-headers.rst references a file that doesn't exist: Documentation/userspace-api/media/Makefile
   Warning: Documentation/leds/leds-lp5812.rst references a file that doesn't exist: Documentation/ABI/testing/sysfs-class-led-multicolor.rst
   Warning: Documentation/translations/it_IT/doc-guide/parse-headers.rst references a file that doesn't exist: Documentation/userspace-api/media/Makefile

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH 3/5] compiler_attributes: Add overflow_behavior macros __ob_trap and __ob_wrap
From: Kees Cook @ 2026-04-01 19:43 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Vincent Mailhol, Justin Stitt, Marco Elver, Andrey Konovalov,
	Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda,
	Nathan Chancellor, kasan-dev, linux-doc, llvm, Linus Torvalds,
	Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton,
	linux-kernel, linux-hardening, linux-kbuild
In-Reply-To: <20260401092027.GW3738786@noisy.programming.kicks-ass.net>

On Wed, Apr 01, 2026 at 11:20:27AM +0200, Peter Zijlstra wrote:
> On Wed, Apr 01, 2026 at 09:19:51AM +0200, Vincent Mailhol wrote:
> > Le 31/03/2026 à 18:37, Kees Cook a écrit :
> 
> > > +  - Saturate (explicitly hold the maximum or minimum representable value)
> > 
> > I just wanted to ask how much consideration was put into this last
> > "saturate" option.
> > 
> > When speaking of "safe" as in "functional safety" this seems a good
> > option to me. The best option is of course proper handling, but as
> > discussed, we are speaking of the scenario in which the code is already
> > buggy and which is the fallout option doing the least damage.
> > 
> > What I have in mind is a new __ob_saturate type qualifier. Something like:
> > 
> > 	void foo(int num)
> > 	{
> > 		int __ob_saturate saturate_var = num;
> > 	
> > 		saturate_var += 42;
> > 	}
> > 
> > would just print a warning and continue execution, thus solving the
> > trapping issue. The above code would generate something equivalent to that:
> > 
> > 	void foo(int num)
> > 	{
> > 		int __ob_saturate saturate_var = num;
> > 	
> > 		if (check_add_overflow(saturate_var, increment,
> > 				       &saturate_var) {
> > 			WARN(true, "saturation occurred");
> > 			saturate_var = type_max(saturate_var);
> > 	}
> 
> So I would like to second this option as being interesting.
> 
> But while pondering it, I did want to note that all of the options, with
> the exception of __ob_wrap (which is effectively what we have today for
> *everything*), will be 'interesting' to compose with _Atomic, another
> one of these qualifiers.
> 
> Now, in the kernel we don't use _Atomic, so strictly speaking I don't
> care ;-) But here goes...
> 
> Something like _Atomic int __ob_wrap, is trivial and good.
> 
> _Atomic int __ob_trap is either doable or impossible depending on how
> you define the result to be on 'trap'. Specifically, the semantics
> proposed where it keeps the old value makes it impossible.
> 
> And _Atomic int __ob_saturate is equally 'challenging', since the
> fundamental thing of 'reset to min/max on under/over-flow' is rather
> a non-atomic kind of thing. Look at the trouble we went through with
> refcount_t to sort of make this work.

Yeah, this is mainly why we didn't spend time working on an
__ob_saturate implementation: the primary place we want it in Linux is
already solved with all the refcount_t work. That said, if the behavior
could be replicated using a future __ob_saturate, that would be very
nice. :)

-- 
Kees Cook

^ permalink raw reply

* Re: [PATCH 3/5] compiler_attributes: Add overflow_behavior macros __ob_trap and __ob_wrap
From: Kees Cook @ 2026-04-01 19:42 UTC (permalink / raw)
  To: Vincent Mailhol
  Cc: Peter Zijlstra, Justin Stitt, Marco Elver, Andrey Konovalov,
	Andrey Ryabinin, Jonathan Corbet, Shuah Khan, Miguel Ojeda,
	Nathan Chancellor, kasan-dev, linux-doc, llvm, Linus Torvalds,
	Nicolas Schier, Arnd Bergmann, Greg Kroah-Hartman, Andrew Morton,
	linux-kernel, linux-hardening, linux-kbuild
In-Reply-To: <bd0a4235-a7f0-4624-802c-aa49a9d13f29@kernel.org>

On Wed, Apr 01, 2026 at 09:19:51AM +0200, Vincent Mailhol wrote:
> Many thanks for this series. Great work and I am ready it with a lot of
> interest!

Yay! Glad to have folks looking at it all.

> I just wanted to ask how much consideration was put into this last
> "saturate" option.
> 
> When speaking of "safe" as in "functional safety" this seems a good
> option to me. The best option is of course proper handling, but as
> discussed, we are speaking of the scenario in which the code is already
> buggy and which is the fallout option doing the least damage.

Right -- harm reduction. :)

> What I have in mind is a new __ob_saturate type qualifier. Something like:
> 
> 	void foo(int num)
> 	{
> 		int __ob_saturate saturate_var = num;
> 	
> 		saturate_var += 42;
> 	}
> 
> would just print a warning and continue execution, thus solving the
> trapping issue. The above code would generate something equivalent to that:
> 
> 	void foo(int num)
> 	{
> 		int __ob_saturate saturate_var = num;
> 	
> 		if (check_add_overflow(saturate_var, increment,
> 				       &saturate_var) {
> 			WARN(true, "saturation occurred");
> 			saturate_var = type_max(saturate_var);
> 	}

Right, yes. Note that __ob_saturate is entirely unimplemented, but we
wanted to leave the door open for other Overflow Behaviors. (It was
tricky enough to even get the semantics worked out from wrap and trap,
so we wanted to get to a distinct first step landed first.)

For the "warn" part with __ob_trap, we borrowed the Sanitizer
infrastructure since architecturally it's in exactly the same places
that __ob_trap needs to be checking, and already has everything
available. In the case of __ob_saturate, it would only be informational.
(Arguably, there should be no "warn" at all, as it's the "expected"
behavior, just like __ob_wrap has no "warn" on wrap-around. But it seems
sensible to me to make that available by enabling the sanitizers too.)

> People using those saturating integers could then later check that the
> value is still in bound.
> 
> This is basically what your size_add() from overflow.h is already doing.
> If an overflow occurred, the allocation the addition does not trap, it
> just saturates and let the allocation functions properly handle the issue.

Right.

> The saturation can neutralize many security attacks and can mitigate
> some safety issues. Think of the Ariane 5 rocket launch: a saturation
> could have prevented the unintended fireworks.
> 
> The caveat I can think of is that the old overflow check pattern becomes
> invalid. Doing:
> 
> 	if (saturate_var + increment < increment)
> 
> is now bogus and would need to be caught if possible by static analysis.
> So those saturating integers will only be usable in newly written code
> and could not be easily retrofitted.

In theory, the "ignored patterns" (or "idiom exclusions") would already
allow this to continue to behave correctly, though it may be worth trying
to figure out if this is "correct" or not.

> > +In the C standard, three basic types can be involved in arithmetic, and each
> > +has a default strategy for solving the overflow problem:
> > +
> > +  - Signed overflow is undefined
> > +  - Unsigned overflow explicitly wraps around
> > +  - Pointer overflow is undefined
> 
> Nitpick: the C standard uses different definitions than yours. In the
> standard:
> 
>   - overflow is *always* undefined
>   - unsigned integer wraparound
>   - signed integer overflow
> 
> The nuance is that in the standard unsigned integers do not overflow,
> they just wraparound.

I guess that's technically true, but for understanding the "overflow
resolution" properties (from a mathematical perspective), the question
is "what happens when a value cannot be represented by the bit pattern
of the storage?" But I think we understand each other here. :)
So given that under C, signed is undefined and unsigned in wraparound,
this is how we ended up phrasing it.

> I am not asking you to change your terminology, but it could be good to
> state in your document that your definition of overflow differs from the
> standard's definition. Maybe a terminology section could help.

I'm open to whatever you think would make this more clear. :)

-Kees

-- 
Kees Cook

^ permalink raw reply

* Re: [PATCH v8 02/10] x86/bhi: Make clear_bhb_loop() effective on newer CPUs
From: Pawan Gupta @ 2026-04-01 18:52 UTC (permalink / raw)
  To: David Laight
  Cc: Borislav Petkov, x86, Jon Kohler, Nikolay Borisov, H. Peter Anvin,
	Josh Poimboeuf, David Kaplan, Sean Christopherson, Dave Hansen,
	Peter Zijlstra, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, KP Singh, Jiri Olsa, David S. Miller,
	Andy Lutomirski, Thomas Gleixner, Ingo Molnar, David Ahern,
	Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	John Fastabend, Stanislav Fomichev, Hao Luo, Paolo Bonzini,
	Jonathan Corbet, linux-kernel, kvm, Asit Mallick, Tao Zhang, bpf,
	netdev, linux-doc
In-Reply-To: <20260401100200.5b347628@pumpkin>

On Wed, Apr 01, 2026 at 10:02:00AM +0100, David Laight wrote:
> > > As well as swapping %al <-> %ah try changing the outer loop decrement to
> > > 	sub $0x100, %ax
> > > since %al is zero that will set the z flag the same.  
> > 
> > Unfortunately, using "sub $0x100, %ax"(with %al as inner loop) isn't better
> > than just using "sub $1, %ah" in the outer loop:
> > 
> >   Event                     %al inner      + sub %ax       Delta
> >   ----------------------  -------------  -------------  ----------
> >   cycles                    776,775,020    813,372,036     +4.7%
> >   instructions/cycle               1.23           1.17     -4.5%
> >   branch-misses               4,792,502      7,610,323    +58.8%
> >   uops_issued.any           768,019,010    827,465,137     +7.7%
> >   time elapsed                 0.1627s        0.1707s      +4.9%
> 
> That is even more interesting.
> The 'sub %ax' version has more uops and more branch-misses.
> Looks like the extra cost of the %ah access is less than the cost
> of the extra mis-predicted branches.
> 
> Makes me wonder where a version that uses %cl fits?
> (Or use a zero-extending read and %eax/%ecx - likely to be the same.)
> I'll bet 'one beer' that is nearest the 'sub %ax' version.

%cl didn't make a noticeable difference, but ...

    Event                      %al/%ah        %al/%cl        Delta
                             (inner/outer)  (inner/outer)
    ----------------------  -------------  -------------  ----------
    cycles                    776,380,149    778,294,183     +0.2%
    instructions/cycle               1.23           1.22     -0.4%
    branch-misses               4,986,437      5,679,599    +13.9%
    uops_issued.any           773,223,387    765,724,878     -1.0%
    time elapsed                 0.1631s        0.1637s      +0.4%

... there are meaningful gains with 32-bit registers:

    Event                      %al/%ah        %eax/%ecx      Delta
                             (inner/outer)  (inner/outer)
    ----------------------  -------------  -------------  ----------
    cycles                    776,380,149    706,331,177     -9.0%
    instructions/cycle               1.23           1.35     +9.9%
    branch-misses               4,986,437      6,089,306    +22.1%
    uops_issued.any           773,223,387    774,539,522     +0.2%
    time elapsed                 0.1631s        0.1482s      -9.1%

These values are for userspace tests with immediates. Next, I will test how
they perform with memory loads in kernel. Before we finalize these uarch
nuances needs to be tested on a variety of CPUs.

^ permalink raw reply

* [PATCH net-next V4 12/12] devlink: Document resource scope filtering
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Document the scope parameter for devlink resource show, which allows
filtering the dump to device-level or port-level resources only.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 .../networking/devlink/devlink-resource.rst   | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/Documentation/networking/devlink/devlink-resource.rst b/Documentation/networking/devlink/devlink-resource.rst
index 9839c1661315..47eec8f875b4 100644
--- a/Documentation/networking/devlink/devlink-resource.rst
+++ b/Documentation/networking/devlink/devlink-resource.rst
@@ -109,3 +109,38 @@ To show resources for a specific port:
     $ devlink resource show pci/0000:03:00.0/196608
     pci/0000:03:00.0/196608:
       name max_SFs size 128 unit entry dpipe_tables none
+
+Resource Scope Filtering
+========================
+
+When dumping resources for all devices, ``devlink resource show`` accepts
+an optional ``scope`` parameter to restrict the response to device-level
+resources, port-level resources, or both (the default).
+
+To dump only device-level resources across all devices:
+
+.. code:: shell
+
+    $ devlink resource show scope dev
+    pci/0000:03:00.0:
+      name max_local_SFs size 128 unit entry dpipe_tables none
+      name max_external_SFs size 128 unit entry dpipe_tables none
+    pci/0000:03:00.1:
+      name max_local_SFs size 128 unit entry dpipe_tables none
+      name max_external_SFs size 128 unit entry dpipe_tables none
+
+To dump only port-level resources across all devices:
+
+.. code:: shell
+
+    $ devlink resource show scope port
+    pci/0000:03:00.0/196608:
+      name max_SFs size 128 unit entry dpipe_tables none
+    pci/0000:03:00.0/196609:
+      name max_SFs size 128 unit entry dpipe_tables none
+    pci/0000:03:00.1/196708:
+      name max_SFs size 128 unit entry dpipe_tables none
+    pci/0000:03:00.1/196709:
+      name max_SFs size 128 unit entry dpipe_tables none
+
+Note that port-level resources are read-only.
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 11/12] selftest: netdevsim: Add resource dump and scope filter test
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Add resource_dump_test() which verifies dumping resources for all
devices and ports, and tests that scope=dev returns only device-level
resources and scope=port returns only port resources.

Skip if userspace does not support the scope parameter.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 .../drivers/net/netdevsim/devlink.sh          | 52 ++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
index 2e63d02fae4b..8118cc211590 100755
--- a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
+++ b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
@@ -5,7 +5,7 @@ lib_dir=$(dirname $0)/../../../net/forwarding
 
 ALL_TESTS="fw_flash_test params_test  \
 	   params_default_test regions_test reload_test \
-	   netns_reload_test resource_test \
+	   netns_reload_test resource_test resource_dump_test \
 	   port_resource_doit_test dev_info_test \
 	   empty_reporter_test dummy_reporter_test rate_test"
 NUM_NETIFS=0
@@ -483,6 +483,56 @@ resource_test()
 	log_test "resource test"
 }
 
+resource_dump_test()
+{
+	RET=0
+
+	local port_jq
+	local dev_jq
+	local dl_jq
+	local count
+
+	dl_jq="with_entries(select(.key | startswith(\"$DL_HANDLE\")))"
+	port_jq="[.[] | $dl_jq | keys |"
+	port_jq+=" map(select(test(\"/.+/\"))) | length] | add"
+	dev_jq="[.[] | $dl_jq | keys |"
+	dev_jq+=" map(select(test(\"/.+/\")|not)) | length] | add"
+
+	if ! devlink resource help 2>&1 | grep -q "scope"; then
+		echo "SKIP: devlink resource show not supported"
+		return
+	fi
+
+	devlink resource show > /dev/null 2>&1
+	check_err $? "Failed to dump all resources"
+
+	count=$(cmd_jq "devlink resource show -j" "$port_jq")
+	[ "$count" -gt "0" ]
+	check_err $? "missing port resources in resource dump"
+
+	count=$(cmd_jq "devlink resource show -j" "$dev_jq")
+	[ "$count" -gt "0" ]
+	check_err $? "missing device resources in resource dump"
+
+	count=$(cmd_jq "devlink resource show scope dev -j" "$dev_jq")
+	[ "$count" -gt "0" ]
+	check_err $? "dev scope missing device resources"
+
+	count=$(cmd_jq "devlink resource show scope dev -j" "$port_jq")
+	[ "$count" -eq "0" ]
+	check_err $? "dev scope returned port resources"
+
+	count=$(cmd_jq "devlink resource show scope port -j" "$port_jq")
+	[ "$count" -gt "0" ]
+	check_err $? "port scope missing port resources"
+
+	count=$(cmd_jq "devlink resource show scope port -j" "$dev_jq")
+	[ "$count" -eq "0" ]
+	check_err $? "port scope returned device resources"
+
+	log_test "resource dump test"
+}
+
 info_get()
 {
 	local name=$1
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 10/12] devlink: Add resource scope filtering to resource dump
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Allow filtering the resource dump to device-level or port-level
resources using the 'scope' option.

Example - dump only device-level resources:

  $ devlink resource show scope dev
  pci/0000:03:00.0:
    name max_local_SFs size 128 unit entry dpipe_tables none
    name max_external_SFs size 128 unit entry dpipe_tables none
  pci/0000:03:00.1:
    name max_local_SFs size 128 unit entry dpipe_tables none
    name max_external_SFs size 128 unit entry dpipe_tables none

Example - dump only port-level resources:

  $ devlink resource show scope port
  pci/0000:03:00.0/196608:
    name max_SFs size 128 unit entry dpipe_tables none
  pci/0000:03:00.0/196609:
    name max_SFs size 128 unit entry dpipe_tables none
  pci/0000:03:00.1/196708:
    name max_SFs size 128 unit entry dpipe_tables none
  pci/0000:03:00.1/196709:
    name max_SFs size 128 unit entry dpipe_tables none

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 Documentation/netlink/specs/devlink.yaml | 24 +++++++++++++++++-
 include/uapi/linux/devlink.h             | 17 +++++++++++++
 net/devlink/netlink_gen.c                |  5 ++--
 net/devlink/resource.c                   | 32 ++++++++++++++++++++++--
 4 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml
index 34aa81ba689e..b7d0490fc49d 100644
--- a/Documentation/netlink/specs/devlink.yaml
+++ b/Documentation/netlink/specs/devlink.yaml
@@ -157,6 +157,14 @@ definitions:
     entries:
       -
         name: entry
+  -
+    type: enum
+    name: resource-scope
+    entries:
+      -
+        name: dev
+      -
+        name: port
   -
     type: enum
     name: reload-action
@@ -873,6 +881,16 @@ attribute-sets:
         doc: Unique devlink instance index.
         checks:
           max: u32-max
+      -
+        name: resource-scope-mask
+        type: bitfield32
+        enum: resource-scope
+        enum-as-flags: true
+        doc: |
+          Bitmask selecting which resource classes to include in a
+          resource-dump response. Bit 0 (dev) selects device-level
+          resources; bit 1 (port) selects port-level resources.
+          When absent all classes are returned.
   -
     name: dl-dev-stats
     subset-of: devlink
@@ -1775,7 +1793,11 @@ operations:
             - resource-list
       dump:
         request:
-          attributes: *dev-id-attrs
+          attributes:
+            - bus-name
+            - dev-name
+            - index
+            - resource-scope-mask
         reply: *resource-dump-reply
 
     -
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 7de2d8cc862f..e0a0b523ce5c 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -645,6 +645,7 @@ enum devlink_attr {
 	DEVLINK_ATTR_PARAM_RESET_DEFAULT,	/* flag */
 
 	DEVLINK_ATTR_INDEX,			/* uint */
+	DEVLINK_ATTR_RESOURCE_SCOPE_MASK,	/* bitfield32 */
 
 	/* Add new attributes above here, update the spec in
 	 * Documentation/netlink/specs/devlink.yaml and re-generate
@@ -704,6 +705,22 @@ enum devlink_resource_unit {
 	DEVLINK_RESOURCE_UNIT_ENTRY,
 };
 
+enum devlink_resource_scope {
+	DEVLINK_RESOURCE_SCOPE_DEV_BIT,
+	DEVLINK_RESOURCE_SCOPE_PORT_BIT,
+
+	__DEVLINK_RESOURCE_SCOPE_MAX_BIT,
+	DEVLINK_RESOURCE_SCOPE_MAX_BIT =
+		__DEVLINK_RESOURCE_SCOPE_MAX_BIT - 1
+};
+
+#define DEVLINK_RESOURCE_SCOPE_DEV \
+	_BITUL(DEVLINK_RESOURCE_SCOPE_DEV_BIT)
+#define DEVLINK_RESOURCE_SCOPE_PORT \
+	_BITUL(DEVLINK_RESOURCE_SCOPE_PORT_BIT)
+#define DEVLINK_RESOURCE_SCOPE_VALID_MASK \
+	(_BITUL(__DEVLINK_RESOURCE_SCOPE_MAX_BIT) - 1)
+
 enum devlink_port_fn_attr_cap {
 	DEVLINK_PORT_FN_ATTR_CAP_ROCE_BIT,
 	DEVLINK_PORT_FN_ATTR_CAP_MIGRATABLE_BIT,
diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c
index 9cc372d9ee41..6d4abd8b828d 100644
--- a/net/devlink/netlink_gen.c
+++ b/net/devlink/netlink_gen.c
@@ -313,10 +313,11 @@ static const struct nla_policy devlink_resource_dump_do_nl_policy[DEVLINK_ATTR_I
 };
 
 /* DEVLINK_CMD_RESOURCE_DUMP - dump */
-static const struct nla_policy devlink_resource_dump_dump_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
+static const struct nla_policy devlink_resource_dump_dump_nl_policy[DEVLINK_ATTR_RESOURCE_SCOPE_MASK + 1] = {
 	[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range),
+	[DEVLINK_ATTR_RESOURCE_SCOPE_MASK] = NLA_POLICY_BITFIELD32(3),
 };
 
 /* DEVLINK_CMD_RELOAD - do */
@@ -974,7 +975,7 @@ const struct genl_split_ops devlink_nl_ops[75] = {
 		.cmd		= DEVLINK_CMD_RESOURCE_DUMP,
 		.dumpit		= devlink_nl_resource_dump_dumpit,
 		.policy		= devlink_resource_dump_dump_nl_policy,
-		.maxattr	= DEVLINK_ATTR_INDEX,
+		.maxattr	= DEVLINK_ATTR_RESOURCE_SCOPE_MASK,
 		.flags		= GENL_CMD_CAP_DUMP,
 	},
 	{
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index 0f1d90bc4b09..c22338b2571d 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -341,6 +341,22 @@ int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info)
 	return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
 }
 
+static u32 devlink_resource_scope_get(struct nlattr **attrs, int *flags)
+{
+	struct nla_bitfield32 scope;
+	u32 value;
+
+	if (!attrs || !attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK])
+		return DEVLINK_RESOURCE_SCOPE_VALID_MASK;
+
+	scope = nla_get_bitfield32(attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK]);
+	value = scope.value & scope.selector;
+	if (value != DEVLINK_RESOURCE_SCOPE_VALID_MASK)
+		*flags |= NLM_F_DUMP_FILTERED;
+
+	return value;
+}
+
 static int
 devlink_resource_dump_fill_one(struct sk_buff *skb, struct devlink *devlink,
 			       struct devlink_port *devlink_port,
@@ -400,16 +416,27 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
 	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
 	struct devlink_port *devlink_port;
 	unsigned long port_idx;
+	u32 scope;
 	int err;
 
-	if (!state->port_number) {
+	scope = devlink_resource_scope_get(genl_info_dump(cb)->attrs, &flags);
+	if (!scope) {
+		NL_SET_ERR_MSG_ATTR(genl_info_dump(cb)->extack,
+				    genl_info_dump(cb)->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK],
+				    "empty resource scope selection");
+		return -EINVAL;
+	}
+	if (!state->port_number && (scope & DEVLINK_RESOURCE_SCOPE_DEV)) {
 		err = devlink_resource_dump_fill_one(skb, devlink, NULL,
-						     cb, flags, &state->idx);
+						     cb, flags,
+						     &state->idx);
 		if (err)
 			return err;
 		state->idx = 0;
 	}
 
+	if (!(scope & DEVLINK_RESOURCE_SCOPE_PORT))
+		goto out;
 	xa_for_each_start(&devlink->ports, port_idx, devlink_port,
 			  state->port_number ? state->port_number - 1 : 0) {
 		err = devlink_resource_dump_fill_one(skb, devlink, devlink_port,
@@ -420,6 +447,7 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
 		}
 		state->idx = 0;
 	}
+out:
 	state->port_number = 0;
 	return 0;
 }
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 09/12] devlink: Document port-level resources and full dump
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman, Jiri Pirko
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Document the port-level resource support and the option to dump all
resources, including both device-level and port-level entries.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Shay Drori <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 .../networking/devlink/devlink-resource.rst   | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/Documentation/networking/devlink/devlink-resource.rst b/Documentation/networking/devlink/devlink-resource.rst
index 3d5ae51e65a2..9839c1661315 100644
--- a/Documentation/networking/devlink/devlink-resource.rst
+++ b/Documentation/networking/devlink/devlink-resource.rst
@@ -74,3 +74,38 @@ attribute, which represents the pending change in size. For example:
 
 Note that changes in resource size may require a device reload to properly
 take effect.
+
+Port-level Resources and Full Dump
+==================================
+
+In addition to device-level resources, ``devlink`` also supports port-level
+resources. These resources are associated with a specific devlink port rather
+than the device as a whole.
+
+To list resources for all devlink devices and ports:
+
+.. code:: shell
+
+    $ devlink resource show
+    pci/0000:03:00.0:
+      name max_local_SFs size 128 unit entry dpipe_tables none
+      name max_external_SFs size 128 unit entry dpipe_tables none
+    pci/0000:03:00.0/196608:
+      name max_SFs size 128 unit entry dpipe_tables none
+    pci/0000:03:00.0/196609:
+      name max_SFs size 128 unit entry dpipe_tables none
+    pci/0000:03:00.1:
+      name max_local_SFs size 128 unit entry dpipe_tables none
+      name max_external_SFs size 128 unit entry dpipe_tables none
+    pci/0000:03:00.1/196708:
+      name max_SFs size 128 unit entry dpipe_tables none
+    pci/0000:03:00.1/196709:
+      name max_SFs size 128 unit entry dpipe_tables none
+
+To show resources for a specific port:
+
+.. code:: shell
+
+    $ devlink resource show pci/0000:03:00.0/196608
+    pci/0000:03:00.0/196608:
+      name max_SFs size 128 unit entry dpipe_tables none
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 08/12] selftest: netdevsim: Add devlink port resource doit test
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Tests that querying a specific port handle returns the expected
resource name and size.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 .../drivers/net/netdevsim/devlink.sh          | 29 ++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
index 1b529ccaf050..2e63d02fae4b 100755
--- a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
+++ b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
@@ -5,7 +5,8 @@ lib_dir=$(dirname $0)/../../../net/forwarding
 
 ALL_TESTS="fw_flash_test params_test  \
 	   params_default_test regions_test reload_test \
-	   netns_reload_test resource_test dev_info_test \
+	   netns_reload_test resource_test \
+	   port_resource_doit_test dev_info_test \
 	   empty_reporter_test dummy_reporter_test rate_test"
 NUM_NETIFS=0
 source $lib_dir/lib.sh
@@ -768,6 +769,32 @@ rate_node_del()
 	devlink port function rate del $handle
 }
 
+port_resource_doit_test()
+{
+	RET=0
+
+	local port_handle="${DL_HANDLE}/0"
+	local name
+	local size
+
+	if ! devlink resource help 2>&1 | grep -q "PORT_INDEX"; then
+		echo "SKIP: devlink resource show not supported for port selector"
+		return
+	fi
+
+	name=$(cmd_jq "devlink resource show $port_handle -j" \
+		      '.[][][].name')
+	[ "$name" == "test_resource" ]
+	check_err $? "wrong port resource name (got $name)"
+
+	size=$(cmd_jq "devlink resource show $port_handle -j" \
+		      '.[][][].size')
+	[ "$size" == "20" ]
+	check_err $? "wrong port resource size (got $size)"
+
+	log_test "port resource doit test"
+}
+
 rate_test()
 {
 	RET=0
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 07/12] devlink: Add port-specific option to resource dump doit
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Allow querying devlink resources per-port via the resource-dump doit
handler. When a port-index attribute is provided, only that port's
resources are returned. When no port-index is given, only device-level
resources are returned, preserving backward compatibility.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 Documentation/netlink/specs/devlink.yaml |  4 +++-
 net/devlink/netlink_gen.c                |  3 ++-
 net/devlink/netlink_gen.h                |  4 ++--
 net/devlink/resource.c                   | 20 +++++++++++++++++---
 4 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml
index c423e049c7bd..34aa81ba689e 100644
--- a/Documentation/netlink/specs/devlink.yaml
+++ b/Documentation/netlink/specs/devlink.yaml
@@ -1757,19 +1757,21 @@ operations:
       attribute-set: devlink
       dont-validate: [strict]
       do:
-        pre: devlink-nl-pre-doit
+        pre: devlink-nl-pre-doit-port-optional
         post: devlink-nl-post-doit
         request:
           attributes:
             - bus-name
             - dev-name
             - index
+            - port-index
         reply: &resource-dump-reply
           value: 36
           attributes:
             - bus-name
             - dev-name
             - index
+            - port-index
             - resource-list
       dump:
         request:
diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c
index a5a47a4c6de8..9cc372d9ee41 100644
--- a/net/devlink/netlink_gen.c
+++ b/net/devlink/netlink_gen.c
@@ -309,6 +309,7 @@ static const struct nla_policy devlink_resource_dump_do_nl_policy[DEVLINK_ATTR_I
 	[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range),
+	[DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, },
 };
 
 /* DEVLINK_CMD_RESOURCE_DUMP - dump */
@@ -962,7 +963,7 @@ const struct genl_split_ops devlink_nl_ops[75] = {
 	{
 		.cmd		= DEVLINK_CMD_RESOURCE_DUMP,
 		.validate	= GENL_DONT_VALIDATE_STRICT,
-		.pre_doit	= devlink_nl_pre_doit,
+		.pre_doit	= devlink_nl_pre_doit_port_optional,
 		.doit		= devlink_nl_resource_dump_doit,
 		.post_doit	= devlink_nl_post_doit,
 		.policy		= devlink_resource_dump_do_nl_policy,
diff --git a/net/devlink/netlink_gen.h b/net/devlink/netlink_gen.h
index d79f6a0888f6..20034b0929a8 100644
--- a/net/devlink/netlink_gen.h
+++ b/net/devlink/netlink_gen.h
@@ -24,11 +24,11 @@ int devlink_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
 			struct genl_info *info);
 int devlink_nl_pre_doit_port(const struct genl_split_ops *ops,
 			     struct sk_buff *skb, struct genl_info *info);
-int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops,
-				 struct sk_buff *skb, struct genl_info *info);
 int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
 				      struct sk_buff *skb,
 				      struct genl_info *info);
+int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops,
+				 struct sk_buff *skb, struct genl_info *info);
 void
 devlink_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
 		     struct genl_info *info);
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index 48f195063551..0f1d90bc4b09 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -251,8 +251,10 @@ static int devlink_resource_list_fill(struct sk_buff *skb,
 static int devlink_resource_fill(struct genl_info *info,
 				 enum devlink_command cmd, int flags)
 {
+	struct devlink_port *devlink_port = info->user_ptr[1];
 	struct devlink *devlink = info->user_ptr[0];
 	struct devlink_resource *resource;
+	struct list_head *resource_list;
 	struct nlattr *resources_attr;
 	struct sk_buff *skb = NULL;
 	struct nlmsghdr *nlh;
@@ -261,7 +263,9 @@ static int devlink_resource_fill(struct genl_info *info,
 	int i;
 	int err;
 
-	resource = list_first_entry(&devlink->resource_list,
+	resource_list = devlink_port ?
+		&devlink_port->resource_list : &devlink->resource_list;
+	resource = list_first_entry(resource_list,
 				    struct devlink_resource, list);
 start_again:
 	err = devlink_nl_msg_reply_and_new(&skb, info);
@@ -277,6 +281,9 @@ static int devlink_resource_fill(struct genl_info *info,
 
 	if (devlink_nl_put_handle(skb, devlink))
 		goto nla_put_failure;
+	if (devlink_port &&
+	    nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
+		goto nla_put_failure;
 
 	resources_attr = nla_nest_start_noflag(skb,
 					       DEVLINK_ATTR_RESOURCE_LIST);
@@ -285,7 +292,7 @@ static int devlink_resource_fill(struct genl_info *info,
 
 	incomplete = false;
 	i = 0;
-	list_for_each_entry_from(resource, &devlink->resource_list, list) {
+	list_for_each_entry_from(resource, resource_list, list) {
 		err = devlink_resource_put(devlink, skb, resource);
 		if (err) {
 			if (!i)
@@ -319,9 +326,16 @@ static int devlink_resource_fill(struct genl_info *info,
 
 int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info)
 {
+	struct devlink_port *devlink_port = info->user_ptr[1];
 	struct devlink *devlink = info->user_ptr[0];
+	struct list_head *resource_list;
+
+	if (info->attrs[DEVLINK_ATTR_PORT_INDEX] && !devlink_port)
+		return -ENODEV;
 
-	if (list_empty(&devlink->resource_list))
+	resource_list = devlink_port ?
+		&devlink_port->resource_list : &devlink->resource_list;
+	if (list_empty(resource_list))
 		return -EOPNOTSUPP;
 
 	return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 06/12] devlink: Include port resources in resource dump dumpit
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Allow querying devlink resources per-port via the resource-dump dumpit
handler. Both device-level and all ports resources are included in the
reply.

For example:

$ devlink resource show
pci/0000:03:00.0:
  name local_max_SFs size 508 unit entry
  name external_max_SFs size 508 unit entry
pci/0000:03:00.0/196608:
  name max_SFs size 20 unit entry
pci/0000:03:00.1:
  name local_max_SFs size 508 unit entry
  name external_max_SFs size 508 unit entry
pci/0000:03:00.1/262144:
  name max_SFs size 20 unit entry

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 net/devlink/devl_internal.h |  4 +++
 net/devlink/resource.c      | 53 +++++++++++++++++++++++++++++++------
 2 files changed, 49 insertions(+), 8 deletions(-)

diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h
index 7dfb7cdd2d23..000b8d271b90 100644
--- a/net/devlink/devl_internal.h
+++ b/net/devlink/devl_internal.h
@@ -164,6 +164,10 @@ struct devlink_nl_dump_state {
 		struct {
 			u64 dump_ts;
 		};
+		/* DEVLINK_CMD_RESOURCE_DUMP */
+		struct {
+			unsigned long port_number;
+		};
 	};
 };
 
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index 02fb36e25c52..48f195063551 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -328,16 +328,20 @@ int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info)
 }
 
 static int
-devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
-			     struct netlink_callback *cb, int flags)
+devlink_resource_dump_fill_one(struct sk_buff *skb, struct devlink *devlink,
+			       struct devlink_port *devlink_port,
+			       struct netlink_callback *cb, int flags, int *idx)
 {
-	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
+	struct list_head *resource_list;
 	struct nlattr *resources_attr;
-	int start_idx = state->idx;
+	int start_idx = *idx;
 	void *hdr;
 	int err;
 
-	if (list_empty(&devlink->resource_list))
+	resource_list = devlink_port ?
+		&devlink_port->resource_list : &devlink->resource_list;
+
+	if (list_empty(resource_list))
 		return 0;
 
 	err = -EMSGSIZE;
@@ -348,15 +352,17 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
 
 	if (devlink_nl_put_handle(skb, devlink))
 		goto nla_put_failure;
+	if (devlink_port &&
+	    nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
+		goto nla_put_failure;
 
 	resources_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE_LIST);
 	if (!resources_attr)
 		goto nla_put_failure;
 
-	err = devlink_resource_list_fill(skb, devlink,
-					 &devlink->resource_list, &state->idx);
+	err = devlink_resource_list_fill(skb, devlink, resource_list, idx);
 	if (err) {
-		if (state->idx == start_idx)
+		if (*idx == start_idx)
 			goto resource_list_cancel;
 		nla_nest_end(skb, resources_attr);
 		genlmsg_end(skb, hdr);
@@ -373,6 +379,37 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
 	return err;
 }
 
+static int
+devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
+			     struct netlink_callback *cb, int flags)
+{
+	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
+	struct devlink_port *devlink_port;
+	unsigned long port_idx;
+	int err;
+
+	if (!state->port_number) {
+		err = devlink_resource_dump_fill_one(skb, devlink, NULL,
+						     cb, flags, &state->idx);
+		if (err)
+			return err;
+		state->idx = 0;
+	}
+
+	xa_for_each_start(&devlink->ports, port_idx, devlink_port,
+			  state->port_number ? state->port_number - 1 : 0) {
+		err = devlink_resource_dump_fill_one(skb, devlink, devlink_port,
+						     cb, flags, &state->idx);
+		if (err) {
+			state->port_number = port_idx + 1;
+			return err;
+		}
+		state->idx = 0;
+	}
+	state->port_number = 0;
+	return 0;
+}
+
 int devlink_nl_resource_dump_dumpit(struct sk_buff *skb,
 				    struct netlink_callback *cb)
 {
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 05/12] devlink: Add dump support for device-level resources
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman, Jiri Pirko
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Add dumpit handler for resource-dump command to iterate over all devlink
devices and show their resources.

  $ devlink resource show
  pci/0000:08:00.0:
    name local_max_SFs size 508 unit entry
    name external_max_SFs size 508 unit entry
  pci/0000:08:00.1:
    name local_max_SFs size 508 unit entry
    name external_max_SFs size 508 unit entry

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Shay Drori <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 Documentation/netlink/specs/devlink.yaml |  6 +-
 net/devlink/netlink_gen.c                | 20 +++++-
 net/devlink/netlink_gen.h                |  4 +-
 net/devlink/resource.c                   | 77 ++++++++++++++++++++++++
 4 files changed, 102 insertions(+), 5 deletions(-)

diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml
index b495d56b9137..c423e049c7bd 100644
--- a/Documentation/netlink/specs/devlink.yaml
+++ b/Documentation/netlink/specs/devlink.yaml
@@ -1764,13 +1764,17 @@ operations:
             - bus-name
             - dev-name
             - index
-        reply:
+        reply: &resource-dump-reply
           value: 36
           attributes:
             - bus-name
             - dev-name
             - index
             - resource-list
+      dump:
+        request:
+          attributes: *dev-id-attrs
+        reply: *resource-dump-reply
 
     -
       name: reload
diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c
index eb35e80e01d1..a5a47a4c6de8 100644
--- a/net/devlink/netlink_gen.c
+++ b/net/devlink/netlink_gen.c
@@ -305,7 +305,14 @@ static const struct nla_policy devlink_resource_set_nl_policy[DEVLINK_ATTR_INDEX
 };
 
 /* DEVLINK_CMD_RESOURCE_DUMP - do */
-static const struct nla_policy devlink_resource_dump_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
+static const struct nla_policy devlink_resource_dump_do_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
+	[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
+	[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
+	[DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range),
+};
+
+/* DEVLINK_CMD_RESOURCE_DUMP - dump */
+static const struct nla_policy devlink_resource_dump_dump_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
 	[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range),
@@ -680,7 +687,7 @@ static const struct nla_policy devlink_notify_filter_set_nl_policy[DEVLINK_ATTR_
 };
 
 /* Ops table for devlink */
-const struct genl_split_ops devlink_nl_ops[74] = {
+const struct genl_split_ops devlink_nl_ops[75] = {
 	{
 		.cmd		= DEVLINK_CMD_GET,
 		.validate	= GENL_DONT_VALIDATE_STRICT,
@@ -958,10 +965,17 @@ const struct genl_split_ops devlink_nl_ops[74] = {
 		.pre_doit	= devlink_nl_pre_doit,
 		.doit		= devlink_nl_resource_dump_doit,
 		.post_doit	= devlink_nl_post_doit,
-		.policy		= devlink_resource_dump_nl_policy,
+		.policy		= devlink_resource_dump_do_nl_policy,
 		.maxattr	= DEVLINK_ATTR_INDEX,
 		.flags		= GENL_CMD_CAP_DO,
 	},
+	{
+		.cmd		= DEVLINK_CMD_RESOURCE_DUMP,
+		.dumpit		= devlink_nl_resource_dump_dumpit,
+		.policy		= devlink_resource_dump_dump_nl_policy,
+		.maxattr	= DEVLINK_ATTR_INDEX,
+		.flags		= GENL_CMD_CAP_DUMP,
+	},
 	{
 		.cmd		= DEVLINK_CMD_RELOAD,
 		.validate	= GENL_DONT_VALIDATE_STRICT,
diff --git a/net/devlink/netlink_gen.h b/net/devlink/netlink_gen.h
index 2817d53a0eba..d79f6a0888f6 100644
--- a/net/devlink/netlink_gen.h
+++ b/net/devlink/netlink_gen.h
@@ -18,7 +18,7 @@ extern const struct nla_policy devlink_dl_rate_tc_bws_nl_policy[DEVLINK_RATE_TC_
 extern const struct nla_policy devlink_dl_selftest_id_nl_policy[DEVLINK_ATTR_SELFTEST_ID_FLASH + 1];
 
 /* Ops table for devlink */
-extern const struct genl_split_ops devlink_nl_ops[74];
+extern const struct genl_split_ops devlink_nl_ops[75];
 
 int devlink_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
 			struct genl_info *info);
@@ -80,6 +80,8 @@ int devlink_nl_dpipe_table_counters_set_doit(struct sk_buff *skb,
 					     struct genl_info *info);
 int devlink_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info);
 int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info);
+int devlink_nl_resource_dump_dumpit(struct sk_buff *skb,
+				    struct netlink_callback *cb);
 int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info);
 int devlink_nl_param_get_doit(struct sk_buff *skb, struct genl_info *info);
 int devlink_nl_param_get_dumpit(struct sk_buff *skb,
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index f3014ec425c4..02fb36e25c52 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -223,6 +223,31 @@ static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
 	return -EMSGSIZE;
 }
 
+static int devlink_resource_list_fill(struct sk_buff *skb,
+				      struct devlink *devlink,
+				      struct list_head *resource_list_head,
+				      int *idx)
+{
+	struct devlink_resource *resource;
+	int i = 0;
+	int err;
+
+	list_for_each_entry(resource, resource_list_head, list) {
+		if (i < *idx) {
+			i++;
+			continue;
+		}
+		err = devlink_resource_put(devlink, skb, resource);
+		if (err) {
+			*idx = i;
+			return err;
+		}
+		i++;
+	}
+	*idx = 0;
+	return 0;
+}
+
 static int devlink_resource_fill(struct genl_info *info,
 				 enum devlink_command cmd, int flags)
 {
@@ -302,6 +327,58 @@ int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info)
 	return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
 }
 
+static int
+devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
+			     struct netlink_callback *cb, int flags)
+{
+	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
+	struct nlattr *resources_attr;
+	int start_idx = state->idx;
+	void *hdr;
+	int err;
+
+	if (list_empty(&devlink->resource_list))
+		return 0;
+
+	err = -EMSGSIZE;
+	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
+			  &devlink_nl_family, flags, DEVLINK_CMD_RESOURCE_DUMP);
+	if (!hdr)
+		return err;
+
+	if (devlink_nl_put_handle(skb, devlink))
+		goto nla_put_failure;
+
+	resources_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE_LIST);
+	if (!resources_attr)
+		goto nla_put_failure;
+
+	err = devlink_resource_list_fill(skb, devlink,
+					 &devlink->resource_list, &state->idx);
+	if (err) {
+		if (state->idx == start_idx)
+			goto resource_list_cancel;
+		nla_nest_end(skb, resources_attr);
+		genlmsg_end(skb, hdr);
+		return err;
+	}
+	nla_nest_end(skb, resources_attr);
+	genlmsg_end(skb, hdr);
+	return 0;
+
+resource_list_cancel:
+	nla_nest_cancel(skb, resources_attr);
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return err;
+}
+
+int devlink_nl_resource_dump_dumpit(struct sk_buff *skb,
+				    struct netlink_callback *cb)
+{
+	return devlink_nl_dumpit(skb, cb, devlink_nl_resource_dump_one);
+}
+
 int devlink_resources_validate(struct devlink *devlink,
 			       struct devlink_resource *resource,
 			       struct genl_info *info)
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 04/12] netdevsim: Add devlink port resource registration
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman, Jiri Pirko
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Register port-level resources for netdevsim ports to enable testing
of the port resource infrastructure.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Shay Drori <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 drivers/net/netdevsim/dev.c       | 23 ++++++++++++++++++++++-
 drivers/net/netdevsim/netdevsim.h |  4 ++++
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index e82de0fd3157..1e06e781c835 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -1486,9 +1486,25 @@ static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_typ
 	if (err)
 		goto err_port_free;
 
+	if (nsim_dev_port_is_pf(nsim_dev_port)) {
+		u64 parent_id = DEVLINK_RESOURCE_ID_PARENT_TOP;
+		struct devlink_resource_size_params params = {
+			.size_max = 100,
+			.size_granularity = 1,
+			.unit = DEVLINK_RESOURCE_UNIT_ENTRY
+		};
+
+		err = devl_port_resource_register(devlink_port,
+						  "test_resource", 20,
+						  NSIM_PORT_RESOURCE_TEST,
+						  parent_id, &params);
+		if (err)
+			goto err_dl_port_unregister;
+	}
+
 	err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port);
 	if (err)
-		goto err_dl_port_unregister;
+		goto err_port_resource_unregister;
 
 	nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port, perm_addr);
 	if (IS_ERR(nsim_dev_port->ns)) {
@@ -1511,6 +1527,9 @@ static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_typ
 	nsim_destroy(nsim_dev_port->ns);
 err_port_debugfs_exit:
 	nsim_dev_port_debugfs_exit(nsim_dev_port);
+err_port_resource_unregister:
+	if (nsim_dev_port_is_pf(nsim_dev_port))
+		devl_port_resources_unregister(devlink_port);
 err_dl_port_unregister:
 	devl_port_unregister(devlink_port);
 err_port_free:
@@ -1527,6 +1546,8 @@ static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
 		devl_rate_leaf_destroy(&nsim_dev_port->devlink_port);
 	nsim_destroy(nsim_dev_port->ns);
 	nsim_dev_port_debugfs_exit(nsim_dev_port);
+	if (nsim_dev_port_is_pf(nsim_dev_port))
+		devl_port_resources_unregister(devlink_port);
 	devl_port_unregister(devlink_port);
 	kfree(nsim_dev_port);
 }
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index c904e14f6b3f..c7de53706ec4 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -224,6 +224,10 @@ enum nsim_resource_id {
 	NSIM_RESOURCE_NEXTHOPS,
 };
 
+enum nsim_port_resource_id {
+	NSIM_PORT_RESOURCE_TEST = 1,
+};
+
 struct nsim_dev_health {
 	struct devlink_health_reporter *empty_reporter;
 	struct devlink_health_reporter *dummy_reporter;
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 03/12] net/mlx5: Register SF resource on PF port representor
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman, Jiri Pirko
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

The device-level "resource show" displays max_local_SFs and
max_external_SFs without indicating which port each resource belongs
to. Users cannot determine the controller number and pfnum associated
with each SF pool.

Register max_SFs resource on the host PF representor port to expose
per-port SF limits. Users can correlate the port resource with the
controller number and pfnum shown in 'devlink port show'.

Future patches will introduce an ECPF that manages multiple PFs,
where each PF has its own SF pool.

Example usage:

  $ devlink resource show pci/0000:03:00.0/196608
  pci/0000:03:00.0/196608:
    name max_SFs size 20 unit entry

  $ devlink port show pci/0000:03:00.0/196608
  pci/0000:03:00.0/196608: type eth netdev pf0hpf flavour pcipf
    controller 1 pfnum 0 external true splittable false
    function:
      hw_addr b8:3f:d2:e1:8f:dc roce enable max_io_eqs 120

We can create up to 20 SFs over devlink port pci/0000:03:00.0/196608,
with pfnum 0 and controller 1.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Shay Drori <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 .../net/ethernet/mellanox/mlx5/core/devlink.h |  4 ++
 .../mellanox/mlx5/core/esw/devlink_port.c     | 37 +++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.h b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
index 43b9bf8829cf..4fbb3926a3e5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
@@ -14,6 +14,10 @@ enum mlx5_devlink_resource_id {
 	MLX5_ID_RES_MAX = __MLX5_ID_RES_MAX - 1,
 };
 
+enum mlx5_devlink_port_resource_id {
+	MLX5_DL_PORT_RES_MAX_SFS = 1,
+};
+
 enum mlx5_devlink_param_id {
 	MLX5_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
 	MLX5_DEVLINK_PARAM_ID_FLOW_STEERING_MODE,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
index 8bffba85f21f..e1d11326af1b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
@@ -3,6 +3,7 @@
 
 #include <linux/mlx5/driver.h>
 #include "eswitch.h"
+#include "devlink.h"
 
 static void
 mlx5_esw_get_port_parent_id(struct mlx5_core_dev *dev, struct netdev_phys_item_id *ppid)
@@ -158,6 +159,32 @@ static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = {
 	.port_fn_max_io_eqs_set = mlx5_devlink_port_fn_max_io_eqs_set,
 };
 
+static int mlx5_esw_devlink_port_res_register(struct mlx5_eswitch *esw,
+					      struct devlink_port *dl_port)
+{
+	struct devlink_resource_size_params size_params;
+	struct mlx5_core_dev *dev = esw->dev;
+	u16 max_sfs, sf_base_id;
+	int err;
+
+	err = mlx5_esw_sf_max_hpf_functions(dev, &max_sfs, &sf_base_id);
+	if (err)
+		return err;
+
+	devlink_resource_size_params_init(&size_params, max_sfs, max_sfs, 1,
+					  DEVLINK_RESOURCE_UNIT_ENTRY);
+
+	return devl_port_resource_register(dl_port, "max_SFs", max_sfs,
+					   MLX5_DL_PORT_RES_MAX_SFS,
+					   DEVLINK_RESOURCE_ID_PARENT_TOP,
+					   &size_params);
+}
+
+static void mlx5_esw_devlink_port_res_unregister(struct devlink_port *dl_port)
+{
+	devl_port_resources_unregister(dl_port);
+}
+
 int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
 {
 	struct mlx5_core_dev *dev = esw->dev;
@@ -189,6 +216,15 @@ int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx
 	if (err)
 		goto rate_err;
 
+	if (vport_num == MLX5_VPORT_PF) {
+		err = mlx5_esw_devlink_port_res_register(esw,
+							 &dl_port->dl_port);
+		if (err)
+			mlx5_core_dbg(dev,
+				      "Failed to register port resources: %d\n",
+				       err);
+	}
+
 	return 0;
 
 rate_err:
@@ -203,6 +239,7 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport)
 	if (!vport->dl_port)
 		return;
 	dl_port = vport->dl_port;
+	mlx5_esw_devlink_port_res_unregister(&dl_port->dl_port);
 
 	mlx5_esw_qos_vport_update_parent(vport, NULL, NULL);
 	devl_rate_leaf_destroy(&dl_port->dl_port);
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 02/12] devlink: Add port-level resource registration infrastructure
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman, Jiri Pirko
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

The current devlink resource infrastructure supports only device-level
resources. Some hardware resources are associated with specific ports
rather than the entire device, and today we have no way to show resource
per-port.

Add support for registering resources at the port level.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Shay Drori <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 include/net/devlink.h  |  8 ++++++++
 net/devlink/port.c     |  2 ++
 net/devlink/resource.c | 43 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+)

diff --git a/include/net/devlink.h b/include/net/devlink.h
index f5439d050eb0..bcd31de1f890 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -129,6 +129,7 @@ struct devlink_rate {
 struct devlink_port {
 	struct list_head list;
 	struct list_head region_list;
+	struct list_head resource_list;
 	struct devlink *devlink;
 	const struct devlink_port_ops *ops;
 	unsigned int index;
@@ -1891,6 +1892,13 @@ void devlink_resources_unregister(struct devlink *devlink);
 int devl_resource_size_get(struct devlink *devlink,
 			   u64 resource_id,
 			   u64 *p_resource_size);
+int
+devl_port_resource_register(struct devlink_port *devlink_port,
+			    const char *resource_name,
+			    u64 resource_size, u64 resource_id,
+			    u64 parent_resource_id,
+			    const struct devlink_resource_size_params *params);
+void devl_port_resources_unregister(struct devlink_port *devlink_port);
 int devl_dpipe_table_resource_set(struct devlink *devlink,
 				  const char *table_name, u64 resource_id,
 				  u64 resource_units);
diff --git a/net/devlink/port.c b/net/devlink/port.c
index 7fcd1d3ed44c..485029d43428 100644
--- a/net/devlink/port.c
+++ b/net/devlink/port.c
@@ -1025,6 +1025,7 @@ void devlink_port_init(struct devlink *devlink,
 		return;
 	devlink_port->devlink = devlink;
 	INIT_LIST_HEAD(&devlink_port->region_list);
+	INIT_LIST_HEAD(&devlink_port->resource_list);
 	devlink_port->initialized = true;
 }
 EXPORT_SYMBOL_GPL(devlink_port_init);
@@ -1042,6 +1043,7 @@ EXPORT_SYMBOL_GPL(devlink_port_init);
 void devlink_port_fini(struct devlink_port *devlink_port)
 {
 	WARN_ON(!list_empty(&devlink_port->region_list));
+	WARN_ON(!list_empty(&devlink_port->resource_list));
 }
 EXPORT_SYMBOL_GPL(devlink_port_fini);
 
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index ee169a467d48..f3014ec425c4 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -532,3 +532,46 @@ void devl_resource_occ_get_unregister(struct devlink *devlink,
 	resource->occ_get_priv = NULL;
 }
 EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister);
+
+/**
+ * devl_port_resource_register - devlink port resource register
+ *
+ * @devlink_port: devlink port
+ * @resource_name: resource's name
+ * @resource_size: resource's size
+ * @resource_id: resource's id
+ * @parent_resource_id: resource's parent id
+ * @params: size parameters
+ *
+ * Generic resources should reuse the same names across drivers.
+ * Please see the generic resources list at:
+ * Documentation/networking/devlink/devlink-resource.rst
+ *
+ * Return: 0 on success, negative error code otherwise.
+ */
+int
+devl_port_resource_register(struct devlink_port *devlink_port,
+			    const char *resource_name,
+			    u64 resource_size, u64 resource_id,
+			    u64 parent_resource_id,
+			    const struct devlink_resource_size_params *params)
+{
+	return __devl_resource_register(devlink_port->devlink,
+					&devlink_port->resource_list,
+					resource_name, resource_size,
+					resource_id, parent_resource_id,
+					params);
+}
+EXPORT_SYMBOL_GPL(devl_port_resource_register);
+
+/**
+ * devl_port_resources_unregister - unregister all devlink port resources
+ *
+ * @devlink_port: devlink port
+ */
+void devl_port_resources_unregister(struct devlink_port *devlink_port)
+{
+	__devl_resources_unregister(devlink_port->devlink,
+				    &devlink_port->resource_list);
+}
+EXPORT_SYMBOL_GPL(devl_port_resources_unregister);
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 01/12] devlink: Refactor resource functions to be generic
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman, Jiri Pirko
In-Reply-To: <20260401184947.135205-1-tariqt@nvidia.com>

From: Or Har-Toov <ohartoov@nvidia.com>

Currently the resource functions take devlink pointer as parameter
and take the resource list from there.
Allow resource functions to work with other resource lists that will
be added in next patches and not only with the devlink's resource list.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Shay Drori <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
 include/net/devlink.h  |   2 +-
 net/devlink/resource.c | 114 ++++++++++++++++++++++++++---------------
 2 files changed, 73 insertions(+), 43 deletions(-)

diff --git a/include/net/devlink.h b/include/net/devlink.h
index 3038af6ec017..f5439d050eb0 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -1885,7 +1885,7 @@ int devl_resource_register(struct devlink *devlink,
 			   u64 resource_size,
 			   u64 resource_id,
 			   u64 parent_resource_id,
-			   const struct devlink_resource_size_params *size_params);
+			   const struct devlink_resource_size_params *params);
 void devl_resources_unregister(struct devlink *devlink);
 void devlink_resources_unregister(struct devlink *devlink);
 int devl_resource_size_get(struct devlink *devlink,
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index 351835a710b1..ee169a467d48 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -36,15 +36,16 @@ struct devlink_resource {
 };
 
 static struct devlink_resource *
-devlink_resource_find(struct devlink *devlink,
-		      struct devlink_resource *resource, u64 resource_id)
+__devlink_resource_find(struct list_head *resource_list_head,
+			struct devlink_resource *resource,
+			u64 resource_id)
 {
 	struct list_head *resource_list;
 
 	if (resource)
 		resource_list = &resource->resource_list;
 	else
-		resource_list = &devlink->resource_list;
+		resource_list = resource_list_head;
 
 	list_for_each_entry(resource, resource_list, list) {
 		struct devlink_resource *child_resource;
@@ -52,14 +53,23 @@ devlink_resource_find(struct devlink *devlink,
 		if (resource->id == resource_id)
 			return resource;
 
-		child_resource = devlink_resource_find(devlink, resource,
-						       resource_id);
+		child_resource = __devlink_resource_find(resource_list_head,
+							 resource,
+							 resource_id);
 		if (child_resource)
 			return child_resource;
 	}
 	return NULL;
 }
 
+static struct devlink_resource *
+devlink_resource_find(struct devlink *devlink,
+		      struct devlink_resource *resource, u64 resource_id)
+{
+	return __devlink_resource_find(&devlink->resource_list,
+				       resource, resource_id);
+}
+
 static void
 devlink_resource_validate_children(struct devlink_resource *resource)
 {
@@ -314,26 +324,12 @@ int devlink_resources_validate(struct devlink *devlink,
 	return err;
 }
 
-/**
- * devl_resource_register - devlink resource register
- *
- * @devlink: devlink
- * @resource_name: resource's name
- * @resource_size: resource's size
- * @resource_id: resource's id
- * @parent_resource_id: resource's parent id
- * @size_params: size parameters
- *
- * Generic resources should reuse the same names across drivers.
- * Please see the generic resources list at:
- * Documentation/networking/devlink/devlink-resource.rst
- */
-int devl_resource_register(struct devlink *devlink,
-			   const char *resource_name,
-			   u64 resource_size,
-			   u64 resource_id,
-			   u64 parent_resource_id,
-			   const struct devlink_resource_size_params *size_params)
+static int
+__devl_resource_register(struct devlink *devlink,
+			 struct list_head *resource_list_head,
+			 const char *resource_name, u64 resource_size,
+			 u64 resource_id, u64 parent_resource_id,
+			 const struct devlink_resource_size_params *params)
 {
 	struct devlink_resource *resource;
 	struct list_head *resource_list;
@@ -343,7 +339,8 @@ int devl_resource_register(struct devlink *devlink,
 
 	top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
 
-	resource = devlink_resource_find(devlink, NULL, resource_id);
+	resource = __devlink_resource_find(resource_list_head, NULL,
+					   resource_id);
 	if (resource)
 		return -EEXIST;
 
@@ -352,12 +349,13 @@ int devl_resource_register(struct devlink *devlink,
 		return -ENOMEM;
 
 	if (top_hierarchy) {
-		resource_list = &devlink->resource_list;
+		resource_list = resource_list_head;
 	} else {
 		struct devlink_resource *parent_resource;
 
-		parent_resource = devlink_resource_find(devlink, NULL,
-							parent_resource_id);
+		parent_resource = __devlink_resource_find(resource_list_head,
+							  NULL,
+							  parent_resource_id);
 		if (parent_resource) {
 			resource_list = &parent_resource->resource_list;
 			resource->parent = parent_resource;
@@ -372,46 +370,78 @@ int devl_resource_register(struct devlink *devlink,
 	resource->size_new = resource_size;
 	resource->id = resource_id;
 	resource->size_valid = true;
-	memcpy(&resource->size_params, size_params,
-	       sizeof(resource->size_params));
+	memcpy(&resource->size_params, params, sizeof(resource->size_params));
 	INIT_LIST_HEAD(&resource->resource_list);
 	list_add_tail(&resource->list, resource_list);
 
 	return 0;
 }
+
+/**
+ * devl_resource_register - devlink resource register
+ *
+ * @devlink: devlink
+ * @resource_name: resource's name
+ * @resource_size: resource's size
+ * @resource_id: resource's id
+ * @parent_resource_id: resource's parent id
+ * @params: size parameters
+ *
+ * Generic resources should reuse the same names across drivers.
+ * Please see the generic resources list at:
+ * Documentation/networking/devlink/devlink-resource.rst
+ *
+ * Return: 0 on success, negative error code otherwise.
+ */
+int devl_resource_register(struct devlink *devlink, const char *resource_name,
+			   u64 resource_size, u64 resource_id,
+			   u64 parent_resource_id,
+			   const struct devlink_resource_size_params *params)
+{
+	return __devl_resource_register(devlink, &devlink->resource_list,
+					resource_name, resource_size,
+					resource_id, parent_resource_id,
+					params);
+}
 EXPORT_SYMBOL_GPL(devl_resource_register);
 
-static void devlink_resource_unregister(struct devlink *devlink,
-					struct devlink_resource *resource)
+static void devlink_resource_unregister(struct devlink_resource *resource)
 {
 	struct devlink_resource *tmp, *child_resource;
 
 	list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
 				 list) {
-		devlink_resource_unregister(devlink, child_resource);
+		devlink_resource_unregister(child_resource);
 		list_del(&child_resource->list);
 		kfree(child_resource);
 	}
 }
 
-/**
- * devl_resources_unregister - free all resources
- *
- * @devlink: devlink
- */
-void devl_resources_unregister(struct devlink *devlink)
+static void
+__devl_resources_unregister(struct devlink *devlink,
+			    struct list_head *resource_list_head)
 {
 	struct devlink_resource *tmp, *child_resource;
 
 	lockdep_assert_held(&devlink->lock);
 
-	list_for_each_entry_safe(child_resource, tmp, &devlink->resource_list,
+	list_for_each_entry_safe(child_resource, tmp, resource_list_head,
 				 list) {
-		devlink_resource_unregister(devlink, child_resource);
+		devlink_resource_unregister(child_resource);
 		list_del(&child_resource->list);
 		kfree(child_resource);
 	}
 }
+
+/**
+ * devl_resources_unregister - free all resources
+ *
+ * @devlink: devlink
+ */
+void devl_resources_unregister(struct devlink *devlink)
+{
+	__devl_resources_unregister(devlink, &devlink->resource_list);
+}
 EXPORT_SYMBOL_GPL(devl_resources_unregister);
 
 /**
-- 
2.44.0


^ permalink raw reply related

* [PATCH net-next V4 00/12] devlink: add per-port resource support
From: Tariq Toukan @ 2026-04-01 18:49 UTC (permalink / raw)
  To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
	David S. Miller
  Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
	Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
	Mark Bloch, Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0),
	Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
	Shahar Shitrit, Daniel Zahka, Jacob Keller, Cosmin Ratiu,
	Parav Pandit, Shay Drori, Adithya Jayachandran, Kees Cook,
	Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
	linux-kselftest, Gal Pressman

Hi,

This series by Or adds devlink per-port resource support.
See detailed description by Or below [1].

Regards,
Tariq

[1]
Currently, devlink resources are only available at the device level.
However, some resources are inherently per-port, such as the maximum
number of subfunctions (SFs) that can be created on a specific PF port.
This limitation prevents user space from obtaining accurate per-port
capacity information.
This series adds infrastructure for per-port resources in devlink core
and implements it in the mlx5 driver to expose the max_SFs resource
on PF devlink ports.

Patch #1  refactors resource functions to be generic
Patch #2  adds port-level resource registration infrastructure
Patch #3  registers SF resource on PF port representor in mlx5
Patch #4  adds devlink port resource registration to netdevsim for testing
Patch #5  adds dump support for device-level resources
Patch #6  includes port resources in the resource dump dumpit path
Patch #7  adds port-specific option to resource dump doit path
Patch #8  adds selftest for devlink port resource doit
Patch #9  documents port-level resources and full dump
Patch #10 adds resource scope filtering to resource dump
Patch #11 adds selftest for resource dump and scope filter
Patch #12 documents resource scope filtering

Userspace patches for iproute2:
https://github.com/ohartoov/iproute2/tree/port_resources

V4:
- Link to V3:
  https://lore.kernel.org/all/20260226221916.1800227-1-tariqt@nvidia.com/
- Remove new devlink port resource command
- Add devlink resource show for all resources (devices + ports) via
  dumpit
- Add scope parameter to dump (scope dev / scope port)
- Extend the doit command with port handle option while preserving the
  legacy dev doit path

Or Har-Toov (12):
  devlink: Refactor resource functions to be generic
  devlink: Add port-level resource registration infrastructure
  net/mlx5: Register SF resource on PF port representor
  netdevsim: Add devlink port resource registration
  devlink: Add dump support for device-level resources
  devlink: Include port resources in resource dump dumpit
  devlink: Add port-specific option to resource dump doit
  selftest: netdevsim: Add devlink port resource doit test
  devlink: Document port-level resources and full dump
  devlink: Add resource scope filtering to resource dump
  selftest: netdevsim: Add resource dump and scope filter test
  devlink: Document resource scope filtering

 Documentation/netlink/specs/devlink.yaml      |  32 +-
 .../networking/devlink/devlink-resource.rst   |  70 ++++
 .../net/ethernet/mellanox/mlx5/core/devlink.h |   4 +
 .../mellanox/mlx5/core/esw/devlink_port.c     |  37 ++
 drivers/net/netdevsim/dev.c                   |  23 +-
 drivers/net/netdevsim/netdevsim.h             |   4 +
 include/net/devlink.h                         |  10 +-
 include/uapi/linux/devlink.h                  |  17 +
 net/devlink/devl_internal.h                   |   4 +
 net/devlink/netlink_gen.c                     |  24 +-
 net/devlink/netlink_gen.h                     |   8 +-
 net/devlink/port.c                            |   2 +
 net/devlink/resource.c                        | 319 +++++++++++++++---
 .../drivers/net/netdevsim/devlink.sh          |  79 ++++-
 14 files changed, 576 insertions(+), 57 deletions(-)


base-commit: f1359c240191e686614847905fc861cbda480b47
-- 
2.44.0


^ permalink raw reply

* Re: [PATCH v2] doc: Add CPU Isolation documentation
From: Randy Dunlap @ 2026-04-01 18:25 UTC (permalink / raw)
  To: Steven Rostedt, Frederic Weisbecker
  Cc: LKML, Anna-Maria Behnsen, Gabriele Monaco, Ingo Molnar,
	Jonathan Corbet, Marcelo Tosatti, Marco Crivellari, Michal Hocko,
	Paul E . McKenney, Peter Zijlstra, Phil Auld, Thomas Gleixner,
	Valentin Schneider, Vlastimil Babka, Waiman Long, linux-doc,
	Sebastian Andrzej Siewior, Bagas Sanjaya
In-Reply-To: <20260401130855.02c161d8@gandalf.local.home>



On 4/1/26 10:08 AM, Steven Rostedt wrote:
> On Wed, 1 Apr 2026 18:27:03 +0200
> Frederic Weisbecker <frederic@kernel.org> wrote:
> 
>>>> +"CPU Isolation" means leaving a CPU exclusive to a given workload
>>>> +without any undesired code interference from the kernel.
>>>> +
>>>> +Those interferences, commonly pointed out as "noise", can be triggered  
>>>
>>> nit:                                            "noise,"  
>>
>> Thanks! I have applied all your suggestions, except this one for now because I don't
>> really understand the typo rule behind. Any hint?
> 
> So this looks to be an American English thing (placing commas within the
> quote), but from what I read, British English places the comma outside the
> quote.
> 
> Here's one case I much rather go the British English way. This also means
> it's only incorrect to Americans ;-)

Yes, just leave it as is.

-- 
~Randy


^ permalink raw reply

* Re: [PATCH v2] doc: Add CPU Isolation documentation
From: Waiman Long @ 2026-04-01 17:58 UTC (permalink / raw)
  To: Frederic Weisbecker
  Cc: LKML, Anna-Maria Behnsen, Gabriele Monaco, Ingo Molnar,
	Jonathan Corbet, Marcelo Tosatti, Marco Crivellari, Michal Hocko,
	Paul E . McKenney, Peter Zijlstra, Phil Auld, Steven Rostedt,
	Thomas Gleixner, Valentin Schneider, Vlastimil Babka, linux-doc,
	Sebastian Andrzej Siewior, Bagas Sanjaya
In-Reply-To: <ac0-LzTrOJIECLoH@localhost.localdomain>

On 4/1/26 11:47 AM, Frederic Weisbecker wrote:
> Le Thu, Mar 26, 2026 at 03:17:48PM -0400, Waiman Long a écrit :
>> On 3/26/26 10:00 AM, Frederic Weisbecker wrote:
>>> nohz_full was introduced in v3.10 in 2013, which means this
>>> documentation is overdue for 13 years.
>>>
>>> Fortunately Paul wrote a part of the needed documentation a while ago,
>>> especially concerning nohz_full in Documentation/timers/no_hz.rst and
>>> also about per-CPU kthreads in
>>> Documentation/admin-guide/kernel-per-CPU-kthreads.rst
>>>
>>> Introduce a new page that gives an overview of CPU isolation in general.
>>>
>>> Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
>>> ---
>>> v2:
>>>      - Fix links and code blocks (Bagas and Sebastian)
>>>      - Isolation is not only about userspace, rephrase accordingly (Valentin)
>>>      - Paste BIOS issues suggestion from Valentin
>>>      - Include the whole rtla suite (Valentin)
>>>      - Rephrase a few details (Waiman)
>>>      - Talk about RCU induced overhead rather than slower RCU (Sebastian)
>>>
>>>    Documentation/admin-guide/cpu-isolation.rst | 357 ++++++++++++++++++++
>>>    Documentation/admin-guide/index.rst         |   1 +
>>>    2 files changed, 358 insertions(+)
>>>    create mode 100644 Documentation/admin-guide/cpu-isolation.rst
>>>
>>> diff --git a/Documentation/admin-guide/cpu-isolation.rst b/Documentation/admin-guide/cpu-isolation.rst
>>> new file mode 100644
>>> index 000000000000..886dec79b056
>>> --- /dev/null
>>> +++ b/Documentation/admin-guide/cpu-isolation.rst
>>> @@ -0,0 +1,357 @@
>>> +.. SPDX-License-Identifier: GPL-2.0
>>> +
>>> +=============
>>> +CPU Isolation
>>> +=============
>>> +
>>> +Introduction
>>> +============
>>> +
>>> +"CPU Isolation" means leaving a CPU exclusive to a given workload
>>> +without any undesired code interference from the kernel.
>>> +
>>> +Those interferences, commonly pointed out as "noise", can be triggered
>>> +by asynchronous events (interrupts, timers, scheduler preemption by
>>> +workqueues and kthreads, ...) or synchronous events (syscalls and page
>>> +faults).
>>> +
>>> +Such noise usually goes unnoticed. After all synchronous events are a
>>> +component of the requested kernel service. And asynchronous events are
>>> +either sufficiently well distributed by the scheduler when executed
>>> +as tasks or reasonably fast when executed as interrupt. The timer
>>> +interrupt can even execute 1024 times per seconds without a significant
>>> +and measurable impact most of the time.
>>> +
>>> +However some rare and extreme workloads can be quite sensitive to
>>> +those kinds of noise. This is the case, for example, with high
>>> +bandwidth network processing that can't afford losing a single packet
>>> +or very low latency network processing. Typically those usecases
>>> +involve DPDK, bypassing the kernel networking stack and performing
>>> +direct access to the networking device from userscace.
>> As also pointed by by Sashiko, there is a typo "userscace" -> "userspace".
>> There are also typos reported in
>>
>> https://sashiko.dev/#/patchset/20260326140055.41555-1-frederic%40kernel.org
> Thanks!
>
> What do you think about these lines of Sashiko's review:
>
> """
> Does this script violate the cgroup v2 "no internal process" constraint?
> By enabling the cpuset controller on the test directory's
> cgroup.subtree_control file, the cgroup cannot also contain processes.
> """
>
> That is confusing me...

I would say that the "no internal process" is a suggestion for the 
cgroup setup. The real world is actually more complicated. So I will 
just ignore that.

Cheers,
Longman


^ permalink raw reply

* Re: [PATCH v4 09/13] ima: Add support for staging measurements with prompt
From: steven chen @ 2026-04-01 17:52 UTC (permalink / raw)
  To: Roberto Sassu, corbet, skhan, zohar, dmitry.kasatkin,
	eric.snowberg, paul, jmorris, serge
  Cc: linux-doc, linux-kernel, linux-integrity, linux-security-module,
	gregorylumen, nramas, Roberto Sassu, steven chen
In-Reply-To: <19a1815a1222bd78f6bfde30f60b60ebfacb65aa.camel@huaweicloud.com>

On 3/27/2026 9:45 AM, Roberto Sassu wrote:
> On Thu, 2026-03-26 at 15:44 -0700, steven chen wrote:
>> On 3/26/2026 10:30 AM, Roberto Sassu wrote:
>>> From: Roberto Sassu <roberto.sassu@huawei.com>
>>>
>>> Introduce the ability of staging the IMA measurement list and deleting them
>>> with a prompt.
>>>
>>> Staging means moving the current content of the measurement list to a
>>> separate location, and allowing users to read and delete it. This causes
>>> the measurement list to be atomically truncated before new measurements can
>>> be added. Staging can be done only once at a time. In the event of kexec(),
>>> staging is reverted and staged entries will be carried over to the new
>>> kernel.
>>>
>>> Introduce ascii_runtime_measurements_<algo>_staged and
>>> binary_runtime_measurements_<algo>_staged interfaces to stage and delete
>>> the measurements. Use 'echo A > <IMA interface>' and
>>> 'echo D > <IMA interface>' to respectively stage and delete the entire
>>> measurements list. Locking of these interfaces is also mediated with a call
>>> to _ima_measurements_open() and with ima_measurements_release().
>>>
>>> Implement the staging functionality by introducing the new global
>>> measurements list ima_measurements_staged, and ima_queue_stage() and
>>> ima_queue_delete_staged_all() to respectively move measurements from the
>>> current measurements list to the staged one, and to move staged
>>> measurements to the ima_measurements_trim list for deletion. Introduce
>>> ima_queue_delete() to delete the measurements.
>>>
>>> Finally, introduce the BINARY_STAGED AND BINARY_FULL binary measurements
>>> list types, to maintain the counters and the binary size of staged
>>> measurements and the full measurements list (including entries that were
>>> staged). BINARY still represents the current binary measurements list.
>>>
>>> Use the binary size for the BINARY + BINARY_STAGED types in
>>> ima_add_kexec_buffer(), since both measurements list types are copied to
>>> the secondary kernel during kexec. Use BINARY_FULL in
>>> ima_measure_kexec_event(), to generate a critical data record.
>>>
>>> It should be noted that the BINARY_FULL counter is not passed through
>>> kexec. Thus, the number of entries included in the kexec critical data
>>> records refers to the entries since the previous kexec records.
>>>
>>> Note: This code derives from the Alt-IMA Huawei project, whose license is
>>>         GPL-2.0 OR MIT.
>>>
>>> Link: https://github.com/linux-integrity/linux/issues/1
>>> Suggested-by: Gregory Lumen <gregorylumen@linux.microsoft.com> (staging revert)
>>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>>> ---
>>>    security/integrity/ima/Kconfig     |  13 +++
>>>    security/integrity/ima/ima.h       |   8 +-
>>>    security/integrity/ima/ima_fs.c    | 167 ++++++++++++++++++++++++++---
>>>    security/integrity/ima/ima_kexec.c |  22 +++-
>>>    security/integrity/ima/ima_queue.c |  97 ++++++++++++++++-
>>>    5 files changed, 286 insertions(+), 21 deletions(-)
>>>
>>> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
>>> index 976e75f9b9ba..e714726f3384 100644
>>> --- a/security/integrity/ima/Kconfig
>>> +++ b/security/integrity/ima/Kconfig
>>> @@ -332,4 +332,17 @@ config IMA_KEXEC_EXTRA_MEMORY_KB
>>>    	  If set to the default value of 0, an extra half page of memory for those
>>>    	  additional measurements will be allocated.
>>>    
>>> +config IMA_STAGING
>>> +	bool "Support for staging the measurements list"
>>> +	default y
>>> +	help
>>> +	  Add support for staging the measurements list.
>>> +
>>> +	  It allows user space to stage the measurements list for deletion and
>>> +	  to delete the staged measurements after confirmation.
>>> +
>>> +	  On kexec, staging is reverted and staged measurements are prepended
>>> +	  to the current measurements list when measurements are copied to the
>>> +	  secondary kernel.
>>> +
>>>    endif
>>> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
>>> index 97b7d6024b5d..65db152a0a24 100644
>>> --- a/security/integrity/ima/ima.h
>>> +++ b/security/integrity/ima/ima.h
>>> @@ -30,9 +30,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
>>>    
>>>    /*
>>>     * BINARY: current binary measurements list
>>> + * BINARY_STAGED: staged binary measurements list
>>> + * BINARY_FULL: binary measurements list since IMA init (lost after kexec)
>>>     */
>>>    enum binary_lists {
>>> -	BINARY, BINARY__LAST
>>> +	BINARY, BINARY_STAGED, BINARY_FULL, BINARY__LAST
>>>    };
>>>    
>>>    /* digest size for IMA, fits SHA1 or MD5 */
>>> @@ -125,6 +127,7 @@ struct ima_queue_entry {
>>>    	struct ima_template_entry *entry;
>>>    };
>>>    extern struct list_head ima_measurements;	/* list of all measurements */
>>> +extern struct list_head ima_measurements_staged; /* list of staged meas. */
>>>    
>>>    /* Some details preceding the binary serialized measurement list */
>>>    struct ima_kexec_hdr {
>>> @@ -314,6 +317,8 @@ struct ima_template_desc *ima_template_desc_current(void);
>>>    struct ima_template_desc *ima_template_desc_buf(void);
>>>    struct ima_template_desc *lookup_template_desc(const char *name);
>>>    bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
>>> +int ima_queue_stage(void);
>>> +int ima_queue_staged_delete_all(void);
>>>    int ima_restore_measurement_entry(struct ima_template_entry *entry);
>>>    int ima_restore_measurement_list(loff_t bufsize, void *buf);
>>>    int ima_measurements_show(struct seq_file *m, void *v);
>>> @@ -334,6 +339,7 @@ extern spinlock_t ima_queue_lock;
>>>    extern atomic_long_t ima_num_entries[BINARY__LAST];
>>>    extern atomic_long_t ima_num_violations;
>>>    extern struct hlist_head __rcu *ima_htable;
>>> +extern struct mutex ima_extend_list_mutex;
>>>    
>>>    static inline unsigned int ima_hash_key(u8 *digest)
>>>    {
>>> diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
>>> index 7709a4576322..39d9128e9f22 100644
>>> --- a/security/integrity/ima/ima_fs.c
>>> +++ b/security/integrity/ima/ima_fs.c
>>> @@ -24,6 +24,13 @@
>>>    
>>>    #include "ima.h"
>>>    
>>> +/*
>>> + * Requests:
>>> + * 'A\n': stage the entire measurements list
>>> + * 'D\n': delete all staged measurements
>>> + */
>>> +#define STAGED_REQ_LENGTH 21
>>> +
>>>    static DEFINE_MUTEX(ima_write_mutex);
>>>    static DEFINE_MUTEX(ima_measure_mutex);
>>>    static long ima_measure_users;
>>> @@ -97,6 +104,11 @@ static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
>>>    	return _ima_measurements_start(m, pos, &ima_measurements);
>>>    }
>>>    
>>> +static void *ima_measurements_staged_start(struct seq_file *m, loff_t *pos)
>>> +{
>>> +	return _ima_measurements_start(m, pos, &ima_measurements_staged);
>>> +}
>>> +
>>>    static void *_ima_measurements_next(struct seq_file *m, void *v, loff_t *pos,
>>>    				    struct list_head *head)
>>>    {
>>> @@ -118,6 +130,12 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
>>>    	return _ima_measurements_next(m, v, pos, &ima_measurements);
>>>    }
>>>    
>>> +static void *ima_measurements_staged_next(struct seq_file *m, void *v,
>>> +					  loff_t *pos)
>>> +{
>>> +	return _ima_measurements_next(m, v, pos, &ima_measurements_staged);
>>> +}
>>> +
>>>    static void ima_measurements_stop(struct seq_file *m, void *v)
>>>    {
>>>    }
>>> @@ -283,6 +301,68 @@ static const struct file_operations ima_measurements_ops = {
>>>    	.release = ima_measurements_release,
>>>    };
>>>    
>>> +static const struct seq_operations ima_measurments_staged_seqops = {
>>> +	.start = ima_measurements_staged_start,
>>> +	.next = ima_measurements_staged_next,
>>> +	.stop = ima_measurements_stop,
>>> +	.show = ima_measurements_show
>>> +};
>>> +
>>> +static int ima_measurements_staged_open(struct inode *inode, struct file *file)
>>> +{
>>> +	return _ima_measurements_open(inode, file,
>>> +				      &ima_measurments_staged_seqops);
>>> +}
>>> +
>>> +static ssize_t ima_measurements_staged_write(struct file *file,
>>> +					     const char __user *buf,
>>> +					     size_t datalen, loff_t *ppos)
>>> +{
>>> +	char req[STAGED_REQ_LENGTH];
>>> +	int ret;
>>> +
>>> +	if (*ppos > 0 || datalen < 2 || datalen > STAGED_REQ_LENGTH)
>>> +		return -EINVAL;
>>> +
>>> +	if (copy_from_user(req, buf, datalen) != 0)
>>> +		return -EFAULT;
>>> +
>>> +	if (req[datalen - 1] != '\n')
>>> +		return -EINVAL;
>>> +
>>> +	req[datalen - 1] = '\0';
>>> +
>>> +	switch (req[0]) {
>>> +	case 'A':
>>> +		if (datalen != 2)
>>> +			return -EINVAL;
>>> +
>>> +		ret = ima_queue_stage();
>>> +		break;
>>> +	case 'D':
>>> +		if (datalen != 2)
>>> +			return -EINVAL;
>>> +
>>> +		ret = ima_queue_staged_delete_all();
>>> +		break;
>> I think the following two steps may not work because of race condition:
>>
>> step1: ret = ima_queue_stage(); //this will put all logs in active list into staged list;
>> step2: ret = ima_queue_staged_delete_all(); //this will delete all logs in staged list;
>>
>> The following is the step of race condition:
>>       1. current active log list LA1;
>>       2. user agent read the TPM quote QA1 match list LA1;
>>       3. new event NewLog is added into active log list LA1+NewLog
>>       4. user agent call ima_queue_stage() and generated staged list
>>          including LA1+NewLog.
>>       5. user agent call ima_queue_staged_delete_all();
>>          The new log NewLog in step 3 is also deleted
> Please refer to the documentation patch which explains the intended
> workflow of this approach (Remote Attestation Agent Workflow).
>
> Roberto
So the user agent needs to deeply involve measurement list management:
in user space, user agent need to maintain two lists
user agent is more complicated in this case

Steven

>> Next time the attestation will fail if using the active log list in the
>> kernel.
>>
>> Thanks,
>>
>> Steven
>>
>>> +	default:
>>> +		ret = -EINVAL;
>>> +	}
>>> +
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	return datalen;
>>> +}
>>> +
>>> +static const struct file_operations ima_measurements_staged_ops = {
>>> +	.open = ima_measurements_staged_open,
>>> +	.read = seq_read,
>>> +	.write = ima_measurements_staged_write,
>>> +	.llseek = seq_lseek,
>>> +	.release = ima_measurements_release,
>>> +};
>>> +
>>>    void ima_print_digest(struct seq_file *m, u8 *digest, u32 size)
>>>    {
>>>    	u32 i;
>>> @@ -356,6 +436,28 @@ static const struct file_operations ima_ascii_measurements_ops = {
>>>    	.release = ima_measurements_release,
>>>    };
>>>    
>>> +static const struct seq_operations ima_ascii_measurements_staged_seqops = {
>>> +	.start = ima_measurements_staged_start,
>>> +	.next = ima_measurements_staged_next,
>>> +	.stop = ima_measurements_stop,
>>> +	.show = ima_ascii_measurements_show
>>> +};
>>> +
>>> +static int ima_ascii_measurements_staged_open(struct inode *inode,
>>> +					      struct file *file)
>>> +{
>>> +	return _ima_measurements_open(inode, file,
>>> +				      &ima_ascii_measurements_staged_seqops);
>>> +}
>>> +
>>> +static const struct file_operations ima_ascii_measurements_staged_ops = {
>>> +	.open = ima_ascii_measurements_staged_open,
>>> +	.read = seq_read,
>>> +	.write = ima_measurements_staged_write,
>>> +	.llseek = seq_lseek,
>>> +	.release = ima_measurements_release,
>>> +};
>>> +
>>>    static ssize_t ima_read_policy(char *path)
>>>    {
>>>    	void *data = NULL;
>>> @@ -459,10 +561,21 @@ static const struct seq_operations ima_policy_seqops = {
>>>    };
>>>    #endif
>>>    
>>> -static int __init create_securityfs_measurement_lists(void)
>>> +static int __init create_securityfs_measurement_lists(bool staging)
>>>    {
>>> +	const struct file_operations *ascii_ops = &ima_ascii_measurements_ops;
>>> +	const struct file_operations *binary_ops = &ima_measurements_ops;
>>> +	mode_t permissions = S_IRUSR | S_IRGRP;
>>> +	const char *file_suffix = "";
>>>    	int count = NR_BANKS(ima_tpm_chip);
>>>    
>>> +	if (staging) {
>>> +		ascii_ops = &ima_ascii_measurements_staged_ops;
>>> +		binary_ops = &ima_measurements_staged_ops;
>>> +		file_suffix = "_staged";
>>> +		permissions |= (S_IWUSR | S_IWGRP);
>>> +	}
>>> +
>>>    	if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip))
>>>    		count++;
>>>    
>>> @@ -473,29 +586,32 @@ static int __init create_securityfs_measurement_lists(void)
>>>    
>>>    		if (algo == HASH_ALGO__LAST)
>>>    			snprintf(file_name, sizeof(file_name),
>>> -				 "ascii_runtime_measurements_tpm_alg_%x",
>>> -				 ima_tpm_chip->allocated_banks[i].alg_id);
>>> +				 "ascii_runtime_measurements_tpm_alg_%x%s",
>>> +				 ima_tpm_chip->allocated_banks[i].alg_id,
>>> +				 file_suffix);
>>>    		else
>>>    			snprintf(file_name, sizeof(file_name),
>>> -				 "ascii_runtime_measurements_%s",
>>> -				 hash_algo_name[algo]);
>>> -		dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
>>> +				 "ascii_runtime_measurements_%s%s",
>>> +				 hash_algo_name[algo], file_suffix);
>>> +		dentry = securityfs_create_file(file_name, permissions,
>>>    						ima_dir, (void *)(uintptr_t)i,
>>> -						&ima_ascii_measurements_ops);
>>> +						ascii_ops);
>>>    		if (IS_ERR(dentry))
>>>    			return PTR_ERR(dentry);
>>>    
>>>    		if (algo == HASH_ALGO__LAST)
>>>    			snprintf(file_name, sizeof(file_name),
>>> -				 "binary_runtime_measurements_tpm_alg_%x",
>>> -				 ima_tpm_chip->allocated_banks[i].alg_id);
>>> +				 "binary_runtime_measurements_tpm_alg_%x%s",
>>> +				 ima_tpm_chip->allocated_banks[i].alg_id,
>>> +				 file_suffix);
>>>    		else
>>>    			snprintf(file_name, sizeof(file_name),
>>> -				 "binary_runtime_measurements_%s",
>>> -				 hash_algo_name[algo]);
>>> -		dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
>>> +				 "binary_runtime_measurements_%s%s",
>>> +				 hash_algo_name[algo], file_suffix);
>>> +
>>> +		dentry = securityfs_create_file(file_name, permissions,
>>>    						ima_dir, (void *)(uintptr_t)i,
>>> -						&ima_measurements_ops);
>>> +						binary_ops);
>>>    		if (IS_ERR(dentry))
>>>    			return PTR_ERR(dentry);
>>>    	}
>>> @@ -503,6 +619,23 @@ static int __init create_securityfs_measurement_lists(void)
>>>    	return 0;
>>>    }
>>>    
>>> +static int __init create_securityfs_staging_links(void)
>>> +{
>>> +	struct dentry *dentry;
>>> +
>>> +	dentry = securityfs_create_symlink("binary_runtime_measurements_staged",
>>> +		ima_dir, "binary_runtime_measurements_sha1_staged", NULL);
>>> +	if (IS_ERR(dentry))
>>> +		return PTR_ERR(dentry);
>>> +
>>> +	dentry = securityfs_create_symlink("ascii_runtime_measurements_staged",
>>> +		ima_dir, "ascii_runtime_measurements_sha1_staged", NULL);
>>> +	if (IS_ERR(dentry))
>>> +		return PTR_ERR(dentry);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>>    /*
>>>     * ima_open_policy: sequentialize access to the policy file
>>>     */
>>> @@ -595,7 +728,13 @@ int __init ima_fs_init(void)
>>>    		goto out;
>>>    	}
>>>    
>>> -	ret = create_securityfs_measurement_lists();
>>> +	ret = create_securityfs_measurement_lists(false);
>>> +	if (ret == 0 && IS_ENABLED(CONFIG_IMA_STAGING)) {
>>> +		ret = create_securityfs_measurement_lists(true);
>>> +		if (ret == 0)
>>> +			ret = create_securityfs_staging_links();
>>> +	}
>>> +
>>>    	if (ret != 0)
>>>    		goto out;
>>>    
>>> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
>>> index d7d0fb639d99..d5503dd5cc9b 100644
>>> --- a/security/integrity/ima/ima_kexec.c
>>> +++ b/security/integrity/ima/ima_kexec.c
>>> @@ -42,8 +42,8 @@ void ima_measure_kexec_event(const char *event_name)
>>>    	long len;
>>>    	int n;
>>>    
>>> -	buf_size = ima_get_binary_runtime_size(BINARY);
>>> -	len = atomic_long_read(&ima_num_entries[BINARY]);
>>> +	buf_size = ima_get_binary_runtime_size(BINARY_FULL);
>>> +	len = atomic_long_read(&ima_num_entries[BINARY_FULL]);
>>>    
>>>    	n = scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN,
>>>    		      "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;"
>>> @@ -106,13 +106,26 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
>>>    
>>>    	memset(&khdr, 0, sizeof(khdr));
>>>    	khdr.version = 1;
>>> -	/* This is an append-only list, no need to hold the RCU read lock */
>>> -	list_for_each_entry_rcu(qe, &ima_measurements, later, true) {
>>> +	/* It can race with ima_queue_stage() and ima_queue_delete_staged(). */
>>> +	mutex_lock(&ima_extend_list_mutex);
>>> +
>>> +	list_for_each_entry_rcu(qe, &ima_measurements_staged, later,
>>> +				lockdep_is_held(&ima_extend_list_mutex)) {
>>>    		ret = ima_dump_measurement(&khdr, qe);
>>>    		if (ret < 0)
>>>    			break;
>>>    	}
>>>    
>>> +	list_for_each_entry_rcu(qe, &ima_measurements, later,
>>> +				lockdep_is_held(&ima_extend_list_mutex)) {
>>> +		if (!ret)
>>> +			ret = ima_dump_measurement(&khdr, qe);
>>> +		if (ret < 0)
>>> +			break;
>>> +	}
>>> +
>>> +	mutex_unlock(&ima_extend_list_mutex);
>>> +
>>>    	/*
>>>    	 * fill in reserved space with some buffer details
>>>    	 * (eg. version, buffer size, number of measurements)
>>> @@ -167,6 +180,7 @@ void ima_add_kexec_buffer(struct kimage *image)
>>>    		extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
>>>    
>>>    	binary_runtime_size = ima_get_binary_runtime_size(BINARY) +
>>> +			      ima_get_binary_runtime_size(BINARY_STAGED) +
>>>    			      extra_memory;
>>>    
>>>    	if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
>>> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
>>> index b6d10dceb669..50519ed837d4 100644
>>> --- a/security/integrity/ima/ima_queue.c
>>> +++ b/security/integrity/ima/ima_queue.c
>>> @@ -26,6 +26,7 @@
>>>    static struct tpm_digest *digests;
>>>    
>>>    LIST_HEAD(ima_measurements);	/* list of all measurements */
>>> +LIST_HEAD(ima_measurements_staged); /* list of staged measurements */
>>>    #ifdef CONFIG_IMA_KEXEC
>>>    static unsigned long binary_runtime_size[BINARY__LAST];
>>>    #else
>>> @@ -45,11 +46,11 @@ atomic_long_t ima_num_violations = ATOMIC_LONG_INIT(0);
>>>    /* key: inode (before secure-hashing a file) */
>>>    struct hlist_head __rcu *ima_htable;
>>>    
>>> -/* mutex protects atomicity of extending measurement list
>>> +/* mutex protects atomicity of extending and staging measurement list
>>>     * and extending the TPM PCR aggregate. Since tpm_extend can take
>>>     * long (and the tpm driver uses a mutex), we can't use the spinlock.
>>>     */
>>> -static DEFINE_MUTEX(ima_extend_list_mutex);
>>> +DEFINE_MUTEX(ima_extend_list_mutex);
>>>    
>>>    /*
>>>     * Used internally by the kernel to suspend measurements.
>>> @@ -174,12 +175,16 @@ static int ima_add_digest_entry(struct ima_template_entry *entry,
>>>    				lockdep_is_held(&ima_extend_list_mutex));
>>>    
>>>    	atomic_long_inc(&ima_num_entries[BINARY]);
>>> +	atomic_long_inc(&ima_num_entries[BINARY_FULL]);
>>> +
>>>    	if (update_htable) {
>>>    		key = ima_hash_key(entry->digests[ima_hash_algo_idx].digest);
>>>    		hlist_add_head_rcu(&qe->hnext, &htable[key]);
>>>    	}
>>>    
>>>    	ima_update_binary_runtime_size(entry, BINARY);
>>> +	ima_update_binary_runtime_size(entry, BINARY_FULL);
>>> +
>>>    	return 0;
>>>    }
>>>    
>>> @@ -280,6 +285,94 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
>>>    	return result;
>>>    }
>>>    
>>> +int ima_queue_stage(void)
>>> +{
>>> +	int ret = 0;
>>> +
>>> +	mutex_lock(&ima_extend_list_mutex);
>>> +	if (!list_empty(&ima_measurements_staged)) {
>>> +		ret = -EEXIST;
>>> +		goto out_unlock;
>>> +	}
>>> +
>>> +	if (list_empty(&ima_measurements)) {
>>> +		ret = -ENOENT;
>>> +		goto out_unlock;
>>> +	}
>>> +
>>> +	list_replace(&ima_measurements, &ima_measurements_staged);
>>> +	INIT_LIST_HEAD(&ima_measurements);
>>> +
>>> +	atomic_long_set(&ima_num_entries[BINARY_STAGED],
>>> +			atomic_long_read(&ima_num_entries[BINARY]));
>>> +	atomic_long_set(&ima_num_entries[BINARY], 0);
>>> +
>>> +	if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
>>> +		binary_runtime_size[BINARY_STAGED] =
>>> +					binary_runtime_size[BINARY];
>>> +		binary_runtime_size[BINARY] = 0;
>>> +	}
>>> +out_unlock:
>>> +	mutex_unlock(&ima_extend_list_mutex);
>>> +	return ret;
>>> +}
>>> +
>>> +static void ima_queue_delete(struct list_head *head);
>>> +
>>> +int ima_queue_staged_delete_all(void)
>>> +{
>>> +	LIST_HEAD(ima_measurements_trim);
>>> +
>>> +	mutex_lock(&ima_extend_list_mutex);
>>> +	if (list_empty(&ima_measurements_staged)) {
>>> +		mutex_unlock(&ima_extend_list_mutex);
>>> +		return -ENOENT;
>>> +	}
>>> +
>>> +	list_replace(&ima_measurements_staged, &ima_measurements_trim);
>>> +	INIT_LIST_HEAD(&ima_measurements_staged);
>>> +
>>> +	atomic_long_set(&ima_num_entries[BINARY_STAGED], 0);
>>> +
>>> +	if (IS_ENABLED(CONFIG_IMA_KEXEC))
>>> +		binary_runtime_size[BINARY_STAGED] = 0;
>>> +
>>> +	mutex_unlock(&ima_extend_list_mutex);
>>> +
>>> +	ima_queue_delete(&ima_measurements_trim);
>>> +	return 0;
>>> +}
>>> +
>>> +static void ima_queue_delete(struct list_head *head)
>>> +{
>>> +	struct ima_queue_entry *qe, *qe_tmp;
>>> +	unsigned int i;
>>> +
>>> +	list_for_each_entry_safe(qe, qe_tmp, head, later) {
>>> +		/*
>>> +		 * Safe to free template_data here without synchronize_rcu()
>>> +		 * because the only htable reader, ima_lookup_digest_entry(),
>>> +		 * accesses only entry->digests, not template_data. If new
>>> +		 * htable readers are added that access template_data, a
>>> +		 * synchronize_rcu() is required here.
>>> +		 */
>>> +		for (i = 0; i < qe->entry->template_desc->num_fields; i++) {
>>> +			kfree(qe->entry->template_data[i].data);
>>> +			qe->entry->template_data[i].data = NULL;
>>> +			qe->entry->template_data[i].len = 0;
>>> +		}
>>> +
>>> +		list_del(&qe->later);
>>> +
>>> +		/* No leak if condition is false, referenced by ima_htable. */
>>> +		if (IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) {
>>> +			kfree(qe->entry->digests);
>>> +			kfree(qe->entry);
>>> +			kfree(qe);
>>> +		}
>>> +	}
>>> +}
>>> +
>>>    int ima_restore_measurement_entry(struct ima_template_entry *entry)
>>>    {
>>>    	int result = 0;



^ permalink raw reply

* Re: [PATCH v4 11/13] ima: Support staging and deleting N measurements entries
From: steven chen @ 2026-04-01 17:48 UTC (permalink / raw)
  To: Roberto Sassu, corbet, skhan, zohar, dmitry.kasatkin,
	eric.snowberg, paul, jmorris, serge
  Cc: linux-doc, linux-kernel, linux-integrity, linux-security-module,
	gregorylumen, nramas, Roberto Sassu, steven chen
In-Reply-To: <af6aa732b85af36e07e4a82b29170e80b13dc7c4.camel@huaweicloud.com>

On 3/27/2026 10:02 AM, Roberto Sassu wrote:
> On Thu, 2026-03-26 at 16:19 -0700, steven chen wrote:
>> On 3/26/2026 10:30 AM, Roberto Sassu wrote:
>>> From: Roberto Sassu <roberto.sassu@huawei.com>
>>>
>>> Add support for sending a value N between 1 and ULONG_MAX to the staging
>>> interface. This value represents the number of measurements that should be
>>> deleted from the current measurements list.
>>>
>>> This staging method allows the remote attestation agents to easily separate
>>> the measurements that were verified (staged and deleted) from those that
>>> weren't due to the race between taking a TPM quote and reading the
>>> measurements list.
>>>
>>> In order to minimize the locking time of ima_extend_list_mutex, deleting
>>> N entries is realized by staging the entire current measurements list
>>> (with the lock), by determining the N-th staged entry (without the lock),
>>> and by splicing the entries in excess back to the current measurements list
>>> (with the lock). Finally, the N entries are deleted (without the lock).
>>>
>>> Flushing the hash table is not supported for N entries, since it would
>>> require removing the N entries one by one from the hash table under the
>>> ima_extend_list_mutex lock, which would increase the locking time.
>>>
>>> The ima_extend_list_mutex lock is necessary in ima_dump_measurement_list()
>>> because ima_queue_staged_delete_partial() uses __list_cut_position() to
>>> modify ima_measurements_staged, for which no RCU-safe variant exists. For
>>> the staging with prompt flavor alone, list_replace_rcu() could have been
>>> used instead, but since both flavors share the same kexec serialization
>>> path, the mutex is required regardless.
>>>
>>> Link: https://github.com/linux-integrity/linux/issues/1
>>> Suggested-by: Steven Chen <chenste@linux.microsoft.com>
>>> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>>> ---
>>>    security/integrity/ima/Kconfig     |  3 ++
>>>    security/integrity/ima/ima.h       |  1 +
>>>    security/integrity/ima/ima_fs.c    | 22 +++++++++-
>>>    security/integrity/ima/ima_queue.c | 70 ++++++++++++++++++++++++++++++
>>>    4 files changed, 95 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
>>> index e714726f3384..6ddb4e77bff5 100644
>>> --- a/security/integrity/ima/Kconfig
>>> +++ b/security/integrity/ima/Kconfig
>>> @@ -341,6 +341,9 @@ config IMA_STAGING
>>>    	  It allows user space to stage the measurements list for deletion and
>>>    	  to delete the staged measurements after confirmation.
>>>    
>>> +	  Or, alternatively, it allows user space to specify N measurements
>>> +	  entries to be deleted.
>>> +
>>>    	  On kexec, staging is reverted and staged measurements are prepended
>>>    	  to the current measurements list when measurements are copied to the
>>>    	  secondary kernel.
>>> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
>>> index 699b735dec7d..de0693fce53c 100644
>>> --- a/security/integrity/ima/ima.h
>>> +++ b/security/integrity/ima/ima.h
>>> @@ -319,6 +319,7 @@ struct ima_template_desc *lookup_template_desc(const char *name);
>>>    bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
>>>    int ima_queue_stage(void);
>>>    int ima_queue_staged_delete_all(void);
>>> +int ima_queue_staged_delete_partial(unsigned long req_value);
>>>    int ima_restore_measurement_entry(struct ima_template_entry *entry);
>>>    int ima_restore_measurement_list(loff_t bufsize, void *buf);
>>>    int ima_measurements_show(struct seq_file *m, void *v);
>>> diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
>>> index 39d9128e9f22..eb3f343c1138 100644
>>> --- a/security/integrity/ima/ima_fs.c
>>> +++ b/security/integrity/ima/ima_fs.c
>>> @@ -28,6 +28,7 @@
>>>     * Requests:
>>>     * 'A\n': stage the entire measurements list
>>>     * 'D\n': delete all staged measurements
>>> + * '[1, ULONG_MAX]\n' delete N measurements entries
>>>     */
>>>    #define STAGED_REQ_LENGTH 21
>>>    
>>> @@ -319,6 +320,7 @@ static ssize_t ima_measurements_staged_write(struct file *file,
>>>    					     size_t datalen, loff_t *ppos)
>>>    {
>>>    	char req[STAGED_REQ_LENGTH];
>>> +	unsigned long req_value;
>>>    	int ret;
>>>    
>>>    	if (*ppos > 0 || datalen < 2 || datalen > STAGED_REQ_LENGTH)
>>> @@ -346,7 +348,25 @@ static ssize_t ima_measurements_staged_write(struct file *file,
>>>    		ret = ima_queue_staged_delete_all();
>>>    		break;
>>>    	default:
>>> -		ret = -EINVAL;
>>> +		if (ima_flush_htable) {
>>> +			pr_debug("Deleting staged N measurements not supported when flushing the hash table is requested\n");
>>> +			return -EINVAL;
>>> +		}
>>> +
>>> +		ret = kstrtoul(req, 10, &req_value);
>>> +		if (ret < 0)
>>> +			return ret;
>>> +
>>> +		if (req_value == 0) {
>>> +			pr_debug("Must delete at least one entry\n");
>>> +			return -EINVAL;
>>> +		}
>>> +
>>> +		ret = ima_queue_stage();
>>> +		if (ret < 0)
>>> +			return ret;
>>> +
>>> +		ret = ima_queue_staged_delete_partial(req_value);
>> The default processing is "Trim N" idea plus performance improvement.
>>
>> Here do everything in one time. And this is what I said in v3.
>>
>> [PATCH v3 1/3] ima: Remove ima_h_table structure
>> <https://lore.kernel.org/linux-integrity/c61aeaa79929a98cb3a6d30835972891fac3570f.camel@linux.ibm.com/T/#t>
> In your approach you do:
>
> lock ima_extend_measure_list_mutex
> scan entries until N
> cut list staged -> trim
> unlock ima_extend_measure_list_mutex
>
>
> In my approach I do:
> lock ima_extend_measure_list_mutex
> list replace active -> staged
> unlock ima_extend_measure_list_mutex
>
> scan entries until N
>
> lock ima_extend_measure_list_mutex
> cut list staged -> trim
> splice staged ->active
> unlock ima_extend_measure_list_mutex
>
> So, I guess if you refer to less user space locking time, you mean one
> lock/unlock and one list replace + list splice less in your solution.
>
> In exchange, you propose to hold the lock in the kernel while scanning
> N. I think it is a significant increase of kernel locking time vs a
> negligible increase of user space locking time (in the kernel, all
> processes need to wait for the ima_extend_measure_list_mutex to be
> released, in user space it is just the agent waiting).
>
> Roberto

Please the version 5:

[PATCH v5 0/3] Trim N entries of IMA event logs 
<https://lore.kernel.org/linux-integrity/20260401172956.4581-1-chenste@linux.microsoft.com/T/#t>

Scanning N is moved out of the lock period.
"Trim N" proposal has less lock time than "Staging and deleting" proposal.
"Trim N" proposal has much less code than "Staging and deleting" proposal.
"Trim N" proposal user space operation is more simple than "Staging and 
deleting".

Steven

>> The important two parts of trimming is "trim N" and performance improvement.
>>
>> The performance improvement include two parts:
>>       hash table staging
>>       active log list staging
>>
>> And I think "Trim N" plus performance improvement is the right direction
>> to go.
>> Lots of code for two steps "stage and trim" "stage" part can be removed.
>>
>> Also race condition may happen if not holding the list all time in user
>> space
>> during attestation period: from stage, read list, attestation and trimming.
>>
>> So in order to improve the above user space lock time, "Trim T:N" can be
>> used
>> not to hold list long in user space during attestation.
>>
>> For Trim T:N, T represent total log trimmed since system boot up. Please
>> refer to
>> https://lore.kernel.org/linux-integrity/20260205235849.7086-1-chenste@linux.microsoft.com/T/#t
>>
>> Thanks,
>>
>> Steven
>>>    	}
>>>    
>>>    	if (ret < 0)
>>> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
>>> index f5c18acfbc43..4fb557d61a88 100644
>>> --- a/security/integrity/ima/ima_queue.c
>>> +++ b/security/integrity/ima/ima_queue.c
>>> @@ -371,6 +371,76 @@ int ima_queue_staged_delete_all(void)
>>>    	return 0;
>>>    }
>>>    
>>> +int ima_queue_staged_delete_partial(unsigned long req_value)
>>> +{
>>> +	unsigned long req_value_copy = req_value;
>>> +	unsigned long size_to_remove = 0, num_to_remove = 0;
>>> +	struct list_head *cut_pos = NULL;
>>> +	LIST_HEAD(ima_measurements_trim);
>>> +	struct ima_queue_entry *qe;
>>> +	int ret = 0;
>>> +
>>> +	/*
>>> +	 * Safe walk (no concurrent write), not under ima_extend_list_mutex
>>> +	 * for performance reasons.
>>> +	 */
>>> +	list_for_each_entry(qe, &ima_measurements_staged, later) {
>>> +		size_to_remove += get_binary_runtime_size(qe->entry);
>>> +		num_to_remove++;
>>> +
>>> +		if (--req_value_copy == 0) {
>>> +			/* qe->later always points to a valid list entry. */
>>> +			cut_pos = &qe->later;
>>> +			break;
>>> +		}
>>> +	}
>>> +
>>> +	/* Nothing to remove, undoing staging. */
>>> +	if (req_value_copy > 0) {
>>> +		size_to_remove = 0;
>>> +		num_to_remove = 0;
>>> +		ret = -ENOENT;
>>> +	}
>>> +
>>> +	mutex_lock(&ima_extend_list_mutex);
>>> +	if (list_empty(&ima_measurements_staged)) {
>>> +		mutex_unlock(&ima_extend_list_mutex);
>>> +		return -ENOENT;
>>> +	}
>>> +
>>> +	if (cut_pos != NULL)
>>> +		/*
>>> +		 * ima_dump_measurement_list() does not modify the list,
>>> +		 * cut_pos remains the same even if it was computed before
>>> +		 * the lock.
>>> +		 */
>>> +		__list_cut_position(&ima_measurements_trim,
>>> +				    &ima_measurements_staged, cut_pos);
>>> +
>>> +	atomic_long_sub(num_to_remove, &ima_num_entries[BINARY_STAGED]);
>>> +	atomic_long_add(atomic_long_read(&ima_num_entries[BINARY_STAGED]),
>>> +			&ima_num_entries[BINARY]);
>>> +	atomic_long_set(&ima_num_entries[BINARY_STAGED], 0);
>>> +
>>> +	if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
>>> +		binary_runtime_size[BINARY_STAGED] -= size_to_remove;
>>> +		binary_runtime_size[BINARY] +=
>>> +					binary_runtime_size[BINARY_STAGED];
>>> +		binary_runtime_size[BINARY_STAGED] = 0;
>>> +	}
>>> +
>>> +	/*
>>> +	 * Splice (prepend) any remaining non-deleted staged entries to the
>>> +	 * active list (RCU not needed, there cannot be concurrent readers).
>>> +	 */
>>> +	list_splice(&ima_measurements_staged, &ima_measurements);
>>> +	INIT_LIST_HEAD(&ima_measurements_staged);
>>> +	mutex_unlock(&ima_extend_list_mutex);
>>> +
>>> +	ima_queue_delete(&ima_measurements_trim, false);
>>> +	return ret;
>>> +}
>>> +
>>>    static void ima_queue_delete(struct list_head *head, bool flush_htable)
>>>    {
>>>    	struct ima_queue_entry *qe, *qe_tmp;



^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox