aboutsummaryrefslogtreecommitdiff
path: root/mm/mmap.c
diff options
context:
space:
mode:
authorLevin Calado <levincalado@gmail.com>2015-06-14 23:24:15 +0800
committerMoyster <oysterized@gmail.com>2016-08-26 20:36:21 +0200
commit3a34dc17318f9bf09dbd7d10ac087a8a75f5f629 (patch)
tree8ea4d532a0a486879f369d7cd61d2d03edeb6618 /mm/mmap.c
parent5cff97db281b250545152284249a258a4f5c5ccf (diff)
add uksm 0.1.2.3 for v3.10 .ge.46.patch
Conflicts: fs/exec.c Signed-off-by: Stefan Guendhoer <stefan@guendhoer.com>
Diffstat (limited to 'mm/mmap.c')
-rw-r--r--mm/mmap.c49
1 files changed, 43 insertions, 6 deletions
diff --git a/mm/mmap.c b/mm/mmap.c
index ceb1b5732..18856ffca 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -36,6 +36,7 @@
#include <linux/sched/sysctl.h>
#include <linux/notifier.h>
#include <linux/memory.h>
+#include <linux/ksm.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
@@ -65,7 +66,7 @@ static void unmap_region(struct mm_struct *mm,
* MAP_SHARED r: (no) no r: (yes) yes r: (no) yes r: (no) yes
* w: (no) no w: (no) no w: (yes) yes w: (no) no
* x: (no) no x: (no) yes x: (no) yes x: (yes) yes
- *
+ *
* MAP_PRIVATE r: (no) no r: (yes) yes r: (no) yes r: (no) yes
* w: (no) no w: (no) no w: (copy) copy w: (no) no
* x: (no) no x: (no) yes x: (no) yes x: (yes) yes
@@ -252,6 +253,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
if (vma->vm_file)
fput(vma->vm_file);
mpol_put(vma_policy(vma));
+ uksm_remove_vma(vma);
kmem_cache_free(vm_area_cachep, vma);
return next;
}
@@ -707,9 +709,16 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
long adjust_next = 0;
int remove_next = 0;
+/*
+ * to avoid deadlock, ksm_remove_vma must be done before any spin_lock is
+ * acquired
+ */
+ uksm_remove_vma(vma);
+
if (next && !insert) {
struct vm_area_struct *exporter = NULL;
+ uksm_remove_vma(next);
if (end >= next->vm_end) {
/*
* vma expands, overlapping all the next, and
@@ -803,6 +812,7 @@ again: remove_next = 1 + (end > next->vm_end);
end_changed = true;
}
vma->vm_pgoff = pgoff;
+
if (adjust_next) {
next->vm_start += adjust_next << PAGE_SHIFT;
next->vm_pgoff += adjust_next;
@@ -873,16 +883,22 @@ again: remove_next = 1 + (end > next->vm_end);
* up the code too much to do both in one go.
*/
next = vma->vm_next;
- if (remove_next == 2)
+ if (remove_next == 2) {
+ uksm_remove_vma(next);
goto again;
- else if (next)
+ } else if (next) {
vma_gap_update(next);
- else
+ } else {
mm->highest_vm_end = end;
+ }
+ } else {
+ if (next && !insert)
+ uksm_vma_add_new(next);
}
if (insert && file)
uprobe_mmap(insert);
+ uksm_vma_add_new(vma);
validate_mm(mm);
return 0;
@@ -1256,6 +1272,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags) |
mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+ /* If uksm is enabled, we add VM_MERGABLE to new VMAs. */
+ uksm_vm_flags_mod(&vm_flags);
+
if (flags & MAP_LOCKED)
if (!can_do_mlock())
return -EPERM;
@@ -1602,6 +1621,7 @@ munmap_back:
vma_link(mm, vma, prev, rb_link, rb_parent);
file = vma->vm_file;
+ uksm_vma_add_new(vma);
/* Once vma denies write, undo our temporary denial count */
if (correct_wcount)
@@ -1633,6 +1653,7 @@ unmap_and_free_vma:
unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end);
charged = 0;
free_vma:
+ uksm_remove_vma(vma);
kmem_cache_free(vm_area_cachep, vma);
unacct_error:
if (charged)
@@ -1881,7 +1902,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
info.align_mask = 0;
return vm_unmapped_area(&info);
}
-#endif
+#endif
void arch_unmap_area(struct mm_struct *mm, unsigned long addr)
{
@@ -2462,6 +2483,8 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
else
err = vma_adjust(vma, vma->vm_start, addr, vma->vm_pgoff, new);
+ uksm_vma_add_new(new);
+
/* Success. */
if (!err)
return 0;
@@ -2658,6 +2681,7 @@ static unsigned long do_brk(unsigned long addr, unsigned long len)
return addr;
flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
+ uksm_vm_flags_mod(&flags);
error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
if (error & ~PAGE_MASK)
@@ -2725,6 +2749,7 @@ static unsigned long do_brk(unsigned long addr, unsigned long len)
vma->vm_flags = flags;
vma->vm_page_prot = vm_get_page_prot(flags);
vma_link(mm, vma, prev, rb_link, rb_parent);
+ uksm_vma_add_new(vma);
out:
perf_event_mmap(vma);
mm->total_vm += len >> PAGE_SHIFT;
@@ -2759,6 +2784,12 @@ void exit_mmap(struct mm_struct *mm)
/* mm's last user has gone, and its about to be pulled down */
mmu_notifier_release(mm);
+ /*
+ * Taking write lock on mmap_sem does not harm others,
+ * but it's crucial for uksm to avoid races.
+ */
+ down_write(&mm->mmap_sem);
+
if (mm->locked_vm) {
vma = mm->mmap;
while (vma) {
@@ -2795,6 +2826,11 @@ void exit_mmap(struct mm_struct *mm)
}
vm_unacct_memory(nr_accounted);
+ mm->mmap = NULL;
+ mm->mm_rb = RB_ROOT;
+ mm->mmap_cache = NULL;
+ up_write(&mm->mmap_sem);
+
WARN_ON(mm->nr_ptes > (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT);
}
@@ -2906,6 +2942,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
new_vma->vm_ops->open(new_vma);
vma_link(mm, new_vma, prev, rb_link, rb_parent);
*need_rmap_locks = false;
+ uksm_vma_add_new(new_vma);
}
}
return new_vma;
@@ -3007,10 +3044,10 @@ int install_special_mapping(struct mm_struct *mm,
ret = insert_vm_struct(mm, vma);
if (ret)
goto out;
-
mm->total_vm += len >> PAGE_SHIFT;
perf_event_mmap(vma);
+ uksm_vma_add_new(vma);
return 0;