s390/mm: implement __get_user_pages_fast()
authorGerald Schaefer <gerald.schaefer@de.ibm.com>
Tue, 4 Sep 2012 13:37:55 +0000 (15:37 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 26 Sep 2012 13:45:08 +0000 (15:45 +0200)
This patch introduces the __get_user_pages_fast() function on s390,
which will be needed with CONFIG_TRANSPARENT_HUGEPAGE and futex.

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/mm/gup.c

index 65cb06e..eeaf802 100644 (file)
@@ -154,6 +154,43 @@ static inline int gup_pud_range(pgd_t *pgdp, pgd_t pgd, unsigned long addr,
        return 1;
 }
 
+/*
+ * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
+ * back to the regular GUP.
+ */
+int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
+                         struct page **pages)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr, len, end;
+       unsigned long next, flags;
+       pgd_t *pgdp, pgd;
+       int nr = 0;
+
+       start &= PAGE_MASK;
+       addr = start;
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+       end = start + len;
+       if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
+                                       (void __user *)start, len)))
+               return 0;
+
+       local_irq_save(flags);
+       pgdp = pgd_offset(mm, addr);
+       do {
+               pgd = *pgdp;
+               barrier();
+               next = pgd_addr_end(addr, end);
+               if (pgd_none(pgd))
+                       break;
+               if (!gup_pud_range(pgdp, pgd, addr, next, write, pages, &nr))
+                       break;
+       } while (pgdp++, addr = next, addr != end);
+       local_irq_restore(flags);
+
+       return nr;
+}
+
 /**
  * get_user_pages_fast() - pin user pages in memory
  * @start:     starting user address