Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5c341ee1 authored by Rik van Riel's avatar Rik van Riel Committed by Linus Torvalds
Browse files

mm: track the root (oldest) anon_vma



Track the root (oldest) anon_vma in each anon_vma tree.  Because we only
take the lock on the root anon_vma, we cannot use the lock on higher-up
anon_vmas to lock anything.  This makes it impossible to do an indirect
lookup of the root anon_vma, since the data structures could go away from
under us.

However, a direct pointer is safe because the root anon_vma is always the
last one that gets freed on munmap or exit, by virtue of the same_vma list
order and unlink_anon_vmas walking the list forward.

[akpm@linux-foundation.org: fix typo]
Signed-off-by: default avatarRik van Riel <riel@redhat.com>
Acked-by: default avatarMel Gorman <mel@csn.ul.ie>
Acked-by: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Tested-by: default avatarLarry Woodman <lwoodman@redhat.com>
Acked-by: default avatarLarry Woodman <lwoodman@redhat.com>
Reviewed-by: default avatarMinchan Kim <minchan.kim@gmail.com>
Acked-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent cba48b98
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
 */
struct anon_vma {
	spinlock_t lock;	/* Serialize access to vma list */
	struct anon_vma *root;	/* Root of this anon_vma tree */
#if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)

	/*
+16 −2
Original line number Diff line number Diff line
@@ -132,6 +132,11 @@ int anon_vma_prepare(struct vm_area_struct *vma)
			if (unlikely(!anon_vma))
				goto out_enomem_free_avc;
			allocated = anon_vma;
			/*
			 * This VMA had no anon_vma yet.  This anon_vma is
			 * the root of any anon_vma tree that might form.
			 */
			anon_vma->root = anon_vma;
		}

		anon_vma_lock(anon_vma);
@@ -224,9 +229,15 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
	avc = anon_vma_chain_alloc();
	if (!avc)
		goto out_error_free_anon_vma;
	anon_vma_chain_link(vma, avc, anon_vma);

	/*
	 * The root anon_vma's spinlock is the lock actually used when we
	 * lock any of the anon_vmas in this anon_vma tree.
	 */
	anon_vma->root = pvma->anon_vma->root;
	/* Mark this anon_vma as the one where our new (COWed) pages go. */
	vma->anon_vma = anon_vma;
	anon_vma_chain_link(vma, avc, anon_vma);

	return 0;

@@ -261,7 +272,10 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
{
	struct anon_vma_chain *avc, *next;

	/* Unlink each anon_vma chained to the VMA. */
	/*
	 * Unlink each anon_vma chained to the VMA.  This list is ordered
	 * from newest to oldest, ensuring the root anon_vma gets freed last.
	 */
	list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
		anon_vma_unlink(avc);
		list_del(&avc->same_vma);