mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
mm: extract in_gate_area() case from __get_user_pages()
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>
This commit is contained in:
parent
4bbd4c776a
commit
f2b495ca82
1 changed files with 48 additions and 42 deletions
90
mm/gup.c
90
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)
|
||||
int ret;
|
||||
ret = get_gate_page(mm, start & PAGE_MASK, gup_flags,
|
||||
&vma, pages ? &pages[i] : NULL);
|
||||
if (ret)
|
||||
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))
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue