[ARM] traps: don't call undef hook functions with spinlock held
authorRussell King <rmk@dyn-67.arm.linux.org.uk>
Mon, 11 Aug 2008 11:27:16 +0000 (12:27 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 12 Aug 2008 18:54:07 +0000 (19:54 +0100)
Calling the undefined instruction handler functions with a
spinlock held is a recipe for must_sleep() warnings.  Avoid it.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/kernel/traps.c

index 7277aef8309836fb74b6e2368beabf050757af9d..872f1f8fbb57841c08a5f4755599c8e761081d64 100644 (file)
@@ -288,14 +288,28 @@ void unregister_undef_hook(struct undef_hook *hook)
        spin_unlock_irqrestore(&undef_lock, flags);
 }
 
+static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
+{
+       struct undef_hook *hook;
+       unsigned long flags;
+       int (*fn)(struct pt_regs *regs, unsigned int instr) = NULL;
+
+       spin_lock_irqsave(&undef_lock, flags);
+       list_for_each_entry(hook, &undef_hook, node)
+               if ((instr & hook->instr_mask) == hook->instr_val &&
+                   (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val)
+                       fn = hook->fn;
+       spin_unlock_irqrestore(&undef_lock, flags);
+
+       return fn ? fn(regs, instr) : 1;
+}
+
 asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 {
        unsigned int correction = thumb_mode(regs) ? 2 : 4;
        unsigned int instr;
-       struct undef_hook *hook;
        siginfo_t info;
        void __user *pc;
-       unsigned long flags;
 
        /*
         * According to the ARM ARM, PC is 2 or 4 bytes ahead,
@@ -325,17 +339,8 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
        }
 #endif
 
-       spin_lock_irqsave(&undef_lock, flags);
-       list_for_each_entry(hook, &undef_hook, node) {
-               if ((instr & hook->instr_mask) == hook->instr_val &&
-                   (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) {
-                       if (hook->fn(regs, instr) == 0) {
-                               spin_unlock_irqrestore(&undef_lock, flags);
-                               return;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&undef_lock, flags);
+       if (call_undef_hook(regs, instr) == 0)
+               return;
 
 #ifdef CONFIG_DEBUG_USER
        if (user_debug & UDBG_UNDEFINED) {