From fb155c1619f056ae9765eed272cd6aba6e1a7399 Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@g5.osdl.org>
Date: Sun, 11 Dec 2005 19:46:02 -0800
Subject: Allow arbitrary shared PFNMAP's

A shared mapping doesn't cause COW-pages, so we don't need to worry
about the whole vm_pgoff logic to decide if a PFN-remapped page has
gone through COW or not.

This makes it possible to entirely avoid the special "partial remapping"
logic for the common case.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 mm/memory.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

(limited to 'mm/memory.c')

diff --git a/mm/memory.c b/mm/memory.c
index aa8af0e..e65f8fc 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -377,6 +377,8 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
 		unsigned long off = (addr - vma->vm_start) >> PAGE_SHIFT;
 		if (pfn == vma->vm_pgoff + off)
 			return NULL;
+		if (vma->vm_flags & VM_SHARED)
+			return NULL;
 	}
 
 	/*
@@ -1343,9 +1345,6 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
 	struct mm_struct *mm = vma->vm_mm;
 	int err;
 
-	if (addr != vma->vm_start || end != vma->vm_end)
-		return incomplete_pfn_remap(vma, addr, end, pfn, prot);
-
 	/*
 	 * Physically remapped pages are special. Tell the
 	 * rest of the world about it:
@@ -1359,9 +1358,18 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
 	 *   VM_PFNMAP tells the core MM that the base pages are just
 	 *	raw PFN mappings, and do not have a "struct page" associated
 	 *	with them.
+	 *
+	 * There's a horrible special case to handle copy-on-write
+	 * behaviour that some programs depend on. We mark the "original"
+	 * un-COW'ed pages by matching them up with "vma->vm_pgoff".
 	 */
+	if (!(vma->vm_flags & VM_SHARED)) {
+		if (addr != vma->vm_start || end != vma->vm_end)
+			return incomplete_pfn_remap(vma, addr, end, pfn, prot);
+		vma->vm_pgoff = pfn;
+	}
+
 	vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-	vma->vm_pgoff = pfn;
 
 	BUG_ON(addr >= end);
 	pfn -= addr >> PAGE_SHIFT;
-- 
cgit v1.1


From 7fc7e2eeecb599ba719c4c4503100fc8cd6a6920 Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@g5.osdl.org>
Date: Sun, 11 Dec 2005 19:57:52 -0800
Subject: Remove (at least temporarily) the "incomplete PFN mapping" support

With the previous commit, we can handle arbitrary shared re-mappings
even without this complexity, and since the only known private mappings
are for strange users of /dev/mem (which never create an incomplete one),
there seems to be no reason to support it.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 mm/memory.c | 46 +---------------------------------------------
 1 file changed, 1 insertion(+), 45 deletions(-)

(limited to 'mm/memory.c')

diff --git a/mm/memory.c b/mm/memory.c
index e65f8fc..430a72e 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1228,50 +1228,6 @@ int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *
 EXPORT_SYMBOL(vm_insert_page);
 
 /*
- * Somebody does a pfn remapping that doesn't actually work as a vma.
- *
- * Do it as individual pages instead, and warn about it. It's bad form,
- * and very inefficient.
- */
-static int incomplete_pfn_remap(struct vm_area_struct *vma,
-		unsigned long start, unsigned long end,
-		unsigned long pfn, pgprot_t prot)
-{
-	static int warn = 10;
-	struct page *page;
-	int retval;
-
-	if (!(vma->vm_flags & VM_INCOMPLETE)) {
-		if (warn) {
-			warn--;
-			printk("%s does an incomplete pfn remapping", current->comm);
-			dump_stack();
-		}
-	}
-	vma->vm_flags |= VM_INCOMPLETE | VM_IO | VM_RESERVED;
-
-	if (start < vma->vm_start || end > vma->vm_end)
-		return -EINVAL;
-
-	if (!pfn_valid(pfn))
-		return -EINVAL;
-
-	page = pfn_to_page(pfn);
-	if (!PageReserved(page))
-		return -EINVAL;
-
-	retval = 0;
-	while (start < end) {
-		retval = insert_page(vma->vm_mm, start, page, prot);
-		if (retval < 0)
-			break;
-		start += PAGE_SIZE;
-		page++;
-	}
-	return retval;
-}
-
-/*
  * maps a range of physical memory into the requested pages. the old
  * mappings are removed. any references to nonexistent pages results
  * in null mappings (currently treated as "copy-on-access")
@@ -1365,7 +1321,7 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
 	 */
 	if (!(vma->vm_flags & VM_SHARED)) {
 		if (addr != vma->vm_start || end != vma->vm_end)
-			return incomplete_pfn_remap(vma, addr, end, pfn, prot);
+			return -EINVAL;
 		vma->vm_pgoff = pfn;
 	}
 
-- 
cgit v1.1


From 67121172f9753f38689651b613a4850e0e75876f Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@g5.osdl.org>
Date: Sun, 11 Dec 2005 20:38:17 -0800
Subject: Allow arbitrary read-only shared pfn-remapping too

The VM layer (for historical reasons) turns a read-only shared mmap into
a private-like mapping with the VM_MAYWRITE bit clear.  Thus checking
just VM_SHARED isn't actually sufficient.

So use a trivial helper function for the cases where we wanted to inquire
if a mapping was COW-like or not.

Moo!

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 mm/memory.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

(limited to 'mm/memory.c')

diff --git a/mm/memory.c b/mm/memory.c
index 430a72e..47c533e 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -349,6 +349,11 @@ void print_bad_pte(struct vm_area_struct *vma, pte_t pte, unsigned long vaddr)
 	dump_stack();
 }
 
+static inline int is_cow_mapping(unsigned int flags)
+{
+	return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
+}
+
 /*
  * This function gets the "struct page" associated with a pte.
  *
@@ -377,7 +382,7 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
 		unsigned long off = (addr - vma->vm_start) >> PAGE_SHIFT;
 		if (pfn == vma->vm_pgoff + off)
 			return NULL;
-		if (vma->vm_flags & VM_SHARED)
+		if (!is_cow_mapping(vma->vm_flags))
 			return NULL;
 	}
 
@@ -439,7 +444,7 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 	 * If it's a COW mapping, write protect it both
 	 * in the parent and the child
 	 */
-	if ((vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE) {
+	if (is_cow_mapping(vm_flags)) {
 		ptep_set_wrprotect(src_mm, addr, src_pte);
 		pte = *src_pte;
 	}
@@ -1319,7 +1324,7 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
 	 * behaviour that some programs depend on. We mark the "original"
 	 * un-COW'ed pages by matching them up with "vma->vm_pgoff".
 	 */
-	if (!(vma->vm_flags & VM_SHARED)) {
+	if (is_cow_mapping(vma->vm_flags)) {
 		if (addr != vma->vm_start || end != vma->vm_end)
 			return -EINVAL;
 		vma->vm_pgoff = pfn;
-- 
cgit v1.1