[PATCH] Register atomic_notifiers in atomic context

From: Alan Stern
Date: Tue Feb 21 2006 - 10:52:32 EST


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 <stern@xxxxxxxxxxxxxxxxxxx>

---

Andrew:

This ought to fix the problem you were seeing with the new notifier chains
on your emt64 system.

Alan Stern



Index: usb-2.6/kernel/sys.c
===================================================================
--- usb-2.6.orig/kernel/sys.c
+++ usb-2.6/kernel/sys.c
@@ -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;
}
Index: usb-2.6/include/linux/notifier.h
===================================================================
--- usb-2.6.orig/include/linux/notifier.h
+++ usb-2.6/include/linux/notifier.h
@@ -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 = { \

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/