All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] swap: fix swapfile read/write offset
@ 2021-03-02 22:36 Jens Axboe
  2021-03-03 15:46 ` Anthony Iliopoulos
  0 siblings, 1 reply; 4+ messages in thread
From: Jens Axboe @ 2021-03-02 22:36 UTC (permalink / raw)
  To: Linux Memory Management List, linux-block; +Cc: Christoph Hellwig, akpm

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...

Fixes: 48d15436fde6 ("mm: remove get_swap_bio")
Signed-off-by: Jens Axboe <axboe@kernel.dk>

---

diff --git a/include/linux/swap.h b/include/linux/swap.h
index 32f665b1ee85..4cc6ec3bf0ab 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -485,6 +485,7 @@ struct backing_dev_info;
 extern int init_swap_address_space(unsigned int type, unsigned long nr_pages);
 extern void exit_swap_address_space(unsigned int type);
 extern struct swap_info_struct *get_swap_device(swp_entry_t entry);
+sector_t swap_page_sector(struct page *page);
 
 static inline void put_swap_device(struct swap_info_struct *si)
 {
diff --git a/mm/page_io.c b/mm/page_io.c
index 485fa5cca4a2..c493ce9ebcf5 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -254,11 +254,6 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
 	return ret;
 }
 
-static sector_t swap_page_sector(struct page *page)
-{
-	return (sector_t)__page_file_index(page) << (PAGE_SHIFT - 9);
-}
-
 static inline void count_swpout_vm_event(struct page *page)
 {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
diff --git a/mm/swapfile.c b/mm/swapfile.c
index f039745989d2..7a8636c6c9ff 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -199,8 +199,8 @@ static int discard_swap(struct swap_info_struct *si)
 	return err;		/* That will often be -EOPNOTSUPP */
 }
 
-static struct swap_extent *
-offset_to_swap_extent(struct swap_info_struct *sis, unsigned long offset)
+struct swap_extent *offset_to_swap_extent(struct swap_info_struct *sis,
+					  unsigned long offset)
 {
 	struct swap_extent *se;
 	struct rb_node *rb;
@@ -1858,6 +1858,19 @@ sector_t swapdev_block(int type, pgoff_t offset)
 	return se->start_block + (offset - se->start_page);
 }
 
+sector_t swap_page_sector(struct page *page)
+{
+	struct swap_info_struct *sis = page_swap_info(page);
+	struct swap_extent *se;
+	sector_t sector;
+	pgoff_t offset;
+
+	offset = __page_file_index(page);
+	se = offset_to_swap_extent(sis, offset);
+	sector = se->start_block + (offset - se->start_page);
+	return sector << (PAGE_SHIFT - 9);
+}
+
 /*
  * Return either the total number of swap pages of given type, or the number
  * of free pages of that type (depending on @free)

-- 
Jens Axboe


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] swap: fix swapfile read/write offset
  2021-03-02 22:36 [PATCH] swap: fix swapfile read/write offset Jens Axboe
@ 2021-03-03 15:46 ` Anthony Iliopoulos
  2021-03-03 16:24   ` Jens Axboe
  0 siblings, 1 reply; 4+ messages in thread
From: Anthony Iliopoulos @ 2021-03-03 15:46 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Linux Memory Management List, linux-block, Christoph Hellwig, akpm

On Tue, Mar 02, 2021 at 03:36:19PM -0700, Jens Axboe wrote:
> 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...
> 
> Fixes: 48d15436fde6 ("mm: remove get_swap_bio")

Presumably the usage of swap_page_sector was already affecting swap on
blockdevs that implement rw_page (currently brd, zram, btt, pmem), so it
may worth adding:

Fixes: dd6bd0d9c7db ("swap: use bdev_read_page() / bdev_write_page()")
Cc: <stable@vger.kernel.org> # v3.16+

for backporting, since it also affects stable.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] swap: fix swapfile read/write offset
  2021-03-03 15:46 ` Anthony Iliopoulos
@ 2021-03-03 16:24   ` Jens Axboe
  2021-03-04  3:19     ` Anthony Iliopoulos
  0 siblings, 1 reply; 4+ messages in thread
From: Jens Axboe @ 2021-03-03 16:24 UTC (permalink / raw)
  To: Anthony Iliopoulos
  Cc: Linux Memory Management List, linux-block, Christoph Hellwig, akpm

On 3/3/21 8:46 AM, Anthony Iliopoulos wrote:
> On Tue, Mar 02, 2021 at 03:36:19PM -0700, Jens Axboe wrote:
>> 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...
>>
>> Fixes: 48d15436fde6 ("mm: remove get_swap_bio")
> 
> Presumably the usage of swap_page_sector was already affecting swap on
> blockdevs that implement rw_page (currently brd, zram, btt, pmem), so it
> may worth adding:
> 
> Fixes: dd6bd0d9c7db ("swap: use bdev_read_page() / bdev_write_page()")
> Cc: <stable@vger.kernel.org> # v3.16+
> 
> for backporting, since it also affects stable.

yes indeed, in fact that is the source of the original issue (copy/paste
from that broken path).

Fix is already upstream, but would be nice if someone would turn it into
something that could be applied to stable.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] swap: fix swapfile read/write offset
  2021-03-03 16:24   ` Jens Axboe
@ 2021-03-04  3:19     ` Anthony Iliopoulos
  0 siblings, 0 replies; 4+ messages in thread
From: Anthony Iliopoulos @ 2021-03-04  3:19 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Linux Memory Management List, linux-block, Christoph Hellwig, akpm

On Wed, Mar 03, 2021 at 09:24:13AM -0700, Jens Axboe wrote:
> On 3/3/21 8:46 AM, Anthony Iliopoulos wrote:
> > On Tue, Mar 02, 2021 at 03:36:19PM -0700, Jens Axboe wrote:
> >> 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...
> >>
> >> Fixes: 48d15436fde6 ("mm: remove get_swap_bio")
> > 
> > Presumably the usage of swap_page_sector was already affecting swap on
> > blockdevs that implement rw_page (currently brd, zram, btt, pmem), so it
> > may worth adding:
> > 
> > Fixes: dd6bd0d9c7db ("swap: use bdev_read_page() / bdev_write_page()")
> > Cc: <stable@vger.kernel.org> # v3.16+
> > 
> > for backporting, since it also affects stable.
> 
> yes indeed, in fact that is the source of the original issue (copy/paste
> from that broken path).
> 
> Fix is already upstream, but would be nice if someone would turn it into
> something that could be applied to stable.

Sure, I have the following for v5.10+ and can post this later today to
stable for review along with backports for the rest of the longterm
kernels:

From f0d75f9a18e5184670ea11b87bf513b0225b6826 Mon Sep 17 00:00:00 2001
From: Anthony Iliopoulos <ailiop@suse.com>
Date: Wed, 3 Mar 2021 20:07:05 +0100
Subject: [PATCH] swap: fix swapfile page offset mapping

Fix block device sector offset calculation for swap page io on top of
blockdevs that provide a rw_page operation and do page-sized io directly
(without the block layer).

Currently swap_page_sector() maps a swap page into a blockdev sector by
obtaining the swap page offset (swap map slot), but ignores the swapfile
starting offset into the blockdev.

In setups where swapfiles are sitting on top of a filesystem, this
results into swapping out activity potentially overwriting filesystem
blocks that fall outside the swapfile region.

[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 regular block devices.]

Fixes: dd6bd0d9c7db ("swap: use bdev_read_page() / bdev_write_page()")
Cc: <stable@vger.kernel.org> # v5.10+

Signed-off-by: Anthony Iliopoulos <ailiop@suse.com>
---
 mm/page_io.c  | 12 ++++--------
 mm/swapfile.c |  2 +-
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/mm/page_io.c b/mm/page_io.c
index 9bca17ecc4df..d2d4d1b3db10 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -37,7 +37,6 @@ static struct bio *get_swap_bio(gfp_t gfp_flags,
 
 		bio->bi_iter.bi_sector = map_swap_page(page, &bdev);
 		bio_set_dev(bio, bdev);
-		bio->bi_iter.bi_sector <<= PAGE_SHIFT - 9;
 		bio->bi_end_io = end_io;
 
 		bio_add_page(bio, page, thp_size(page), 0);
@@ -273,11 +272,6 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
 	return ret;
 }
 
-static sector_t swap_page_sector(struct page *page)
-{
-	return (sector_t)__page_file_index(page) << (PAGE_SHIFT - 9);
-}
-
 static inline void count_swpout_vm_event(struct page *page)
 {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -355,7 +349,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_swpout_vm_event(page);
 		return 0;
@@ -414,7 +409,8 @@ int swap_readpage(struct page *page, bool synchronous)
 	}
 
 	if (sis->flags & SWP_SYNCHRONOUS_IO) {
-		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);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 9fffc5af29d1..47524a4d5e90 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2308,7 +2308,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);
 }
 
 /*
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-03-04  3:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-02 22:36 [PATCH] swap: fix swapfile read/write offset Jens Axboe
2021-03-03 15:46 ` Anthony Iliopoulos
2021-03-03 16:24   ` Jens Axboe
2021-03-04  3:19     ` Anthony Iliopoulos

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.