From: Rajesh Venkatasubramanian 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++; _