From 1799cf9b6a4f92814154a8846e746d5e4710fabc Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Wed, 30 Apr 2014 12:02:17 -0700 Subject: [PATCH] dtrace: ensure one can try to get user pages without locking or faulting This commit changes the FOLL_NOFAULT flag into a FOLL_IMMED flag, to more accurately convey its meaning, i.e. to request user pages without waiting for any locks and without servicing any page faults as a result of the request. This is necessary in order to request user pages from interrupt context. This also completes the implementation by ensuring that the PTE spinlock is checked rather than trying to lock it (and possibly get stuck in a deadlock spinning for it). Orabug: 18653173 Signed-off-by: Kris Van Hees Reviewed-by: Chuck Anderson Reviewed-by: Jerry Snitselaar --- include/linux/mm.h | 8 +++++++- mm/gup.c | 16 ++++++++++------ mm/hugetlb.c | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 0fe9b2c06aea..3d6d48e7073d 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1535,6 +1535,12 @@ static inline void pgtable_page_dtor(struct page *page) __pte; \ }) +#define pte_is_locked(mm, pmd) \ +({ \ + spinlock_t *__ptl = pte_lockptr(mm, pmd); \ + spin_is_locked(__ptl); \ +}) + #define pte_unmap_unlock(pte, ptl) do { \ spin_unlock(ptl); \ pte_unmap(pte); \ @@ -2035,7 +2041,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma, #define FOLL_NUMA 0x200 /* force NUMA hinting page fault */ #define FOLL_MIGRATION 0x400 /* wait for page to replace migration entry */ #define FOLL_TRIED 0x800 /* a retry, previous pass started an IO */ -#define FOLL_NOFAULT 0x1000 /* fail rather than fault pages in */ +#define FOLL_IMMED 0x08000000 /* fail if locking, or faulting pages in */ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, void *data); diff --git a/mm/gup.c b/mm/gup.c index 6dd07dc3eb82..50f624a0d5e6 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -44,6 +44,9 @@ retry: if (unlikely(pmd_bad(*pmd))) return no_page_table(vma, flags); + if ((flags & FOLL_IMMED) && pte_is_locked(mm, pmd)) + return no_page_table(vma, flags); + ptep = pte_offset_map_lock(mm, pmd, address, &ptl); pte = *ptep; if (!pte_present(pte)) { @@ -136,9 +139,10 @@ no_page: * * @flags can have FOLL_ flags set, defined in * - * Returns the mapped (struct page *), %NULL if no mapping exists, or - * an error pointer if there is a mapping to something not represented - * by a page descriptor (see also vm_normal_page()). + * Returns the mapped (struct page *), %NULL if no mapping exists or if + * FOLL_IMMED is set and the PTE is locked, or an error pointer if there is a + * mapping to something not represented by a page descriptor (see also + * vm_normal_page()). */ struct page *follow_page_mask(struct vm_area_struct *vma, unsigned long address, unsigned int flags, @@ -265,7 +269,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma, unsigned int fault_flags = 0; int ret; - if (unlikely(*flags & FOLL_NOFAULT)) { + if (unlikely(*flags & FOLL_IMMED)) { if (nonblocking) *nonblocking = 0; return -EBUSY; @@ -405,14 +409,14 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags) * appropriate) must be called after the page is finished with, and * before put_page is called. * - * If FOLL_NOFAULT is set, pinning of pages will cease as soon as a page is + * If FOLL_IMMED is set, pinning of pages will cease as soon as a page is * encountered that needs to be faulted in. (No attempt is made to see if * further pages could be pinned without faulting: the caller must do that, if * desired.) * * If @nonblocking != NULL, __get_user_pages will not wait for disk IO or * mmap_sem contention, and if waiting is needed to pin all pages, or - * FOLL_NOFAULT is set and a fault is needed, *@nonblocking will be set to 0. + * FOLL_IMMED is set and a fault is needed, *@nonblocking will be set to 0. * Further, if @gup_flags does not include FOLL_NOWAIT, the mmap_sem will be * released via up_read() in this case. * diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 706c0d0d8d03..234a27bdbe85 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3440,7 +3440,7 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, if (pte) spin_unlock(ptl); - if (flags & FOLL_NOFAULT) + if (flags & FOLL_IMMED) return i; ret = hugetlb_fault(mm, vma, vaddr, -- 2.50.1