aboutsummaryrefslogtreecommitdiffstats
path: root/mm/ksm.c
diff options
context:
space:
mode:
authorMichel Lespinasse <walken@google.com>2012-10-08 19:31:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 03:22:41 -0400
commitbf181b9f9d8dfbba58b23441ad60d0bc33806d64 (patch)
tree7ad0caaf8998f31c5d910dcbb768f5a1d381b5f4 /mm/ksm.c
parent108d6642ad81bb1d62b401490a334d2c12397517 (diff)
mm anon rmap: replace same_anon_vma linked list with an interval tree.
When a large VMA (anon or private file mapping) is first touched, which will populate its anon_vma field, and then split into many regions through the use of mprotect(), the original anon_vma ends up linking all of the vmas on a linked list. This can cause rmap to become inefficient, as we have to walk potentially thousands of irrelevent vmas before finding the one a given anon page might fall into. By replacing the same_anon_vma linked list with an interval tree (where each avc's interval is determined by its vma's start and last pgoffs), we can make rmap efficient for this use case again. While the change is large, all of its pieces are fairly simple. Most places that were walking the same_anon_vma list were looking for a known pgoff, so they can just use the anon_vma_interval_tree_foreach() interval tree iterator instead. The exception here is ksm, where the page's index is not known. It would probably be possible to rework ksm so that the index would be known, but for now I have decided to keep things simple and just walk the entirety of the interval tree there. When updating vma's that already have an anon_vma assigned, we must take care to re-index the corresponding avc's on their interval tree. This is done through the use of anon_vma_interval_tree_pre_update_vma() and anon_vma_interval_tree_post_update_vma(), which remove the avc's from their interval tree before the update and re-insert them after the update. The anon_vma stays locked during the update, so there is no chance that rmap would miss the vmas that are being updated. Signed-off-by: Michel Lespinasse <walken@google.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Rik van Riel <riel@redhat.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Daniel Santos <daniel.santos@pobox.com> Cc: Hugh Dickins <hughd@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/ksm.c')
-rw-r--r--mm/ksm.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/mm/ksm.c b/mm/ksm.c
index 9638620a7530..14ee5cf8a513 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1618,7 +1618,8 @@ again:
1618 struct vm_area_struct *vma; 1618 struct vm_area_struct *vma;
1619 1619
1620 anon_vma_lock(anon_vma); 1620 anon_vma_lock(anon_vma);
1621 list_for_each_entry(vmac, &anon_vma->head, same_anon_vma) { 1621 anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
1622 0, ULONG_MAX) {
1622 vma = vmac->vma; 1623 vma = vmac->vma;
1623 if (rmap_item->address < vma->vm_start || 1624 if (rmap_item->address < vma->vm_start ||
1624 rmap_item->address >= vma->vm_end) 1625 rmap_item->address >= vma->vm_end)
@@ -1671,7 +1672,8 @@ again:
1671 struct vm_area_struct *vma; 1672 struct vm_area_struct *vma;
1672 1673
1673 anon_vma_lock(anon_vma); 1674 anon_vma_lock(anon_vma);
1674 list_for_each_entry(vmac, &anon_vma->head, same_anon_vma) { 1675 anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
1676 0, ULONG_MAX) {
1675 vma = vmac->vma; 1677 vma = vmac->vma;
1676 if (rmap_item->address < vma->vm_start || 1678 if (rmap_item->address < vma->vm_start ||
1677 rmap_item->address >= vma->vm_end) 1679 rmap_item->address >= vma->vm_end)
@@ -1723,7 +1725,8 @@ again:
1723 struct vm_area_struct *vma; 1725 struct vm_area_struct *vma;
1724 1726
1725 anon_vma_lock(anon_vma); 1727 anon_vma_lock(anon_vma);
1726 list_for_each_entry(vmac, &anon_vma->head, same_anon_vma) { 1728 anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
1729 0, ULONG_MAX) {
1727 vma = vmac->vma; 1730 vma = vmac->vma;
1728 if (rmap_item->address < vma->vm_start || 1731 if (rmap_item->address < vma->vm_start ||
1729 rmap_item->address >= vma->vm_end) 1732 rmap_item->address >= vma->vm_end)