mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 03:09:34 +03:00
Set cwd to '/' for the process executing insmod.
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.
This commit is contained in:
parent
0e77fc118e
commit
51a727e90f
@ -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.
|
||||
|
210
configure
vendored
210
configure
vendored
@ -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
|
||||
|
35
include/linux/module_compat.h
Normal file
35
include/linux/module_compat.h
Normal file
@ -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 */
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
||||
@ -120,6 +123,9 @@
|
||||
/* __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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user