| .. | .. |
|---|
| 3 | 3 | #include <linux/spinlock.h> |
|---|
| 4 | 4 | #include <linux/once.h> |
|---|
| 5 | 5 | #include <linux/random.h> |
|---|
| 6 | | -#include <linux/module.h> |
|---|
| 7 | 6 | |
|---|
| 8 | 7 | struct once_work { |
|---|
| 9 | 8 | struct work_struct work; |
|---|
| 10 | 9 | struct static_key_true *key; |
|---|
| 11 | | - struct module *module; |
|---|
| 12 | 10 | }; |
|---|
| 13 | 11 | |
|---|
| 14 | 12 | static void once_deferred(struct work_struct *w) |
|---|
| .. | .. |
|---|
| 18 | 16 | work = container_of(w, struct once_work, work); |
|---|
| 19 | 17 | BUG_ON(!static_key_enabled(work->key)); |
|---|
| 20 | 18 | static_branch_disable(work->key); |
|---|
| 21 | | - module_put(work->module); |
|---|
| 22 | 19 | kfree(work); |
|---|
| 23 | 20 | } |
|---|
| 24 | 21 | |
|---|
| 25 | | -static void once_disable_jump(struct static_key_true *key, struct module *mod) |
|---|
| 22 | +static void once_disable_jump(struct static_key_true *key) |
|---|
| 26 | 23 | { |
|---|
| 27 | 24 | struct once_work *w; |
|---|
| 28 | 25 | |
|---|
| .. | .. |
|---|
| 32 | 29 | |
|---|
| 33 | 30 | INIT_WORK(&w->work, once_deferred); |
|---|
| 34 | 31 | w->key = key; |
|---|
| 35 | | - w->module = mod; |
|---|
| 36 | | - __module_get(mod); |
|---|
| 37 | 32 | schedule_work(&w->work); |
|---|
| 38 | 33 | } |
|---|
| 39 | 34 | |
|---|
| .. | .. |
|---|
| 58 | 53 | EXPORT_SYMBOL(__do_once_start); |
|---|
| 59 | 54 | |
|---|
| 60 | 55 | void __do_once_done(bool *done, struct static_key_true *once_key, |
|---|
| 61 | | - unsigned long *flags, struct module *mod) |
|---|
| 56 | + unsigned long *flags) |
|---|
| 62 | 57 | __releases(once_lock) |
|---|
| 63 | 58 | { |
|---|
| 64 | 59 | *done = true; |
|---|
| 65 | 60 | spin_unlock_irqrestore(&once_lock, *flags); |
|---|
| 66 | | - once_disable_jump(once_key, mod); |
|---|
| 61 | + once_disable_jump(once_key); |
|---|
| 67 | 62 | } |
|---|
| 68 | 63 | EXPORT_SYMBOL(__do_once_done); |
|---|
| 64 | + |
|---|
| 65 | +static DEFINE_MUTEX(once_mutex); |
|---|
| 66 | + |
|---|
| 67 | +bool __do_once_slow_start(bool *done) |
|---|
| 68 | + __acquires(once_mutex) |
|---|
| 69 | +{ |
|---|
| 70 | + mutex_lock(&once_mutex); |
|---|
| 71 | + if (*done) { |
|---|
| 72 | + mutex_unlock(&once_mutex); |
|---|
| 73 | + /* Keep sparse happy by restoring an even lock count on |
|---|
| 74 | + * this mutex. In case we return here, we don't call into |
|---|
| 75 | + * __do_once_done but return early in the DO_ONCE_SLOW() macro. |
|---|
| 76 | + */ |
|---|
| 77 | + __acquire(once_mutex); |
|---|
| 78 | + return false; |
|---|
| 79 | + } |
|---|
| 80 | + |
|---|
| 81 | + return true; |
|---|
| 82 | +} |
|---|
| 83 | +EXPORT_SYMBOL(__do_once_slow_start); |
|---|
| 84 | + |
|---|
| 85 | +void __do_once_slow_done(bool *done, struct static_key_true *once_key, |
|---|
| 86 | + struct module *mod) |
|---|
| 87 | + __releases(once_mutex) |
|---|
| 88 | +{ |
|---|
| 89 | + *done = true; |
|---|
| 90 | + mutex_unlock(&once_mutex); |
|---|
| 91 | + once_disable_jump(once_key); |
|---|
| 92 | +} |
|---|
| 93 | +EXPORT_SYMBOL(__do_once_slow_done); |
|---|