aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2010-04-22 12:48:40 -0700
committerBrian Behlendorf <[email protected]>2010-04-22 12:53:58 -0700
commit82a358d9c0750a84232adf5c092aeec339c9dd3a (patch)
treee2441f69955f7fd0ea2b52d25caaf5b07e271fc6 /module
parentef6c1368848f364ac08ccba60bb88010548d9930 (diff)
Update vn_set_pwd() to allow user|kernal address for filename
During module init spl_setup()->The vn_set_pwd("/") was failing with -EFAULT because user_path_dir() and __user_walk() both expect 'filename' to be a user space address and it's not in this case. To handle this the data segment size is increased to to ensure strncpy_from_user() does not fail with -EFAULT. Additionally, I've added a printk() warning to catch this and log it to the console if it ever reoccurs. I thought everything was working properly here because there consequences of this failing are subtle and usually non-critical.
Diffstat (limited to 'module')
-rw-r--r--module/spl/spl-generic.c6
-rw-r--r--module/spl/spl-vnode.c19
2 files changed, 20 insertions, 5 deletions
diff --git a/module/spl/spl-generic.c b/module/spl/spl-generic.c
index 290c5275d..aaf1a4c10 100644
--- a/module/spl/spl-generic.c
+++ b/module/spl/spl-generic.c
@@ -444,12 +444,16 @@ spl_fini(void)
void
spl_setup(void)
{
+ int rc;
+
/*
* At module load time the pwd is set to '/' on a Solaris system.
* On a Linux system will be set to whatever directory the caller
* was in when executing insmod/modprobe.
*/
- vn_set_pwd("/");
+ rc = vn_set_pwd("/");
+ if (rc)
+ printk("SPL: Warning unable to set pwd to '/': %d\n", rc);
}
EXPORT_SYMBOL(spl_setup);
diff --git a/module/spl/spl-vnode.c b/module/spl/spl-vnode.c
index 12e09b781..77652a5a2 100644
--- a/module/spl/spl-vnode.c
+++ b/module/spl/spl-vnode.c
@@ -647,9 +647,22 @@ vn_set_pwd(const char *filename)
{
#ifdef HAVE_2ARGS_SET_FS_PWD
struct path path;
+#else
+ struct nameidata nd;
+#endif /* HAVE_2ARGS_SET_FS_PWD */
+ mm_segment_t saved_fs;
int rc;
ENTRY;
+ /*
+ * user_path_dir() and __user_walk() both expect 'filename' to be
+ * a user space address so we must briefly increase the data segment
+ * size to ensure strncpy_from_user() does not fail with -EFAULT.
+ */
+ saved_fs = get_fs();
+ set_fs(get_ds());
+
+#ifdef HAVE_2ARGS_SET_FS_PWD
rc = user_path_dir(filename, &path);
if (rc)
GOTO(out, rc);
@@ -663,10 +676,6 @@ vn_set_pwd(const char *filename)
dput_and_out:
path_put(&path);
#else
- struct nameidata nd;
- int rc;
- ENTRY;
-
rc = __user_walk(filename,
LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
if (rc)
@@ -682,6 +691,8 @@ dput_and_out:
vn_path_release(&nd);
#endif /* HAVE_2ARGS_SET_FS_PWD */
out:
+ set_fs(saved_fs);
+
RETURN(-rc);
} /* vn_set_pwd() */
EXPORT_SYMBOL(vn_set_pwd);