aboutsummaryrefslogtreecommitdiffstats
path: root/mm/fremap.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2007-07-19 04:47:24 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:41 -0400
commit3ee6dafc677a68e461a7ddafc94a580ebab80735 (patch)
tree6a92c9f5bd24ff80c52c944327c3b065234f7ad2 /mm/fremap.c
parentbb2d5ce16409efcdf94017a6b6fecd468226e29c (diff)
only allow nonlinear vmas for ram backed filesystems
page_mkclean() doesn't re-protect ptes for non-linear mappings, so a later re-dirty through such a mapping will not generate a fault, PG_dirty will not reflect the dirty state and the dirty count will be skewed. This implies that msync() is also currently broken for nonlinear mappings. The easiest solution is to emulate remap_file_pages on non-linear mappings with simple mmap() for non ram-backed filesystems. Applications continue to work (albeit slower), as long as the number of remappings remain below the maximum vma count. However all currently known real uses of non-linear mappings are for ram backed filesystems, which this patch doesn't affect. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: William Lee Irwin III <wli@holomorphy.com> Cc: Nick Piggin <nickpiggin@yahoo.com.au> Cc: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/fremap.c')
-rw-r--r--mm/fremap.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/mm/fremap.c b/mm/fremap.c
index 5f50d736a037..c395b1abf082 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -181,6 +181,25 @@ asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
181 goto retry; 181 goto retry;
182 } 182 }
183 mapping = vma->vm_file->f_mapping; 183 mapping = vma->vm_file->f_mapping;
184 /*
185 * page_mkclean doesn't work on nonlinear vmas, so if
186 * dirty pages need to be accounted, emulate with linear
187 * vmas.
188 */
189 if (mapping_cap_account_dirty(mapping)) {
190 unsigned long addr;
191
192 flags &= MAP_NONBLOCK;
193 addr = mmap_region(vma->vm_file, start, size,
194 flags, vma->vm_flags, pgoff, 1);
195 if (IS_ERR_VALUE(addr)) {
196 err = addr;
197 } else {
198 BUG_ON(addr != start);
199 err = 0;
200 }
201 goto out;
202 }
184 spin_lock(&mapping->i_mmap_lock); 203 spin_lock(&mapping->i_mmap_lock);
185 flush_dcache_mmap_lock(mapping); 204 flush_dcache_mmap_lock(mapping);
186 vma->vm_flags |= VM_NONLINEAR; 205 vma->vm_flags |= VM_NONLINEAR;