From: Usama Arif <usama.arif@linux.dev>
To: Yosry Ahmed <yosry@kernel.org>, Alexandre Ghiti <alex@ghiti.fr>
Cc: Andrew Morton <akpm@linux-foundation.org>,
david@kernel.org, chrisl@kernel.org, kasong@tencent.com,
ljs@kernel.org, ziy@nvidia.com, linux-mm@kvack.org,
ying.huang@linux.alibaba.com, Baoquan He <baoquan.he@linux.dev>,
willy@infradead.org, youngjun.park@lge.com, hannes@cmpxchg.org,
riel@surriel.com, shakeel.butt@linux.dev, alex@ghiti.fr,
kas@kernel.org, baohua@kernel.org, dev.jain@arm.com,
baolin.wang@linux.alibaba.com, Nico Pache <nico.pache@linux.dev>,
"Liam R. Howlett" <liam@infradead.org>,
ryan.roberts@arm.com, Vlastimil Babka <vbabka@kernel.org>,
lance.yang@linux.dev, linux-kernel@vger.kernel.org,
nphamcs@gmail.com, shikemeng@huaweicloud.com,
kernel-team@meta.com, Alexandre Ghiti <alexghiti@fb.com>
Subject: Re: [PATCH v5 04/11] mm: zswap: add range lookup for large-folio swapin
Date: Thu, 23 Jul 2026 13:45:15 +0100 [thread overview]
Message-ID: <ee172b01-54c3-47ef-9040-1342a1566796@linux.dev> (raw)
In-Reply-To: <amFZmtGHEZjXEw5R@google.com>
On 23/07/2026 01:01, Yosry Ahmed wrote:
> On Wed, Jul 22, 2026 at 08:19:35AM -0700, Usama Arif wrote:
>> From: Alexandre Ghiti <alexghiti@fb.com>
>>
>> A large folio reaches zswap_load() only when the caller expects
>> the whole range to be on disk. Zswap still stores large folios as
>> independent order-0 entries, so reconstructing a large folio from
>> zswap entries would risk returning partially initialized data.
>>
>> Teach zswap_load() to scan the covered range. If no slot is in zswap,
>> return -ENOENT so swap_read_folio() reads the backing device. If any
>> slot is still in zswap, fail the large-folio read so the caller can
>> fall back to per-page swapin.
>>
>> Return -EIO rather than -EINVAL for that conflict. Large-folio loads
>> are now valid requests; the error means zswap cannot safely satisfy
>> the request from partial per-page compressed state, not that the
>> request is unsupported. Existing callers only distinguish -ENOENT,
>> so this is a semantic clarification rather than a behavioral change.
>>
>> Add zswap_is_present() so PMD swap-entry consumers can make the same
>> range decision before attempting PMD-order swapin.
>>
>> Signed-off-by: Alexandre Ghiti <alexghiti@fb.com>
>> Signed-off-by: Usama Arif <usama.arif@linux.dev>
>> ---
>> include/linux/zswap.h | 6 ++++++
>> mm/zswap.c | 42 ++++++++++++++++++++++++++++++++----------
>> 2 files changed, 38 insertions(+), 10 deletions(-)
>>
>> diff --git a/include/linux/zswap.h b/include/linux/zswap.h
>> index 30c193a1207e..cd9efcf9dec9 100644
>> --- a/include/linux/zswap.h
>> +++ b/include/linux/zswap.h
>> @@ -35,6 +35,7 @@ void zswap_lruvec_state_init(struct lruvec *lruvec);
>> void zswap_folio_swapin(struct folio *folio);
>> bool zswap_is_enabled(void);
>> bool zswap_never_enabled(void);
>> +bool zswap_is_present(swp_entry_t entry, unsigned int nr);
>> #else
>>
>> struct zswap_lruvec_state {};
>> @@ -69,6 +70,11 @@ static inline bool zswap_never_enabled(void)
>> return true;
>> }
>>
>> +static inline bool zswap_is_present(swp_entry_t entry, unsigned int nr)
>> +{
>> + return false;
>> +}
>> +
>> #endif
>>
>> #endif /* _LINUX_ZSWAP_H */
>> diff --git a/mm/zswap.c b/mm/zswap.c
>> index 4e76a4a87cdc..384492f1f696 100644
>> --- a/mm/zswap.c
>> +++ b/mm/zswap.c
>> @@ -1561,6 +1561,23 @@ bool zswap_store(struct folio *folio)
>> return ret;
>> }
>>
>> +/**
>> + * zswap_is_present() - is any slot in [entry, entry + nr) in zswap?
>> + * @entry: base swap entry of the range
>> + * @nr: number of contiguous slots to check (pass 1 for a single-slot query)
>> + */
>> +bool zswap_is_present(swp_entry_t entry, unsigned int nr)
>> +{
>> + pgoff_t offset = swp_offset(entry);
>> + struct xarray *tree = swap_zswap_tree(entry);
>> + unsigned long index = offset;
>> +
>> + if (!nr || zswap_never_enabled())
>> + return false;
>> +
>> + return xa_find(tree, &index, offset + nr - 1, XA_PRESENT);
>> +}
>> +
>> /**
>> * zswap_load() - load a folio from zswap
>> * @folio: folio to load
>> @@ -1573,10 +1590,9 @@ bool zswap_store(struct folio *folio)
>> * NOT marked up-to-date, so that an IO error is emitted (e.g. do_swap_page()
>> * will SIGBUS).
>> *
>> - * -EINVAL: if the swapped out content was in zswap, but the page belongs
>> - * to a large folio, which is not supported by zswap. The folio is unlocked,
>> - * but NOT marked up-to-date, so that an IO error is emitted (e.g.
>> - * do_swap_page() will SIGBUS).
>> + * -EIO: if a slot in a large-folio range is unexpectedly still in zswap.
>> + * The folio is unlocked, but NOT marked up-to-date, so that an IO
>> + * error is emitted (e.g. do_swap_page() will SIGBUS).
>> *
>> * -ENOENT: if the swapped out content was not in zswap. The folio remains
>> * locked on return.
>> @@ -1595,13 +1611,19 @@ int zswap_load(struct folio *folio)
>> return -ENOENT;
>>
>> /*
>> - * Large folios should not be swapped in while zswap is being used, as
>> - * they are not properly handled. Zswap does not properly load large
>> - * folios, and a large folio may only be partially in zswap.
>> + * A large folio reaches zswap_load() only when its whole range is
>> + * expected to be on disk: PMD swap-entry consumers split before
>> + * calling into PMD-order swapin whenever any slot is still in zswap.
>> + * Confirm the range is entirely absent from zswap and return -ENOENT
>> + * so the caller reads it from disk; if a slot is unexpectedly still in
>> + * zswap, fail the read rather than return partially-initialized data.
>> */
>> - if (WARN_ON_ONCE(folio_test_large(folio))) {
>> - folio_unlock(folio);
>> - return -EINVAL;
>> + if (folio_test_large(folio)) {
>> + if (zswap_is_present(swp, folio_nr_pages(folio))) {
>
> Is dropping the warning here intentional (for the folio_test_large() &&
> zswap_is_present() case)?
>
Yes, so we can end up in a race, which should be handled gracefully.
For example, lets say we have zswap writeback enabled, which means we
can end up in a state where we have a PMD swap entry and 511 of the 512
slots have been written to disk, but 1 slot (slot X) is still in zswap.
We can then have the following race:
CPU A: PMD swap-in CPU B: split-PTE swap-in
------------------ ------------------------
Checks swap cache: empty
Faults slot X
Adds order-0 folio F
zswap_load(F):
removes X from zswap
marks F dirty
Checks zswap range: empty
A is preempted
Unmaps/reclaims F
zswap_store(F):
puts X back in zswap
Removes F from swap cache
A resumes
Allocates large swap-cache folio G
zswap_load(G) finds X in zswap
The correct action would be to reject the PMD order read and fall back
to per-page loading.
I am bit torn about what to do for zswap here. The series is quite big
already. Alexandre is looking at adding support for PMD swap, but will
send patches once this series gets merged. My initial versions 1
and 2, basically stopped installing PMD swap entry if zswap was ever enabled.
From v3, I used Alexandre's suggestion to do zswap_is_present() test
so that PMD swap entry can keep on working.
Both of these paths are temporary till Alex sends his series. I
do feel my initial version was simpler but will basically stop
working if zswap is ever enabled. Do you have any suggestions on
what your preference is for zswap?
Thanks!
Usama
>> + folio_unlock(folio);
>> + return -EIO;
>> + }
>> + return -ENOENT;
>> }
>>
>> entry = xa_load(tree, offset);
>> --
>> 2.53.0-Meta
>>
next prev parent reply other threads:[~2026-07-23 12:45 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-22 15:19 [PATCH v5 00/11] mm: PMD-level swap entries for anonymous THPs Usama Arif
2026-07-22 15:19 ` [PATCH v5 01/11] mm: add PMD swap entry detection support Usama Arif
2026-07-22 15:19 ` [PATCH v5 02/11] mm: add PMD swap entry splitting support Usama Arif
2026-07-22 15:19 ` [PATCH v5 03/11] mm: handle PMD swap entries in fork path Usama Arif
2026-07-22 15:19 ` [PATCH v5 04/11] mm: zswap: add range lookup for large-folio swapin Usama Arif
2026-07-23 0:01 ` Yosry Ahmed
2026-07-23 12:45 ` Usama Arif [this message]
2026-07-22 15:19 ` [PATCH v5 05/11] mm: swap in PMD swap entries as whole THPs during swapoff Usama Arif
2026-07-22 15:19 ` [PATCH v5 06/11] mm: handle PMD swap entries in non-present PMD walkers Usama Arif
2026-07-22 15:19 ` [PATCH v5 07/11] mm: handle PMD swap entries in MADV_WILLNEED Usama Arif
2026-07-22 15:19 ` [PATCH v5 08/11] mm: handle PMD swap entries in UFFDIO_MOVE Usama Arif
2026-07-22 15:19 ` [PATCH v5 09/11] mm: handle PMD swap entry faults on swap-in Usama Arif
2026-07-22 15:19 ` [PATCH v5 10/11] mm: install PMD swap entries on swap-out Usama Arif
2026-07-22 15:19 ` [PATCH v5 11/11] selftests/mm: add PMD swap entry tests Usama Arif
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ee172b01-54c3-47ef-9040-1342a1566796@linux.dev \
--to=usama.arif@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=alex@ghiti.fr \
--cc=alexghiti@fb.com \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=baoquan.he@linux.dev \
--cc=chrisl@kernel.org \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=hannes@cmpxchg.org \
--cc=kas@kernel.org \
--cc=kasong@tencent.com \
--cc=kernel-team@meta.com \
--cc=lance.yang@linux.dev \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=nico.pache@linux.dev \
--cc=nphamcs@gmail.com \
--cc=riel@surriel.com \
--cc=ryan.roberts@arm.com \
--cc=shakeel.butt@linux.dev \
--cc=shikemeng@huaweicloud.com \
--cc=vbabka@kernel.org \
--cc=willy@infradead.org \
--cc=ying.huang@linux.alibaba.com \
--cc=yosry@kernel.org \
--cc=youngjun.park@lge.com \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox