mm: extract in_gate_area() case from __get_user_pages()
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Wed, 4 Jun 2014 23:08:11 +0000 (16:08 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 4 Jun 2014 23:54:04 +0000 (16:54 -0700)
The case is special and disturb from reading main __get_user_pages()
code path. Let's move it to separate function.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/gup.c

index ea88b65f264dcb7bd6edc24aa9e7b9cbca8e0d26..0bf127b332e7e3e5f9c65dba4da4974438c50739 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -213,6 +213,50 @@ static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long add
               stack_guard_page_end(vma, addr+PAGE_SIZE);
 }
 
+static int get_gate_page(struct mm_struct *mm, unsigned long address,
+               unsigned int gup_flags, struct vm_area_struct **vma,
+               struct page **page)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+       int ret = -EFAULT;
+
+       /* user gate pages are read-only */
+       if (gup_flags & FOLL_WRITE)
+               return -EFAULT;
+       if (address > TASK_SIZE)
+               pgd = pgd_offset_k(address);
+       else
+               pgd = pgd_offset_gate(mm, address);
+       BUG_ON(pgd_none(*pgd));
+       pud = pud_offset(pgd, address);
+       BUG_ON(pud_none(*pud));
+       pmd = pmd_offset(pud, address);
+       if (pmd_none(*pmd))
+               return -EFAULT;
+       VM_BUG_ON(pmd_trans_huge(*pmd));
+       pte = pte_offset_map(pmd, address);
+       if (pte_none(*pte))
+               goto unmap;
+       *vma = get_gate_vma(mm);
+       if (!page)
+               goto out;
+       *page = vm_normal_page(*vma, address, *pte);
+       if (!*page) {
+               if ((gup_flags & FOLL_DUMP) || !is_zero_pfn(pte_pfn(*pte)))
+                       goto unmap;
+               *page = pte_page(*pte);
+       }
+       get_page(*page);
+out:
+       ret = 0;
+unmap:
+       pte_unmap(pte);
+       return ret;
+}
+
 /**
  * __get_user_pages() - pin user pages in memory
  * @tsk:       task_struct of target task
@@ -291,49 +335,11 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 
                vma = find_extend_vma(mm, start);
                if (!vma && in_gate_area(mm, start)) {
-                       unsigned long pg = start & PAGE_MASK;
-                       pgd_t *pgd;
-                       pud_t *pud;
-                       pmd_t *pmd;
-                       pte_t *pte;
-
-                       /* user gate pages are read-only */
-                       if (gup_flags & FOLL_WRITE)
-                               goto efault;
-                       if (pg > TASK_SIZE)
-                               pgd = pgd_offset_k(pg);
-                       else
-                               pgd = pgd_offset_gate(mm, pg);
-                       BUG_ON(pgd_none(*pgd));
-                       pud = pud_offset(pgd, pg);
-                       BUG_ON(pud_none(*pud));
-                       pmd = pmd_offset(pud, pg);
-                       if (pmd_none(*pmd))
+                       int ret;
+                       ret = get_gate_page(mm, start & PAGE_MASK, gup_flags,
+                                       &vma, pages ? &pages[i] : NULL);
+                       if (ret)
                                goto efault;
-                       VM_BUG_ON(pmd_trans_huge(*pmd));
-                       pte = pte_offset_map(pmd, pg);
-                       if (pte_none(*pte)) {
-                               pte_unmap(pte);
-                               goto efault;
-                       }
-                       vma = get_gate_vma(mm);
-                       if (pages) {
-                               struct page *page;
-
-                               page = vm_normal_page(vma, start, *pte);
-                               if (!page) {
-                                       if (!(gup_flags & FOLL_DUMP) &&
-                                            is_zero_pfn(pte_pfn(*pte)))
-                                               page = pte_page(*pte);
-                                       else {
-                                               pte_unmap(pte);
-                                               goto efault;
-                                       }
-                               }
-                               pages[i] = page;
-                               get_page(page);
-                       }
-                       pte_unmap(pte);
                        page_mask = 0;
                        goto next_page;
                }