The write side now builds one bio per contiguous run. The read side still submits a bio per page. The image is read in the order it was written, so the offsets arrive in the same runs. Fill the batch for reads the same way as for writes. The compressed path queues reads ahead and then waits on the reads or on its threads. Submit the queued reads before those waits, so the last of them do not wait for more reads to fill the bio. Reading a 5G image without compression on a VM took 9 to 10% less time. Assisted-by: Claude:claude-fable-5 Assisted-by: Claude:claude-opus-5 Signed-off-by: Youngjun Park --- kernel/power/swap.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 34e47c662798..f2fc8495ddf8 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -252,7 +252,7 @@ struct hib_bio_batch { wait_queue_head_t wait; blk_status_t error; struct blk_plug plug; - struct bio *cur; /* write bio still being filled */ + struct bio *cur; /* the bio still being filled */ unsigned int max_pages; /* what the device takes at once */ unsigned int nr_pages; /* what the next bio is sized for */ }; @@ -308,7 +308,7 @@ static void hib_end_io(struct bio *bio) (unsigned long long)bio->bi_iter.bi_sector); } - /* A write bio carries as many pages as the image was contiguous for. */ + /* A bio carries as many pages as the image was contiguous for. */ bio_for_each_segment_all(bv, bio, iter_all) { struct page *page = bv->bv_page; @@ -334,19 +334,18 @@ static int hib_submit_io_sync(blk_opf_t opf, pgoff_t page_off, void *addr) } /* - * The image goes out a page at a time. Keep filling one bio for as long as - * the next page lands right after the last, so that pages that are - * consecutive on the device reach it as one request rather than as many that - * the block layer then has to merge. + * The image moves a page at a time in either direction. Keep filling one bio + * for as long as the next page lands right after the last, so that pages that + * are consecutive on the device reach it as one request rather than as many + * that the block layer then has to merge. */ static int hib_submit_io_async(blk_opf_t opf, pgoff_t page_off, void *addr, struct hib_bio_batch *hb) { sector_t sector = page_off * (PAGE_SIZE >> 9); - bool write = op_is_write(opf); struct bio *bio; - if (write && hb->cur) { + if (hb->cur) { bool contiguous = bio_end_sector(hb->cur) == sector; if (contiguous && hb->cur->bi_vcnt < hb->cur->bi_max_vecs) { @@ -367,21 +366,13 @@ static int hib_submit_io_async(blk_opf_t opf, pgoff_t page_off, void *addr, hib_submit_cur(hb); } - bio = bio_alloc(file_bdev(hib_resume_bdev_file), - write ? hb->nr_pages : 1, opf, + bio = bio_alloc(file_bdev(hib_resume_bdev_file), hb->nr_pages, opf, GFP_NOIO | __GFP_HIGH); bio->bi_iter.bi_sector = sector; bio_add_virt_nofail(bio, addr, PAGE_SIZE); bio->bi_end_io = hib_end_io; bio->bi_private = hb; - - if (write) { - hb->cur = bio; - return 0; - } - - atomic_inc(&hb->count); - submit_bio(bio); + hb->cur = bio; return 0; } @@ -1477,6 +1468,12 @@ static int load_compressed_image(struct swap_map_handle *handle, asked += i; want -= i; + /* + * Submit the reads queued above now. Otherwise the last of + * them can wait in the bio until more reads fill it. + */ + hib_submit_cur(&hb); + /* * We are out of data, wait for some more. */ -- 2.48.1