diff --git a/lib/once.c b/lib/once.c index 8b7d6235217ee3bcea4612e4d9cbd713ff12e74b..959f8db41ccfa10da0bdc57cf78398260a2647d9 100644 --- a/lib/once.c +++ b/lib/once.c @@ -3,10 +3,12 @@ #include #include #include +#include struct once_work { struct work_struct work; struct static_key_true *key; + struct module *module; }; static void once_deferred(struct work_struct *w) @@ -16,11 +18,24 @@ static void once_deferred(struct work_struct *w) work = container_of(w, struct once_work, work); BUG_ON(!static_key_enabled(work->key)); static_branch_disable(work->key); + module_put(work->module); kfree(work); } +static struct module *find_module_by_key(struct static_key_true *key) +{ + struct module *mod; + + preempt_disable(); + mod = __module_address((unsigned long)key); + preempt_enable(); + + return mod; +} + static void once_disable_jump(struct static_key_true *key) { + struct module *mod = find_module_by_key(key); struct once_work *w; w = kmalloc(sizeof(*w), GFP_ATOMIC); @@ -29,6 +44,8 @@ static void once_disable_jump(struct static_key_true *key) INIT_WORK(&w->work, once_deferred); w->key = key; + w->module = mod; + __module_get(mod); schedule_work(&w->work); }