diff options
Diffstat (limited to 'arch/s390/mm/gup.c')
| -rw-r--r-- | arch/s390/mm/gup.c | 37 | 
1 files changed, 37 insertions, 0 deletions
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index 65cb06e2af4..eeaf8023851 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c @@ -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  |