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().
Now that we take the reference to the module before calling
luster_fill_super(), we don't need to take one inside
lustre_fill_super().
Linux-commit:
d487fe31f49e78f3cdd826923bf0c340a839ffd8
Signed-off-by: Mr NeilBrown <neilb@suse.de>
Change-Id: I9474622f2a253d9882eae3f0578c50782dd11ad4
Reviewed-on: https://review.whamcloud.com/37020
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: James Simmons <jsimmons@infradead.org>
Reviewed-by: Jian Yu <yujian@whamcloud.com>
Reviewed-by: Petros Koutoupis <pkoutoupis@cray.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
int server_name2fsname(const char *svname, char *fsname, const char **endptr);
void obdname2fsname(const char *tgt, char *fsname, size_t fslen);
int server_name2fsname(const char *svname, char *fsname, const char **endptr);
void obdname2fsname(const char *tgt, char *fsname, size_t fslen);
-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);
int lustre_common_put_super(struct super_block *sb);
int mgc_fsname2resid(char *fsname, struct ldlm_res_id *res_id, int type);
CDEBUG(D_VFSTRACE, "VFS Op: cfg_instance %s-%016lx (sb %p)\n",
profilenm, cfg_instance, sb);
CDEBUG(D_VFSTRACE, "VFS Op: cfg_instance %s-%016lx (sb %p)\n",
profilenm, cfg_instance, sb);
- try_module_get(THIS_MODULE);
-
OBD_ALLOC_PTR(cfg);
if (cfg == NULL)
GOTO(out_free_cfg, err = -ENOMEM);
OBD_ALLOC_PTR(cfg);
if (cfg == NULL)
GOTO(out_free_cfg, err = -ENOMEM);
if (rc != 0)
GOTO(out_inode_fini_env, rc);
if (rc != 0)
GOTO(out_inode_fini_env, rc);
- 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);
static void __exit lustre_exit(void)
{
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);
llite_tunables_unregister();
llite_tunables_unregister();
#include <lustre_disk.h>
#include <uapi/linux/lustre/lustre_param.h>
#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);
static int (*client_fill_super)(struct super_block *sb);
static void (*kill_super_cb)(struct super_block *sb);
}
if (lmd_is_client(lmd)) {
}
if (lmd_is_client(lmd)) {
+ bool have_client = false;
+
CDEBUG(D_MOUNT, "Mounting client %s\n", lmd->lmd_profile);
CDEBUG(D_MOUNT, "Mounting client %s\n", lmd->lmd_profile);
- if (client_fill_super == NULL)
+ if (!client_fill_super)
request_module("lustre");
request_module("lustre");
- if (client_fill_super == NULL) {
+ 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);
LCONSOLE_ERROR_MSG(0x165,
"Nothing registered for client mount! Is the 'lustre' module loaded?\n");
lustre_put_lsi(sb);
/* Connect and start */
/* (should always be ll_fill_super) */
rc = (*client_fill_super)(sb);
/* 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,
+ * which takes care of the module reference.
+ */
}
} else {
#ifdef HAVE_SERVER_SUPPORT
}
} else {
#ifdef HAVE_SERVER_SUPPORT
* We can't call ll_fill_super by name because it lives in a module that
* must be loaded after this one.
*/
* 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;
+ 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 ******************/
#ifdef HAVE_FSTYPE_MOUNT
/***************** FS registration ******************/
#ifdef HAVE_FSTYPE_MOUNT