Commit 487ff320 authored by Russell King's avatar Russell King Committed by Russell King

Allow architectures to override copy_user_highpage()

With aliasing VIPT cache support, the ARM implementation of
clear_user_page() and copy_user_page() sets up a temporary kernel space
mapping such that we have the same cache colour as the userspace page.
This avoids having to consider any userspace aliases from this operation.

However, when highmem is enabled, kmap_atomic() have to setup mappings.
The copy_user_highpage() and clear_user_highpage() call these functions
before delegating the copies to copy_user_page() and clear_user_page().

The effect of this is that each of the *_user_highpage() functions setup
their own kmap mapping, followed by the *_user_page() functions setting
up another mapping.  This is rather wasteful.

Thankfully, copy_user_highpage() can be overriden by architectures by
defining __HAVE_ARCH_COPY_USER_HIGHPAGE.  However, replacement of
clear_user_highpage() is more difficult because its inline definition
is not conditional.  It seems that you're expected to define
__HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE and provide a replacement
__alloc_zeroed_user_highpage() implementation instead.

The allocation itself is fine, so we don't want to override that.  What
we really want to do is to override clear_user_highpage() with our own
version which doesn't kmap_atomic() unnecessarily.

Other VIPT architectures (PARISC and SH) would also like to override
this function as well.
Acked-by: default avatarHugh Dickins <hugh@veritas.com>
Acked-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
Acked-by: default avatarPaul Mundt <lethal@linux-sh.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 6417a917
...@@ -63,12 +63,14 @@ static inline void *kmap_atomic(struct page *page, enum km_type idx) ...@@ -63,12 +63,14 @@ static inline void *kmap_atomic(struct page *page, enum km_type idx)
#endif /* CONFIG_HIGHMEM */ #endif /* CONFIG_HIGHMEM */
/* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
#ifndef clear_user_highpage
static inline void clear_user_highpage(struct page *page, unsigned long vaddr) static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
{ {
void *addr = kmap_atomic(page, KM_USER0); void *addr = kmap_atomic(page, KM_USER0);
clear_user_page(addr, vaddr, page); clear_user_page(addr, vaddr, page);
kunmap_atomic(addr, KM_USER0); kunmap_atomic(addr, KM_USER0);
} }
#endif
#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE #ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment