aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2014-08-06 19:08:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-06 21:01:22 -0400
commitaecd6f44266c13b8709245b21ded2d19291ab070 (patch)
tree805e451bb46a2d6091db0d9e23c7f11422aa4121 /mm
parent2ab051e11bfa3cbb7b24177f3d6aaed10a0d743e (diff)
mm: close race between do_fault_around() and fault_around_bytes_set()
Things can go wrong if fault_around_bytes will be changed under do_fault_around(): between fault_around_mask() and fault_around_pages(). Let's read fault_around_bytes only once during do_fault_around() and calculate mask based on the reading. Note: fault_around_bytes can only be updated via debug interface. Also I've tried but was not able to trigger a bad behaviour without the patch. So I would not consider this patch as urgent. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Andrey Ryabinin <a.ryabinin@samsung.com> Cc: Sasha Levin <sasha.levin@oracle.com> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/memory.c21
1 files changed, 7 insertions, 14 deletions
diff --git a/mm/memory.c b/mm/memory.c
index 4d0a543f3bb3..dc47261c4686 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2768,16 +2768,6 @@ void do_set_pte(struct vm_area_struct *vma, unsigned long address,
2768 2768
2769static unsigned long fault_around_bytes = rounddown_pow_of_two(65536); 2769static unsigned long fault_around_bytes = rounddown_pow_of_two(65536);
2770 2770
2771static inline unsigned long fault_around_pages(void)
2772{
2773 return fault_around_bytes >> PAGE_SHIFT;
2774}
2775
2776static inline unsigned long fault_around_mask(void)
2777{
2778 return ~(fault_around_bytes - 1) & PAGE_MASK;
2779}
2780
2781#ifdef CONFIG_DEBUG_FS 2771#ifdef CONFIG_DEBUG_FS
2782static int fault_around_bytes_get(void *data, u64 *val) 2772static int fault_around_bytes_get(void *data, u64 *val)
2783{ 2773{
@@ -2842,12 +2832,15 @@ late_initcall(fault_around_debugfs);
2842static void do_fault_around(struct vm_area_struct *vma, unsigned long address, 2832static void do_fault_around(struct vm_area_struct *vma, unsigned long address,
2843 pte_t *pte, pgoff_t pgoff, unsigned int flags) 2833 pte_t *pte, pgoff_t pgoff, unsigned int flags)
2844{ 2834{
2845 unsigned long start_addr; 2835 unsigned long start_addr, nr_pages, mask;
2846 pgoff_t max_pgoff; 2836 pgoff_t max_pgoff;
2847 struct vm_fault vmf; 2837 struct vm_fault vmf;
2848 int off; 2838 int off;
2849 2839
2850 start_addr = max(address & fault_around_mask(), vma->vm_start); 2840 nr_pages = ACCESS_ONCE(fault_around_bytes) >> PAGE_SHIFT;
2841 mask = ~(nr_pages * PAGE_SIZE - 1) & PAGE_MASK;
2842
2843 start_addr = max(address & mask, vma->vm_start);
2851 off = ((address - start_addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); 2844 off = ((address - start_addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
2852 pte -= off; 2845 pte -= off;
2853 pgoff -= off; 2846 pgoff -= off;
@@ -2859,7 +2852,7 @@ static void do_fault_around(struct vm_area_struct *vma, unsigned long address,
2859 max_pgoff = pgoff - ((start_addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + 2852 max_pgoff = pgoff - ((start_addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +
2860 PTRS_PER_PTE - 1; 2853 PTRS_PER_PTE - 1;
2861 max_pgoff = min3(max_pgoff, vma_pages(vma) + vma->vm_pgoff - 1, 2854 max_pgoff = min3(max_pgoff, vma_pages(vma) + vma->vm_pgoff - 1,
2862 pgoff + fault_around_pages() - 1); 2855 pgoff + nr_pages - 1);
2863 2856
2864 /* Check if it makes any sense to call ->map_pages */ 2857 /* Check if it makes any sense to call ->map_pages */
2865 while (!pte_none(*pte)) { 2858 while (!pte_none(*pte)) {
@@ -2894,7 +2887,7 @@ static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma,
2894 * something). 2887 * something).
2895 */ 2888 */
2896 if (vma->vm_ops->map_pages && !(flags & FAULT_FLAG_NONLINEAR) && 2889 if (vma->vm_ops->map_pages && !(flags & FAULT_FLAG_NONLINEAR) &&
2897 fault_around_pages() > 1) { 2890 fault_around_bytes >> PAGE_SHIFT > 1) {
2898 pte = pte_offset_map_lock(mm, pmd, address, &ptl); 2891 pte = pte_offset_map_lock(mm, pmd, address, &ptl);
2899 do_fault_around(vma, address, pte, pgoff, flags); 2892 do_fault_around(vma, address, pte, pgoff, flags);
2900 if (!pte_same(*pte, orig_pte)) 2893 if (!pte_same(*pte, orig_pte))