staging: lustre: obd_mount: fix possible race with module unload.
lustre_fill_super() calls client_fill_super() without holding a reference to the module containing client_fill_super. If that module is unloaded at a bad time, this can crash. To be able to get a reference to the module using try_get_module(), we need a pointer to the module. So replace lustre_register_client_fill_super() and lustre_register_kill_super_cb() with a single lustre_register_super_ops() which also passed a module pointer. Then use a spinlock to ensure the module pointer isn't removed while try_module_get() is running, and use try_module_get() to ensure we have a reference before calling client_fill_super(). Signed-off-by: NeilBrown <neilb@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
7dc2155195
Коммит
d487fe31f4
|
@ -141,8 +141,9 @@ struct lustre_sb_info {
|
|||
/* obd_mount.c */
|
||||
|
||||
int lustre_start_mgc(struct super_block *sb);
|
||||
void lustre_register_client_fill_super(int (*cfs)(struct super_block *sb));
|
||||
void lustre_register_kill_super_cb(void (*cfs)(struct super_block *sb));
|
||||
void lustre_register_super_ops(struct module *mod,
|
||||
int (*cfs)(struct super_block *sb),
|
||||
void (*ksc)(struct super_block *sb));
|
||||
int lustre_common_put_super(struct super_block *sb);
|
||||
|
||||
int mgc_fsname2resid(char *fsname, struct ldlm_res_id *res_id, int type);
|
||||
|
|
|
@ -159,8 +159,7 @@ static int __init lustre_init(void)
|
|||
if (rc != 0)
|
||||
goto out_inode_fini_env;
|
||||
|
||||
lustre_register_client_fill_super(ll_fill_super);
|
||||
lustre_register_kill_super_cb(ll_kill_super);
|
||||
lustre_register_super_ops(THIS_MODULE, ll_fill_super, ll_kill_super);
|
||||
lustre_register_client_process_config(ll_process_config);
|
||||
|
||||
return 0;
|
||||
|
@ -181,8 +180,7 @@ out_cache:
|
|||
|
||||
static void __exit lustre_exit(void)
|
||||
{
|
||||
lustre_register_client_fill_super(NULL);
|
||||
lustre_register_kill_super_cb(NULL);
|
||||
lustre_register_super_ops(NULL, NULL, NULL);
|
||||
lustre_register_client_process_config(NULL);
|
||||
|
||||
debugfs_remove(llite_root);
|
||||
|
|
|
@ -49,8 +49,9 @@
|
|||
#include <lustre_disk.h>
|
||||
#include <uapi/linux/lustre/lustre_param.h>
|
||||
|
||||
static DEFINE_SPINLOCK(client_lock);
|
||||
static struct module *client_mod;
|
||||
static int (*client_fill_super)(struct super_block *sb);
|
||||
|
||||
static void (*kill_super_cb)(struct super_block *sb);
|
||||
|
||||
/**************** config llog ********************/
|
||||
|
@ -1143,10 +1144,15 @@ static int lustre_fill_super(struct super_block *sb, void *lmd2_data, int silent
|
|||
}
|
||||
|
||||
if (lmd_is_client(lmd)) {
|
||||
bool have_client = false;
|
||||
CDEBUG(D_MOUNT, "Mounting client %s\n", lmd->lmd_profile);
|
||||
if (!client_fill_super)
|
||||
request_module("lustre");
|
||||
if (!client_fill_super) {
|
||||
spin_lock(&client_lock);
|
||||
if (client_fill_super && try_module_get(client_mod))
|
||||
have_client = true;
|
||||
spin_unlock(&client_lock);
|
||||
if (!have_client) {
|
||||
LCONSOLE_ERROR_MSG(0x165, "Nothing registered for client mount! Is the 'lustre' module loaded?\n");
|
||||
lustre_put_lsi(sb);
|
||||
rc = -ENODEV;
|
||||
|
@ -1159,7 +1165,9 @@ static int lustre_fill_super(struct super_block *sb, void *lmd2_data, int silent
|
|||
/* Connect and start */
|
||||
/* (should always be ll_fill_super) */
|
||||
rc = (*client_fill_super)(sb);
|
||||
/* c_f_s will call lustre_common_put_super on failure */
|
||||
/* c_f_s will call lustre_common_put_super on failure, otherwise
|
||||
* c_f_s will have taken another reference to the module */
|
||||
module_put(client_mod);
|
||||
}
|
||||
} else {
|
||||
CERROR("This is client-side-only module, cannot handle server mount.\n");
|
||||
|
@ -1185,17 +1193,17 @@ out:
|
|||
/* We can't call ll_fill_super by name because it lives in a module that
|
||||
* must be loaded after this one.
|
||||
*/
|
||||
void lustre_register_client_fill_super(int (*cfs)(struct super_block *sb))
|
||||
void lustre_register_super_ops(struct module *mod,
|
||||
int (*cfs)(struct super_block *sb),
|
||||
void (*ksc)(struct super_block *sb))
|
||||
{
|
||||
spin_lock(&client_lock);
|
||||
client_mod = mod;
|
||||
client_fill_super = cfs;
|
||||
kill_super_cb = ksc;
|
||||
spin_unlock(&client_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(lustre_register_client_fill_super);
|
||||
|
||||
void lustre_register_kill_super_cb(void (*cfs)(struct super_block *sb))
|
||||
{
|
||||
kill_super_cb = cfs;
|
||||
}
|
||||
EXPORT_SYMBOL(lustre_register_kill_super_cb);
|
||||
EXPORT_SYMBOL(lustre_register_super_ops);
|
||||
|
||||
/***************** FS registration ******************/
|
||||
static struct dentry *lustre_mount(struct file_system_type *fs_type, int flags,
|
||||
|
|
Загрузка…
Ссылка в новой задаче