aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memory.c')
-rw-r--r--mm/memory.c51
1 files changed, 49 insertions, 2 deletions
diff --git a/mm/memory.c b/mm/memory.c
index 072c1135ad37..e7066e71dfa3 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1277,6 +1277,51 @@ int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *
1277} 1277}
1278EXPORT_SYMBOL(vm_insert_page); 1278EXPORT_SYMBOL(vm_insert_page);
1279 1279
1280/**
1281 * vm_insert_pfn - insert single pfn into user vma
1282 * @vma: user vma to map to
1283 * @addr: target user address of this page
1284 * @pfn: source kernel pfn
1285 *
1286 * Similar to vm_inert_page, this allows drivers to insert individual pages
1287 * they've allocated into a user vma. Same comments apply.
1288 *
1289 * This function should only be called from a vm_ops->fault handler, and
1290 * in that case the handler should return NULL.
1291 */
1292int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
1293 unsigned long pfn)
1294{
1295 struct mm_struct *mm = vma->vm_mm;
1296 int retval;
1297 pte_t *pte, entry;
1298 spinlock_t *ptl;
1299
1300 BUG_ON(!(vma->vm_flags & VM_PFNMAP));
1301 BUG_ON(is_cow_mapping(vma->vm_flags));
1302
1303 retval = -ENOMEM;
1304 pte = get_locked_pte(mm, addr, &ptl);
1305 if (!pte)
1306 goto out;
1307 retval = -EBUSY;
1308 if (!pte_none(*pte))
1309 goto out_unlock;
1310
1311 /* Ok, finally just insert the thing.. */
1312 entry = pfn_pte(pfn, vma->vm_page_prot);
1313 set_pte_at(mm, addr, pte, entry);
1314 update_mmu_cache(vma, addr, entry);
1315
1316 retval = 0;
1317out_unlock:
1318 pte_unmap_unlock(pte, ptl);
1319
1320out:
1321 return retval;
1322}
1323EXPORT_SYMBOL(vm_insert_pfn);
1324
1280/* 1325/*
1281 * maps a range of physical memory into the requested pages. the old 1326 * maps a range of physical memory into the requested pages. the old
1282 * mappings are removed. any references to nonexistent pages results 1327 * mappings are removed. any references to nonexistent pages results
@@ -2310,10 +2355,12 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
2310 BUG_ON(is_cow_mapping(vma->vm_flags)); 2355 BUG_ON(is_cow_mapping(vma->vm_flags));
2311 2356
2312 pfn = vma->vm_ops->nopfn(vma, address & PAGE_MASK); 2357 pfn = vma->vm_ops->nopfn(vma, address & PAGE_MASK);
2313 if (pfn == NOPFN_OOM) 2358 if (unlikely(pfn == NOPFN_OOM))
2314 return VM_FAULT_OOM; 2359 return VM_FAULT_OOM;
2315 if (pfn == NOPFN_SIGBUS) 2360 else if (unlikely(pfn == NOPFN_SIGBUS))
2316 return VM_FAULT_SIGBUS; 2361 return VM_FAULT_SIGBUS;
2362 else if (unlikely(pfn == NOPFN_REFAULT))
2363 return VM_FAULT_MINOR;
2317 2364
2318 page_table = pte_offset_map_lock(mm, pmd, address, &ptl); 2365 page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
2319 2366