Commit 382a7dec authored by Christoph Lameter's avatar Christoph Lameter Committed by Linus Torvalds

[PATCH] alloc_zeroed_user_highpage() to fix the clear_user_highpage issue

This patch adds a new function alloc_zeroed_user_highpage that is then used
in the anonymous page fault handler and in the COW code to allocate zeroed
pages.  The function can be defined per arch to setup special processing
for user pages by defining __HAVE_ARCH_ALLOC_ZEROED_USER_PAGE.  For arches
that do not need to do special things for user pages,
alloc_zeroed_user_highpage is defined to simply do

	alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)

This patch needs to update a number of archs. Wish there was a better way
to do this.
Signed-off-by: default avatarChristoph Lameter <clameter@sgi.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent bb459c65
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
extern void clear_page(void *page); extern void clear_page(void *page);
#define clear_user_page(page, vaddr, pg) clear_page(page) #define clear_user_page(page, vaddr, pg) clear_page(page)
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vmaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
extern void copy_page(void * _to, void * _from); extern void copy_page(void * _to, void * _from);
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
#define clear_user_page(page, vaddr, pg) clear_page(page) #define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/* /*
* These are used to make use of C type-checking.. * These are used to make use of C type-checking..
*/ */
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#define clear_user_page(page, vaddr, pg) clear_page(page) #define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/* /*
* These are used to make use of C type-checking.. * These are used to make use of C type-checking..
*/ */
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#define clear_user_page(page, vaddr, pg) clear_page(page) #define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/* /*
* These are used to make use of C type-checking.. * These are used to make use of C type-checking..
*/ */
......
...@@ -75,6 +75,16 @@ do { \ ...@@ -75,6 +75,16 @@ do { \
flush_dcache_page(page); \ flush_dcache_page(page); \
} while (0) } while (0)
#define alloc_zeroed_user_highpage(vma, vaddr) \
({ \
struct page *page = alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr); \
flush_dcache_page(page); \
page; \
})
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#ifdef CONFIG_VIRTUAL_MEM_MAP #ifdef CONFIG_VIRTUAL_MEM_MAP
......
...@@ -17,6 +17,9 @@ extern void copy_page(void *to, void *from); ...@@ -17,6 +17,9 @@ extern void copy_page(void *to, void *from);
#define clear_user_page(page, vaddr, pg) clear_page(page) #define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/* /*
* These are used to make use of C type-checking.. * These are used to make use of C type-checking..
*/ */
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#define clear_user_page(page, vaddr, pg) clear_page(page) #define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/* /*
* These are used to make use of C type-checking.. * These are used to make use of C type-checking..
*/ */
......
...@@ -106,6 +106,9 @@ static inline void copy_page(void *to, void *from) ...@@ -106,6 +106,9 @@ static inline void copy_page(void *to, void *from)
#define clear_user_page(page, vaddr, pg) clear_page(page) #define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/* Pure 2^n version of get_order */ /* Pure 2^n version of get_order */
extern __inline__ int get_order(unsigned long size) extern __inline__ int get_order(unsigned long size)
{ {
......
...@@ -38,6 +38,8 @@ void copy_page(void *, void *); ...@@ -38,6 +38,8 @@ void copy_page(void *, void *);
#define clear_user_page(page, vaddr, pg) clear_page(page) #define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/* /*
* These are used to make use of C type-checking.. * These are used to make use of C type-checking..
*/ */
......
...@@ -42,6 +42,17 @@ static inline void clear_user_highpage(struct page *page, unsigned long vaddr) ...@@ -42,6 +42,17 @@ static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
smp_wmb(); smp_wmb();
} }
#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
static inline struct page *
alloc_zeroed_user_highpage(struct vm_area_struct *vma, unsigned long vaddr)
{
struct page *page = alloc_page_vma(GFP_HIGHUSER, vma, vaddr);
clear_user_highpage(page, vaddr);
return page;
}
#endif
static inline void clear_highpage(struct page *page) static inline void clear_highpage(struct page *page)
{ {
void *kaddr = kmap_atomic(page, KM_USER0); void *kaddr = kmap_atomic(page, KM_USER0);
......
...@@ -83,20 +83,6 @@ EXPORT_SYMBOL(num_physpages); ...@@ -83,20 +83,6 @@ EXPORT_SYMBOL(num_physpages);
EXPORT_SYMBOL(high_memory); EXPORT_SYMBOL(high_memory);
EXPORT_SYMBOL(vmalloc_earlyreserve); EXPORT_SYMBOL(vmalloc_earlyreserve);
/*
* We special-case the C-O-W ZERO_PAGE, because it's such
* a common occurrence (no need to read the page to know
* that it's zero - better for the cache and memory subsystem).
*/
static inline void copy_cow_page(struct page * from, struct page * to, unsigned long address)
{
if (from == ZERO_PAGE(address)) {
clear_user_highpage(to, address);
return;
}
copy_user_highpage(to, from, address);
}
/* /*
* Note: this doesn't free the actual pages themselves. That * Note: this doesn't free the actual pages themselves. That
* has been handled earlier when unmapping all the memory regions. * has been handled earlier when unmapping all the memory regions.
...@@ -1330,11 +1316,16 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -1330,11 +1316,16 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
if (unlikely(anon_vma_prepare(vma))) if (unlikely(anon_vma_prepare(vma)))
goto no_new_page; goto no_new_page;
new_page = alloc_page_vma(GFP_HIGHUSER, vma, address); if (old_page == ZERO_PAGE(address)) {
if (!new_page) new_page = alloc_zeroed_user_highpage(vma, address);
goto no_new_page; if (!new_page)
copy_cow_page(old_page,new_page,address); goto no_new_page;
} else {
new_page = alloc_page_vma(GFP_HIGHUSER, vma, address);
if (!new_page)
goto no_new_page;
copy_user_highpage(new_page, old_page, address);
}
/* /*
* Re-check the pte - we dropped the lock * Re-check the pte - we dropped the lock
*/ */
...@@ -1805,10 +1796,9 @@ do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -1805,10 +1796,9 @@ do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
if (unlikely(anon_vma_prepare(vma))) if (unlikely(anon_vma_prepare(vma)))
goto no_mem; goto no_mem;
page = alloc_page_vma(GFP_HIGHUSER, vma, addr); page = alloc_zeroed_user_highpage(vma, addr);
if (!page) if (!page)
goto no_mem; goto no_mem;
clear_user_highpage(page, addr);
spin_lock(&mm->page_table_lock); spin_lock(&mm->page_table_lock);
page_table = pte_offset_map(pmd, addr); page_table = pte_offset_map(pmd, addr);
......
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