aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/kernel-fst-mount.m428
-rw-r--r--config/kernel-mount-nodev.m420
-rw-r--r--config/kernel.m42
-rw-r--r--include/linux/vfs_compat.h24
-rw-r--r--module/zfs/zpl_super.c65
-rw-r--r--tests/runfiles/linux.run2
-rw-r--r--tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am3
-rwxr-xr-xtests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_multi_mount.ksh104
8 files changed, 219 insertions, 29 deletions
diff --git a/config/kernel-fst-mount.m4 b/config/kernel-fst-mount.m4
new file mode 100644
index 000000000..a8ac50bdd
--- /dev/null
+++ b/config/kernel-fst-mount.m4
@@ -0,0 +1,28 @@
+dnl #
+dnl # 2.6.38 API change
+dnl # The .get_sb callback has been replaced by a .mount callback
+dnl # in the file_system_type structure.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FST_MOUNT], [
+ AC_MSG_CHECKING([whether fst->mount() exists])
+ ZFS_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+
+ static struct dentry *
+ mount(struct file_system_type *fs_type, int flags,
+ const char *osname, void *data) {
+ struct dentry *d = NULL;
+ return (d);
+ }
+
+ static struct file_system_type fst __attribute__ ((unused)) = {
+ .mount = mount,
+ };
+ ],[
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_FST_MOUNT, 1, [fst->mount() exists])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
diff --git a/config/kernel-mount-nodev.m4 b/config/kernel-mount-nodev.m4
deleted file mode 100644
index 28a45157e..000000000
--- a/config/kernel-mount-nodev.m4
+++ /dev/null
@@ -1,20 +0,0 @@
-dnl #
-dnl # 2.6.39 API change
-dnl # The .get_sb callback has been replaced by a .mount callback
-dnl # in the file_system_type structure. When using the new
-dnl # interface the caller must now use the mount_nodev() helper.
-dnl # This updated callback and helper no longer pass the vfsmount.
-dnl #
-AC_DEFUN([ZFS_AC_KERNEL_MOUNT_NODEV],
- [AC_MSG_CHECKING([whether mount_nodev() is available])
- ZFS_LINUX_TRY_COMPILE_SYMBOL([
- #include <linux/fs.h>
- ], [
- mount_nodev(NULL, 0, NULL, NULL);
- ], [mount_nodev], [fs/super.c], [
- AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_MOUNT_NODEV, 1, [mount_nodev() is available])
- ], [
- AC_MSG_RESULT(no)
- ])
-])
diff --git a/config/kernel.m4 b/config/kernel.m4
index 59065ca08..e3daeffa8 100644
--- a/config/kernel.m4
+++ b/config/kernel.m4
@@ -103,7 +103,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
ZFS_AC_KERNEL_TRUNCATE_SETSIZE
ZFS_AC_KERNEL_6ARGS_SECURITY_INODE_INIT_SECURITY
ZFS_AC_KERNEL_CALLBACK_SECURITY_INODE_INIT_SECURITY
- ZFS_AC_KERNEL_MOUNT_NODEV
+ ZFS_AC_KERNEL_FST_MOUNT
ZFS_AC_KERNEL_SHRINK
ZFS_AC_KERNEL_SHRINK_CONTROL_HAS_NID
ZFS_AC_KERNEL_S_INSTANCES_LIST_HEAD
diff --git a/include/linux/vfs_compat.h b/include/linux/vfs_compat.h
index 6347268af..c8203bd55 100644
--- a/include/linux/vfs_compat.h
+++ b/include/linux/vfs_compat.h
@@ -183,6 +183,30 @@ zpl_bdi_destroy(struct super_block *sb)
#endif
/*
+ * 4.14 adds SB_* flag definitions, define them to MS_* equivalents
+ * if not set.
+ */
+#ifndef SB_RDONLY
+#define SB_RDONLY MS_RDONLY
+#endif
+
+#ifndef SB_SILENT
+#define SB_SILENT MS_SILENT
+#endif
+
+#ifndef SB_ACTIVE
+#define SB_ACTIVE MS_ACTIVE
+#endif
+
+#ifndef SB_POSIXACL
+#define SB_POSIXACL MS_POSIXACL
+#endif
+
+#ifndef SB_MANDLOCK
+#define SB_MANDLOCK MS_MANDLOCK
+#endif
+
+/*
* 2.6.38 API change,
* LOOKUP_RCU flag introduced to distinguish rcu-walk from ref-walk cases.
*/
diff --git a/module/zfs/zpl_super.c b/module/zfs/zpl_super.c
index 25e75a897..fc10271b7 100644
--- a/module/zfs/zpl_super.c
+++ b/module/zfs/zpl_super.c
@@ -248,14 +248,61 @@ zpl_fill_super(struct super_block *sb, void *data, int silent)
return (error);
}
-#ifdef HAVE_MOUNT_NODEV
+static int
+zpl_test_super(struct super_block *s, void *data)
+{
+ zfsvfs_t *zfsvfs = s->s_fs_info;
+ objset_t *os = data;
+
+ if (zfsvfs == NULL)
+ return (0);
+
+ return (os == zfsvfs->z_os);
+}
+
+static struct super_block *
+zpl_mount_impl(struct file_system_type *fs_type, int flags, zfs_mnt_t *zm)
+{
+ struct super_block *s;
+ objset_t *os;
+ int err;
+
+ err = dmu_objset_hold(zm->mnt_osname, FTAG, &os);
+ if (err)
+ return (ERR_PTR(-err));
+
+ s = zpl_sget(fs_type, zpl_test_super, set_anon_super, flags, os);
+ dmu_objset_rele(os, FTAG);
+ if (IS_ERR(s))
+ return (ERR_CAST(s));
+
+ if (s->s_root == NULL) {
+ err = zpl_fill_super(s, zm, flags & SB_SILENT ? 1 : 0);
+ if (err) {
+ deactivate_locked_super(s);
+ return (ERR_PTR(err));
+ }
+ s->s_flags |= SB_ACTIVE;
+ } else if ((flags ^ s->s_flags) & SB_RDONLY) {
+ deactivate_locked_super(s);
+ return (ERR_PTR(-EBUSY));
+ }
+
+ return (s);
+}
+
+#ifdef HAVE_FST_MOUNT
static struct dentry *
zpl_mount(struct file_system_type *fs_type, int flags,
const char *osname, void *data)
{
zfs_mnt_t zm = { .mnt_osname = osname, .mnt_data = data };
- return (mount_nodev(fs_type, flags, &zm, zpl_fill_super));
+ struct super_block *sb = zpl_mount_impl(fs_type, flags, &zm);
+ if (IS_ERR(sb))
+ return (ERR_CAST(sb));
+
+ return (dget(sb->s_root));
}
#else
static int
@@ -264,9 +311,15 @@ zpl_get_sb(struct file_system_type *fs_type, int flags,
{
zfs_mnt_t zm = { .mnt_osname = osname, .mnt_data = data };
- return (get_sb_nodev(fs_type, flags, &zm, zpl_fill_super, mnt));
+ struct super_block *sb = zpl_mount_impl(fs_type, flags, &zm);
+ if (IS_ERR(sb))
+ return (PTR_ERR(sb));
+
+ (void) simple_set_mnt(mnt, sb);
+
+ return (0);
}
-#endif /* HAVE_MOUNT_NODEV */
+#endif /* HAVE_FST_MOUNT */
static void
zpl_kill_sb(struct super_block *sb)
@@ -333,10 +386,10 @@ const struct super_operations zpl_super_operations = {
struct file_system_type zpl_fs_type = {
.owner = THIS_MODULE,
.name = ZFS_DRIVER,
-#ifdef HAVE_MOUNT_NODEV
+#ifdef HAVE_FST_MOUNT
.mount = zpl_mount,
#else
.get_sb = zpl_get_sb,
-#endif /* HAVE_MOUNT_NODEV */
+#endif /* HAVE_FST_MOUNT */
.kill_sb = zpl_kill_sb,
};
diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run
index 9af97b81f..fb489d9fe 100644
--- a/tests/runfiles/linux.run
+++ b/tests/runfiles/linux.run
@@ -174,7 +174,7 @@ tests = ['zfs_mount_001_pos', 'zfs_mount_002_pos', 'zfs_mount_003_pos',
'zfs_mount_004_pos', 'zfs_mount_005_pos', 'zfs_mount_007_pos',
'zfs_mount_008_pos', 'zfs_mount_009_neg', 'zfs_mount_010_neg',
'zfs_mount_011_neg', 'zfs_mount_012_neg', 'zfs_mount_all_001_pos',
- 'zfs_mount_encrypted', 'zfs_mount_remount']
+ 'zfs_mount_encrypted', 'zfs_mount_remount', 'zfs_multi_mount']
tags = ['functional', 'cli_root', 'zfs_mount']
[tests/functional/cli_root/zfs_program]
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am
index b0d4e9469..05cbd8a77 100644
--- a/tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am
@@ -16,7 +16,8 @@ dist_pkgdata_SCRIPTS = \
zfs_mount_012_neg.ksh \
zfs_mount_encrypted.ksh \
zfs_mount_all_001_pos.ksh \
- zfs_mount_remount.ksh
+ zfs_mount_remount.ksh \
+ zfs_multi_mount.ksh
dist_pkgdata_DATA = \
zfs_mount.cfg \
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_multi_mount.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_multi_mount.ksh
new file mode 100755
index 000000000..e015d0aff
--- /dev/null
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_multi_mount.ksh
@@ -0,0 +1,104 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy is of the CDDL is also available via the Internet
+# at http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright(c) 2018 Datto Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify multi mount functionality
+#
+# STRATEGY:
+# 1. Create fs
+# 2. Create and hold open file in filesystem
+# 3. Lazy unmount
+# 4. Verify remounting fs that was lazily unmounted is possible
+# 5. Verify multiple mounts of the same dataset are possible
+# 6. Verify bind mount doesn't prevent rename
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+ ismounted $MNTPFS && log_must umount $MNTPFS
+ ismounted $MNTPFS2 && log_must umount $MNTPFS2
+ ismounted $MNTPFS3 && log_must umount $MNTPFS3
+ ismounted $MNTPFS4 && log_must umount $MNTPFS4
+ ismounted $RENAMEMNT && log_must umount $RENAMEMNT
+ datasetexists $TESTDS && log_must destroy_dataset "$TESTDS" "-f"
+}
+log_onexit cleanup
+
+log_assert "Verify multiple mounts into one namespace are possible"
+
+# 1. Create fs
+TESTDS="$TESTPOOL/multi-mount-test"
+log_must zfs create $TESTDS
+
+# 2. Create and hold open file in filesystem
+MNTPFS="$(get_prop mountpoint $TESTDS)"
+FILENAME="$MNTPFS/file"
+log_must mkfile 128k $FILENAME
+log_must exec 9<> $FILENAME # open file
+
+# 3. Lazy umount
+log_must umount -l $MNTPFS
+if [ -f $FILENAME ]; then
+ log_fail "Lazy unmount failed"
+fi
+
+# 4. Verify remounting fs that was lazily unmounted is possible
+log_must zfs mount $TESTDS
+if [ ! -f $FILENAME ]; then
+ log_fail "Lazy remount failed"
+fi
+log_must exec 9>&- # close fd
+
+# 5. Verify multiple mounts of the same dataset are possible
+MNTPFS2="$MNTPFS-second"
+FILENAME="$MNTPFS2/file"
+log_must mkdir $MNTPFS2
+log_must mount -t zfs -o zfsutil $TESTDS $MNTPFS2
+if [ ! -f $FILENAME ]; then
+ log_fail "First multi mount failed"
+fi
+
+MNTPFS3="$MNTPFS-third"
+FILENAME="$MNTPFS3/file"
+log_must mkdir $MNTPFS3
+log_must mount -t zfs -o zfsutil $TESTDS $MNTPFS3
+if [ ! -f $FILENAME ]; then
+ log_fail "Second multi mount failed"
+fi
+
+# 6. Verify bind mount doesn't prevent rename
+RENAMEFS="$TESTDS-newname"
+MNTPFS4="$MNTPFS-fourth"
+log_must mkdir $MNTPFS4
+log_must mount --bind $MNTPFS $MNTPFS4
+log_must zfs rename $TESTDS $RENAMEFS
+RENAMEMNT="$(get_prop mountpoint $RENAMEFS)"
+FILENAME="$RENAMEMNT/file"
+if [ ! -f $FILENAME ]; then
+ log_fail "Rename failed"
+fi
+log_must zfs rename $RENAMEFS $TESTDS
+
+log_pass "Multiple mounts are possible"