]> git.hungrycats.org Git - linux/commitdiff
[PATCH] remap file pages MAP_NONBLOCK fix
authorAndrew Morton <akpm@osdl.org>
Tue, 9 Sep 2003 17:20:33 +0000 (10:20 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Tue, 9 Sep 2003 17:20:33 +0000 (10:20 -0700)
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/

include/linux/mm.h
mm/filemap.c
mm/fremap.c
mm/shmem.c

index 9f9743146b54a8b4d795d2b69a2d68d0c9cc4864..e7ad98ea59b78cb8f54e0b55ed22fa8876eebc70 100644 (file)
@@ -432,6 +432,7 @@ extern pmd_t *FASTCALL(__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned lo
 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);
index 0fe1ba24b8b2381fa959f09704db13448cb171f1..31333d717960014199316a48b1faa26b3fb34e58 100644 (file)
@@ -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;
index b19bdde07bb61c64ce46b0cf93b582f745bdd024..f2c9ee7c78a84590929201ffcfc781373c1150e8 100644 (file)
@@ -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.
index bb429eee7ebdbc4a5201f9bb4a8b325d48456596..b3add61c21d83e77396799cc95d9deda8f31fc6a 100644 (file)
@@ -984,7 +984,22 @@ static int shmem_populate(struct vm_area_struct *vma,
                                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++;