Commit be98a9cd authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] remap file pages MAP_NONBLOCK fix

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/
parent 5335712e
......@@ -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);
......
......@@ -1266,6 +1266,20 @@ static int filemap_populate(struct vm_area_struct *vma,
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;
......
......@@ -100,6 +100,45 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
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.
......
......@@ -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++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment