Commit 4bb9c5c02153dfc89a6c73a6f32091413805ad7d

Authored by Pallipadi, Venkatesh
Committed by Ingo Molnar
1 parent 6a5c05f002

VM, x86, PAT: Change is_linear_pfn_mapping to not use vm_pgoff

Impact: fix false positive PAT warnings - also fix VirtalBox hang

Use of vma->vm_pgoff to identify the pfnmaps that are fully
mapped at mmap time is broken. vm_pgoff is set by generic mmap
code even for cases where drivers are setting up the mappings
at the fault time.

The problem was originally reported here:

 http://marc.info/?l=linux-kernel&m=123383810628583&w=2

Change is_linear_pfn_mapping logic to overload VM_INSERTPAGE
flag along with VM_PFNMAP to mean full PFNMAP setup at mmap
time.

Problem also tracked at:

 http://bugzilla.kernel.org/show_bug.cgi?id=12800

Reported-by: Thomas Hellstrom <thellstrom@vmware.com>
Tested-by: Frans Pop <elendil@planet.nl>
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Suresh Siddha <suresh.b.siddha>@intel.com>
Cc: Nick Piggin <npiggin@suse.de>
Cc: "ebiederm@xmission.com" <ebiederm@xmission.com>
Cc: <stable@kernel.org> # only for 2.6.29.1, not .28
LKML-Reference: <20090313004527.GA7176@linux-os.sc.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

Showing 3 changed files with 20 additions and 6 deletions Side-by-side Diff

... ... @@ -641,10 +641,11 @@
641 641 is_ram = pat_pagerange_is_ram(paddr, paddr + size);
642 642  
643 643 /*
644   - * reserve_pfn_range() doesn't support RAM pages.
  644 + * reserve_pfn_range() doesn't support RAM pages. Maintain the current
  645 + * behavior with RAM pages by returning success.
645 646 */
646 647 if (is_ram != 0)
647   - return -EINVAL;
  648 + return 0;
648 649  
649 650 ret = reserve_memtype(paddr, paddr + size, want_flags, &flags);
650 651 if (ret)
... ... @@ -98,7 +98,7 @@
98 98 #define VM_HUGETLB 0x00400000 /* Huge TLB Page VM */
99 99 #define VM_NONLINEAR 0x00800000 /* Is non-linear (remap_file_pages) */
100 100 #define VM_MAPPED_COPY 0x01000000 /* T if mapped copy of data (nommu mmap) */
101   -#define VM_INSERTPAGE 0x02000000 /* The vma has had "vm_insert_page()" done on it */
  101 +#define VM_INSERTPAGE 0x02000000 /* The vma has had "vm_insert_page()" done on it. Refer note in VM_PFNMAP_AT_MMAP below */
102 102 #define VM_ALWAYSDUMP 0x04000000 /* Always include in core dumps */
103 103  
104 104 #define VM_CAN_NONLINEAR 0x08000000 /* Has ->fault & does nonlinear pages */
... ... @@ -127,6 +127,17 @@
127 127 #define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_RESERVED | VM_PFNMAP)
128 128  
129 129 /*
  130 + * pfnmap vmas that are fully mapped at mmap time (not mapped on fault).
  131 + * Used by x86 PAT to identify such PFNMAP mappings and optimize their handling.
  132 + * Note VM_INSERTPAGE flag is overloaded here. i.e,
  133 + * VM_INSERTPAGE && !VM_PFNMAP implies
  134 + * The vma has had "vm_insert_page()" done on it
  135 + * VM_INSERTPAGE && VM_PFNMAP implies
  136 + * The vma is PFNMAP with full mapping at mmap time
  137 + */
  138 +#define VM_PFNMAP_AT_MMAP (VM_INSERTPAGE | VM_PFNMAP)
  139 +
  140 +/*
130 141 * mapping from the currently active vm_flags protection bits (the
131 142 * low four bits) to a page protection mask..
132 143 */
... ... @@ -145,7 +156,7 @@
145 156 */
146 157 static inline int is_linear_pfn_mapping(struct vm_area_struct *vma)
147 158 {
148   - return ((vma->vm_flags & VM_PFNMAP) && vma->vm_pgoff);
  159 + return ((vma->vm_flags & VM_PFNMAP_AT_MMAP) == VM_PFNMAP_AT_MMAP);
149 160 }
150 161  
151 162 static inline int is_pfn_mapping(struct vm_area_struct *vma)
... ... @@ -1665,9 +1665,10 @@
1665 1665 * behaviour that some programs depend on. We mark the "original"
1666 1666 * un-COW'ed pages by matching them up with "vma->vm_pgoff".
1667 1667 */
1668   - if (addr == vma->vm_start && end == vma->vm_end)
  1668 + if (addr == vma->vm_start && end == vma->vm_end) {
1669 1669 vma->vm_pgoff = pfn;
1670   - else if (is_cow_mapping(vma->vm_flags))
  1670 + vma->vm_flags |= VM_PFNMAP_AT_MMAP;
  1671 + } else if (is_cow_mapping(vma->vm_flags))
1671 1672 return -EINVAL;
1672 1673  
1673 1674 vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
... ... @@ -1679,6 +1680,7 @@
1679 1680 * needed from higher level routine calling unmap_vmas
1680 1681 */
1681 1682 vma->vm_flags &= ~(VM_IO | VM_RESERVED | VM_PFNMAP);
  1683 + vma->vm_flags &= ~VM_PFNMAP_AT_MMAP;
1682 1684 return -EINVAL;
1683 1685 }
1684 1686