diff options
author | Nick Piggin <nickpiggin@yahoo.com.au> | 2005-08-03 06:24:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-08-03 12:12:05 -0400 |
commit | f33ea7f404e592e4563b12101b7a4d17da6558d7 (patch) | |
tree | 1d587ad8a06cb6d2e3a187f0312c8a524ffefe53 /include | |
parent | 5cb4cc0d8211c490537c8568001958fc76741312 (diff) |
[PATCH] fix get_user_pages bug
Checking pte_dirty instead of pte_write in __follow_page is problematic
for s390, and for copy_one_pte which leaves dirty when clearing write.
So revert __follow_page to check pte_write as before, and make
do_wp_page pass back a special extra VM_FAULT_WRITE bit to say it has
done its full job: once get_user_pages receives this value, it no longer
requires pte_write in __follow_page.
But most callers of handle_mm_fault, in the various architectures, have
switch statements which do not expect this new case. To avoid changing
them all in a hurry, make an inline wrapper function (using the old
name) that masks off the new bit, and use the extended interface with
double underscores.
Yes, we do have a call to do_wp_page from do_swap_page, but no need to
change that: in rare case it's needed, another do_wp_page will follow.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
[ Cleanups by Nick Piggin ]
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/mm.h | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h index 6eb7f48317f8..82d7024f0765 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -625,10 +625,16 @@ static inline int page_mapped(struct page *page) | |||
625 | * Used to decide whether a process gets delivered SIGBUS or | 625 | * Used to decide whether a process gets delivered SIGBUS or |
626 | * just gets major/minor fault counters bumped up. | 626 | * just gets major/minor fault counters bumped up. |
627 | */ | 627 | */ |
628 | #define VM_FAULT_OOM (-1) | 628 | #define VM_FAULT_OOM 0x00 |
629 | #define VM_FAULT_SIGBUS 0 | 629 | #define VM_FAULT_SIGBUS 0x01 |
630 | #define VM_FAULT_MINOR 1 | 630 | #define VM_FAULT_MINOR 0x02 |
631 | #define VM_FAULT_MAJOR 2 | 631 | #define VM_FAULT_MAJOR 0x03 |
632 | |||
633 | /* | ||
634 | * Special case for get_user_pages. | ||
635 | * Must be in a distinct bit from the above VM_FAULT_ flags. | ||
636 | */ | ||
637 | #define VM_FAULT_WRITE 0x10 | ||
632 | 638 | ||
633 | #define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) | 639 | #define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) |
634 | 640 | ||
@@ -704,7 +710,13 @@ extern pte_t *FASTCALL(pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsign | |||
704 | extern pte_t *FASTCALL(pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address)); | 710 | extern pte_t *FASTCALL(pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address)); |
705 | extern int install_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, struct page *page, pgprot_t prot); | 711 | extern int install_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, struct page *page, pgprot_t prot); |
706 | extern int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, unsigned long pgoff, pgprot_t prot); | 712 | extern int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, unsigned long pgoff, pgprot_t prot); |
707 | extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access); | 713 | extern int __handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access); |
714 | |||
715 | static inline int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, int write_access) | ||
716 | { | ||
717 | return __handle_mm_fault(mm, vma, address, write_access) & (~VM_FAULT_WRITE); | ||
718 | } | ||
719 | |||
708 | extern int make_pages_present(unsigned long addr, unsigned long end); | 720 | extern int make_pages_present(unsigned long addr, unsigned long end); |
709 | extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); | 721 | extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); |
710 | void install_arg_page(struct vm_area_struct *, struct page *, unsigned long); | 722 | void install_arg_page(struct vm_area_struct *, struct page *, unsigned long); |