From: Alan Stern Some atomic notifier chains require registrations to take place in atomic context. An example is the die_notifier, which on some architectures may be accessed very early during the boot-up procedure, before task-switching is legal. To accomodate these chains, this patch (as655) replaces the mutex in the atomic_notifier_head structure with a spinlock. Signed-off-by: Alan Stern Signed-off-by: Andrew Morton --- include/linux/notifier.h | 12 ++++++------ kernel/sys.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff -puN include/linux/notifier.h~notifier-chain-update-api-changes-register-atomic_notifiers-in-atomic-context include/linux/notifier.h --- devel/include/linux/notifier.h~notifier-chain-update-api-changes-register-atomic_notifiers-in-atomic-context 2006-02-21 13:15:44.000000000 -0800 +++ devel-akpm/include/linux/notifier.h 2006-02-21 13:15:44.000000000 -0800 @@ -24,9 +24,9 @@ * registration, or unregistration. All locking and protection * must be provided by the caller. * - * atomic_notifier_chain_register() and blocking_notifier_chain_register() - * may be called only from process context, and likewise for the - * corresponding _unregister() routines. + * atomic_notifier_chain_register() may be called from an atomic context, + * but blocking_notifier_chain_register() must be called from a process + * context. Ditto for the corresponding _unregister() routines. * * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister() * _must not_ be called from within the call chain. @@ -39,7 +39,7 @@ struct notifier_block { }; struct atomic_notifier_head { - struct mutex mutex; + spinlock_t lock; struct notifier_block *head; }; @@ -53,7 +53,7 @@ struct raw_notifier_head { }; #define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \ - mutex_init(&(name)->mutex); \ + spin_lock_init(&(name)->lock); \ (name)->head = NULL; \ } while (0) #define BLOCKING_INIT_NOTIFIER_HEAD(name) do { \ @@ -66,7 +66,7 @@ struct raw_notifier_head { #define ATOMIC_NOTIFIER_HEAD(name) \ struct atomic_notifier_head name = { \ - .mutex = __MUTEX_INITIALIZER((name).mutex), \ + .lock = SPIN_LOCK_UNLOCKED, \ .head = NULL } #define BLOCKING_NOTIFIER_HEAD(name) \ struct blocking_notifier_head name = { \ diff -puN kernel/sys.c~notifier-chain-update-api-changes-register-atomic_notifiers-in-atomic-context kernel/sys.c --- devel/kernel/sys.c~notifier-chain-update-api-changes-register-atomic_notifiers-in-atomic-context 2006-02-21 13:15:44.000000000 -0800 +++ devel-akpm/kernel/sys.c 2006-02-21 13:15:51.000000000 -0800 @@ -155,7 +155,6 @@ static int __kprobes notifier_call_chain * @n: New entry in notifier chain * * Adds a notifier to an atomic notifier chain. - * Must be called in process context. * * Currently always returns zero. */ @@ -163,11 +162,12 @@ static int __kprobes notifier_call_chain int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *n) { + unsigned long flags; int ret; - mutex_lock(&nh->mutex); + spin_lock_irqsave(&nh->lock, flags); ret = notifier_chain_register(&nh->head, n); - mutex_unlock(&nh->mutex); + spin_unlock_irqrestore(&nh->lock, flags); return ret; } @@ -179,18 +179,18 @@ EXPORT_SYMBOL(atomic_notifier_chain_regi * @n: Entry to remove from notifier chain * * Removes a notifier from an atomic notifier chain. - * Must be called from process context. * * Returns zero on success or %-ENOENT on failure. */ int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, struct notifier_block *n) { + unsigned long flags; int ret; - mutex_lock(&nh->mutex); + spin_lock_irqsave(&nh->lock, flags); ret = notifier_chain_unregister(&nh->head, n); - mutex_unlock(&nh->mutex); + spin_unlock_irqrestore(&nh->lock, flags); synchronize_rcu(); return ret; } _