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 65cb06e2af4e..eeaf8023851f 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, | |||
154 | return 1; | 154 | return 1; |
155 | } | 155 | } |
156 | 156 | ||
157 | /* | ||
158 | * Like get_user_pages_fast() except its IRQ-safe in that it won't fall | ||
159 | * back to the regular GUP. | ||
160 | */ | ||
161 | int __get_user_pages_fast(unsigned long start, int nr_pages, int write, | ||
162 | struct page **pages) | ||
163 | { | ||
164 | struct mm_struct *mm = current->mm; | ||
165 | unsigned long addr, len, end; | ||
166 | unsigned long next, flags; | ||
167 | pgd_t *pgdp, pgd; | ||
168 | int nr = 0; | ||
169 | |||
170 | start &= PAGE_MASK; | ||
171 | addr = start; | ||
172 | len = (unsigned long) nr_pages << PAGE_SHIFT; | ||
173 | end = start + len; | ||
174 | if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, | ||
175 | (void __user *)start, len))) | ||
176 | return 0; | ||
177 | |||
178 | local_irq_save(flags); | ||
179 | pgdp = pgd_offset(mm, addr); | ||
180 | do { | ||
181 | pgd = *pgdp; | ||
182 | barrier(); | ||
183 | next = pgd_addr_end(addr, end); | ||
184 | if (pgd_none(pgd)) | ||
185 | break; | ||
186 | if (!gup_pud_range(pgdp, pgd, addr, next, write, pages, &nr)) | ||
187 | break; | ||
188 | } while (pgdp++, addr = next, addr != end); | ||
189 | local_irq_restore(flags); | ||
190 | |||
191 | return nr; | ||
192 | } | ||
193 | |||
157 | /** | 194 | /** |
158 | * get_user_pages_fast() - pin user pages in memory | 195 | * get_user_pages_fast() - pin user pages in memory |
159 | * @start: starting user address | 196 | * @start: starting user address |