
From: Rajesh Venkatasubramanian <vrajesh@eecs.umich.edu>

The remap_file_pages system call with MAP_NONBLOCK flag does not
install file-ptes when the required pages are not found in the
page cache. Modify the populate functions to install file-ptes
if the mapping is non-linear and the required pages are not found
in the page cache.

Patch is for test4-mm6. Compiles and boots. Patch tested using the
programs at:

http://www-personal.engin.umich.edu/~vrajesh/linux/remap-file-pages/




 25-akpm/include/linux/mm.h |    1 +
 25-akpm/mm/filemap.c       |   14 ++++++++++++++
 25-akpm/mm/fremap.c        |   39 +++++++++++++++++++++++++++++++++++++++
 25-akpm/mm/shmem.c         |   15 +++++++++++++++
 4 files changed, 69 insertions(+)

diff -puN include/linux/mm.h~remap_file_pages-MAP_NONBLOCK-fix include/linux/mm.h
--- 25/include/linux/mm.h~remap_file_pages-MAP_NONBLOCK-fix	Fri Sep  5 11:35:04 2003
+++ 25-akpm/include/linux/mm.h	Fri Sep  5 11:35:04 2003
@@ -432,6 +432,7 @@ extern pmd_t *FASTCALL(__pmd_alloc(struc
 extern pte_t *FASTCALL(pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsigned long address));
 extern pte_t *FASTCALL(pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address));
 extern int install_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, struct page *page, pgprot_t prot);
+extern int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, unsigned long pgoff, pgprot_t prot);
 extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
diff -puN mm/filemap.c~remap_file_pages-MAP_NONBLOCK-fix mm/filemap.c
--- 25/mm/filemap.c~remap_file_pages-MAP_NONBLOCK-fix	Fri Sep  5 11:35:04 2003
+++ 25-akpm/mm/filemap.c	Fri Sep  5 11:35:04 2003
@@ -1266,6 +1266,20 @@ repeat:
 			page_cache_release(page);
 			return err;
 		}
+	} else {
+	    	/*
+		 * If a nonlinear mapping then store the file page offset
+		 * in the pte.
+		 */
+	    	unsigned long pgidx;
+		pgidx = (addr - vma->vm_start) >> PAGE_SHIFT;
+		pgidx += vma->vm_pgoff;
+		pgidx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
+		if (pgoff != pgidx) {
+	    		err = install_file_pte(mm, vma, addr, pgoff, prot);
+			if (err)
+		    		return err;
+		}
 	}
 
 	len -= PAGE_SIZE;
diff -puN mm/fremap.c~remap_file_pages-MAP_NONBLOCK-fix mm/fremap.c
--- 25/mm/fremap.c~remap_file_pages-MAP_NONBLOCK-fix	Fri Sep  5 11:35:04 2003
+++ 25-akpm/mm/fremap.c	Fri Sep  5 11:35:04 2003
@@ -100,6 +100,45 @@ err:
 EXPORT_SYMBOL(install_page);
 
 
+/*
+ * Install a file pte to a given virtual memory address, release any
+ * previously existing mapping.
+ */
+int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
+		unsigned long addr, unsigned long pgoff, pgprot_t prot)
+{
+	int err = -ENOMEM, flush;
+	pte_t *pte;
+	pgd_t *pgd;
+	pmd_t *pmd;
+
+	pgd = pgd_offset(mm, addr);
+	spin_lock(&mm->page_table_lock);
+
+	pmd = pmd_alloc(mm, pgd, addr);
+	if (!pmd)
+		goto err_unlock;
+
+	pte = pte_alloc_map(mm, pmd, addr);
+	if (!pte)
+		goto err_unlock;
+
+	flush = zap_pte(mm, vma, addr, pte);
+
+	set_pte(pte, pgoff_to_pte(pgoff));
+	pte_unmap(pte);
+	if (flush)
+		flush_tlb_page(vma, addr);
+	update_mmu_cache(vma, addr, *pte);
+	spin_unlock(&mm->page_table_lock);
+	return 0;
+
+err_unlock:
+	spin_unlock(&mm->page_table_lock);
+	return err;
+}
+
+
 /***
  * sys_remap_file_pages - remap arbitrary pages of a shared backing store
  *                        file within an existing vma.
diff -puN mm/shmem.c~remap_file_pages-MAP_NONBLOCK-fix mm/shmem.c
--- 25/mm/shmem.c~remap_file_pages-MAP_NONBLOCK-fix	Fri Sep  5 11:35:04 2003
+++ 25-akpm/mm/shmem.c	Fri Sep  5 11:35:04 2003
@@ -984,7 +984,22 @@ static int shmem_populate(struct vm_area
 				page_cache_release(page);
 				return err;
 			}
+		} else if (nonblock) {
+	    		/*
+		 	 * If a nonlinear mapping then store the file page
+			 * offset in the pte.
+			 */
+	    		unsigned long pgidx;
+			pgidx = (addr - vma->vm_start) >> PAGE_SHIFT;
+			pgidx += vma->vm_pgoff;
+			pgidx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
+			if (pgoff != pgidx) {
+	    			err = install_file_pte(mm, vma, addr, pgoff, prot);
+				if (err)
+		    			return err;
+			}
 		}
+
 		len -= PAGE_SIZE;
 		addr += PAGE_SIZE;
 		pgoff++;

_
