* Re: [PATCH v6 05/15] mm: add VM_UFFD_RWP VMA flag
From: Lorenzo Stoakes @ 2026-06-03 12:52 UTC (permalink / raw)
To: Kiryl Shutsemau (Meta)
Cc: akpm, rppt, peterx, david, surenb, vbabka, Liam.Howlett, ziy,
corbet, skhan, seanjc, pbonzini, jthoughton, aarcange, sj,
usama.arif, linux-mm, linux-kernel, linux-doc, linux-kselftest,
kvm, kernel-team
In-Reply-To: <20260529172716.357179-6-kas@kernel.org>
On Fri, May 29, 2026 at 06:26:34PM +0100, Kiryl Shutsemau (Meta) wrote:
> Preparatory patch for userfaultfd read-write protection (RWP). RWP
> extends userfaultfd protection from plain write-protection (WP) to
> full read-write protection: accesses to an RWP-protected range --
> reads as well as writes -- trap through userfaultfd.
>
> Reserve VM_UFFD_RWP, add the userfaultfd_rwp() and
> userfaultfd_protected() helpers, and wire up the smaps "ur" entry and
> the trace-flag table the rest of the series will use. The flag is
> gated on CONFIG_USERFAULTFD_RWP, which is introduced together with the
> UAPI in a later patch; until then VM_UFFD_RWP aliases VM_NONE and
> every downstream check folds to dead code.
>
> Nothing sets or queries the flag yet.
>
> Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
> Assisted-by: Claude:claude-opus-4-6
> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Reviewed-by: SeongJae Park <sj@kernel.org>
LGTM, so:
Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
> ---
> Documentation/filesystems/proc.rst | 1 +
> fs/proc/task_mmu.c | 3 +++
> include/linux/mm.h | 41 ++++++++++++++++++++----------
> include/linux/userfaultfd_k.h | 32 +++++++++++++++++++----
> include/trace/events/mmflags.h | 7 +++++
> 5 files changed, 65 insertions(+), 19 deletions(-)
>
> diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst
> index db6167befb7b..db28207c5290 100644
> --- a/Documentation/filesystems/proc.rst
> +++ b/Documentation/filesystems/proc.rst
> @@ -607,6 +607,7 @@ encoded manner. The codes are the following:
> um userfaultfd missing tracking
> uw userfaultfd wr-protect tracking
> ui userfaultfd minor fault
> + ur userfaultfd read-write-protect tracking
> ss shadow/guarded control stack page
> sl sealed
> lf lock on fault pages
> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> index 939657aa334a..ca0f69b347e8 100644
> --- a/fs/proc/task_mmu.c
> +++ b/fs/proc/task_mmu.c
> @@ -1237,6 +1237,9 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
> #ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> [ilog2(VM_UFFD_MINOR)] = "ui",
> #endif /* CONFIG_HAVE_ARCH_USERFAULTFD_MINOR */
> +#ifdef CONFIG_USERFAULTFD_RWP
> + [ilog2(VM_UFFD_RWP)] = "ur",
> +#endif
> #ifdef CONFIG_ARCH_HAS_USER_SHADOW_STACK
> [ilog2(VM_SHADOW_STACK)] = "ss",
> #endif
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 485df9c2dbdd..5ac31fbadeef 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -353,6 +353,7 @@ enum {
> #endif
> DECLARE_VMA_BIT(UFFD_MINOR, 41),
> DECLARE_VMA_BIT(SEALED, 42),
> + DECLARE_VMA_BIT(UFFD_RWP, 43),
> /* Flags that reuse flags above. */
> DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
> DECLARE_VMA_BIT_ALIAS(PKEY_BIT1, HIGH_ARCH_1),
> @@ -496,12 +497,17 @@ enum {
> #else
> #define VM_UFFD_MINOR VM_NONE
> #endif
> +#ifdef CONFIG_USERFAULTFD_RWP
> +#define VM_UFFD_RWP INIT_VM_FLAG(UFFD_RWP)
> +#else
> +#define VM_UFFD_RWP VM_NONE
> +#endif
>
> /*
> - * vma_flags_t masks for the userfaultfd VMA flags. VMA_UFFD_MINOR is gated on
> - * the same config as VM_UFFD_MINOR -- which implies 64BIT, where the bit fits
> - * -- so an out-of-range bit is never fed to mk_vma_flags() on a build whose
> - * bitmap cannot hold it.
> + * vma_flags_t masks for the userfaultfd VMA flags. The two high-bit modes are
> + * gated on the same configs as their VM_* flags above -- both of which imply
> + * 64BIT -- so an out-of-range bit is never fed to mk_vma_flags() on a build
> + * whose bitmap cannot hold it.
> */
> #define VMA_UFFD_MISSING mk_vma_flags(VMA_UFFD_MISSING_BIT)
> #define VMA_UFFD_WP mk_vma_flags(VMA_UFFD_WP_BIT)
> @@ -510,6 +516,11 @@ enum {
> #else
> #define VMA_UFFD_MINOR EMPTY_VMA_FLAGS
> #endif
> +#ifdef CONFIG_USERFAULTFD_RWP
> +#define VMA_UFFD_RWP mk_vma_flags(VMA_UFFD_RWP_BIT)
> +#else
> +#define VMA_UFFD_RWP EMPTY_VMA_FLAGS
> +#endif
>
> #ifdef CONFIG_64BIT
> #define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
> @@ -648,22 +659,24 @@ enum {
> * reconsistuted upon page fault, so necessitate page table copying upon fork.
> *
> * Note that these flags should be compared with the DESTINATION VMA not the
> - * source, as VM_UFFD_WP may not be propagated to destination, while all other
> - * flags will be.
> + * source: VM_UFFD_WP and VM_UFFD_RWP may be cleared on the destination
> + * (dup_userfaultfd() -> userfaultfd_reset_ctx() when the parent context did
> + * not negotiate UFFD_FEATURE_EVENT_FORK), while all other flags propagate.
> *
> * VM_PFNMAP / VM_MIXEDMAP - These contain kernel-mapped data which cannot be
> * reasonably reconstructed on page fault.
> *
> * VM_UFFD_WP - Encodes metadata about an installed uffd
> - * write protect handler, which cannot be
> - * reconstructed on page fault.
> + * VM_UFFD_RWP write- or read-write-protect handler, which
> + * cannot be reconstructed on page fault.
> *
> - * We always copy pgtables when dst_vma has uffd-wp
> - * enabled even if it's file-backed
> - * (e.g. shmem). Because when uffd-wp is enabled,
> - * pgtable contains uffd-wp protection information,
> - * that's something we can't retrieve from page cache,
> - * and skip copying will lose those info.
> + * We always copy pgtables when dst_vma has the
> + * uffd PTE bit in use even if it's file-backed
> + * (e.g. shmem). Because when the uffd bit is
> + * in use, the pgtable contains the protection
> + * information, that's something we can't
> + * retrieve from page cache, and skip copying
> + * will lose those info.
> *
> * VM_MAYBE_GUARD - Could contain page guard region markers which
> * by design are a property of the page tables
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index c4f2cc6dfcf0..f3b2db27989b 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -21,10 +21,11 @@
> #include <linux/hugetlb_inline.h>
>
> /* The set of all possible UFFD-related VM flags. */
> -#define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_WP | VM_UFFD_MINOR)
> +#define __VM_UFFD_FLAGS (VM_UFFD_MISSING | VM_UFFD_MINOR | \
> + VM_UFFD_WP | VM_UFFD_RWP)
>
> #define __VMA_UFFD_FLAGS mk_vma_flags_from_masks(VMA_UFFD_MISSING, VMA_UFFD_WP, \
> - VMA_UFFD_MINOR)
> + VMA_UFFD_MINOR, VMA_UFFD_RWP)
>
> /*
> * CAREFUL: Check include/uapi/asm-generic/fcntl.h when defining
> @@ -179,7 +180,8 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
> {
> return vma_test_any_mask(vma,
> - mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_MINOR));
> + mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_MINOR,
> + VMA_UFFD_RWP));
Wonder if a vma_test_any_masks() is worth adding now :) [will do separately though]
> }
>
> /*
> @@ -210,6 +212,16 @@ static inline bool userfaultfd_minor(struct vm_area_struct *vma)
> return vma_test_any_mask(vma, VMA_UFFD_MINOR);
> }
>
> +static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
> +{
> + return vma_test_any_mask(vma, VMA_UFFD_RWP);
NIT: You could use vma_flags_test_single_mask() just to make it clear it's a single
flag. It's not a big deal though really.
> +}
> +
> +static inline bool userfaultfd_protected(struct vm_area_struct *vma)
> +{
> + return userfaultfd_wp(vma) || userfaultfd_rwp(vma);
> +}
> +
> static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
> pte_t pte)
> {
> @@ -330,6 +342,16 @@ static inline bool userfaultfd_minor(struct vm_area_struct *vma)
> return false;
> }
>
> +static inline bool userfaultfd_rwp(struct vm_area_struct *vma)
> +{
> + return false;
> +}
> +
> +static inline bool userfaultfd_protected(struct vm_area_struct *vma)
> +{
> + return false;
> +}
> +
> static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
> pte_t pte)
> {
> @@ -423,8 +445,8 @@ static inline bool userfaultfd_wp_use_markers(struct vm_area_struct *vma)
> }
>
> /*
> - * Returns true if this is a swap pte and was uffd-wp wr-protected in either
> - * forms (pte marker or a normal swap pte), false otherwise.
> + * Returns true if this swap pte carries uffd-tracked state in either
> + * form (pte marker or a normal swap pte), false otherwise.
> */
> static inline bool pte_swp_uffd_any(pte_t pte)
> {
> diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
> index a6e5a44c9b42..bfface3d0203 100644
> --- a/include/trace/events/mmflags.h
> +++ b/include/trace/events/mmflags.h
> @@ -194,6 +194,12 @@ IF_HAVE_PG_ARCH_3(arch_3)
> # define IF_HAVE_UFFD_MINOR(flag, name)
> #endif
>
> +#ifdef CONFIG_USERFAULTFD_RWP
> +# define IF_HAVE_UFFD_RWP(flag, name) {flag, name},
> +#else
> +# define IF_HAVE_UFFD_RWP(flag, name)
> +#endif
> +
> #if defined(CONFIG_64BIT) || defined(CONFIG_PPC32)
> # define IF_HAVE_VM_DROPPABLE(flag, name) {flag, name},
> #else
> @@ -215,6 +221,7 @@ IF_HAVE_UFFD_MINOR(VM_UFFD_MINOR, "uffd_minor" ) \
> {VM_PFNMAP, "pfnmap" }, \
> {VM_MAYBE_GUARD, "maybe_guard" }, \
> {VM_UFFD_WP, "uffd_wp" }, \
> +IF_HAVE_UFFD_RWP(VM_UFFD_RWP, "uffd_rwp" ) \
> {VM_LOCKED, "locked" }, \
> {VM_IO, "io" }, \
> {VM_SEQ_READ, "seqread" }, \
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH v6 04/15] userfaultfd: test uffd VMA flags through the vma_flags_t API
From: Lorenzo Stoakes @ 2026-06-03 12:54 UTC (permalink / raw)
To: Kiryl Shutsemau (Meta)
Cc: akpm, rppt, peterx, david, surenb, vbabka, Liam.Howlett, ziy,
corbet, skhan, seanjc, pbonzini, jthoughton, aarcange, sj,
usama.arif, linux-mm, linux-kernel, linux-doc, linux-kselftest,
kvm, kernel-team
In-Reply-To: <20260529172716.357179-5-kas@kernel.org>
On Fri, May 29, 2026 at 06:26:33PM +0100, Kiryl Shutsemau (Meta) wrote:
> The uffd VMA-flag helpers read vma->vm_flags directly. Now that
> config-gated per-mode masks exist, switch them to the vma_flags_t
> accessor vma_test_any_mask(), which is the going-forward API and keeps a
> single place (the VMA_UFFD_* masks) that knows which modes are available
> on the current build.
>
> No functional change: vma_flags_t is in union with vm_flags, so the same
> bits are read, and the masks fold to the same code the open-coded
> vm_flags tests produced -- verified identical on gcc and clang, 32- and
> 64-bit.
>
> Suggested-by: Lorenzo Stoakes <ljs@kernel.org>
> Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
Thanks, LGTM so:
Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
> Assisted-by: Claude:claude-opus-4-8
> ---
> include/linux/userfaultfd_k.h | 14 ++++++++------
> 1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index 658740df2978..c4f2cc6dfcf0 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -178,7 +178,8 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> */
> static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
> {
> - return vma->vm_flags & (VM_UFFD_WP | VM_UFFD_MINOR);
> + return vma_test_any_mask(vma,
> + mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_MINOR));
> }
>
> /*
> @@ -190,22 +191,23 @@ static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
> */
> static inline bool uffd_disable_fault_around(struct vm_area_struct *vma)
> {
> - return vma->vm_flags & (VM_UFFD_WP | VM_UFFD_MINOR);
> + return vma_test_any_mask(vma,
> + mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_MINOR));
> }
>
> static inline bool userfaultfd_missing(struct vm_area_struct *vma)
> {
> - return vma->vm_flags & VM_UFFD_MISSING;
> + return vma_test_any_mask(vma, VMA_UFFD_MISSING);
> }
>
> static inline bool userfaultfd_wp(struct vm_area_struct *vma)
> {
> - return vma->vm_flags & VM_UFFD_WP;
> + return vma_test_any_mask(vma, VMA_UFFD_WP);
> }
>
> static inline bool userfaultfd_minor(struct vm_area_struct *vma)
> {
> - return vma->vm_flags & VM_UFFD_MINOR;
> + return vma_test_any_mask(vma, VMA_UFFD_MINOR);
> }
>
> static inline bool userfaultfd_pte_wp(struct vm_area_struct *vma,
> @@ -222,7 +224,7 @@ static inline bool userfaultfd_huge_pmd_wp(struct vm_area_struct *vma,
>
> static inline bool userfaultfd_armed(struct vm_area_struct *vma)
> {
> - return vma->vm_flags & __VM_UFFD_FLAGS;
> + return vma_test_any_mask(vma, __VMA_UFFD_FLAGS);
> }
>
> static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma)
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH v6 08/15] mm: handle VM_UFFD_RWP in khugepaged, rmap, and GUP
From: Lorenzo Stoakes @ 2026-06-03 12:57 UTC (permalink / raw)
To: Kiryl Shutsemau (Meta)
Cc: akpm, rppt, peterx, david, surenb, vbabka, Liam.Howlett, ziy,
corbet, skhan, seanjc, pbonzini, jthoughton, aarcange, sj,
usama.arif, linux-mm, linux-kernel, linux-doc, linux-kselftest,
kvm, kernel-team
In-Reply-To: <20260529172716.357179-9-kas@kernel.org>
On Fri, May 29, 2026 at 06:26:37PM +0100, Kiryl Shutsemau (Meta) wrote:
> Three mm paths outside the fault handler gate on the uffd PTE bit
> today: khugepaged (skip collapse on ranges carrying markers), rmap
> (cap unmap batching), and GUP (force a fault through
> gup_can_follow_protnone). Extend each to treat VM_UFFD_RWP the same
> as VM_UFFD_WP; otherwise per-PTE RWP state is silently destroyed or
> bypassed.
>
> khugepaged: try_collapse_pte_mapped_thp() and
> file_backed_vma_is_retractable() already refuse to collapse or
> retract page tables on ranges carrying the uffd PTE bit. Broaden the
> VMA predicate from userfaultfd_wp() to userfaultfd_protected() so
> VM_UFFD_RWP ranges get the same protection. hpage_collapse_scan_pmd()
> needs no change — its existing pte_uffd() check already catches an
> RWP PTE because it carries the uffd bit.
>
> rmap: folio_unmap_pte_batch() caps batching at 1 for VM_UFFD_RWP so
> the restore path handles each PTE with its own marker.
>
> GUP: gup_can_follow_protnone() forces a fault on VM_UFFD_RWP VMAs
> regardless of FOLL_HONOR_NUMA_FAULT. RWP uses protnone as an
> access-tracking marker, not for NUMA hinting, so any GUP — read or
> write — must go through the userfaultfd fault path.
>
> Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
> Assisted-by: Claude:claude-opus-4-6
> Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Nit below but LGTM, so:
Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
> ---
> include/linux/mm.h | 16 +++++++++++++++-
> mm/khugepaged.c | 18 +++++++++++-------
> mm/rmap.c | 2 +-
> 3 files changed, 27 insertions(+), 9 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 3d4d5f9a6f1b..2b04f690b516 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -4644,11 +4644,25 @@ static inline int vm_fault_to_errno(vm_fault_t vm_fault, int foll_flags)
>
> /*
> * Indicates whether GUP can follow a PROT_NONE mapped page, or whether
> - * a (NUMA hinting) fault is required.
> + * a (NUMA hinting or userfaultfd RWP) fault is required.
> */
> static inline bool gup_can_follow_protnone(const struct vm_area_struct *vma,
> unsigned int flags)
> {
> + /*
> + * VM_UFFD_RWP uses protnone as an access-tracking marker, not for
> + * NUMA hinting. GUP must always take a fault so the access is
> + * delivered to userfaultfd, regardless of FOLL_HONOR_NUMA_FAULT.
> + *
> + * Only do so while the VMA is accessible. If it has been made
> + * inaccessible (e.g. mprotect(PROT_NONE)), fall through to the guard
> + * below: forcing a fault there would loop, as handle_mm_fault() makes
> + * no progress on protnone in an inaccessible VMA, and the access is
> + * denied regardless of RWP anyway.
> + */
> + if ((vma->vm_flags & VM_UFFD_RWP) && vma_is_accessible(vma))
> + return false;
Can be:
if (vma_test_single_mask(vma, VMA_UFFD_RWP) && vma_is_accessible(vma))
return false;
> +
> /*
> * If callers don't want to honor NUMA hinting faults, no need to
> * determine if we would actually have to trigger a NUMA hinting fault.
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index afa218be15de..4f3fedcd75cf 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -1895,8 +1895,11 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
> if (!thp_vma_allowable_order(vma, vma->vm_flags, TVA_FORCED_COLLAPSE, PMD_ORDER))
> return SCAN_VMA_CHECK;
>
> - /* Keep pmd pgtable for uffd-wp; see comment in retract_page_tables() */
> - if (userfaultfd_wp(vma))
> + /*
> + * Keep pmd pgtable while the uffd bit is in use; see comment in
> + * retract_page_tables().
> + */
> + if (userfaultfd_protected(vma))
> return SCAN_PTE_UFFD;
>
> folio = filemap_lock_folio(vma->vm_file->f_mapping,
> @@ -2109,13 +2112,14 @@ static bool file_backed_vma_is_retractable(struct vm_area_struct *vma)
> return false;
>
> /*
> - * When a vma is registered with uffd-wp, we cannot recycle
> + * When a vma is registered with uffd-wp or RWP, we cannot recycle
> * the page table because there may be pte markers installed.
> - * Other vmas can still have the same file mapped hugely, but
> - * skip this one: it will always be mapped in small page size
> - * for uffd-wp registered ranges.
> + * VM_UFFD_RWP ranges similarly rely on per-PTE uffd state
> + * and cannot be recycled to a shared PMD. Other vmas can still
> + * have the same file mapped hugely, but skip this one: it will
> + * always be mapped in small page size for these registrations.
> */
> - if (userfaultfd_wp(vma))
> + if (userfaultfd_protected(vma))
> return false;
>
> /*
> diff --git a/mm/rmap.c b/mm/rmap.c
> index 546bc1cf9391..9fb733489898 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -1965,7 +1965,7 @@ static inline unsigned int folio_unmap_pte_batch(struct folio *folio,
> if (pte_unused(pte))
> return 1;
>
> - if (userfaultfd_wp(vma))
> + if (userfaultfd_protected(vma))
> return 1;
>
> /*
> --
> 2.54.0
>
^ permalink raw reply
* [PATCH v4 0/3] mm: clean up folio LRU and swap declarations
From: Jianyue Wu @ 2026-06-03 13:05 UTC (permalink / raw)
To: Andrew Morton, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Johannes Weiner,
David Hildenbrand, Michal Hocko, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Jonathan Corbet, Shuah Khan
Cc: linux-mm, linux-kernel, linux-doc, Jianyue Wu
The previous version moved the folio LRU helpers out of mm/swap.c in
one step. Based on review feedback from Johannes, Baoquan and Barry,
split the cleanup into smaller steps:
- move the page-cluster sysctl next to swap readahead in mm/swap_state.c
- rename mm/swap.c to mm/folio_lru.c after the swap-specific bits move out
- move MM-internal reclaim declarations out of include/linux/swap.h
After this series, swap cache and swap-in readahead stay in mm/swap_state.c,
folio LRU helpers live in mm/folio_lru.c, and MM-internal reclaim/workingset
declarations move from include/linux/swap.h to mm/internal.h (public LRU
helpers used outside mm/ remain in swap.h).
The first patch handles the swap-specific page-cluster state before the
file rename, so the rename commit only carries folio LRU code. The last
patch keeps the LRU helpers used outside mm/ in include/linux/swap.h and
moves the internal reclaim/workingset declarations to mm/internal.h.
This series is based on Christoph Hellwig's swap_ops series, which
moves swap I/O dispatch behind swap_ops and leaves mm/swap.c with less
swap-specific state. That makes the folio LRU cleanup more natural to
split out on top.
https://lore.kernel.org/r/20260528124559.2566481-1-hch@lst.de
To: Andrew Morton <akpm@linux-foundation.org>
To: Chris Li <chrisl@kernel.org>
To: Kairui Song <kasong@tencent.com>
To: Kemeng Shi <shikemeng@huaweicloud.com>
To: Nhat Pham <nphamcs@gmail.com>
To: Baoquan He <bhe@redhat.com>
To: Barry Song <baohua@kernel.org>
To: Youngjun Park <youngjun.park@lge.com>
To: Qi Zheng <qi.zheng@linux.dev>
To: Shakeel Butt <shakeel.butt@linux.dev>
To: Axel Rasmussen <axelrasmussen@google.com>
To: Yuanchu Xie <yuanchu@google.com>
To: Wei Xu <weixugc@google.com>
To: Johannes Weiner <hannes@cmpxchg.org>
To: David Hildenbrand <david@kernel.org>
To: Michal Hocko <mhocko@kernel.org>
To: Lorenzo Stoakes <ljs@kernel.org>
To: Liam R. Howlett <liam@infradead.org>
To: Vlastimil Babka <vbabka@kernel.org>
To: Mike Rapoport <rppt@kernel.org>
To: Suren Baghdasaryan <surenb@google.com>
To: Michal Hocko <mhocko@suse.com>
To: Hugh Dickins <hughd@google.com>
To: Baolin Wang <baolin.wang@linux.alibaba.com>
To: Jonathan Corbet <corbet@lwn.net>
To: Shuah Khan <skhan@linuxfoundation.org>
Cc: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Signed-off-by: Jianyue Wu <wujianyue000@gmail.com>
Changes in v4:
- Address Baoquan He's review on v3: align patch 2 subject with
rename-only scope; fix vm.rst sysctl documentation; refresh file
header comments in mm/folio_lru.c and swap.h declaration comments.
- Expand patch 1 commit message on CONFIG_SWAP=n vm.page-cluster
registration (also on CONFIG_SWAP=n kernels).
- Link to v3: https://lore.kernel.org/all/20260602-ch-swap-series-plus-folio-lru-cleanup-v3-0-5bbb567f8c99@gmail.com
---
Jianyue Wu (3):
mm/swap: colocate page-cluster sysctl with swap readahead
mm: rename swap.c to folio_lru.c
mm: move reclaim-internal declarations out of swap.h
Documentation/admin-guide/sysctl/vm.rst | 3 --
Documentation/core-api/mm-api.rst | 2 +-
MAINTAINERS | 3 +-
include/linux/swap.h | 75 +++------------------------------
mm/Makefile | 2 +-
mm/{swap.c => folio_lru.c} | 46 ++------------------
mm/internal.h | 68 ++++++++++++++++++++++++++++++
mm/memfd.c | 1 +
mm/swap.h | 8 +++-
mm/swap_state.c | 37 ++++++++++++++++
mm/vmscan.c | 2 +-
11 files changed, 126 insertions(+), 121 deletions(-)
---
base-commit: d7be408821acadd7d713d1da16a6742886799114
change-id: 20260531-ch-swap-series-plus-folio-lru-cleanup-d9781c8332dc
Best regards,
--
Jianyue Wu <wujianyue000@gmail.com>
^ permalink raw reply
* [PATCH v4 1/3] mm/swap: colocate page-cluster sysctl with swap readahead
From: Jianyue Wu @ 2026-06-03 13:05 UTC (permalink / raw)
To: Andrew Morton, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Johannes Weiner,
David Hildenbrand, Michal Hocko, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Jonathan Corbet, Shuah Khan
Cc: linux-mm, linux-kernel, linux-doc, Jianyue Wu
In-Reply-To: <20260603-ch-swap-series-plus-folio-lru-cleanup-v4-0-ce0219e100d9@gmail.com>
page_cluster and the vm.page-cluster sysctl are only used by swap-in
readahead in swap_state.c. Move them out of swap.c together with
swap_readahead_setup(), and make page_cluster static to that file.
Rename swap_setup() while moving it as well. The helper is internal to
MM and now only sets up swap readahead defaults and its sysctl hook, so
the more specific name matches its reduced scope.
swap_setup() previously lived in mm/swap.c, which is built
unconditionally, so the vm.page-cluster sysctl was registered also on
CONFIG_SWAP=n kernels. swap_readahead_setup() is now a no-op stub when
CONFIG_SWAP is disabled, so vm.page-cluster is no longer registered
there. The knob only tunes swap-in readahead and had no effect without
swap.
Suggested-by: Baoquan He <bhe@redhat.com>
Suggested-by: Barry Song <baohua@kernel.org>
Signed-off-by: Jianyue Wu <wujianyue000@gmail.com>
---
include/linux/swap.h | 1 -
mm/swap.c | 36 ------------------------------------
mm/swap.h | 8 ++++++--
mm/swap_state.c | 37 +++++++++++++++++++++++++++++++++++++
mm/vmscan.c | 2 +-
5 files changed, 44 insertions(+), 40 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 636d94108166..5bd6f1d5984a 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -345,7 +345,6 @@ extern void lru_add_drain_cpu_zone(struct zone *zone);
extern void lru_add_drain_all(void);
void folio_deactivate(struct folio *folio);
void folio_mark_lazyfree(struct folio *folio);
-extern void swap_setup(void);
/* linux/mm/vmscan.c */
extern unsigned long zone_reclaimable_pages(struct zone *zone);
diff --git a/mm/swap.c b/mm/swap.c
index 588f50d8f1a8..e4b3dadaa6dc 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -43,10 +43,6 @@
#define CREATE_TRACE_POINTS
#include <trace/events/pagemap.h>
-/* How many pages do we try to swap or page in/out together? As a power of 2 */
-int page_cluster;
-static const int page_cluster_max = 31;
-
struct cpu_fbatches {
/*
* The following folio batches are grouped together because they are protected
@@ -1171,35 +1167,3 @@ void lru_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent, int
lruvec_reparent_lru(child_lruvec, parent_lruvec, lru, nid);
}
#endif
-
-static const struct ctl_table swap_sysctl_table[] = {
- {
- .procname = "page-cluster",
- .data = &page_cluster,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = SYSCTL_ZERO,
- .extra2 = (void *)&page_cluster_max,
- }
-};
-
-/*
- * Perform any setup for the swap system
- */
-void __init swap_setup(void)
-{
- unsigned long megs = PAGES_TO_MB(totalram_pages());
-
- /* Use a smaller cluster for small-memory machines */
- if (megs < 16)
- page_cluster = 2;
- else
- page_cluster = 3;
- /*
- * Right now other parts of the system means that we
- * _really_ don't want to cluster much more
- */
-
- register_sysctl_init("vm", swap_sysctl_table);
-}
diff --git a/mm/swap.h b/mm/swap.h
index 8742b82cd0db..f860f8c669e8 100644
--- a/mm/swap.h
+++ b/mm/swap.h
@@ -9,8 +9,6 @@ struct mempolicy;
struct swap_iocb;
struct swap_memcg_table;
-extern int page_cluster;
-
#if defined(MAX_POSSIBLE_PHYSMEM_BITS)
#define SWAP_CACHE_PFN_BITS (MAX_POSSIBLE_PHYSMEM_BITS - PAGE_SHIFT)
#elif defined(MAX_PHYSMEM_BITS)
@@ -96,6 +94,8 @@ struct swap_ops {
};
#ifdef CONFIG_SWAP
+void swap_readahead_setup(void);
+
#include <linux/swapops.h> /* for swp_offset */
#include <linux/blk_types.h> /* for bio_end_io_t */
@@ -345,6 +345,10 @@ static inline unsigned int folio_swap_flags(struct folio *folio)
}
#else /* CONFIG_SWAP */
+static inline void swap_readahead_setup(void)
+{
+}
+
static inline struct swap_cluster_info *swap_cluster_lock(
struct swap_info_struct *si, pgoff_t offset, bool irq)
{
diff --git a/mm/swap_state.c b/mm/swap_state.c
index b9613026950e..692dfcd89bcd 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -22,10 +22,15 @@
#include <linux/vmalloc.h>
#include <linux/huge_mm.h>
#include <linux/shmem_fs.h>
+#include <linux/sysctl.h>
#include "internal.h"
#include "swap_table.h"
#include "swap.h"
+/* Swap readahead cluster size, as a power of 2 pages. */
+static int page_cluster;
+static const int page_cluster_max = 31;
+
/*
* swapper_space is a fiction, retained to simplify the path through
* vmscan's shrink_folio_list.
@@ -986,6 +991,38 @@ struct folio *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
return folio;
}
+static const struct ctl_table swap_readahead_sysctl_table[] = {
+ {
+ .procname = "page-cluster",
+ .data = &page_cluster,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = (void *)&page_cluster_max,
+ }
+};
+
+/**
+ * swap_readahead_setup - defaults and sysctl for swap cache readahead clustering
+ */
+void __init swap_readahead_setup(void)
+{
+ unsigned long megs = PAGES_TO_MB(totalram_pages());
+
+ /* Use a smaller cluster for small-memory machines */
+ if (megs < 16)
+ page_cluster = 2;
+ else
+ page_cluster = 3;
+ /*
+ * Right now other parts of the system means that we
+ * _really_ don't want to cluster much more
+ */
+
+ register_sysctl_init("vm", swap_readahead_sysctl_table);
+}
+
#ifdef CONFIG_SYSFS
static ssize_t vma_ra_enabled_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 2d44ebfebdea..e34f1565f42f 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -7651,7 +7651,7 @@ static int __init kswapd_init(void)
{
int nid;
- swap_setup();
+ swap_readahead_setup();
for_each_node_state(nid, N_MEMORY)
kswapd_run(nid);
register_sysctl_init("vm", vmscan_sysctl_table);
--
2.43.0
^ permalink raw reply related
* [PATCH v4 2/3] mm: rename swap.c to folio_lru.c
From: Jianyue Wu @ 2026-06-03 13:05 UTC (permalink / raw)
To: Andrew Morton, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Johannes Weiner,
David Hildenbrand, Michal Hocko, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Jonathan Corbet, Shuah Khan
Cc: linux-mm, linux-kernel, linux-doc, Jianyue Wu
In-Reply-To: <20260603-ch-swap-series-plus-folio-lru-cleanup-v4-0-ce0219e100d9@gmail.com>
Rename mm/swap.c to mm/folio_lru.c so the filename better matches
the code's main responsibility.
This keeps the implementation split from swap-specific code without
changing the published LRU helper interfaces.
Update MAINTAINERS and the remaining mm/swap.c documentation references
after the rename.
Suggested-by: Baoquan He <bhe@redhat.com>
Suggested-by: David Hildenbrand <david@kernel.org>
Signed-off-by: Jianyue Wu <wujianyue000@gmail.com>
---
Documentation/admin-guide/sysctl/vm.rst | 3 ---
Documentation/core-api/mm-api.rst | 2 +-
MAINTAINERS | 3 +--
mm/Makefile | 2 +-
mm/{swap.c => folio_lru.c} | 10 +++-------
5 files changed, 6 insertions(+), 14 deletions(-)
diff --git a/Documentation/admin-guide/sysctl/vm.rst b/Documentation/admin-guide/sysctl/vm.rst
index 97e12359775c..2b9513371324 100644
--- a/Documentation/admin-guide/sysctl/vm.rst
+++ b/Documentation/admin-guide/sysctl/vm.rst
@@ -19,9 +19,6 @@ The files in this directory can be used to tune the operation
of the virtual memory (VM) subsystem of the Linux kernel and
the writeout of dirty data to disk.
-Default values and initialization routines for most of these
-files can be found in mm/swap.c.
-
Currently, these files are in /proc/sys/vm:
- admin_reserve_kbytes
diff --git a/Documentation/core-api/mm-api.rst b/Documentation/core-api/mm-api.rst
index aabdd3cba58e..d6d189b9a996 100644
--- a/Documentation/core-api/mm-api.rst
+++ b/Documentation/core-api/mm-api.rst
@@ -117,7 +117,7 @@ More Memory Management Functions
.. #kernel-doc:: mm/hmm.c (build warnings)
.. kernel-doc:: mm/memremap.c
.. kernel-doc:: mm/hugetlb.c
-.. kernel-doc:: mm/swap.c
+.. kernel-doc:: mm/folio_lru.c
.. kernel-doc:: mm/memcontrol.c
.. #kernel-doc:: mm/memory-tiers.c (build warnings)
.. kernel-doc:: mm/shmem.c
diff --git a/MAINTAINERS b/MAINTAINERS
index e3ee97f5474e..6bd39e0afceb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16900,7 +16900,7 @@ F: Documentation/admin-guide/mm/multigen_lru.rst
F: Documentation/mm/multigen_lru.rst
F: include/linux/mm_inline.h
F: include/linux/mmzone.h
-F: mm/swap.c
+F: mm/folio_lru.c
F: mm/vmscan.c
F: mm/workingset.c
@@ -17045,7 +17045,6 @@ F: include/linux/swap.h
F: include/linux/swapfile.h
F: include/linux/swapops.h
F: mm/page_io.c
-F: mm/swap.c
F: mm/swap.h
F: mm/swap_table.h
F: mm/swap_state.c
diff --git a/mm/Makefile b/mm/Makefile
index eff9f9e7e061..5f712f9bbe73 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -50,7 +50,7 @@ endif
obj-y := filemap.o mempool.o oom_kill.o fadvise.o \
maccess.o page-writeback.o folio-compat.o \
- readahead.o swap.o truncate.o vmscan.o shrinker.o \
+ readahead.o folio_lru.o truncate.o vmscan.o shrinker.o \
shmem.o util.o mmzone.o vmstat.o backing-dev.o \
mm_init.o percpu.o slab_common.o \
compaction.o show_mem.o \
diff --git a/mm/swap.c b/mm/folio_lru.c
similarity index 99%
rename from mm/swap.c
rename to mm/folio_lru.c
index e4b3dadaa6dc..46924a797ead 100644
--- a/mm/swap.c
+++ b/mm/folio_lru.c
@@ -1,17 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * linux/mm/swap.c
+ * linux/mm/folio_lru.c
*
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
*/
/*
- * This file contains the default values for the operation of the
- * Linux VM subsystem. Fine-tuning documentation can be found in
- * Documentation/admin-guide/sysctl/vm.rst.
- * Started 18.12.91
- * Swap aging added 23.2.95, Stephen Tweedie.
- * Buffermem limits added 12.3.98, Rik van Riel.
+ * Folio LRU helpers: add/remove folios from LRU lists, batching,
+ * activation/deactivation, and page cache release paths.
*/
#include <linux/mm.h>
--
2.43.0
^ permalink raw reply related
* [PATCH v4 3/3] mm: move reclaim-internal declarations out of swap.h
From: Jianyue Wu @ 2026-06-03 13:05 UTC (permalink / raw)
To: Andrew Morton, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
Baoquan He, Barry Song, Youngjun Park, Qi Zheng, Shakeel Butt,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Johannes Weiner,
David Hildenbrand, Michal Hocko, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Jonathan Corbet, Shuah Khan
Cc: linux-mm, linux-kernel, linux-doc, Jianyue Wu
In-Reply-To: <20260603-ch-swap-series-plus-folio-lru-cleanup-v4-0-ce0219e100d9@gmail.com>
Keep include/linux/swap.h focused on swap-facing interfaces by moving
MM-internal reclaim and workingset declarations into mm/internal.h.
Leave the small set of LRU helper declarations that are used outside mm/
in swap.h so this cleanup does not need a new public header under
include/linux/.
Suggested-by: Barry Song <baohua@kernel.org>
Suggested-by: Baoquan He <bhe@redhat.com>
Signed-off-by: Jianyue Wu <wujianyue000@gmail.com>
---
include/linux/swap.h | 74 +++++-----------------------------------------------
mm/internal.h | 68 +++++++++++++++++++++++++++++++++++++++++++++++
mm/memfd.c | 1 +
3 files changed, 76 insertions(+), 67 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 5bd6f1d5984a..5c0d92613a35 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -292,39 +292,19 @@ static inline swp_entry_t page_swap_entry(struct page *page)
return entry;
}
-/* linux/mm/workingset.c */
-bool workingset_test_recent(void *shadow, bool file, bool *workingset,
- bool flush);
-void workingset_age_nonresident(struct lruvec *lruvec, unsigned long nr_pages);
-void *workingset_eviction(struct folio *folio, struct mem_cgroup *target_memcg);
-void workingset_refault(struct folio *folio, void *shadow);
-void workingset_activation(struct folio *folio);
-
/* linux/mm/page_alloc.c */
extern unsigned long totalreserve_pages;
/* Definition of global_zone_page_state not available yet */
#define nr_free_pages() global_zone_page_state(NR_FREE_PAGES)
+/* linux/mm/folio_lru.c */
+void folio_add_lru(struct folio *folio);
+void folio_mark_accessed(struct folio *folio);
+void lru_add_drain_all(void);
-/* linux/mm/swap.c */
-void lru_note_cost_unlock_irq(struct lruvec *lruvec, bool file,
- unsigned int nr_io, unsigned int nr_rotated);
-void lru_note_cost_refault(struct folio *);
-void folio_add_lru(struct folio *);
-void folio_add_lru_vma(struct folio *, struct vm_area_struct *);
-void mark_page_accessed(struct page *);
-void folio_mark_accessed(struct folio *);
-
-static inline bool folio_may_be_lru_cached(struct folio *folio)
-{
- /*
- * Holding PMD-sized folios in per-CPU LRU cache unbalances accounting.
- * Holding small numbers of low-order mTHP folios in per-CPU LRU cache
- * will be sensible, but nobody has implemented and tested that yet.
- */
- return !folio_test_large(folio);
-}
+/* linux/mm/folio-compat.c */
+void mark_page_accessed(struct page *page);
extern atomic_t lru_disable_count;
@@ -333,42 +313,7 @@ static inline bool lru_cache_disabled(void)
return atomic_read(&lru_disable_count);
}
-static inline void lru_cache_enable(void)
-{
- atomic_dec(&lru_disable_count);
-}
-
-extern void lru_cache_disable(void);
-extern void lru_add_drain(void);
-extern void lru_add_drain_cpu(int cpu);
-extern void lru_add_drain_cpu_zone(struct zone *zone);
-extern void lru_add_drain_all(void);
-void folio_deactivate(struct folio *folio);
-void folio_mark_lazyfree(struct folio *folio);
-
/* linux/mm/vmscan.c */
-extern unsigned long zone_reclaimable_pages(struct zone *zone);
-extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
- gfp_t gfp_mask, nodemask_t *mask);
-unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone_idx);
-
-#define MEMCG_RECLAIM_MAY_SWAP (1 << 1)
-#define MEMCG_RECLAIM_PROACTIVE (1 << 2)
-#define MIN_SWAPPINESS 0
-#define MAX_SWAPPINESS 200
-
-/* Just reclaim from anon folios in proactive memory reclaim */
-#define SWAPPINESS_ANON_ONLY (MAX_SWAPPINESS + 1)
-
-extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
- unsigned long nr_pages,
- gfp_t gfp_mask,
- unsigned int reclaim_options,
- int *swappiness);
-extern unsigned long mem_cgroup_shrink_node(struct mem_cgroup *mem,
- gfp_t gfp_mask, bool noswap,
- pg_data_t *pgdat,
- unsigned long *nr_scanned);
extern unsigned long shrink_all_memory(unsigned long nr_pages);
extern int vm_swappiness;
long remove_mapping(struct address_space *mapping, struct folio *folio);
@@ -389,11 +334,6 @@ static inline void reclaim_unregister_node(struct node *node)
}
#endif /* CONFIG_SYSFS && CONFIG_NUMA */
-#ifdef CONFIG_NUMA
-extern int sysctl_min_unmapped_ratio;
-extern int sysctl_min_slab_ratio;
-#endif
-
void check_move_unevictable_folios(struct folio_batch *fbatch);
extern void __meminit kswapd_run(int nid);
@@ -553,7 +493,7 @@ static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg)
void lru_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent, int nid);
#else
-static inline int mem_cgroup_swappiness(struct mem_cgroup *mem)
+static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg)
{
return READ_ONCE(vm_swappiness);
}
diff --git a/mm/internal.h b/mm/internal.h
index 5602393054f3..1744bb6b3222 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -24,6 +24,74 @@
struct folio_batch;
+/* mm/workingset.c */
+bool workingset_test_recent(void *shadow, bool file, bool *workingset,
+ bool flush);
+void workingset_age_nonresident(struct lruvec *lruvec, unsigned long nr_pages);
+void *workingset_eviction(struct folio *folio,
+ struct mem_cgroup *target_memcg);
+void workingset_refault(struct folio *folio, void *shadow);
+void workingset_activation(struct folio *folio);
+
+/* mm/folio_lru.c */
+void lru_note_cost_unlock_irq(struct lruvec *lruvec, bool file,
+ unsigned int nr_io, unsigned int nr_rotated)
+ __releases(lruvec->lru_lock);
+void lru_note_cost_refault(struct folio *folio);
+void folio_add_lru_vma(struct folio *folio, struct vm_area_struct *vma);
+
+static inline bool folio_may_be_lru_cached(struct folio *folio)
+{
+ /*
+ * Holding PMD-sized folios in per-CPU LRU cache unbalances accounting.
+ * Holding small numbers of low-order mTHP folios in per-CPU LRU cache
+ * will be sensible, but nobody has implemented and tested that yet.
+ */
+ return !folio_test_large(folio);
+}
+
+static inline void lru_cache_enable(void)
+{
+ atomic_dec(&lru_disable_count);
+}
+
+void lru_cache_disable(void);
+void lru_add_drain(void);
+void lru_add_drain_cpu(int cpu);
+void lru_add_drain_cpu_zone(struct zone *zone);
+void folio_deactivate(struct folio *folio);
+void folio_mark_lazyfree(struct folio *folio);
+
+/* mm/vmscan.c */
+unsigned long zone_reclaimable_pages(struct zone *zone);
+unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
+ gfp_t gfp_mask, nodemask_t *mask);
+unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru,
+ int zone_idx);
+
+#define MEMCG_RECLAIM_MAY_SWAP (1 << 1)
+#define MEMCG_RECLAIM_PROACTIVE (1 << 2)
+#define MIN_SWAPPINESS 0
+#define MAX_SWAPPINESS 200
+
+/* Just reclaim from anon folios in proactive memory reclaim */
+#define SWAPPINESS_ANON_ONLY (MAX_SWAPPINESS + 1)
+
+unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
+ unsigned long nr_pages,
+ gfp_t gfp_mask,
+ unsigned int reclaim_options,
+ int *swappiness);
+unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
+ gfp_t gfp_mask, bool noswap,
+ pg_data_t *pgdat,
+ unsigned long *nr_scanned);
+
+#ifdef CONFIG_NUMA
+extern int sysctl_min_unmapped_ratio;
+extern int sysctl_min_slab_ratio;
+#endif
+
/*
* Maintains state across a page table move. The operation assumes both source
* and destination VMAs already exist and are specified by the user.
diff --git a/mm/memfd.c b/mm/memfd.c
index abe13b291ddc..6c72fe6caef7 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -19,6 +19,7 @@
#include <linux/memfd.h>
#include <linux/pid_namespace.h>
#include <uapi/linux/memfd.h>
+#include "internal.h"
#include "swap.h"
/*
--
2.43.0
^ permalink raw reply related
* [PATCH v6.1 07/13] kho: add support for linked-block serialization
From: Pasha Tatashin @ 2026-06-03 13:06 UTC (permalink / raw)
To: rppt
Cc: linux-kselftest, shuah, akpm, linux-mm, skhan, linux-doc,
linux-kernel, corbet, dmatlack, kexec, pratyush, skhawaja, graf
In-Reply-To: <aiAgHTbleCL60SYm@plex>
Introduce a linked-block serialization mechanism for state handover.
Previously, LUO used contiguous memory blocks for serializing sessions
and files, which imposed limits on the total number of items that could
be preserved across a live update.
This commit adds the infrastructure for a more flexible, block-based
approach where serialized data is stored in a chain of linked blocks.
This is a generic KHO serialization block infrastructure that can be
used by multiple subsystems.
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
Documentation/core-api/kho/abi.rst | 5 +
Documentation/core-api/kho/index.rst | 11 +
MAINTAINERS | 1 +
include/linux/kho/abi/block.h | 56 ++++
include/linux/kho_block.h | 106 +++++++
kernel/liveupdate/Makefile | 1 +
kernel/liveupdate/kho_block.c | 416 +++++++++++++++++++++++++++
7 files changed, 596 insertions(+)
create mode 100644 include/linux/kho/abi/block.h
create mode 100644 include/linux/kho_block.h
create mode 100644 kernel/liveupdate/kho_block.c
diff --git a/Documentation/core-api/kho/abi.rst b/Documentation/core-api/kho/abi.rst
index 799d743105a6..edeb5b311963 100644
--- a/Documentation/core-api/kho/abi.rst
+++ b/Documentation/core-api/kho/abi.rst
@@ -28,6 +28,11 @@ KHO persistent memory tracker ABI
.. kernel-doc:: include/linux/kho/abi/kexec_handover.h
:doc: KHO persistent memory tracker
+KHO serialization block ABI
+===========================
+
+.. kernel-doc:: include/linux/kho/abi/block.h
+
See Also
========
diff --git a/Documentation/core-api/kho/index.rst b/Documentation/core-api/kho/index.rst
index 0a2dee4f8e7d..320914a42178 100644
--- a/Documentation/core-api/kho/index.rst
+++ b/Documentation/core-api/kho/index.rst
@@ -83,6 +83,17 @@ Public API
.. kernel-doc:: kernel/liveupdate/kexec_handover.c
:export:
+KHO Serialization Blocks API
+============================
+
+.. kernel-doc:: kernel/liveupdate/kho_block.c
+ :doc: KHO Serialization Blocks
+
+.. kernel-doc:: include/linux/kho_block.h
+
+.. kernel-doc:: kernel/liveupdate/kho_block.c
+ :internal:
+
See Also
========
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ec290e38b44..920ba7622afa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14208,6 +14208,7 @@ F: Documentation/admin-guide/mm/kho.rst
F: Documentation/core-api/kho/*
F: include/linux/kexec_handover.h
F: include/linux/kho/
+F: include/linux/kho_block.h
F: kernel/liveupdate/kexec_handover*
F: lib/test_kho.c
F: tools/testing/selftests/kho/
diff --git a/include/linux/kho/abi/block.h b/include/linux/kho/abi/block.h
new file mode 100644
index 000000000000..8641c20b379b
--- /dev/null
+++ b/include/linux/kho/abi/block.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026, Google LLC.
+ * Pasha Tatashin <pasha.tatashin@soleen.com>
+ */
+
+/**
+ * DOC: KHO Serialization Blocks ABI
+ *
+ * Subsystems using the KHO Serialization Blocks framework rely on the stable
+ * Application Binary Interface defined below to pass serialized state from a
+ * pre-update kernel to a post-update kernel.
+ *
+ * This interface is a contract. Any modification to the structure fields,
+ * compatible strings, or the layout of the `__packed` serialization
+ * structures defined here constitutes a breaking change. Such changes require
+ * incrementing the version number in the `KHO_BLOCK_ABI_COMPATIBLE` string to
+ * prevent a new kernel from misinterpreting data from an old kernel.
+ *
+ * Changes are allowed provided the compatibility version is incremented;
+ * however, backward/forward compatibility is only guaranteed for kernels
+ * supporting the same ABI version.
+ */
+
+#ifndef _LINUX_KHO_ABI_BLOCK_H
+#define _LINUX_KHO_ABI_BLOCK_H
+
+#include <asm/page.h>
+#include <linux/types.h>
+
+#define KHO_BLOCK_ABI_COMPATIBLE "kho-block-v1"
+
+/**
+ * KHO_BLOCK_SIZE - The size of each serialization block.
+ *
+ * This is defined as PAGE_SIZE. PAGE_SIZE is ABI compliant because live
+ * update between kernels with different page sizes is not supported by KHO.
+ */
+#define KHO_BLOCK_SIZE PAGE_SIZE
+
+/**
+ * struct kho_block_header_ser - Header for the serialized data block.
+ * @next: Physical address of the next struct kho_block_header_ser.
+ * @count: The number of entries that immediately follow this header in the
+ * memory block.
+ *
+ * This structure is located at the beginning of a block of physical memory
+ * preserved across a kexec. It provides the necessary metadata to interpret
+ * the array of entries that follow.
+ */
+struct kho_block_header_ser {
+ u64 next;
+ u64 count;
+} __packed;
+
+#endif /* _LINUX_KHO_ABI_BLOCK_H */
diff --git a/include/linux/kho_block.h b/include/linux/kho_block.h
new file mode 100644
index 000000000000..93a7cc2be5f5
--- /dev/null
+++ b/include/linux/kho_block.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026, Google LLC.
+ * Pasha Tatashin <pasha.tatashin@soleen.com>
+ */
+
+#ifndef _LINUX_KHO_BLOCK_H
+#define _LINUX_KHO_BLOCK_H
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/kho/abi/block.h>
+
+/**
+ * struct kho_block - Internal representation of a serialization block.
+ * @list: List head for linking blocks in memory.
+ * @ser: Pointer to the serialized header in preserved memory.
+ */
+struct kho_block {
+ struct list_head list;
+ struct kho_block_header_ser *ser;
+};
+
+/**
+ * struct kho_block_set - A set of blocks containing serialized entries of the same type.
+ * @blocks: The list of serialization blocks (struct kho_block).
+ * @nblocks: The number of allocated serialization blocks.
+ * @head_pa: Physical address of the first block header.
+ * @entry_size: The size of each entry in the blocks.
+ * @count_per_block: The maximum number of entries each block can hold.
+ * @incoming: True if this block set was restored from the previous kernel.
+ *
+ * Note: Synchronization and locking are the responsibility of the caller.
+ * The block set structure itself is not internally synchronized.
+ */
+struct kho_block_set {
+ struct list_head blocks;
+ long nblocks;
+ u64 head_pa;
+ size_t entry_size;
+ u64 count_per_block;
+ bool incoming;
+};
+
+/**
+ * struct kho_block_set_it - Iterator for serializing entries into blocks.
+ * @bs: The block set being iterated.
+ * @block: The current block.
+ * @i: The current entry index within @block.
+ */
+struct kho_block_set_it {
+ struct kho_block_set *bs;
+ struct kho_block *block;
+ u64 i;
+};
+
+/**
+ * KHO_BLOCK_SET_INIT - Initialize a static kho_block_set.
+ * @_name: Name of the kho_block_set variable.
+ * @_entry_size: The size of each entry in the block set.
+ */
+#define KHO_BLOCK_SET_INIT(_name, _entry_size) { \
+ .blocks = LIST_HEAD_INIT((_name).blocks), \
+ .entry_size = _entry_size, \
+ .count_per_block = (KHO_BLOCK_SIZE - \
+ sizeof(struct kho_block_header_ser)) / \
+ (_entry_size), \
+}
+
+void kho_block_set_init(struct kho_block_set *bs, size_t entry_size);
+
+int kho_block_set_grow(struct kho_block_set *bs, u64 count);
+void kho_block_set_shrink(struct kho_block_set *bs, u64 count);
+
+int kho_block_set_restore(struct kho_block_set *bs, u64 head_pa);
+void kho_block_set_destroy(struct kho_block_set *bs);
+void kho_block_set_clear(struct kho_block_set *bs);
+
+/**
+ * kho_block_set_head_pa - Get the physical address of the first block header.
+ * @bs: The block set.
+ *
+ * Return: The physical address of the first block header, or 0 if empty.
+ */
+static inline u64 kho_block_set_head_pa(struct kho_block_set *bs)
+{
+ return bs->head_pa;
+}
+
+/**
+ * kho_block_set_is_empty - Check if the block set has no allocated blocks.
+ * @bs: The block set.
+ *
+ * Return: True if there are no blocks in the set, false otherwise.
+ */
+static inline bool kho_block_set_is_empty(struct kho_block_set *bs)
+{
+ return list_empty(&bs->blocks);
+}
+
+void kho_block_set_it_init(struct kho_block_set_it *it, struct kho_block_set *bs);
+void *kho_block_set_it_reserve_entry(struct kho_block_set_it *it);
+void *kho_block_set_it_read_entry(struct kho_block_set_it *it);
+void *kho_block_set_it_prev(struct kho_block_set_it *it);
+
+#endif /* _LINUX_KHO_BLOCK_H */
diff --git a/kernel/liveupdate/Makefile b/kernel/liveupdate/Makefile
index d2f779cbe279..eec9d3ae07eb 100644
--- a/kernel/liveupdate/Makefile
+++ b/kernel/liveupdate/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
luo-y := \
+ kho_block.o \
luo_core.o \
luo_file.o \
luo_flb.o \
diff --git a/kernel/liveupdate/kho_block.c b/kernel/liveupdate/kho_block.c
new file mode 100644
index 000000000000..0d2a342ef422
--- /dev/null
+++ b/kernel/liveupdate/kho_block.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2026, Google LLC.
+ * Pasha Tatashin <pasha.tatashin@soleen.com>
+ */
+
+/**
+ * DOC: KHO Serialization Blocks
+ *
+ * KHO provides a mechanism to preserve stateful data across a kexec handover
+ * by serializing it into memory blocks, and provides the common
+ * infrastructure for managing these blocks.
+ *
+ * Each block consists of a header (struct kho_block_header_ser) followed by an
+ * array of serialized entries. Multiple blocks are linked together via a
+ * physical pointer in the header, forming a linked list that can be easily
+ * traversed in both the current and the next kernel.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/kexec_handover.h>
+#include <linux/kho/abi/block.h>
+#include <linux/kho_block.h>
+#include <linux/slab.h>
+
+/*
+ * Safeguard limit for the number of serialization blocks. This is used to
+ * prevent infinite loops and excessive memory allocation in case of memory
+ * corruption in the preserved state.
+ *
+ * With a 4KB page size, 10k blocks is about 40MB. For 32-byte entries
+ * (e.g. 4 u64s), each block holds up to 127 entries (accounting for the
+ * 16-byte header), allowing the block set to hold up to 1.27M entries.
+ */
+#define KHO_MAX_BLOCKS 10000
+
+/**
+ * kho_block_set_init - Initialize a block set.
+ * @bs: The block set to initialize.
+ * @entry_size: The size of each entry in the blocks.
+ */
+void kho_block_set_init(struct kho_block_set *bs, size_t entry_size)
+{
+ *bs = (struct kho_block_set)KHO_BLOCK_SET_INIT(*bs, entry_size);
+ WARN_ON_ONCE(!bs->count_per_block);
+}
+
+/* Serialized entries start immediately after the block header */
+static void *kho_block_entries(struct kho_block *block)
+{
+ return (void *)(block->ser + 1);
+}
+
+/* Get the address of the serialized entry at the specified index */
+static void *kho_block_entry(struct kho_block_set_it *it, u64 index)
+{
+ return kho_block_entries(it->block) + (index * it->bs->entry_size);
+}
+
+/* Free serialized data */
+static void kho_block_free_ser(struct kho_block_set *bs,
+ struct kho_block_header_ser *ser)
+{
+ if (bs->incoming)
+ kho_restore_free(ser);
+ else
+ kho_unpreserve_free(ser);
+}
+
+static struct kho_block_header_ser *kho_block_alloc_ser(struct kho_block_set *bs)
+{
+ WARN_ON_ONCE(bs->incoming);
+ return kho_alloc_preserve(KHO_BLOCK_SIZE);
+}
+
+static int kho_block_add(struct kho_block_set *bs,
+ struct kho_block_header_ser *ser)
+{
+ struct kho_block *block, *last;
+
+ if (bs->nblocks >= KHO_MAX_BLOCKS)
+ return -ENOSPC;
+
+ block = kzalloc_obj(*block);
+ if (!block)
+ return -ENOMEM;
+
+ block->ser = ser;
+ last = list_last_entry_or_null(&bs->blocks, struct kho_block, list);
+ list_add_tail(&block->list, &bs->blocks);
+ bs->nblocks++;
+
+ if (last)
+ last->ser->next = virt_to_phys(ser);
+ else
+ bs->head_pa = virt_to_phys(ser);
+
+ return 0;
+}
+
+static int kho_block_set_grow_one(struct kho_block_set *bs)
+{
+ struct kho_block_header_ser *ser;
+ int err;
+
+ ser = kho_block_alloc_ser(bs);
+ if (IS_ERR(ser))
+ return PTR_ERR(ser);
+
+ err = kho_block_add(bs, ser);
+ if (err) {
+ kho_block_free_ser(bs, ser);
+ return err;
+ }
+
+ return 0;
+}
+
+static void kho_block_set_shrink_one(struct kho_block_set *bs)
+{
+ struct kho_block *last, *new_last;
+
+ if (list_empty(&bs->blocks))
+ return;
+
+ last = list_last_entry(&bs->blocks, struct kho_block, list);
+ list_del(&last->list);
+ bs->nblocks--;
+ kho_block_free_ser(bs, last->ser);
+ kfree(last);
+
+ new_last = list_last_entry_or_null(&bs->blocks, struct kho_block, list);
+ if (new_last)
+ new_last->ser->next = 0;
+ else
+ bs->head_pa = 0;
+}
+
+/**
+ * kho_block_set_grow - Expand the block set to accommodate the target count.
+ * @bs: The block set.
+ * @count: The target number of valid entries to accommodate.
+ *
+ * Dynamically preallocates and links preserved memory blocks if the target
+ * entry count exceeds the current total capacity of the set, ensuring they
+ * are available during serialization/deserialization.
+ *
+ * Context: Caller must hold a lock protecting the block set.
+ * Return: 0 on success, or a negative errno on failure.
+ */
+int kho_block_set_grow(struct kho_block_set *bs, u64 count)
+{
+ long orig_nblocks = bs->nblocks;
+ int err;
+
+ if (WARN_ON_ONCE(bs->incoming))
+ return -EINVAL;
+
+ while (count > bs->nblocks * bs->count_per_block) {
+ err = kho_block_set_grow_one(bs);
+ if (err)
+ goto err_shrink;
+ }
+
+ return 0;
+
+err_shrink:
+ while (bs->nblocks > orig_nblocks)
+ kho_block_set_shrink_one(bs);
+ return err;
+}
+
+/**
+ * kho_block_set_shrink - Shrink the block set to accommodate the target count.
+ * @bs: The block set.
+ * @count: The target number of valid entries to accommodate.
+ *
+ * Releases and unallocates redundant preserved memory blocks. Checks if the
+ * last block in the set can be removed because the remaining entry count is
+ * fully accommodated by the preceding blocks.
+ *
+ * Note: It is the caller's responsibility to ensure that entries are removed
+ * in the reverse order of their insertion. Because shrinking destroys the last
+ * block in the set, removing entries in any other order would corrupt active
+ * data.
+ *
+ * Context: Caller must hold a lock protecting the block set.
+ */
+void kho_block_set_shrink(struct kho_block_set *bs, u64 count)
+{
+ while (bs->nblocks > 0 && count <= (bs->nblocks - 1) * bs->count_per_block)
+ kho_block_set_shrink_one(bs);
+}
+
+/*
+ * kho_block_set_is_cyclic - Check for cycles in a linked list of blocks.
+ * Uses Floyd's cycle-finding algorithm to ensure sanity of the incoming list.
+ *
+ * Return: true if a cycle or corruption is detected, false otherwise.
+ */
+static bool kho_block_set_is_cyclic(struct kho_block_set *bs)
+{
+ struct kho_block_header_ser *fast;
+ struct kho_block_header_ser *slow;
+ int count = 0;
+
+ fast = phys_to_virt(bs->head_pa);
+ slow = fast;
+
+ while (fast) {
+ if (count++ >= KHO_MAX_BLOCKS) {
+ pr_err("Block set is corrupted\n");
+ return true;
+ }
+
+ if (!fast->next)
+ break;
+
+ fast = phys_to_virt(fast->next);
+ if (!fast->next)
+ break;
+
+ fast = phys_to_virt(fast->next);
+ slow = phys_to_virt(slow->next);
+
+ if (slow == fast) {
+ pr_err("Block set is corrupted\n");
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * kho_block_set_restore - Restore a block set from a physical address.
+ * @bs: The block set to restore.
+ * @head_pa: Physical address of the first block header.
+ *
+ * Restores a serialized block set from a given physical address. The caller is
+ * responsible for ensuring that the block set @bs has been allocated and
+ * initialized prior to calling this function.
+ *
+ * Return: 0 on success, or a negative errno on failure.
+ */
+int kho_block_set_restore(struct kho_block_set *bs, u64 head_pa)
+{
+ struct kho_block_header_ser *ser;
+ u64 next_pa = head_pa;
+ int err;
+
+ /* Restored block sets use size from the previous kernel */
+ bs->incoming = true;
+ if (!head_pa)
+ return 0;
+
+ bs->head_pa = head_pa;
+ if (kho_block_set_is_cyclic(bs)) {
+ bs->head_pa = 0;
+ return -EINVAL;
+ }
+
+ while (next_pa) {
+ ser = phys_to_virt(next_pa);
+ if (!ser->count || ser->count > bs->count_per_block) {
+ pr_warn("Block contains invalid entry count: %llu\n",
+ ser->count);
+ err = -EINVAL;
+ goto err_destroy;
+ }
+ err = kho_block_add(bs, ser);
+ if (err)
+ goto err_destroy;
+ next_pa = ser->next;
+ }
+
+ return 0;
+
+err_destroy:
+ kho_block_set_destroy(bs);
+
+ /* Free the remaining un-restored blocks in the physical chain */
+ while (next_pa) {
+ struct kho_block_header_ser *next_ser = phys_to_virt(next_pa);
+
+ next_pa = next_ser->next;
+ kho_block_free_ser(bs, next_ser);
+ }
+ return err;
+}
+
+/**
+ * kho_block_set_destroy - Destroy all blocks in a block set.
+ * @bs: The block set.
+ */
+void kho_block_set_destroy(struct kho_block_set *bs)
+{
+ struct kho_block *block, *tmp;
+
+ list_for_each_entry_safe(block, tmp, &bs->blocks, list) {
+ list_del(&block->list);
+ kho_block_free_ser(bs, block->ser);
+ kfree(block);
+ }
+ bs->nblocks = 0;
+ bs->head_pa = 0;
+}
+
+/**
+ * kho_block_set_clear - Clear all serialized data in a block set.
+ * @bs: The block set to clear.
+ */
+void kho_block_set_clear(struct kho_block_set *bs)
+{
+ struct kho_block *block;
+
+ list_for_each_entry(block, &bs->blocks, list) {
+ block->ser->count = 0;
+ memset(block->ser + 1, 0, KHO_BLOCK_SIZE - sizeof(*block->ser));
+ }
+}
+
+/**
+ * kho_block_set_it_init - Initialize a block set iterator.
+ * @it: The iterator to initialize.
+ * @bs: The block set to iterate over.
+ */
+void kho_block_set_it_init(struct kho_block_set_it *it, struct kho_block_set *bs)
+{
+ it->bs = bs;
+ it->block = list_first_entry_or_null(&bs->blocks, struct kho_block, list);
+ it->i = 0;
+}
+
+/**
+ * kho_block_set_it_reserve_entry - Reserve and return the next available slot for writing.
+ * @it: The block iterator.
+ *
+ * Reserves a slot in the current block during state serialization to add a new
+ * entry, advancing the internal index. If the current block is full, it
+ * automatically moves to the next block in the set.
+ *
+ * Return: A pointer to the reserved entry slot, or NULL if the block set's
+ * capacity is fully exhausted.
+ */
+void *kho_block_set_it_reserve_entry(struct kho_block_set_it *it)
+{
+ void *entry;
+
+ if (!it->block)
+ return NULL;
+
+ if (it->i == it->bs->count_per_block) {
+ if (list_is_last(&it->block->list, &it->bs->blocks))
+ return NULL;
+ it->block = list_next_entry(it->block, list);
+ it->i = 0;
+ }
+
+ entry = kho_block_entry(it, it->i++);
+ it->block->ser->count = it->i;
+ return entry;
+}
+
+/**
+ * kho_block_set_it_read_entry - Read the next serialized entry from the block set.
+ * @it: The block iterator.
+ *
+ * Iterates through previously written entries during state deserialization,
+ * respecting the actual count stored in each block's header.
+ *
+ * Return: A pointer to the next serialized entry, or NULL if all serialized
+ * entries have been read.
+ */
+void *kho_block_set_it_read_entry(struct kho_block_set_it *it)
+{
+ if (!it->block)
+ return NULL;
+
+ if (it->i == it->block->ser->count) {
+ if (list_is_last(&it->block->list, &it->bs->blocks))
+ return NULL;
+ it->block = list_next_entry(it->block, list);
+ it->i = 0;
+ }
+
+ return kho_block_entry(it, it->i++);
+}
+
+/**
+ * kho_block_set_it_prev - Return the previous entry slot in the block set.
+ * @it: The block iterator.
+ *
+ * If the current index is at the start of a block, it automatically moves to
+ * the end of the previous block.
+ *
+ * Return: A pointer to the previous entry slot, or NULL if at the very
+ * beginning of the block set.
+ */
+void *kho_block_set_it_prev(struct kho_block_set_it *it)
+{
+ if (!it->block)
+ return NULL;
+
+ if (it->i == 0) {
+ if (list_is_first(&it->block->list, &it->bs->blocks))
+ return NULL;
+ it->block = list_prev_entry(it->block, list);
+ it->i = it->bs->count_per_block;
+ }
+
+ return kho_block_entry(it, --it->i);
+}
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v4 2/3] mm: rename swap.c to folio_lru.c
From: David Hildenbrand (Arm) @ 2026-06-03 13:09 UTC (permalink / raw)
To: Jianyue Wu, Andrew Morton, Chris Li, Kairui Song, Kemeng Shi,
Nhat Pham, Baoquan He, Barry Song, Youngjun Park, Qi Zheng,
Shakeel Butt, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Johannes Weiner, Michal Hocko, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Jonathan Corbet, Shuah Khan
Cc: linux-mm, linux-kernel, linux-doc
In-Reply-To: <20260603-ch-swap-series-plus-folio-lru-cleanup-v4-2-ce0219e100d9@gmail.com>
On 6/3/26 15:05, Jianyue Wu wrote:
> Rename mm/swap.c to mm/folio_lru.c so the filename better matches
> the code's main responsibility.
>
> This keeps the implementation split from swap-specific code without
> changing the published LRU helper interfaces.
>
> Update MAINTAINERS and the remaining mm/swap.c documentation references
> after the rename.
>
> Suggested-by: Baoquan He <bhe@redhat.com>
> Suggested-by: David Hildenbrand <david@kernel.org>
> Signed-off-by: Jianyue Wu <wujianyue000@gmail.com>
> ---
We can later decide to rename it to folio.c But maybe it makes sense to keep
this LRU batching magic in its own file.
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply
* Re: [PATCH v4 1/3] mm/swap: colocate page-cluster sysctl with swap readahead
From: David Hildenbrand (Arm) @ 2026-06-03 13:10 UTC (permalink / raw)
To: Jianyue Wu, Andrew Morton, Chris Li, Kairui Song, Kemeng Shi,
Nhat Pham, Baoquan He, Barry Song, Youngjun Park, Qi Zheng,
Shakeel Butt, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Johannes Weiner, Michal Hocko, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Jonathan Corbet, Shuah Khan
Cc: linux-mm, linux-kernel, linux-doc
In-Reply-To: <20260603-ch-swap-series-plus-folio-lru-cleanup-v4-1-ce0219e100d9@gmail.com>
On 6/3/26 15:05, Jianyue Wu wrote:
> page_cluster and the vm.page-cluster sysctl are only used by swap-in
> readahead in swap_state.c. Move them out of swap.c together with
> swap_readahead_setup(), and make page_cluster static to that file.
>
> Rename swap_setup() while moving it as well. The helper is internal to
> MM and now only sets up swap readahead defaults and its sysctl hook, so
> the more specific name matches its reduced scope.
>
> swap_setup() previously lived in mm/swap.c, which is built
> unconditionally, so the vm.page-cluster sysctl was registered also on
> CONFIG_SWAP=n kernels. swap_readahead_setup() is now a no-op stub when
> CONFIG_SWAP is disabled, so vm.page-cluster is no longer registered
> there. The knob only tunes swap-in readahead and had no effect without
> swap.
>
> Suggested-by: Baoquan He <bhe@redhat.com>
> Suggested-by: Barry Song <baohua@kernel.org>
> Signed-off-by: Jianyue Wu <wujianyue000@gmail.com>
> ---
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply
* Re: [PATCH v2 05/18] perf test: Add deterministic workload
From: James Clark @ 2026-06-03 13:10 UTC (permalink / raw)
To: Leo Yan
Cc: Suzuki K Poulose, Mike Leach, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis, coresight, linux-perf-users,
linux-kernel, Arnaldo Carvalho de Melo, linux-doc
In-Reply-To: <20260603112742.GT101133@e132581.arm.com>
On 03/06/2026 12:27 pm, Leo Yan wrote:
> On Tue, Jun 02, 2026 at 03:26:47PM +0100, James Clark wrote:
>
> [...]
>
>> @@ -22,3 +23,4 @@ CFLAGS_brstack.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
>> CFLAGS_datasym.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
>> CFLAGS_traploop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
>> CFLAGS_inlineloop.o = -g -O2
>> +CFLAGS_deterministic.o = -g -O0
>
> I have no strong opinion for using 'noinline' in source or using the
> global option '-fno-inline', just thought this is not easy to follow
> up if anyone (likely myself) will write a new workload for disabling
> inline. Could we have consistent style for this?
>
> For the patch itself:
>
> Reviewed-by: Leo Yan <leo.yan@arm.com>
Actually it's a fair question why some have -fno-inline and others do it
in the code, it could just be copied from when these were built by their
shell script tests. From a quick look I would say we can easily drop the
-fno-inline and do it in the code, and it's better to only noinline
what's needed rather than everything. But that's probably a change for
another time.
That leaves the only custom build options as the ones that force -O0
(which also requires U_FORTIFY_SOURCE), or force -O2.
^ permalink raw reply
* [PATCH v2] hwmon: add a driver for the temp/voltage sensor on PolarFire SoC
From: Conor Dooley @ 2026-06-03 13:19 UTC (permalink / raw)
To: linux-hwmon
Cc: conor, Lars Randers, Conor Dooley, Guenter Roeck, Jonathan Corbet,
Shuah Khan, Daire McNamara, linux-doc, linux-kernel, linux-riscv,
Valentina.FernandezAlanis
From: Lars Randers <lranders@mail.dk>
Add a driver for the temperature and voltage sensors on PolarFire SoC.
The temperature reports how hot the die is, and the voltages are the
SoC's 1.05, 1.8 and 2.5 volt rails respectively.
The hardware supports alarms in theory, but there is an erratum that
prevents clearing them once triggered, so no support is added for them.
The hardware measures voltage with 16 bits, of which 1 is a sign bit and
the remainder holds the voltage as a fixed point integer value. It's
improbable that the hardware will work if the voltages are negative, so
the driver ignores the sign bits.
There's no dt support etc here because this is the child of a simple-mfd
syscon.
Signed-off-by: Lars Randers <lranders@mail.dk>
Co-developed-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
---
v2:
- Fix some minor things pointed out by Sashiko including inaccurate
comments, bounds checking of values read from sysfs and Kconfig
dependencies.
- Make update_interval use milliseconds instead of microseconds
(I'll add update_interval_us support when that lands, there's a
proposed workaround for the erratum circulating internally, so it'll
probably come alongside alarm support).
CC: Guenter Roeck <linux@roeck-us.net>
CC: Jonathan Corbet <corbet@lwn.net>
CC: Shuah Khan <skhan@linuxfoundation.org>
CC: Conor Dooley <conor.dooley@microchip.com>
CC: Daire McNamara <daire.mcnamara@microchip.com>
CC: linux-hwmon@vger.kernel.org
CC: linux-doc@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: linux-riscv@lists.infradead.org
CC: Valentina.FernandezAlanis@microchip.com
---
Documentation/hwmon/index.rst | 1 +
Documentation/hwmon/tvs-mpfs.rst | 53 +++++
MAINTAINERS | 1 +
drivers/hwmon/Kconfig | 13 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/tvs-mpfs.c | 394 +++++++++++++++++++++++++++++++
6 files changed, 463 insertions(+)
create mode 100644 Documentation/hwmon/tvs-mpfs.rst
create mode 100644 drivers/hwmon/tvs-mpfs.c
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 8b655e5d6b68..84a5339e1d6f 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -262,6 +262,7 @@ Hardware Monitoring Kernel Drivers
tps53679
tps546d24
tsc1641
+ tvs-mpfs
twl4030-madc-hwmon
ucd9000
ucd9200
diff --git a/Documentation/hwmon/tvs-mpfs.rst b/Documentation/hwmon/tvs-mpfs.rst
new file mode 100644
index 000000000000..ff445844d07c
--- /dev/null
+++ b/Documentation/hwmon/tvs-mpfs.rst
@@ -0,0 +1,53 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver tvs-mpfs
+======================
+
+Supported chips:
+
+ * PolarFire SoC
+
+Authors:
+
+ - Conor Dooley <conor.dooley@microchip.com>
+ - Lars Randers <lranders@mail.dk>
+
+Description
+-----------
+
+This driver implements support for the temperature and voltage sensors on
+PolarFire SoC. The temperature reports how hot the die is, and the voltages are
+the SoC's 1.05, 1.8 and 2.5 volt rails respectively.
+
+
+Usage Notes
+-----------
+
+update_interval has a permitted range of 0 to 8.
+
+Temperatures are read in millidegrees Celsius, but the hardware measures in
+degrees Kelvin, storing the result as 11.4 fixed point data, for a maximum
+value of 2047.9375 degrees Kelvin.
+
+Voltages are read in millivolts. The hardware measures in millivolts, storing
+the value as 12.3 fixed point data, for a maximum of 4095.875 millivolts.
+The minimum value reportable by the driver is 0 volts, although the hardware
+is capable of measuring negative values.
+
+Sysfs entries
+-------------
+
+The following attributes are supported. update_interval is read-write, as are
+the enables. All other attributes are read only.
+
+======================= ====================================================
+temp1_label Fixed name for channel.
+temp1_input Measured temperature for channel.
+temp1_enable Enable/disable for channel.
+
+in[0-2]_label Fixed name for channel.
+in[0-2]_input Measured voltage for channel.
+in[0-2]_enable Enable/disable for channel.
+
+update_interval The interval at which the chip will update readings.
+======================= ====================================================
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..a492cf5ad0fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22938,6 +22938,7 @@ F: drivers/char/hw_random/mpfs-rng.c
F: drivers/clk/microchip/clk-mpfs*.c
F: drivers/firmware/microchip/mpfs-auto-update.c
F: drivers/gpio/gpio-mpfs.c
+F: drivers/hwmon/tvs-mpfs.c
F: drivers/i2c/busses/i2c-microchip-corei2c.c
F: drivers/mailbox/mailbox-mpfs.c
F: drivers/pci/controller/plda/pcie-microchip-host.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 14e4cea48acc..2b9622b1db95 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -930,6 +930,19 @@ config SENSORS_JC42
This driver can also be built as a module. If so, the module
will be called jc42.
+config SENSORS_POLARFIRE_SOC_TVS
+ tristate "PolarFire SoC (MPFS) temperature and voltage sensor"
+ depends on POLARFIRE_SOC_SYSCONS || COMPILE_TEST
+ depends on MFD_SYSCON
+ help
+ This driver adds support for the PolarFire SoC (MPFS) Temperature and
+ Voltage Sensor.
+
+ To compile this driver as a module, choose M here. the
+ module will be called tvs-mpfs.
+
+ If unsure, say N.
+
config SENSORS_POWERZ
tristate "ChargerLAB POWER-Z USB-C tester"
depends on USB
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4788996aa137..b58d249e4cf4 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -194,6 +194,7 @@ obj-$(CONFIG_SENSORS_NZXT_SMART2) += nzxt-smart2.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+obj-$(CONFIG_SENSORS_POLARFIRE_SOC_TVS) += tvs-mpfs.o
obj-$(CONFIG_SENSORS_POWERZ) += powerz.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PT5161L) += pt5161l.o
diff --git a/drivers/hwmon/tvs-mpfs.c b/drivers/hwmon/tvs-mpfs.c
new file mode 100644
index 000000000000..f086f178b4ba
--- /dev/null
+++ b/drivers/hwmon/tvs-mpfs.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Author: Lars Randers <lranders@mail.dk>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/freezer.h>
+#include <linux/hwmon.h>
+#include <linux/io.h>
+#include <linux/kthread.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MPFS_TVS_CTRL 0x08
+#define MPFS_TVS_OUTPUT0 0x24
+#define MPFS_TVS_OUTPUT1 0x28
+
+#define MPFS_TVS_CTRL_TEMP_VALID BIT(19)
+#define MPFS_TVS_CTRL_V2P5_VALID BIT(18)
+#define MPFS_TVS_CTRL_V1P8_VALID BIT(17)
+#define MPFS_TVS_CTRL_V1P05_VALID BIT(16)
+
+#define MPFS_TVS_CTRL_TEMP_ENABLE BIT(3)
+#define MPFS_TVS_CTRL_V2P5_ENABLE BIT(2)
+#define MPFS_TVS_CTRL_V1P8_ENABLE BIT(1)
+#define MPFS_TVS_CTRL_V1P05_ENABLE BIT(0)
+#define MPFS_TVS_CTRL_ENABLE_ALL GENMASK(3, 0)
+
+/*
+ * For all of these the value in millivolts is stored in 16 bits, with an upper
+ * sign bit and a lower 3 bits of decimal. These masks discard the sign bit and
+ * decimal places, because if Linux is running these voltages cannot be negative
+ * and so avoid having to convert to two's complement.
+ */
+#define MPFS_OUTPUT0_V1P8_MASK GENMASK(30, 19)
+#define MPFS_OUTPUT0_V1P05_MASK GENMASK(14, 3)
+#define MPFS_OUTPUT1_V2P5_MASK GENMASK(14, 3)
+
+/*
+ * The register map claims that the temperature is stored in bits 31:16, but
+ * application note "AN4682: PolarFire FPGA Temperature and Voltage Sensor"
+ * says that 31 is reserved. Temperature is in kelvin, so what's probably a
+ * sign bit has no value anyway.
+ */
+#define MPFS_OUTPUT1_TEMP_MASK GENMASK(30, 16)
+
+#define MPFS_TVS_INTERVAL_MASK GENMASK(15, 8)
+#define MPFS_TVS_INTERVAL_OFFSET 8
+/* The interval register is in increments of 32 us */
+#define MPFS_TVS_INTERVAL_SCALE 32
+
+/* 273.1875 in 11.4 fixed-point notation */
+#define MPFS_TVS_K_TO_C 0x1113
+
+enum mpfs_tvs_sensors {
+ SENSOR_V1P05 = 0,
+ SENSOR_V1P8,
+ SENSOR_V2P5,
+};
+
+static const char * const mpfs_tvs_voltage_labels[] = { "1P05", "1P8", "2P5" };
+
+struct mpfs_tvs {
+ struct regmap *regmap;
+};
+
+static int mpfs_tvs_voltage_read(struct mpfs_tvs *data, u32 attr,
+ int channel, long *val)
+{
+ u32 tmp, control;
+
+ if (attr != hwmon_in_input && attr != hwmon_in_enable)
+ return -EOPNOTSUPP;
+
+ regmap_read(data->regmap, MPFS_TVS_CTRL, &control);
+
+ switch (channel) {
+ case SENSOR_V2P5:
+ if (attr == hwmon_in_enable) {
+ *val = FIELD_GET(MPFS_TVS_CTRL_V2P5_ENABLE, control);
+ break;
+ }
+
+ if (!(control & MPFS_TVS_CTRL_V2P5_VALID))
+ return -EINVAL;
+
+ regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp);
+ *val = FIELD_GET(MPFS_OUTPUT1_V2P5_MASK, tmp);
+ break;
+ case SENSOR_V1P8:
+ if (attr == hwmon_in_enable) {
+ *val = FIELD_GET(MPFS_TVS_CTRL_V1P8_ENABLE, control);
+ break;
+ }
+
+ if (!(control & MPFS_TVS_CTRL_V1P8_VALID))
+ return -EINVAL;
+
+ regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp);
+ *val = FIELD_GET(MPFS_OUTPUT0_V1P8_MASK, tmp);
+ break;
+ case SENSOR_V1P05:
+ if (attr == hwmon_in_enable) {
+ *val = FIELD_GET(MPFS_TVS_CTRL_V1P05_ENABLE, control);
+ break;
+ }
+
+ if (!(control & MPFS_TVS_CTRL_V1P05_VALID))
+ return -EINVAL;
+
+ regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp);
+ *val = FIELD_GET(MPFS_OUTPUT0_V1P05_MASK, tmp);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int mpfs_tvs_voltage_write(struct mpfs_tvs *data, u32 attr,
+ int channel, long val)
+{
+ u32 tmp;
+
+ if (attr != hwmon_in_enable)
+ return -EOPNOTSUPP;
+
+ switch (channel) {
+ case SENSOR_V2P5:
+ if (val > 1 || val < 0)
+ return -EINVAL;
+
+ tmp = FIELD_PREP(MPFS_TVS_CTRL_V2P5_ENABLE, val);
+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+ MPFS_TVS_CTRL_V2P5_ENABLE, tmp);
+ break;
+ case SENSOR_V1P8:
+ if (val > 1 || val < 0)
+ return -EINVAL;
+
+ tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P8_ENABLE, val);
+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+ MPFS_TVS_CTRL_V1P8_ENABLE, tmp);
+ break;
+ case SENSOR_V1P05:
+ if (val > 1 || val < 0)
+ return -EINVAL;
+
+ tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P05_ENABLE, val);
+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+ MPFS_TVS_CTRL_V1P05_ENABLE, tmp);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int mpfs_tvs_temp_read(struct mpfs_tvs *data, u32 attr, long *val)
+{
+ u32 tmp, control;
+
+ if (attr != hwmon_temp_input && attr != hwmon_temp_enable)
+ return -EOPNOTSUPP;
+
+ regmap_read(data->regmap, MPFS_TVS_CTRL, &control);
+
+ if (attr == hwmon_temp_enable) {
+ *val = FIELD_GET(MPFS_TVS_CTRL_TEMP_ENABLE, control);
+ return 0;
+ }
+
+ if (!(control & MPFS_TVS_CTRL_TEMP_VALID))
+ return -EINVAL;
+
+ regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp);
+ *val = FIELD_GET(MPFS_OUTPUT1_TEMP_MASK, tmp);
+ *val -= MPFS_TVS_K_TO_C;
+ *val = (1000 * *val) >> 4; /* fixed point (11.4) to millidegrees */
+
+ return 0;
+}
+
+static int mpfs_tvs_temp_write(struct mpfs_tvs *data, u32 attr, long val)
+{
+ u32 tmp;
+
+ if (attr != hwmon_temp_enable)
+ return -EOPNOTSUPP;
+
+ if (val > 1 || val < 0)
+ return -EINVAL;
+
+ tmp = FIELD_PREP(MPFS_TVS_CTRL_TEMP_ENABLE, val);
+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+ MPFS_TVS_CTRL_TEMP_ENABLE, tmp);
+
+ return 0;
+}
+
+static int mpfs_tvs_interval_read(struct mpfs_tvs *data, u32 attr, long *val)
+{
+ u32 tmp;
+
+ if (attr != hwmon_chip_update_interval)
+ return -EOPNOTSUPP;
+
+ regmap_read(data->regmap, MPFS_TVS_CTRL, &tmp);
+ *val = FIELD_GET(MPFS_TVS_INTERVAL_MASK, tmp);
+ *val *= MPFS_TVS_INTERVAL_SCALE;
+ *val /= 1000;
+
+ return 0;
+}
+
+static int mpfs_tvs_interval_write(struct mpfs_tvs *data, u32 attr, long val)
+{
+ unsigned long temp = val;
+
+ if (attr != hwmon_chip_update_interval)
+ return -EOPNOTSUPP;
+
+ temp *= 1000;
+ temp /= MPFS_TVS_INTERVAL_SCALE;
+
+ /*
+ * The value is 8 bits wide, but 255 is described as
+ * "255= Do single set of transfers when scoverride set"
+ * but there's no scoverride bit in the tvs register region.
+ * Ban using 255 since its behaviour is suspect.
+ */
+ if (temp > 254)
+ return -EINVAL;
+
+ temp <<= MPFS_TVS_INTERVAL_OFFSET;
+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+ MPFS_TVS_INTERVAL_MASK, temp);
+
+ return 0;
+}
+
+static umode_t mpfs_tvs_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ if (type == hwmon_chip && attr == hwmon_chip_update_interval)
+ return 0644;
+
+ if (type == hwmon_temp) {
+ switch (attr) {
+ case hwmon_temp_enable:
+ return 0644;
+ case hwmon_temp_input:
+ case hwmon_temp_label:
+ return 0444;
+ default:
+ return 0;
+ }
+ }
+
+ if (type == hwmon_in) {
+ switch (attr) {
+ case hwmon_in_enable:
+ return 0644;
+ case hwmon_in_input:
+ case hwmon_in_label:
+ return 0444;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int mpfs_tvs_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct mpfs_tvs *data = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_temp:
+ return mpfs_tvs_temp_read(data, attr, val);
+ case hwmon_in:
+ return mpfs_tvs_voltage_read(data, attr, channel, val);
+ case hwmon_chip:
+ return mpfs_tvs_interval_read(data, attr, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int mpfs_tvs_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ struct mpfs_tvs *data = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_temp:
+ return mpfs_tvs_temp_write(data, attr, val);
+ case hwmon_in:
+ return mpfs_tvs_voltage_write(data, attr, channel, val);
+ case hwmon_chip:
+ return mpfs_tvs_interval_write(data, attr, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int mpfs_tvs_read_labels(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel,
+ const char **str)
+{
+ switch (type) {
+ case hwmon_temp:
+ *str = "Die Temp";
+ return 0;
+ case hwmon_in:
+ *str = mpfs_tvs_voltage_labels[channel];
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct hwmon_ops mpfs_tvs_ops = {
+ .is_visible = mpfs_tvs_is_visible,
+ .read_string = mpfs_tvs_read_labels,
+ .read = mpfs_tvs_read,
+ .write = mpfs_tvs_write,
+};
+
+static const struct hwmon_channel_info *mpfs_tvs_info[] = {
+ HWMON_CHANNEL_INFO(chip,
+ HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_ENABLE),
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE,
+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE,
+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE),
+ NULL
+};
+
+static const struct hwmon_chip_info mpfs_tvs_chip_info = {
+ .ops = &mpfs_tvs_ops,
+ .info = mpfs_tvs_info,
+};
+
+static int mpfs_tvs_probe(struct platform_device *pdev)
+{
+ struct device *hwmon_dev;
+ struct mpfs_tvs *data;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->regmap = device_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(data->regmap),
+ "Failed to find syscon regmap\n");
+
+ regmap_write(data->regmap, MPFS_TVS_CTRL, MPFS_TVS_CTRL_ENABLE_ALL);
+
+ hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "mpfs_tvs",
+ data,
+ &mpfs_tvs_chip_info,
+ NULL);
+ if (IS_ERR(hwmon_dev))
+ return dev_err_probe(&pdev->dev, PTR_ERR(hwmon_dev),
+ "hwmon device registration failed.\n");
+
+ return 0;
+}
+
+static struct platform_driver mpfs_tvs_driver = {
+ .probe = mpfs_tvs_probe,
+ .driver = {
+ .name = "mpfs-tvs",
+ },
+};
+module_platform_driver(mpfs_tvs_driver);
+
+MODULE_AUTHOR("Lars Randers <lranders@mail.dk>");
+MODULE_DESCRIPTION("PolarFire SoC temperature & voltage sensor driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v6 07/13] kho: add support for linked-block serialization
From: Pasha Tatashin @ 2026-06-03 13:21 UTC (permalink / raw)
To: Mike Rapoport
Cc: Pasha Tatashin, linux-kselftest, shuah, akpm, linux-mm, skhan,
linux-doc, linux-kernel, corbet, dmatlack, kexec, pratyush,
skhawaja, graf
In-Reply-To: <aiANtYRRDr5iO5QR@plex>
On 06-03 12:05, Pasha Tatashin wrote:
> On 06-03 09:49, Mike Rapoport wrote:
> > On Wed, 03 Jun 2026 03:28:58 +0000, Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
> > > diff --git a/include/linux/kho/abi/block.h b/include/linux/kho/abi/block.h
> > > new file mode 100644
> > > index 000000000000..8641c20b379b
> > > --- /dev/null
> > > +++ b/include/linux/kho/abi/block.h
> > > @@ -0,0 +1,56 @@
> > > [ ... skip 25 lines ... ]
> > > +#define _LINUX_KHO_ABI_BLOCK_H
> > > +
> > > +#include <asm/page.h>
> > > +#include <linux/types.h>
> > > +
> > > +#define KHO_BLOCK_ABI_COMPATIBLE "kho-block-v1"
> >
> > It's never used by block set and after looking at the following patches I
> > found that it's appended to LUO compatible string.
> >
> > While this works for LUO, I think it should be kho_block_set_restore()
> > responsibility to verify the compatibility.
>
> It should work for any component that relies on kho_block. My proposal
> is to use this method for other common KHO data structures (e.g., kho
> vmalloc, kho radix, future kho xarray). There is no need for them to
> carry the compatibility string in their metadata, as whoever uses them
> will include their compatibility string.
>
> For now, reviewers will have to make sure that if the ABI header content
> is changed, the compatibility string is updated.
>
> > > diff --git a/kernel/liveupdate/kho_block.c b/kernel/liveupdate/kho_block.c
> > > new file mode 100644
> > > index 000000000000..4f147c308e6b
> > > --- /dev/null
> > > +++ b/kernel/liveupdate/kho_block.c
> > > @@ -0,0 +1,411 @@
> > > [ ... skip 121 lines ... ]
> > > +/**
> > > + * kho_block_set_grow - Expand the block set to accommodate the target count.
> > > + * @bs: The block set.
> > > + * @count: The target number of valid entries to accommodate.
> > > + *
> > > + * Acts as a runtime notifier when new resources (such as files or sessions)
> >
> > Not sure I understand what "runtime notifier" means in this context.
>
> It came from discussion with Pratyush, but I think we are on the same
> page what they are, and I will just remove this.
>
> >
> > > [ ... skip 11 lines ... ]
> > > +
> > > + while (count > bs->nblocks * bs->count_per_block) {
> > > + int err = kho_block_set_grow_one(bs);
> > > +
> > > + if (err)
> > > + return err;
> >
> > This leaks memory if more than one block is added.
> >
> > > [ ... skip 31 lines ... ]
> > > + * unregistered, allowing the block set to release and unallocate redundant
> > > + * preserved memory blocks. Checks if the last block in the set can be removed
> > > + * because the remaining entry count is fully accommodated by the preceding blocks.
> > > + *
> > > + * Note: It is the caller's responsibility to ensure that entries are removed
> > > + * in LIFO (last-in, first-out) order (the reverse order of their insertion).
> >
> > I think "in LIFO order" is sufficient :)
>
> Oh, I keep removing those :-)
>
> > > [ ... skip 173 lines ... ]
> > > + it->i = 0;
> > > + }
> > > +
> > > + entry = kho_block_entry(it, it->i++);
> > > + it->block->ser->count = it->i;
> > > + return entry;
> >
> > This looks way better than the previous version :)
> > Thanks!
>
> Thank you. I will send a new version of this patch as a reply to this
> email to avoid cluttering the mailing list.
The patch is here:
https://lore.kernel.org/all/20260603130612.397948-1-pasha.tatashin@soleen.com/
I messed up in-reply-to field with wrong message-id.
Pasha
>
> Pasha
>
> >
> > --
> > Sincerely yours,
> > Mike.
> >
^ permalink raw reply
* Re: [PATCH 04/15] accel/qda: Add compute bus for QDA context banks
From: Dmitry Baryshkov @ 2026-06-03 13:25 UTC (permalink / raw)
To: Ekansh Gupta
Cc: Oded Gabbay, Jonathan Corbet, Shuah Khan, Joerg Roedel,
Will Deacon, Robin Murphy, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Sumit Semwal,
Christian König, Bharath Kumar, Chenna Kesava Raju, srini,
andersson, konradybcio, robin.clark, linux-kernel, dri-devel,
linux-doc, linux-arm-msm, iommu, linux-media, linaro-mm-sig
In-Reply-To: <587b450c-c527-4c6a-b48b-8a7a266bd673@oss.qualcomm.com>
On Wed, Jun 03, 2026 at 10:58:09AM +0530, Ekansh Gupta wrote:
> On 20-05-2026 19:49, Dmitry Baryshkov wrote:
> > On Tue, May 19, 2026 at 11:45:54AM +0530, Ekansh Gupta via B4 Relay wrote:
> >> From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
> >>
> >> Introduce a custom virtual bus (qda-compute-cb) for managing IOMMU
> >> context bank (CB) devices used by the QDA driver.
> >>
> >> IOMMU context banks are synthetic constructs — they are not real
> >> platform devices and do not appear as children of a platform bus node
> >> in the device tree. Using a platform driver to represent them was
> >> therefore incorrect and introduced a probe-ordering race: device nodes
> >> were created before the RPMsg channel resources were fully initialized,
> >> and because probe runs asynchronously, user-space could open a CB
> >> device and attempt to start a session before the underlying transport
> >> was ready.
> >>
> >> The qda-compute-cb bus solves this by allowing the main QDA driver to
> >> create CB devices explicitly and under its own control, making their
> >> lifetime strictly subordinate to the parent qda_dev. The bus provides
> >> a dma_configure callback that calls of_dma_configure() so that each CB
> >> device gets its own IOMMU domain derived from its device-tree node,
> >> enabling per-session memory isolation.
> >>
> >> The bus type and the CB device constructor (create_qda_cb_device) are
> >> exported for use by the QDA memory manager.
> >>
> >> A hidden Kconfig symbol (DRM_ACCEL_QDA_COMPUTE_BUS) is introduced and
> >> automatically selected by DRM_ACCEL_QDA so that the bus initialisation
> >> runs via postcore_initcall before any QDA device probes.
> >>
> >> Assisted-by: Claude:claude-4-6-sonnet
> >> Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
> >> ---
> >> drivers/accel/Makefile | 1 +
> >> drivers/accel/qda/Kconfig | 4 +++
> >> drivers/accel/qda/Makefile | 2 ++
> >> drivers/accel/qda/qda_compute_bus.c | 68 +++++++++++++++++++++++++++++++++++++
> >> include/linux/qda_compute_bus.h | 32 +++++++++++++++++
> >> 5 files changed, 107 insertions(+)
> >>
> >> diff --git a/drivers/accel/Makefile b/drivers/accel/Makefile
> >> index 58c08dd5f389..9ed843cd293f 100644
> >> --- a/drivers/accel/Makefile
> >> +++ b/drivers/accel/Makefile
> >> @@ -6,4 +6,5 @@ obj-$(CONFIG_DRM_ACCEL_HABANALABS) += habanalabs/
> >> obj-$(CONFIG_DRM_ACCEL_IVPU) += ivpu/
> >> obj-$(CONFIG_DRM_ACCEL_QAIC) += qaic/
> >> obj-$(CONFIG_DRM_ACCEL_QDA) += qda/
> >> +obj-$(CONFIG_DRM_ACCEL_QDA_COMPUTE_BUS) += qda/
> >
> > Ugh. The previous line should be enough (but don't trust me).
> I was seeing build failures if I don't add this. Took it as a reference
> from host1x driver and recent iris patch.>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 06/15] accel/qda: Create compute context bank devices on QDA compute bus
From: Dmitry Baryshkov @ 2026-06-03 13:26 UTC (permalink / raw)
To: Ekansh Gupta
Cc: Oded Gabbay, Jonathan Corbet, Shuah Khan, Joerg Roedel,
Will Deacon, Robin Murphy, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Sumit Semwal,
Christian König, Bharath Kumar, Chenna Kesava Raju, srini,
andersson, konradybcio, robin.clark, linux-kernel, dri-devel,
linux-doc, linux-arm-msm, iommu, linux-media, linaro-mm-sig
In-Reply-To: <37ae68ba-6639-4bd2-9483-5aa0156fd772@oss.qualcomm.com>
On Wed, Jun 03, 2026 at 11:09:31AM +0530, Ekansh Gupta wrote:
> On 20-05-2026 19:53, Dmitry Baryshkov wrote:
> > On Tue, May 19, 2026 at 11:45:56AM +0530, Ekansh Gupta via B4 Relay wrote:
> >> From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
> >>
> >> Introduce the CB (compute context bank) device management layer for the
> >> QDA driver. Each DSP domain node in the device tree may contain child
> >> nodes with compatible "qcom,fastrpc-compute-cb", each representing one
> >> IOMMU context bank. The driver enumerates those child nodes during
> >> RPMsg probe and creates a corresponding device on the qda-compute-cb
> >> bus for each one.
> >>
> >> The CB devices are created via create_qda_cb_device(), which registers
> >> them on the qda-compute-cb bus so that the IOMMU subsystem assigns each
> >> device its own IOMMU domain, enabling per-session address space
> >> isolation for DSP buffer mapping.
> >>
> >> The new qda_cb.c file provides two functions:
> >>
> >> qda_create_cb_device()
> >> Reads the "reg" property from the DT child node to obtain the
> >> stream ID, constructs a unique device name of the form
> >> "qda-cb-<dsp>-<sid>", and registers the device on the compute bus.
> >> A qda_cb_dev entry is allocated and appended to qdev->cb_devs so
> >> that the list can be walked during teardown.
> >>
> >> qda_destroy_cb_device()
> >> Removes the device from its IOMMU group before calling
> >> device_unregister(), ensuring the IOMMU domain is released cleanly.
> >>
> >> CB devices are populated before the DRM device is registered and
> >> destroyed before it is unplugged, so no DRM operation can race with
> >> CB teardown. On probe failure after population, qda_cb_unpopulate()
> >> is called to clean up any CBs that were successfully created before
> >> the error.
> >>
> >> Assisted-by: Claude:claude-4-6-sonnet
> >> Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
> >> ---
> >> drivers/accel/qda/Makefile | 1 +
> >> drivers/accel/qda/qda_cb.c | 99 +++++++++++++++++++++++++++++++++++++++++++
> >> drivers/accel/qda/qda_cb.h | 32 ++++++++++++++
> >> drivers/accel/qda/qda_drv.c | 1 +
> >> drivers/accel/qda/qda_drv.h | 3 ++
> >> drivers/accel/qda/qda_rpmsg.c | 12 +++++-
> >> 6 files changed, 147 insertions(+), 1 deletion(-)
> >> @@ -59,9 +61,17 @@ static int qda_rpmsg_probe(struct rpmsg_device *rpdev)
> >> }
> >> qdev->dsp_name = label;
> >>
> >> + ret = qda_cb_populate(qdev, rpdev->dev.of_node);
> >> + if (ret) {
> >> + dev_err(qdev->dev, "Failed to populate child devices: %d\n", ret);
> >> + return ret;
> >> + }
> >> +
> >> ret = qda_register_device(qdev);
> >> - if (ret)
> >> + if (ret) {
> >> + qda_cb_unpopulate(qdev);
> >> return ret;
> >
> > Unwinding registration?
> did I miss something here? The intention to free up the CB devices in
> case the device registration fails.>
Don't you need to unwind anything else?
> >> + }
> >>
> >> drm_info(&qdev->drm_dev, "QDA RPMsg probe complete for %s\n", qdev->dsp_name);
> >> return 0;
> >>
> >> --
> >> 2.34.1
> >>
> >>
> >
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH v6 04/13] liveupdate: register luo_ser as KHO subtree
From: Mike Rapoport @ 2026-06-03 13:31 UTC (permalink / raw)
To: Pasha Tatashin
Cc: linux-kselftest, rppt, shuah, akpm, linux-mm, skhan, linux-doc,
linux-kernel, corbet, dmatlack, kexec, pratyush, skhawaja, graf
In-Reply-To: <20260603032905.344462-5-pasha.tatashin@soleen.com>
On Wed, 03 Jun 2026 03:28:55 +0000, Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
> Entirely remove the LUO FDT wrapper since the FDT only carries the
> compatible string and the pointer to the centralized struct luo_ser.
> Instead, register the struct luo_ser via the KHO raw subtree
> API, placing the compatibility string inside the structure itself.
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
--
Sincerely yours,
Mike.
^ permalink raw reply
* Re: [PATCH v2] cpufreq: Documentation: fix freq_step description
From: Zhongqiu Han @ 2026-06-03 13:31 UTC (permalink / raw)
To: Pengjie Zhang, rafael, viresh.kumar, corbet, skhan
Cc: linux-pm, linux-doc, linux-kernel, linuxarm, zhanjie9, prime.zeng,
wanghuiqiang, xuwei5, lihuisong, zhenglifeng1, yubowen8,
wangzhi12, zhongqiu.han
In-Reply-To: <20260603055635.1549943-1-zhangpengjie2@huawei.com>
On 6/3/2026 1:56 PM, Pengjie Zhang wrote:
> The conservative governor documentation incorrectly states that setting
> freq_step to 0 will use the default 5% frequency step. In reality, since
> at least commit 8e677ce83bf4 ("[CPUFREQ] conservative: fixup governor to
> function more like ondemand logic"), freq_step=0 has always caused the
> governor to skip frequency updates entirely.
>
> Correct the documentation to reflect the actual behavior: freq_step=0
> disables frequency changes by the governor entirely.
>
> Fixes: 2a0e49279850 ("cpufreq: User/admin documentation update and consolidation")
> Signed-off-by: Pengjie Zhang <zhangpengjie2@huawei.com>
> ---
> Changes in v2:
> - Update commit message to reference the correct historical commit
> 8e677ce83bf4 instead of b9170836d1aa, as the original implementation
> had asymmetric behavior for freq_step=0 (suggested by Zhongqiu Han).
> - Link to v1:https://lore.kernel.org/all/20260529111122.3321645-1-zhangpengjie2@huawei.com/
Looks good to me.
Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
> ---
> Documentation/admin-guide/pm/cpufreq.rst | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/admin-guide/pm/cpufreq.rst b/Documentation/admin-guide/pm/cpufreq.rst
> index dbe6d23a5d67..98c724d49047 100644
> --- a/Documentation/admin-guide/pm/cpufreq.rst
> +++ b/Documentation/admin-guide/pm/cpufreq.rst
> @@ -586,8 +586,8 @@ This governor exposes the following tunables:
> 100 (5 by default).
>
> This is how much the frequency is allowed to change in one go. Setting
> - it to 0 will cause the default frequency step (5 percent) to be used
> - and setting it to 100 effectively causes the governor to periodically
> + it to 0 disables frequency changes by the governor entirely and setting
> + it to 100 effectively causes the governor to periodically
> switch the frequency between the ``scaling_min_freq`` and
> ``scaling_max_freq`` policy limits.
>
--
Thx and BRs,
Zhongqiu Han
^ permalink raw reply
* Re: [PATCH 2/3] AF_ALG: Drop support for off-CPU cryptography
From: Harald Freudenberger @ 2026-06-03 13:33 UTC (permalink / raw)
To: devnull+demiobenour.gmail.com
Cc: acme, adrian.hunter, alexander.shishkin, ardb, axboe, corbet,
davem, demiobenour, ebiggers, edumazet, herbert, horms, io-uring,
irogers, james.clark, jolsa, kuba, kuniyu, linux-crypto,
linux-doc, linux-kernel, linux-perf-users, mark.rutland, mingo,
namhyung, netdev, pabeni, peterz, skhan, willemb, linux-s390
In-Reply-To: <20260523-af-alg-harden-v1-2-c76755c3a5c5@gmail.com>
> AF_ALG is deprecated and exposed to unprivileged userspace. Only
> use the least buggy algorithm implementations: the pure software ones.
>
I thought AF_ALG is marked as deprecated but still usable. This patch
now actively disables groups of crypto implementations. Also it just
assumes that all algorithms which are asynchronously implemented or
do not have a fallback are to be disabled via AF_ALG.
There are may reasons for not having a synchronous implementation. For
example if you need to fetch (asynch) some information from a HSM before
doing the job of the algorithm. Also all secure key operations can't
by definition run directly on the CPU but need to be fed into some
hardware. Same is true with just acceleration - and acceleration via
special hardware (crypto hw, or AI hardware for example) is very common
on platforms priced by CPU cycles.
I also can't find any arguments for the statement 'Hardware accelerator
drivers are frequently buggy.' Does this mean that the linux kernel
from now on will not accept any hardware accelerator drivers any more?
Statements about code quality should be addressed to the driver
maintainer but not lead to tagging of groups of drivers.
I can understand that the AF_ALG shall be deprecated and fade away.
But this patch out of the sudden disables the long standing AF_ALG
interface at least for testing purpose and causes some failures in
the s390 crypto test area without any chance to react at all.
> This removes one of the main advantages of AF_ALG, which is the
> ability to use it with off-CPU accelerators. However, using off-CPU
> accelerators has huge overheads, both in performance and attack surface.
> I have yet to see real-world, performance-critical workloads where using
> an accelerator via AF_ALG is actually a win over doing cryptography in
> userspace.
>
> If using an off-CPU accelerator really does turn out to be a win, a new
> API should be developed that is actually a good fit for it.
>
> Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
> ---
> Documentation/crypto/userspace-if.rst | 7 ++++++-
> crypto/af_alg.c | 2 +-
> crypto/algif_aead.c | 4 ++--
> crypto/algif_hash.c | 4 ++--
> crypto/algif_rng.c | 4 ++--
> crypto/algif_skcipher.c | 4 ++--
> include/crypto/if_alg.h | 14 +++++++++++++-
> 7 files changed, 28 insertions(+), 11 deletions(-)
>
> diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
> index ea1b1b3f4049fd4673528dc2a6234f6376a3489f..b31117d4415dda6ad6ca36275e615bec7df9552e 100644
> --- a/Documentation/crypto/userspace-if.rst
> +++ b/Documentation/crypto/userspace-if.rst
> @@ -9,7 +9,8 @@ symmetric cipher, AEAD, and RNG algorithms that are implemented in kernel-mode
> code.
>
> AF_ALG is insecure and is deprecated. Originally added to the kernel in 2010,
> -most kernel developers now consider it to be a mistake.
> +most kernel developers now consider it to be a mistake. Support for hardware
> +accelerators, which was the original purpose of AF_ALG, has been removed.
>
> AF_ALG continues to be supported only for backwards compatibility. On systems
> where no programs using AF_ALG remain, the support for it should be disabled by
> @@ -59,6 +60,10 @@ Some of the examples include:
> - CVE-2013-7421
> - CVE-2011-4081
>
> +Hardware accelerator drivers are frequently buggy. To reduce attack surface,
> +AF_ALG now only provides access to algorithms implemented in software. This
> +means that AF_ALG no longer fulfills its original purpose.
> +
> It is recommended that, whenever possible, userspace programs be migrated to
> userspace crypto code (which again, is what is normally used anyway) and
> ``CONFIG_CRYPTO_USER_API_*`` be disabled. On systems that use SELinux, SELinux
> diff --git a/crypto/af_alg.c b/crypto/af_alg.c
> index 8ccf7a737cd6ca9a5d5bf47050c9afea0dfd61bf..cce000e8590e469927b5a5a0ceccfdf0ef54633d 100644
> --- a/crypto/af_alg.c
> +++ b/crypto/af_alg.c
> @@ -181,7 +181,7 @@ static int alg_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int add
> if (IS_ERR(type))
> return PTR_ERR(type);
>
> - private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask);
> + private = type->bind(sa->salg_name);
> if (IS_ERR(private)) {
> module_put(type->owner);
> return PTR_ERR(private);
> diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
> index 60f06597cb0b13036bc975641a0b02ea8a41ad03..787aac8aeb24eed128f08345ba730478113919b3 100644
> --- a/crypto/algif_aead.c
> +++ b/crypto/algif_aead.c
> @@ -342,9 +342,9 @@ static struct proto_ops algif_aead_ops_nokey = {
> .poll = af_alg_poll,
> };
>
> -static void *aead_bind(const char *name, u32 type, u32 mask)
> +static void *aead_bind(const char *name)
> {
> - return crypto_alloc_aead(name, type, mask);
> + return crypto_alloc_aead(name, 0, AF_ALG_CRYPTOAPI_MASK);
> }
>
> static void aead_release(void *private)
> diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
> index 4d3dfc60a16a6d8b677d903d209df18d67202c98..5452ad6c15069c3cb0ff78fe58868fe7ce4b0fc3 100644
> --- a/crypto/algif_hash.c
> +++ b/crypto/algif_hash.c
> @@ -380,9 +380,9 @@ static struct proto_ops algif_hash_ops_nokey = {
> .accept = hash_accept_nokey,
> };
>
> -static void *hash_bind(const char *name, u32 type, u32 mask)
> +static void *hash_bind(const char *name)
> {
> - return crypto_alloc_ahash(name, type, mask);
> + return crypto_alloc_ahash(name, 0, AF_ALG_CRYPTOAPI_MASK);
> }
>
> static void hash_release(void *private)
> diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c
> index a9fb492e929a70c94476f296f5f5e7c42f0313b7..4dfe7899f8fa4ce82d5f2236297230fb44bc35d6 100644
> --- a/crypto/algif_rng.c
> +++ b/crypto/algif_rng.c
> @@ -197,7 +197,7 @@ static struct proto_ops __maybe_unused algif_rng_test_ops = {
> .sendmsg = rng_test_sendmsg,
> };
>
> -static void *rng_bind(const char *name, u32 type, u32 mask)
> +static void *rng_bind(const char *name)
> {
> struct rng_parent_ctx *pctx;
> struct crypto_rng *rng;
> @@ -206,7 +206,7 @@ static void *rng_bind(const char *name, u32 type, u32 mask)
> if (!pctx)
> return ERR_PTR(-ENOMEM);
>
> - rng = crypto_alloc_rng(name, type, mask);
> + rng = crypto_alloc_rng(name, 0, AF_ALG_CRYPTOAPI_MASK);
> if (IS_ERR(rng)) {
> kfree(pctx);
> return ERR_CAST(rng);
> diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
> index 9dbccabd87b13920c27aff5a450a235cc6a27d59..df20bdfe1f1f4e453782dee3b743dd1939ab4c6c 100644
> --- a/crypto/algif_skcipher.c
> +++ b/crypto/algif_skcipher.c
> @@ -307,9 +307,9 @@ static struct proto_ops algif_skcipher_ops_nokey = {
> .poll = af_alg_poll,
> };
>
> -static void *skcipher_bind(const char *name, u32 type, u32 mask)
> +static void *skcipher_bind(const char *name)
> {
> - return crypto_alloc_skcipher(name, type, mask);
> + return crypto_alloc_skcipher(name, 0, AF_ALG_CRYPTOAPI_MASK);
> }
>
> static void skcipher_release(void *private)
> diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
> index 62867daca47d76c9ea1a7ed233188788c5f6c3c0..7643ba954125aba0c06aaf19de087985325885ad 100644
> --- a/include/crypto/if_alg.h
> +++ b/include/crypto/if_alg.h
> @@ -41,7 +41,7 @@ struct af_alg_control {
> };
>
> struct af_alg_type {
> - void *(*bind)(const char *name, u32 type, u32 mask);
> + void *(*bind)(const char *name);
> void (*release)(void *private);
> int (*setkey)(void *private, const u8 *key, unsigned int keylen);
> int (*setentropy)(void *private, sockptr_t entropy, unsigned int len);
> @@ -243,4 +243,16 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags,
> struct af_alg_async_req *areq, size_t maxsize,
> size_t *outlen);
>
> +/*
> + * Mask used to disable unsupported algorithm implementations.
> + *
> + * This is the same as FSCRYPT_CRYPTOAPI_MASK in fs/crypto/fscrypt_private.h.
> + * In additions to the motivations there, this API is exposed to userspace
> + * that might not be fully trusted.
> + */
> +#define AF_ALG_CRYPTOAPI_MASK \
> + (CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY | \
> + CRYPTO_ALG_KERN_DRIVER_ONLY)
> +
> +
> #endif /* _CRYPTO_IF_ALG_H */
>
> --
> 2.54.0
>
Harald Freudenberger
^ permalink raw reply
* Re: [PATCH 11/15] accel/qda: Add PRIME DMA-BUF import support
From: Christian König @ 2026-06-03 13:40 UTC (permalink / raw)
To: Ekansh Gupta, Oded Gabbay, Jonathan Corbet, Shuah Khan,
Joerg Roedel, Will Deacon, Robin Murphy, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Sumit Semwal
Cc: Bharath Kumar, Chenna Kesava Raju, srini, dmitry.baryshkov,
andersson, konradybcio, robin.clark, linux-kernel, dri-devel,
linux-doc, linux-arm-msm, iommu, linux-media, linaro-mm-sig
In-Reply-To: <e465ed15-1568-467b-ac6b-94f903b46776@oss.qualcomm.com>
On 6/3/26 08:11, Ekansh Gupta wrote:
> On 19-05-2026 12:25, Christian König wrote:
>> On 5/19/26 08:16, Ekansh Gupta via B4 Relay wrote:
>>> From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
...
>>> +static int qda_memory_manager_map_imported(struct qda_memory_manager *mem_mgr,
>>> + struct qda_gem_obj *gem_obj,
>>> + struct qda_iommu_device *iommu_dev)
>>> +{
>>> + struct scatterlist *sg;
>>> + dma_addr_t dma_addr;
>>> +
>>> + if (!gem_obj->is_imported || !gem_obj->sgt || !iommu_dev) {
>>> + drm_err(gem_obj->base.dev, "Invalid parameters for imported buffer mapping\n");
>>> + return -EINVAL;
>>> + }
>>> +
>>> + sg = gem_obj->sgt->sgl;
>>> + if (!sg) {
>>> + drm_err(gem_obj->base.dev, "Invalid scatter-gather list for imported buffer\n");
>>> + return -EINVAL;
>>> + }
>>> +
>>> + gem_obj->iommu_dev = iommu_dev;
>>> +
>>> + /*
>>> + * After dma_buf_map_attachment_unlocked(), sg_dma_address() returns the
>>> + * IOMMU virtual address, not the physical address. The IOMMU maps the
>>> + * entire buffer as a contiguous range in the IOMMU address space even if
>>> + * the underlying physical memory is non-contiguous. Therefore the first
>>> + * sg entry's DMA address is the start of the complete contiguous
>>> + * IOMMU-mapped range and is sufficient to describe the buffer to the DSP.
>>> + */
>>> + dma_addr = sg_dma_address(sg);
>>> + dma_addr += ((u64)iommu_dev->sid << 32);
>>> + gem_obj->dma_addr = dma_addr;
>>
>> That handling here is completely broken since it assumes that the exporter maps the buffer as contigious range.
>>
>> But that's in no way guaranteed.
> I'll collect more details and will try to implement this in the right
> way, maybe by iterating the full sg_table.>
You could also document explicitly that you can only import contiguous buffers (e.g. DMA-buf heap CMA etc....) and then cleanly reject non contiguous buffers here.
We have quite a number of drivers/HW with that limitation, so only accepting contiguous buffers is perfectly ok.
You just can't silently assume that IOMMU would always map the entire buffer as one contiguous range, cause that is certainly not true.
Regards,
Christian.
>> Regards,
>> Christian.
^ permalink raw reply
* Re: [PATCH v2 2/2] HID: nintendo: Use %pM format specifier for MAC addresses
From: Andy Shevchenko @ 2026-06-03 13:42 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Jiri Kosina, Daniel J. Ogorchock, Petr Mladek, Tamir Duberstein,
linux-doc, linux-kernel, linux-input, Steven Rostedt,
Rasmus Villemoes, Sergey Senozhatsky, Jonathan Corbet, Shuah Khan,
Andrew Morton
In-Reply-To: <aiAXraQh-IrbAe0C@beelink>
On Wed, Jun 03, 2026 at 02:03:01PM +0200, Benjamin Tissoires wrote:
> On Jun 03 2026, Andy Shevchenko wrote:
> > Convert to %pM instead of using custom code.
> >
> > Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> Not sure where the first patch should land,
Up to the maintainers Petr and you, to me it makes no difference.
> so in case someone prefers having the full series through their tree:
> Acked-by: Benjamin Tissoires <bentiss@kernel.org>
Thank you!
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 05/18] perf test: Add deterministic workload
From: Leo Yan @ 2026-06-03 13:43 UTC (permalink / raw)
To: James Clark
Cc: Suzuki K Poulose, Mike Leach, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis, coresight, linux-perf-users,
linux-kernel, Arnaldo Carvalho de Melo, linux-doc
In-Reply-To: <b4836fe9-49cf-44c3-96a9-548e890cee29@linaro.org>
On Wed, Jun 03, 2026 at 02:10:37PM +0100, James Clark wrote:
>
>
> On 03/06/2026 12:27 pm, Leo Yan wrote:
> > On Tue, Jun 02, 2026 at 03:26:47PM +0100, James Clark wrote:
> >
> > [...]
> >
> > > @@ -22,3 +23,4 @@ CFLAGS_brstack.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
> > > CFLAGS_datasym.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
> > > CFLAGS_traploop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
> > > CFLAGS_inlineloop.o = -g -O2
> > > +CFLAGS_deterministic.o = -g -O0
> >
> > I have no strong opinion for using 'noinline' in source or using the
> > global option '-fno-inline', just thought this is not easy to follow
> > up if anyone (likely myself) will write a new workload for disabling
> > inline. Could we have consistent style for this?
> >
> > For the patch itself:
> >
> > Reviewed-by: Leo Yan <leo.yan@arm.com>
>
> Actually it's a fair question why some have -fno-inline and others do it in
> the code, it could just be copied from when these were built by their shell
> script tests. From a quick look I would say we can easily drop the
> -fno-inline and do it in the code, and it's better to only noinline what's
> needed rather than everything. But that's probably a change for another
> time.
Seems to me, `-fno-inline` is more reliable.
I.e., in this patch deterministic() has no 'noinline' annotation, my
understanding is the test expects it is not inlined. With `-fno-inline`
flag, we don't need to worry anything is missed.
Thanks,
Leo
^ permalink raw reply
* Re: [PATCH 08/15] accel/qda: Add QUERY IOCTL and QDA UAPI header
From: Dmitry Baryshkov @ 2026-06-03 13:43 UTC (permalink / raw)
To: Ekansh Gupta
Cc: Oded Gabbay, Jonathan Corbet, Shuah Khan, Joerg Roedel,
Will Deacon, Robin Murphy, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Sumit Semwal,
Christian König, Bharath Kumar, Chenna Kesava Raju, srini,
andersson, konradybcio, robin.clark, linux-kernel, dri-devel,
linux-doc, linux-arm-msm, iommu, linux-media, linaro-mm-sig
In-Reply-To: <b5c9d149-1a48-4c0d-aa0d-9ad331896f47@oss.qualcomm.com>
On Wed, Jun 03, 2026 at 11:21:43AM +0530, Ekansh Gupta wrote:
> On 20-05-2026 19:59, Dmitry Baryshkov wrote:
> > On Tue, May 19, 2026 at 11:45:58AM +0530, Ekansh Gupta via B4 Relay wrote:
> >> From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
> >>
> >> Introduce the DRM_IOCTL_QDA_QUERY IOCTL, which allows user-space to
> >> identify which DSP domain a given /dev/accel/accel* node represents
> >> (e.g. "cdsp", "adsp").
> >>
> >> include/uapi/drm/qda_accel.h
> >> Defines the QDA IOCTL command numbers and the associated data
> >> structures. The header follows the standard DRM UAPI conventions:
> >> __u8/__u32 types, a C++ extern "C" guard, and GPL-2.0-only WITH
> >> Linux-syscall-note licensing.
> >>
> >> drivers/accel/qda/qda_ioctl.c / qda_ioctl.h
> >> Implements qda_ioctl_query(), which copies the DSP domain name
> >> stored in qda_dev.dsp_name into the user-supplied drm_qda_query
> >> buffer using strscpy().
> >>
> >> drivers/accel/qda/qda_drv.c
> >> Registers the qda_ioctls[] table with the drm_driver so that the
> >> DRM core dispatches DRM_IOCTL_QDA_QUERY to qda_ioctl_query().
> >>
> >> Assisted-by: Claude:claude-4-6-sonnet
> >> Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
> >> ---
> >> drivers/accel/qda/Makefile | 1 +
> >> drivers/accel/qda/qda_drv.c | 8 +++++++
> >> drivers/accel/qda/qda_ioctl.c | 26 +++++++++++++++++++++++
> >> drivers/accel/qda/qda_ioctl.h | 13 ++++++++++++
> >> include/uapi/drm/qda_accel.h | 49 +++++++++++++++++++++++++++++++++++++++++++
> >> 5 files changed, 97 insertions(+)
> >>
> >> diff --git a/drivers/accel/qda/Makefile b/drivers/accel/qda/Makefile
> >> index 701fad5ffb50..b658dad35fee 100644
> >> --- a/drivers/accel/qda/Makefile
> >> +++ b/drivers/accel/qda/Makefile
> >> @@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_ACCEL_QDA) := qda.o
> >> qda-y := \
> >> qda_cb.o \
> >> qda_drv.o \
> >> + qda_ioctl.o \
> >> qda_memory_manager.o \
> >> qda_rpmsg.o
> >>
> >> diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c
> >> index 0ad5d9873d7e..becd831d10be 100644
> >> --- a/drivers/accel/qda/qda_drv.c
> >> +++ b/drivers/accel/qda/qda_drv.c
> >> @@ -8,8 +8,10 @@
> >> #include <drm/drm_gem.h>
> >> #include <drm/drm_ioctl.h>
> >> #include <drm/drm_print.h>
> >> +#include <drm/qda_accel.h>
> >>
> >> #include "qda_drv.h"
> >> +#include "qda_ioctl.h"
> >> #include "qda_rpmsg.h"
> >>
> >> static int qda_open(struct drm_device *dev, struct drm_file *file)
> >> @@ -36,11 +38,17 @@ static void qda_postclose(struct drm_device *dev, struct drm_file *file)
> >>
> >> DEFINE_DRM_ACCEL_FOPS(qda_accel_fops);
> >>
> >> +static const struct drm_ioctl_desc qda_ioctls[] = {
> >> + DRM_IOCTL_DEF_DRV(QDA_QUERY, qda_ioctl_query, 0),
> >> +};
> >> +
> >> static const struct drm_driver qda_drm_driver = {
> >> .driver_features = DRIVER_COMPUTE_ACCEL,
> >> .fops = &qda_accel_fops,
> >> .open = qda_open,
> >> .postclose = qda_postclose,
> >> + .ioctls = qda_ioctls,
> >> + .num_ioctls = ARRAY_SIZE(qda_ioctls),
> >> .name = QDA_DRIVER_NAME,
> >> .desc = "Qualcomm DSP Accelerator Driver",
> >> };
> >> diff --git a/drivers/accel/qda/qda_ioctl.c b/drivers/accel/qda/qda_ioctl.c
> >> new file mode 100644
> >> index 000000000000..761d3567c33f
> >> --- /dev/null
> >> +++ b/drivers/accel/qda/qda_ioctl.c
> >> @@ -0,0 +1,26 @@
> >> +// SPDX-License-Identifier: GPL-2.0-only
> >> +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> >> +#include <drm/drm_ioctl.h>
> >> +#include <drm/qda_accel.h>
> >> +#include "qda_drv.h"
> >> +#include "qda_ioctl.h"
> >> +
> >> +/**
> >> + * qda_ioctl_query() - Query DSP device information
> >> + * @dev: DRM device structure
> >> + * @data: User-space data (struct drm_qda_query)
> >> + * @file_priv: DRM file private data
> >> + *
> >> + * Return: 0 on success, negative error code on failure
> >> + */
> >> +int qda_ioctl_query(struct drm_device *dev, void *data, struct drm_file *file_priv)
> >> +{
> >> + struct drm_qda_query *args = data;
> >> + struct qda_dev *qdev;
> >> +
> >> + qdev = qda_dev_from_drm(dev);
> >> +
> >> + strscpy(args->dsp_name, qdev->dsp_name, sizeof(args->dsp_name));
> >> +
> >> + return 0;
> >> +}
> >> diff --git a/drivers/accel/qda/qda_ioctl.h b/drivers/accel/qda/qda_ioctl.h
> >> new file mode 100644
> >> index 000000000000..b8fd536a111f
> >> --- /dev/null
> >> +++ b/drivers/accel/qda/qda_ioctl.h
> >> @@ -0,0 +1,13 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-only */
> >> +/*
> >> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> >> + */
> >> +
> >> +#ifndef __QDA_IOCTL_H__
> >> +#define __QDA_IOCTL_H__
> >> +
> >> +#include "qda_drv.h"
> >> +
> >> +int qda_ioctl_query(struct drm_device *dev, void *data, struct drm_file *file_priv);
> >> +
> >> +#endif /* __QDA_IOCTL_H__ */
> >> diff --git a/include/uapi/drm/qda_accel.h b/include/uapi/drm/qda_accel.h
> >> new file mode 100644
> >> index 000000000000..1971a4263065
> >> --- /dev/null
> >> +++ b/include/uapi/drm/qda_accel.h
> >> @@ -0,0 +1,49 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
> >> +/*
> >> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> >> + */
> >> +
> >> +#ifndef __QDA_ACCEL_H__
> >> +#define __QDA_ACCEL_H__
> >> +
> >> +#include "drm.h"
> >> +
> >> +#if defined(__cplusplus)
> >> +extern "C" {
> >> +#endif
> >> +
> >> +/*
> >> + * QDA IOCTL command numbers
> >> + *
> >> + * These define the command numbers for QDA-specific IOCTLs.
> >> + * They are used with DRM_COMMAND_BASE to create the full IOCTL numbers.
> >> + */
> >> +#define DRM_QDA_QUERY 0x00
> >> +
> >> +/*
> >> + * QDA IOCTL definitions
> >> + *
> >> + * These macros define the actual IOCTL numbers used by userspace applications.
> >> + * They combine the command numbers with DRM_COMMAND_BASE and specify the
> >> + * data structure and direction (read/write) for each IOCTL.
> >> + */
> >> +#define DRM_IOCTL_QDA_QUERY DRM_IOR(DRM_COMMAND_BASE + DRM_QDA_QUERY, \
> >> + struct drm_qda_query)
> >> +
> >> +/**
> >> + * struct drm_qda_query - Device information query structure
> >> + * @dsp_name: Name of DSP (e.g., "adsp", "cdsp", "cdsp1", "gdsp0", "gdsp1")
> >> + *
> >> + * This structure is used with DRM_IOCTL_QDA_QUERY to query device type,
> >> + * allowing userspace to identify which DSP a device node represents. The
> >> + * kernel provides the DSP name directly as a null-terminated string.
> >> + */
> >> +struct drm_qda_query {
> >> + __u8 dsp_name[16];
> >
> > Are you sure that you want to query only the name? No extra options, no
> > attributes, no hardware capabilities?
> There are plans to extend this ioctl to support DSP capabilities and few
> other query options, but as per my understanding, I don't need to add
> reserved IOCTLs in drm case and I can extend it in future. Please
> correct me if my understanding is wrong and I should add reserved fields.
>
> Copying the statement from the doc[1].
> "Note that drm_ioctl() automatically zero-extends structures, hence make
> sure you can add more stuff at the end, i.e. don’t put a variable sized
> array there."
I'd rather have a query type as an input here, to be able to return one
of querried params.
>
> [1]
> https://www.kernel.org/doc/html/v7.0/gpu/drm-uapi.html#ioctl-support-on-device-nodes>
>
> >> +};
> >> +
> >> +#if defined(__cplusplus)
> >> +}
> >> +#endif
> >> +
> >> +#endif /* __QDA_ACCEL_H__ */
> >>
> >> --
> >> 2.34.1
> >>
> >>
> >
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH v7 07/42] KVM: guest_memfd: Only prepare folios for private pages
From: Michael Roth @ 2026-06-03 13:51 UTC (permalink / raw)
To: Suzuki K Poulose
Cc: Ackerley Tng, aik, andrew.jones, binbin.wu, brauner, chao.p.peng,
david, ira.weiny, jmattson, jthoughton, oupton, pankaj.gupta,
qperret, rick.p.edgecombe, rientjes, shivankg, steven.price,
tabba, willy, wyihan, yan.y.zhao, forkloop, pratyush,
aneesh.kumar, liam, Paolo Bonzini, Sean Christopherson,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Jonathan Corbet, Shuah Khan, Shuah Khan,
Vishal Annapurve, Andrew Morton, Chris Li, Kairui Song,
Kemeng Shi, Nhat Pham, Baoquan He, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Youngjun Park, Qi Zheng, Shakeel Butt,
Kiryl Shutsemau, Jason Gunthorpe, Vlastimil Babka, kvm,
linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, linux-coco
In-Reply-To: <88cae738-18e9-4ed3-8414-506a1ad8fb18@arm.com>
On Wed, Jun 03, 2026 at 09:58:45AM +0100, Suzuki K Poulose wrote:
> On 02/06/2026 23:41, Ackerley Tng wrote:
> > Suzuki K Poulose <suzuki.poulose@arm.com> writes:
> >
> > >
> > > [...snip...]
> > >
> > > > > @@ -914,7 +916,8 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct
> > > > > kvm_memory_slot *slot,
> > > > > folio_mark_uptodate(folio);
> > > > > }
> > > > > - r = kvm_gmem_prepare_folio(kvm, slot, gfn, folio);
> > > > > + if (kvm_gmem_is_private_mem(inode, index))
> > > >
> > > > Don't we need to make sure the entire folio is private ? Not just the
> > > > page at the index ?
> > > > if (kvm_gmem_range_is_private(, index, folio_nr_pages(folio)) ?
> >
> > I was thinking to fix this when I do huge pages, for now guest_memfd is
> > always just PAGE_SIZE, so just looking up index is fine.
> >
> > Is that okay?
>
> Thats fine, but would be good to enforce that here, so that we don't miss
> out when we add support for multi page folios.
We sort of already enforce that in kvm_gmem_get_folio():
/*
* External interfaces like kvm_gmem_get_pfn() support dealing
* with hugepages to a degree, but internally, guest_memfd currently
* assumes that all folios are order-0 and handling would need
* to be updated for anything otherwise (e.g. page-clearing
* operations).
*/
WARN_ON_ONCE(!IS_ERR(folio) && folio_order(folio));
which was done as part of:
commit 6538b6221cc2feda415ca1946e66a5ef02dc6a0a
Author: Michael Roth <michael.roth@amd.com>
Date: Thu Jan 8 15:46:18 2026 -0600
KVM: guest_memfd: Remove partial hugepage handling from kvm_gmem_populate()
and that should trigger before you even reach the prepare path, so I think
that's covered.
In general, there some previous discussion where we decided we would stop wasting
time guessing at what we'll need to do for hugepages and instead just strip out
the partial support. Sean wanted the folio order kept at part of the internal API
since we know MMU will need that one way or another, but elsewhere within
guest_memfd we are okay to assume 4K. If we *know* certain points that will need
to change then a comment mentioning it isn't a bad idea, but even those comments
have tended to be wrong so far about exactly what changes are supposed to happen.
I'm not sure where the original discussion happened but there's some aftermath
discussion here[1] that I think summarizes current [non-]plans around
prepare+hugepages.
[1] https://lore.kernel.org/kvm/20250711163440.kwjebnzd7zeb4bxt@amd.com/
>
> >
> > >
> > > Or rather, we should go through the individual pages and apply the
> > > prepare for ones that are private ?
> > >
> > > Suzuki
> > >
> >
> > IIRC the plan was to make kvm_gmem_prepare_folio() idempotent, as in, if
> > a page is already private, just skip. Currently sev_gmem_prepare() does
> > a pr_debug(), which I guess is technically still idempotent.
> >
> > I'm thinking that the information tha needs tracking to make
> > .gmem_prepare() idempotent should be tracked by arch code.
> >
> > Does this work for ARM CCA?
>
> We don't hook into the prepare yet, but have plans to do that. We should
> be able to handle the pages that are already private. (For CCA context,
> RMI_GRANULE_DELEGATE_RANGE can skip over already REALM pages). So this
> should be fine.
>
> My point is, in a given folio, there may be pages that are shared.
> Like you said, this could be dealt with when we support hugepages.
Sounds good, that's also what SNP will do once hugepages come along.
-Mike
>
> Suzuki
>
>
> >
> > > >
> > > > [...snip...]
> > > >
>
^ permalink raw reply
* Re: [PATCH v7 07/42] KVM: guest_memfd: Only prepare folios for private pages
From: Michael Roth @ 2026-06-03 13:54 UTC (permalink / raw)
To: Ackerley Tng
Cc: Suzuki K Poulose, aik, andrew.jones, binbin.wu, brauner,
chao.p.peng, david, ira.weiny, jmattson, jthoughton, oupton,
pankaj.gupta, qperret, rick.p.edgecombe, rientjes, shivankg,
steven.price, tabba, willy, wyihan, yan.y.zhao, forkloop,
pratyush, aneesh.kumar, liam, Paolo Bonzini, Sean Christopherson,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Jonathan Corbet, Shuah Khan, Shuah Khan,
Vishal Annapurve, Andrew Morton, Chris Li, Kairui Song,
Kemeng Shi, Nhat Pham, Baoquan He, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Youngjun Park, Qi Zheng, Shakeel Butt,
Kiryl Shutsemau, Jason Gunthorpe, Vlastimil Babka, kvm,
linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, linux-coco
In-Reply-To: <CAEvNRgGzOnA34WyOHtkOx5MZDZhOHaXAe+nD75AiJsZ-PsTSFQ@mail.gmail.com>
On Tue, Jun 02, 2026 at 01:46:09PM -0700, Ackerley Tng wrote:
> Suzuki K Poulose <suzuki.poulose@arm.com> writes:
>
> > On 23/05/2026 01:17, Ackerley Tng via B4 Relay wrote:
> >> From: Ackerley Tng <ackerleytng@google.com>
> >>
> >> All-shared guest_memfd used to be only supported for non-CoCo VMs where
> >> preparation doesn't apply. INIT_SHARED is about to be supported for
> >> non-CoCo VMs in a later patch in this series.
> >
> > nit: s/non-CoCo/CoCo ?
> >
>
> Yes, thanks!
>
> >>
> >> In addition, KVM_SET_MEMORY_ATTRIBUTES2 is about to be supported in
> >> guest_memfd in a later patch in this series.
> >>
> >> This means that the kvm fault handler may now call kvm_gmem_get_pfn() on a
> >> shared folio for a CoCo VM where preparation applies.
> >>
> >> Add a check to make sure that preparation is only performed for private
> >> folios.
> >>
> >> Preparation will be undone on freeing (see kvm_gmem_free_folio()) and on
> >> conversion to shared.
> >>
> >> Signed-off-by: Michael Roth <michael.roth@amd.com>
> >
> > nit: Missing Co-Developed-by: ?
> >
>
> IIRC this should have been
>
> Suggested-by: Michael Roth <michael.roth@amd.com>
>
> IIRC Michael suggested this on one of the guest_memfd calls, Michael
> please let me know if you remember otherwise!
That rings a bell. Feel free to add, or just drop the stray SoB, either
way.
-Mike
>
> >>
> >> [...snip...]
> >>
^ permalink raw reply
* Re: [PATCH v6 07/13] kho: add support for linked-block serialization
From: Mike Rapoport @ 2026-06-03 13:59 UTC (permalink / raw)
To: Pasha Tatashin
Cc: linux-kselftest, shuah, akpm, linux-mm, skhan, linux-doc,
linux-kernel, corbet, dmatlack, kexec, pratyush, skhawaja, graf
In-Reply-To: <aiANtYRRDr5iO5QR@plex>
On Wed, Jun 03, 2026 at 12:05:04PM +0000, Pasha Tatashin wrote:
> On 06-03 09:49, Mike Rapoport wrote:
> > On Wed, 03 Jun 2026 03:28:58 +0000, Pasha Tatashin <pasha.tatashin@soleen.com> wrote:
> > > diff --git a/include/linux/kho/abi/block.h b/include/linux/kho/abi/block.h
> > > new file mode 100644
> > > index 000000000000..8641c20b379b
> > > --- /dev/null
> > > +++ b/include/linux/kho/abi/block.h
> > > @@ -0,0 +1,56 @@
> > > [ ... skip 25 lines ... ]
> > > +#define _LINUX_KHO_ABI_BLOCK_H
> > > +
> > > +#include <asm/page.h>
> > > +#include <linux/types.h>
> > > +
> > > +#define KHO_BLOCK_ABI_COMPATIBLE "kho-block-v1"
> >
> > It's never used by block set and after looking at the following patches I
> > found that it's appended to LUO compatible string.
> >
> > While this works for LUO, I think it should be kho_block_set_restore()
> > responsibility to verify the compatibility.
>
> It should work for any component that relies on kho_block. My proposal
> is to use this method for other common KHO data structures (e.g., kho
> vmalloc, kho radix, future kho xarray). There is no need for them to
> carry the compatibility string in their metadata, as whoever uses them
> will include their compatibility string.
So if, say, memfd_luo uses kho vmalloc, xarray and blocks it'll have five
compatibility strings glued together?
> For now, reviewers will have to make sure that if the ABI header content
> is changed, the compatibility string is updated.
--
Sincerely yours,
Mike.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox