swap: fix swapfile read/write offset

commit caf6912f3f upstream.

We're not factoring in the start of the file for where to write and
read the swapfile, which leads to very unfortunate side effects of
writing where we should not be...

[This issue only affects swapfiles on filesystems on top of blockdevs
that implement rw_page ops (brd, zram, btt, pmem), and not on top of any
other block devices, in contrast to the upstream commit fix.]

Fixes: dd6bd0d9c7 ("swap: use bdev_read_page() / bdev_write_page()")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Cc: stable@vger.kernel.org # 4.9
Signed-off-by: Anthony Iliopoulos <ailiop@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Jens Axboe 2021-03-02 14:53:21 -07:00 committed by Greg Kroah-Hartman
parent d72be3a8e5
commit da4e1e3f62
2 changed files with 4 additions and 9 deletions

View File

@ -32,7 +32,6 @@ static struct bio *get_swap_bio(gfp_t gfp_flags,
bio = bio_alloc(gfp_flags, 1);
if (bio) {
bio->bi_iter.bi_sector = map_swap_page(page, &bio->bi_bdev);
bio->bi_iter.bi_sector <<= PAGE_SHIFT - 9;
bio->bi_end_io = end_io;
bio_add_page(bio, page, PAGE_SIZE, 0);
@ -252,11 +251,6 @@ out:
return ret;
}
static sector_t swap_page_sector(struct page *page)
{
return (sector_t)__page_file_index(page) << (PAGE_SHIFT - 9);
}
int __swap_writepage(struct page *page, struct writeback_control *wbc,
bio_end_io_t end_write_func)
{
@ -306,7 +300,8 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc,
return ret;
}
ret = bdev_write_page(sis->bdev, swap_page_sector(page), page, wbc);
ret = bdev_write_page(sis->bdev, map_swap_page(page, &sis->bdev),
page, wbc);
if (!ret) {
count_vm_event(PSWPOUT);
return 0;
@ -357,7 +352,7 @@ int swap_readpage(struct page *page)
return ret;
}
ret = bdev_read_page(sis->bdev, swap_page_sector(page), page);
ret = bdev_read_page(sis->bdev, map_swap_page(page, &sis->bdev), page);
if (!ret) {
if (trylock_page(page)) {
swap_slot_free_notify(page);

View File

@ -1666,7 +1666,7 @@ sector_t map_swap_page(struct page *page, struct block_device **bdev)
{
swp_entry_t entry;
entry.val = page_private(page);
return map_swap_entry(entry, bdev);
return map_swap_entry(entry, bdev) << (PAGE_SHIFT - 9);
}
/*