From: Linus Torvalds <torvalds@linux-foundation.org>
To: Mel Gorman <mel@csn.ul.ie>
Cc: Andrew Morton <akpm@linux-foundation.org>,
Linux-MM <linux-mm@kvack.org>,
LKML <linux-kernel@vger.kernel.org>,
Minchan Kim <minchan.kim@gmail.com>,
KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>,
Christoph Lameter <cl@linux.com>,
Andrea Arcangeli <aarcange@redhat.com>,
Rik van Riel <riel@redhat.com>
Subject: Re: [PATCH 1/2] mm,migration: Prevent rmap_walk_[anon|ksm] seeing the wrong VMA information
Date: Wed, 5 May 2010 10:34:03 -0700 (PDT) [thread overview]
Message-ID: <alpine.LFD.2.00.1005051007140.27218@i5.linux-foundation.org> (raw)
In-Reply-To: <20100505155454.GT20979@csn.ul.ie>
On Wed, 5 May 2010, Mel Gorman wrote:
>
> I'm still thinking of the ordering but one possibility would be to use a mutex
> similar to mm_all_locks_mutex to force the serialisation of rmap_walk instead
> of the trylock-and-retry. That way, the ordering wouldn't matter. It would
> slow migration if multiple processes are migrating pages by some unknowable
> quantity but it would avoid livelocking.
Hmm.. An idea is starting to take form..
How about something like this?
- the lock is per-anon_vma
BUT
- you always lock the _deepest_ anon_vma you can find.
That means just a single lock. And the "deepest" anon_vma is well-defined
for all anon_vma's, because each same_anon_vma chain is always rooted in
the original anon_vma that caused it.
>From the vma, it's simply
avc = list_entry(vma->anon_vma_chain.prev, struct anon_vma_chain, same_vma);
anon_vma = avc->anon_vma;
and once you take that lock, you know you've gotten the lock for all
chains related to that page. We _know_ that every single vma that is
associated with that anon_vma must have a chain that eventually ends in
that entry.
So I wonder if the locking can't be just something like this:
struct anon_vma *lock_anon_vma_root(struct page *page)
{
struct anon_vma *anon_vma, *root;
rcu_read_lock();
anon_vma = page_anon_vma(page);
if (!anon_vma)
return ret;
/* Make sure the anon_vma 'same_anon_vma' list is stable! */
spin_lock(&anon_vma->lock);
root = NULL;
if (!list_empty(&anon_vma->head)) {
struct anon_vma_chain *avc;
struct vm_area_struct *vma;
struct anon_vma *root;
avc = list_first_entry(&anon_vma->head, struct anon_vma_chain, same_anon_vma);
vma = avc->vma;
avc = list_entry(vma->anon_vma_chain.prev, struct anon_vma_chain, same_vma);
root = avc->anon_vma;
}
/* We already locked it - anon_vma _was_ the root */
if (root == anon_vma)
return root;
spin_unlock(&anon_vma->lock);
if (root) {
spin_lock(&root->lock);
return root;
}
rcu_read_unlock();
return NULL;
}
and
void unlock_anon_vma_root(struct anon_vma *root)
{
spin_unlock(&root->lock);
rcu_read_unlock();
}
or something. I agree that the above is not _beautiful_, and it's not
exactly simple, but it does seem to have the absolutely huge advantage
that it is a nice O(1) thing that only ever takes a single lock and has no
nesting. And while the code looks complicated, it's based on a pretty
simple constraint on the anon_vma's that we already require (ie that all
related anon_vma chains have to end up at the same root anon_vma).
In other words: _any_ vma that is associated with _any_ related anon_vma
will always end up feeding up to the same root anon_vma.
I do think other people should think this through. And it needs a comment
that really explains all this.
(And the code above is written in my email editor - it has not been
tested, compiled, or anythign else. It may _look_ like real code, but
think of it as pseudo-code where the explanation for the code is more
important than the exact details.
NOTE NOTE NOTE! In particular, I think that the 'rcu_read_lock()' and the
actual lookup of the anon_vma (ie the "anon_vma = page_anon_vma(page)")
part should probably be in the callers. I put it in the pseudo-code itself
to just show how you go from a 'struct page' to the "immediate" anon_vma
it is associated with, and from that to the "root" anon_vma of the whole
chain.
And maybe I'm too clever for myself, and I've made some fundamental
mistake that means that the above doesn't work.
Linus
next prev parent reply other threads:[~2010-05-05 17:37 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-05 13:14 [PATCH 0/2] Fix migration races in rmap_walk() V5 Mel Gorman
2010-05-05 13:14 ` [PATCH 1/2] mm,migration: Prevent rmap_walk_[anon|ksm] seeing the wrong VMA information Mel Gorman
2010-05-05 14:34 ` Linus Torvalds
2010-05-05 14:56 ` Mel Gorman
2010-05-05 15:31 ` Linus Torvalds
2010-05-05 15:54 ` Mel Gorman
2010-05-05 16:13 ` Andrea Arcangeli
2010-05-05 19:11 ` Peter Zijlstra
2010-05-05 19:57 ` Andrea Arcangeli
2010-05-21 0:27 ` Andrea Arcangeli
2010-05-06 10:37 ` Mel Gorman
2010-05-05 17:34 ` Linus Torvalds [this message]
2010-05-05 17:57 ` Linus Torvalds
2010-05-05 18:14 ` Mel Gorman
2010-05-05 18:34 ` Linus Torvalds
2010-05-06 11:03 ` Mel Gorman
2010-05-06 13:40 ` Rik van Riel
2010-05-06 13:45 ` Mel Gorman
2010-05-05 17:53 ` Mel Gorman
2010-05-05 18:02 ` Linus Torvalds
2010-05-05 18:17 ` Mel Gorman
2010-05-06 0:22 ` Mel Gorman
2010-05-06 0:42 ` Linus Torvalds
2010-05-06 10:02 ` Mel Gorman
2010-05-06 14:15 ` Linus Torvalds
2010-05-06 14:25 ` Mel Gorman
2010-05-06 9:47 ` Minchan Kim
2010-05-06 9:54 ` Mel Gorman
2010-05-06 10:01 ` Minchan Kim
2010-05-06 10:10 ` Mel Gorman
2010-05-06 14:06 ` Linus Torvalds
2010-05-06 15:59 ` Minchan Kim
2010-05-06 7:38 ` KAMEZAWA Hiroyuki
2010-05-06 9:46 ` Mel Gorman
2010-05-06 23:52 ` KAMEZAWA Hiroyuki
2010-05-07 5:49 ` KAMEZAWA Hiroyuki
2010-05-05 13:14 ` [PATCH 2/2] mm,migration: Fix race between shift_arg_pages and rmap_walk by guaranteeing rmap_walk finds PTEs created within the temporary stack Mel Gorman
2010-05-06 15:33 [PATCH 0/2] Fix migration races in rmap_walk() V6 Mel Gorman
2010-05-06 15:33 ` [PATCH 1/2] mm,migration: Prevent rmap_walk_[anon|ksm] seeing the wrong VMA information Mel Gorman
2010-05-06 15:44 ` Rik van Riel
2010-05-06 15:51 ` Mel Gorman
2010-05-06 15:59 ` Linus Torvalds
2010-05-06 17:07 ` Mel Gorman
2010-05-06 23:20 [PATCH 0/2] Fix migration races in rmap_walk() V7 Mel Gorman
2010-05-06 23:20 ` [PATCH 1/2] mm,migration: Prevent rmap_walk_[anon|ksm] seeing the wrong VMA information Mel Gorman
2010-05-07 0:56 ` KAMEZAWA Hiroyuki
2010-05-07 16:26 ` Mel Gorman
2010-05-08 15:39 ` Andrea Arcangeli
2010-05-08 17:02 ` Linus Torvalds
2010-05-08 18:04 ` Andrea Arcangeli
2010-05-08 19:51 ` Linus Torvalds
2010-05-09 19:23 ` Mel Gorman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=alpine.LFD.2.00.1005051007140.27218@i5.linux-foundation.org \
--to=torvalds@linux-foundation.org \
--cc=aarcange@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=cl@linux.com \
--cc=kamezawa.hiroyu@jp.fujitsu.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mel@csn.ul.ie \
--cc=minchan.kim@gmail.com \
--cc=riel@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®