Re: [PATCH v3 6/9] mm/swapfile: Add batched version of folio_dup_swap

From: David Hildenbrand (Arm)

Date: Tue May 12 2026 - 02:42:45 EST


On 5/12/26 08:07, Dev Jain wrote:
>
>
> On 11/05/26 1:15 pm, David Hildenbrand (Arm) wrote:
>> On 5/6/26 11:45, Dev Jain wrote:
>>> Add folio_dup_swap_pages to handle a batch of consecutive pages. Note
>>> that folio_dup_swap already can handle a subset of this: nr_pages == 1 and
>>> nr_pages == folio_nr_pages(folio). Generalize this to any nr_pages.
>>>
>>> Currently we have a not-so-nice logic of passing in subpage == NULL if
>>> we mean to exercise the logic on the entire folio, and subpage != NULL if
>>> we want to exercise the logic on only that subpage. Remove this
>>> indirection: the caller invokes folio_dup_swap_pages() if it wants to
>>> operate on a range of pages in the folio (i.e nr_pages may be anything
>>> between 1 till folio_nr_pages()), and invokes folio_dup_swap() if it
>>> wants to operate on the entire folio.
>>>
>>> Signed-off-by: Dev Jain <dev.jain@xxxxxxx>
>>> ---
>>> mm/rmap.c | 2 +-
>>> mm/shmem.c | 2 +-
>>> mm/swap.h | 12 ++++++++++--
>>> mm/swapfile.c | 20 ++++++++++++--------
>>> 4 files changed, 24 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/mm/rmap.c b/mm/rmap.c
>>> index 25813e3605991..352ba77d90f67 100644
>>> --- a/mm/rmap.c
>>> +++ b/mm/rmap.c
>>> @@ -2314,7 +2314,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
>>> goto finish_unmap;
>>> }
>>>
>>> - if (folio_dup_swap(folio, subpage) < 0) {
>>> + if (folio_dup_swap_pages(folio, subpage, 1) < 0) {
>>
>> Can you throw in a patch to rename subpage -> page first?
>
> Sure.
>
>>
>>> set_pte_at(mm, address, pvmw.pte, pteval);
>>> goto walk_abort;
>>> }
>>> diff --git a/mm/shmem.c b/mm/shmem.c
>>> index bab3529af23c5..5e4f521399847 100644
>>> --- a/mm/shmem.c
>>> +++ b/mm/shmem.c
>>> @@ -1698,7 +1698,7 @@ int shmem_writeout(struct folio *folio, struct swap_iocb **plug,
>>> spin_unlock(&shmem_swaplist_lock);
>>> }
>>>
>>> - folio_dup_swap(folio, NULL);
>>> + folio_dup_swap(folio);
>>> shmem_delete_from_page_cache(folio, swp_to_radix_entry(folio->swap));
>>>
>>> BUG_ON(folio_mapped(folio));
>>> diff --git a/mm/swap.h b/mm/swap.h
>>> index a77016f2423b9..3c25f914e908b 100644
>>> --- a/mm/swap.h
>>> +++ b/mm/swap.h
>>> @@ -206,7 +206,9 @@ extern int swap_retry_table_alloc(swp_entry_t entry, gfp_t gfp);
>>> * folio_put_swap(): does the opposite thing of folio_dup_swap().
>>> */
>>> int folio_alloc_swap(struct folio *folio);
>>> -int folio_dup_swap(struct folio *folio, struct page *subpage);
>>> +int folio_dup_swap(struct folio *folio);
>>> +int folio_dup_swap_pages(struct folio *folio, struct page *page,
>>> + unsigned long nr_pages);
>>> void folio_put_swap(struct folio *folio, struct page *subpage);
>>>
>>> /* For internal use */
>>> @@ -390,7 +392,13 @@ static inline int folio_alloc_swap(struct folio *folio)
>>> return -EINVAL;
>>> }
>>>
>>> -static inline int folio_dup_swap(struct folio *folio, struct page *page)
>>> +static inline int folio_dup_swap(struct folio *folio)
>>> +{
>>> + return -EINVAL;
>>> +}
>>> +
>>
>> Much cleaner.
>>
>> Can we have a common folio_dup_swap() function instead that does what the
>> variant below does? (call folio_dup_swap_pages())
>
> I am guessing you are saying to simply remove the folio_dup_swap stub because
> we have a stub for folio_dup_swap_pages anyways, I'll do that.

Right, dropping the "return -EINVAL;" variant, and instead move ...

>>>
>>> +int folio_dup_swap(struct folio *folio)
>>> +{
>>> + return folio_dup_swap_pages(folio, folio_page(folio, 0),
>>> + folio_nr_pages(folio));
>>> +}

... this variant out of the ifdef, that will call the folio_dup_swap_pages() stub.

--
Cheers,

David