]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: ensure one can try to get user pages without locking or faulting
authorKris Van Hees <kris.van.hees@oracle.com>
Wed, 30 Apr 2014 19:02:17 +0000 (12:02 -0700)
committerNick Alcock <nick.alcock@oracle.com>
Tue, 21 Jul 2015 14:29:38 +0000 (15:29 +0100)
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 <kris.van.hees@oracle.com>
Reviewed-by: Chuck Anderson <chuck.anderson@oracle.com>
Reviewed-by: Jerry Snitselaar <jerry.snitselaar@oracle.com>
include/linux/mm.h
mm/gup.c
mm/hugetlb.c

index 0fe9b2c06aeadde395f8deb732ccacb05afd1834..3d6d48e7073d3002c5318ef50266302d4342f046 100644 (file)
@@ -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);
index 6dd07dc3eb8218f3d68b3fc3067bb966ca856231..50f624a0d5e6866d07e1d928ba23504cbd75a187 100644 (file)
--- 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 <linux/mm.h>
  *
- * 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.
  *
index 706c0d0d8d03adb1e5429be6c146fcbe9b848d97..234a27bdbe85295a962aceaf5c2a22b37e4165cc 100644 (file)
@@ -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,