diff options
-rw-r--r-- | mm/madvise.c | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/mm/madvise.c b/mm/madvise.c index 603c5257ed6e..e75096b5a6d3 100644 --- a/mm/madvise.c +++ b/mm/madvise.c | |||
@@ -12,6 +12,24 @@ | |||
12 | #include <linux/hugetlb.h> | 12 | #include <linux/hugetlb.h> |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * Any behaviour which results in changes to the vma->vm_flags needs to | ||
16 | * take mmap_sem for writing. Others, which simply traverse vmas, need | ||
17 | * to only take it for reading. | ||
18 | */ | ||
19 | static int madvise_need_mmap_write(int behavior) | ||
20 | { | ||
21 | switch (behavior) { | ||
22 | case MADV_REMOVE: | ||
23 | case MADV_WILLNEED: | ||
24 | case MADV_DONTNEED: | ||
25 | return 0; | ||
26 | default: | ||
27 | /* be safe, default to 1. list exceptions explicitly */ | ||
28 | return 1; | ||
29 | } | ||
30 | } | ||
31 | |||
32 | /* | ||
15 | * We can potentially split a vm area into separate | 33 | * We can potentially split a vm area into separate |
16 | * areas, each area with its own behavior. | 34 | * areas, each area with its own behavior. |
17 | */ | 35 | */ |
@@ -183,9 +201,9 @@ static long madvise_remove(struct vm_area_struct *vma, | |||
183 | + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); | 201 | + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); |
184 | 202 | ||
185 | /* vmtruncate_range needs to take i_mutex and i_alloc_sem */ | 203 | /* vmtruncate_range needs to take i_mutex and i_alloc_sem */ |
186 | up_write(¤t->mm->mmap_sem); | 204 | up_read(¤t->mm->mmap_sem); |
187 | error = vmtruncate_range(mapping->host, offset, endoff); | 205 | error = vmtruncate_range(mapping->host, offset, endoff); |
188 | down_write(¤t->mm->mmap_sem); | 206 | down_read(¤t->mm->mmap_sem); |
189 | return error; | 207 | return error; |
190 | } | 208 | } |
191 | 209 | ||
@@ -270,7 +288,10 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior) | |||
270 | int error = -EINVAL; | 288 | int error = -EINVAL; |
271 | size_t len; | 289 | size_t len; |
272 | 290 | ||
273 | down_write(¤t->mm->mmap_sem); | 291 | if (madvise_need_mmap_write(behavior)) |
292 | down_write(¤t->mm->mmap_sem); | ||
293 | else | ||
294 | down_read(¤t->mm->mmap_sem); | ||
274 | 295 | ||
275 | if (start & ~PAGE_MASK) | 296 | if (start & ~PAGE_MASK) |
276 | goto out; | 297 | goto out; |
@@ -332,6 +353,10 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior) | |||
332 | vma = find_vma(current->mm, start); | 353 | vma = find_vma(current->mm, start); |
333 | } | 354 | } |
334 | out: | 355 | out: |
335 | up_write(¤t->mm->mmap_sem); | 356 | if (madvise_need_mmap_write(behavior)) |
357 | up_write(¤t->mm->mmap_sem); | ||
358 | else | ||
359 | up_read(¤t->mm->mmap_sem); | ||
360 | |||
336 | return error; | 361 | return error; |
337 | } | 362 | } |