Message ID | 1407882507-325-2-git-send-email-mcgrof@do-not-panic.com |
---|---|
State | Changes Requested, archived |
Delegated to: | David Miller |
Headers | show |
Luis R. Rodriguez wrote: > Tetsuo bisected and found that commit 786235ee \"kthread: make > kthread_create() killable\" modified kthread_create() to bail as > soon as SIGKILL is received. I just wrote commit 786235ee. It is not Tetsuo who bisected it. > @@ -128,4 +129,38 @@ bool queue_kthread_work(struct kthread_worker *worker, > void flush_kthread_work(struct kthread_work *work); > void flush_kthread_worker(struct kthread_worker *worker); > > +#ifndef MODULE > + > +#define module_long_probe_init(x) __initcall(x); > +#define module_long_probe_exit(x) __exitcall(x); > + > +#else > +/* To be used by modules which can take over 30 seconds at probe */ > +#define module_long_probe_init(initfn) \\ > + static struct task_struct *__init_thread; \\ > + static int _long_probe_##initfn(void *arg) \\ > + { \\ > + return initfn(); \\ > + } \\ > + static inline __init int __long_probe_##initfn(void) \\ > + { \\ > + __init_thread = kthread_run(_long_probe_##initfn,\\ > + NULL, \\ > + #initfn); \\ > + if (IS_ERR(__init_thread)) \\ > + return PTR_ERR(__init_thread); \\ > + return 0; \\ > + } \\ > + module_init(__long_probe_##initfn); > +/* To be used by modules that require module_long_probe_init() */ > +#define module_long_probe_exit(exitfn) \\ > + static inline void __long_probe_##exitfn(void) \\ > + { \\ > + exitfn(); \\ exitfn() must not be called if initfn() failed or has not completed yet. You need a bool variable for indicating that we are ready to call exitfn(). Also, subsequent userspace operations may fail if we return to userspace before initfn() completes (e.g. device nodes are not created yet). > + if (__init_thread) \\ > + kthread_stop(__init_thread); \\ We can\'t use kthread_stop() here because we have to wait for initfn() to succeed before exitfn() is called. > + } \\ > + module_exit(__long_probe_##exitfn); > +#endif /* MODULE */ > + > #endif /* _LINUX_KTHREAD_H */ -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Aug 13, 2014 at 07:59:06AM +0900, Tetsuo Handa wrote: > Luis R. Rodriguez wrote: > > Tetsuo bisected and found that commit 786235ee \"kthread: make > > kthread_create() killable\" modified kthread_create() to bail as > > soon as SIGKILL is received. > > I just wrote commit 786235ee. It is not Tetsuo who bisected it. > > > @@ -128,4 +129,38 @@ bool queue_kthread_work(struct kthread_worker *worker, > > void flush_kthread_work(struct kthread_work *work); > > void flush_kthread_worker(struct kthread_worker *worker); > > > > +#ifndef MODULE > > + > > +#define module_long_probe_init(x) __initcall(x); > > +#define module_long_probe_exit(x) __exitcall(x); > > + > > +#else > > +/* To be used by modules which can take over 30 seconds at probe */ > > +#define module_long_probe_init(initfn) \\ > > + static struct task_struct *__init_thread; \\ > > + static int _long_probe_##initfn(void *arg) \\ > > + { \\ > > + return initfn(); \\ > > + } \\ > > + static inline __init int __long_probe_##initfn(void) \\ > > + { \\ > > + __init_thread = kthread_run(_long_probe_##initfn,\\ > > + NULL, \\ > > + #initfn); \\ > > + if (IS_ERR(__init_thread)) \\ > > + return PTR_ERR(__init_thread); \\ > > + return 0; \\ > > + } \\ > > + module_init(__long_probe_##initfn); > > +/* To be used by modules that require module_long_probe_init() */ > > +#define module_long_probe_exit(exitfn) \\ > > + static inline void __long_probe_##exitfn(void) \\ > > + { \\ > > + exitfn(); \\ > > exitfn() must not be called if initfn() failed or has not > completed yet. You need a bool variable for indicating that > we are ready to call exitfn(). > > Also, subsequent userspace operations may fail if > we return to userspace before initfn() completes > (e.g. device nodes are not created yet). I doubt that this will be a problem, as device nodes are usually created _after_ module_init() returns. But the cleanup issues are real on error paths. Given that these drivers will need "work" anyway, I don't think it's really a big deal. thanks, greg k-h -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 08/12, Luis R. Rodriguez wrote: > > +/* To be used by modules which can take over 30 seconds at probe */ Probably the comment should explain that this hack should only be used if the driver is buggy and is wating for "real fix". > +#define module_long_probe_init(initfn) \ > + static struct task_struct *__init_thread; \ > + static int _long_probe_##initfn(void *arg) \ > + { \ > + return initfn(); \ > + } \ > + static inline __init int __long_probe_##initfn(void) \ > + { \ > + __init_thread = kthread_run(_long_probe_##initfn,\ > + NULL, \ > + #initfn); \ > + if (IS_ERR(__init_thread)) \ > + return PTR_ERR(__init_thread); \ > + return 0; \ > + } \ > + module_init(__long_probe_##initfn); > +/* To be used by modules that require module_long_probe_init() */ > +#define module_long_probe_exit(exitfn) \ > + static inline void __long_probe_##exitfn(void) \ > + { \ > + exitfn(); \ > + if (__init_thread) \ > + kthread_stop(__init_thread); \ > + } \ exitfn() should be called after kthread_stop(), and only if initfn() returns 0. So it should probably do int err = kthread_stop(__init_thread); if (!err) exitfn(); But there is an additional complication, you can't use __init_thread without get_task_struct(), so __long_probe_##initfn() can't use kthread_run(). It needs kthread_create() + get_task_struct() + wakeup. Oleg. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Aug 13, 2014 at 07:51:01PM +0200, Oleg Nesterov wrote: > On 08/12, Luis R. Rodriguez wrote: > > > > +/* To be used by modules which can take over 30 seconds at probe */ > > Probably the comment should explain that this hack should only be > used if the driver is buggy and is wating for "real fix". > > > +#define module_long_probe_init(initfn) \ > > + static struct task_struct *__init_thread; \ > > + static int _long_probe_##initfn(void *arg) \ > > + { \ > > + return initfn(); \ > > + } \ > > + static inline __init int __long_probe_##initfn(void) \ > > + { \ > > + __init_thread = kthread_run(_long_probe_##initfn,\ > > + NULL, \ > > + #initfn); \ > > + if (IS_ERR(__init_thread)) \ > > + return PTR_ERR(__init_thread); \ > > + return 0; \ > > + } \ > > + module_init(__long_probe_##initfn); > > +/* To be used by modules that require module_long_probe_init() */ > > +#define module_long_probe_exit(exitfn) \ > > + static inline void __long_probe_##exitfn(void) \ > > + { \ > > + exitfn(); \ > > + if (__init_thread) \ > > + kthread_stop(__init_thread); \ > > + } \ > > exitfn() should be called after kthread_stop(), and only if initfn() > returns 0. So it should probably do > > int err = kthread_stop(__init_thread); > if (!err) > exitfn(); Thanks! With the check for __init_thread as well as it can be ERR_PTR(-ENOMEM), ERR_PTR(-EINTR), or NULL (for whatever other reason). > But there is an additional complication, you can't use __init_thread > without get_task_struct(), Can you elaborate why ? kthread_stop() uses get_task_struct(), wake_up_process() and finally put_task_struct(), and we're the only user of this thread. Also kthread_run() ensures wake_up_process() gets called on startup, so not sure where the race would be provided all users here and with the respective helpers on buggy drivers. > so __long_probe_##initfn() can't use > kthread_run(). It needs kthread_create() + get_task_struct() + wakeup. I fail to see why we'd need to add get_task_struct() on module_long_probe_init(), can you clarify? Luis -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 08/15, Luis R. Rodriguez wrote: > > On Wed, Aug 13, 2014 at 07:51:01PM +0200, Oleg Nesterov wrote: > > On 08/12, Luis R. Rodriguez wrote: > > > > > > +/* To be used by modules which can take over 30 seconds at probe */ > > > > Probably the comment should explain that this hack should only be > > used if the driver is buggy and is wating for "real fix". > > > > > +#define module_long_probe_init(initfn) \ > > > + static struct task_struct *__init_thread; \ > > > + static int _long_probe_##initfn(void *arg) \ > > > + { \ > > > + return initfn(); \ > > > + } \ > > > + static inline __init int __long_probe_##initfn(void) \ > > > + { \ > > > + __init_thread = kthread_run(_long_probe_##initfn,\ > > > + NULL, \ > > > + #initfn); \ > > > + if (IS_ERR(__init_thread)) \ > > > + return PTR_ERR(__init_thread); \ > > > + return 0; \ > > > + } \ > > > + module_init(__long_probe_##initfn); > > > +/* To be used by modules that require module_long_probe_init() */ > > > +#define module_long_probe_exit(exitfn) \ > > > + static inline void __long_probe_##exitfn(void) \ > > > + { \ > > > + exitfn(); \ > > > + if (__init_thread) \ > > > + kthread_stop(__init_thread); \ > > > + } \ > > > > exitfn() should be called after kthread_stop(), and only if initfn() > > returns 0. So it should probably do > > > > int err = kthread_stop(__init_thread); > > if (!err) > > exitfn(); > > Thanks! With the check for __init_thread as well as it can be > ERR_PTR(-ENOMEM), ERR_PTR(-EINTR), or NULL (for whatever other > reason). Do you mean __long_probe_##exitfn() should also check ERR_PTR(__init_thread)? I don't think so. If kthread_run() above fails, module_init() should return the error (it does), so module_exit() won't be called. > > But there is an additional complication, you can't use __init_thread > > without get_task_struct(), > > Can you elaborate why ? kthread_stop() uses get_task_struct(), This is too late. This task_struct can be already freed/reused. See below. > wake_up_process() and finally put_task_struct(), and we're the > only user of this thread. Also kthread_run() ensures wake_up_process() > gets called on startup, so not sure where the race would be provided > all users here and with the respective helpers on buggy drivers. > > > so __long_probe_##initfn() can't use > > kthread_run(). It needs kthread_create() + get_task_struct() + wakeup. > > I fail to see why we'd need to add get_task_struct() on > module_long_probe_init(), can you clarify? kthread_stop(kthread_run(callback)) is only safe if callback() can not exit on its own, without checking kthread_should_stop(). And btw that is why kthread_stop() does get_task_struct()). If callback() can exit (if it calls do_exit() or simply returns), then nothing protects this task_struct, it will be freed. Oleg. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Fri, Aug 15, 2014 at 04:39:02PM +0200, Oleg Nesterov wrote: > On 08/15, Luis R. Rodriguez wrote: > > > > On Wed, Aug 13, 2014 at 07:51:01PM +0200, Oleg Nesterov wrote: > > > On 08/12, Luis R. Rodriguez wrote: > > > > > > > > +/* To be used by modules which can take over 30 seconds at probe */ > > > > > > Probably the comment should explain that this hack should only be > > > used if the driver is buggy and is wating for "real fix". > > > > > > > +#define module_long_probe_init(initfn) \ > > > > + static struct task_struct *__init_thread; \ > > > > + static int _long_probe_##initfn(void *arg) \ > > > > + { \ > > > > + return initfn(); \ > > > > + } \ > > > > + static inline __init int __long_probe_##initfn(void) \ > > > > + { \ > > > > + __init_thread = kthread_run(_long_probe_##initfn,\ > > > > + NULL, \ > > > > + #initfn); \ > > > > + if (IS_ERR(__init_thread)) \ > > > > + return PTR_ERR(__init_thread); \ > > > > + return 0; \ > > > > + } \ > > > > + module_init(__long_probe_##initfn); > > > > +/* To be used by modules that require module_long_probe_init() */ > > > > +#define module_long_probe_exit(exitfn) \ > > > > + static inline void __long_probe_##exitfn(void) \ > > > > + { \ > > > > + exitfn(); \ > > > > + if (__init_thread) \ > > > > + kthread_stop(__init_thread); \ > > > > + } \ > > > > > > exitfn() should be called after kthread_stop(), and only if initfn() > > > returns 0. So it should probably do > > > > > > int err = kthread_stop(__init_thread); > > > if (!err) > > > exitfn(); > > > > Thanks! With the check for __init_thread as well as it can be > > ERR_PTR(-ENOMEM), ERR_PTR(-EINTR), or NULL (for whatever other > > reason). > > Do you mean __long_probe_##exitfn() should also check ERR_PTR(__init_thread)? > I don't think so. If kthread_run() above fails, module_init() should return > the error (it does), so module_exit() won't be called. Good point. > > > But there is an additional complication, you can't use __init_thread > > > without get_task_struct(), > > > > Can you elaborate why ? kthread_stop() uses get_task_struct(), > > This is too late. This task_struct can be already freed/reused. See below. > > > wake_up_process() and finally put_task_struct(), and we're the > > only user of this thread. Also kthread_run() ensures wake_up_process() > > gets called on startup, so not sure where the race would be provided > > all users here and with the respective helpers on buggy drivers. > > > > > so __long_probe_##initfn() can't use > > > kthread_run(). It needs kthread_create() + get_task_struct() + wakeup. > > > > I fail to see why we'd need to add get_task_struct() on > > module_long_probe_init(), can you clarify? > > kthread_stop(kthread_run(callback)) is only safe if callback() can not exit > on its own, without checking kthread_should_stop(). And btw that is why > kthread_stop() does get_task_struct()). > > If callback() can exit (if it calls do_exit() or simply returns), then nothing > protects this task_struct, it will be freed. OK thanks, yeah I see the issue now, and I was able to create a null pointer dereference by simply calling schedule() quite a bit, will roll in the required fixes, but come to think of it if there are other uses (I haven't SmPLd grep'd for grammar uses yet) perhaps generic helpers would be good? kthread_run_alloc() kthread_run_free(). Luis -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
At Sat, 16 Aug 2014 04:50:07 +0200, Luis R. Rodriguez wrote: > > On Fri, Aug 15, 2014 at 04:39:02PM +0200, Oleg Nesterov wrote: > > On 08/15, Luis R. Rodriguez wrote: > > > > > > On Wed, Aug 13, 2014 at 07:51:01PM +0200, Oleg Nesterov wrote: > > > > On 08/12, Luis R. Rodriguez wrote: > > > > > > > > > > +/* To be used by modules which can take over 30 seconds at probe */ > > > > > > > > Probably the comment should explain that this hack should only be > > > > used if the driver is buggy and is wating for "real fix". > > > > > > > > > +#define module_long_probe_init(initfn) \ > > > > > + static struct task_struct *__init_thread; \ > > > > > + static int _long_probe_##initfn(void *arg) \ > > > > > + { \ > > > > > + return initfn(); \ > > > > > + } \ > > > > > + static inline __init int __long_probe_##initfn(void) \ > > > > > + { \ > > > > > + __init_thread = kthread_run(_long_probe_##initfn,\ > > > > > + NULL, \ > > > > > + #initfn); \ > > > > > + if (IS_ERR(__init_thread)) \ > > > > > + return PTR_ERR(__init_thread); \ > > > > > + return 0; \ > > > > > + } \ > > > > > + module_init(__long_probe_##initfn); > > > > > +/* To be used by modules that require module_long_probe_init() */ > > > > > +#define module_long_probe_exit(exitfn) \ > > > > > + static inline void __long_probe_##exitfn(void) \ > > > > > + { \ > > > > > + exitfn(); \ > > > > > + if (__init_thread) \ > > > > > + kthread_stop(__init_thread); \ > > > > > + } \ > > > > > > > > exitfn() should be called after kthread_stop(), and only if initfn() > > > > returns 0. So it should probably do > > > > > > > > int err = kthread_stop(__init_thread); > > > > if (!err) > > > > exitfn(); > > > > > > Thanks! With the check for __init_thread as well as it can be > > > ERR_PTR(-ENOMEM), ERR_PTR(-EINTR), or NULL (for whatever other > > > reason). > > > > Do you mean __long_probe_##exitfn() should also check ERR_PTR(__init_thread)? > > I don't think so. If kthread_run() above fails, module_init() should return > > the error (it does), so module_exit() won't be called. > > Good point. > > > > > But there is an additional complication, you can't use __init_thread > > > > without get_task_struct(), > > > > > > Can you elaborate why ? kthread_stop() uses get_task_struct(), > > > > This is too late. This task_struct can be already freed/reused. See below. > > > > > wake_up_process() and finally put_task_struct(), and we're the > > > only user of this thread. Also kthread_run() ensures wake_up_process() > > > gets called on startup, so not sure where the race would be provided > > > all users here and with the respective helpers on buggy drivers. > > > > > > > so __long_probe_##initfn() can't use > > > > kthread_run(). It needs kthread_create() + get_task_struct() + wakeup. > > > > > > I fail to see why we'd need to add get_task_struct() on > > > module_long_probe_init(), can you clarify? > > > > kthread_stop(kthread_run(callback)) is only safe if callback() can not exit > > on its own, without checking kthread_should_stop(). And btw that is why > > kthread_stop() does get_task_struct()). > > > > If callback() can exit (if it calls do_exit() or simply returns), then nothing > > protects this task_struct, it will be freed. > > OK thanks, yeah I see the issue now, and I was able to create a null > pointer dereference by simply calling schedule() quite a bit, will > roll in the required fixes, but come to think of it if there are > other uses (I haven't SmPLd grep'd for grammar uses yet) perhaps > generic helpers would be good? kthread_run_alloc() kthread_run_free(). How about just increasing/decreasing the module count for blocking the exit call? For example: #define module_long_probe_init(initfn) \ static int _long_probe_##initfn(void *arg) \ { \ int ret = initfn(); \ module_put(THIS_MODULE); \ return ret; \ } \ static inline __init int __long_probe_##initfn(void) \ { \ struct task_struct *__init_thread; \ __module_get(THIS_MODULE); \ __init_thread = kthread_run(_long_probe_##initfn,\ NULL, \ #initfn); \ if (IS_ERR(__init_thread)) { \ module_put(THIS_MODULE); \ return PTR_ERR(__init_thread); \ } \ return 0; \ } \ module_init(__long_probe_##initfn); /* To be used by modules that require module_long_probe_init() */ #define module_long_probe_exit(exitfn) \ module_exit(exitfn); Takashi -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 08/17, Takashi Iwai wrote: > > How about just increasing/decreasing the module count for blocking the > exit call? For example: > > #define module_long_probe_init(initfn) \ > static int _long_probe_##initfn(void *arg) \ > { \ > int ret = initfn(); \ > module_put(THIS_MODULE); \ WINDOW, please see below. > return ret; \ > } \ > static inline __init int __long_probe_##initfn(void) \ > { \ > struct task_struct *__init_thread; \ > __module_get(THIS_MODULE); \ > __init_thread = kthread_run(_long_probe_##initfn,\ > NULL, \ > #initfn); \ > if (IS_ERR(__init_thread)) { \ > module_put(THIS_MODULE); \ > return PTR_ERR(__init_thread); \ > } \ > return 0; \ > } \ I leave this to you and Luis, but personally I think this is very nice idea, I like it. Because sys_delete_module() won't hang in D state waiting for initfn(). There is a small problem. This module can be unloaded right after module_put() above. In this case its memory can be unmapped and the exiting thread can crash. This is very unlikely, this thread needs to execute just a few insn and escape from this module's memory. Given that only the buggy modules should use this hack, perhaps we can even ignore this race. But perhaps it makes sense to close this race anyway, and we already have complete_and_exit() which can be used instead of "return ret" above. Just we need the additional "static struct completion" and module_exit() should call wait_for_completion. Oleg. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 08/17, Oleg Nesterov wrote: > > On 08/17, Takashi Iwai wrote: > > > > How about just increasing/decreasing the module count for blocking the > > exit call? For example: > > > > #define module_long_probe_init(initfn) \ > > static int _long_probe_##initfn(void *arg) \ > > { \ > > int ret = initfn(); \ > > module_put(THIS_MODULE); \ > > WINDOW, please see below. > > > return ret; \ > > } \ > > static inline __init int __long_probe_##initfn(void) \ > > { \ > > struct task_struct *__init_thread; \ > > __module_get(THIS_MODULE); \ > > __init_thread = kthread_run(_long_probe_##initfn,\ > > NULL, \ > > #initfn); \ > > if (IS_ERR(__init_thread)) { \ > > module_put(THIS_MODULE); \ > > return PTR_ERR(__init_thread); \ > > } \ > > return 0; \ > > } \ > > I leave this to you and Luis, but personally I think this is very > nice idea, I like it. Because sys_delete_module() won't hang in D > state waiting for initfn(). > > There is a small problem. This module can be unloaded right after > module_put() above. In this case its memory can be unmapped and > the exiting thread can crash. > > This is very unlikely, this thread needs to execute just a few insn > and escape from this module's memory. Given that only the buggy > modules should use this hack, perhaps we can even ignore this race. > > But perhaps it makes sense to close this race anyway, and we already > have complete_and_exit() which can be used instead of "return ret" > above. Just we need the additional "static struct completion" and > module_exit() should call wait_for_completion. Forgot to mention... and __long_probe_##initfn() could be simpler without kthread_run, __init_thread = kthread_create(...); if (IS_ERR(__init_thread)) return PTR_ERR(); module_get(THIS_MODULE); wake_up_process(__init_thread); return 0; but this is subjective, up to you. Oleg. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Damn, sorry for noise ;) I was going to suggest to introduce module_put_and_exit() to simplify this and potentially other users, but it already exists. So this code can use it too without additional complications. On 08/17, Oleg Nesterov wrote: > On 08/17, Oleg Nesterov wrote: > > > > On 08/17, Takashi Iwai wrote: > > > > > > How about just increasing/decreasing the module count for blocking the > > > exit call? For example: > > > > > > #define module_long_probe_init(initfn) \ > > > static int _long_probe_##initfn(void *arg) \ > > > { \ > > > int ret = initfn(); \ > > > module_put(THIS_MODULE); \ > > > > WINDOW, please see below. > > > > > return ret; \ > > > } \ > > > static inline __init int __long_probe_##initfn(void) \ > > > { \ > > > struct task_struct *__init_thread; \ > > > __module_get(THIS_MODULE); \ > > > __init_thread = kthread_run(_long_probe_##initfn,\ > > > NULL, \ > > > #initfn); \ > > > if (IS_ERR(__init_thread)) { \ > > > module_put(THIS_MODULE); \ > > > return PTR_ERR(__init_thread); \ > > > } \ > > > return 0; \ > > > } \ > > > > I leave this to you and Luis, but personally I think this is very > > nice idea, I like it. Because sys_delete_module() won't hang in D > > state waiting for initfn(). > > > > There is a small problem. This module can be unloaded right after > > module_put() above. In this case its memory can be unmapped and > > the exiting thread can crash. > > > > This is very unlikely, this thread needs to execute just a few insn > > and escape from this module's memory. Given that only the buggy > > modules should use this hack, perhaps we can even ignore this race. > > > > But perhaps it makes sense to close this race anyway, and we already > > have complete_and_exit() which can be used instead of "return ret" > > above. Just we need the additional "static struct completion" and > > module_exit() should call wait_for_completion. > > Forgot to mention... and __long_probe_##initfn() could be simpler > without kthread_run, > > __init_thread = kthread_create(...); > if (IS_ERR(__init_thread)) > return PTR_ERR(); > > module_get(THIS_MODULE); > wake_up_process(__init_thread); > return 0; > > but this is subjective, up to you. > > Oleg. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/include/linux/kthread.h b/include/linux/kthread.h index 13d5520..2b5555a 100644 --- a/include/linux/kthread.h +++ b/include/linux/kthread.h @@ -1,6 +1,7 @@ #ifndef _LINUX_KTHREAD_H #define _LINUX_KTHREAD_H /* Simple interface for creating and stopping kernel threads without mess. */ +#include <linux/init.h> #include <linux/err.h> #include <linux/sched.h> @@ -128,4 +129,38 @@ bool queue_kthread_work(struct kthread_worker *worker, void flush_kthread_work(struct kthread_work *work); void flush_kthread_worker(struct kthread_worker *worker); +#ifndef MODULE + +#define module_long_probe_init(x) __initcall(x); +#define module_long_probe_exit(x) __exitcall(x); + +#else +/* To be used by modules which can take over 30 seconds at probe */ +#define module_long_probe_init(initfn) \ + static struct task_struct *__init_thread; \ + static int _long_probe_##initfn(void *arg) \ + { \ + return initfn(); \ + } \ + static inline __init int __long_probe_##initfn(void) \ + { \ + __init_thread = kthread_run(_long_probe_##initfn,\ + NULL, \ + #initfn); \ + if (IS_ERR(__init_thread)) \ + return PTR_ERR(__init_thread); \ + return 0; \ + } \ + module_init(__long_probe_##initfn); +/* To be used by modules that require module_long_probe_init() */ +#define module_long_probe_exit(exitfn) \ + static inline void __long_probe_##exitfn(void) \ + { \ + exitfn(); \ + if (__init_thread) \ + kthread_stop(__init_thread); \ + } \ + module_exit(__long_probe_##exitfn); +#endif /* MODULE */ + #endif /* _LINUX_KTHREAD_H */