Merge tag 'v3.8-rc5' into x86/mm
The __pa() fixup series that follows touches KVM code that is not present in the existing branch based on v3.7-rc5, so merge in the current upstream from Linus. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
#include <asm/pgalloc.h> /* pgd_*(), ... */
|
||||
#include <asm/kmemcheck.h> /* kmemcheck_*(), ... */
|
||||
#include <asm/fixmap.h> /* VSYSCALL_START */
|
||||
#include <asm/rcu.h> /* exception_enter(), ... */
|
||||
#include <asm/context_tracking.h> /* exception_enter(), ... */
|
||||
|
||||
/*
|
||||
* Page fault error code bits:
|
||||
@@ -803,20 +803,6 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
|
||||
__bad_area(regs, error_code, address, SEGV_ACCERR);
|
||||
}
|
||||
|
||||
/* TODO: fixup for "mm-invoke-oom-killer-from-page-fault.patch" */
|
||||
static void
|
||||
out_of_memory(struct pt_regs *regs, unsigned long error_code,
|
||||
unsigned long address)
|
||||
{
|
||||
/*
|
||||
* We ran out of memory, call the OOM killer, and return the userspace
|
||||
* (which will retry the fault, or kill us if we got oom-killed):
|
||||
*/
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
|
||||
pagefault_out_of_memory();
|
||||
}
|
||||
|
||||
static void
|
||||
do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
|
||||
unsigned int fault)
|
||||
@@ -879,7 +865,14 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
|
||||
return 1;
|
||||
}
|
||||
|
||||
out_of_memory(regs, error_code, address);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
|
||||
/*
|
||||
* We ran out of memory, call the OOM killer, and return the
|
||||
* userspace (which will retry the fault, or kill us if we got
|
||||
* oom-killed):
|
||||
*/
|
||||
pagefault_out_of_memory();
|
||||
} else {
|
||||
if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
|
||||
VM_FAULT_HWPOISON_LARGE))
|
||||
|
@@ -274,42 +274,15 @@ static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file,
|
||||
unsigned long pgoff, unsigned long flags)
|
||||
{
|
||||
struct hstate *h = hstate_file(file);
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *vma;
|
||||
unsigned long start_addr;
|
||||
struct vm_unmapped_area_info info;
|
||||
|
||||
if (len > mm->cached_hole_size) {
|
||||
start_addr = mm->free_area_cache;
|
||||
} else {
|
||||
start_addr = TASK_UNMAPPED_BASE;
|
||||
mm->cached_hole_size = 0;
|
||||
}
|
||||
|
||||
full_search:
|
||||
addr = ALIGN(start_addr, huge_page_size(h));
|
||||
|
||||
for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
|
||||
/* At this point: (!vma || addr < vma->vm_end). */
|
||||
if (TASK_SIZE - len < addr) {
|
||||
/*
|
||||
* Start a new search - just in case we missed
|
||||
* some holes.
|
||||
*/
|
||||
if (start_addr != TASK_UNMAPPED_BASE) {
|
||||
start_addr = TASK_UNMAPPED_BASE;
|
||||
mm->cached_hole_size = 0;
|
||||
goto full_search;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!vma || addr + len <= vma->vm_start) {
|
||||
mm->free_area_cache = addr + len;
|
||||
return addr;
|
||||
}
|
||||
if (addr + mm->cached_hole_size < vma->vm_start)
|
||||
mm->cached_hole_size = vma->vm_start - addr;
|
||||
addr = ALIGN(vma->vm_end, huge_page_size(h));
|
||||
}
|
||||
info.flags = 0;
|
||||
info.length = len;
|
||||
info.low_limit = TASK_UNMAPPED_BASE;
|
||||
info.high_limit = TASK_SIZE;
|
||||
info.align_mask = PAGE_MASK & ~huge_page_mask(h);
|
||||
info.align_offset = 0;
|
||||
return vm_unmapped_area(&info);
|
||||
}
|
||||
|
||||
static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file,
|
||||
@@ -317,83 +290,30 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file,
|
||||
unsigned long pgoff, unsigned long flags)
|
||||
{
|
||||
struct hstate *h = hstate_file(file);
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *vma;
|
||||
unsigned long base = mm->mmap_base;
|
||||
unsigned long addr = addr0;
|
||||
unsigned long largest_hole = mm->cached_hole_size;
|
||||
unsigned long start_addr;
|
||||
struct vm_unmapped_area_info info;
|
||||
unsigned long addr;
|
||||
|
||||
/* don't allow allocations above current base */
|
||||
if (mm->free_area_cache > base)
|
||||
mm->free_area_cache = base;
|
||||
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
|
||||
info.length = len;
|
||||
info.low_limit = PAGE_SIZE;
|
||||
info.high_limit = current->mm->mmap_base;
|
||||
info.align_mask = PAGE_MASK & ~huge_page_mask(h);
|
||||
info.align_offset = 0;
|
||||
addr = vm_unmapped_area(&info);
|
||||
|
||||
if (len <= largest_hole) {
|
||||
largest_hole = 0;
|
||||
mm->free_area_cache = base;
|
||||
}
|
||||
try_again:
|
||||
start_addr = mm->free_area_cache;
|
||||
|
||||
/* make sure it can fit in the remaining address space */
|
||||
if (mm->free_area_cache < len)
|
||||
goto fail;
|
||||
|
||||
/* either no address requested or can't fit in requested address hole */
|
||||
addr = (mm->free_area_cache - len) & huge_page_mask(h);
|
||||
do {
|
||||
/*
|
||||
* Lookup failure means no vma is above this address,
|
||||
* i.e. return with success:
|
||||
*/
|
||||
vma = find_vma(mm, addr);
|
||||
if (!vma)
|
||||
return addr;
|
||||
|
||||
if (addr + len <= vma->vm_start) {
|
||||
/* remember the address as a hint for next time */
|
||||
mm->cached_hole_size = largest_hole;
|
||||
return (mm->free_area_cache = addr);
|
||||
} else if (mm->free_area_cache == vma->vm_end) {
|
||||
/* pull free_area_cache down to the first hole */
|
||||
mm->free_area_cache = vma->vm_start;
|
||||
mm->cached_hole_size = largest_hole;
|
||||
}
|
||||
|
||||
/* remember the largest hole we saw so far */
|
||||
if (addr + largest_hole < vma->vm_start)
|
||||
largest_hole = vma->vm_start - addr;
|
||||
|
||||
/* try just below the current vma->vm_start */
|
||||
addr = (vma->vm_start - len) & huge_page_mask(h);
|
||||
} while (len <= vma->vm_start);
|
||||
|
||||
fail:
|
||||
/*
|
||||
* if hint left us with no space for the requested
|
||||
* mapping then try again:
|
||||
*/
|
||||
if (start_addr != base) {
|
||||
mm->free_area_cache = base;
|
||||
largest_hole = 0;
|
||||
goto try_again;
|
||||
}
|
||||
/*
|
||||
* A failed mmap() very likely causes application failure,
|
||||
* so fall back to the bottom-up function here. This scenario
|
||||
* can happen with large stack limits and large mmap()
|
||||
* allocations.
|
||||
*/
|
||||
mm->free_area_cache = TASK_UNMAPPED_BASE;
|
||||
mm->cached_hole_size = ~0UL;
|
||||
addr = hugetlb_get_unmapped_area_bottomup(file, addr0,
|
||||
len, pgoff, flags);
|
||||
|
||||
/*
|
||||
* Restore the topdown base:
|
||||
*/
|
||||
mm->free_area_cache = base;
|
||||
mm->cached_hole_size = ~0UL;
|
||||
if (addr & ~PAGE_MASK) {
|
||||
VM_BUG_ON(addr != -ENOMEM);
|
||||
info.flags = 0;
|
||||
info.low_limit = TASK_UNMAPPED_BASE;
|
||||
info.high_limit = TASK_SIZE;
|
||||
addr = vm_unmapped_area(&info);
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
@@ -715,10 +715,7 @@ static void __init test_wp_bit(void)
|
||||
|
||||
if (!boot_cpu_data.wp_works_ok) {
|
||||
printk(KERN_CONT "No.\n");
|
||||
#ifdef CONFIG_X86_WP_WORKS_OK
|
||||
panic(
|
||||
"This kernel doesn't support CPU's with broken WP. Recompile it for a 386!");
|
||||
#endif
|
||||
panic("Linux doesn't support CPUs with broken WP.");
|
||||
} else {
|
||||
printk(KERN_CONT "Ok.\n");
|
||||
}
|
||||
|
@@ -630,7 +630,9 @@ void __init paging_init(void)
|
||||
* numa support is not compiled in, and later node_set_state
|
||||
* will not set it back.
|
||||
*/
|
||||
node_clear_state(0, N_NORMAL_MEMORY);
|
||||
node_clear_state(0, N_MEMORY);
|
||||
if (N_MEMORY != N_NORMAL_MEMORY)
|
||||
node_clear_state(0, N_NORMAL_MEMORY);
|
||||
|
||||
zone_sizes_init();
|
||||
}
|
||||
|
@@ -137,7 +137,7 @@ static void pgd_dtor(pgd_t *pgd)
|
||||
* against pageattr.c; it is the unique case in which a valid change
|
||||
* of kernel pagetables can't be lazily synchronized by vmalloc faults.
|
||||
* vmalloc faults work because attached pagetables are never freed.
|
||||
* -- wli
|
||||
* -- nyc
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
@@ -301,6 +301,13 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
|
||||
free_page((unsigned long)pgd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to set accessed or dirty bits in the page table entries
|
||||
* on other architectures. On x86, the accessed and dirty bits
|
||||
* are tracked by hardware. However, do_wp_page calls this function
|
||||
* to also make the pte writeable at the same time the dirty bit is
|
||||
* set. In that case we do actually need to write the PTE.
|
||||
*/
|
||||
int ptep_set_access_flags(struct vm_area_struct *vma,
|
||||
unsigned long address, pte_t *ptep,
|
||||
pte_t entry, int dirty)
|
||||
@@ -310,7 +317,6 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
|
||||
if (changed && dirty) {
|
||||
*ptep = entry;
|
||||
pte_update_defer(vma->vm_mm, address, ptep);
|
||||
flush_tlb_page(vma, address);
|
||||
}
|
||||
|
||||
return changed;
|
||||
|
@@ -104,7 +104,7 @@ static void flush_tlb_func(void *info)
|
||||
return;
|
||||
|
||||
if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {
|
||||
if (f->flush_end == TLB_FLUSH_ALL || !cpu_has_invlpg)
|
||||
if (f->flush_end == TLB_FLUSH_ALL)
|
||||
local_flush_tlb();
|
||||
else if (!f->flush_end)
|
||||
__flush_tlb_single(f->flush_start);
|
||||
@@ -197,7 +197,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
|
||||
}
|
||||
|
||||
if (end == TLB_FLUSH_ALL || tlb_flushall_shift == -1
|
||||
|| vmflag == VM_HUGETLB) {
|
||||
|| vmflag & VM_HUGETLB) {
|
||||
local_flush_tlb();
|
||||
goto flush_all;
|
||||
}
|
||||
@@ -337,10 +337,8 @@ static const struct file_operations fops_tlbflush = {
|
||||
|
||||
static int __cpuinit create_tlb_flushall_shift(void)
|
||||
{
|
||||
if (cpu_has_invlpg) {
|
||||
debugfs_create_file("tlb_flushall_shift", S_IRUSR | S_IWUSR,
|
||||
arch_debugfs_dir, NULL, &fops_tlbflush);
|
||||
}
|
||||
debugfs_create_file("tlb_flushall_shift", S_IRUSR | S_IWUSR,
|
||||
arch_debugfs_dir, NULL, &fops_tlbflush);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(create_tlb_flushall_shift);
|
||||
|
Reference in New Issue
Block a user