2021-07-13 05:54:19

by Christoph Hellwig

[permalink] [raw]
Subject: fix memcpy_to_page and memzero_page

Hi all,

we need to call flush_dcache_page on any kmapped page, and on any page
we write to that may be mapped into the page cache, which can happen
quite frequently for anything we use raw pages for.

Patch 1 make sure memcpy_to_page and memzero_page to do the right thing
for that, and patch 2 fixes up the lost switch to kmap_local_page for
memzero_page.


2021-07-13 05:54:19

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 1/2] mm: call flush_dcache_page in memcpy_to_page and memzero_page

memcpy_to_page and memzero_page can write to arbitrary pages, which could
be in the page cache or in high memory, so call flush_kernel_dcache_pages
to flush the dcache.

Fixes: bb90d4bc7b6a ("mm/highmem: Lift memcpy_[to|from]_page to core")
Fixes: 28961998f858 ("iov_iter: lift memzero_page() to highmem.h")
Signed-off-by: Christoph Hellwig <[email protected]>
---
include/linux/highmem.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 8c6e8e996c87..8e7e50a53a12 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -318,6 +318,7 @@ static inline void memcpy_to_page(struct page *page, size_t offset,

VM_BUG_ON(offset + len > PAGE_SIZE);
memcpy(to + offset, from, len);
+ flush_dcache_page(page);
kunmap_local(to);
}

@@ -325,6 +326,7 @@ static inline void memzero_page(struct page *page, size_t offset, size_t len)
{
char *addr = kmap_atomic(page);
memset(addr + offset, 0, len);
+ flush_dcache_page(page);
kunmap_atomic(addr);
}

--
2.30.2

2021-07-14 01:32:05

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 1/2] mm: call flush_dcache_page in memcpy_to_page and memzero_page

On Tue, 13 Jul 2021 07:52:30 +0200 Christoph Hellwig <[email protected]> wrote:

> memcpy_to_page and memzero_page can write to arbitrary pages, which could
> be in the page cache or in high memory, so call flush_kernel_dcache_pages
> to flush the dcache.

I assume this presently is not known to cause any problems, but that
some problems might be discovered in the future? In which case,
should we cc:stable?

2021-07-14 05:29:22

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH 1/2] mm: call flush_dcache_page in memcpy_to_page and memzero_page

On Tue, Jul 13, 2021 at 06:31:23PM -0700, Andrew Morton wrote:
> On Tue, 13 Jul 2021 07:52:30 +0200 Christoph Hellwig <[email protected]> wrote:
>
> > memcpy_to_page and memzero_page can write to arbitrary pages, which could
> > be in the page cache or in high memory, so call flush_kernel_dcache_pages
> > to flush the dcache.
>
> I assume this presently is not known to cause any problems, but that
> some problems might be discovered in the future? In which case,
> should we cc:stable?

This is a problem when using these helpers on dcache challeneged
architectures. Right now there are just a few users, chances
are no one used the PC floppy drŅ–ver, the aha1542 driver for an ISA
SCSI HBA, and a few advanced and optional btrfs and ext4 features
on those platforms yet since the conversion. So yes, stable would be
good.

2021-07-14 08:10:54

by Ira Weiny

[permalink] [raw]
Subject: Re: [PATCH 1/2] mm: call flush_dcache_page in memcpy_to_page and memzero_page

On Tue, Jul 13, 2021 at 07:52:30AM +0200, Christoph Hellwig wrote:
> memcpy_to_page and memzero_page can write to arbitrary pages, which could
> be in the page cache or in high memory, so call flush_kernel_dcache_pages
> to flush the dcache.
>
> Fixes: bb90d4bc7b6a ("mm/highmem: Lift memcpy_[to|from]_page to core")
> Fixes: 28961998f858 ("iov_iter: lift memzero_page() to highmem.h")
> Signed-off-by: Christoph Hellwig <[email protected]>

Reviewed-by: Ira Weiny <[email protected]>

> ---
> include/linux/highmem.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/include/linux/highmem.h b/include/linux/highmem.h
> index 8c6e8e996c87..8e7e50a53a12 100644
> --- a/include/linux/highmem.h
> +++ b/include/linux/highmem.h
> @@ -318,6 +318,7 @@ static inline void memcpy_to_page(struct page *page, size_t offset,
>
> VM_BUG_ON(offset + len > PAGE_SIZE);
> memcpy(to + offset, from, len);
> + flush_dcache_page(page);
> kunmap_local(to);
> }
>
> @@ -325,6 +326,7 @@ static inline void memzero_page(struct page *page, size_t offset, size_t len)
> {
> char *addr = kmap_atomic(page);
> memset(addr + offset, 0, len);
> + flush_dcache_page(page);
> kunmap_atomic(addr);
> }
>
> --
> 2.30.2
>