From: Baoquan He <baoquan.he@linux.dev>
To: Christoph Hellwig <hch@lst.de>
Cc: akpm@linux-foundation.org, chrisl@kernel.org,
usama.arif@linux.dev, kasong@tencent.com, nphamcs@gmail.com,
shikemeng@huaweicloud.com, youngjun.park@lge.com,
linux-mm@kvack.org
Subject: Re: [PATCH 3/8] mm/swap: introduce struct swap_io_ctx
Date: Thu, 4 Jun 2026 18:58:34 +0800 [thread overview]
Message-ID: <aiFaWmCWgEWAFj4W@MiWiFi-R3L-srv> (raw)
In-Reply-To: <20260601113449.3464734-4-hch@lst.de>
On 06/01/26 at 01:34pm, Christoph Hellwig wrote:
> Generalize the context currently provided by double pointers to struct
> swap_iocb to an on-stack context. This cleans up the code and prepares
> for adding more fields and supporting batching multiple folios into a
> single bio for block-based swap as well.
>
> This new swap_io_ctx is required for all functions using it, the old
> way of allowing a NULL iocb for some callers is removed to keep the
> interface consistent.
In this patch, except of introducng struct swap_io_ctx, it also does:
- swap_cache_read_folio_sync() helper introduced for the two readahead
"skip" paths where the target page was already read
- swap_write_unplug → swap_write_submit,
__swap_read_unplug → swap_read_submit;
the NULL-checking inline swap_read_unplug() wrapper is removed
It would be better if these are mentioned in log too, or should be split
into a separate patch. Otherwise it doesn't match the subject.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> mm/madvise.c | 16 ++++++-------
> mm/page_io.c | 60 ++++++++++++++++++++++++++-----------------------
> mm/shmem.c | 13 +++++++----
> mm/swap.h | 36 +++++++++++++----------------
> mm/swap_state.c | 53 +++++++++++++++++++++++++------------------
> mm/vmscan.c | 15 ++++++-------
> mm/zswap.c | 4 +++-
> 7 files changed, 106 insertions(+), 91 deletions(-)
>
> diff --git a/mm/madvise.c b/mm/madvise.c
> index cd9bb077072c..cd84e993190a 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
> @@ -188,7 +188,7 @@ static int swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start,
> unsigned long end, struct mm_walk *walk)
> {
> struct vm_area_struct *vma = walk->private;
> - struct swap_iocb *splug = NULL;
> + struct swap_io_ctx ctx = {};
> pte_t *ptep = NULL;
> spinlock_t *ptl;
> unsigned long addr;
> @@ -212,15 +212,15 @@ static int swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start,
> pte_unmap_unlock(ptep, ptl);
> ptep = NULL;
>
> - folio = read_swap_cache_async(entry, GFP_HIGHUSER_MOVABLE,
> - vma, addr, &splug);
> + folio = read_swap_cache_async(&ctx, entry, GFP_HIGHUSER_MOVABLE,
> + vma, addr);
And I am wondering why &ctx has to be put as the 1st para, is there a
rule of C language or linux kernel? It obviously adds a lot of
unnecessary code churn. I will read swap cache, of course swap entry is
the main subject I will operate on, why bother moving &ctx which is
associated date at first.
> if (folio)
> folio_put(folio);
> }
>
> if (ptep)
> pte_unmap_unlock(ptep, ptl);
> - swap_read_unplug(splug);
> + swap_read_submit(&ctx);
> cond_resched();
>
> return 0;
> @@ -238,7 +238,7 @@ static void shmem_swapin_range(struct vm_area_struct *vma,
> XA_STATE(xas, &mapping->i_pages, linear_page_index(vma, start));
> pgoff_t end_index = linear_page_index(vma, end) - 1;
> struct folio *folio;
> - struct swap_iocb *splug = NULL;
> + struct swap_io_ctx ctx = {};
>
> rcu_read_lock();
> xas_for_each(&xas, folio, end_index) {
> @@ -257,15 +257,15 @@ static void shmem_swapin_range(struct vm_area_struct *vma,
> xas_pause(&xas);
> rcu_read_unlock();
>
> - folio = read_swap_cache_async(entry, mapping_gfp_mask(mapping),
> - vma, addr, &splug);
> + folio = read_swap_cache_async(&ctx, entry,
> + mapping_gfp_mask(mapping), vma, addr);
> if (folio)
> folio_put(folio);
>
> rcu_read_lock();
> }
> rcu_read_unlock();
> - swap_read_unplug(splug);
> + swap_read_submit(&ctx);
> }
> #endif /* CONFIG_SWAP */
>
> diff --git a/mm/page_io.c b/mm/page_io.c
> index f2d8fe7fd057..0bf035dc1170 100644
> --- a/mm/page_io.c
> +++ b/mm/page_io.c
> @@ -248,7 +248,7 @@ static void swap_zeromap_folio_clear(struct folio *folio)
> * We may have stale swap cache pages in memory: notice
> * them here and get rid of the unnecessary final write.
> */
> -int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug)
> +int swap_writeout(struct swap_io_ctx *ctx, struct folio *folio)
> {
> int ret = 0;
>
> @@ -295,7 +295,7 @@ int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug)
> }
> rcu_read_unlock();
>
> - __swap_writepage(folio, swap_plug);
> + __swap_writepage(ctx, folio);
> return 0;
> out_unlock:
> folio_unlock(folio);
> @@ -385,9 +385,9 @@ 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_io_ctx *ctx, struct folio *folio)
> {
> - struct swap_iocb *sio = swap_plug ? *swap_plug : NULL;
> + struct swap_iocb *sio = ctx->sio;
> 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);
> @@ -398,7 +398,7 @@ static void swap_writepage_fs(struct folio *folio, struct swap_iocb **swap_plug)
> if (sio) {
> if (sio->iocb.ki_filp != swap_file ||
> sio->iocb.ki_pos + sio->len != pos) {
> - swap_write_unplug(sio);
> + swap_write_submit(ctx);
> sio = NULL;
> }
> }
> @@ -413,12 +413,11 @@ static void swap_writepage_fs(struct folio *folio, struct swap_iocb **swap_plug)
> bvec_set_folio(&sio->bvecs[sio->nr_bvecs], folio, folio_size(folio), 0);
> sio->len += folio_size(folio);
> sio->nr_bvecs += 1;
> - if (sio->nr_bvecs == ARRAY_SIZE(sio->bvecs) || !swap_plug) {
> - swap_write_unplug(sio);
> + if (sio->nr_bvecs == ARRAY_SIZE(sio->bvecs)) {
> + swap_write_submit(ctx);
> sio = NULL;
> }
> - if (swap_plug)
> - *swap_plug = sio;
> + ctx->sio = sio;
> }
>
> static void swap_writepage_bdev_sync(struct folio *folio,
> @@ -458,7 +457,7 @@ static void swap_writepage_bdev_async(struct folio *folio,
> submit_bio(bio);
> }
>
> -void __swap_writepage(struct folio *folio, struct swap_iocb **swap_plug)
> +void __swap_writepage(struct swap_io_ctx *ctx, struct folio *folio)
> {
> struct swap_info_struct *sis = __swap_entry_to_info(folio->swap);
>
> @@ -469,7 +468,7 @@ void __swap_writepage(struct folio *folio, struct swap_iocb **swap_plug)
> * is safe.
> */
> if (data_race(sis->flags & SWP_FS_OPS))
> - swap_writepage_fs(folio, swap_plug);
> + swap_writepage_fs(ctx, folio);
> /*
> * ->flags can be updated non-atomically,
> * but that will never affect SWP_SYNCHRONOUS_IO, so the data_race
> @@ -481,16 +480,20 @@ void __swap_writepage(struct folio *folio, struct swap_iocb **swap_plug)
> swap_writepage_bdev_async(folio, sis);
> }
>
> -void swap_write_unplug(struct swap_iocb *sio)
> +void swap_write_submit(struct swap_io_ctx *ctx)
> {
> + struct swap_iocb *sio = ctx->sio;
> struct iov_iter from;
> - struct address_space *mapping = sio->iocb.ki_filp->f_mapping;
> int ret;
>
> + if (!sio)
> + return;
> +
> iov_iter_bvec(&from, ITER_SOURCE, sio->bvecs, sio->nr_bvecs, sio->len);
> - ret = mapping->a_ops->swap_rw(&sio->iocb, &from);
> + ret = sio->iocb.ki_filp->f_mapping->a_ops->swap_rw(&sio->iocb, &from);
> if (ret != -EIOCBQUEUED)
> sio_write_complete(&sio->iocb, ret);
> + ctx->sio = NULL;
> }
>
> static void sio_read_complete(struct kiocb *iocb, long ret)
> @@ -582,18 +585,16 @@ 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_io_ctx *ctx, struct folio *folio)
> {
> struct swap_info_struct *sis = __swap_entry_to_info(folio->swap);
> - struct swap_iocb *sio = NULL;
> + struct swap_iocb *sio = ctx->sio;
> loff_t pos = swap_dev_pos(folio->swap);
>
> - if (plug)
> - sio = *plug;
> if (sio) {
> if (sio->iocb.ki_filp != sis->swap_file ||
> sio->iocb.ki_pos + sio->len != pos) {
> - swap_read_unplug(sio);
> + swap_read_submit(ctx);
> sio = NULL;
> }
> }
> @@ -608,12 +609,11 @@ static void swap_read_folio_fs(struct folio *folio, struct swap_iocb **plug)
> bvec_set_folio(&sio->bvecs[sio->nr_bvecs], folio, folio_size(folio), 0);
> sio->len += folio_size(folio);
> sio->nr_bvecs += 1;
> - if (sio->nr_bvecs == ARRAY_SIZE(sio->bvecs) || !plug) {
> - swap_read_unplug(sio);
> + if (sio->nr_bvecs == ARRAY_SIZE(sio->bvecs)) {
> + swap_read_submit(ctx);
> sio = NULL;
> }
> - if (plug)
> - *plug = sio;
> + ctx->sio = sio;
> }
>
> static void swap_read_folio_bdev_sync(struct folio *folio,
> @@ -653,7 +653,7 @@ static void swap_read_folio_bdev_async(struct folio *folio,
> submit_bio(bio);
> }
>
> -void swap_read_folio(struct folio *folio, struct swap_iocb **plug)
> +void swap_read_folio(struct swap_io_ctx *ctx, struct folio *folio)
> {
> struct swap_info_struct *sis = __swap_entry_to_info(folio->swap);
> bool synchronous = sis->flags & SWP_SYNCHRONOUS_IO;
> @@ -688,7 +688,7 @@ void swap_read_folio(struct folio *folio, struct swap_iocb **plug)
> zswap_folio_swapin(folio);
>
> if (data_race(sis->flags & SWP_FS_OPS)) {
> - swap_read_folio_fs(folio, plug);
> + swap_read_folio_fs(ctx, folio);
> } else if (synchronous) {
> swap_read_folio_bdev_sync(folio, sis);
> } else {
> @@ -703,14 +703,18 @@ void swap_read_folio(struct folio *folio, struct swap_iocb **plug)
> delayacct_swapin_end();
> }
>
> -void __swap_read_unplug(struct swap_iocb *sio)
> +void swap_read_submit(struct swap_io_ctx *ctx)
> {
> + struct swap_iocb *sio = ctx->sio;
> struct iov_iter from;
> - struct address_space *mapping = sio->iocb.ki_filp->f_mapping;
> int ret;
>
> + if (!sio)
> + return;
> +
> iov_iter_bvec(&from, ITER_DEST, sio->bvecs, sio->nr_bvecs, sio->len);
> - ret = mapping->a_ops->swap_rw(&sio->iocb, &from);
> + ret = sio->iocb.ki_filp->f_mapping->a_ops->swap_rw(&sio->iocb, &from);
> if (ret != -EIOCBQUEUED)
> sio_read_complete(&sio->iocb, ret);
> + ctx->sio = NULL;
> }
> diff --git a/mm/shmem.c b/mm/shmem.c
> index d10735e49b25..17eb16dbfaa9 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1584,13 +1584,13 @@ int shmem_unuse(unsigned int type)
>
> /**
> * shmem_writeout - Write the folio to swap
> + * @ctx: swap I/O context
> * @folio: The folio to write
> - * @plug: swap plug
> * @folio_list: list to put back folios on split
> *
> * Move the folio from the page cache to the swap cache.
> */
> -int shmem_writeout(struct folio *folio, struct swap_iocb **plug,
> +int shmem_writeout(struct swap_io_ctx *ctx, struct folio *folio,
> struct list_head *folio_list)
> {
> struct address_space *mapping = folio->mapping;
> @@ -1702,7 +1702,7 @@ int shmem_writeout(struct folio *folio, struct swap_iocb **plug,
> shmem_delete_from_page_cache(folio, swp_to_radix_entry(folio->swap));
>
> BUG_ON(folio_mapped(folio));
> - error = swap_writeout(folio, plug);
> + error = swap_writeout(ctx, folio);
> if (error != AOP_WRITEPAGE_ACTIVATE) {
> /* folio has been unlocked */
> return error;
> @@ -1741,7 +1741,12 @@ int shmem_writeout(struct folio *folio, struct swap_iocb **plug,
>
> int shmem_write_folio(struct folio *folio)
> {
> - return shmem_writeout(folio, NULL, NULL);
> + struct swap_io_ctx ctx = {};
> + int err;
> +
> + err = shmem_writeout(&ctx, folio, NULL);
> + swap_write_submit(&ctx);
> + return err;
> }
> EXPORT_SYMBOL_GPL(shmem_write_folio);
>
> diff --git a/mm/swap.h b/mm/swap.h
> index 4f86ef338a60..79d66272dfd4 100644
> --- a/mm/swap.h
> +++ b/mm/swap.h
> @@ -4,6 +4,7 @@
>
> #include <linux/atomic.h> /* for atomic_long_t */
> #include <linux/mm.h> /* for PAGE_SHIFT */
> +
> struct mempolicy;
> struct swap_iocb;
> struct swap_memcg_table;
> @@ -78,6 +79,10 @@ enum swap_cluster_flags {
> CLUSTER_FLAG_MAX,
> };
>
> +struct swap_io_ctx {
> + struct swap_iocb *sio;
> +};
> +
> #ifdef CONFIG_SWAP
> #include <linux/swapops.h> /* for swp_offset */
> #include <linux/blk_types.h> /* for bio_end_io_t */
> @@ -240,17 +245,11 @@ extern void __swap_cluster_free_entries(struct swap_info_struct *si,
>
> /* linux/mm/page_io.c */
> int sio_pool_init(void);
> -struct swap_iocb;
> -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)
> -{
> - if (unlikely(plug))
> - __swap_read_unplug(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);
> +void swap_read_folio(struct swap_io_ctx *ctx, struct folio *folio);
> +void swap_read_submit(struct swap_io_ctx *ctx);
> +void swap_write_submit(struct swap_io_ctx *ctx);
> +int swap_writeout(struct swap_io_ctx *ctx, struct folio *folio);
> +void __swap_writepage(struct swap_io_ctx *ctx, struct folio *folio);
>
> /* linux/mm/swap_state.c */
> extern struct address_space swap_space __read_mostly;
> @@ -317,9 +316,8 @@ void __swap_cache_replace_folio(struct swap_cluster_info *ci,
>
> void show_swap_cache_info(void);
> void swapcache_clear(struct swap_info_struct *si, swp_entry_t entry, int nr);
> -struct folio *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
> - struct vm_area_struct *vma, unsigned long addr,
> - struct swap_iocb **plug);
> +struct folio *read_swap_cache_async(struct swap_io_ctx *ctx, swp_entry_t entry,
> + gfp_t gfp_mask, struct vm_area_struct *vma, unsigned long addr);
> struct folio *swap_cluster_readahead(swp_entry_t entry, gfp_t flag,
> struct mempolicy *mpol, pgoff_t ilx);
> struct folio *swapin_readahead(swp_entry_t entry, gfp_t flag,
> @@ -335,7 +333,6 @@ static inline unsigned int folio_swap_flags(struct folio *folio)
> }
>
> #else /* CONFIG_SWAP */
> -struct swap_iocb;
> static inline struct swap_cluster_info *swap_cluster_lock(
> struct swap_info_struct *si, pgoff_t offset, bool irq)
> {
> @@ -381,11 +378,11 @@ static inline void folio_put_swap(struct folio *folio, struct page *page)
> {
> }
>
> -static inline void swap_read_folio(struct folio *folio, struct swap_iocb **plug)
> +static inline void swap_read_folio(struct swap_io_ctx *ctx, struct folio *folio)
> {
> }
>
> -static inline void swap_write_unplug(struct swap_iocb *sio)
> +static inline void swap_write_submit(struct swap_io_ctx *ctx)
> {
> }
>
> @@ -427,8 +424,7 @@ static inline void swap_update_readahead(struct folio *folio,
> {
> }
>
> -static inline int swap_writeout(struct folio *folio,
> - struct swap_iocb **swap_plug)
> +static inline int swap_writeout(struct swap_io_ctx *ctx, struct folio *folio)
> {
> return 0;
> }
> @@ -474,7 +470,7 @@ static inline unsigned int folio_swap_flags(struct folio *folio)
>
> #endif /* CONFIG_SWAP */
>
> -int shmem_writeout(struct folio *folio, struct swap_iocb **plug,
> +int shmem_writeout(struct swap_io_ctx *ctx, struct folio *folio,
> struct list_head *folio_list);
>
> #endif /* _MM_SWAP_H */
> diff --git a/mm/swap_state.c b/mm/swap_state.c
> index 04f5ce992401..b9613026950e 100644
> --- a/mm/swap_state.c
> +++ b/mm/swap_state.c
> @@ -623,9 +623,9 @@ void swap_update_readahead(struct folio *folio, struct vm_area_struct *vma,
> }
> }
>
> -static struct folio *swap_cache_read_folio(swp_entry_t entry, gfp_t gfp,
> - struct mempolicy *mpol, pgoff_t ilx,
> - struct swap_iocb **plug, bool readahead)
> +static struct folio *swap_cache_read_folio(struct swap_io_ctx *ctx,
> + swp_entry_t entry, gfp_t gfp, struct mempolicy *mpol,
> + pgoff_t ilx, bool readahead)
> {
> struct folio *folio;
>
> @@ -639,7 +639,7 @@ static struct folio *swap_cache_read_folio(swp_entry_t entry, gfp_t gfp,
> if (IS_ERR_OR_NULL(folio))
> return NULL;
>
> - swap_read_folio(folio, plug);
> + swap_read_folio(ctx, folio);
> if (readahead) {
> folio_set_readahead(folio);
> count_vm_event(SWAP_RA);
> @@ -667,6 +667,7 @@ static struct folio *swap_cache_read_folio(swp_entry_t entry, gfp_t gfp,
> struct folio *swapin_sync(swp_entry_t entry, gfp_t gfp, unsigned long orders,
> struct vm_fault *vmf, struct mempolicy *mpol, pgoff_t ilx)
> {
> + struct swap_io_ctx ctx = {};
> struct folio *folio;
>
> do {
> @@ -679,7 +680,8 @@ struct folio *swapin_sync(swp_entry_t entry, gfp_t gfp, unsigned long orders,
> if (IS_ERR(folio))
> return folio;
>
> - swap_read_folio(folio, NULL);
> + swap_read_folio(&ctx, folio);
> + swap_read_submit(&ctx);
> return folio;
> }
>
> @@ -689,9 +691,8 @@ struct folio *swapin_sync(swp_entry_t entry, gfp_t gfp, unsigned long orders,
> * A failure return means that either the page allocation failed or that
> * the swap entry is no longer in use.
> */
> -struct folio *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
> - struct vm_area_struct *vma, unsigned long addr,
> - struct swap_iocb **plug)
> +struct folio *read_swap_cache_async(struct swap_io_ctx *ctx, swp_entry_t entry,
> + gfp_t gfp_mask, struct vm_area_struct *vma, unsigned long addr)
> {
> struct swap_info_struct *si;
> struct mempolicy *mpol;
> @@ -703,13 +704,24 @@ struct folio *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
> return NULL;
>
> mpol = get_vma_policy(vma, addr, 0, &ilx);
> - folio = swap_cache_read_folio(entry, gfp_mask, mpol, ilx, plug, false);
> + folio = swap_cache_read_folio(ctx, entry, gfp_mask, mpol, ilx, false);
> mpol_cond_put(mpol);
>
> put_swap_device(si);
> return folio;
> }
>
> +static struct folio *swap_cache_read_folio_sync(swp_entry_t entry, gfp_t gfp,
> + struct mempolicy *mpol, pgoff_t ilx)
> +{
> + struct swap_io_ctx ctx = {};
> + struct folio *folio;
> +
> + folio = swap_cache_read_folio(&ctx, entry, gfp, mpol, ilx, false);
> + swap_read_submit(&ctx);
> + return folio;
> +}
> +
> static unsigned int __swapin_nr_pages(unsigned long prev_offset,
> unsigned long offset,
> int hits,
> @@ -798,8 +810,8 @@ struct folio *swap_cluster_readahead(swp_entry_t entry, gfp_t gfp_mask,
> unsigned long start_offset, end_offset;
> unsigned long mask;
> struct swap_info_struct *si = __swap_entry_to_info(entry);
> + struct swap_io_ctx ctx = {};
> struct blk_plug plug;
> - struct swap_iocb *splug = NULL;
> swp_entry_t ra_entry;
>
> mask = swapin_nr_pages(offset) - 1;
> @@ -818,18 +830,17 @@ struct folio *swap_cluster_readahead(swp_entry_t entry, gfp_t gfp_mask,
> for (offset = start_offset; offset <= end_offset ; offset++) {
> /* Ok, do the async read-ahead now */
> ra_entry = swp_entry(swp_type(entry), offset);
> - folio = swap_cache_read_folio(ra_entry, gfp_mask, mpol, ilx,
> - &splug, offset != entry_offset);
> + folio = swap_cache_read_folio(&ctx, ra_entry, gfp_mask, mpol,
> + ilx, offset != entry_offset);
> if (!folio)
> continue;
> folio_put(folio);
> }
> blk_finish_plug(&plug);
> - swap_read_unplug(splug);
> + swap_read_submit(&ctx);
> lru_add_drain(); /* Push any new pages onto the LRU now */
> skip:
> - /* The page was likely read above, so no need for plugging here */
> - return swap_cache_read_folio(entry, gfp_mask, mpol, ilx, NULL, false);
> + return swap_cache_read_folio_sync(entry, gfp_mask, mpol, ilx);
> }
>
> static int swap_vma_ra_win(struct vm_fault *vmf, unsigned long *start,
> @@ -889,8 +900,8 @@ static int swap_vma_ra_win(struct vm_fault *vmf, unsigned long *start,
> static struct folio *swap_vma_readahead(swp_entry_t targ_entry, gfp_t gfp_mask,
> struct mempolicy *mpol, pgoff_t targ_ilx, struct vm_fault *vmf)
> {
> + struct swap_io_ctx ctx = {};
> struct blk_plug plug;
> - struct swap_iocb *splug = NULL;
> struct folio *folio;
> pte_t *pte = NULL, pentry;
> int win;
> @@ -929,8 +940,8 @@ static struct folio *swap_vma_readahead(swp_entry_t targ_entry, gfp_t gfp_mask,
> if (!si)
> continue;
> }
> - folio = swap_cache_read_folio(entry, gfp_mask, mpol, ilx,
> - &splug, addr != vmf->address);
> + folio = swap_cache_read_folio(&ctx, entry, gfp_mask, mpol, ilx,
> + addr != vmf->address);
> if (si)
> put_swap_device(si);
> if (!folio)
> @@ -940,13 +951,11 @@ static struct folio *swap_vma_readahead(swp_entry_t targ_entry, gfp_t gfp_mask,
> if (pte)
> pte_unmap(pte);
> blk_finish_plug(&plug);
> - swap_read_unplug(splug);
> + swap_read_submit(&ctx);
> lru_add_drain();
> skip:
> /* The folio was likely read above, so no need for plugging here */
> - folio = swap_cache_read_folio(targ_entry, gfp_mask, mpol, targ_ilx,
> - NULL, false);
> - return folio;
> + return swap_cache_read_folio_sync(targ_entry, gfp_mask, mpol, targ_ilx);
> }
>
> /**
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index d7303eea1265..c43177a8e4dd 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -615,8 +615,8 @@ typedef enum {
> /*
> * pageout is called by shrink_folio_list() for each dirty folio.
> */
> -static pageout_t pageout(struct folio *folio, struct address_space *mapping,
> - struct swap_iocb **plug, struct list_head *folio_list)
> +static pageout_t pageout(struct swap_io_ctx *ctx, struct address_space *mapping,
> + struct folio *folio, struct list_head *folio_list)
> {
> int res;
>
> @@ -652,9 +652,9 @@ static pageout_t pageout(struct folio *folio, struct address_space *mapping,
> * the split out folios get added back to folio_list.
> */
> if (shmem_mapping(mapping))
> - res = shmem_writeout(folio, plug, folio_list);
> + res = shmem_writeout(ctx, folio, folio_list);
> else
> - res = swap_writeout(folio, plug);
> + res = swap_writeout(ctx, folio);
>
> if (res < 0)
> handle_write_error(mapping, folio, res);
> @@ -1063,7 +1063,7 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
> unsigned int nr_reclaimed = 0, nr_demoted = 0;
> unsigned int pgactivate = 0;
> bool do_demote_pass;
> - struct swap_iocb *plug = NULL;
> + struct swap_io_ctx ctx = {};
>
> folio_batch_init(&free_folios);
> memset(stat, 0, sizeof(*stat));
> @@ -1394,7 +1394,7 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
> * starts and then write it out here.
> */
> try_to_unmap_flush_dirty();
> - switch (pageout(folio, mapping, &plug, folio_list)) {
> + switch (pageout(&ctx, mapping, folio, folio_list)) {
> case PAGE_KEEP:
> goto keep_locked;
> case PAGE_ACTIVATE:
> @@ -1584,8 +1584,7 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
> list_splice(&ret_folios, folio_list);
> count_vm_events(PGACTIVATE, pgactivate);
>
> - if (plug)
> - swap_write_unplug(plug);
> + swap_write_submit(&ctx);
> return nr_reclaimed;
> }
>
> diff --git a/mm/zswap.c b/mm/zswap.c
> index 761cd699e0a3..feed2557f6ed 100644
> --- a/mm/zswap.c
> +++ b/mm/zswap.c
> @@ -992,6 +992,7 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
> struct folio *folio;
> struct mempolicy *mpol;
> struct swap_info_struct *si;
> + struct swap_io_ctx ctx = {};
> int ret = 0;
>
> /* try to allocate swap cache folio */
> @@ -1049,7 +1050,8 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
> folio_set_reclaim(folio);
>
> /* start writeback */
> - __swap_writepage(folio, NULL);
> + __swap_writepage(&ctx, folio);
> + swap_write_submit(&ctx);
>
> out:
> if (ret) {
> --
> 2.53.0
>
next prev parent reply other threads:[~2026-06-04 10:58 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-01 11:34 better block swap batching and a different take on swap_ops v2 Christoph Hellwig
2026-06-01 11:34 ` [PATCH 1/8] shmem: provide a shmem_write_folio wrapper Christoph Hellwig
2026-06-04 9:43 ` Baoquan He
2026-06-05 17:07 ` Nhat Pham
2026-06-01 11:34 ` [PATCH 2/8] mm: merge writeout into pageout Christoph Hellwig
2026-06-04 9:44 ` Baoquan He
2026-06-05 17:07 ` Nhat Pham
2026-06-01 11:34 ` [PATCH 3/8] mm/swap: introduce struct swap_io_ctx Christoph Hellwig
2026-06-04 10:58 ` Baoquan He [this message]
2026-06-05 17:41 ` Nhat Pham
2026-06-01 11:34 ` [PATCH 4/8] mm/swap: also use struct swap_iocb for block I/O Christoph Hellwig
2026-06-04 10:59 ` Baoquan He
2026-06-04 11:37 ` Baoquan He
2026-06-01 11:34 ` [PATCH 5/8] mm/swap: remove count_swpout_vm_event Christoph Hellwig
2026-06-04 11:37 ` Baoquan He
2026-06-05 17:50 ` Nhat Pham
2026-06-01 11:34 ` [PATCH 6/8] mm/swap: use swap_ops to register swap device's methods Christoph Hellwig
2026-06-05 17:53 ` Nhat Pham
2026-06-01 11:34 ` [PATCH 7/8] mm/swap: remove SWP_FS_OPS Christoph Hellwig
2026-06-05 5:21 ` Baoquan He
2026-06-05 17:58 ` Nhat Pham
2026-06-01 11:34 ` [PATCH 8/8] mm/vmstat: add NRSWP{IN,OUT} counters Christoph Hellwig
2026-06-05 7:16 ` Baoquan He
2026-06-05 17:48 ` Nhat Pham
2026-06-01 13:29 ` better block swap batching and a different take on swap_ops v2 Baoquan He
2026-06-01 14:50 ` Christoph Hellwig
2026-06-01 15:17 ` Baoquan He
2026-06-01 15:25 ` Christoph Hellwig
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=aiFaWmCWgEWAFj4W@MiWiFi-R3L-srv \
--to=baoquan.he@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=chrisl@kernel.org \
--cc=hch@lst.de \
--cc=kasong@tencent.com \
--cc=linux-mm@kvack.org \
--cc=nphamcs@gmail.com \
--cc=shikemeng@huaweicloud.com \
--cc=usama.arif@linux.dev \
--cc=youngjun.park@lge.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.