diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/hugetlb.c | 12 | ||||
-rw-r--r-- | mm/memory.c | 48 | ||||
-rw-r--r-- | mm/vmscan.c | 2 |
3 files changed, 60 insertions, 2 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index ca9a7c6d7e97..1a12f5b9a0ab 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -2961,7 +2961,17 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2961 | break; | 2961 | break; |
2962 | } | 2962 | } |
2963 | 2963 | ||
2964 | if (absent || | 2964 | /* |
2965 | * We need call hugetlb_fault for both hugepages under migration | ||
2966 | * (in which case hugetlb_fault waits for the migration,) and | ||
2967 | * hwpoisoned hugepages (in which case we need to prevent the | ||
2968 | * caller from accessing to them.) In order to do this, we use | ||
2969 | * here is_swap_pte instead of is_hugetlb_entry_migration and | ||
2970 | * is_hugetlb_entry_hwpoisoned. This is because it simply covers | ||
2971 | * both cases, and because we can't follow correct pages | ||
2972 | * directly from any kind of swap entries. | ||
2973 | */ | ||
2974 | if (absent || is_swap_pte(huge_ptep_get(pte)) || | ||
2965 | ((flags & FOLL_WRITE) && !pte_write(huge_ptep_get(pte)))) { | 2975 | ((flags & FOLL_WRITE) && !pte_write(huge_ptep_get(pte)))) { |
2966 | int ret; | 2976 | int ret; |
2967 | 2977 | ||
diff --git a/mm/memory.c b/mm/memory.c index 494526ae024a..ba94dec5b259 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -216,6 +216,7 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm) | |||
216 | tlb->mm = mm; | 216 | tlb->mm = mm; |
217 | 217 | ||
218 | tlb->fullmm = fullmm; | 218 | tlb->fullmm = fullmm; |
219 | tlb->need_flush_all = 0; | ||
219 | tlb->start = -1UL; | 220 | tlb->start = -1UL; |
220 | tlb->end = 0; | 221 | tlb->end = 0; |
221 | tlb->need_flush = 0; | 222 | tlb->need_flush = 0; |
@@ -2392,6 +2393,53 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, | |||
2392 | } | 2393 | } |
2393 | EXPORT_SYMBOL(remap_pfn_range); | 2394 | EXPORT_SYMBOL(remap_pfn_range); |
2394 | 2395 | ||
2396 | /** | ||
2397 | * vm_iomap_memory - remap memory to userspace | ||
2398 | * @vma: user vma to map to | ||
2399 | * @start: start of area | ||
2400 | * @len: size of area | ||
2401 | * | ||
2402 | * This is a simplified io_remap_pfn_range() for common driver use. The | ||
2403 | * driver just needs to give us the physical memory range to be mapped, | ||
2404 | * we'll figure out the rest from the vma information. | ||
2405 | * | ||
2406 | * NOTE! Some drivers might want to tweak vma->vm_page_prot first to get | ||
2407 | * whatever write-combining details or similar. | ||
2408 | */ | ||
2409 | int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len) | ||
2410 | { | ||
2411 | unsigned long vm_len, pfn, pages; | ||
2412 | |||
2413 | /* Check that the physical memory area passed in looks valid */ | ||
2414 | if (start + len < start) | ||
2415 | return -EINVAL; | ||
2416 | /* | ||
2417 | * You *really* shouldn't map things that aren't page-aligned, | ||
2418 | * but we've historically allowed it because IO memory might | ||
2419 | * just have smaller alignment. | ||
2420 | */ | ||
2421 | len += start & ~PAGE_MASK; | ||
2422 | pfn = start >> PAGE_SHIFT; | ||
2423 | pages = (len + ~PAGE_MASK) >> PAGE_SHIFT; | ||
2424 | if (pfn + pages < pfn) | ||
2425 | return -EINVAL; | ||
2426 | |||
2427 | /* We start the mapping 'vm_pgoff' pages into the area */ | ||
2428 | if (vma->vm_pgoff > pages) | ||
2429 | return -EINVAL; | ||
2430 | pfn += vma->vm_pgoff; | ||
2431 | pages -= vma->vm_pgoff; | ||
2432 | |||
2433 | /* Can we fit all of the mapping? */ | ||
2434 | vm_len = vma->vm_end - vma->vm_start; | ||
2435 | if (vm_len >> PAGE_SHIFT > pages) | ||
2436 | return -EINVAL; | ||
2437 | |||
2438 | /* Ok, let it rip */ | ||
2439 | return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot); | ||
2440 | } | ||
2441 | EXPORT_SYMBOL(vm_iomap_memory); | ||
2442 | |||
2395 | static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd, | 2443 | static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd, |
2396 | unsigned long addr, unsigned long end, | 2444 | unsigned long addr, unsigned long end, |
2397 | pte_fn_t fn, void *data) | 2445 | pte_fn_t fn, void *data) |
diff --git a/mm/vmscan.c b/mm/vmscan.c index 88c5fed8b9a4..669fba39be1a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -3188,9 +3188,9 @@ int kswapd_run(int nid) | |||
3188 | if (IS_ERR(pgdat->kswapd)) { | 3188 | if (IS_ERR(pgdat->kswapd)) { |
3189 | /* failure at boot is fatal */ | 3189 | /* failure at boot is fatal */ |
3190 | BUG_ON(system_state == SYSTEM_BOOTING); | 3190 | BUG_ON(system_state == SYSTEM_BOOTING); |
3191 | pgdat->kswapd = NULL; | ||
3192 | pr_err("Failed to start kswapd on node %d\n", nid); | 3191 | pr_err("Failed to start kswapd on node %d\n", nid); |
3193 | ret = PTR_ERR(pgdat->kswapd); | 3192 | ret = PTR_ERR(pgdat->kswapd); |
3193 | pgdat->kswapd = NULL; | ||
3194 | } | 3194 | } |
3195 | return ret; | 3195 | return ret; |
3196 | } | 3196 | } |