]> Pileus Git - ~andy/linux/blobdiff - arch/s390/mm/gup.c
s390/gup: fix access_ok() usage in __get_user_pages_fast()
[~andy/linux] / arch / s390 / mm / gup.c
index eeaf8023851f41e5c3516a7194cc3b7dbf3cba4a..1f5315d1215c2640f5691555801e9ff7885c7fcf 100644 (file)
@@ -115,9 +115,18 @@ static inline int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr,
                pmd = *pmdp;
                barrier();
                next = pmd_addr_end(addr, end);
-               if (pmd_none(pmd))
+               /*
+                * The pmd_trans_splitting() check below explains why
+                * pmdp_splitting_flush() has to serialize with
+                * smp_call_function() against our disabled IRQs, to stop
+                * this gup-fast code from running while we set the
+                * splitting bit in the pmd. Returning zero will take
+                * the slow path that will call wait_split_huge_page()
+                * if the pmd is still in splitting state.
+                */
+               if (pmd_none(pmd) || pmd_trans_splitting(pmd))
                        return 0;
-               if (unlikely(pmd_huge(pmd))) {
+               if (unlikely(pmd_large(pmd))) {
                        if (!gup_huge_pmd(pmdp, pmd, addr, next,
                                          write, pages, nr))
                                return 0;
@@ -171,8 +180,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
        addr = start;
        len = (unsigned long) nr_pages << PAGE_SHIFT;
        end = start + len;
-       if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
-                                       (void __user *)start, len)))
+       if ((end < start) || (end > TASK_SIZE))
                return 0;
 
        local_irq_save(flags);
@@ -220,7 +228,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
        addr = start;
        len = (unsigned long) nr_pages << PAGE_SHIFT;
        end = start + len;
-       if (end < start)
+       if ((end < start) || (end > TASK_SIZE))
                goto slow_irqon;
 
        /*