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:
NeilBrown 2017-12-18 12:13:20 +11:00 коммит произвёл Greg Kroah-Hartman
Родитель 7dc2155195
Коммит d487fe31f4
3 изменённых файлов: 24 добавлений и 17 удалений

Просмотреть файл

@ -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,