]> git.proxmox.com Git - mirror_spl-debian.git/commitdiff
Set cwd to '/' for the process executing insmod.
authorBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 1 Oct 2009 23:06:15 +0000 (16:06 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 1 Oct 2009 23:06:15 +0000 (16:06 -0700)
Ricardo has pointed out that under Solaris the cwd is set to '/'
during module load, while under Linux it is set to the callers cwd.
To handle this cleanly I've reworked the module *_init()/_exit()
macros so they call a *_setup()/_cleanup() function when any SPL
dependent module is loaded or unloaded.  This gives us a chance to
perform any needed modification of the process, in this case changing
the cwd.  It also handily provides a way to avoid creating wrapper
init()/exit() functions because the Solaris and Linux prototypes
differ slightly.  All dependent modules should now call the spl
helper macros spl_module_{init,exit}() instead of the native linux
versions.

Unfortunately, it appears that under Linux there has been no consistent
API in the kernel to set the cwd in a module.  Because of this I have
had to add more autoconf magic than I'd like.  However, what I have
done is correct and has been tested on RHEL5, SLES11, FC11, and CHAOS
kernels.

In addition, I have change the rootdir type from a 'void *' to the
correct 'vnode_t *' type.  And I've set rootdir to a non-NULL value.

config/spl-build.m4
configure
include/linux/module_compat.h [new file with mode: 0644]
include/sys/sysmacros.h
include/sys/types.h
include/sys/vnode.h
module/spl/spl-generic.c
module/spl/spl-vnode.c
module/splat/splat-ctl.c
spl_config.h.in

index 3293aa2733f00180808b74175faea035cab6a0a1..e6a62610843b2f7235cf1aefcfdc9d67f79ab85c 100644 (file)
@@ -64,6 +64,8 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
        SPL_AC_ZONE_STAT_ITEM_INACTIVE
        SPL_AC_ZONE_STAT_ITEM_ACTIVE
        SPL_AC_GET_ZONE_COUNTS
+       SPL_AC_SET_FS_PWD
+       SPL_AC_2ARGS_SET_FS_PWD
        SPL_AC_2ARGS_VFS_UNLINK
        SPL_AC_4ARGS_VFS_RENAME
        SPL_AC_CRED_STRUCT
@@ -1203,6 +1205,37 @@ AC_DEFUN([SPL_AC_GET_ZONE_COUNTS], [
        ])
 ])
 
+dnl #
+dnl # Symbol available in RHEL kernels not in stock kernels.
+dnl #
+AC_DEFUN([SPL_AC_SET_FS_PWD], [
+       SPL_CHECK_SYMBOL_EXPORT(
+               [set_fs_pwd],
+               [],
+               [AC_DEFINE(HAVE_SET_FS_PWD, 1,
+               [set_fs_pwd() is available])],
+               [])
+])
+
+dnl #
+dnl # 2.6.25 API change,
+dnl # Simplied API by replacing mnt+dentry args with a single path arg.
+dnl #
+AC_DEFUN([SPL_AC_2ARGS_SET_FS_PWD],
+       [AC_MSG_CHECKING([whether set_fs_pwd() wants 2 args])
+       SPL_LINUX_TRY_COMPILE([
+               #include <linux/sched.h>
+       ],[
+               set_fs_pwd(NULL, NULL);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_2ARGS_SET_FS_PWD, 1,
+                         [set_fs_pwd() wants 2 args])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
 dnl #
 dnl # SLES API change, never adopted in mainline,
 dnl # Third 'struct vfsmount *' argument removed.
index 03b23036e80bdf2d77f4285c7f865b3cda23bfcd..8c87368838062ef95aeb8cea944581cc716c7848 100755 (executable)
--- a/configure
+++ b/configure
@@ -21709,6 +21709,111 @@ _ACEOF
 
 
 
+fi
+
+       rm -Rf build
+
+
+
+
+       echo "$as_me:$LINENO: checking whether symbol set_fs_pwd is exported" >&5
+echo $ECHO_N "checking whether symbol set_fs_pwd is exported... $ECHO_C" >&6
+       grep -q -E '[[:space:]]set_fs_pwd[[:space:]]' \
+               $LINUX_OBJ/Module*.symvers 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in ; do
+                       grep -q -E "EXPORT_SYMBOL.*(set_fs_pwd)" \
+                               "$LINUX_OBJ/$file" 2>/dev/null
+                       rc=$?
+                       if test $rc -eq 0; then
+                               export=1
+                               break;
+                       fi
+               done
+               if test $export -eq 0; then
+                       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+               else
+                       echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SET_FS_PWD 1
+_ACEOF
+
+               fi
+       else
+               echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SET_FS_PWD 1
+_ACEOF
+
+       fi
+
+
+       echo "$as_me:$LINENO: checking whether set_fs_pwd() wants 2 args" >&5
+echo $ECHO_N "checking whether set_fs_pwd() wants 2 args... $ECHO_C" >&6
+
+
+cat >conftest.c <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+               #include <linux/sched.h>
+
+int
+main (void)
+{
+
+               set_fs_pwd(NULL, NULL);
+
+  ;
+  return 0;
+}
+
+_ACEOF
+
+
+       rm -Rf build && mkdir -p build
+       echo "obj-m := conftest.o" >build/Makefile
+       if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+               echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_2ARGS_SET_FS_PWD 1
+_ACEOF
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+               echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+
+
 fi
 
        rm -Rf build
@@ -24752,6 +24857,111 @@ _ACEOF
 
 
 
+fi
+
+       rm -Rf build
+
+
+
+
+       echo "$as_me:$LINENO: checking whether symbol set_fs_pwd is exported" >&5
+echo $ECHO_N "checking whether symbol set_fs_pwd is exported... $ECHO_C" >&6
+       grep -q -E '[[:space:]]set_fs_pwd[[:space:]]' \
+               $LINUX_OBJ/Module*.symvers 2>/dev/null
+       rc=$?
+       if test $rc -ne 0; then
+               export=0
+               for file in ; do
+                       grep -q -E "EXPORT_SYMBOL.*(set_fs_pwd)" \
+                               "$LINUX_OBJ/$file" 2>/dev/null
+                       rc=$?
+                       if test $rc -eq 0; then
+                               export=1
+                               break;
+                       fi
+               done
+               if test $export -eq 0; then
+                       echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+               else
+                       echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SET_FS_PWD 1
+_ACEOF
+
+               fi
+       else
+               echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SET_FS_PWD 1
+_ACEOF
+
+       fi
+
+
+       echo "$as_me:$LINENO: checking whether set_fs_pwd() wants 2 args" >&5
+echo $ECHO_N "checking whether set_fs_pwd() wants 2 args... $ECHO_C" >&6
+
+
+cat >conftest.c <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+               #include <linux/sched.h>
+
+int
+main (void)
+{
+
+               set_fs_pwd(NULL, NULL);
+
+  ;
+  return 0;
+}
+
+_ACEOF
+
+
+       rm -Rf build && mkdir -p build
+       echo "obj-m := conftest.o" >build/Makefile
+       if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+               echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_2ARGS_SET_FS_PWD 1
+_ACEOF
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+               echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+
+
 fi
 
        rm -Rf build
diff --git a/include/linux/module_compat.h b/include/linux/module_compat.h
new file mode 100644 (file)
index 0000000..766cb58
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _SPL_MODULE_COMPAT_H
+#define _SPL_MODULE_COMPAT_H
+
+#include <linux/module.h>
+
+#define spl_module_init(init_fn)                                        \
+static int                                                              \
+spl_##init_fn(void)                                                     \
+{                                                                       \
+       int rc;                                                         \
+                                                                       \
+       spl_setup();                                                    \
+       rc = init_fn();                                                 \
+                                                                        \
+       return rc;                                                      \
+}                                                                       \
+                                                                        \
+module_init(spl_##init_fn)
+
+#define spl_module_exit(exit_fn)                                        \
+static void                                                             \
+spl_##exit_fn(void)                                                     \
+{                                                                       \
+       int rc;                                                         \
+                                                                        \
+       rc = exit_fn();                                                 \
+       spl_cleanup();                                                  \
+       if (rc)                                                         \
+               printk(KERN_ERR "SPL: Failure %d unloading "            \
+                      "dependent module\n", rc);                       \
+}                                                                       \
+                                                                        \
+module_exit(spl_##exit_fn)
+
+#endif /* _SPL_MODULE_COMPAT_H */
index 67afbfeb04d5c40f4bb6e7650400e36f332646d8..e66d8d99127e5f8a6e3e01ddccfd3b36439363fe 100644 (file)
@@ -144,6 +144,8 @@ extern int p0;
 /* Missing misc functions */
 extern int highbit(unsigned long i);
 extern uint32_t zone_get_hostid(void *zone);
+extern void spl_setup(void);
+extern void spl_cleanup(void);
 
 #define makedevice(maj,min) makedev(maj,min)
 
index 252def7bd906cddd54082a767d11e140c810fb8f..89cf115c02fd09bf455cc864287ba07a68f24f5c 100644 (file)
@@ -18,6 +18,7 @@ extern "C" {
 #include <linux/workqueue_compat.h>
 #include <linux/kallsyms_compat.h>
 #include <linux/mutex_compat.h>
+#include <linux/module_compat.h>
 
 #ifndef HAVE_UINTPTR_T
 typedef unsigned long                  uintptr_t;
index 7972f654822f0a53f36fca9e08f7c1c72eafd28d..d8a8df2722bc91bac80d245b4d9f4a1eae135713 100644 (file)
@@ -215,6 +215,7 @@ extern int vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4);
 extern int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4);
 extern file_t *vn_getf(int fd);
 extern void vn_releasef(int fd);
+extern int vn_set_pwd(const char *filename);
 
 int vn_init(void);
 void vn_fini(void);
@@ -241,7 +242,7 @@ vn_putpage(vnode_t *vp, offset_t off, ssize_t size,
 #define getf                                   vn_getf
 #define releasef                               vn_releasef
 
-extern void *rootdir;
+extern vnode_t *rootdir;
 
 #ifdef  __cplusplus
 }
index 8bf97e0cf14de32079fed2a7997089ea93f326c6..dc0ac21d039bcd45d3711cfe2d93729c143e39d5 100644 (file)
@@ -358,7 +358,8 @@ set_kallsyms_lookup_name(void)
 }
 #endif
 
-static int __init spl_init(void)
+static int
+__init spl_init(void)
 {
        int rc = 0;
 
@@ -421,7 +422,8 @@ out1:
        return rc;
 }
 
-static void spl_fini(void)
+static void
+spl_fini(void)
 {
        ENTRY;
 
@@ -436,6 +438,26 @@ static void spl_fini(void)
        debug_fini();
 }
 
+/* Called when a dependent module is loaded */
+void
+spl_setup(void)
+{
+        /*
+         * 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("/");
+}
+EXPORT_SYMBOL(spl_setup);
+
+/* Called when a dependent module is unloaded */
+void
+spl_cleanup(void)
+{
+}
+EXPORT_SYMBOL(spl_cleanup);
+
 module_init(spl_init);
 module_exit(spl_fini);
 
index 08c339a5a5c04d9bcfb4f66c33ca90febf1617ca..7d2080022ad8eddb9b9ef6046f4402a254869173 100644 (file)
@@ -34,7 +34,7 @@
 
 #define DEBUG_SUBSYSTEM S_VNODE
 
-void *rootdir = NULL;
+vnode_t *rootdir = (vnode_t *)0xabcd1234;
 EXPORT_SYMBOL(rootdir);
 
 static spl_kmem_cache_t *vn_cache;
@@ -602,6 +602,90 @@ vn_releasef(int fd)
 } /* releasef() */
 EXPORT_SYMBOL(releasef);
 
+#ifndef HAVE_SET_FS_PWD
+# ifdef HAVE_2ARGS_SET_FS_PWD
+/* Used from 2.6.25 - 2.6.31+ */
+void
+set_fs_pwd(struct fs_struct *fs, struct path *path)
+{
+        struct path old_pwd;
+
+        write_lock(&fs->lock);
+        old_pwd = fs->pwd;
+        fs->pwd = *path;
+        path_get(path);
+        write_unlock(&fs->lock);
+
+        if (old_pwd.dentry)
+                path_put(&old_pwd);
+}
+# else
+/* Used from 2.6.11 - 2.6.24 */
+void
+set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt, struct dentry *dentry)
+{
+        struct dentry *old_pwd;
+        struct vfsmount *old_pwdmnt;
+
+        write_lock(&fs->lock);
+        old_pwd = fs->pwd;
+        old_pwdmnt = fs->pwdmnt;
+        fs->pwdmnt = mntget(mnt);
+        fs->pwd = dget(dentry);
+        write_unlock(&fs->lock);
+
+        if (old_pwd) {
+                dput(old_pwd);
+                mntput(old_pwdmnt);
+        }
+}
+# endif /* HAVE_2ARGS_SET_FS_PWD */
+#endif /* HAVE_SET_FS_PWD */
+
+int
+vn_set_pwd(const char *filename)
+{
+#ifdef HAVE_2ARGS_SET_FS_PWD
+        struct path path;
+        int rc;
+        ENTRY;
+
+        rc = user_path_dir(filename, &path);
+        if (rc)
+                GOTO(out, rc);
+
+        rc = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
+        if (rc)
+                GOTO(dput_and_out, rc);
+
+        set_fs_pwd(current->fs, &path);
+
+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)
+                GOTO(out, rc);
+
+        rc = vfs_permission(&nd, MAY_EXEC);
+        if (rc)
+                GOTO(dput_and_out, rc);
+
+        set_fs_pwd(current->fs, nd.nd_mnt, nd.nd_dentry);
+
+dput_and_out:
+        vn_path_release(&nd);
+#endif /* HAVE_2ARGS_SET_FS_PWD */
+out:
+        RETURN(-rc);
+} /* vn_set_pwd() */
+EXPORT_SYMBOL(vn_set_pwd);
+
 static int
 vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
 {
index 1591039807614620b003b70f74cbb1b31277d3d0..9e52ab4fbb68bbf113819707bc18cab31989c89c 100644 (file)
@@ -608,7 +608,7 @@ static struct cdev splat_cdev = {
        .kobj   =       { .name = SPLAT_NAME, },
 };
 
-static int __init
+static int
 splat_init(void)
 {
        dev_t dev;
@@ -667,7 +667,7 @@ error:
        return rc;
 }
 
-static void
+static int
 splat_fini(void)
 {
        dev_t dev = MKDEV(SPLAT_MAJOR, 0);
@@ -695,10 +695,12 @@ splat_fini(void)
        ASSERT(list_empty(&splat_module_list));
        printk(KERN_INFO "SPLAT: Unloaded Solaris Porting LAyer "
               "Tests v%s\n", SPL_META_VERSION);
+
+       return 0;
 }
 
-module_init(splat_init);
-module_exit(splat_fini);
+spl_module_init(splat_init);
+spl_module_exit(splat_fini);
 
 MODULE_AUTHOR("Lawrence Livermore National Labs");
 MODULE_DESCRIPTION("Solaris Porting LAyer Tests");
index bd42119cb81dc85d209a85be62b6404ad05250a3..176da466b730032ca4b76824823b7e20698cacba 100644 (file)
@@ -12,6 +12,9 @@
 /* register_sysctl_table() wants 2 args */
 #undef HAVE_2ARGS_REGISTER_SYSCTL
 
+/* set_fs_pwd() wants 2 args */
+#undef HAVE_2ARGS_SET_FS_PWD
+
 /* vfs_unlink() wants 2 args */
 #undef HAVE_2ARGS_VFS_UNLINK
 
 /* __put_task_struct() is available */
 #undef HAVE_PUT_TASK_STRUCT
 
+/* set_fs_pwd() is available */
+#undef HAVE_SET_FS_PWD
+
 /* set_normalized_timespec() is available as export */
 #undef HAVE_SET_NORMALIZED_TIMESPEC_EXPORT