From: Baoquan He <baoquan.he@linux.dev> Date: 2026-05-12 10:42:11
This can simplify the code logic and benefit any new type of swap device
added later.
And also do renaming in this patchset:
-------
file renaming:
---
mm/page_io.c to mm/swap_io.c
function renaming:
---
swap_writepage_* to swap_write_folio_* in file mm/swap_io.c
Changlog:
===
-v6:
* Fix a code bug Kairui found out when reviewing patch in mm/swapfile.c
in patch 2/3. Has fixed it by moving it to appropriate place and add
comment to explain.
-v5:
* Change the return value of init_swap_ops() as -EINVAL as per Chris's
suggestion and adjust its invocation in swapon() accordingly.
* Add Chris and Usama's Ack tags.
-v4:
* Fix a typo opeations -> operations
* Fix a code bug inside init_swap_ops(). I was taking a change at the
time, thought the change is trivial, so I only compiled but didn't
run kernel to test in v3. Now fix it and test passed.
Thanaks to Usama for catching the above two issues.
-v3:
* Rename setup_swap_ops() to init_swap_ops() which reflect the function
behaviour a little better
* Check if sis->ops, sis->ops->read_folio and sis->ops->write_folio is
NULL in init_swap_ops(), but not spread them where they are called.
And once the checking failed, fail swapon immediately. This is
suggested by Chris.
* Call init_swap_ops() before setup_swap_extents() invocation. This
doesn't harm anything and can benefit later adding sis->ops->swap_activate
method.
-v2:
* lots of cleanup for patch 2/3: renaming, moving data
structures, and using const properly
* collected tags from Kairui, Nhat and Barry
-v1:
https://lore.kernel.org/linux-mm/20260302104016.163542-1-bhe@redhat.com/
Baoquan He (3):
mm/swap: rename mm/page_io.c to mm/swap_io.c
mm/swap: use swap_ops to register swap device's methods
mm/swap_io.c: rename swap_writepage_* to swap_write_folio_*
MAINTAINERS | 2 +-
include/linux/swap.h | 2 +
mm/Makefile | 2 +-
mm/swap.h | 12 ++++-
mm/{page_io.c => swap_io.c} | 104 ++++++++++++++++++++----------------
mm/swapfile.c | 9 ++++
mm/zswap.c | 2 +-
7 files changed, 83 insertions(+), 50 deletions(-)
rename mm/{page_io.c => swap_io.c} (90%)
--
2.52.0
From: Baoquan He <baoquan.he@linux.dev> Date: 2026-05-12 10:42:18
Codes in mm/page_io.c are only related to swap io, it has
nothing to do with other page io.
Rename it to avoid confusion.
Reviewed-by: Nhat Pham <nphamcs@gmail.com>
Reviewed-by: Barry Song <baohua@kernel.org>
Acked-by: Kairui Song <kasong@tencent.com>
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
---
MAINTAINERS | 2 +-
mm/Makefile | 2 +-
mm/swap.h | 2 +-
mm/{page_io.c => swap_io.c} | 2 --
4 files changed, 3 insertions(+), 5 deletions(-)
rename mm/{page_io.c => swap_io.c} (99%)
diff --git a/mm/page_io.c b/mm/swap_io.csimilarity index 99%rename from mm/page_io.crename to mm/swap_io.cindex 7ed76592e20d..7c1a3a3a53f8 100644--- a/mm/page_io.c+++ b/mm/swap_io.c
From: Chris Li <chrisl@kernel.org> Date: 2026-05-13 00:27:43
On Tue, May 12, 2026 at 3:42 AM Baoquan He [off-list ref] wrote:
Codes in mm/page_io.c are only related to swap io, it has
nothing to do with other page io.
Rename it to avoid confusion.
Reviewed-by: Nhat Pham <nphamcs@gmail.com>
Reviewed-by: Barry Song <baohua@kernel.org>
Acked-by: Kairui Song <kasong@tencent.com>
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
From: Christoph Hellwig <hch@infradead.org> Date: 2026-05-13 05:21:29
On Tue, May 12, 2026 at 06:41:59PM +0800, Baoquan He wrote:
Codes in mm/page_io.c are only related to swap io, it has
nothing to do with other page io.
That is true. At the same time it also (mostly) isn't about all swap
I/O, but specifically about the block based I/O backend for swap, and
secondarily a little bit about helpers for the swsusp I/O to the swap
file, with a little bit generic swap I/O wrappers thrown in.
So the new new isn't grest either. And I'd rather wait with this until
we can nicely split stuff out - the rest of this series is a good step
toward that, and my swap_activate series is another. After that we
should be able to stop creating swap_extent structures for
SWP_FS_OPS-based I/O, and contain struct swap_extent with the bio code
and actually create a coherent abstraction. This will require moving
a bit more code around, though. My preference for the resulting name
would be swap-block.c or swap-bio.c, but that's up for future
discussion.
Can we just skip this for now?
From: Baoquan He <baoquan.he@linux.dev> Date: 2026-05-13 07:10:50
On 05/12/26 at 10:21pm, Christoph Hellwig wrote:
On Tue, May 12, 2026 at 06:41:59PM +0800, Baoquan He wrote:
quoted
Codes in mm/page_io.c are only related to swap io, it has
nothing to do with other page io.
That is true. At the same time it also (mostly) isn't about all swap
I/O, but specifically about the block based I/O backend for swap, and
secondarily a little bit about helpers for the swsusp I/O to the swap
file, with a little bit generic swap I/O wrappers thrown in.
So the new new isn't grest either. And I'd rather wait with this until
"So the new isn't great either." ?
Take it easy, I can feel this abstraction falls into your area?
we can nicely split stuff out - the rest of this series is a good step
toward that, and my swap_activate series is another. After that we
should be able to stop creating swap_extent structures for
SWP_FS_OPS-based I/O, and contain struct swap_extent with the bio code
and actually create a coherent abstraction. This will require moving
a bit more code around, though. My preference for the resulting name
would be swap-block.c or swap-bio.c, but that's up for future
discussion.
Can we just skip this for now?
Yes, I agree with you, and the swap_extent creating thing sounds great,
look forward to seeing it. I will drop this patch 1/3 in v7.
From: Baoquan He <baoquan.he@linux.dev> Date: 2026-05-12 10:42:25
This simplifies codes and makes logic clearer. And also makes later any
new swap device type being added easier to handle.
Currently there are three types of swap devices: bdev_fs, bdev_sync
and bdev_async, and only operations read_folio and write_folio are
included. In the future, there could be more swap device types added
and more appropriate opeations adapted into swap_ops.
Suggested-by: Chris Li <chrisl@kernel.org>
Acked-by: Chris Li <chrisl@kernel.org>
Co-developed-by: Barry Song <baohua@kernel.org>
Signed-off-by: Barry Song <baohua@kernel.org>
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
---
include/linux/swap.h | 2 +
mm/swap.h | 10 ++++-
mm/swap_io.c | 102 +++++++++++++++++++++++++------------------
mm/swapfile.c | 9 ++++
mm/zswap.c | 2 +-
5 files changed, 80 insertions(+), 45 deletions(-)
From: Kairui Song <hidden> Date: 2026-05-12 17:54:07
On Tue, May 12, 2026 at 6:50 PM Baoquan He [off-list ref] wrote:
This simplifies codes and makes logic clearer. And also makes later any
new swap device type being added easier to handle.
Currently there are three types of swap devices: bdev_fs, bdev_sync
and bdev_async, and only operations read_folio and write_folio are
included. In the future, there could be more swap device types added
and more appropriate opeations adapted into swap_ops.
opeations -> operations
Suggested-by: Chris Li <chrisl@kernel.org>
Acked-by: Chris Li <chrisl@kernel.org>
Co-developed-by: Barry Song <baohua@kernel.org>
Signed-off-by: Barry Song <baohua@kernel.org>
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
I checked the comment above previously and it looked good. But the
error label seems not that correct after double check. inode->i_flags
will keep the S_SWAPFILE flag. Maybe something like add a
inode->i_flags &= ~S_SWAPFILE here and goto free_swap_zswap. Sorry I
didn't check this part carefully last time.
But fortunately, init_swap_ops will never fail at this moment so the
issue never triggers.
quoted hunk
+
mutex_lock(&swapon_mutex);
prio = DEF_SWAP_PRIO;
if (swap_flags & SWAP_FLAG_PREFER)
From: Baoquan He <baoquan.he@linux.dev> Date: 2026-05-14 02:06:18
On 05/13/26 at 01:53am, Kairui Song wrote:
On Tue, May 12, 2026 at 6:50 PM Baoquan He [off-list ref] wrote:
quoted
This simplifies codes and makes logic clearer. And also makes later any
new swap device type being added easier to handle.
Currently there are three types of swap devices: bdev_fs, bdev_sync
and bdev_async, and only operations read_folio and write_folio are
included. In the future, there could be more swap device types added
and more appropriate opeations adapted into swap_ops.
opeations -> operations
Will fix, thanks.
quoted
Suggested-by: Chris Li <chrisl@kernel.org>
Acked-by: Chris Li <chrisl@kernel.org>
Co-developed-by: Barry Song <baohua@kernel.org>
Signed-off-by: Barry Song <baohua@kernel.org>
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
This sanify check is dropped and not added back in anywhere. This is
fine, but it might be better to have a similar VM_WARN_ON_FOLIO in
swap_writeout?
Good catch. In the old code, it's called by both swap_writeout() and
zswap_writeback_entry(). In zswap_writeback_entry(), the folio is
allocated in-place, we don't need to worry about it now. I am fine to
add it back in swap_writeout() because adding it inside all three
swap_write_xxx() is a little too much.
Cscope tag: __swap_writepage
# line filename / context / line
1 288 /home/bhe/code/linux/mm/page_io.c <<swap_writeout>>
__swap_writepage(folio, swap_plug);
2 1053 /home/bhe/code/linux/mm/zswap.c <<zswap_writeback_entry>>
__swap_writepage(folio, NULL);
I checked the comment above previously and it looked good. But the
error label seems not that correct after double check. inode->i_flags
will keep the S_SWAPFILE flag. Maybe something like add a
inode->i_flags &= ~S_SWAPFILE here and goto free_swap_zswap. Sorry I
didn't check this part carefully last time.
Right. How about moving it zswap_swapon() because it only relies on
si->flags setting currently?
But fortunately, init_swap_ops will never fail at this moment so the
issue never triggers.
quoted
+
mutex_lock(&swapon_mutex);
prio = DEF_SWAP_PRIO;
if (swap_flags & SWAP_FLAG_PREFER)
From: Kairui Song <hidden> Date: 2026-05-14 06:42:06
On Thu, May 14, 2026 at 10:06 AM Baoquan He [off-list ref] wrote:
On 05/13/26 at 01:53am, Kairui Song wrote:
quoted
On Tue, May 12, 2026 at 6:50 PM Baoquan He [off-list ref] wrote:
quoted
This simplifies codes and makes logic clearer. And also makes later any
new swap device type being added easier to handle.
Currently there are three types of swap devices: bdev_fs, bdev_sync
and bdev_async, and only operations read_folio and write_folio are
included. In the future, there could be more swap device types added
and more appropriate opeations adapted into swap_ops.
opeations -> operations
Will fix, thanks.
quoted
quoted
Suggested-by: Chris Li <chrisl@kernel.org>
Acked-by: Chris Li <chrisl@kernel.org>
Co-developed-by: Barry Song <baohua@kernel.org>
Signed-off-by: Barry Song <baohua@kernel.org>
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
This sanify check is dropped and not added back in anywhere. This is
fine, but it might be better to have a similar VM_WARN_ON_FOLIO in
swap_writeout?
Good catch. In the old code, it's called by both swap_writeout() and
zswap_writeback_entry(). In zswap_writeback_entry(), the folio is
allocated in-place, we don't need to worry about it now. I am fine to
add it back in swap_writeout() because adding it inside all three
swap_write_xxx() is a little too much.
Cscope tag: __swap_writepage
# line filename / context / line
1 288 /home/bhe/code/linux/mm/page_io.c <<swap_writeout>>
__swap_writepage(folio, swap_plug);
2 1053 /home/bhe/code/linux/mm/zswap.c <<zswap_writeback_entry>>
__swap_writepage(folio, NULL);
I checked the comment above previously and it looked good. But the
error label seems not that correct after double check. inode->i_flags
will keep the S_SWAPFILE flag. Maybe something like add a
inode->i_flags &= ~S_SWAPFILE here and goto free_swap_zswap. Sorry I
didn't check this part carefully last time.
Right. How about moving it zswap_swapon() because it only relies on
si->flags setting currently?
You mean before zswap_swapon()? Then that sounds good to me.
I checked the comment above previously and it looked good. But the
error label seems not that correct after double check. inode->i_flags
will keep the S_SWAPFILE flag. Maybe something like add a
inode->i_flags &= ~S_SWAPFILE here and goto free_swap_zswap. Sorry I
didn't check this part carefully last time.
Right. How about moving it zswap_swapon() because it only relies on
si->flags setting currently?
You mean before zswap_swapon()? Then that sounds good to me.
Yeah, just before zswap_swapon(). I missed a word.
From: Christoph Hellwig <hch@infradead.org> Date: 2026-05-13 05:32:43
};
+struct swap_ops;
/*
Please keep empty spaces before comments. And keeping forward
declarations at the beginning of the file makes them much easier to
organize (although the current swap.h is a complete mess not only in this
regard).
+int init_swap_ops(struct swap_info_struct *sis)
+{
+ /*
+ * ->flags can be updated non-atomically, but that will
+ * never affect SWP_FS_OPS, so the data_race is safe.
+ */
+ if (data_race(sis->flags & SWP_FS_OPS))
+ sis->ops = &bdev_fs_swap_ops;
+ /*
+ * ->flags can be updated non-atomically, but that will
+ * never affect SWP_SYNCHRONOUS_IO, so the data_race is safe.
+ */
+ else if (data_race(sis->flags & SWP_SYNCHRONOUS_IO))
+ sis->ops = &bdev_sync_swap_ops;
+ else
+ sis->ops = &bdev_async_swap_ops;
+
+ if (!sis->ops || !sis->ops->read_folio || !sis->ops->write_folio)
+ return -EINVAL;
In the long run setting these from the helpers for ->swap_activate would
make more sense. Also as ls long as the ops are a small statically
defined set these checks here are a bit odd.
I guess we just need to land this ASAP, then my swap_activate series and
then do a big round of cleanups for a coherent swap interface.
This is a really annoying double-indirection for the SWP_FS_OPS
case. I think we should have one level of indirection here. One
way to do this would be to remove the swap_rw operation and
implement the swap_ops directly in nfs and cifs.
From: Baoquan He <baoquan.he@linux.dev> Date: 2026-05-13 15:33:58
On 05/12/26 at 10:32pm, Christoph Hellwig wrote:
quoted
};
+struct swap_ops;
/*
Please keep empty spaces before comments. And keeping forward
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I may not follow, I noticed that all the comments in the code use
tabs for indentation rather than spaces.
declarations at the beginning of the file makes them much easier to
organize (although the current swap.h is a complete mess not only in this
regard).
Sure, will move it at the beginning of linux/swap.h. Thanks.
quoted
+int init_swap_ops(struct swap_info_struct *sis)
+{
+ /*
+ * ->flags can be updated non-atomically, but that will
+ * never affect SWP_FS_OPS, so the data_race is safe.
+ */
+ if (data_race(sis->flags & SWP_FS_OPS))
+ sis->ops = &bdev_fs_swap_ops;
+ /*
+ * ->flags can be updated non-atomically, but that will
+ * never affect SWP_SYNCHRONOUS_IO, so the data_race is safe.
+ */
+ else if (data_race(sis->flags & SWP_SYNCHRONOUS_IO))
+ sis->ops = &bdev_sync_swap_ops;
+ else
+ sis->ops = &bdev_async_swap_ops;
+
+ if (!sis->ops || !sis->ops->read_folio || !sis->ops->write_folio)
+ return -EINVAL;
In the long run setting these from the helpers for ->swap_activate would
make more sense. Also as ls long as the ops are a small statically
defined set these checks here are a bit odd.
In fact, except of your ->swap_activate, I have my ->swap_activate too
queued in my local branch. While from your comments, seems we don't have
conflict because we have different concerns.
Please see Youngjun's comment and my reply in this thread:
https://lore.kernel.org/linux-mm/aaWiBaeSCILBCzqd@yjaykim-PowerEdge-T330/
I guess we just need to land this ASAP, then my swap_activate series and
then do a big round of cleanups for a coherent swap interface.
This patchset is part I. I posted v1 to collect suggestions, later I
took a leave, then people think the v1 can be merged firstly and helped
to post v2. I later came back and continue to push this part. If you
just found this patch series and come up with those cleanups, could you
wait a moment until we merge this part and part II is posted? I think
the split handling of block and fs in swap you mentioned is super cool,
and is beyond our plan.
This is a really annoying double-indirection for the SWP_FS_OPS
case. I think we should have one level of indirection here. One
way to do this would be to remove the swap_rw operation and
implement the swap_ops directly in nfs and cifs.
From: Christoph Hellwig <hch@infradead.org> Date: 2026-05-15 06:30:47
On Wed, May 13, 2026 at 11:33:50PM +0800, Baoquan He wrote:
This patchset is part I. I posted v1 to collect suggestions, later I
took a leave, then people think the v1 can be merged firstly and helped
to post v2. I later came back and continue to push this part. If you
just found this patch series and come up with those cleanups, could you
wait a moment until we merge this part and part II is posted? I think
the split handling of block and fs in swap you mentioned is super cool,
and is beyond our plan.
I've been looking at this a bit more, and I think it is going very
much in the wrong direction. I've started drafting a version that
moves block to the same model as fs to build up multi-folio bios,
which actually allows for a clean abstraction.
From: Chris Li <chrisl@kernel.org> Date: 2026-05-15 21:31:13
On Thu, May 14, 2026 at 11:30 PM Christoph Hellwig [off-list ref] wrote:
On Wed, May 13, 2026 at 11:33:50PM +0800, Baoquan He wrote:
quoted
This patchset is part I. I posted v1 to collect suggestions, later I
took a leave, then people think the v1 can be merged firstly and helped
to post v2. I later came back and continue to push this part. If you
just found this patch series and come up with those cleanups, could you
wait a moment until we merge this part and part II is posted? I think
the split handling of block and fs in swap you mentioned is super cool,
and is beyond our plan.
I've been looking at this a bit more, and I think it is going very
much in the wrong direction. I've started drafting a version that
moves block to the same model as fs to build up multi-folio bios,
which actually allows for a clean abstraction.
That is for the swapin_readahead() where multiple folios can be read
in one batch, right? I assume It should not impact the swap out path.
Curious to see what you have in mind. The swap_vma_readahead() can
hit more than one swap device. The current swap_ops is per swap device
so your multi-folio bios will likely stay in the core swap layer. I
will take a look at your new implementation; hopefully, the swap_ops
can adapt to that as well.
Chris
From: Chris Li <chrisl@kernel.org> Date: 2026-05-16 00:34:48
On Fri, May 15, 2026 at 2:31 PM Chris Li [off-list ref] wrote:
quoted
I've been looking at this a bit more, and I think it is going very
much in the wrong direction. I've started drafting a version that
moves block to the same model as fs to build up multi-folio bios,
which actually allows for a clean abstraction.
That is for the swapin_readahead() where multiple folios can be read
in one batch, right? I assume It should not impact the swap out path.
Curious to see what you have in mind. The swap_vma_readahead() can
hit more than one swap device. The current swap_ops is per swap device
so your multi-folio bios will likely stay in the core swap layer. I
will take a look at your new implementation; hopefully, the swap_ops
can adapt to that as well.
Never mind that; I just saw your swap batching series. I will reply there.
Chris
From: Christoph Hellwig <hch@infradead.org> Date: 2026-05-13 05:45:55
Looking a bit more I also think this abastraction is still leaky because
the unplug calls for fs based swap aren't properly abstracted out.
(note that it would make sense to use them for block based swap as well,
as building a single bio will be a lot more efficient than relying on
block layer plugging, but that's a separate issue)
From: Baoquan He <baoquan.he@linux.dev> Date: 2026-05-13 15:38:30
On 05/12/26 at 10:45pm, Christoph Hellwig wrote:
Looking a bit more I also think this abastraction is still leaky because
the unplug calls for fs based swap aren't properly abstracted out.
Right, and this can be easily done by adding a unplug callback in
swap_ops.
(note that it would make sense to use them for block based swap as well,
as building a single bio will be a lot more efficient than relying on
block layer plugging, but that's a separate issue)
From: Baoquan He <baoquan.he@linux.dev> Date: 2026-05-12 10:42:31
All these swap_writepage_* functions handle a passed-in folio,
not a page. This renaming makes them consistent with their
counterpart swap_read_folio_* functions.
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Nhat Pham <nphamcs@gmail.com>
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
---
mm/swap_io.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
From: Kairui Song <hidden> Date: 2026-05-12 17:55:27
On Tue, May 12, 2026 at 6:42 PM Baoquan He [off-list ref] wrote:
All these swap_writepage_* functions handle a passed-in folio,
not a page. This renaming makes them consistent with their
counterpart swap_read_folio_* functions.
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Nhat Pham <nphamcs@gmail.com>
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
---
mm/swap_io.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
From: Chris Li <chrisl@kernel.org> Date: 2026-05-13 00:32:00
On Tue, May 12, 2026 at 3:42 AM Baoquan He [off-list ref] wrote:
All these swap_writepage_* functions handle a passed-in folio,
not a page. This renaming makes them consistent with their
counterpart swap_read_folio_* functions.
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Nhat Pham <nphamcs@gmail.com>
Signed-off-by: Baoquan He <baoquan.he@linux.dev>
The convention for method naming is prefix##method_name, i.e.
swap_fs_read_folio, swap_fs_write_folio, swap_bdev_sync_read_folios,
etc.
To me _fs is a modifier to qualify the method type. If need change, we
may need change all swap_readxxx_fs/bdev_sync/bdev_async and swap_writexxx
likewise.