diff --git a/include/linux/swap.h b/include/linux/swap.h index b4b1c0a84c8b..5979b1427368 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -276,6 +276,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/page_io.c b/mm/page_io.c index 56f21e49572e..c36b44ffe947 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -334,21 +334,7 @@ static bool swap_can_merge(struct swap_io_ctx *ctx, struct folio *folio, if (ctx->sis != sis) return false; - - if (sis->flags & SWP_FS_OPS) { - if (swap_dev_pos(folio->swap) != - swap_dev_pos(prev_folio->swap) + prev_folio_size) - return false; - } else { - if (swap_folio_sector(folio) != - swap_folio_sector(prev_folio) + - (prev_folio_size >> SECTOR_SHIFT)) - return false; - if (rw == WRITE && !folio_blkg_can_merge(folio, prev_folio)) - return false; - } - - return true; + return sis->ops->can_merge(folio, prev_folio, prev_folio_size, rw); } static void swap_add_folio(struct swap_io_ctx *ctx, struct folio *folio, int rw) @@ -646,6 +632,23 @@ static void swap_bdev_submit_read(struct swap_io_ctx *ctx) } } +static bool swap_bdev_can_merge(struct folio *folio, struct folio *prev_folio, + size_t prev_folio_size, int rw) +{ + if (swap_folio_sector(folio) != + swap_folio_sector(prev_folio) + (prev_folio_size >> SECTOR_SHIFT)) + return false; + if (rw == WRITE && !folio_blkg_can_merge(folio, prev_folio)) + return false; + return true; +} + +const struct swap_ops swap_bdev_ops = { + .submit_write = swap_bdev_submit_write, + .submit_read = swap_bdev_submit_read, + .can_merge = swap_bdev_can_merge, +}; + static void swap_fs_submit(struct swap_io_ctx *ctx, int rw) { struct swap_iocb *sio = ctx->sio; @@ -666,15 +669,34 @@ static void swap_fs_submit(struct swap_io_ctx *ctx, int rw) sio->iocb.ki_complete(&sio->iocb, ret); } +static void swap_fs_submit_write(struct swap_io_ctx *ctx) +{ + swap_fs_submit(ctx, WRITE); +} + +static void swap_fs_submit_read(struct swap_io_ctx *ctx) +{ + swap_fs_submit(ctx, READ); +} + +static bool swap_fs_can_merge(struct folio *folio, struct folio *prev_folio, + size_t prev_folio_size, int rw) +{ + return swap_dev_pos(folio->swap) == + swap_dev_pos(prev_folio->swap) + prev_folio_size; +} + +const struct swap_ops swap_fs_ops = { + .submit_write = swap_fs_submit_write, + .submit_read = swap_fs_submit_read, + .can_merge = swap_fs_can_merge, +}; + void swap_write_submit(struct swap_io_ctx *ctx) { if (!ctx->sio) return; - - if (ctx->sis->flags & SWP_FS_OPS) - swap_fs_submit(ctx, WRITE); - else - swap_bdev_submit_write(ctx); + ctx->sis->ops->submit_write(ctx); ctx->sio = NULL; ctx->sis = NULL; } @@ -683,11 +705,7 @@ void swap_read_submit(struct swap_io_ctx *ctx) { if (!ctx->sio) return; - - if (ctx->sis->flags & SWP_FS_OPS) - swap_fs_submit(ctx, READ); - else - swap_bdev_submit_read(ctx); + ctx->sis->ops->submit_read(ctx); ctx->sio = NULL; ctx->sis = NULL; } diff --git a/mm/swap.h b/mm/swap.h index 86b2a241b734..ffc36695d4ac 100644 --- a/mm/swap.h +++ b/mm/swap.h @@ -96,6 +96,13 @@ struct swap_io_ctx { struct swap_info_struct *sis; }; +struct swap_ops { + bool (*can_merge)(struct folio *folio, struct folio *prev_folio, + size_t prev_folio_size, int rw); + void (*submit_write)(struct swap_io_ctx *ctx); + void (*submit_read)(struct swap_io_ctx *ctx); +}; + #ifdef CONFIG_SWAP #include /* for swp_offset */ #include /* for bio_end_io_t */ @@ -483,6 +490,9 @@ static inline unsigned int folio_swap_flags(struct folio *folio) #endif /* CONFIG_SWAP */ +extern const struct swap_ops swap_bdev_ops; +extern const struct swap_ops swap_fs_ops; + int shmem_writeout(struct swap_io_ctx *ctx, struct folio *folio, struct list_head *folio_list); diff --git a/mm/swapfile.c b/mm/swapfile.c index be75c995c49b..ad623dae483b 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2963,6 +2963,8 @@ static int setup_swap_extents(struct swap_info_struct *sis, if (ret) return ret; + sis->ops = &swap_bdev_ops; + if (S_ISBLK(inode->i_mode)) { ret = add_swap_extent(sis, 0, sis->max, 0); *span = sis->pages; @@ -2973,6 +2975,8 @@ static int setup_swap_extents(struct swap_info_struct *sis, ret = mapping->a_ops->swap_activate(sis, swap_file, span); if (ret < 0) return ret; + if (sis->flags & SWP_FS_OPS) + sis->ops = &swap_fs_ops; sis->flags |= SWP_ACTIVATED; return ret; }