Linux Documentation
 help / color / mirror / Atom feed
* Re: [RFC PATCH v1 00/13] exec: add spawn templates for repeated executable startup
From: John Ericson @ 2026-06-08 23:06 UTC (permalink / raw)
  To: Li Chen, Christian Brauner
  Cc: Kees Cook, Al Viro, linux-fsdevel, linux-api, LKML, linux-mm,
	linux-arch, linux-doc, linux-kselftest, x86, Arnd Bergmann,
	Andy Lutomirski, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, H. Peter Anvin, Jan Kara, Jonathan Corbet,
	Shuah Khan
In-Reply-To: <19e8113d290.893abab26142069.5024234139508454104@linux.beauty>

Hi all,

I am happy to see this thread appear. I emailed Christian and others ~5 years
ago about this in this thread[1]; it would be great to see it finally happen!

I very much agree that the new process spawning should be pidfd based. I also
want to emphasize that the crux of the matter is that code needed to set up the
initial unscheduled process --- which I do think should be "real state" and
more than a mere template --- is currently chopped up between clone and exec.
So the real meat of the implementation would be factoring out a bunch of stuff
so it can be reused in both the legacy clone+exec and modern code paths.

I'll say a bit more about this "real state" vs "mere template" distinction,
which is that the latter is effectively some sort of ad-hoc operation batching
language, and always runs the risk of falling behind what the kernel actually
supports. The "real state" approach, where we have honest-to-goodness process
state, just in some partially initialized fashion and thus it's not yet
scheduled, always supports everything the kernel supports in principle.

Yes, alternative syscalls that specify which "embryonic" process (as opposed to
always the current active process) need to be created, but that is less bad
than trying to stuff things into flags etc. for a single existing system call,
and also one can imagine a world (as described in
https://catern.com/rsys21.pdf) where the exact "which process?" parameter
starts getting added to new process modifying machinery by *default*, with a
sentinel value analogous to `AT_FDCWD` used to mean "the current process" for
the legacy used-between-fork-and-exec usecase.

---

Anyways, years ago, after taking a glance at the relevant code in Linux and
FreeBSD, I figured that it would be easier for me personally to first implement
this functionality in FreeBSD, and then, once I had a feel for some of the
refactoring, take a stab at it in Linux. This is because Linux's feature set,
especially things like `binfmt_misc`, makes its clone and exec quite a bit more
complex, and thus the (IMO) necessary heavy refactoring quite a bit more
extensive too.

I never got around to it in the 5 years, but these days, with LLMs, doing an
"exploratory refactor" (to get a sketch of a patch that is fodder for discussion
not yet fit for actual submission) is much easier. So inspired by this thread, I
took a few hours to do the exploratory FreeBSD refactor in [2]. The man page for
the new syscalls, [3], might be a good place to start reading. (This, being from
a FreeBSD patch, describes the change in terms of "proc fds", but the switch to
Linux's "pidfds" should be self-explanatory. The former after all inspired the
latter.)

Hope discussion of such a patch isn't too off topic here, but there is an
interesting thing to note that would also apply to a Linux implementation. It
took *more* factored out helper functions than I thought. The current count is
over 15(!) --- there didn't seem to be a way to build both the old and new way
of doing things with fewer, coarser building blocks. Now, granted, maybe
someone more familiar with either kernel than me could do a better job, but I
think it will still be a number of functions. This indicates just how much
untangling there is to do. And the number will surely be much higher for Linux.

[1]: https://lore.kernel.org/all/f8457e20-c3cc-6e56-96a4-3090d7da0cb6@JohnEricson.me/

[2]: https://github.com/obsidiansystems/freebsd-src/commit/better-proc-spawn
     239dcdefe6ad244e58d998155b527375e5293ff7 for posterity

[3]: https://raw.githubusercontent.com/obsidiansystems/freebsd-src/refs/heads/better-proc-spawn/lib/libsys/proc_new.2


On Sun, May 31, 2026, at 10:47 PM, Li Chen wrote:
> Hi Christian,
>
> Thanks a lot for your great review!
>
> ---- On Thu, 28 May 2026 19:02:53 +0800  Christian Brauner <brauner@kernel.org> wrote ---
> > On Thu, May 28, 2026 at 05:52:21PM +0800, Li Chen wrote:
> > > Hi,
> > >
> > > This is an early RFC for an idea that is probably still rough in both the
> > > UAPI and implementation details. Sorry for the rough edges; I am sending
> > > it now to check whether this direction is worth pursuing and to get
> > > feedback on the kernel/userspace boundary.
> >
> > The idea of having a builder api for exec isn't all that crazy. But it
> > should simply be built on top of pidfds and thus pidfs itself instead.
> > It has all the basic infrastructure in place already.
>
> Yes, that makes a lot more sense. I was staring too hard at the "hot
> executable" part and made the cache/template the API, which was probably
> the wrong thing to expose. Sorry about that.
>
> > Any implementation
> > should also allow userspace to implement posix_spawn() on top of it.
>
> That's so cool, and this is a really useful point. I had not thought about this as
> something that could sit under posix_spawn(), but that makes the target
> much clearer. It should be a generic exec/spawn builder first, and the
> agent use case should just be one user of it.
>
> > fd = pidfd_open(0, PIDFD_EMPTY /* or better name */)
> >
> > pidfd_config(fd, ...) // modeled similar to fsconfig()
>
> Reusing pidfd_open() with an empty target is nice because it keeps the API close
> to pidfds, but I wonder if a separate entry point such as
> pidfd_spawn_open() or pidfd_create() would make the "new process
> builder" case a bit more explicit? Either way, the configuration side
> being fsconfig-like makes sense to me.

Yeah check out my syscalls [3] on that front. It's important to design the
workflow / state machine in a good way. Performance/efficiency, security (share
less state/privileges by default!), and extensibility (where will newer
concepts, like a new type of namespace, fit in?) are all competing concerns,
but I think they mostly pull in the same direction. (Only no ambient authority,
back compat, and extensibility exist in some tension.)

> Thanks again for pointing me in this direction. It helps a lot.
>
> Regards,
> Li

Glad you are sold on pidfds, and more broadly, best of luck! You'll be a hero
to everyone else that has wanted this over the years :)

John

^ permalink raw reply

* Re: [PATCH v3 2/4] mm/zswap: Implement proactive writeback
From: Yosry Ahmed @ 2026-06-08 22:27 UTC (permalink / raw)
  To: Shakeel Butt
  Cc: Hao Jia, Johannes Weiner, mhocko, tj, mkoutny, roman.gushchin,
	Nhat Pham, akpm, chengming.zhou, muchun.song, cgroups, linux-mm,
	linux-kernel, linux-doc, Hao Jia, youngjun.park
In-Reply-To: <aictKA0XWMWbxFdN@linux.dev>

> > > Youngjun is working on swap tiers. At the moment he is more interested in
> > > allowing a specific swap device to a memcg or not. I can imagine in future there
> > > will be use-cases where there will be a need to demote data on higher tier swap
> > > to lower tier swap. What would be the appropriate interface?
> > >
> > > BTW does zswap folks think of zswap as a top swap tier or something different?
> >
> > I haven't been following the swap tiers work closely, but personally I
> > do think of zswap as a top swap tier.
>
> Same for me though I imagine swap tiers would introduce some duplication i.e.
> different way (interface) to set limits for swap tiers for a given memcg.
>
> > Things will probably get more
> > blurry with memory tiers and compressed memory nodes though.
>
> I think there will still be distinction between byte addressable and fault on
> access devices.

Yeah, I think it makes sense to define "swap" as fault on access
(zswap, SSD, etc), and memory tiers as byte-addressable (even if you
put an SSD behind CXL and make it byte-addressable). But I also
remember seeing discussions about unifying memory tiers and swap in a
way, and it makes sense from a reclaim perspective (swap or demote
first?).

^ permalink raw reply

* Re: [PATCH v5 0/4] Enable sysfs module symlink for more built-in drivers
From: Danilo Krummrich @ 2026-06-08 22:24 UTC (permalink / raw)
  To: Shashank Balaji
  Cc: Suzuki K Poulose, James Clark, Alexander Shishkin,
	Greg Kroah-Hartman, Rafael J . Wysocki, Danilo Krummrich,
	Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Jonathan Corbet, Shuah Khan, Luis Chamberlain, Petr Pavlu,
	Daniel Gomez, Sami Tolvanen, Aaron Tomlin, Mike Leach, Leo Yan,
	Thierry Reding, Jonathan Hunter, Rahul Bukte, linux-kernel,
	coresight, linux-arm-kernel, driver-core, rust-for-linux,
	linux-doc, Daniel Palmer, Tim Bird, linux-modules, linux-tegra,
	Sumit Gupta
In-Reply-To: <20260518-acpi_mod_name-v5-0-705ccc430885@sony.com>

On Mon, 18 May 2026 19:19:56 +0900, Shashank Balaji wrote:
> [PATCH v5 0/4] Enable sysfs module symlink for more built-in drivers

Applied, thanks!

  Branch: driver-core-testing
  Tree:   git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git

[1/4] soc/tegra: cbb: Move driver registration from pure_initcall to core_initcall
      commit: cd6e95e7ab29
[2/4] kernel: param: initialize module_kset in a pure_initcall
      commit: c82dfce47833
[3/4] coresight: pass THIS_MODULE implicitly through a macro
      commit: efc22b3f89a3
[4/4] driver core: platform: set mod_name in driver registration
      commit: a7a7dc5c46a0

The patches will appear in the next linux-next integration (typically within 24
hours on weekdays).

The patches are in the driver-core-testing branch and will be promoted to
driver-core-next after validation.

^ permalink raw reply

* Re: [PATCH v3 2/4] mm/zswap: Implement proactive writeback
From: Shakeel Butt @ 2026-06-08 22:22 UTC (permalink / raw)
  To: Yosry Ahmed
  Cc: Hao Jia, Johannes Weiner, mhocko, tj, mkoutny, roman.gushchin,
	Nhat Pham, akpm, chengming.zhou, muchun.song, cgroups, linux-mm,
	linux-kernel, linux-doc, Hao Jia, youngjun.park
In-Reply-To: <CAO9r8zNBJ-BsXyKFveA92jbwMu63uFVTY5CuT4fRHTBVcOjhPw@mail.gmail.com>

On Mon, Jun 08, 2026 at 01:19:32PM -0700, Yosry Ahmed wrote:
> On Mon, Jun 8, 2026 at 12:50 PM Shakeel Butt <shakeel.butt@linux.dev> wrote:
> >
> > +Youngjun
> >
> > On Mon, Jun 08, 2026 at 11:30:30AM -0700, Shakeel Butt wrote:
> > > On Wed, Jun 03, 2026 at 10:36:07PM -0700, Yosry Ahmed wrote:
> > > > > >> But doesn't it make more sense to specify the compressed size, which is
> > > > > >> ultimately the amount of memory you actually want to reclaim.
> > > > > >>
> > > > > >
> > > > > > I personally prefer compressed size to pre-compressed size. That's
> > > > > > kinda what user cares about, no?
> > > > > >
> > > > > > One thing we can do is let users prescribe a compressed size, but
> > > > > > internally, we can multiply that by the average compression ratio.
> > > > > > That gives us a guesstimate of how many pages we need to reclaim, and
> > > > > > you can follow the rest of your implementation as is (perhaps with
> > > > > > short-circuit when we reach the goal with fewer pages reclaimed).
> > > > >
> > > > > Got it. I will change it to use the compressed size in the next version.
> > > > >
> > > > > Yosry, Nhat, should we continue using the zswap_writeback_only key to
> > > > > trigger proactive writeback?
> > > >
> > > > I *really* want the memcg maintainers to chime in here, it's
> > > > ultimately their call.
> > > >
> > > > Michal? Johannes? Shakeel? Roman? Anyone? :D
> > >
> > > Between the options of having an explicit interface (i.e.
> > > memory.zswap.writeback*) or a key (i.e. zswap_writeback_only) to memory.reclaim
> > > interface, I prefer the key option. I have not looked into how much proactively
> > > reclaiming zswap memory or proactively triggering zswap writeback makes sense
> > > but from the perspective of memcg interface, I think the key option would give a
> > > more clean solution if we decide in the future that this whole thing was a bad
> > > idea.
> > >
> > > Next regarding future proofing zswap writeback trigger, do we expect any
> > > potential additions/changes/new-features for this interface? For example do we
> > > expect in future we may want to trigger the zswap writeback only from a specific
> > > node or lowest memory tier?
> 
> The way I see it, zswap writeback is just a "special" type of
> proactive reclaim, but the goal is still proactively freeing cold
> memory. In that regard, I think it makes sense to have things like
> node-specific reclaim. Not sure about other extensions, but Hao
> initially suggested making this age-based, so I think the answer is
> yes.
> 
> For both of these examples (node-specific reclaim, age-based reclaim),
> I think the same semantics could apply to memory.reclaim in general,
> which is why I suggested making it a part of memory.reclaim. I also
> like the idea of having a single proactive reclaim interface in
> general, but maybe we don't want to overload it too much.

IMHO it is fine.

> 
> > Youngjun is working on swap tiers. At the moment he is more interested in
> > allowing a specific swap device to a memcg or not. I can imagine in future there
> > will be use-cases where there will be a need to demote data on higher tier swap
> > to lower tier swap. What would be the appropriate interface?
> >
> > BTW does zswap folks think of zswap as a top swap tier or something different?
> 
> I haven't been following the swap tiers work closely, but personally I
> do think of zswap as a top swap tier.

Same for me though I imagine swap tiers would introduce some duplication i.e.
different way (interface) to set limits for swap tiers for a given memcg.

> Things will probably get more
> blurry with memory tiers and compressed memory nodes though.

I think there will still be distinction between byte addressable and fault on
access devices.

^ permalink raw reply

* Re: [PATCH v5 0/4] Enable sysfs module symlink for more built-in drivers
From: Danilo Krummrich @ 2026-06-08 22:16 UTC (permalink / raw)
  To: Shashank Balaji
  Cc: Suzuki K Poulose, James Clark, Alexander Shishkin,
	Greg Kroah-Hartman, Rafael J. Wysocki, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Jonathan Corbet, Shuah Khan,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Aaron Tomlin, Mike Leach, Leo Yan, Thierry Reding,
	Jonathan Hunter, Rahul Bukte, linux-kernel, coresight,
	linux-arm-kernel, driver-core, rust-for-linux, linux-doc,
	Daniel Palmer, Tim Bird, linux-modules, linux-tegra, Sumit Gupta
In-Reply-To: <20260518-acpi_mod_name-v5-0-705ccc430885@sony.com>

On Mon May 18, 2026 at 12:19 PM CEST, Shashank Balaji wrote:
> Shashank Balaji (4):
>       soc/tegra: cbb: Move driver registration from pure_initcall to core_initcall
>       kernel: param: initialize module_kset in a pure_initcall
>       coresight: pass THIS_MODULE implicitly through a macro
>       driver core: platform: set mod_name in driver registration

Picking this up now, so it can still make it for 7.2-rc1 and get some time in
linux-next.

Suzuki, since I haven't heard back I figured it should be fine to also pick the
coresight change as it is purely mechanic and driver-core motivated, but please
let me know if you have any concerns.

Thanks,
Danilo

^ permalink raw reply

* Re: [PATCH 4/4] block: add configurable error injection
From: Bart Van Assche @ 2026-06-08 22:08 UTC (permalink / raw)
  To: Christoph Hellwig, Jens Axboe
  Cc: Jonathan Corbet, Damien Le Moal, Hannes Reinecke, Keith Busch,
	linux-block, linux-doc, Hannes Reinecke
In-Reply-To: <20260608051416.1205282-5-hch@lst.de>

On 6/7/26 10:14 PM, Christoph Hellwig wrote:
> +Configurable error injection allows injecting specific block layer status codes
> +for ranges of a block device.  Errors can be injected unconditionally, or with a

ranges -> sector ranges?

> +static void error_inject_removall(struct gendisk *disk)
 > +{

Is a letter "e" perhaps missing from the above function name? (remov -> 
remove)

Thanks,

Bart.

^ permalink raw reply

* Re: [PATCH 3/4] block: add a str_to_blk_op helper
From: Bart Van Assche @ 2026-06-08 21:57 UTC (permalink / raw)
  To: Christoph Hellwig, Jens Axboe
  Cc: Jonathan Corbet, Damien Le Moal, Hannes Reinecke, Keith Busch,
	linux-block, linux-doc, Hannes Reinecke
In-Reply-To: <20260608051416.1205282-4-hch@lst.de>

On 6/7/26 10:14 PM, Christoph Hellwig wrote:
> +enum req_op str_to_blk_op(const char *op)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(blk_op_name); i++)
> +		if (blk_op_name[i] && !strcmp(blk_op_name[i], op))
> +			return (enum req_op)i;
> +	return REQ_OP_LAST;
> +}
The above function is similar but not identical to
__sysfs_match_string(). Is __sysfs_match_string() good enough in this
context?

Thanks,

Bart.


^ permalink raw reply

* Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
From: David Matlack @ 2026-06-08 21:56 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: kexec, linux-doc, linux-kernel, linux-mm, linux-pci,
	Adithya Jayachandran, Alexander Graf, Alex Williamson,
	Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
	Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Leon Romanovsky,
	Lukas Wunner, Mike Rapoport, Parav Pandit, Pasha Tatashin,
	Pratyush Yadav, Saeed Mahameed, Samiullah Khawaja, Shuah Khan,
	Vipin Sharma, William Tu, Yi Liu
In-Reply-To: <aiXWmR-ettxin4LC@google.com>

On 2026-06-07 08:37 PM, Pranjal Shrivastava wrote:
> On Fri, May 22, 2026 at 08:24:06PM +0000, David Matlack wrote:
> > Inherit Access Control Services (ACS) flags on all incoming preserved
> > devices (endpoints and upstream bridges) during a Live Update.
> > 
> > Inheriting ACS flags avoids changing routing rules while memory
> > transactions are in flight from preserved devices. This is also strictly
> > necessary to ensure that IOMMU group assignments do not change across
> > a Live Update for preserved devices, as changing ACS configurations can
> > split or merge IOMMU groups.
> > 
> > Cache the inherited ACS controls established by the previous kernel in
> > struct pci_dev so that ACS controls do not change after a reset
> > (pci_restore_state() calls pci_enable_acs()).
> > 
> > To simplify ACS inheritance, reject preserving any devices that require
> > quirks to enable ACS as those quirks would also have to take Live Update
> > into account.
> > 
> > Signed-off-by: David Matlack <dmatlack@google.com>
> > ---
> >  drivers/pci/liveupdate.c       | 68 ++++++++++++++++++++++++++++++++++
> >  drivers/pci/liveupdate.h       | 11 ++++++
> >  drivers/pci/pci.c              |  5 +++
> >  drivers/pci/pci.h              |  5 +++
> >  drivers/pci/quirks.c           |  7 ++++
> >  include/linux/pci_liveupdate.h |  6 +++
> >  6 files changed, 102 insertions(+)
> > 
> 
> [...]
> 
> >  
> > +void pci_liveupdate_init_acs(struct pci_dev *dev)
> > +{
> > +	guard(rwsem_read)(&pci_liveupdate.rwsem);
> > +
> > +	if (!dev->acs_cap || !dev->liveupdate.incoming)
> > +		return;
> > +
> > +	pci_read_config_word(dev, dev->acs_cap + PCI_ACS_CTRL, &dev->liveupdate.acs_ctrl);
> 
> I might be thinking out loud here, but as an attacker, this motivates me
> to somehow hack the EP FW to mis-report the PCI_ACS_CTRL register across
> a liveupdate to fool the incoming kernel. If the FW feeds a 0, it silently
> strips ACS protections.
> 
> Should we also serialize ACS state in ser somehow to ensure we aren't 
> fooled by something like this?

What does "EP FW" mean?

Does such an attacker even need Live Update to attack the system? It
seems like such an attacker could route TLPs in whatever malicious way
they want regardless of Live Update.

> 
> > +}
> > +
> > +int pci_liveupdate_enable_acs(struct pci_dev *dev)
> > +{
> > +	u16 acs_ctrl = dev->liveupdate.acs_ctrl;
> > +	u16 acs_cap = dev->acs_cap;
> > +
> > +	/*
> > +	 * Use liveupdate.was_preserved instead of liveupdate.incoming since the
> > +	 * device's ACS controls should not change even after the device is
> > +	 * finished participating in the Live Update.
> > +	 */
> > +	if (!dev->liveupdate.was_preserved)
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * The previous kernel should not have preserved any devices that
> > +	 * require device-specific quirks to enable ACS, but if such a device is
> > +	 * detected, log a big warning and fall back to the normal enable ACS
> > +	 * path.
> > +	 */
> 
> Nit: It might be worth adding a note here that this can also happen if a
> new device-specific ACS quirk is introduced in the incoming kernel for a
> device that was preserved by the old kernel (which didn't have the quirk).
> In such cases, the two kernels are essentially non-LUO-compatible..

Yes will do.

> 
> > +	if (pci_need_dev_specific_enable_acs(dev)) {
> > +		pci_warn(dev, "Device-specific quirk required to enable ACS!\n");
> > +		WARN_ON_ONCE(true);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (acs_cap)
> > +		pci_write_config_word(dev, acs_cap + PCI_ACS_CTRL, acs_ctrl);
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> >   * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved
> >   * @dev: The PCI device to check
> 
> [...]
> 
> Thanks,
> Praan

^ permalink raw reply

* Re: [PATCH 2/4] block: add a "tag" for block status codes
From: Bart Van Assche @ 2026-06-08 21:55 UTC (permalink / raw)
  To: Christoph Hellwig, Jens Axboe
  Cc: Jonathan Corbet, Damien Le Moal, Hannes Reinecke, Keith Busch,
	linux-block, linux-doc, Hannes Reinecke
In-Reply-To: <20260608051416.1205282-3-hch@lst.de>

On 6/7/26 10:14 PM, Christoph Hellwig wrote:
> +const char *blk_status_to_tag(blk_status_t status)
> +{
> +	int idx = (__force int)status;
> +
> +	if (WARN_ON_ONCE(idx >= ARRAY_SIZE(blk_errors)))
> +		return "<null>";
> +	return blk_errors[idx].tag;
> +}

Since designated initializers are used to initialize blk_errors[], it's
probably a good idea to check the value of blk_errors[idx].tag, e.g. as
follows:

return blk_errors[idx].tag ?: "<null>";

Thanks,

Bart.


^ permalink raw reply

* Re: [PATCH 1/4] block: add a macro to initialize the status table
From: Bart Van Assche @ 2026-06-08 21:51 UTC (permalink / raw)
  To: Christoph Hellwig, Jens Axboe
  Cc: Jonathan Corbet, Damien Le Moal, Hannes Reinecke, Keith Busch,
	linux-block, linux-doc, Hannes Reinecke
In-Reply-To: <20260608051416.1205282-2-hch@lst.de>

On 6/7/26 10:14 PM, Christoph Hellwig wrote:
> Prepare for adding a new value to the error table by adding a macro
> to fill it.
Reviewed-by: Bart Van Assche <bvanassche@acm.org>

^ permalink raw reply

* Re: [PATCH v6 07/12] PCI: Refactor matching logic for pci_dev_acs_ops
From: David Matlack @ 2026-06-08 21:49 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: kexec, linux-doc, linux-kernel, linux-mm, linux-pci,
	Adithya Jayachandran, Alexander Graf, Alex Williamson,
	Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
	Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Leon Romanovsky,
	Lukas Wunner, Mike Rapoport, Parav Pandit, Pasha Tatashin,
	Pratyush Yadav, Saeed Mahameed, Samiullah Khawaja, Shuah Khan,
	Vipin Sharma, William Tu, Yi Liu
In-Reply-To: <aiW_M7y0fFwLN84G@google.com>

On 2026-06-07 07:01 PM, Pranjal Shrivastava wrote:
> On Fri, May 22, 2026 at 08:24:05PM +0000, David Matlack wrote:
> > Refactor the logic to match devices to pci_dev_acs_ops by factoring out
> > the loop and device matching into its own routine. This eliminates some
> > duplicate code between pci_dev_specific_enable_acs() and
> > pci_dev_specific_disable_acs_redir(), and will also be used in a
> > subsequent commit to check if a device requires device-specific
> > enable_acs() during a Live Update.
> > 
> > No functional change intended.
> > 
> > Signed-off-by: David Matlack <dmatlack@google.com>
> > ---
> >  drivers/pci/quirks.c | 50 ++++++++++++++++++--------------------------
> >  1 file changed, 20 insertions(+), 30 deletions(-)
> > 
> 
> [...]
> 
> >  } pci_dev_acs_ops[] = {
> >  	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
> > +	    .match = pci_quirk_intel_pch_acs_match,
> >  	    .enable_acs = pci_quirk_enable_intel_pch_acs,
> >  	},
> >  	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
> > +	    .match = pci_quirk_intel_spt_pch_acs_match,
> >  	    .enable_acs = pci_quirk_enable_intel_spt_pch_acs,
> >  	    .disable_acs_redir = pci_quirk_disable_intel_spt_pch_acs_redir,
> >  	},
> >  };
> >  
> > -int pci_dev_specific_enable_acs(struct pci_dev *dev)
> > +static const struct pci_dev_acs_ops *pci_dev_acs_ops_get(struct pci_dev *dev)
> >  {
> >  	const struct pci_dev_acs_ops *p;
> > -	int i, ret;
> > +	int i;
> >  
> >  	for (i = 0; i < ARRAY_SIZE(pci_dev_acs_ops); i++) {
> >  		p = &pci_dev_acs_ops[i];
> > @@ -5481,33 +5475,29 @@ int pci_dev_specific_enable_acs(struct pci_dev *dev)
> >  		     p->vendor == (u16)PCI_ANY_ID) &&
> >  		    (p->device == dev->device ||
> >  		     p->device == (u16)PCI_ANY_ID) &&
> > -		    p->enable_acs) {
> > -			ret = p->enable_acs(dev);
> > -			if (ret >= 0)
> > -				return ret;
> > -		}
> > +		    p->match(dev))
> > +			return p;
> 
> Nit:
> Should we check if (p->match != NULL) like we check for p->enable_acs &
> p->disable_acs_redir(). 
> 
> Otherwise, it seems like we're mandating the existence of a match op in
> the pci_dev_acs_ops here? Today, we just have two Intel entries in that
> array, both of which need the match op. However, AFAICT, it shouldn't be
> mandatory for future SoCs that might only need a simple vid + devid match

*shrug*

I would usually say those future SoCs should be the ones to make it
optional if and when they need to.

But making p->matc optional now isn't so bad:

        for (i = 0; i < ARRAY_SIZE(pci_dev_acs_ops); i++) {
                p = &pci_dev_acs_ops[i];
                if ((p->vendor == dev->vendor ||
                     p->vendor == (u16)PCI_ANY_ID) &&
                    (p->device == dev->device ||
-                    p->device == (u16)PCI_ANY_ID) &&
-                   p->enable_acs) {
-                       ret = p->enable_acs(dev);
-                       if (ret >= 0)
-                               return ret;
+                    p->device == (u16)PCI_ANY_ID)) {
+                       if (!p->match || p->match(dev))
+                               return p;
                }
        }

I can include this in v7 if you would like.


> 
> [...]
> 
> with that nit:
> Reviewed-by: Pranjal Shrivastava <praan@google.com>
> 
> Thanks,
> Praan

^ permalink raw reply

* Re: [PATCH v6 06/12] PCI: liveupdate: Auto-preserve upstream bridges across Live Update
From: David Matlack @ 2026-06-08 21:34 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: kexec, linux-doc, linux-kernel, linux-mm, linux-pci,
	Adithya Jayachandran, Alexander Graf, Alex Williamson,
	Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
	Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Leon Romanovsky,
	Lukas Wunner, Mike Rapoport, Parav Pandit, Pasha Tatashin,
	Pratyush Yadav, Saeed Mahameed, Samiullah Khawaja, Shuah Khan,
	Vipin Sharma, William Tu, Yi Liu
In-Reply-To: <aiSb85Ec6jW4xPaE@google.com>

On 2026-06-06 10:15 PM, Pranjal Shrivastava wrote:
> On Fri, May 22, 2026 at 08:24:04PM +0000, David Matlack wrote:
> > When a PCI device is preserved across a Live Update, all of its upstream
> > bridges up to the root port must also be preserved. This enables the PCI
> > core and any drivers bound to the bridges to manage bridges correctly
> > across a Live Update.
> > 
> > Notably, this will be used in subsequent commits to ensure that
> > preserved devices can continue performing memory transactions without a
> > disruption or change in routing.
> > 
> > To preserve bridges, the PCI core tracks the number of downstream
> > devices preserved under each bridge using a reference count in struct
> > pci_dev_ser. This allows a bridge to remain preserved until all its
> > downstream preserved devices are unpreserved or finish their
> > participation in the Live Update.
> > 
> > Signed-off-by: David Matlack <dmatlack@google.com>
> > ---
> >  drivers/pci/liveupdate.c    | 136 +++++++++++++++++++++++++++++++-----
> >  include/linux/kho/abi/pci.h |   5 +-
> >  2 files changed, 122 insertions(+), 19 deletions(-)
> > 
> 
> [...]
> 
> > +
> > +#define for_each_pci_dev_in_path(_d, _start, _end) \
> > +	for ((_d) = (_start); (_d) != (_end); (_d) = (_d)->bus->self)
> > +
> > +static void __pci_liveupdate_unpreserve_path(struct pci_ser *ser,
> > +					     struct pci_dev *start,
> > +					     struct pci_dev *end)
> > +{
> > +	struct pci_dev *dev;
> > +
> > +	for_each_pci_dev_in_path(dev, start, end) {
> > +		if (pci_liveupdate_unpreserve_device(ser, dev))
> 
> I might be reading this wrong but are we leaking some upstream devs if 
> an intermediate node fails?
> 
> 			  EP0
> 			/
> Assume we have: RC -> B1 -> B2 
> 				\
> 				 EP1
> 
> and EP0 & EP1 were preserved successfully.
> 
> And then we try unpreserving EP1, we follow:
> 
> unpreserve EP1 -> unpreserve B2 failed due to a corruption.
> 
> This aborts the loop, skipping B1 and RC completely?
> Their refcounts remain elevated, effectively leaking them as preserved 
> state permanently? (i.e. if we unpreserve EP0 after this, B1 & RC will
> still get preserved).

Yes, but that would only happen if there is some sort of kernel bug or
silent data corruption. I guess we could proceed with trying to
unpreserve the bridges upstream. But I opted to log a big warning and
bail immediately.

pci_liveupdate_finish_path() has the same behavior BTW.

> 
> > +			return;
> > +	}
> > +}
> > +
> > +static void pci_liveupdate_unpreserve_path(struct pci_ser *ser,
> > +					   struct pci_dev *start)
> > +{
> > +	__pci_liveupdate_unpreserve_path(ser, start, /*end=*/NULL);
> > +}
> > +
> > +static int pci_liveupdate_preserve_path(struct pci_ser *ser,
> > +					struct pci_dev *start)
> > +{
> > +	struct pci_dev *dev;
> > +	int ret;
> > +
> > +	for_each_pci_dev_in_path(dev, start, NULL) {
> > +		ret = pci_liveupdate_preserve_device(ser, dev);
> > +		if (ret) {
> > +			__pci_liveupdate_unpreserve_path(ser, start, dev);
> > +			return ret;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> >   * pci_liveupdate_preserve() - Preserve a PCI device across Live Update
> >   * @dev: The PCI device to preserve.
> > @@ -321,6 +403,9 @@ static int pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev *d
> >   * pci_liveupdate_preserve() from their struct liveupdate_file_handler
> >   * preserve() callback to ensure the outgoing struct pci_ser is already set up.
> >   *
> > + * pci_liveupdate_preserve() automatically preserves all bridges upstream of
> > + * @dev.
> > + *
> >   * Returns: 0 on success, <0 on failure.
> >   */
> >  int pci_liveupdate_preserve(struct pci_dev *dev)
> > @@ -336,7 +421,7 @@ int pci_liveupdate_preserve(struct pci_dev *dev)
> >  	if (IS_ERR(ser))
> >  		return PTR_ERR(ser);
> >  
> > -	return pci_liveupdate_preserve_device(ser, dev);
> > +	return pci_liveupdate_preserve_path(ser, dev);
> 
> Minor nit: I might be too nitpicky here (and it's NOT a strong opinion)
> but naming it pci_liveupdate_preserve_path_for_dev() reads better to me.

Noted :). I'll keep the current name for now since that is pretty long,
but if anyone else votes for it I'm happy to be overridden.

> >  }
> >  EXPORT_SYMBOL_GPL(pci_liveupdate_preserve);
> >  
> 
> [...]
> 
> Thanks,
> Praan

^ permalink raw reply

* Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
From: David Matlack @ 2026-06-08 20:57 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: kexec, linux-doc, linux-kernel, linux-mm, linux-pci,
	Adithya Jayachandran, Alexander Graf, Alex Williamson,
	Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
	Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Leon Romanovsky,
	Lukas Wunner, Mike Rapoport, Parav Pandit, Pasha Tatashin,
	Pratyush Yadav, Saeed Mahameed, Samiullah Khawaja, Shuah Khan,
	Vipin Sharma, William Tu, Yi Liu
In-Reply-To: <aiPxVxu2sUVQfG9D@google.com>

On 2026-06-06 10:08 AM, Pranjal Shrivastava wrote:
> On Fri, May 22, 2026 at 08:24:01PM +0000, David Matlack wrote:
> > During PCI enumeration, the previous kernel might have passed state about
> > devices that were preserved across kexec. The PCI core needs to fetch
> > this state to identify which devices are "incoming" and require special
> > handling.
> > 
> > Add pci_liveupdate_setup_device() which is called during device setup
> > to fetch the serialized state (struct pci_ser) from the Live Update
> > Orchestrator. The first time this happens, pci_flb_retrieve() will run
> > and convert the array of pci_dev_ser structs into an xarray so that it
> > can be looked up efficiently.
> > 
> > If a device is found in the xarray, the PCI core stores a pointer to its
> > state in dev->liveupdate_incoming and holds a reference to the incoming
> > FLB until pci_liveupdate_finish() is called by the driver.
> > 
> > This ensures proper lifecycle management for incoming preserved devices
> > and allows the PCI core and drivers to apply specific Live Update
> > logic to them in subsequent commits.
> > 
> > Drivers can check if a device is an incoming preserved device (e.g.
> > during probe) by calling pci_liveupdate_is_incoming().
> > 
> > CONFIG_64BIT is now required to enable CONFIG_PCI_LIVEUPDATE so that the
> > domain and bdf can be guaranteed to fit in an unsigned long and be used
> > as the xarray key.
> > 
> > Signed-off-by: David Matlack <dmatlack@google.com>
> > ---
> >  MAINTAINERS                    |   1 +
> >  drivers/pci/Kconfig            |   2 +-
> >  drivers/pci/liveupdate.c       | 230 ++++++++++++++++++++++++++++++++-
> >  drivers/pci/liveupdate.h       |   5 +
> >  drivers/pci/probe.c            |   3 +
> >  include/linux/pci_liveupdate.h |  13 ++
> >  6 files changed, 251 insertions(+), 3 deletions(-)
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 6c618830cf61..0e262c0ceb43 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -20537,6 +20537,7 @@ L:	linux-pci@vger.kernel.org
> >  S:	Maintained
> >  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git
> >  F:	drivers/pci/liveupdate.c
> > +F:	drivers/pci/liveupdate.h
> >  F:	include/linux/kho/abi/pci.h
> >  F:	include/linux/pci_liveupdate.h
> >  
> > diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> > index 10c9b65aa242..e68ae5c172d4 100644
> > --- a/drivers/pci/Kconfig
> > +++ b/drivers/pci/Kconfig
> > @@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUS
> >  
> >  config PCI_LIVEUPDATE
> >  	bool "PCI Live Update Support"
> > -	depends on PCI && LIVEUPDATE
> > +	depends on PCI && LIVEUPDATE && 64BIT
> 
> I see that the static assertions in Patch 1 work because of the 64BIT
> enforcement here. In that case, should we have the assertions check u64?

The static asserts have nothing to do with the 64BIT enforcement here.
The static asserts just verify that the array elements in struct pci_ser
are naturally aligned (unsigned long) so they can be accessed
efficiently. The requirement here for CONFIG_64BIT is for the xarray
key.

Theoretically if we got the xarray to work with 32-bit architectures
then we could drop the CONFIG_64BIT requirement here.

> 
> >  	help
> >  	  Enable PCI core support for preserving PCI devices across Live
> >  	  Update. This, in combination with support in a device's driver,
> >
> 
> [...]
> 
> >  static int pci_flb_retrieve(struct liveupdate_flb_op_args *args)
> >  {
> > -	args->obj = phys_to_virt(args->data);
> > +	struct pci_ser *ser = phys_to_virt(args->data);
> > +	struct pci_flb_incoming *incoming;
> > +	int ret = -ENOMEM;
> > +	u32 i;
> > +
> > +	incoming = kmalloc_obj(*incoming);
> > +	if (!incoming)
> > +		goto err_restore_free;
> > +
> > +	incoming->ser = ser;
> > +	xa_init(&incoming->xa);
> > +
> > +	for (i = 0; i < incoming->ser->max_nr_devices; i++) {
> > +		struct pci_dev_ser *dev_ser = &incoming->ser->devices[i];
> > +		unsigned long key;
> > +
> > +		if (!dev_ser->refcount)
> > +			continue;
> > +
> > +		key = pci_ser_xa_key(dev_ser->domain, dev_ser->bdf);
> > +		ret = xa_insert(&incoming->xa, key, dev_ser, GFP_KERNEL);
> > +		if (ret)
> > +			goto err_xa_destroy;
> > +	}
> > +
> > +	args->obj = incoming;
> >  	return 0;
> > +
> > +err_xa_destroy:
> > +	xa_destroy(&incoming->xa);
> > +	kfree(incoming);
> > +err_restore_free:
> > +	kho_restore_free(ser);
> 
> I tend to partly agree with Sashiko[1] here.. it raises a policy-hole.
> We may need a policy here, the options I have in mind are:
> 
> 1. Retrieve shall ONLY be tried once, if it fails (like -ENOMEM in the
>    xArray alloc), it's a liveupdate failure. We can't retry liveupdate.
> 
> 2. Retrying retrieve is allowed.
> 
> The only downside with option 1 is, the user may want flexibility due to
> certain subsystems OR may choose NOT to use the proposed LUOd and instead
> have its own user-space component which might try funny things or have a
> different use-case.
> 
> In such a situation, the system may have transiently run out of memory
> during the kexec transition (for e.g. a subsystem uses GFP_ATOMIC to
> allocate memory and temporarily runs out of the atomic pool). [Note we
> removed it in IOMMU v1 [2] but subsystems may have a use-case for it]
> 
> If the kernel frees the KHO page on the first failure, it removes any
> chance of recovery. :/
> 
> Thus, it might make sense to let the user decide if it wants to fail the
> liveupdate or retry again based on the failure type / source?

The plan is to have LUO enforce that retrieve() is only called once:

  https://lore.kernel.org/kexec/20260528174140.1921129-3-dmatlack@google.com/

Supporting retry gets complicated since there's many different places
where retrieve() could have failed.

> 
> [...]
> 
> The changes LGTM, except for policy-based, kho_restore_free discussion.
> 
> Reviewed-by: Pranjal Shrivastava <praan@google.com>
> 
> Thanks,
> Praan
> 
> [1] https://lore.kernel.org/all/20260522211333.D56A21F000E9@smtp.kernel.org/
> [2] https://lore.kernel.org/all/20260203220948.2176157-2-skhawaja@google.com/

^ permalink raw reply

* Re: [PATCH v3 4/6] alloc_tag: add accuracy based filtering to ioctl
From: Suren Baghdasaryan @ 2026-06-08 20:55 UTC (permalink / raw)
  To: Hao Ge
  Cc: Abhishek Bapat, Shuah Khan, Jonathan Corbet, linux-doc,
	linux-kernel, linux-mm, Sourav Panda, Andrew Morton,
	Kent Overstreet
In-Reply-To: <a58e659e-5f54-4511-9a29-dc921002d102@linux.dev>

On Mon, Jun 8, 2026 at 1:25 AM Hao Ge <hao.ge@linux.dev> wrote:
>
>
> On 2026/6/8 14:22, Hao Ge wrote:
> > Hi Abhishek
> >
> >
> > On 2026/6/6 07:36, Abhishek Bapat wrote:
> >> Extend the allocinfo filtering mechanism to allow users to filter tags
> >> based on their accuracy.
> >>
> >> Signed-off-by: Abhishek Bapat <abhishekbapat@google.com>
> >> ---
> >>   include/uapi/linux/alloc_tag.h | 3 +++
> >>   lib/alloc_tag.c                | 8 ++++++++
> >>   2 files changed, 11 insertions(+)
> >>
> >> diff --git a/include/uapi/linux/alloc_tag.h
> >> b/include/uapi/linux/alloc_tag.h
> >> index 0e648192df4d..42445bdb11c5 100644
> >> --- a/include/uapi/linux/alloc_tag.h
> >> +++ b/include/uapi/linux/alloc_tag.h
> >> @@ -20,6 +20,7 @@ struct allocinfo_tag {
> >>       char function[ALLOCINFO_STR_SIZE];
> >>       char filename[ALLOCINFO_STR_SIZE];
> >>       __u64 lineno;
> >> +    __u64 inaccurate;
> >
> >
> > I was wondering if it would make sense to define inaccurate as a flags
> > field
> >
> > (e.g. __u64 flags with ALLOCINFO_TAG_F_INACCURATE (1 <<0)),
> >
> > so that only bit 0 is used today and the upper bits are reserved for
> > future use,
> >
> > aligning with current kernel codebase.
> >
> > This design also allows for better extensibility if we need to
> >
> > add new flags for any reason in the future.
> >
> > We also need to add flag validity checks if we go this route.
> >
> And I've reviewed the issue reported by Sashiko, and I think it's valid.
>
> When we expand the allocinfo_tag_data structure
>
> struct allocinfo_tag_data{
>
>      char modname[64];
>
>      char function[64];
>
>      char filename[64];
>
>      __u64 lineno;
>
>      __u64 inaccurate;
>
>      __u64 bytes;
>
>      __u64 calls;
>
>      __u8 accurate;
>    /* padding */
>
> }
>
> I think user space may see two fields related to inaccuracy.

Yes but one field (inside allocinfo_tag) is the input parameter which
user provides to specify the filtering criteria and the other is the
returned tag information. It's similar to any other tag attribute
which you can be included in the filters.

>
> How do you like these modifications?
>
>
> diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h
> --- a/include/uapi/linux/alloc_tag.h
> +++ b/include/uapi/linux/alloc_tag.h
> @@ -20,7 +20,6 @@ struct allocinfo_tag {
>       char function[ALLOCINFO_STR_SIZE];
>       char filename[ALLOCINFO_STR_SIZE];
>       __u64 lineno;
> -    __u64 inaccurate;
>   };
>
>   /* The alignment ensures 32-bit compatible interfaces are not broken */
> @@ -40,7 +39,7 @@ enum {
>       ALLOCINFO_FILTER_FUNCTION,
>       ALLOCINFO_FILTER_FILENAME,
>       ALLOCINFO_FILTER_LINENO,
> -    ALLOCINFO_FILTER_INACCURATE,
> +    ALLOCINFO_FILTER_FLAGS,
>       ALLOCINFO_FILTER_MIN_SIZE,
>       ALLOCINFO_FILTER_MAX_SIZE,
>       __ALLOCINFO_FILTER_LAST = ALLOCINFO_FILTER_MAX_SIZE
> @@ -50,16 +49,20 @@ enum {
>   #define ALLOCINFO_FILTER_MASK_FUNCTION        (1 <<
> ALLOCINFO_FILTER_FUNCTION)
>   #define ALLOCINFO_FILTER_MASK_FILENAME        (1 <<
> ALLOCINFO_FILTER_FILENAME)
>   #define ALLOCINFO_FILTER_MASK_LINENO        (1 << ALLOCINFO_FILTER_LINENO)
> -#define ALLOCINFO_FILTER_MASK_INACCURATE    (1 <<
> ALLOCINFO_FILTER_INACCURATE)
> +#define ALLOCINFO_FILTER_MASK_FLAGS        (1 << ALLOCINFO_FILTER_FLAGS)
>   #define ALLOCINFO_FILTER_MASK_MIN_SIZE        (1 <<
> ALLOCINFO_FILTER_MIN_SIZE)
>   #define ALLOCINFO_FILTER_MASK_MAX_SIZE        (1 <<
> ALLOCINFO_FILTER_MAX_SIZE)
>
>   #define ALLOCINFO_FILTER_MASKS \
>       ((1 << (__ALLOCINFO_FILTER_LAST + 1)) - 1)
>
> +#define ALLOCINFO_FILTER_F_INACCURATE    (1ULL << 0)
> +#define ALLOCINFO_FILTER_FLAGS_ALL ALLOCINFO_FILTER_F_INACCURATE
> +
>   struct allocinfo_filter {
>       __u64 mask; /* bitmask of the filter fields used */
>       struct allocinfo_tag fields;
> +    __u64 flags; /* bitmask of ALLOCINFO_FILTER_F_* */
>       __u64 min_size;
>       __u64 max_size;
>   };
> diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
> --- a/lib/alloc_tag.c
> +++ b/lib/alloc_tag.c
> @@ -249,8 +249,6 @@ static bool matches_filter(struct codetag *ct,
> struct allocinfo_filter *filter,
>                  struct alloc_tag_counters *counters,
>                  bool *fetched_counters)
>   {
> -    bool inaccurate;
> -
>       if (!filter || !filter->mask)
>           return true;
>
> @@ -277,10 +275,11 @@ static bool matches_filter(struct codetag *ct,
> struct allocinfo_filter *filter,
>           ct->lineno != filter->fields.lineno)
>           return false;
>
> -    if (filter->mask & ALLOCINFO_FILTER_MASK_INACCURATE) {
> -        inaccurate = !!(ct->flags & CODETAG_FLAG_INACCURATE);
> -        if (inaccurate != !!(filter->fields.inaccurate))
> -            return false;
> +    if (filter->mask & ALLOCINFO_FILTER_MASK_FLAGS) {
> +        if (filter->flags & ALLOCINFO_FILTER_F_INACCURATE) {
> +            if (!(ct->flags & CODETAG_FLAG_INACCURATE))

How would you filter records which have only accurate data?

Overall I would prefer ALLOCINFO_FILTER_MASK_INACCURATE rather than
ALLOCINFO_FILTER_MASK_FLAGS. The fact that this attribute is a
single-bit flag is a technical detail. It's still a tag attribuite
like file and module names and IMO deserves its own filter.



> +                return false;
> +        }
>       }
>
>       if (filter->mask & (ALLOCINFO_FILTER_MASK_MIN_SIZE |
> ALLOCINFO_FILTER_MASK_MAX_SIZE)) {
> @@ -318,6 +317,10 @@ static int allocinfo_ioctl_get_at(struct seq_file
> *m, void __user *arg)
>       if (params.filter.mask & ~ALLOCINFO_FILTER_MASKS)
>           return -EINVAL;
>
> +    if ((params.filter.mask & ALLOCINFO_FILTER_MASK_FLAGS) &&
> +        (params.filter.flags & ~ALLOCINFO_FILTER_FLAGS_ALL))
> +        return -EINVAL;
> +
>       if ((params.filter.mask & ALLOCINFO_FILTER_MASK_MIN_SIZE) &&
>           (params.filter.mask & ALLOCINFO_FILTER_MASK_MAX_SIZE) &&
>           params.filter.min_size > params.filter.max_size)
>
>
> Thanks
>
> Best Regards
>
> Hao
>
>
> >
> > Thanks
> >
> > Best Regards
> >
> > Hao
> >
> >
> >>   };
> >>     /* The alignment ensures 32-bit compatible interfaces are not
> >> broken */
> >> @@ -39,6 +40,7 @@ enum {
> >>       ALLOCINFO_FILTER_FUNCTION,
> >>       ALLOCINFO_FILTER_FILENAME,
> >>       ALLOCINFO_FILTER_LINENO,
> >> +    ALLOCINFO_FILTER_INACCURATE,
> >>       ALLOCINFO_FILTER_MIN_SIZE,
> >>       ALLOCINFO_FILTER_MAX_SIZE,
> >>       __ALLOCINFO_FILTER_LAST = ALLOCINFO_FILTER_MAX_SIZE
> >> @@ -48,6 +50,7 @@ enum {
> >>   #define ALLOCINFO_FILTER_MASK_FUNCTION        (1 <<
> >> ALLOCINFO_FILTER_FUNCTION)
> >>   #define ALLOCINFO_FILTER_MASK_FILENAME        (1 <<
> >> ALLOCINFO_FILTER_FILENAME)
> >>   #define ALLOCINFO_FILTER_MASK_LINENO        (1 <<
> >> ALLOCINFO_FILTER_LINENO)
> >> +#define ALLOCINFO_FILTER_MASK_INACCURATE    (1 <<
> >> ALLOCINFO_FILTER_INACCURATE)
> >>   #define ALLOCINFO_FILTER_MASK_MIN_SIZE        (1 <<
> >> ALLOCINFO_FILTER_MIN_SIZE)
> >>   #define ALLOCINFO_FILTER_MASK_MAX_SIZE        (1 <<
> >> ALLOCINFO_FILTER_MAX_SIZE)
> >>   diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
> >> index ddc6946f56ab..cbcd12c4ef9c 100644
> >> --- a/lib/alloc_tag.c
> >> +++ b/lib/alloc_tag.c
> >> @@ -249,6 +249,8 @@ static bool matches_filter(struct codetag *ct,
> >> struct allocinfo_filter *filter,
> >>                  struct alloc_tag_counters *counters,
> >>                  bool *fetched_counters)
> >>   {
> >> +    bool inaccurate;
> >> +
> >>       if (!filter || !filter->mask)
> >>           return true;
> >>   @@ -275,6 +277,12 @@ static bool matches_filter(struct codetag *ct,
> >> struct allocinfo_filter *filter,
> >>           ct->lineno != filter->fields.lineno)
> >>           return false;
> >>   +    if (filter->mask & ALLOCINFO_FILTER_MASK_INACCURATE) {
> >> +        inaccurate = !!(ct->flags & CODETAG_FLAG_INACCURATE);
> >> +        if (inaccurate != !!(filter->fields.inaccurate))
> >> +            return false;
> >> +    }
> >> +
> >>       if (filter->mask & (ALLOCINFO_FILTER_MASK_MIN_SIZE |
> >> ALLOCINFO_FILTER_MASK_MAX_SIZE)) {
> >>           if (!*fetched_counters) {
> >>               *counters = allocinfo_prefetch_counters(ct);

^ permalink raw reply

* Re: [PATCH v5 10/21] nfsd: add notification handlers for dir events
From: Chuck Lever @ 2026-06-08 20:52 UTC (permalink / raw)
  To: Jeff Layton, Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo,
	Tom Talpey, Trond Myklebust, Anna Schumaker, Jonathan Corbet,
	Shuah Khan
  Cc: Steven Rostedt, Alexander Aring, Amir Goldstein, Jan Kara,
	Alexander Viro, Christian Brauner, Calum Mackay, linux-kernel,
	linux-doc, linux-nfs
In-Reply-To: <20260522-dir-deleg-v5-10-542cddfad576@kernel.org>



On Fri, May 22, 2026, at 3:42 PM, Jeff Layton wrote:
> Add the necessary parts to accept a fsnotify callback for directory
> change event and create a CB_NOTIFY request for it. When a dir nfsd_file
> is created set a handle_event callback to handle the notification.

> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index e17488a911f7..31df04675713 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -4172,6 +4172,127 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, 
> struct xdr_stream *xdr,
>  	goto out;
>  }
> 
> +static bool
> +nfsd4_setup_notify_entry4(struct notify_entry4 *ne, struct xdr_stream 
> *xdr,
> +			  struct dentry *dentry, struct nfs4_delegation *dp,
> +			  struct nfsd_file *nf, char *name, u32 namelen)
> +{
> +	uint32_t *attrmask;
> +
> +	/* Reserve space for attrmask */
> +	attrmask = xdr_reserve_space(xdr, 3 * sizeof(uint32_t));
> +	if (!attrmask)
> +		return false;
> +
> +	ne->ne_file.data = name;
> +	ne->ne_file.len = namelen;
> +	ne->ne_attrs.attrmask.element = attrmask;
> +
> +	attrmask[0] = 0;
> +	attrmask[1] = 0;
> +	attrmask[2] = 0;
> +	ne->ne_attrs.attr_vals.data = NULL;
> +	ne->ne_attrs.attr_vals.len = 0;
> +	ne->ne_attrs.attrmask.count = 1;
> +	return true;
> +}
> +
> +/**
> + * nfsd4_encode_notify_event - encode a notify
> + * @xdr: stream to which to encode the fattr4
> + * @nne: nfsd_notify_event to encode
> + * @dp: delegation where the event occurred
> + * @nf: nfsd_file on which event occurred
> + * @notify_mask: pointer to word where notification mask should be set
> + *
> + * Encode @nne into @xdr. Returns a pointer to the start of the event, 
> or NULL if
> + * the event couldn't be encoded. The appropriate bit in the 
> notify_mask will also
> + * be set on success.
> + */
> +u8 *nfsd4_encode_notify_event(struct xdr_stream *xdr, struct 
> nfsd_notify_event *nne,
> +			      struct nfs4_delegation *dp, struct nfsd_file *nf,
> +			      u32 *notify_mask)
> +{
> +	u8 *p = NULL;
> +
> +	*notify_mask = 0;
> +
> +	if (nne->ne_mask & FS_DELETE) {
> +		struct notify_remove4 nr = { };
> +
> +		if (!nfsd4_setup_notify_entry4(&nr.nrm_old_entry, xdr, 
> nne->ne_dentry, dp,
> +					       nf, nne->ne_name, nne->ne_namelen))
> +			goto out_err;
> +		p = (u8 *)xdr->p;
> +		if (!xdrgen_encode_notify_remove4(xdr, &nr))
> +			goto out_err;
> +		*notify_mask |= BIT(NOTIFY4_REMOVE_ENTRY);
> +	} else if (nne->ne_mask & FS_CREATE) {
> +		struct notify_add4 na = { };
> +		struct notify_remove4 old = { };
> +
> +		if (!nfsd4_setup_notify_entry4(&na.nad_new_entry, xdr, 
> nne->ne_dentry, dp,
> +					       nf, nne->ne_name, nne->ne_namelen))
> +			goto out_err;
> +
> +		/* If a file was overwritten, report it in nad_old_entry */
> +		if (nne->ne_target) {
> +			if (!nfsd4_setup_notify_entry4(&old.nrm_old_entry, xdr,
> +						       NULL, dp, nf,
> +						       nne->ne_name, nne->ne_namelen))
> +				goto out_err;
> +			na.nad_old_entry.count = 1;
> +			na.nad_old_entry.element = &old;
> +		}
> +
> +		p = (u8 *)xdr->p;
> +		if (!xdrgen_encode_notify_add4(xdr, &na))
> +			goto out_err;
> +
> +		*notify_mask |= BIT(NOTIFY4_ADD_ENTRY);
> +	} else if (nne->ne_mask & FS_RENAME) {
> +		struct notify_rename4 nr = { };
> +		struct notify_remove4 old = { };
> +		struct name_snapshot n;
> +		bool ret;
> +
> +		/* Don't send any attributes in the old_entry since they're the same 
> in new */
> +		if (!nfsd4_setup_notify_entry4(&nr.nrn_old_entry.nrm_old_entry, xdr,
> +					       NULL, dp, nf, nne->ne_name,
> +					       nne->ne_namelen))
> +			goto out_err;
> +
> +		take_dentry_name_snapshot(&n, nne->ne_dentry);
> +		ret = nfsd4_setup_notify_entry4(&nr.nrn_new_entry.nad_new_entry, xdr,
> +					       nne->ne_dentry, dp, nf, (char *)n.name.name,
> +					       n.name.len);

Now once I got all of the previous edits in place, all three LLM
reviewers identified an issue here that might require a significant
rewrite. This is why I stopped the minor editing here and decided
it was time for you to consider restructuring (or not). I haven't
looked at patches 11-21.

  I think the new name here has a time-of-use problem.
  
  nrn_old_entry uses nne->ne_name, which alloc_nfsd_notify_event() copied
  when fsnotify delivered the rename.  nrn_new_entry instead reads the
  live dentry via take_dentry_name_snapshot() at callback-prepare time,
  which can run long after the event was queued.

  CB_NOTIFY is asynchronous: nfsd_handle_dir_event() queues the event on
  ncn_evt[] and nothing holds ne_dentry stable until the work runs.
  d_move() reuses the same dentry and rewrites d_name in place, so a
  second rename of the entry before the queued callback encodes leaves
  the dget'd ne_dentry carrying the later name.  An A->B event then
  encodes as A->C, and a client holding the directory delegation applies
  the wrong old->new mapping to its cache.  The old name is immune
  because it was snapshotted up front; only the new name is read late.

  The new name is available at notification time -- fsnotify_move() passes
  &moved->d_name as new_name, and ne_dentry is that moved dentry -- so
  alloc_nfsd_notify_event() can snapshot it alongside the old name.

What I haven't assessed is whether the suggested restructuring is
now vulnerable to misbehavior during memory exhaustion.


> +
> +		/* If a file was overwritten, report it in nad_old_entry */
> +		if (ret && nne->ne_target) {
> +			ret = nfsd4_setup_notify_entry4(&old.nrm_old_entry, xdr,
> +							NULL, dp, nf,
> +							(char *)n.name.name, n.name.len);
> +			if (ret) {
> +				nr.nrn_new_entry.nad_old_entry.count = 1;
> +				nr.nrn_new_entry.nad_old_entry.element = &old;
> +			}
> +		}
> +
> +		if (ret) {
> +			p = (u8 *)xdr->p;
> +			ret = xdrgen_encode_notify_rename4(xdr, &nr);
> +		}
> +		release_dentry_name_snapshot(&n);
> +		if (!ret)
> +			goto out_err;
> +		*notify_mask |= BIT(NOTIFY4_RENAME_ENTRY);
> +	}
> +	return p;
> +out_err:
> +	pr_warn("nfsd: unable to marshal notify_rename4 to xdr stream\n");
> +	return NULL;
> +}
> +
>  static void svcxdr_init_encode_from_buffer(struct xdr_stream *xdr,
>  				struct xdr_buf *buf, __be32 *p, int bytes)
>  {


-- 
Chuck Lever

^ permalink raw reply

* Re: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
From: David Matlack @ 2026-06-08 20:51 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: kexec, linux-doc, linux-kernel, linux-mm, linux-pci,
	Adithya Jayachandran, Alexander Graf, Alex Williamson,
	Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
	Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Leon Romanovsky,
	Lukas Wunner, Mike Rapoport, Parav Pandit, Pasha Tatashin,
	Pratyush Yadav, Saeed Mahameed, Samiullah Khawaja, Shuah Khan,
	Vipin Sharma, William Tu, Yi Liu
In-Reply-To: <aiJhoq_Yj6-1Hl5r@google.com>

On 2026-06-05 05:41 AM, Pranjal Shrivastava wrote:
> On Fri, May 22, 2026 at 08:23:59PM +0000, David Matlack wrote:
> > Set up a File-Lifecycle-Bound (FLB) handler for the PCI core to enable
> > it to participate in the preservation of PCI devices across Live Update.
> > Essentially, this commit enables the PCI core to allocate a struct
> > (struct pci_ser) and preserve it across a Live Update whenever at least
> > one device is preserved.
> > 
> > Preserving PCI devices across Live Update is built on top of the Live
> > Update Orchestrator's (LUO) support for file preservation. Drivers are
> > expected to expose a file to userspace to represent a single PCI device
> > and support preservation of that file. This is intended primarily to
> > support preservation of PCI devices bound to VFIO drivers.
> > 
> > This commit enables drivers to register their liveupdate_file_handler
> > with the PCI core so that the PCI core can do its own tracking and
> > enforcement of which devices are preserved.
> > 
> >   pci_liveupdate_register_flb(driver_file_handler);
> >   pci_liveupdate_unregister_flb(driver_file_handler);
> > 
> > When the first file (with a handler registered with the PCI core) is
> > preserved, the PCI core will be notified to allocate its tracking struct
> > (pci_ser). When the last file is unpreserved (i.e. preservation
> > cancelled) the PCI core will be notified to free struct pci_ser.
> > 
> > This struct is preserved across a Live Update using KHO and can be
> > fetched by the PCI core during early boot (e.g. during device
> > enumeration) so that it knows which devices were preserved.
> > 
> > Note: This commit only allocates struct pci_ser and preserves it across
> > Live Update. A subsequent commit will add an API for drivers to tell the
> > PCI core exactly which devices are being preserved.
> > 
> > Note: There is no reason to check for kho_is_enabled() since it can be
> > assumed to return true. If KHO was not enabled then Live Update would
> > not be enabled and these routines would never run.
> > 
> 
> [...]
> 
> > +/**
> > + * struct pci_dev_ser - Serialized state about a single PCI device.
> > + *
> > + * @domain: The device's PCI domain number (segment).
> > + * @bdf: The device's PCI bus, device, and function number.
> > + * @padding: Padding to naturally align struct pci_dev_ser.
> > + */
> > +struct pci_dev_ser {
> > +	u32 domain;
> > +	u16 bdf;
> > +	u16 padding;
> > +} __packed;
> > +
> > +/**
> > + * struct pci_ser - PCI Subsystem Live Update State
> > + *
> > + * This struct tracks state about all devices that are being preserved across
> > + * a Live Update for the next kernel.
> > + *
> > + * @max_nr_devices: The length of the devices[] flexible array.
> > + * @nr_devices: The number of devices that were preserved.
> > + * @devices: Flexible array of pci_dev_ser structs for each device.
> > + */
> > +struct pci_ser {
> > +	u32 max_nr_devices;
> > +	u32 nr_devices;
> > +	struct pci_dev_ser devices[];
> > +} __packed;
> > +
> > +/* Ensure all elements of devices[] are naturally aligned. */
> > +static_assert(offsetof(struct pci_ser, devices) % sizeof(unsigned long) == 0);
> > +static_assert(sizeof(struct pci_dev_ser) % sizeof(unsigned long) == 0);
> 
> Minor Nit: Shall we consider using specific bitwidth types here?
> I'm wondering if down the line another u32 field is added to 
> struct pci_dev_ser.. in that case on a 32-bit machine 12 % 4 == 0 but on
> a 64-bit machine 12 % 8 != 0..

I think natural alignment is what matters for efficient access of the
array elements. So failing the assert only on 64-bit architectures seems
like the correct behavior.

> 
> [...]
> 
> With the nit:
> 
> Reviewed-by: Pranjal Shrivastava <praan@google.com>
> 
> Thanks,
> Praan

^ permalink raw reply

* Re: [PATCH v5 10/21] nfsd: add notification handlers for dir events
From: Chuck Lever @ 2026-06-08 20:40 UTC (permalink / raw)
  To: Jeff Layton, Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo,
	Tom Talpey, Trond Myklebust, Anna Schumaker, Jonathan Corbet,
	Shuah Khan
  Cc: Steven Rostedt, Alexander Aring, Amir Goldstein, Jan Kara,
	Alexander Viro, Christian Brauner, Calum Mackay, linux-kernel,
	linux-doc, linux-nfs
In-Reply-To: <20260522-dir-deleg-v5-10-542cddfad576@kernel.org>



On Fri, May 22, 2026, at 3:42 PM, Jeff Layton wrote:
> Add the necessary parts to accept a fsnotify callback for directory
> change event and create a CB_NOTIFY request for it. When a dir nfsd_file
> is created set a handle_event callback to handle the notification.
>
> Use that to allocate a nfsd_notify_event object and then hand off a
> reference to each delegation's CB_NOTIFY. If anything fails along the
> way, recall any affected delegations.
>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>

There are some significant-looking sashiko review findings which I did
not follow up on.


> diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
> index ea3e7deb06fa..1964a213f80e 100644
> --- a/fs/nfsd/nfs4callback.c
> +++ b/fs/nfsd/nfs4callback.c
> @@ -870,21 +870,30 @@ static void nfs4_xdr_enc_cb_notify(struct 
> rpc_rqst *req,
>  				   const void *data)
>  {
>  	const struct nfsd4_callback *cb = data;
> +	struct nfsd4_cb_notify *ncn = container_of(cb, struct 
> nfsd4_cb_notify, ncn_cb);
> +	struct nfs4_delegation *dp = container_of(ncn, struct 
> nfs4_delegation, dl_cb_notify);
>  	struct nfs4_cb_compound_hdr hdr = {
>  		.ident = 0,
>  		.minorversion = cb->cb_clp->cl_minorversion,
>  	};
> -	struct CB_NOTIFY4args args = { };
> +	struct CB_NOTIFY4args args;
> +	__be32 *p;
> 
>  	WARN_ON_ONCE(hdr.minorversion == 0);
> 
>  	encode_cb_compound4args(xdr, &hdr);
>  	encode_cb_sequence4args(xdr, cb, &hdr);
> 
> -	/*
> -	 * FIXME: get stateid and fh from delegation. Inline the cna_changes
> -	 * buffer, and zero it.
> -	 */
> +	p = xdr_reserve_space(xdr, 4);
> +	*p = cpu_to_be32(OP_CB_NOTIFY);
> +
> +	args.cna_stateid.seqid = dp->dl_stid.sc_stateid.si_generation;
> +	memcpy(&args.cna_stateid.other, &dp->dl_stid.sc_stateid.si_opaque,
> +	       ARRAY_SIZE(args.cna_stateid.other));
> +	args.cna_fh.len = dp->dl_stid.sc_file->fi_fhandle.fh_size;
> +	args.cna_fh.data = dp->dl_stid.sc_file->fi_fhandle.fh_raw;
> +	args.cna_changes.count = ncn->ncn_nf_cnt;
> +	args.cna_changes.element = ncn->ncn_nf;
>  	WARN_ON_ONCE(!xdrgen_encode_CB_NOTIFY4args(xdr, &args));
> 
>  	hdr.nops++;

I want to avoid the need to use xdrgen to encode the CB_NOTIFY arguments.
How about this:

+       struct nfsd4_cb_notify *ncn = container_of(cb, struct nfsd4_cb_notify, ncn_cb);
+       struct nfs4_delegation *dp = container_of(ncn, struct nfs4_delegation, dl_cb_notify);

   ...

+       encode_stateid4(xdr, &dp->dl_stid.sc_stateid);
+       encode_nfs_fh4(xdr, &dp->dl_stid.sc_file->fi_fhandle);
+       xdr_stream_encode_u32(xdr, ncn->ncn_nf_cnt);
+       for (u32 i = 0; i < ncn->ncn_nf_cnt; i++)
+               (void)xdrgen_encode_notify4(xdr, &ncn->ncn_nf[i]);

And then add a "pragma public notify4;" in nfs4_1.x .


> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index b0652c755b3b..20477144475b 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c

> @@ -3461,19 +3462,131 @@ nfsd4_cb_getattr_release(struct nfsd4_callback *cb)
>  	nfs4_put_stid(&dp->dl_stid);
>  }
> 
> +static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
> +{
> +	bool queued;
> +
> +	if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &dp->dl_recall.cb_flags))
> +		return;
> +
> +	/*
> +	 * We're assuming the state code never drops its reference
> +	 * without first removing the lease.  Since we're in this lease
> +	 * callback (and since the lease code is serialized by the
> +	 * flc_lock) we know the server hasn't removed the lease yet, and
> +	 * we know it's safe to take a reference.
> +	 */
> +	refcount_inc(&dp->dl_stid.sc_count);
> +	queued = nfsd4_run_cb(&dp->dl_recall);
> +	WARN_ON_ONCE(!queued);
> +	if (!queued)
> +		refcount_dec(&dp->dl_stid.sc_count);
> +}
> +
> +static bool
> +nfsd4_cb_notify_prepare(struct nfsd4_callback *cb)
> +{
> +	struct nfsd4_cb_notify *ncn = container_of(cb, struct 
> nfsd4_cb_notify, ncn_cb);
> +	struct nfs4_delegation *dp = container_of(ncn, struct 
> nfs4_delegation, dl_cb_notify);
> +	struct nfsd_notify_event *events[NOTIFY4_EVENT_QUEUE_SIZE];
> +	struct xdr_buf xdr = { .buflen = PAGE_SIZE * NOTIFY4_PAGE_ARRAY_SIZE,
> +			       .pages  = ncn->ncn_pages };
> +	struct xdr_stream stream;
> +	struct nfsd_file *nf;
> +	int count, i;
> +	bool error = false;
> +
> +	xdr_init_encode_pages(&stream, &xdr);
> +
> +	spin_lock(&ncn->ncn_lock);
> +	count = ncn->ncn_evt_cnt;
> +
> +	/* spurious queueing? */
> +	if (count == 0) {
> +		spin_unlock(&ncn->ncn_lock);
> +		return false;
> +	}
> +
> +	/* we can't keep up! */
> +	if (count > NOTIFY4_EVENT_QUEUE_SIZE) {
> +		spin_unlock(&ncn->ncn_lock);
> +		goto out_recall;
> +	}
> +
> +	memcpy(events, ncn->ncn_evt, sizeof(*events) * count);
> +	ncn->ncn_evt_cnt = 0;
> +	spin_unlock(&ncn->ncn_lock);
> +
> +	rcu_read_lock();
> +	nf = 
> nfsd_file_get(rcu_dereference(dp->dl_stid.sc_file->fi_deleg_file));
> +	rcu_read_unlock();
> +	if (!nf) {
> +		for (i = 0; i < count; ++i)
> +			nfsd_notify_event_put(events[i]);
> +		goto out_recall;
> +	}
> +
> +	for (i = 0; i < count; ++i) {
> +		struct nfsd_notify_event *nne = events[i];
> +
> +		if (!error) {
> +			u32 *maskp = (u32 *)xdr_reserve_space(&stream, sizeof(*maskp));
> +			u8 *p;
> +
> +			if (!maskp) {
> +				error = true;
> +				goto put_event;
> +			}
> +
> +			p = nfsd4_encode_notify_event(&stream, nne, dp, nf, maskp);
> +			if (!p) {
> +				pr_notice("Could not generate CB_NOTIFY from fsnotify mask 0x%x\n",
> +					  nne->ne_mask);
> +				error = true;
> +				goto put_event;
> +			}
> +
> +			ncn->ncn_nf[i].notify_mask.count = 1;
> +			ncn->ncn_nf[i].notify_mask.element = maskp;
> +			ncn->ncn_nf[i].notify_vals.data = p;
> +			ncn->ncn_nf[i].notify_vals.len = (u8 *)stream.p - p;
> +		}
> +put_event:
> +		nfsd_notify_event_put(nne);
> +	}
> +	if (!error) {
> +		ncn->ncn_nf_cnt = count;
> +		nfsd_file_put(nf);
> +		return true;
> +	}
> +	nfsd_file_put(nf);
> +out_recall:
> +	nfsd_break_one_deleg(dp);
> +	return false;
> +}
> +
>  static int
>  nfsd4_cb_notify_done(struct nfsd4_callback *cb,
>  				struct rpc_task *task)
>  {
> +	struct nfsd4_cb_notify *ncn = container_of(cb, struct 
> nfsd4_cb_notify, ncn_cb);
> +	struct nfs4_delegation *dp = container_of(ncn, struct 
> nfs4_delegation, dl_cb_notify);
> +
>  	switch (task->tk_status) {
>  	case -NFS4ERR_DELAY:
>  		rpc_delay(task, 2 * HZ);
>  		return 0;
>  	default:
> +		/* For any other hard error, recall the deleg */
> +		nfsd_break_one_deleg(dp);
> +		fallthrough;
> +	case 0:
>  		return 1;
>  	}
>  }
> 
> +static void nfsd4_run_cb_notify(struct nfsd4_cb_notify *ncn);
> +
>  static void
>  nfsd4_cb_notify_release(struct nfsd4_callback *cb)
>  {
> @@ -3482,6 +3595,9 @@ nfsd4_cb_notify_release(struct nfsd4_callback *cb)
>  	struct nfs4_delegation *dp =
>  			container_of(ncn, struct nfs4_delegation, dl_cb_notify);
> 
> +	/* Drain events that arrived while this callback was in flight */
> +	if (ncn->ncn_evt_cnt > 0)
> +		nfsd4_run_cb_notify(ncn);

The above check needs to be serialized with modification of
ncn_evt_cnt:

+       bool pending;
 
+       /* Drain events that arrived while this callback was in flight */
+       spin_lock(&ncn->ncn_lock);
+       pending = ncn->ncn_evt_cnt > 0;
+       spin_unlock(&ncn->ncn_lock);
+       if (pending)
+               nfsd4_run_cb_notify(ncn);


>  	nfs4_put_stid(&dp->dl_stid);
>  }
> 

> @@ -9858,3 +9954,133 @@ void nfsd_update_cmtime_attr(struct file *f, 
> unsigned int flags)
>  				      MINOR(inode->i_sb->s_dev),
>  				      inode->i_ino, ret);
>  }
> +
> +static void
> +nfsd4_run_cb_notify(struct nfsd4_cb_notify *ncn)
> +{
> +	struct nfs4_delegation *dp = container_of(ncn, struct 
> nfs4_delegation, dl_cb_notify);
> +
> +	if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &ncn->ncn_cb.cb_flags))
> +		return;
> +
> +	if (!refcount_inc_not_zero(&dp->dl_stid.sc_count))
> +		clear_bit(NFSD4_CALLBACK_RUNNING, &ncn->ncn_cb.cb_flags);
> +	else
> +		nfsd4_run_cb(&ncn->ncn_cb);
> +}
> +
> +static struct nfsd_notify_event *
> +alloc_nfsd_notify_event(u32 mask, const struct qstr *q, struct dentry 
> *dentry,
> +			struct inode *target)
> +{
> +	struct nfsd_notify_event *ne;
> +
> +	ne = kmalloc(sizeof(*ne) + q->len + 1, GFP_NOFS);
> +	if (!ne)
> +		return NULL;
> +
> +	memcpy(&ne->ne_name, q->name, q->len);
> +	refcount_set(&ne->ne_ref, 1);
> +	ne->ne_mask = mask;
> +	ne->ne_name[q->len] = '\0';
> +	ne->ne_namelen = q->len;
> +	ne->ne_dentry = dget(dentry);
> +	ne->ne_target = target;
> +	if (ne->ne_target)
> +		ihold(ne->ne_target);
> +	return ne;
> +}
> +
> +static bool
> +should_notify_deleg(u32 mask, struct file_lease *fl)
> +{
> +	/* Don't notify the client generating the event */
> +	if (nfsd_breaker_owns_lease(fl))
> +		return false;
> +
> +	/* Skip if this event wasn't ignored by the lease */
> +	if ((mask & FS_DELETE) && !(fl->c.flc_flags & FL_IGN_DIR_DELETE))
> +		return false;
> +	if ((mask & FS_CREATE) && !(fl->c.flc_flags & FL_IGN_DIR_CREATE))
> +		return false;
> +	if ((mask & FS_RENAME) && !(fl->c.flc_flags & FL_IGN_DIR_RENAME))
> +		return false;
> +
> +	return true;
> +}
> +
> +static void
> +nfsd_recall_all_dir_delegs(const struct inode *dir)
> +{
> +	struct file_lock_context *ctx = locks_inode_context(dir);
> +	struct file_lock_core *flc;
> +
> +	spin_lock(&ctx->flc_lock);
> +	list_for_each_entry(flc, &ctx->flc_lease, flc_list) {
> +		struct file_lease *fl = container_of(flc, struct file_lease, c);
> +
> +		if (fl->fl_lmops == &nfsd_lease_mng_ops)
> +			nfsd_break_deleg_cb(fl);
> +	}
> +	spin_unlock(&ctx->flc_lock);
> +}
> +
> +int
> +nfsd_handle_dir_event(u32 mask, const struct inode *dir, const void 
> *data,
> +		      int data_type, const struct qstr *name)
> +{
> +	struct dentry *dentry = fsnotify_data_dentry(data, data_type);
> +	struct inode *target = fsnotify_data_rename_target(data, data_type);
> +	struct file_lock_context *ctx;
> +	struct file_lock_core *flc;
> +	struct nfsd_notify_event *evt;
> +
> +	/* Normalize cross-dir rename events to create/delete */
> +	if (mask & FS_MOVED_FROM) {
> +		mask &= ~FS_MOVED_FROM;
> +		mask |= FS_DELETE;
> +	}
> +	if (mask & FS_MOVED_TO) {
> +		mask &= ~FS_MOVED_TO;
> +		mask |= FS_CREATE;
> +	}
> +

I inserted an extra check here for rename notifications:

+       /*
+        * FS_RENAME fires on the source directory even for a cross-dir
+        * rename, where the moved entry now lives under a different
+        * parent. NOTIFY4_RENAME_ENTRY describes an in-place rename, so
+        * reporting it here would advertise a name absent from this
+        * directory.
+        */
+       if ((mask & FS_RENAME) && dentry && d_inode(dentry->d_parent) != dir)
+               mask &= ~FS_RENAME;


> +	/* Don't do anything if this is not an expected event */
> +	if (!(mask & (FS_CREATE|FS_DELETE|FS_RENAME)))
> +		return 0;
> +
> +	ctx = locks_inode_context(dir);
> +	if (!ctx || list_empty(&ctx->flc_lease))
> +		return 0;
> +
> +	evt = alloc_nfsd_notify_event(mask, name, dentry, target);
> +	if (!evt) {
> +		nfsd_recall_all_dir_delegs(dir);
> +		return 0;
> +	}
> +
> +	spin_lock(&ctx->flc_lock);
> +	list_for_each_entry(flc, &ctx->flc_lease, flc_list) {
> +		struct file_lease *fl = container_of(flc, struct file_lease, c);
> +		struct nfs4_delegation *dp = flc->flc_owner;
> +		struct nfsd4_cb_notify *ncn = &dp->dl_cb_notify;
> +

I added:

+               if (fl->fl_lmops != &nfsd_lease_mng_ops)
+                       continue;

Otherwise the loop treats every lease on the inode as an nfsd delegation
unconditionally.


> +		if (!should_notify_deleg(mask, fl))
> +			continue;
> +
> +		spin_lock(&ncn->ncn_lock);
> +		if (ncn->ncn_evt_cnt >= NOTIFY4_EVENT_QUEUE_SIZE) {
> +			/* We're generating notifications too fast. Recall. */
> +			spin_unlock(&ncn->ncn_lock);
> +			nfsd_break_deleg_cb(fl);
> +			continue;
> +		}
> +		ncn->ncn_evt[ncn->ncn_evt_cnt++] = nfsd_notify_event_get(evt);
> +		spin_unlock(&ncn->ncn_lock);
> +
> +		nfsd4_run_cb_notify(ncn);
> +	}
> +	spin_unlock(&ctx->flc_lock);
> +	nfsd_notify_event_put(evt);
> +	return 0;
> +}
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index e17488a911f7..31df04675713 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -4172,6 +4172,127 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, 
> struct xdr_stream *xdr,
>  	goto out;
>  }
> 
> +static bool
> +nfsd4_setup_notify_entry4(struct notify_entry4 *ne, struct xdr_stream 
> *xdr,
> +			  struct dentry *dentry, struct nfs4_delegation *dp,
> +			  struct nfsd_file *nf, char *name, u32 namelen)
> +{
> +	uint32_t *attrmask;
> +
> +	/* Reserve space for attrmask */
> +	attrmask = xdr_reserve_space(xdr, 3 * sizeof(uint32_t));
> +	if (!attrmask)
> +		return false;
> +
> +	ne->ne_file.data = name;
> +	ne->ne_file.len = namelen;
> +	ne->ne_attrs.attrmask.element = attrmask;
> +
> +	attrmask[0] = 0;
> +	attrmask[1] = 0;
> +	attrmask[2] = 0;
> +	ne->ne_attrs.attr_vals.data = NULL;
> +	ne->ne_attrs.attr_vals.len = 0;
> +	ne->ne_attrs.attrmask.count = 1;
> +	return true;
> +}
> +
> +/**
> + * nfsd4_encode_notify_event - encode a notify
> + * @xdr: stream to which to encode the fattr4
> + * @nne: nfsd_notify_event to encode
> + * @dp: delegation where the event occurred
> + * @nf: nfsd_file on which event occurred
> + * @notify_mask: pointer to word where notification mask should be set
> + *
> + * Encode @nne into @xdr. Returns a pointer to the start of the event, 
> or NULL if
> + * the event couldn't be encoded. The appropriate bit in the 
> notify_mask will also
> + * be set on success.
> + */

Nit: Let's use the usual kdoc style to describe the return value.

+ * Encode @nne into @xdr. The matching bit in @notify_mask is set on
+ * success.
+ *
+ * Return: pointer to the start of the encoded event, or NULL if the
+ * event could not be encoded.
+ */


> +u8 *nfsd4_encode_notify_event(struct xdr_stream *xdr, struct 
> nfsd_notify_event *nne,
> +			      struct nfs4_delegation *dp, struct nfsd_file *nf,
> +			      u32 *notify_mask)
> +{
> +	u8 *p = NULL;
> +
> +	*notify_mask = 0;
> +
> +	if (nne->ne_mask & FS_DELETE) {
> +		struct notify_remove4 nr = { };
> +
> +		if (!nfsd4_setup_notify_entry4(&nr.nrm_old_entry, xdr, 
> nne->ne_dentry, dp,
> +					       nf, nne->ne_name, nne->ne_namelen))
> +			goto out_err;
> +		p = (u8 *)xdr->p;
> +		if (!xdrgen_encode_notify_remove4(xdr, &nr))
> +			goto out_err;
> +		*notify_mask |= BIT(NOTIFY4_REMOVE_ENTRY);
> +	} else if (nne->ne_mask & FS_CREATE) {
> +		struct notify_add4 na = { };
> +		struct notify_remove4 old = { };
> +
> +		if (!nfsd4_setup_notify_entry4(&na.nad_new_entry, xdr, 
> nne->ne_dentry, dp,
> +					       nf, nne->ne_name, nne->ne_namelen))
> +			goto out_err;
> +
> +		/* If a file was overwritten, report it in nad_old_entry */
> +		if (nne->ne_target) {
> +			if (!nfsd4_setup_notify_entry4(&old.nrm_old_entry, xdr,
> +						       NULL, dp, nf,
> +						       nne->ne_name, nne->ne_namelen))
> +				goto out_err;
> +			na.nad_old_entry.count = 1;
> +			na.nad_old_entry.element = &old;
> +		}
> +
> +		p = (u8 *)xdr->p;
> +		if (!xdrgen_encode_notify_add4(xdr, &na))
> +			goto out_err;
> +
> +		*notify_mask |= BIT(NOTIFY4_ADD_ENTRY);
> +	} else if (nne->ne_mask & FS_RENAME) {
> +		struct notify_rename4 nr = { };
> +		struct notify_remove4 old = { };
> +		struct name_snapshot n;
> +		bool ret;
> +
> +		/* Don't send any attributes in the old_entry since they're the same 
> in new */
> +		if (!nfsd4_setup_notify_entry4(&nr.nrn_old_entry.nrm_old_entry, xdr,
> +					       NULL, dp, nf, nne->ne_name,
> +					       nne->ne_namelen))
> +			goto out_err;
> +
> +		take_dentry_name_snapshot(&n, nne->ne_dentry);
> +		ret = nfsd4_setup_notify_entry4(&nr.nrn_new_entry.nad_new_entry, xdr,
> +					       nne->ne_dentry, dp, nf, (char *)n.name.name,
> +					       n.name.len);
> +
> +		/* If a file was overwritten, report it in nad_old_entry */
> +		if (ret && nne->ne_target) {
> +			ret = nfsd4_setup_notify_entry4(&old.nrm_old_entry, xdr,
> +							NULL, dp, nf,
> +							(char *)n.name.name, n.name.len);
> +			if (ret) {
> +				nr.nrn_new_entry.nad_old_entry.count = 1;
> +				nr.nrn_new_entry.nad_old_entry.element = &old;
> +			}
> +		}
> +
> +		if (ret) {
> +			p = (u8 *)xdr->p;
> +			ret = xdrgen_encode_notify_rename4(xdr, &nr);
> +		}
> +		release_dentry_name_snapshot(&n);
> +		if (!ret)
> +			goto out_err;
> +		*notify_mask |= BIT(NOTIFY4_RENAME_ENTRY);
> +	}
> +	return p;
> +out_err:
> +	pr_warn("nfsd: unable to marshal notify_rename4 to xdr stream\n");

Nit: The warning needs to match the semantics of nfsd4_encode_notify_event().
How about:

+       pr_warn("nfsd: unable to marshal notify event to xdr stream\n");


> +	return NULL;
> +}
> +


-- 
Chuck Lever

^ permalink raw reply

* Re: [PATCH v16 08/14] iio: core: add decimal value formatting into 64-bit value
From: Nuno Sá @ 2026-06-08 20:32 UTC (permalink / raw)
  To: rodrigo.alencar, linux-kernel, linux-iio, devicetree, linux-doc,
	linux
  Cc: Jonathan Cameron, David Lechner, Andy Shevchenko,
	Lars-Peter Clausen, Michael Hennerich, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet, Andrew Morton,
	Petr Mladek, Steven Rostedt, Andy Shevchenko, Rasmus Villemoes,
	Sergey Senozhatsky, Shuah Khan
In-Reply-To: <20260604-adf41513-iio-driver-v16-8-1a7d09143bc2@analog.com>

On Thu, 2026-06-04 at 10:59 +0100, Rodrigo Alencar via B4 Relay wrote:
> From: Rodrigo Alencar <rodrigo.alencar@analog.com>
> 
> Create new format types for iio values (IIO_VAL_DECIMAL64_*), which
> defines the representation of fixed decimal point values into a single
> 64-bit number. This new format increases the range of represented values,
> allowing for integer parts greater than 2^32, as bits are not "wasted"
> in the fractional part, which can be seen in IIO_VAL_INT_PLUS_MICRO and
> IIO_VAL_INT_PLUS_NANO. Helpers are created to compose and decompose 64-bit
> decimals into integer values used in IIO formatting interfaces, which
> creates consistency and avoid error-prone manual assignments when using
> wordpart macros. When doing the parsing, kstrtodec64() is used with the
> scale defined by the specific decimal format type.
> 
> Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
> ---

Reviewed-by: Nuno Sá <nuno.sa@analog.com>

>  drivers/iio/industrialio-core.c | 49 ++++++++++++++++++++++++++++++++---------
>  include/linux/iio/types.h       | 20 +++++++++++++++++
>  2 files changed, 59 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> index ffe0dc49c4b9..93c2540d4cd2 100644
> --- a/drivers/iio/industrialio-core.c
> +++ b/drivers/iio/industrialio-core.c
> @@ -19,6 +19,7 @@
>  #include <linux/idr.h>
>  #include <linux/kdev_t.h>
>  #include <linux/kernel.h>
> +#include <linux/math64.h>
>  #include <linux/module.h>
>  #include <linux/mutex.h>
>  #include <linux/poll.h>
> @@ -26,7 +27,6 @@
>  #include <linux/sched.h>
>  #include <linux/slab.h>
>  #include <linux/wait.h>
> -#include <linux/wordpart.h>
>  
>  #include <linux/iio/buffer.h>
>  #include <linux/iio/buffer_impl.h>
> @@ -656,6 +656,7 @@ static ssize_t __iio_format_value(char *buf, size_t offset,
> unsigned int type,
>  				  int size, const int *vals)
>  {
>  	int tmp0, tmp1;
> +	int l = 0;
>  	s64 tmp2;
>  	bool scale_db = false;
>  
> @@ -699,7 +700,6 @@ static ssize_t __iio_format_value(char *buf, size_t offset,
> unsigned int type,
>  	case IIO_VAL_INT_MULTIPLE:
>  	{
>  		int i;
> -		int l = 0;
>  
>  		for (i = 0; i < size; ++i)
>  			l += sysfs_emit_at(buf, offset + l, "%d ", vals[i]);
> @@ -708,8 +708,25 @@ static ssize_t __iio_format_value(char *buf, size_t offset,
> unsigned int type,
>  	case IIO_VAL_CHAR:
>  		return sysfs_emit_at(buf, offset, "%c", (char)vals[0]);
>  	case IIO_VAL_INT_64:
> -		tmp2 = (s64)((((u64)vals[1]) << 32) | (u32)vals[0]);
> -		return sysfs_emit_at(buf, offset, "%lld", tmp2);
> +		return sysfs_emit_at(buf, offset, "%lld",
> +				     iio_val_s64_compose(vals[0], vals[1]));
> +	case IIO_VAL_DECIMAL64_MILLI:
> +	case IIO_VAL_DECIMAL64_MICRO:
> +	case IIO_VAL_DECIMAL64_NANO:
> +	case IIO_VAL_DECIMAL64_PICO:
> +	{
> +		int scale = type - IIO_VAL_DECIMAL64_BASE;
> +		s64 frac;
> +
> +		tmp2 = div64_s64_rem(iio_val_s64_compose(vals[0], vals[1]),
> +				     int_pow(10, scale), &frac);
> +		if (tmp2 == 0 && frac < 0)
> +			l += sysfs_emit_at(buf, offset, "-");
> +
> +		l += sysfs_emit_at(buf, offset + l, "%lld.%0*lld", tmp2, scale,
> +				   abs(frac));
> +		return l;
> +	}
>  	default:
>  		return 0;
>  	}
> @@ -979,6 +996,7 @@ static ssize_t iio_write_channel_info(struct device *dev,
>  	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
>  	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
>  	int ret, fract_mult = 100000;
> +	int type, dec_scale = 0;
>  	int integer, fract = 0;
>  	long long integer64;
>  	bool is_char = false;
> @@ -989,9 +1007,11 @@ static ssize_t iio_write_channel_info(struct device *dev,
>  	if (!indio_dev->info->write_raw)
>  		return -EINVAL;
>  
> -	if (indio_dev->info->write_raw_get_fmt)
> -		switch (indio_dev->info->write_raw_get_fmt(indio_dev,
> -			this_attr->c, this_attr->address)) {
> +	if (indio_dev->info->write_raw_get_fmt) {
> +		type = indio_dev->info->write_raw_get_fmt(indio_dev,
> +							  this_attr->c,
> +							  this_attr->address);
> +		switch (type) {
>  		case IIO_VAL_INT:
>  			fract_mult = 0;
>  			break;
> @@ -1007,12 +1027,19 @@ static ssize_t iio_write_channel_info(struct device *dev,
>  		case IIO_VAL_CHAR:
>  			is_char = true;
>  			break;
> +		case IIO_VAL_DECIMAL64_MILLI:
> +		case IIO_VAL_DECIMAL64_MICRO:
> +		case IIO_VAL_DECIMAL64_NANO:
> +		case IIO_VAL_DECIMAL64_PICO:
> +			dec_scale = type - IIO_VAL_DECIMAL64_BASE;
> +			fallthrough;
>  		case IIO_VAL_INT_64:
>  			is_64bit = true;
>  			break;
>  		default:
>  			return -EINVAL;
>  		}
> +	}
>  
>  	if (is_char) {
>  		char ch;
> @@ -1021,12 +1048,14 @@ static ssize_t iio_write_channel_info(struct device *dev,
>  			return -EINVAL;
>  		integer = ch;
>  	} else if (is_64bit) {
> -		ret = kstrtoll(buf, 0, &integer64);
> +		if (dec_scale)
> +			ret = kstrtodec64(buf, dec_scale, &integer64);
> +		else
> +			ret = kstrtoll(buf, 0, &integer64);
>  		if (ret)
>  			return ret;
>  
> -		fract = upper_32_bits(integer64);
> -		integer = lower_32_bits(integer64);
> +		iio_val_s64_decompose(integer64, &integer, &fract);
>  	} else {
>  		ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract,
>  					    scale_db);
> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> index 4e3099defc1d..924ac9dc6893 100644
> --- a/include/linux/iio/types.h
> +++ b/include/linux/iio/types.h
> @@ -7,6 +7,9 @@
>  #ifndef _IIO_TYPES_H_
>  #define _IIO_TYPES_H_
>  
> +#include <linux/types.h>
> +#include <linux/wordpart.h>
> +
>  #include <uapi/linux/iio/types.h>
>  
>  enum iio_event_info {
> @@ -34,6 +37,23 @@ enum iio_event_info {
>  #define IIO_VAL_FRACTIONAL_LOG2 11
>  #define IIO_VAL_CHAR 12
>  
> +#define IIO_VAL_DECIMAL64_BASE		32
> +#define IIO_VAL_DECIMAL64_MILLI		(IIO_VAL_DECIMAL64_BASE + 3)
> +#define IIO_VAL_DECIMAL64_MICRO		(IIO_VAL_DECIMAL64_BASE + 6)
> +#define IIO_VAL_DECIMAL64_NANO		(IIO_VAL_DECIMAL64_BASE + 9)
> +#define IIO_VAL_DECIMAL64_PICO		(IIO_VAL_DECIMAL64_BASE + 12)
> +
> +static inline s64 iio_val_s64_compose(s32 val0, s32 val1)
> +{
> +	return (s64)(((u64)val1 << 32) | (u32)val0);
> +}
> +
> +static inline void iio_val_s64_decompose(s64 dec64, s32 *val0, s32 *val1)
> +{
> +	*val0 = lower_32_bits(dec64);
> +	*val1 = upper_32_bits(dec64);
> +}
> +
>  enum iio_available_type {
>  	IIO_AVAIL_LIST,
>  	IIO_AVAIL_RANGE,

^ permalink raw reply

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

On Tue, 7 Apr 2026 22:40:55 +0300 Tariq Toukan wrote:
> Userspace patches for iproute2:
> https://github.com/ohartoov/iproute2/tree/port_resources

Hi! As far as I can tell these iproute2 patches have not even been
posted? Please try to get them upstream ASAP, we have to manually 
carry them in the CI right now.

^ permalink raw reply

* Re: [PATCH v3 2/4] mm/zswap: Implement proactive writeback
From: Yosry Ahmed @ 2026-06-08 20:19 UTC (permalink / raw)
  To: Shakeel Butt
  Cc: Hao Jia, Johannes Weiner, mhocko, tj, mkoutny, roman.gushchin,
	Nhat Pham, akpm, chengming.zhou, muchun.song, cgroups, linux-mm,
	linux-kernel, linux-doc, Hao Jia, youngjun.park
In-Reply-To: <aicZ-5GX9De3MAU7@linux.dev>

On Mon, Jun 8, 2026 at 12:50 PM Shakeel Butt <shakeel.butt@linux.dev> wrote:
>
> +Youngjun
>
> On Mon, Jun 08, 2026 at 11:30:30AM -0700, Shakeel Butt wrote:
> > On Wed, Jun 03, 2026 at 10:36:07PM -0700, Yosry Ahmed wrote:
> > > > >> But doesn't it make more sense to specify the compressed size, which is
> > > > >> ultimately the amount of memory you actually want to reclaim.
> > > > >>
> > > > >
> > > > > I personally prefer compressed size to pre-compressed size. That's
> > > > > kinda what user cares about, no?
> > > > >
> > > > > One thing we can do is let users prescribe a compressed size, but
> > > > > internally, we can multiply that by the average compression ratio.
> > > > > That gives us a guesstimate of how many pages we need to reclaim, and
> > > > > you can follow the rest of your implementation as is (perhaps with
> > > > > short-circuit when we reach the goal with fewer pages reclaimed).
> > > >
> > > > Got it. I will change it to use the compressed size in the next version.
> > > >
> > > > Yosry, Nhat, should we continue using the zswap_writeback_only key to
> > > > trigger proactive writeback?
> > >
> > > I *really* want the memcg maintainers to chime in here, it's
> > > ultimately their call.
> > >
> > > Michal? Johannes? Shakeel? Roman? Anyone? :D
> >
> > Between the options of having an explicit interface (i.e.
> > memory.zswap.writeback*) or a key (i.e. zswap_writeback_only) to memory.reclaim
> > interface, I prefer the key option. I have not looked into how much proactively
> > reclaiming zswap memory or proactively triggering zswap writeback makes sense
> > but from the perspective of memcg interface, I think the key option would give a
> > more clean solution if we decide in the future that this whole thing was a bad
> > idea.
> >
> > Next regarding future proofing zswap writeback trigger, do we expect any
> > potential additions/changes/new-features for this interface? For example do we
> > expect in future we may want to trigger the zswap writeback only from a specific
> > node or lowest memory tier?

The way I see it, zswap writeback is just a "special" type of
proactive reclaim, but the goal is still proactively freeing cold
memory. In that regard, I think it makes sense to have things like
node-specific reclaim. Not sure about other extensions, but Hao
initially suggested making this age-based, so I think the answer is
yes.

For both of these examples (node-specific reclaim, age-based reclaim),
I think the same semantics could apply to memory.reclaim in general,
which is why I suggested making it a part of memory.reclaim. I also
like the idea of having a single proactive reclaim interface in
general, but maybe we don't want to overload it too much.

> Youngjun is working on swap tiers. At the moment he is more interested in
> allowing a specific swap device to a memcg or not. I can imagine in future there
> will be use-cases where there will be a need to demote data on higher tier swap
> to lower tier swap. What would be the appropriate interface?
>
> BTW does zswap folks think of zswap as a top swap tier or something different?

I haven't been following the swap tiers work closely, but personally I
do think of zswap as a top swap tier. Things will probably get more
blurry with memory tiers and compressed memory nodes though.

^ permalink raw reply

* Re: [PATCH v5 09/21] nfsd: add data structures for handling CB_NOTIFY
From: Chuck Lever @ 2026-06-08 20:18 UTC (permalink / raw)
  To: Jeff Layton, Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo,
	Tom Talpey, Trond Myklebust, Anna Schumaker, Jonathan Corbet,
	Shuah Khan
  Cc: Steven Rostedt, Alexander Aring, Amir Goldstein, Jan Kara,
	Alexander Viro, Christian Brauner, Calum Mackay, linux-kernel,
	linux-doc, linux-nfs
In-Reply-To: <20260522-dir-deleg-v5-9-542cddfad576@kernel.org>



On Fri, May 22, 2026, at 3:42 PM, Jeff Layton wrote:
> Add the data structures, allocation helpers, and callback operations
> needed for directory delegation CB_NOTIFY support:

> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index 9c6e2e7abc82..505fabf8f1bf 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -197,6 +197,44 @@ struct nfs4_cb_fattr {
>  #define NOTIFY4_EVENT_QUEUE_SIZE	3
>  #define NOTIFY4_PAGE_ARRAY_SIZE		1
> 
> +struct nfsd_notify_event {
> +	refcount_t	ne_ref;		// refcount
> +	u32		ne_mask;	// FS_* mask from fsnotify callback
> +	struct dentry	*ne_dentry;	// dentry reference to target
> +	u32		ne_namelen;	// length of ne_name
> +	char		ne_name[];	// name of dentry being changed

Nit: checkpatch doesn't like the C++ comment style.


> +};
> +
> +static inline struct nfsd_notify_event *nfsd_notify_event_get(struct 
> nfsd_notify_event *ne)
> +{
> +	refcount_inc(&ne->ne_ref);
> +	return ne;
> +}
> +
> +static inline void nfsd_notify_event_put(struct nfsd_notify_event *ne)
> +{
> +	if (refcount_dec_and_test(&ne->ne_ref)) {
> +		dput(ne->ne_dentry);
> +		kfree(ne);
> +	}
> +}
> +
> +/*
> + * Represents a directory delegation. The callback is for handling 
> CB_NOTIFYs.
> + * As notifications from fsnotify come in, allocate a new event, take 
> the ncn_lock,
> + * and add it to the ncn_evt queue. The CB_NOTIFY prepare handler will 
> take the
> + * lock, clean out the list and process it.
> + */
> +struct nfsd4_cb_notify {
> +	spinlock_t			ncn_lock;	// protects the evt queue and count
> +	int				ncn_evt_cnt;	// count of events in ncn_evt
> +	int				ncn_nf_cnt;	// count of valid entries in ncn_nf
> +	struct nfsd_notify_event	*ncn_evt[NOTIFY4_EVENT_QUEUE_SIZE]; // list 
> of events
> +	struct page			*ncn_pages[NOTIFY4_PAGE_ARRAY_SIZE]; // for encoding
> +	struct notify4			*ncn_nf;	// array of notify4's to be sent
> +	struct nfsd4_callback		ncn_cb;		// notify4 callback
> +};

Ditto.


-- 
Chuck Lever

^ permalink raw reply

* Re: [PATCH v3 2/4] mm/zswap: Implement proactive writeback
From: Shakeel Butt @ 2026-06-08 19:50 UTC (permalink / raw)
  To: Yosry Ahmed
  Cc: Hao Jia, Johannes Weiner, mhocko, tj, mkoutny, roman.gushchin,
	Nhat Pham, akpm, chengming.zhou, muchun.song, cgroups, linux-mm,
	linux-kernel, linux-doc, Hao Jia, youngjun.park
In-Reply-To: <aicJBVT4pBvmyooT@linux.dev>

+Youngjun

On Mon, Jun 08, 2026 at 11:30:30AM -0700, Shakeel Butt wrote:
> On Wed, Jun 03, 2026 at 10:36:07PM -0700, Yosry Ahmed wrote:
> > > >> But doesn't it make more sense to specify the compressed size, which is
> > > >> ultimately the amount of memory you actually want to reclaim.
> > > >>
> > > >
> > > > I personally prefer compressed size to pre-compressed size. That's
> > > > kinda what user cares about, no?
> > > >
> > > > One thing we can do is let users prescribe a compressed size, but
> > > > internally, we can multiply that by the average compression ratio.
> > > > That gives us a guesstimate of how many pages we need to reclaim, and
> > > > you can follow the rest of your implementation as is (perhaps with
> > > > short-circuit when we reach the goal with fewer pages reclaimed).
> > >
> > > Got it. I will change it to use the compressed size in the next version.
> > >
> > > Yosry, Nhat, should we continue using the zswap_writeback_only key to
> > > trigger proactive writeback?
> > 
> > I *really* want the memcg maintainers to chime in here, it's
> > ultimately their call.
> > 
> > Michal? Johannes? Shakeel? Roman? Anyone? :D
> 
> Between the options of having an explicit interface (i.e.
> memory.zswap.writeback*) or a key (i.e. zswap_writeback_only) to memory.reclaim
> interface, I prefer the key option. I have not looked into how much proactively
> reclaiming zswap memory or proactively triggering zswap writeback makes sense
> but from the perspective of memcg interface, I think the key option would give a
> more clean solution if we decide in the future that this whole thing was a bad
> idea.
> 
> Next regarding future proofing zswap writeback trigger, do we expect any
> potential additions/changes/new-features for this interface? For example do we
> expect in future we may want to trigger the zswap writeback only from a specific
> node or lowest memory tier?

Youngjun is working on swap tiers. At the moment he is more interested in
allowing a specific swap device to a memcg or not. I can imagine in future there
will be use-cases where there will be a need to demote data on higher tier swap
to lower tier swap. What would be the appropriate interface?

BTW does zswap folks think of zswap as a top swap tier or something different?

^ permalink raw reply

* Re: [PATCH v16 00/10] arm64/riscv: Add support for crashkernel CMA reservation
From: Mike Rapoport @ 2026-06-08 19:00 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Jinjie Ruan, corbet, skhan, catalin.marinas, will, chenhuacai,
	kernel, maddy, mpe, npiggin, chleroy, pjw, palmer, aou, alex,
	tglx, mingo, bp, dave.hansen, hpa, robh, saravanak, bhe,
	pasha.tatashin, pratyush, ruirui.yang, rdunlap, peterz, feng.tang,
	dapeng1.mi, kees, elver, kuba, lirongqing, ebiggers, paulmck,
	leitao, coxu, Liam.Howlett, ryan.roberts, osandov, jbohac,
	cfsworks, tangyouling, sourabhjain, ritesh.list, adityag,
	liaoyuanhong, seanjc, fuqiang.wang, ardb, chenjiahao16, guoren,
	x86, linux-doc, linux-kernel, linux-arm-kernel, loongarch,
	linuxppc-dev, linux-riscv, devicetree, kexec
In-Reply-To: <20260608091000.d88d7f5cc1bc4fa17f5774fe@linux-foundation.org>

On Mon, Jun 08, 2026 at 09:10:00AM -0700, Andrew Morton wrote:
> On Mon, 8 Jun 2026 15:34:49 +0800 Jinjie Ruan <ruanjinjie@huawei.com> wrote:
> 
> > The crash memory allocation, and the exclude of crashk_res, crashk_low_res
> > and crashk_cma memory are almost identical across different architectures,
> > This patch set handle them in crash core in a general way, which eliminate
> > a lot of duplication code.
> > 
> > And add support for crashkernel CMA reservation for arm64 and riscv.
> 
> fyi, AI review might have found a bunch of issues in arch-specific
> code, all of them pre-existing.

v15 grew to 23 patches because of them and Baoquan suggested to split the
fixes into a separate series.
 
> 	https://sashiko.dev/#/patchset/20260608073459.3119290-1-ruanjinjie@huawei.com

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH v2 0/5] watchdog: improve comments & Documentation
From: Guenter Roeck @ 2026-06-08 18:53 UTC (permalink / raw)
  To: Randy Dunlap, linux-kernel
  Cc: Wim Van Sebroeck, linux-watchdog, Jonathan Corbet, Shuah Khan,
	linux-doc
In-Reply-To: <20260529212024.2119204-1-rdunlap@infradead.org>

On 5/29/26 14:20, Randy Dunlap wrote:
> Add the missing devm_watchdog_register_device() to watchdog-kernel-api.rst.
> Convert some struct and function comments to kernel-doc format.
> Add some UAPI comments for quick reference.
> Correct some grammar and bulleted list format.
> 
> v2: modify comments in patch 3/5 per sashiko review
> 
> [PATCH v2 1/5] watchdog: add devm_watchdog_register_device() to watchdog-kernel-api
> [PATCH v2 2/5] watchdog: linux/watchdog.h: repair kernel-doc comments
> [PATCH v2 3/5] watchdog: uapi: add comments for what bit masks apply to
> [PATCH v2 4/5] watchdog: core: clean up some comments
> [PATCH v2 5/5] watchdog: dev: convert to kernel-doc comments
> 
>   Documentation/watchdog/watchdog-kernel-api.rst |    8 ++++
>   drivers/watchdog/watchdog_core.c               |   12 +++---
>   drivers/watchdog/watchdog_dev.c                |   30 +++++++--------
>   include/linux/watchdog.h                       |    8 +++-
>   include/uapi/linux/watchdog.h                  |    2 +
>   5 files changed, 37 insertions(+), 23 deletions(-)
> 
> Cc: Wim Van Sebroeck <wim@linux-watchdog.org>
> Cc: Guenter Roeck <linux@roeck-us.net>
> Cc: linux-watchdog@vger.kernel.org
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Shuah Khan <skhan@linuxfoundation.org>
> Cc: linux-doc@vger.kernel.org

Series applied.

Thanks,
Guenter


^ permalink raw reply

* Re: [PATCH v3 2/4] mm/zswap: Implement proactive writeback
From: Shakeel Butt @ 2026-06-08 18:30 UTC (permalink / raw)
  To: Yosry Ahmed
  Cc: Hao Jia, Johannes Weiner, mhocko, tj, mkoutny, roman.gushchin,
	Nhat Pham, akpm, chengming.zhou, muchun.song, cgroups, linux-mm,
	linux-kernel, linux-doc, Hao Jia
In-Reply-To: <CAO9r8zM4SDdTgz9L2s1VfXL8K2VBjMD9ej2BTDxaGge1t2+quA@mail.gmail.com>

On Wed, Jun 03, 2026 at 10:36:07PM -0700, Yosry Ahmed wrote:
> > >> But doesn't it make more sense to specify the compressed size, which is
> > >> ultimately the amount of memory you actually want to reclaim.
> > >>
> > >
> > > I personally prefer compressed size to pre-compressed size. That's
> > > kinda what user cares about, no?
> > >
> > > One thing we can do is let users prescribe a compressed size, but
> > > internally, we can multiply that by the average compression ratio.
> > > That gives us a guesstimate of how many pages we need to reclaim, and
> > > you can follow the rest of your implementation as is (perhaps with
> > > short-circuit when we reach the goal with fewer pages reclaimed).
> >
> > Got it. I will change it to use the compressed size in the next version.
> >
> > Yosry, Nhat, should we continue using the zswap_writeback_only key to
> > trigger proactive writeback?
> 
> I *really* want the memcg maintainers to chime in here, it's
> ultimately their call.
> 
> Michal? Johannes? Shakeel? Roman? Anyone? :D

Between the options of having an explicit interface (i.e.
memory.zswap.writeback*) or a key (i.e. zswap_writeback_only) to memory.reclaim
interface, I prefer the key option. I have not looked into how much proactively
reclaiming zswap memory or proactively triggering zswap writeback makes sense
but from the perspective of memcg interface, I think the key option would give a
more clean solution if we decide in the future that this whole thing was a bad
idea.

Next regarding future proofing zswap writeback trigger, do we expect any
potential additions/changes/new-features for this interface? For example do we
expect in future we may want to trigger the zswap writeback only from a specific
node or lowest memory tier?

^ 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