Commit f965803d authored by Rusty Russell's avatar Rusty Russell Committed by Linus Torvalds

[PATCH] module_put_and_exit

Author: Neil Brown

Define module_put_and_exit() and use it for nfsd/lockd

Both nfsd and lockd have threads which expect to hold a reference
to the module while the thread is running.  In order for the thread
to be able to put_module() the module before exiting, the
put_module code must be call from outside the module.

This patch provides module_put_and_exit in non-modular code which a
thread-in-a-module can call.  It also gets nfsd and lockd to use it
as appropriate.

Note that in lockd, we can __get_module in the thread itself as the
creator of the thread is waiting for the thread to startup.

In nfsd and for the 'reclaimer' threaded started by locked, we
__get_module first and put_module if the thread failed to start.
parent dc33faea
...@@ -187,8 +187,9 @@ nlmclnt_recovery(struct nlm_host *host, u32 newstate) ...@@ -187,8 +187,9 @@ nlmclnt_recovery(struct nlm_host *host, u32 newstate)
} else { } else {
nlmclnt_prepare_reclaim(host, newstate); nlmclnt_prepare_reclaim(host, newstate);
nlm_get_host(host); nlm_get_host(host);
MOD_INC_USE_COUNT; __module_get(THIS_MODULE);
kernel_thread(reclaimer, host, CLONE_KERNEL); if (kernel_thread(reclaimer, host, CLONE_KERNEL))
module_put(THIS_MODULE);
} }
} }
...@@ -244,7 +245,5 @@ reclaimer(void *ptr) ...@@ -244,7 +245,5 @@ reclaimer(void *ptr)
nlm_release_host(host); nlm_release_host(host);
lockd_down(); lockd_down();
unlock_kernel(); unlock_kernel();
MOD_DEC_USE_COUNT; module_put_and_exit(0);
return 0;
} }
...@@ -88,7 +88,11 @@ lockd(struct svc_rqst *rqstp) ...@@ -88,7 +88,11 @@ lockd(struct svc_rqst *rqstp)
unsigned long grace_period_expire; unsigned long grace_period_expire;
/* Lock module and set up kernel thread */ /* Lock module and set up kernel thread */
MOD_INC_USE_COUNT; /* lockd_up is waiting for us to startup, so will
* be holding a reference to this module, so it
* is safe to just claim another reference
*/
__module_get(THIS_MODULE);
lock_kernel(); lock_kernel();
/* /*
...@@ -183,7 +187,7 @@ lockd(struct svc_rqst *rqstp) ...@@ -183,7 +187,7 @@ lockd(struct svc_rqst *rqstp)
/* Release module */ /* Release module */
unlock_kernel(); unlock_kernel();
MOD_DEC_USE_COUNT; module_put_and_exit(0);
} }
/* /*
......
...@@ -116,10 +116,13 @@ nfsd_svc(unsigned short port, int nrservs) ...@@ -116,10 +116,13 @@ nfsd_svc(unsigned short port, int nrservs)
nrservs -= (nfsd_serv->sv_nrthreads-1); nrservs -= (nfsd_serv->sv_nrthreads-1);
while (nrservs > 0) { while (nrservs > 0) {
nrservs--; nrservs--;
__module_get(THIS_MODULE);
error = svc_create_thread(nfsd, nfsd_serv); error = svc_create_thread(nfsd, nfsd_serv);
if (error < 0) if (error < 0) {
module_put(THIS_MODULE);
break; break;
} }
}
victim = nfsd_list.next; victim = nfsd_list.next;
while (nrservs < 0 && victim != &nfsd_list) { while (nrservs < 0 && victim != &nfsd_list) {
struct nfsd_list *nl = struct nfsd_list *nl =
...@@ -175,7 +178,6 @@ nfsd(struct svc_rqst *rqstp) ...@@ -175,7 +178,6 @@ nfsd(struct svc_rqst *rqstp)
sigset_t shutdown_mask, allowed_mask; sigset_t shutdown_mask, allowed_mask;
/* Lock module and set up kernel thread */ /* Lock module and set up kernel thread */
MOD_INC_USE_COUNT;
lock_kernel(); lock_kernel();
daemonize("nfsd"); daemonize("nfsd");
current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
...@@ -281,7 +283,7 @@ nfsd(struct svc_rqst *rqstp) ...@@ -281,7 +283,7 @@ nfsd(struct svc_rqst *rqstp)
svc_exit_thread(rqstp); svc_exit_thread(rqstp);
/* Release module */ /* Release module */
MOD_DEC_USE_COUNT; module_put_and_exit(0);
} }
int int
......
...@@ -277,8 +277,12 @@ struct module *module_get_kallsym(unsigned int symnum, ...@@ -277,8 +277,12 @@ struct module *module_get_kallsym(unsigned int symnum,
char *type, char *type,
char namebuf[128]); char namebuf[128]);
int is_exported(const char *name, const struct module *mod); int is_exported(const char *name, const struct module *mod);
#ifdef CONFIG_MODULE_UNLOAD
extern void __module_put_and_exit(struct module *mod, long code)
__attribute__((noreturn));
#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code);
#ifdef CONFIG_MODULE_UNLOAD
unsigned int module_refcount(struct module *mod); unsigned int module_refcount(struct module *mod);
void __symbol_put(const char *symbol); void __symbol_put(const char *symbol);
#define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x) #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x)
...@@ -440,6 +444,8 @@ static inline int unregister_module_notifier(struct notifier_block * nb) ...@@ -440,6 +444,8 @@ static inline int unregister_module_notifier(struct notifier_block * nb)
return 0; return 0;
} }
#define module_put_and_exit(code) do_exit(code)
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
#ifdef MODULE #ifdef MODULE
......
...@@ -98,6 +98,17 @@ int init_module(void) ...@@ -98,6 +98,17 @@ int init_module(void)
} }
EXPORT_SYMBOL(init_module); EXPORT_SYMBOL(init_module);
/* A thread that wants to hold a reference to a module only while it
* is running can call ths to safely exit.
* nfsd and lockd use this.
*/
void __module_put_and_exit(struct module *mod, long code)
{
module_put(mod);
do_exit(code);
}
EXPORT_SYMBOL(__module_put_and_exit);
/* Find a module section: 0 means not found. */ /* Find a module section: 0 means not found. */
static unsigned int find_sec(Elf_Ehdr *hdr, static unsigned int find_sec(Elf_Ehdr *hdr,
Elf_Shdr *sechdrs, Elf_Shdr *sechdrs,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment