* [PATCH v3 0/3] mm/swap: use swap_ops to register swap device's methods
@ 2026-04-15 8:56 Baoquan He
2026-04-15 8:56 ` [PATCH v3 1/3] mm/swap: rename mm/page_io.c to mm/swap_io.c Baoquan He
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Baoquan He @ 2026-04-15 8:56 UTC (permalink / raw)
To: linux-mm
Cc: akpm, baohua, chrisl, kasong, nphamcs, shikemeng, youngjun.park,
linux-kernel, Baoquan He
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:
===
-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 | 5 ++
mm/zswap.c | 2 +-
7 files changed, 79 insertions(+), 50 deletions(-)
rename mm/{page_io.c => swap_io.c} (90%)
--
2.52.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v3 1/3] mm/swap: rename mm/page_io.c to mm/swap_io.c 2026-04-15 8:56 [PATCH v3 0/3] mm/swap: use swap_ops to register swap device's methods Baoquan He @ 2026-04-15 8:56 ` Baoquan He 2026-04-15 8:56 ` [PATCH v3 2/3] mm/swap: use swap_ops to register swap device's methods Baoquan He 2026-04-15 8:56 ` [PATCH v3 3/3] mm/swap_io.c: rename swap_writepage_* to swap_write_folio_* Baoquan He 2 siblings, 0 replies; 6+ messages in thread From: Baoquan He @ 2026-04-15 8:56 UTC (permalink / raw) To: linux-mm Cc: akpm, baohua, chrisl, kasong, nphamcs, shikemeng, youngjun.park, linux-kernel, Baoquan He 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/MAINTAINERS b/MAINTAINERS index 92eb723573aa..6fb19fe0bdd3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16948,7 +16948,7 @@ F: Documentation/mm/swap-table.rst F: include/linux/swap.h F: include/linux/swapfile.h F: include/linux/swapops.h -F: mm/page_io.c +F: mm/swap_io.c F: mm/swap.c F: mm/swap.h F: mm/swap_table.h diff --git a/mm/Makefile b/mm/Makefile index 8ad2ab08244e..a65ac900096a 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -75,7 +75,7 @@ ifdef CONFIG_MMU obj-$(CONFIG_ADVISE_SYSCALLS) += madvise.o endif -obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o +obj-$(CONFIG_SWAP) += swap_io.o swap_state.o swapfile.o obj-$(CONFIG_ZSWAP) += zswap.o obj-$(CONFIG_HAS_DMA) += dmapool.o obj-$(CONFIG_HUGETLBFS) += hugetlb.o hugetlb_sysfs.o hugetlb_sysctl.o diff --git a/mm/swap.h b/mm/swap.h index bfafa637c458..81a80605fc6a 100644 --- a/mm/swap.h +++ b/mm/swap.h @@ -210,7 +210,7 @@ extern void swap_entries_free(struct swap_info_struct *si, struct swap_cluster_info *ci, unsigned long offset, unsigned int nr_pages); -/* linux/mm/page_io.c */ +/* linux/mm/swap_io.c */ int sio_pool_init(void); struct swap_iocb; void swap_read_folio(struct folio *folio, struct swap_iocb **plug); diff --git a/mm/page_io.c b/mm/swap_io.c similarity index 99% rename from mm/page_io.c rename to mm/swap_io.c index a2c034660c80..4bf210bd677e 100644 --- a/mm/page_io.c +++ b/mm/swap_io.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 /* - * linux/mm/page_io.c - * * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds * * Swap reorganised 29.12.95, -- 2.52.0 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 2/3] mm/swap: use swap_ops to register swap device's methods 2026-04-15 8:56 [PATCH v3 0/3] mm/swap: use swap_ops to register swap device's methods Baoquan He 2026-04-15 8:56 ` [PATCH v3 1/3] mm/swap: rename mm/page_io.c to mm/swap_io.c Baoquan He @ 2026-04-15 8:56 ` Baoquan He 2026-04-15 15:05 ` Usama Arif 2026-04-15 8:56 ` [PATCH v3 3/3] mm/swap_io.c: rename swap_writepage_* to swap_write_folio_* Baoquan He 2 siblings, 1 reply; 6+ messages in thread From: Baoquan He @ 2026-04-15 8:56 UTC (permalink / raw) To: linux-mm Cc: akpm, baohua, chrisl, kasong, nphamcs, shikemeng, youngjun.park, linux-kernel, Baoquan He 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> 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 | 5 +++ mm/zswap.c | 2 +- 5 files changed, 76 insertions(+), 45 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index 62fc7499b408..3069bbfd7a05 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -255,6 +255,7 @@ struct swap_sequential_cluster { unsigned int next[SWAP_NR_ORDERS]; /* Likely next allocation offset */ }; +struct swap_ops; /* * The in-memory structure used to track swap areas. */ @@ -300,6 +301,7 @@ struct swap_info_struct { struct work_struct reclaim_work; /* reclaim worker */ struct list_head discard_clusters; /* discard clusters list */ struct plist_node avail_list; /* entry in swap_avail_head */ + const struct swap_ops *ops; }; static inline swp_entry_t page_swap_entry(struct page *page) diff --git a/mm/swap.h b/mm/swap.h index 81a80605fc6a..0f4c597e3f28 100644 --- a/mm/swap.h +++ b/mm/swap.h @@ -213,6 +213,15 @@ extern void swap_entries_free(struct swap_info_struct *si, /* linux/mm/swap_io.c */ int sio_pool_init(void); struct swap_iocb; +struct swap_ops { + void (*read_folio)(struct swap_info_struct *sis, + struct folio *folio, + struct swap_iocb **plug); + void (*write_folio)(struct swap_info_struct *sis, + struct folio *folio, + struct swap_iocb **plug); +}; +int init_swap_ops(struct swap_info_struct *sis); void swap_read_folio(struct folio *folio, struct swap_iocb **plug); void __swap_read_unplug(struct swap_iocb *plug); static inline void swap_read_unplug(struct swap_iocb *plug) @@ -222,7 +231,6 @@ static inline void swap_read_unplug(struct swap_iocb *plug) } void swap_write_unplug(struct swap_iocb *sio); int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug); -void __swap_writepage(struct folio *folio, struct swap_iocb **swap_plug); /* linux/mm/swap_state.c */ extern struct address_space swap_space __read_mostly; diff --git a/mm/swap_io.c b/mm/swap_io.c index 4bf210bd677e..602e9b871b30 100644 --- a/mm/swap_io.c +++ b/mm/swap_io.c @@ -238,6 +238,7 @@ static void swap_zeromap_folio_clear(struct folio *folio) int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug) { int ret = 0; + struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); if (folio_free_swap(folio)) goto out_unlock; @@ -279,7 +280,7 @@ int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug) return AOP_WRITEPAGE_ACTIVATE; } - __swap_writepage(folio, swap_plug); + sis->ops->write_folio(sis, folio, swap_plug); return 0; out_unlock: folio_unlock(folio); @@ -369,10 +370,11 @@ static void sio_write_complete(struct kiocb *iocb, long ret) mempool_free(sio, sio_pool); } -static void swap_writepage_fs(struct folio *folio, struct swap_iocb **swap_plug) +static void swap_writepage_fs(struct swap_info_struct *sis, + struct folio *folio, + struct swap_iocb **swap_plug) { struct swap_iocb *sio = swap_plug ? *swap_plug : NULL; - struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); struct file *swap_file = sis->swap_file; loff_t pos = swap_dev_pos(folio->swap); @@ -405,8 +407,9 @@ static void swap_writepage_fs(struct folio *folio, struct swap_iocb **swap_plug) *swap_plug = sio; } -static void swap_writepage_bdev_sync(struct folio *folio, - struct swap_info_struct *sis) +static void swap_writepage_bdev_sync(struct swap_info_struct *sis, + struct folio *folio, + struct swap_iocb **plug) { struct bio_vec bv; struct bio bio; @@ -425,8 +428,9 @@ static void swap_writepage_bdev_sync(struct folio *folio, __end_swap_bio_write(&bio); } -static void swap_writepage_bdev_async(struct folio *folio, - struct swap_info_struct *sis) +static void swap_writepage_bdev_async(struct swap_info_struct *sis, + struct folio *folio, + struct swap_iocb **plug) { struct bio *bio; @@ -442,29 +446,6 @@ static void swap_writepage_bdev_async(struct folio *folio, submit_bio(bio); } -void __swap_writepage(struct folio *folio, struct swap_iocb **swap_plug) -{ - struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); - - VM_BUG_ON_FOLIO(!folio_test_swapcache(folio), folio); - /* - * ->flags can be updated non-atomically (scan_swap_map_slots), - * but that will never affect SWP_FS_OPS, so the data_race - * is safe. - */ - if (data_race(sis->flags & SWP_FS_OPS)) - swap_writepage_fs(folio, swap_plug); - /* - * ->flags can be updated non-atomically (scan_swap_map_slots), - * but that will never affect SWP_SYNCHRONOUS_IO, so the data_race - * is safe. - */ - else if (data_race(sis->flags & SWP_SYNCHRONOUS_IO)) - swap_writepage_bdev_sync(folio, sis); - else - swap_writepage_bdev_async(folio, sis); -} - void swap_write_unplug(struct swap_iocb *sio) { struct iov_iter from; @@ -533,9 +514,10 @@ static bool swap_read_folio_zeromap(struct folio *folio) return true; } -static void swap_read_folio_fs(struct folio *folio, struct swap_iocb **plug) +static void swap_read_folio_fs(struct swap_info_struct *sis, + struct folio *folio, + struct swap_iocb **plug) { - struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); struct swap_iocb *sio = NULL; loff_t pos = swap_dev_pos(folio->swap); @@ -567,8 +549,9 @@ static void swap_read_folio_fs(struct folio *folio, struct swap_iocb **plug) *plug = sio; } -static void swap_read_folio_bdev_sync(struct folio *folio, - struct swap_info_struct *sis) +static void swap_read_folio_bdev_sync(struct swap_info_struct *sis, + struct folio *folio, + struct swap_iocb **plug) { struct bio_vec bv; struct bio bio; @@ -589,8 +572,9 @@ static void swap_read_folio_bdev_sync(struct folio *folio, put_task_struct(current); } -static void swap_read_folio_bdev_async(struct folio *folio, - struct swap_info_struct *sis) +static void swap_read_folio_bdev_async(struct swap_info_struct *sis, + struct folio *folio, + struct swap_iocb **plug) { struct bio *bio; @@ -604,6 +588,44 @@ static void swap_read_folio_bdev_async(struct folio *folio, submit_bio(bio); } +static const struct swap_ops bdev_fs_swap_ops = { + .read_folio = swap_read_folio_fs, + .write_folio = swap_writepage_fs, +}; + +static const struct swap_ops bdev_sync_swap_ops = { + .read_folio = swap_read_folio_bdev_sync, + .write_folio = swap_writepage_bdev_sync, +}; + +static const struct swap_ops bdev_async_swap_ops = { + .read_folio = swap_read_folio_bdev_async, + .write_folio = swap_writepage_bdev_async, +}; + +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 -1; + + return 0; +} + void swap_read_folio(struct folio *folio, struct swap_iocb **plug) { struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); @@ -638,13 +660,7 @@ void swap_read_folio(struct folio *folio, struct swap_iocb **plug) /* We have to read from slower devices. Increase zswap protection. */ zswap_folio_swapin(folio); - if (data_race(sis->flags & SWP_FS_OPS)) { - swap_read_folio_fs(folio, plug); - } else if (synchronous) { - swap_read_folio_bdev_sync(folio, sis); - } else { - swap_read_folio_bdev_async(folio, sis); - } + sis->ops->read_folio(sis, folio, plug); finish: if (workingset) { diff --git a/mm/swapfile.c b/mm/swapfile.c index 60e21414624b..7e1660f59c00 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -3413,6 +3413,11 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) goto bad_swap_unlock_inode; } + if (init_swap_ops(si)) { + error = -EINVAL; + goto bad_swap_unlock_inode; + } + si->max = maxpages; si->pages = maxpages - 1; nr_extents = setup_swap_extents(si, &span); diff --git a/mm/zswap.c b/mm/zswap.c index 16b2ef7223e1..d8930d9054df 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -1061,7 +1061,7 @@ static int zswap_writeback_entry(struct zswap_entry *entry, folio_set_reclaim(folio); /* start writeback */ - __swap_writepage(folio, NULL); + si->ops->write_folio(si, folio, NULL); out: if (ret && ret != -EEXIST) { -- 2.52.0 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/3] mm/swap: use swap_ops to register swap device's methods 2026-04-15 8:56 ` [PATCH v3 2/3] mm/swap: use swap_ops to register swap device's methods Baoquan He @ 2026-04-15 15:05 ` Usama Arif 2026-04-15 15:24 ` Baoquan He 0 siblings, 1 reply; 6+ messages in thread From: Usama Arif @ 2026-04-15 15:05 UTC (permalink / raw) To: Baoquan He Cc: Usama Arif, linux-mm, akpm, baohua, chrisl, kasong, nphamcs, shikemeng, youngjun.park, linux-kernel On Wed, 15 Apr 2026 16:56:57 +0800 Baoquan He <baoquan.he@linux.dev> 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. s/opeations/operations/ > > Suggested-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 | 5 +++ > mm/zswap.c | 2 +- > 5 files changed, 76 insertions(+), 45 deletions(-) > > diff --git a/include/linux/swap.h b/include/linux/swap.h > index 62fc7499b408..3069bbfd7a05 100644 > --- a/include/linux/swap.h > +++ b/include/linux/swap.h > @@ -255,6 +255,7 @@ struct swap_sequential_cluster { > unsigned int next[SWAP_NR_ORDERS]; /* Likely next allocation offset */ > }; > > +struct swap_ops; > /* > * The in-memory structure used to track swap areas. > */ > @@ -300,6 +301,7 @@ struct swap_info_struct { > struct work_struct reclaim_work; /* reclaim worker */ > struct list_head discard_clusters; /* discard clusters list */ > struct plist_node avail_list; /* entry in swap_avail_head */ > + const struct swap_ops *ops; > }; > > static inline swp_entry_t page_swap_entry(struct page *page) > diff --git a/mm/swap.h b/mm/swap.h > index 81a80605fc6a..0f4c597e3f28 100644 > --- a/mm/swap.h > +++ b/mm/swap.h > @@ -213,6 +213,15 @@ extern void swap_entries_free(struct swap_info_struct *si, > /* linux/mm/swap_io.c */ > int sio_pool_init(void); > struct swap_iocb; > +struct swap_ops { > + void (*read_folio)(struct swap_info_struct *sis, > + struct folio *folio, > + struct swap_iocb **plug); > + void (*write_folio)(struct swap_info_struct *sis, > + struct folio *folio, > + struct swap_iocb **plug); > +}; > +int init_swap_ops(struct swap_info_struct *sis); > void swap_read_folio(struct folio *folio, struct swap_iocb **plug); > void __swap_read_unplug(struct swap_iocb *plug); > static inline void swap_read_unplug(struct swap_iocb *plug) > @@ -222,7 +231,6 @@ static inline void swap_read_unplug(struct swap_iocb *plug) > } > void swap_write_unplug(struct swap_iocb *sio); > int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug); > -void __swap_writepage(struct folio *folio, struct swap_iocb **swap_plug); > > /* linux/mm/swap_state.c */ > extern struct address_space swap_space __read_mostly; > diff --git a/mm/swap_io.c b/mm/swap_io.c > index 4bf210bd677e..602e9b871b30 100644 > --- a/mm/swap_io.c > +++ b/mm/swap_io.c > @@ -238,6 +238,7 @@ static void swap_zeromap_folio_clear(struct folio *folio) > int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug) > { > int ret = 0; > + struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); > > if (folio_free_swap(folio)) > goto out_unlock; > @@ -279,7 +280,7 @@ int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug) > return AOP_WRITEPAGE_ACTIVATE; > } > > - __swap_writepage(folio, swap_plug); > + sis->ops->write_folio(sis, folio, swap_plug); > return 0; > out_unlock: > folio_unlock(folio); > @@ -369,10 +370,11 @@ static void sio_write_complete(struct kiocb *iocb, long ret) > mempool_free(sio, sio_pool); > } > > -static void swap_writepage_fs(struct folio *folio, struct swap_iocb **swap_plug) > +static void swap_writepage_fs(struct swap_info_struct *sis, > + struct folio *folio, > + struct swap_iocb **swap_plug) > { > struct swap_iocb *sio = swap_plug ? *swap_plug : NULL; > - struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); > struct file *swap_file = sis->swap_file; > loff_t pos = swap_dev_pos(folio->swap); > > @@ -405,8 +407,9 @@ static void swap_writepage_fs(struct folio *folio, struct swap_iocb **swap_plug) > *swap_plug = sio; > } > > -static void swap_writepage_bdev_sync(struct folio *folio, > - struct swap_info_struct *sis) > +static void swap_writepage_bdev_sync(struct swap_info_struct *sis, > + struct folio *folio, > + struct swap_iocb **plug) > { > struct bio_vec bv; > struct bio bio; > @@ -425,8 +428,9 @@ static void swap_writepage_bdev_sync(struct folio *folio, > __end_swap_bio_write(&bio); > } > > -static void swap_writepage_bdev_async(struct folio *folio, > - struct swap_info_struct *sis) > +static void swap_writepage_bdev_async(struct swap_info_struct *sis, > + struct folio *folio, > + struct swap_iocb **plug) > { > struct bio *bio; > > @@ -442,29 +446,6 @@ static void swap_writepage_bdev_async(struct folio *folio, > submit_bio(bio); > } > > -void __swap_writepage(struct folio *folio, struct swap_iocb **swap_plug) > -{ > - struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); > - > - VM_BUG_ON_FOLIO(!folio_test_swapcache(folio), folio); > - /* > - * ->flags can be updated non-atomically (scan_swap_map_slots), > - * but that will never affect SWP_FS_OPS, so the data_race > - * is safe. > - */ > - if (data_race(sis->flags & SWP_FS_OPS)) > - swap_writepage_fs(folio, swap_plug); > - /* > - * ->flags can be updated non-atomically (scan_swap_map_slots), > - * but that will never affect SWP_SYNCHRONOUS_IO, so the data_race > - * is safe. > - */ > - else if (data_race(sis->flags & SWP_SYNCHRONOUS_IO)) > - swap_writepage_bdev_sync(folio, sis); > - else > - swap_writepage_bdev_async(folio, sis); > -} > - > void swap_write_unplug(struct swap_iocb *sio) > { > struct iov_iter from; > @@ -533,9 +514,10 @@ static bool swap_read_folio_zeromap(struct folio *folio) > return true; > } > > -static void swap_read_folio_fs(struct folio *folio, struct swap_iocb **plug) > +static void swap_read_folio_fs(struct swap_info_struct *sis, > + struct folio *folio, > + struct swap_iocb **plug) > { > - struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); > struct swap_iocb *sio = NULL; > loff_t pos = swap_dev_pos(folio->swap); > > @@ -567,8 +549,9 @@ static void swap_read_folio_fs(struct folio *folio, struct swap_iocb **plug) > *plug = sio; > } > > -static void swap_read_folio_bdev_sync(struct folio *folio, > - struct swap_info_struct *sis) > +static void swap_read_folio_bdev_sync(struct swap_info_struct *sis, > + struct folio *folio, > + struct swap_iocb **plug) > { > struct bio_vec bv; > struct bio bio; > @@ -589,8 +572,9 @@ static void swap_read_folio_bdev_sync(struct folio *folio, > put_task_struct(current); > } > > -static void swap_read_folio_bdev_async(struct folio *folio, > - struct swap_info_struct *sis) > +static void swap_read_folio_bdev_async(struct swap_info_struct *sis, > + struct folio *folio, > + struct swap_iocb **plug) > { > struct bio *bio; > > @@ -604,6 +588,44 @@ static void swap_read_folio_bdev_async(struct folio *folio, > submit_bio(bio); > } > > +static const struct swap_ops bdev_fs_swap_ops = { > + .read_folio = swap_read_folio_fs, > + .write_folio = swap_writepage_fs, > +}; > + > +static const struct swap_ops bdev_sync_swap_ops = { > + .read_folio = swap_read_folio_bdev_sync, > + .write_folio = swap_writepage_bdev_sync, > +}; > + > +static const struct swap_ops bdev_async_swap_ops = { > + .read_folio = swap_read_folio_bdev_async, > + .write_folio = swap_writepage_bdev_async, > +}; > + > +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 -1; sis->ops is always non-NULL, and you will return -1 here and swapon will always fail with -EINVAL. You probably wanted? if (!sis->ops || !sis->ops->read_folio || !sis->ops->write_folio) return -1; > + > + return 0; > +} > + > void swap_read_folio(struct folio *folio, struct swap_iocb **plug) > { > struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); > @@ -638,13 +660,7 @@ void swap_read_folio(struct folio *folio, struct swap_iocb **plug) > /* We have to read from slower devices. Increase zswap protection. */ > zswap_folio_swapin(folio); > > - if (data_race(sis->flags & SWP_FS_OPS)) { > - swap_read_folio_fs(folio, plug); > - } else if (synchronous) { > - swap_read_folio_bdev_sync(folio, sis); > - } else { > - swap_read_folio_bdev_async(folio, sis); > - } > + sis->ops->read_folio(sis, folio, plug); > > finish: > if (workingset) { > diff --git a/mm/swapfile.c b/mm/swapfile.c > index 60e21414624b..7e1660f59c00 100644 > --- a/mm/swapfile.c > +++ b/mm/swapfile.c > @@ -3413,6 +3413,11 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) > goto bad_swap_unlock_inode; > } > > + if (init_swap_ops(si)) { > + error = -EINVAL; > + goto bad_swap_unlock_inode; > + } > + > si->max = maxpages; > si->pages = maxpages - 1; > nr_extents = setup_swap_extents(si, &span); > diff --git a/mm/zswap.c b/mm/zswap.c > index 16b2ef7223e1..d8930d9054df 100644 > --- a/mm/zswap.c > +++ b/mm/zswap.c > @@ -1061,7 +1061,7 @@ static int zswap_writeback_entry(struct zswap_entry *entry, > folio_set_reclaim(folio); > > /* start writeback */ > - __swap_writepage(folio, NULL); > + si->ops->write_folio(si, folio, NULL); > > out: > if (ret && ret != -EEXIST) { > -- > 2.52.0 > > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/3] mm/swap: use swap_ops to register swap device's methods 2026-04-15 15:05 ` Usama Arif @ 2026-04-15 15:24 ` Baoquan He 0 siblings, 0 replies; 6+ messages in thread From: Baoquan He @ 2026-04-15 15:24 UTC (permalink / raw) To: Usama Arif Cc: linux-mm, akpm, baohua, chrisl, kasong, nphamcs, shikemeng, youngjun.park, linux-kernel On 04/15/26 at 08:05am, Usama Arif wrote: > On Wed, 15 Apr 2026 16:56:57 +0800 Baoquan He <baoquan.he@linux.dev> 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. > > s/opeations/operations/ Good catch, thanks. > > > > > Suggested-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 | 5 +++ > > mm/zswap.c | 2 +- > > 5 files changed, 76 insertions(+), 45 deletions(-) > > ...snip... > > diff --git a/mm/swap_io.c b/mm/swap_io.c > > index 4bf210bd677e..602e9b871b30 100644 > > --- a/mm/swap_io.c > > +++ b/mm/swap_io.c ...snip... > > @@ -604,6 +588,44 @@ static void swap_read_folio_bdev_async(struct folio *folio, > > submit_bio(bio); > > } > > > > +static const struct swap_ops bdev_fs_swap_ops = { > > + .read_folio = swap_read_folio_fs, > > + .write_folio = swap_writepage_fs, > > +}; > > + > > +static const struct swap_ops bdev_sync_swap_ops = { > > + .read_folio = swap_read_folio_bdev_sync, > > + .write_folio = swap_writepage_bdev_sync, > > +}; > > + > > +static const struct swap_ops bdev_async_swap_ops = { > > + .read_folio = swap_read_folio_bdev_async, > > + .write_folio = swap_writepage_bdev_async, > > +}; > > + > > +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 -1; > > sis->ops is always non-NULL, and you will return -1 here and > swapon will always fail with -EINVAL. > > You probably wanted? > > if (!sis->ops || !sis->ops->read_folio || !sis->ops->write_folio) > return -1; You are right. Think one thing, write another. Will fix it in v4. Thanks a lot for your careful reviewing. > > > + > > + return 0; > > +} > > + > > void swap_read_folio(struct folio *folio, struct swap_iocb **plug) > > { > > struct swap_info_struct *sis = __swap_entry_to_info(folio->swap); ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 3/3] mm/swap_io.c: rename swap_writepage_* to swap_write_folio_* 2026-04-15 8:56 [PATCH v3 0/3] mm/swap: use swap_ops to register swap device's methods Baoquan He 2026-04-15 8:56 ` [PATCH v3 1/3] mm/swap: rename mm/page_io.c to mm/swap_io.c Baoquan He 2026-04-15 8:56 ` [PATCH v3 2/3] mm/swap: use swap_ops to register swap device's methods Baoquan He @ 2026-04-15 8:56 ` Baoquan He 2 siblings, 0 replies; 6+ messages in thread From: Baoquan He @ 2026-04-15 8:56 UTC (permalink / raw) To: linux-mm Cc: akpm, baohua, chrisl, kasong, nphamcs, shikemeng, youngjun.park, linux-kernel, Baoquan He All these swap_writepage_* functions are hanlding passed in folio, but not page. And this renaming make them consistent with the 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(-) diff --git a/mm/swap_io.c b/mm/swap_io.c index 602e9b871b30..26f2daabb91f 100644 --- a/mm/swap_io.c +++ b/mm/swap_io.c @@ -370,7 +370,7 @@ static void sio_write_complete(struct kiocb *iocb, long ret) mempool_free(sio, sio_pool); } -static void swap_writepage_fs(struct swap_info_struct *sis, +static void swap_write_folio_fs(struct swap_info_struct *sis, struct folio *folio, struct swap_iocb **swap_plug) { @@ -407,7 +407,7 @@ static void swap_writepage_fs(struct swap_info_struct *sis, *swap_plug = sio; } -static void swap_writepage_bdev_sync(struct swap_info_struct *sis, +static void swap_write_folio_bdev_sync(struct swap_info_struct *sis, struct folio *folio, struct swap_iocb **plug) { @@ -428,7 +428,7 @@ static void swap_writepage_bdev_sync(struct swap_info_struct *sis, __end_swap_bio_write(&bio); } -static void swap_writepage_bdev_async(struct swap_info_struct *sis, +static void swap_write_folio_bdev_async(struct swap_info_struct *sis, struct folio *folio, struct swap_iocb **plug) { @@ -590,17 +590,17 @@ static void swap_read_folio_bdev_async(struct swap_info_struct *sis, static const struct swap_ops bdev_fs_swap_ops = { .read_folio = swap_read_folio_fs, - .write_folio = swap_writepage_fs, + .write_folio = swap_write_folio_fs, }; static const struct swap_ops bdev_sync_swap_ops = { .read_folio = swap_read_folio_bdev_sync, - .write_folio = swap_writepage_bdev_sync, + .write_folio = swap_write_folio_bdev_sync, }; static const struct swap_ops bdev_async_swap_ops = { .read_folio = swap_read_folio_bdev_async, - .write_folio = swap_writepage_bdev_async, + .write_folio = swap_write_folio_bdev_async, }; int init_swap_ops(struct swap_info_struct *sis) -- 2.52.0 ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-15 15:24 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-04-15 8:56 [PATCH v3 0/3] mm/swap: use swap_ops to register swap device's methods Baoquan He 2026-04-15 8:56 ` [PATCH v3 1/3] mm/swap: rename mm/page_io.c to mm/swap_io.c Baoquan He 2026-04-15 8:56 ` [PATCH v3 2/3] mm/swap: use swap_ops to register swap device's methods Baoquan He 2026-04-15 15:05 ` Usama Arif 2026-04-15 15:24 ` Baoquan He 2026-04-15 8:56 ` [PATCH v3 3/3] mm/swap_io.c: rename swap_writepage_* to swap_write_folio_* Baoquan He
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox