diff options
author | Rich Felker <dalias@libc.org> | 2016-05-20 19:57:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-20 20:58:30 -0400 |
commit | 63678c32e209bd165f33432bbed72b2954ce5ae4 (patch) | |
tree | 8e94976dbe50b78ca23292fe9cf5d69c580e3170 | |
parent | f4fcd55841fc9e46daac553b39361572453c2b88 (diff) |
tmpfs/ramfs: fix VM_MAYSHARE mappings for NOMMU
The nommu do_mmap expects f_op->get_unmapped_area to either succeed or
return -ENOSYS for VM_MAYSHARE (e.g. private read-only) mappings.
Returning addr in the non-MAP_SHARED case was completely wrong, and only
happened to work because addr was 0. However, it prevented VM_MAYSHARE
mappings from sharing backing with the fs cache, and forced such
mappings (including shareable program text) to be copied whenever the
number of mappings transitioned from 0 to 1, impacting performance and
memory usage. Subsequent mappings beyond the first still correctly
shared memory with the first.
Instead, treat VM_MAYSHARE identically to VM_SHARED at the file ops level;
do_mmap already handles the semantic differences between them.
Signed-off-by: Rich Felker <dalias@libc.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Greg Ungerer <gerg@uclinux.org>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/ramfs/file-nommu.c | 8 |
1 files changed, 2 insertions, 6 deletions
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index a586467f6ff6..be3ddd189cd4 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c | |||
@@ -211,14 +211,11 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file, | |||
211 | struct page **pages = NULL, **ptr, *page; | 211 | struct page **pages = NULL, **ptr, *page; |
212 | loff_t isize; | 212 | loff_t isize; |
213 | 213 | ||
214 | if (!(flags & MAP_SHARED)) | ||
215 | return addr; | ||
216 | |||
217 | /* the mapping mustn't extend beyond the EOF */ | 214 | /* the mapping mustn't extend beyond the EOF */ |
218 | lpages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 215 | lpages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
219 | isize = i_size_read(inode); | 216 | isize = i_size_read(inode); |
220 | 217 | ||
221 | ret = -EINVAL; | 218 | ret = -ENOSYS; |
222 | maxpages = (isize + PAGE_SIZE - 1) >> PAGE_SHIFT; | 219 | maxpages = (isize + PAGE_SIZE - 1) >> PAGE_SHIFT; |
223 | if (pgoff >= maxpages) | 220 | if (pgoff >= maxpages) |
224 | goto out; | 221 | goto out; |
@@ -227,7 +224,6 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file, | |||
227 | goto out; | 224 | goto out; |
228 | 225 | ||
229 | /* gang-find the pages */ | 226 | /* gang-find the pages */ |
230 | ret = -ENOMEM; | ||
231 | pages = kcalloc(lpages, sizeof(struct page *), GFP_KERNEL); | 227 | pages = kcalloc(lpages, sizeof(struct page *), GFP_KERNEL); |
232 | if (!pages) | 228 | if (!pages) |
233 | goto out_free; | 229 | goto out_free; |
@@ -263,7 +259,7 @@ out: | |||
263 | */ | 259 | */ |
264 | static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma) | 260 | static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma) |
265 | { | 261 | { |
266 | if (!(vma->vm_flags & VM_SHARED)) | 262 | if (!(vma->vm_flags & (VM_SHARED | VM_MAYSHARE))) |
267 | return -ENOSYS; | 263 | return -ENOSYS; |
268 | 264 | ||
269 | file_accessed(file); | 265 | file_accessed(file); |