Linux Documentation
 help / color / mirror / Atom feed
* Re: [RFC PATCH 0/7] tracing/probes: Add more typecast features
From: Masami Hiramatsu @ 2026-06-09  1:42 UTC (permalink / raw)
  To: Masami Hiramatsu (Google)
  Cc: Steven Rostedt, Mathieu Desnoyers, Jonathan Corbet, Shuah Khan,
	linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest
In-Reply-To: <178092865666.163648.10457567771536160909.stgit@devnote2>

Hi,

On Mon,  8 Jun 2026 23:24:16 +0900
"Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:

> Hi,
> 
> Here is a series of patches to introduce more typecast features
> to probe events, which includes 1. expanding BTF typecast to
> fprobe and kprobe events, 2. introducing container_of like typecst
> option, 3. supporting nested typecast, 4. adding $current special
> variable support, 5. adding per-cpu dereference support, 6. adding
> a testcase to check typecasts.

Sashiko found many issues on this series. I'll fix those.

BTW, for $current, I think it should typecasted to task_struct without
typecast. (except if it is the container_of() type typecasting)
In this case, ctx->strcut_btf will be updated automatically if $current
is specified.

Also, I'm thinking redesign +CPU/+PCPU/this_cpu_ptr().
Instead of those, what about introducing followings?

 - this_cpu_read(VAR)
 - this_cpu_ptr(VAR)

Comments are welcome!

Thanks,

> 
> Steve introduced BTF typecast feature for eprobe[1].
> This series extends it and add more options:
> 
> 1. Expanding BTF typecast to kprobe and fprobe.
>    (currently only function entry/exit)
> 
> 2. Introduce container_of like typecast. This adds a "assigned
>    member" option to the typecast.
> 
>    (STRUCT,MEMBER)VAR->ANOTHER_MEMBER
> 
>    This casts VAR to STRUCT type but the VAR is as the address
>    of STRUCT.MEMBER. In C, it is:
> 
>    container_of(VAR, STRUCT, MEMBER)->ANOTHER_MEMBER
> 
> 3. Support nested typecast, e.g.
> 
>    (STRUCT)((STRUCT2)VAR->MEMBER2)->MEMBER
> 
>    the nest level must be smaller than 3.
> 
> 4. Add $current variable to point "current" task_struct.
>    This is useful with typecast, e.g.
> 
>    (task_struct)$current->pid
> 
> 5. per-cpu dereference support.
> 
>    +CPU(VAR) is the same as this_cpu_read(VAR), and
>    +PCPU(VAR) is the same as this_cpu_ptr(VAR).
>    Also, "this_cpu_ptr(VAR)" is available. This is good
>    with nesting expression.
> 
>    (STRUCT)(this_cpu_ptr(VAR))->MEMBER
> 
>    (However, it might be better to allow a special way to omit
>     parentheses for thi_cpu_ptr())
> 
> And added a test script to test part of them.
> 
> [1] https://lore.kernel.org/all/20260601130746.2139d926@gandalf.local.home/
> 
> 
> ---
> 
> Masami Hiramatsu (Google) (7):
>       tracing/probes: Support typecast for various probe events
>       tracing/probes: Support nested typecast
>       tracing/probes: Support field specifier option for typecast
>       tracing/probes: Add $current variable support
>       tracing/probes: Add +CPU() and +PCPU() dereference method to fetcharg
>       tracing/probes: Support reserved this_cpu_ptr() method
>       tracing/probes: Add a new testcase for BTF typecasts
> 
> 
>  Documentation/trace/eprobetrace.rst                |   11 +
>  Documentation/trace/fprobetrace.rst                |   11 +
>  Documentation/trace/kprobetrace.rst                |   12 +
>  kernel/trace/trace.c                               |    6 
>  kernel/trace/trace_probe.c                         |  312 +++++++++++++++-----
>  kernel/trace/trace_probe.h                         |   12 +
>  kernel/trace/trace_probe_tmpl.h                    |   33 ++
>  samples/trace_events/trace-events-sample.c         |   38 ++
>  samples/trace_events/trace-events-sample.h         |   34 ++
>  .../ftrace/test.d/dynevent/btf_probe_event.tc      |   52 +++
>  10 files changed, 422 insertions(+), 99 deletions(-)
>  create mode 100644 tools/testing/selftests/ftrace/test.d/dynevent/btf_probe_event.tc
> 
> --
> Signature


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply

* Re: [PATCH v3 4/6] alloc_tag: add accuracy based filtering to ioctl
From: Hao Ge @ 2026-06-09  1:26 UTC (permalink / raw)
  To: Suren Baghdasaryan
  Cc: Abhishek Bapat, Shuah Khan, Jonathan Corbet, linux-doc,
	linux-kernel, linux-mm, Sourav Panda, Andrew Morton,
	Kent Overstreet
In-Reply-To: <CAJuCfpHtdd=9D68cfRp4HDHHHCZdzTNP_RH9i2D-f9tJXht56A@mail.gmail.com>

Hi Suren


On 2026/6/9 04:55, Suren Baghdasaryan wrote:
> 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?


Sorry, I overlooked this case.

Since allocinfo_tag_data exposes both inaccurate (from allocinfo_tag) and

accurate (from allocinfo_counter), userspace developers might mistakenly 
read

inaccurate instead of accurate when checking accuracy.

How about we add a comment to clarify?

struct allocinfo_tag {

     /* ... */

     __u64 lineno;

     /* filter criteria only; see allocinfo_counter.accurate for actual 
accuracy */

     __u64 inaccurate;

};


LGTM for the rest.


Thanks

Best Regards

Hao

> 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: [RFC v1 0/9] kho: granular compatibility and header decoupling
From: Pasha Tatashin @ 2026-06-09  1:14 UTC (permalink / raw)
  To: Mike Rapoport
  Cc: Pasha Tatashin, linux-kselftest, shuah, akpm, linux-mm, skhan,
	linux-doc, jasonmiu, linux-kernel, corbet, ran.xiaokai, kexec,
	pratyush, graf
In-Reply-To: <aicF5Sa11B4ujfSa@kernel.org>

On 06-08 21:11, Mike Rapoport wrote:
> On Mon, Jun 08, 2026 at 04:12:56PM +0000, Pasha Tatashin wrote:
> > On 06-08 13:26, Mike Rapoport wrote:
> > > On 2026-06-07 13:43:09+00:00, Pasha Tatashin wrote:
> >
> > Keeping all of that in a single KHO file is the wrong approach and goes 
> > against how other logically separated subsystems in Linux are organized 
> > (e.g., mm/vmap.c, mm/vmalloc.c, etc.). Yes, there are some messier 
> > places in the kernel as well, but keeping this in its own dedicated 
> > kho_vmalloc.c file makes complete sense to me.
> 
> Either I hallucinated or b4 ate a paragraph from my reply ;)
> 
> Regarding the code movement
> - splitting radix tree makes perfect sense to me, just the documentation
>   part needs more care than mechanical move

Agreed. I'll also pay closer attention to the documentation.

> - I'm fine with abi/vmalloc.h, presuming KHOSER_PTR() is not part of it

Yes, I will move KHOSER_PTR() to the shared compat.h in v2 so it's not 
tied to vmalloc.

> - I can live with kho_vmalloc.c although I still consider it unnecessary
>   churn

Appreciate it.

> - I'm against moving vmalloc APIs from kexec_handover.h because they are
>   very close in nature to folio and pages. I don't see core KHO as
>   responsible for preserving physically contiguous ranges but rather as
>   preserving allocations. Not sure we'll ever support kmalloc(), but still.

That is a very reasonable compromise. I am fine with keeping the 
consumer-facing function declarations in kexec_handover.h so they remain 
grouped  with folios and pages.

> > However, overall enforcing the use of KHOSER is unrelated to this work. 
> > I have my own thoughts on this, and perhaps with proper versioning, 
> > using KHOSER_PTR everywhere would be appropriate, but let's keep that as 
> > a separate work.
> 
> This is a separate work, indeed. But regardless of the versioning it's
> already better than plain u64 because it provides type safety.

Agreed.

Thanks!
Pasha

^ permalink raw reply

* Re: [PATCH v3 4/6] alloc_tag: add accuracy based filtering to ioctl
From: Abhishek Bapat @ 2026-06-09  0:51 UTC (permalink / raw)
  To: Suren Baghdasaryan
  Cc: Hao Ge, Shuah Khan, Jonathan Corbet, linux-doc, linux-kernel,
	linux-mm, Sourav Panda, Andrew Morton, Kent Overstreet
In-Reply-To: <CAJuCfpHtdd=9D68cfRp4HDHHHCZdzTNP_RH9i2D-f9tJXht56A@mail.gmail.com>

Btw, Sashiko left a comment in this patch stating that the value of
"inaccurate" is echoed back to the user. But since it's an input-only
parameter, that is expected. Changing it in the kernel would be
unexpected. Hence, I will ignore that comment.

On Mon, Jun 8, 2026 at 1:55 PM Suren Baghdasaryan <surenb@google.com> wrote:
>
> 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 v3 0/6] alloc_tag: introduce IOCTL-based filtering for MAP
From: Suren Baghdasaryan @ 2026-06-09  0:29 UTC (permalink / raw)
  To: Abhishek Bapat
  Cc: Andrew Morton, Kent Overstreet, Hao Ge, Shuah Khan,
	Jonathan Corbet, linux-doc, linux-kernel, linux-mm, Sourav Panda
In-Reply-To: <CAL41Mv6pZOVacLdUGta7UnxmFryumBbN6=Po50KfzgLzMs2PQg@mail.gmail.com>

On Mon, Jun 8, 2026 at 5:02 PM Abhishek Bapat <abhishekbapat@google.com> wrote:
>
> On Fri, Jun 5, 2026 at 5:09 PM Andrew Morton <akpm@linux-foundation.org> wrote:
> >
> > On Fri,  5 Jun 2026 23:36:45 +0000 Abhishek Bapat <abhishekbapat@google.com> wrote:
> >
> > > Currently, memory allocation profiling data is primarily exposed through
> > > /proc/allocinfo. While useful for manual inspection, this text-based
> > > interface poses challenges for production monitoring and large-scale
> > > analysis:
> > >
> > > 1. Userspace must parse large amounts of text to extract specific
> > > fields.
> > > 2. To find specific tags, userspace must read the entire dataset,
> > > requiring many context switches and high data copying.
> > > 3. The kernel currently aggregates per-CPU counters for every allocation
> > > size, even those the user intends to filter out immediately.
> > >
> > > This series introduces a new IOCTL-based binary interface for allocinfo
> > > that supports kernel-side filtering. By allowing the user to specify a
> > > filter mask, we significantly reduce the work performed in-kernel and
> > > the amount of data transferred to userspace.
> >
> > Thanks.  AI review found several things - you'll want to address at
> > least the first few.
> >
> >         https://sashiko.dev/#/patchset/cover.1780701922.git.abhishekbapat@google.com
>
> All, please note I missed attaching the reason for choosing the IOCTL
> mechanism to this cover letter, but I will attach it to the v4
> patchset cover letter along with other changes. Thanks!

Can you please add it here now so that we can review that?

^ permalink raw reply

* Re: [PATCH v3 1/6] alloc_tag: add ioctl to /proc/allocinfo
From: Abhishek Bapat @ 2026-06-09  0:19 UTC (permalink / raw)
  To: Hao Ge
  Cc: Suren Baghdasaryan, Andrew Morton, Kent Overstreet, Shuah Khan,
	Jonathan Corbet, linux-doc, linux-kernel, linux-mm, Sourav Panda
In-Reply-To: <41a7ebb9-1113-4f13-abbf-6f55d99d62f3@linux.dev>

On Sun, Jun 7, 2026 at 6:53 PM Hao Ge <hao.ge@linux.dev> wrote:
>
> Hi Suren and Abhishek
>
>
> Thanks for the new version.
>
>
> On 2026/6/6 07:36, Abhishek Bapat wrote:
> > From: Suren Baghdasaryan <surenb@google.com>
> >
> > Add the following ioctl commands for /proc/allocinfo file:
> >
> > ALLOCINFO_IOC_CONTENT_ID - gets content identifier which can be used
> > to check whether the file content has changed specifically due to module
> > load/unload. Every time a module is loaded / unloaded, the returned
> > value will be different. By comparing the identifier value at the
> > beginning and at the end of the content retrieval operation, users can
> > validate retrieved information for consistency.
> >
> > ALLOCINFO_IOC_GET_AT - gets the record at the specified position. This
> > is the position of a record in /proc/allocinfo.
> >
> > ALLOCINFO_IOC_GET_NEXT - gets the record next to the last retrieved
> > one. If no records were previously retrieved, returns the first
> > record.
> >
> > Signed-off-by: Suren Baghdasaryan <surenb@google.com>
> > Signed-off-by: Abhishek Bapat <abhishekbapat@google.com>
> > ---
> >   Documentation/mm/allocation-profiling.rst     |   5 +
> >   .../userspace-api/ioctl/ioctl-number.rst      |   2 +
> >   MAINTAINERS                                   |   1 +
> >   include/linux/codetag.h                       |   2 +
> >   include/uapi/linux/alloc_tag.h                |  54 ++++
> >   lib/alloc_tag.c                               | 232 +++++++++++++++++-
> >   lib/codetag.c                                 |  18 ++
> >   7 files changed, 312 insertions(+), 2 deletions(-)
> >   create mode 100644 include/uapi/linux/alloc_tag.h
> >
> > diff --git a/Documentation/mm/allocation-profiling.rst b/Documentation/mm/allocation-profiling.rst
> > index 5389d241176a..c3a28467955f 100644
> > --- a/Documentation/mm/allocation-profiling.rst
> > +++ b/Documentation/mm/allocation-profiling.rst
> > @@ -46,6 +46,11 @@ sysctl:
> >   Runtime info:
> >     /proc/allocinfo
> >
> > +  Profiling data can be retrieved either by reading `/proc/allocinfo` directly as
> > +  text or programmatically via `ioctl()` calls defined in `<uapi/linux/alloc_tag.h>`.
> > +  The ioctl interface supports structured binary data extraction as well as filtering
> > +  by module name, function, file, line number, accuracy, or allocation size limits.
> > +
> >   Example output::
> >
> >     root@moria-kvm:~# sort -g /proc/allocinfo|tail|numfmt --to=iec
> > diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > index 331223761fff..84f6808a8578 100644
> > --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
> > +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
> > @@ -349,6 +349,8 @@ Code  Seq#    Include File                                             Comments
> >                                                                          <mailto:luzmaximilian@gmail.com>
> >   0xA5  20-2F  linux/surface_aggregator/dtx.h                            Microsoft Surface DTX driver
> >                                                                          <mailto:luzmaximilian@gmail.com>
> > +0xA6  00-0F  uapi/linux/alloc_tag.h                                    Memory allocation profiling
> > +                                                                       <mailto:surenb@google.com>
> >   0xAA  00-3F  linux/uapi/linux/userfaultfd.h
> >   0xAB  00-1F  linux/nbd.h
> >   0xAC  00-1F  linux/raw.h
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index a31f6f207afd..77f3fc487691 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -16711,6 +16711,7 @@ S:    Maintained
> >   F:  Documentation/mm/allocation-profiling.rst
> >   F:  include/linux/alloc_tag.h
> >   F:  include/linux/pgalloc_tag.h
> > +F:   include/uapi/linux/alloc_tag.h
> >   F:  lib/alloc_tag.c
> >
> >   MEMORY CONTROLLER DRIVERS
> > diff --git a/include/linux/codetag.h b/include/linux/codetag.h
> > index ddae7484ca45..a25a085c2df1 100644
> > --- a/include/linux/codetag.h
> > +++ b/include/linux/codetag.h
> > @@ -77,6 +77,8 @@ struct codetag_iterator {
> >   void codetag_lock_module_list(struct codetag_type *cttype);
> >   bool codetag_trylock_module_list(struct codetag_type *cttype);
> >   void codetag_unlock_module_list(struct codetag_type *cttype);
> > +unsigned long codetag_get_content_id(struct codetag_type *cttype);
> > +unsigned int codetag_get_count(struct codetag_type *cttype);
> >   struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype);
> >   struct codetag *codetag_next_ct(struct codetag_iterator *iter);
> >
> > diff --git a/include/uapi/linux/alloc_tag.h b/include/uapi/linux/alloc_tag.h
> > new file mode 100644
> > index 000000000000..901199bad514
> > --- /dev/null
> > +++ b/include/uapi/linux/alloc_tag.h
> > @@ -0,0 +1,54 @@
> > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> > +/*
> > + *  include/linux/alloc_tag.h
>
> nit: it should be include/uapi/linux/alloc_tag.h
>
> (I guess you may have missed the comment I brought up before. It is not
> a critical problem though.)
>
Apologies, I missed that comment earlier. Included in the v4 patchset.
Thanks for bringing this up.

> > + */
> > +
> > +#ifndef _UAPI_ALLOC_TAG_H
> > +#define _UAPI_ALLOC_TAG_H
> > +
> > +#include <linux/types.h>
> > +
> > +#define ALLOCINFO_STR_SIZE   64
> > +
> > +struct allocinfo_content_id {
> > +     __u64 id;
> > +};
> > +
> > +struct allocinfo_tag {
> > +     /* Longer names are trimmed */
> > +     char modname[ALLOCINFO_STR_SIZE];
> > +     char function[ALLOCINFO_STR_SIZE];
> > +     char filename[ALLOCINFO_STR_SIZE];
> > +     __u64 lineno;
> > +};
> > +
> > +/* The alignment ensures 32-bit compatible interfaces are not broken */
> > +struct allocinfo_counter {
> > +     __u64 bytes;
> > +     __u64 calls;
> > +     __u8 accurate;
> > +} __attribute__((aligned(8)));
> > +
> > +struct allocinfo_tag_data {
> > +     struct allocinfo_tag tag;
> > +     struct allocinfo_counter counter;
> > +};
> > +
> > +struct allocinfo_get_at {
> > +     __u64 pos;      /* input */
> > +     struct allocinfo_tag_data data;
> > +};
> > +
> > +#define _ALLOCINFO_IOC_CONTENT_ID    0
> > +#define _ALLOCINFO_IOC_GET_AT                1
> > +#define _ALLOCINFO_IOC_GET_NEXT              2
> > +
> > +#define ALLOCINFO_IOC_BASE           0xA6
> > +#define ALLOCINFO_IOC_CONTENT_ID     _IOR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_CONTENT_ID,     \
> > +                                          struct allocinfo_content_id)
> > +#define ALLOCINFO_IOC_GET_AT         _IOWR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_GET_AT,        \
> > +                                           struct allocinfo_get_at)
> > +#define ALLOCINFO_IOC_GET_NEXT               _IOR(ALLOCINFO_IOC_BASE, _ALLOCINFO_IOC_GET_NEXT,       \
> > +                                          struct allocinfo_tag_data)
> > +
> > +#endif /* _UAPI_ALLOC_TAG_H */
> > diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
> > index d9be1cf5187d..a0577215eb3d 100644
> > --- a/lib/alloc_tag.c
> > +++ b/lib/alloc_tag.c
> > @@ -5,6 +5,7 @@
> >   #include <linux/gfp.h>
> >   #include <linux/kallsyms.h>
> >   #include <linux/module.h>
> > +#include <linux/mutex.h>
> >   #include <linux/page_ext.h>
> >   #include <linux/pgalloc_tag.h>
> >   #include <linux/proc_fs.h>
> > @@ -14,6 +15,7 @@
> >   #include <linux/string_choices.h>
> >   #include <linux/vmalloc.h>
> >   #include <linux/kmemleak.h>
> > +#include <uapi/linux/alloc_tag.h>
> >
> >   #define ALLOCINFO_FILE_NAME         "allocinfo"
> >   #define MODULE_ALLOC_TAG_VMAP_SIZE  (100000UL * sizeof(struct alloc_tag))
> > @@ -47,6 +49,10 @@ struct allocinfo_private {
> >       struct codetag_iterator iter;
> >       struct codetag_iterator reported_iter;
> >       bool print_header;
> > +     /* ioctl uses a separate iterator not to interfere with reads */
> > +     struct codetag_iterator ioctl_iter;
> > +     bool positioned; /* seq_open_private() sets to 0 */
> > +     struct mutex ioctl_lock;
> >   };
> >
> >   static void *allocinfo_start(struct seq_file *m, loff_t *pos)
> > @@ -130,6 +136,229 @@ static const struct seq_operations allocinfo_seq_op = {
> >       .show   = allocinfo_show,
> >   };
> >
> > +/*
> > + * Initializes seq_file operations and allocates private state when opening
> > + * the /proc/allocinfo procfs entry.
> > + */
> > +static int allocinfo_open(struct inode *inode, struct file *file)
> > +{
> > +     int ret;
> > +
> > +     ret = seq_open_private(file, &allocinfo_seq_op,
> > +                            sizeof(struct allocinfo_private));
> > +     if (!ret) {
> > +             struct seq_file *m = file->private_data;
> > +             struct allocinfo_private *priv = m->private;
> > +
> > +             mutex_init(&priv->ioctl_lock);
> > +     }
> > +     return ret;
> > +}
> > +
> > +/*
> > + * Cleans up the seq_file state and frees up the private state allocated in
> > + * allocinfo_open() when closing the /proc/allocinfo file descriptor.
> > + */
> > +static int allocinfo_release(struct inode *inode, struct file *file)
> > +{
> > +     return seq_release_private(inode, file);
> > +}
> > +
> > +/*
> > + * Returns a pointer to the suffix of a string so that its length fits within
> > + * ALLOCINFO_STR_SIZE, preserving the trailing characters.
> > + */
> > +static const char *allocinfo_str(const char *str)
> > +{
> > +     size_t len = strlen(str);
> > +
> > +     /* Keep an extra space for the trailing NULL. */
> > +     if (len >= ALLOCINFO_STR_SIZE)
> > +             str += (len - ALLOCINFO_STR_SIZE) + 1;
> > +     return str;
> > +}
> > +
> > +/* Copy a string and trim from the beginning if it's too long */
> > +static void allocinfo_copy_str(char *dest, const char *src)
> > +{
> > +     strscpy_pad(dest, allocinfo_str(src), ALLOCINFO_STR_SIZE);
> > +}
> > +
> > +/*
> > + * Populates the UAPI allocinfo_tag_data structure with active runtime
> > + * profiling counters extracted from the given kernel codetag.
> > + */
> > +static void allocinfo_to_params(struct codetag *ct,
> > +                             struct allocinfo_tag_data *data)
> > +{
> > +     struct alloc_tag *tag = ct_to_alloc_tag(ct);
> > +     struct alloc_tag_counters counter = alloc_tag_read(tag);
> > +
> > +     if (ct->modname)
> > +             allocinfo_copy_str(data->tag.modname, ct->modname);
> > +     else
> > +             data->tag.modname[0] = '\0';
> > +     allocinfo_copy_str(data->tag.function, ct->function);
> > +     allocinfo_copy_str(data->tag.filename, ct->filename);
> > +     data->tag.lineno = ct->lineno;
> > +     data->counter.bytes = counter.bytes;
> > +     data->counter.calls = counter.calls;
> > +     data->counter.accurate = !alloc_tag_is_inaccurate(tag);
> > +}
> > +
> > +/*
> > + * Retrieves the unique content ID representing the current allocation tag module
> > + * layout, allowing userspace to detect if modules were loaded / unloaded.
> > + */
> > +static int allocinfo_ioctl_get_content_id(struct seq_file *m, void __user *arg)
> > +{
> > +     struct allocinfo_content_id params;
> > +
> > +     codetag_lock_module_list(alloc_tag_cttype);
> > +     params.id = codetag_get_content_id(alloc_tag_cttype);
> > +     codetag_unlock_module_list(alloc_tag_cttype);
> > +     if (copy_to_user(arg, &params, sizeof(params)))
> > +             return -EFAULT;
> > +
> > +     return 0;
> > +}
> > +
> > +/*
> > + * Seeks the ioctl iterator to the specified 0-indexed tag position, reads its
> > + * profiling data and returns it to userspace.
> > + */
> > +static int allocinfo_ioctl_get_at(struct seq_file *m, void __user *arg)
> > +{
> > +     struct allocinfo_private *priv;
> > +     struct codetag *ct;
> > +     __u64 pos;
> > +     struct allocinfo_get_at params = {0};
> > +
> > +     if (copy_from_user(&params, arg, sizeof(params)))
> > +             return -EFAULT;
> > +
> > +     priv = m->private;
> > +     pos = params.pos;
> > +
> > +     mutex_lock(&priv->ioctl_lock);
> > +     codetag_lock_module_list(alloc_tag_cttype);
> > +
> > +     if (pos >= codetag_get_count(alloc_tag_cttype)) {
> > +             codetag_unlock_module_list(alloc_tag_cttype);
> > +             mutex_unlock(&priv->ioctl_lock);
> > +             return -ENOENT;
> > +     }
> > +
> > +     /* Find the codetag */
> > +     priv->ioctl_iter = codetag_get_ct_iter(alloc_tag_cttype);
> > +     ct = codetag_next_ct(&priv->ioctl_iter);
> > +     while (ct && pos--)
> > +             ct = codetag_next_ct(&priv->ioctl_iter);
> > +     if (ct) {
> > +             allocinfo_to_params(ct, &params.data);
> > +             priv->positioned = true;
> > +     }
> > +
> > +     codetag_unlock_module_list(alloc_tag_cttype);
> > +     mutex_unlock(&priv->ioctl_lock);
> > +
> > +     if (!ct)
> > +             return -ENOENT;
> > +
> > +     if (copy_to_user(arg, &params, sizeof(params)))
> > +             return -EFAULT;
> > +
> > +     return 0;
> > +}
> > +
> > +/*
> > + * Advances the ioctl iterator to the next allocation tag in the sequence and
> > + * returns its profiling data to userspace.
> > + */
> > +static int allocinfo_ioctl_get_next(struct seq_file *m, void __user *arg)
> > +{
> > +     struct allocinfo_private *priv;
> > +     struct codetag *ct;
> > +     struct allocinfo_tag_data params;
> > +     int ret = 0;
> > +
> > +     memset(&params, 0, sizeof(params));
> > +     priv = m->private;
> > +
> > +     mutex_lock(&priv->ioctl_lock);
> > +     codetag_lock_module_list(alloc_tag_cttype);
> > +
> > +     if (!priv->positioned) {
> > +             priv->ioctl_iter = codetag_get_ct_iter(alloc_tag_cttype);
> > +             priv->positioned = true;
> > +     }
> > +
> > +     ct = codetag_next_ct(&priv->ioctl_iter);
> > +     if (ct)
> > +             allocinfo_to_params(ct, &params);
> > +
> > +     if (!ct) {
> > +             priv->positioned = false;
> > +             ret = -ENOENT;
> > +     }
> > +     codetag_unlock_module_list(alloc_tag_cttype);
> > +     mutex_unlock(&priv->ioctl_lock);
> > +
> > +     if (ret == 0) {
> > +             if (copy_to_user(arg, &params, sizeof(params)))
> > +                     return -EFAULT;
> > +     }
> > +     return ret;
> > +}
> > +
> > +/*
> > + * Entry point ioctl function for /proc/allocinfo routing requests to fetch the
> > + * layout content ID, seek to a specific tag, or read sequential tags.
> > + */
> > +static long allocinfo_ioctl(struct file *file, unsigned int cmd,
> > +                         unsigned long __arg)
> > +{
> > +     void __user *arg = (void __user *)__arg;
> > +     int ret;
> > +
> > +     switch (cmd) {
> > +     case ALLOCINFO_IOC_CONTENT_ID:
> > +             ret = allocinfo_ioctl_get_content_id(file->private_data, arg);
> > +             break;
> > +     case ALLOCINFO_IOC_GET_AT:
> > +             ret = allocinfo_ioctl_get_at(file->private_data, arg);
> > +             break;
> > +     case ALLOCINFO_IOC_GET_NEXT:
> > +             ret = allocinfo_ioctl_get_next(file->private_data, arg);
> > +             break;
> > +     default:
> > +             ret = -ENOIOCTLCMD;
> > +             break;
> > +     }
> > +
> > +     return ret;
> > +}
> > +
> > +#ifdef CONFIG_COMPAT
> > +static long allocinfo_compat_ioctl(struct file *file, unsigned int cmd,
> > +                                unsigned long arg)
> > +{
> > +     return allocinfo_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
> > +}
> > +#endif
> > +
> > +static const struct proc_ops allocinfo_proc_ops = {
> > +     .proc_open              = allocinfo_open,
> > +     .proc_read_iter         = seq_read_iter,
> > +     .proc_lseek             = seq_lseek,
> > +     .proc_release           = allocinfo_release,
> > +     .proc_ioctl             = allocinfo_ioctl,
> > +#ifdef CONFIG_COMPAT
> > +     .proc_compat_ioctl      = allocinfo_compat_ioctl,
> > +#endif
> > +
> > +};
> > +
> >   size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sleep)
> >   {
> >       struct codetag_iterator iter;
> > @@ -993,8 +1222,7 @@ static int __init alloc_tag_init(void)
> >               return 0;
> >       }
> >
> > -     if (!proc_create_seq_private(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_seq_op,
> > -                                  sizeof(struct allocinfo_private), NULL)) {
> > +     if (!proc_create(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_proc_ops)) {
> >               pr_err("Failed to create %s file\n", ALLOCINFO_FILE_NAME);
> >               shutdown_mem_profiling(false);
> >               return -ENOMEM;
> > diff --git a/lib/codetag.c b/lib/codetag.c
> > index 4001a7ea6675..a9cda4c962a3 100644
> > --- a/lib/codetag.c
> > +++ b/lib/codetag.c
> > @@ -19,6 +19,8 @@ struct codetag_type {
> >       struct codetag_type_desc desc;
> >       /* generates unique sequence number for module load */
> >       unsigned long next_mod_seq;
> > +     /* bumped on every module load and unload */
> > +     unsigned long content_id;
> >   };
> >
> >   struct codetag_range {
> > @@ -50,6 +52,20 @@ void codetag_unlock_module_list(struct codetag_type *cttype)
> >       up_read(&cttype->mod_lock);
> >   }
> >
> > +unsigned long codetag_get_content_id(struct codetag_type *cttype)
> > +{
> > +     lockdep_assert_held(&cttype->mod_lock);
> > +
> > +     return cttype->content_id;
> > +}
> > +
> > +unsigned int codetag_get_count(struct codetag_type *cttype)
> > +{
> > +     lockdep_assert_held(&cttype->mod_lock);
> > +
> > +     return cttype->count;
> > +}
> > +
> >   struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype)
> >   {
> >       struct codetag_iterator iter = {
> > @@ -204,6 +220,7 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
> >
> >       down_write(&cttype->mod_lock);
> >       cmod->mod_seq = ++cttype->next_mod_seq;
> > +     ++cttype->content_id;
>
> I have a comment on the content_id bump placement.
>
> ++cttype->content_id is placed before idr_alloc and the module_load
>
> callback. If idr_alloc fails or module_load returns an error
>
> (While the chance of this occurring is very low.), the idr entry gets
>
> rolled back but content_id has already been bumped. The actual
>
> content didn't change in this case, so userspace would see a
>
> different content_id and assume the data is inconsistent when it
>
> isn't.
>
>
> Thanks
>
> Best Regards
>
> Hao

While I agree with your comment, I decided to place the counter
increment there because the chance of failure is low. Furthermore,
even if it falsely invalidates user data, the user will simply query
the content again. This placement also aligns with where the
previously used field (cttype->next_mod_seq) was incremented. Let me
know if you still think I should move it. Thanks!

>
> >       mod_id = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
> >       if (mod_id >= 0) {
> >               if (cttype->desc.module_load) {
> > @@ -368,6 +385,7 @@ void codetag_unload_module(struct module *mod)
> >                       cttype->count -= range_size(cttype, &cmod->range);
> >                       idr_remove(&cttype->mod_idr, mod_id);
> >                       kfree(cmod);
> > +                     ++cttype->content_id;
> >               }
> >               up_write(&cttype->mod_lock);
> >               if (found && cttype->desc.free_section_mem)

^ permalink raw reply

* Re: [PATCH v3 0/6] alloc_tag: introduce IOCTL-based filtering for MAP
From: Abhishek Bapat @ 2026-06-09  0:02 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Suren Baghdasaryan, Kent Overstreet, Hao Ge, Shuah Khan,
	Jonathan Corbet, linux-doc, linux-kernel, linux-mm, Sourav Panda
In-Reply-To: <20260605170858.9ee9ca2181a041bb9a4c3098@linux-foundation.org>

On Fri, Jun 5, 2026 at 5:09 PM Andrew Morton <akpm@linux-foundation.org> wrote:
>
> On Fri,  5 Jun 2026 23:36:45 +0000 Abhishek Bapat <abhishekbapat@google.com> wrote:
>
> > Currently, memory allocation profiling data is primarily exposed through
> > /proc/allocinfo. While useful for manual inspection, this text-based
> > interface poses challenges for production monitoring and large-scale
> > analysis:
> >
> > 1. Userspace must parse large amounts of text to extract specific
> > fields.
> > 2. To find specific tags, userspace must read the entire dataset,
> > requiring many context switches and high data copying.
> > 3. The kernel currently aggregates per-CPU counters for every allocation
> > size, even those the user intends to filter out immediately.
> >
> > This series introduces a new IOCTL-based binary interface for allocinfo
> > that supports kernel-side filtering. By allowing the user to specify a
> > filter mask, we significantly reduce the work performed in-kernel and
> > the amount of data transferred to userspace.
>
> Thanks.  AI review found several things - you'll want to address at
> least the first few.
>
>         https://sashiko.dev/#/patchset/cover.1780701922.git.abhishekbapat@google.com

All, please note I missed attaching the reason for choosing the IOCTL
mechanism to this cover letter, but I will attach it to the v4
patchset cover letter along with other changes. Thanks!

^ permalink raw reply

* Re: [RFC PATCH v1 00/13] exec: add spawn templates for repeated executable startup
From: Andy Lutomirski @ 2026-06-09  0:01 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Li Chen, Kees Cook, Alexander Viro, linux-fsdevel, linux-api,
	linux-kernel, 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: <20260528-madig-fachrichtung-fehlinformation-61117ba640da@brauner>

On Thu, May 28, 2026 at 4:05 AM 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. Any implementation
> should also allow userspace to implement posix_spawn() on top of it.
>
> fd = pidfd_open(0, PIDFD_EMPTY /* or better name */)
>
> pidfd_config(fd, ...) // modeled similar to fsconfig()
>

After contemplating this for a bit... why pidfd?  Doesn't a pidfd
refer to an actual process that is, or at least was, running?  This
new thing is a process that we are contemplating spawning.  I can
imagine that basically all pidfd APIs would be a bit confused by the
nonexistence of the process in question.

^ permalink raw reply

* Re: [PATCH RFC v4 0/6] iio: add Open Sensor Fusion IIO driver
From: Kim Jinseob @ 2026-06-08 23:27 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Jonathan Cameron, linux-iio, David Lechner, Nuno Sá,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jonathan Corbet, Shuah Khan, devicetree, linux-kernel, linux-doc
In-Reply-To: <20260608-catnap-thinness-e25c9b8983c3@spud>

> Other than the fact that new revisions must not be sent as a diff on top
> of a prior revision, please stop sending new versions without actually
> replying to my v1 comments.

You are right, sorry for the noise.

I made a process mistake here. I prepared v4 on top of the previously sent
series instead of preparing it as a full standalone replacement series from
the proper base. I will not ask you to review v4 in that form, and I will
prepare the next revision as a full series from a clean base.

I also should have answered your protocol versioning questions directly before
sending another revision.

> What does "v0" mean here? Is the data format not complete yet?
> Are versions of the protocol likely to be backwards compatible?
> Will the device identify what version of the protocol it implements?

The current OSF wire header starts with a fixed 4-byte magic, "OSF0", at a
fixed offset. The same header also carries explicit protocol_major and
protocol_minor fields at fixed offsets.

For the currently supported firmware and driver, protocol_major is 0. The "0"
in "OSF0" is intended to denote the current major wire-format revision, not
the Linux driver identity.

The binding is intended for devices implementing this discoverable OSF header
layout. The driver currently supports protocol major version 0. Minor version
changes are intended to be backward compatible. Incompatible wire-format
changes require a new protocol_major value.

If a future major revision cannot be discovered using the same fixed header
layout, or is not compatible with this binding, it should use a new compatible
string.

I will spell this out in the binding commit message and documentation in the
next revision.

Jinseob

^ permalink raw reply

* 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


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