diff options
Diffstat (limited to 'drivers/char/mspec.c')
-rw-r--r-- | drivers/char/mspec.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index fe2a95b5d3c0..30f095a8c2d4 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c | |||
@@ -193,25 +193,23 @@ mspec_close(struct vm_area_struct *vma) | |||
193 | } | 193 | } |
194 | 194 | ||
195 | /* | 195 | /* |
196 | * mspec_nopfn | 196 | * mspec_fault |
197 | * | 197 | * |
198 | * Creates a mspec page and maps it to user space. | 198 | * Creates a mspec page and maps it to user space. |
199 | */ | 199 | */ |
200 | static unsigned long | 200 | static int |
201 | mspec_nopfn(struct vm_area_struct *vma, unsigned long address) | 201 | mspec_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
202 | { | 202 | { |
203 | unsigned long paddr, maddr; | 203 | unsigned long paddr, maddr; |
204 | unsigned long pfn; | 204 | unsigned long pfn; |
205 | int index; | 205 | pgoff_t index = vmf->pgoff; |
206 | struct vma_data *vdata = vma->vm_private_data; | 206 | struct vma_data *vdata = vma->vm_private_data; |
207 | 207 | ||
208 | BUG_ON(address < vdata->vm_start || address >= vdata->vm_end); | ||
209 | index = (address - vdata->vm_start) >> PAGE_SHIFT; | ||
210 | maddr = (volatile unsigned long) vdata->maddr[index]; | 208 | maddr = (volatile unsigned long) vdata->maddr[index]; |
211 | if (maddr == 0) { | 209 | if (maddr == 0) { |
212 | maddr = uncached_alloc_page(numa_node_id(), 1); | 210 | maddr = uncached_alloc_page(numa_node_id(), 1); |
213 | if (maddr == 0) | 211 | if (maddr == 0) |
214 | return NOPFN_OOM; | 212 | return VM_FAULT_OOM; |
215 | 213 | ||
216 | spin_lock(&vdata->lock); | 214 | spin_lock(&vdata->lock); |
217 | if (vdata->maddr[index] == 0) { | 215 | if (vdata->maddr[index] == 0) { |
@@ -231,13 +229,20 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address) | |||
231 | 229 | ||
232 | pfn = paddr >> PAGE_SHIFT; | 230 | pfn = paddr >> PAGE_SHIFT; |
233 | 231 | ||
234 | return pfn; | 232 | /* |
233 | * vm_insert_pfn can fail with -EBUSY, but in that case it will | ||
234 | * be because another thread has installed the pte first, so it | ||
235 | * is no problem. | ||
236 | */ | ||
237 | vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); | ||
238 | |||
239 | return VM_FAULT_NOPAGE; | ||
235 | } | 240 | } |
236 | 241 | ||
237 | static struct vm_operations_struct mspec_vm_ops = { | 242 | static struct vm_operations_struct mspec_vm_ops = { |
238 | .open = mspec_open, | 243 | .open = mspec_open, |
239 | .close = mspec_close, | 244 | .close = mspec_close, |
240 | .nopfn = mspec_nopfn | 245 | .fault = mspec_fault, |
241 | }; | 246 | }; |
242 | 247 | ||
243 | /* | 248 | /* |