diff options
author | Pekka Paalanen <pq@iki.fi> | 2009-02-24 14:44:15 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-02 04:20:37 -0500 |
commit | 340430c572f7b2b275d39965e88bafa71693cb23 (patch) | |
tree | 4be609589171a4bd8c5744178625454c6e5efa3a /arch | |
parent | 3e39aa156a24ce386da378784edd0f748c770087 (diff) |
x86 mmiotrace: fix race with release_kmmio_fault_page()
There was a theoretical possibility to a race between arming a page in
post_kmmio_handler() and disarming the page in
release_kmmio_fault_page():
cpu0 cpu1
------------------------------------------------------------------
mmiotrace shutdown
enter release_kmmio_fault_page
fault on the page
disarm the page
disarm the page
handle the MMIO access
re-arm the page
put the page on release list
remove_kmmio_fault_pages()
fault on the page
page not known to mmiotrace
fall back to do_page_fault()
*KABOOM*
(This scenario also shows the double disarm case which is allowed.)
Fixed by acquiring kmmio_lock in post_kmmio_handler() and checking
if the page is being released from mmiotrace.
Signed-off-by: Pekka Paalanen <pq@iki.fi>
Cc: Stuart Bennett <stuart@freedesktop.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/mm/kmmio.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c index 4c66bd3a240d..9f205030d9aa 100644 --- a/arch/x86/mm/kmmio.c +++ b/arch/x86/mm/kmmio.c | |||
@@ -38,7 +38,8 @@ struct kmmio_fault_page { | |||
38 | /* | 38 | /* |
39 | * Number of times this page has been registered as a part | 39 | * Number of times this page has been registered as a part |
40 | * of a probe. If zero, page is disarmed and this may be freed. | 40 | * of a probe. If zero, page is disarmed and this may be freed. |
41 | * Used only by writers (RCU). | 41 | * Used only by writers (RCU) and post_kmmio_handler(). |
42 | * Protected by kmmio_lock, when linked into kmmio_page_table. | ||
42 | */ | 43 | */ |
43 | int count; | 44 | int count; |
44 | }; | 45 | }; |
@@ -317,7 +318,11 @@ static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs) | |||
317 | if (ctx->probe && ctx->probe->post_handler) | 318 | if (ctx->probe && ctx->probe->post_handler) |
318 | ctx->probe->post_handler(ctx->probe, condition, regs); | 319 | ctx->probe->post_handler(ctx->probe, condition, regs); |
319 | 320 | ||
320 | arm_kmmio_fault_page(ctx->fpage); | 321 | /* Prevent racing against release_kmmio_fault_page(). */ |
322 | spin_lock(&kmmio_lock); | ||
323 | if (ctx->fpage->count) | ||
324 | arm_kmmio_fault_page(ctx->fpage); | ||
325 | spin_unlock(&kmmio_lock); | ||
321 | 326 | ||
322 | regs->flags &= ~X86_EFLAGS_TF; | 327 | regs->flags &= ~X86_EFLAGS_TF; |
323 | regs->flags |= ctx->saved_flags; | 328 | regs->flags |= ctx->saved_flags; |