mm/gup.c: stricter check on THP migration entry during follow_pmd_mask
[linux-2.6-microblaze.git] / mm / gup.c
index 2c51e97..f0af462 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -642,12 +642,17 @@ static struct page *follow_pmd_mask(struct vm_area_struct *vma,
        }
 retry:
        if (!pmd_present(pmdval)) {
+               /*
+                * Should never reach here, if thp migration is not supported;
+                * Otherwise, it must be a thp migration entry.
+                */
+               VM_BUG_ON(!thp_migration_supported() ||
+                                 !is_pmd_migration_entry(pmdval));
+
                if (likely(!(flags & FOLL_MIGRATION)))
                        return no_page_table(vma, flags);
-               VM_BUG_ON(thp_migration_supported() &&
-                                 !is_pmd_migration_entry(pmdval));
-               if (is_pmd_migration_entry(pmdval))
-                       pmd_migration_entry_wait(mm, pmd);
+
+               pmd_migration_entry_wait(mm, pmd);
                pmdval = READ_ONCE(*pmd);
                /*
                 * MADV_DONTNEED may convert the pmd to null because
@@ -1672,21 +1677,22 @@ size_t fault_in_writeable(char __user *uaddr, size_t size)
 
        if (unlikely(size == 0))
                return 0;
+       if (!user_write_access_begin(uaddr, size))
+               return size;
        if (!PAGE_ALIGNED(uaddr)) {
-               if (unlikely(__put_user(0, uaddr) != 0))
-                       return size;
+               unsafe_put_user(0, uaddr, out);
                uaddr = (char __user *)PAGE_ALIGN((unsigned long)uaddr);
        }
        end = (char __user *)PAGE_ALIGN((unsigned long)start + size);
        if (unlikely(end < start))
                end = NULL;
        while (uaddr != end) {
-               if (unlikely(__put_user(0, uaddr) != 0))
-                       goto out;
+               unsafe_put_user(0, uaddr, out);
                uaddr += PAGE_SIZE;
        }
 
 out:
+       user_write_access_end();
        if (size > uaddr - start)
                return size - (uaddr - start);
        return 0;
@@ -1771,21 +1777,22 @@ size_t fault_in_readable(const char __user *uaddr, size_t size)
 
        if (unlikely(size == 0))
                return 0;
+       if (!user_read_access_begin(uaddr, size))
+               return size;
        if (!PAGE_ALIGNED(uaddr)) {
-               if (unlikely(__get_user(c, uaddr) != 0))
-                       return size;
+               unsafe_get_user(c, uaddr, out);
                uaddr = (const char __user *)PAGE_ALIGN((unsigned long)uaddr);
        }
        end = (const char __user *)PAGE_ALIGN((unsigned long)start + size);
        if (unlikely(end < start))
                end = NULL;
        while (uaddr != end) {
-               if (unlikely(__get_user(c, uaddr) != 0))
-                       goto out;
+               unsafe_get_user(c, uaddr, out);
                uaddr += PAGE_SIZE;
        }
 
 out:
+       user_read_access_end();
        (void)c;
        if (size > uaddr - start)
                return size - (uaddr - start);