diff options
author | Brian Behlendorf <[email protected]> | 2010-04-22 12:48:40 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2010-04-22 12:53:58 -0700 |
commit | 82a358d9c0750a84232adf5c092aeec339c9dd3a (patch) | |
tree | e2441f69955f7fd0ea2b52d25caaf5b07e271fc6 /module | |
parent | ef6c1368848f364ac08ccba60bb88010548d9930 (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.c | 6 | ||||
-rw-r--r-- | module/spl/spl-vnode.c | 19 |
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); |