Return -EEXIST when a notifier callback has already been registered on a notifier chain. This should avoid any homegrown registration tracking at the callsite like https://lore.kernel.org/amd-gfx/20210512013058.6827-1-mukul.joshi@amd.com for example. This version is an alternative of https://lore.kernel.org/r/20211108101157.15189-1-bp@alien8.de which needed to touch every caller not checking the registration routine's return value.
Unified · Split
| @@ -20,12 +20,13 @@ BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); · 19 unmodified lines | |||
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | static int notifier_chain_register(struct notifier_block **nl, | 22 | static int notifier_chain_register(struct notifier_block **nl, |
| 23 | struct notifier_block *n) | 23 | struct notifier_block *n) |
| 24 | { | 24 | { |
| 25 | while ((*nl) != NULL) { | 25 | while ((*nl) != NULL) { |
| 26 | if (unlikely((*nl) == n)) { | 26 | if (unlikely((*nl) == n)) { |
| 27 | WARN(1, "double register detected"); | 27 | WARN(1, "notifier callback %ps already registered", |
| 28 | return 0; | 28 | n->notifier_call); |
| 29 | return -EEXIST; | ||
| 29 | } | 30 | } |
| 30 | if (n->priority > (*nl)->priority) | 31 | if (n->priority > (*nl)->priority) |
| 31 | break; | 32 | break; |
| @@ -134,7 +135,7 @@ static int notifier_call_chain_robust(struct notifier_block **nl, · 102 unmodified lines | |||
| 134 | * | 135 | * |
| 135 | * Adds a notifier to an atomic notifier chain. | 136 | * Adds a notifier to an atomic notifier chain. |
| 136 | * | 137 | * |
| 137 | * Currently always returns zero. | 138 | * Returns 0 on success, %-EEXIST on error. |
| 138 | */ | 139 | */ |
| 139 | int atomic_notifier_chain_register(struct atomic_notifier_head *nh, | 140 | int atomic_notifier_chain_register(struct atomic_notifier_head *nh, |
| 140 | struct notifier_block *n) | 141 | struct notifier_block *n) |
| @@ -216,7 +217,7 @@ NOKPROBE_SYMBOL(atomic_notifier_call_chain); · 75 unmodified lines | |||
| 216 | * Adds a notifier to a blocking notifier chain. | 217 | * Adds a notifier to a blocking notifier chain. |
| 217 | * Must be called in process context. | 218 | * Must be called in process context. |
| 218 | * | 219 | * |
| 219 | * Currently always returns zero. | 220 | * Returns 0 on success, %-EEXIST on error. |
| 220 | */ | 221 | */ |
| 221 | int blocking_notifier_chain_register(struct blocking_notifier_head *nh, | 222 | int blocking_notifier_chain_register(struct blocking_notifier_head *nh, |
| 222 | struct notifier_block *n) | 223 | struct notifier_block *n) |
| @@ -335,7 +336,7 @@ EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); · 112 unmodified lines | |||
| 335 | * Adds a notifier to a raw notifier chain. | 336 | * Adds a notifier to a raw notifier chain. |
| 336 | * All locking must be provided by the caller. | 337 | * All locking must be provided by the caller. |
| 337 | * | 338 | * |
| 338 | * Currently always returns zero. | 339 | * Returns 0 on success, %-EEXIST on error. |
| 339 | */ | 340 | */ |
| 340 | int raw_notifier_chain_register(struct raw_notifier_head *nh, | 341 | int raw_notifier_chain_register(struct raw_notifier_head *nh, |
| 341 | struct notifier_block *n) | 342 | struct notifier_block *n) |
| @@ -406,7 +407,7 @@ EXPORT_SYMBOL_GPL(raw_notifier_call_chain); · 64 unmodified lines | |||
| 406 | * Adds a notifier to an SRCU notifier chain. | 407 | * Adds a notifier to an SRCU notifier chain. |
| 407 | * Must be called in process context. | 408 | * Must be called in process context. |
| 408 | * | 409 | * |
| 409 | * Currently always returns zero. | 410 | * Returns 0 on success, %-EEXIST on error. |
| 410 | */ | 411 | */ |
| 411 | int srcu_notifier_chain_register(struct srcu_notifier_head *nh, | 412 | int srcu_notifier_chain_register(struct srcu_notifier_head *nh, |
| 412 | struct notifier_block *n) | 413 | struct notifier_block *n) |