Skip to content

Commit 4994e38

Browse files
committed
x86/mm/kmmio: Switch to arch_spin_lock()
The mmiotrace tracer is "special". The purpose is to help reverse engineer binary drivers by removing the memory allocated by the driver and when the driver goes to access it, a fault occurs, the mmiotracer will record what the driver was doing and then do the work on its behalf by single stepping through the process. But to achieve this ability, it must do some special things. One is it needs to grab a lock while in the breakpoint handler. This is considered an NMI state, and then lockdep warns that the lock is being held in both an NMI state (really a breakpoint handler) and also in normal context. As the breakpoint/NMI state only happens when the driver is accessing memory, there's no concern of a race condition against the setup and tear-down of mmiotracer. To make lockdep and mmiotrace work together, convert the locks used in the breakpoint handler into arch_spin_lock(). Link: https://lkml.kernel.org/r/[email protected] Link: https://lore.kernel.org/lkml/[email protected]/ Cc: Masami Hiramatsu <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Karol Herbst <[email protected]> Cc: Pekka Paalanen <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Borislav Petkov <[email protected]> Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent e25e43a commit 4994e38

File tree

1 file changed

+22
-9
lines changed

1 file changed

+22
-9
lines changed

arch/x86/mm/kmmio.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,13 @@ struct kmmio_context {
6262
int active;
6363
};
6464

65-
static DEFINE_SPINLOCK(kmmio_lock);
65+
/*
66+
* The kmmio_lock is taken in int3 context, which is treated as NMI context.
67+
* This causes lockdep to complain about it bein in both NMI and normal
68+
* context. Hide it from lockdep, as it should not have any other locks
69+
* taken under it, and this is only enabled for debugging mmio anyway.
70+
*/
71+
static arch_spinlock_t kmmio_lock = __ARCH_SPIN_LOCK_UNLOCKED;
6672

6773
/* Protected by kmmio_lock */
6874
unsigned int kmmio_count;
@@ -346,10 +352,10 @@ static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
346352
ctx->probe->post_handler(ctx->probe, condition, regs);
347353

348354
/* Prevent racing against release_kmmio_fault_page(). */
349-
spin_lock(&kmmio_lock);
355+
arch_spin_lock(&kmmio_lock);
350356
if (ctx->fpage->count)
351357
arm_kmmio_fault_page(ctx->fpage);
352-
spin_unlock(&kmmio_lock);
358+
arch_spin_unlock(&kmmio_lock);
353359

354360
regs->flags &= ~X86_EFLAGS_TF;
355361
regs->flags |= ctx->saved_flags;
@@ -440,7 +446,8 @@ int register_kmmio_probe(struct kmmio_probe *p)
440446
unsigned int l;
441447
pte_t *pte;
442448

443-
spin_lock_irqsave(&kmmio_lock, flags);
449+
local_irq_save(flags);
450+
arch_spin_lock(&kmmio_lock);
444451
if (get_kmmio_probe(addr)) {
445452
ret = -EEXIST;
446453
goto out;
@@ -460,7 +467,9 @@ int register_kmmio_probe(struct kmmio_probe *p)
460467
size += page_level_size(l);
461468
}
462469
out:
463-
spin_unlock_irqrestore(&kmmio_lock, flags);
470+
arch_spin_unlock(&kmmio_lock);
471+
local_irq_restore(flags);
472+
464473
/*
465474
* XXX: What should I do here?
466475
* Here was a call to global_flush_tlb(), but it does not exist
@@ -494,7 +503,8 @@ static void remove_kmmio_fault_pages(struct rcu_head *head)
494503
struct kmmio_fault_page **prevp = &dr->release_list;
495504
unsigned long flags;
496505

497-
spin_lock_irqsave(&kmmio_lock, flags);
506+
local_irq_save(flags);
507+
arch_spin_lock(&kmmio_lock);
498508
while (f) {
499509
if (!f->count) {
500510
list_del_rcu(&f->list);
@@ -506,7 +516,8 @@ static void remove_kmmio_fault_pages(struct rcu_head *head)
506516
}
507517
f = *prevp;
508518
}
509-
spin_unlock_irqrestore(&kmmio_lock, flags);
519+
arch_spin_unlock(&kmmio_lock);
520+
local_irq_restore(flags);
510521

511522
/* This is the real RCU destroy call. */
512523
call_rcu(&dr->rcu, rcu_free_kmmio_fault_pages);
@@ -540,14 +551,16 @@ void unregister_kmmio_probe(struct kmmio_probe *p)
540551
if (!pte)
541552
return;
542553

543-
spin_lock_irqsave(&kmmio_lock, flags);
554+
local_irq_save(flags);
555+
arch_spin_lock(&kmmio_lock);
544556
while (size < size_lim) {
545557
release_kmmio_fault_page(addr + size, &release_list);
546558
size += page_level_size(l);
547559
}
548560
list_del_rcu(&p->list);
549561
kmmio_count--;
550-
spin_unlock_irqrestore(&kmmio_lock, flags);
562+
arch_spin_unlock(&kmmio_lock);
563+
local_irq_restore(flags);
551564

552565
if (!release_list)
553566
return;

0 commit comments

Comments
 (0)