x86/nmi: Make register_nmi_handler() more robust
[platform/kernel/linux-starfive.git] / arch / x86 / kernel / nmi.c
index e73f7df..cec0bfa 100644 (file)
@@ -157,7 +157,7 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action)
        struct nmi_desc *desc = nmi_to_desc(type);
        unsigned long flags;
 
-       if (!action->handler)
+       if (WARN_ON_ONCE(!action->handler || !list_empty(&action->list)))
                return -EINVAL;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
@@ -177,7 +177,7 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action)
                list_add_rcu(&action->list, &desc->head);
        else
                list_add_tail_rcu(&action->list, &desc->head);
-       
+
        raw_spin_unlock_irqrestore(&desc->lock, flags);
        return 0;
 }
@@ -186,7 +186,7 @@ EXPORT_SYMBOL(__register_nmi_handler);
 void unregister_nmi_handler(unsigned int type, const char *name)
 {
        struct nmi_desc *desc = nmi_to_desc(type);
-       struct nmiaction *n;
+       struct nmiaction *n, *found = NULL;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
@@ -200,12 +200,16 @@ void unregister_nmi_handler(unsigned int type, const char *name)
                        WARN(in_nmi(),
                                "Trying to free NMI (%s) from NMI context!\n", n->name);
                        list_del_rcu(&n->list);
+                       found = n;
                        break;
                }
        }
 
        raw_spin_unlock_irqrestore(&desc->lock, flags);
-       synchronize_rcu();
+       if (found) {
+               synchronize_rcu();
+               INIT_LIST_HEAD(&found->list);
+       }
 }
 EXPORT_SYMBOL_GPL(unregister_nmi_handler);