linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5]
@ 2017-06-14 15:15 David Howells
  2017-06-14 15:15 ` [PATCH 01/27] Provide a function to create a NUL-terminated string from unterminated data " David Howells
                   ` (27 more replies)
  0 siblings, 28 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:15 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel


Here are a set of patches to create a filesystem context prior to setting
up a new mount, populating it with the parsed options/binary data, creating
the superblock and then effecting the mount.  This is also used for remount
since much of the parsing stuff is common in many filesystems.

This allows namespaces and other information to be conveyed through the
mount procedure.  A method is also provided by which supplementary error
information to be retrieved (so many things can go wrong during a mount
that a small integer isn't really sufficient to convey the issue).

This also allows Miklós Szeredi's idea of doing:

	fd = fsopen("nfs");
	write(fd, "option=val", ...);
	fsmount(fd, "/mnt");

that he presented at LSF-2017 to be implemented (see the relevant patches
in the series).  I add a

	prctl(PR_ERRMSG_ENABLE, 1);

call to enable error message buffering and:

	prctl(PR_ERRMSG_READ, ...);

to retrieve and discard the latest error message.

I didn't use netlink as that would make the core kernel depend on
CONFIG_NET and CONFIG_NETLINK and would introduce network namespacing
issues.

I've implemented mount context handling for procfs, nfs, mqueue, cpuset,
kernfs, sysfs and cgroup filesystems.

Significant changes:

 ver #5:

 (*) Renamed sb_config -> fs_context and adjusted variable names.

 (*) Differentiated the flags in sb->s_flags (now named SB_*) from those
     passed to mount(2) (named MS_*).

 (*) Renamed __vfs_new_fs_context() to vfs_new_fs_context() and made the
     caller always provide a struct file_system_type pointer and the
     parameters required.

 (*) Got rid of vfs_submount_fc() in favour of passing
     FS_CONTEXT_FOR_SUBMOUNT to vfs_new_fs_context().  The purpose is now
     used more.

 (*) Call ->validate() on the remount path.

 (*) Got rid of the inode locking in sys_fsmount().

 (*) Call security_sb_mountpoint() in the mount(2) path.

 ver #4:

 (*) Split the sb_config patch up somewhat.

 (*) Made the supplementary error string facility something attached to the
     task_struct rather than the sb_config so that error messages can be
     obtained from NFS doing a mount-root-and-pathwalk inside the
     nfs_get_tree() operation.

     Further, made this managed and read by prctl rather than through the
     mount fd so that it's more generally available.

 ver #3:

 (*) Rebased on 4.12-rc1.

 (*) Split the NFS patch up somewhat.

 ver #2:

 (*) Removed the ->fill_super() from sb_config_operations and passed it in
     directly to functions that want to call it.  NFS now calls
     nfs_fill_super() directly rather than jumping through a pointer to it
     since there's only the one option at the moment.

 (*) Removed ->mnt_ns and ->sb from sb_config and moved ->pid_ns into
     proc_sb_config.

 (*) Renamed create_super -> get_tree.

 (*) Renamed struct mount_context to struct sb_config and amended various
     variable names.

 (*) sys_fsmount() acquired AT_* flags and MS_* flags (for MNT_* flags)
     arguments.

 ver #1:

 (*) Split the sb_config stuff out into its own header.

 (*) Support non-context aware filesystems through a special set of
     sb_config operations.

 (*) Stored the created superblock and root dentry into the sb_config after
     creation rather than directly into a vfsmount.  This allows some
     arguments to be removed to various NFS functions.

 (*) Added an explicit superblock-creation step.  This allows a created
     superblock to then be mounted multiple times.

 (*) Added a flag to say that the sb_config is degraded and cannot have
     another go at having a superblock creation whilst getting rid of the
     one that says it's already mounted.

Further developments:

 (*) Implement sb reconfiguration (for now it returns ENOANO).

 (*) Implement mount context support in more filesystems, ext4 being next
     on my list.

 (*) Move the walk-from-root stuff that nfs has to generic code so that you
     can do something akin to:

	mount /dev/sda1:/foo/bar /mnt

     See nfs_follow_remote_path() and mount_subtree().  This is slightly
     tricky in NFS as we have to prevent referral loops.

 (*) Work out how to get at the error message incurred by submounts
     encountered during nfs_follow_remote_path().

     Should the error message be moved to task_struct and made more
     general, perhaps retrieved with a prctl() function?

 (*) Clean up/consolidate the security functions.  Possibly add a
     validation hook to be called at the same time as the mount context
     validate op.

The patches can be found here also:

	http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=mount-context

David
---
David Howells (27):
      Provide a function to create a NUL-terminated string from unterminated data
      VFS: Clean up whitespace in fs/namespace.c and fs/super.c
      VFS: Make get_mnt_ns() return the namespace
      VFS: Make get_filesystem() return the affected filesystem
      VFS: Provide empty name qstr
      Provide supplementary error message facility
      VFS: Differentiate mount flags (MS_*) from internal superblock flags
      VFS: Introduce the structs and doc for a filesystem context
      VFS: Add LSM hooks for filesystem context
      VFS: Implement a filesystem superblock creation/configuration context
      VFS: Remove unused code after filesystem context changes
      VFS: Implement fsopen() to prepare for a mount
      VFS: Implement fsmount() to effect a pre-configured mount
      VFS: Add a sample program for fsopen/fsmount
      procfs: Move proc_fill_super() to fs/proc/root.c
      proc: Add fs_context support to procfs
      NFS: Move mount parameterisation bits into their own file
      NFS: Constify mount argument match tables
      NFS: Rename struct nfs_parsed_mount_data to struct nfs_fs_context
      NFS: Split nfs_parse_mount_options()
      NFS: Deindent nfs_fs_context_parse_option()
      NFS: Add a small buffer in nfs_fs_context to avoid string dup
      NFS: Do some tidying of the parsing code
      NFS: Add fs_context support.
      ipc: Convert mqueue fs to fs_context
      cpuset: Use fs_context
      kernfs, sysfs, cgroup: Support fs_context


 Documentation/filesystems/mounting.txt             |  436 +++++
 Documentation/filesystems/porting                  |    2 
 arch/x86/entry/syscalls/syscall_32.tbl             |    2 
 arch/x86/entry/syscalls/syscall_64.tbl             |    2 
 drivers/base/devtmpfs.c                            |    4 
 drivers/mtd/mtdsuper.c                             |    6 
 drivers/staging/lustre/lustre/llite/file.c         |    2 
 drivers/staging/lustre/lustre/llite/llite_lib.c    |   16 
 drivers/staging/lustre/lustre/llite/namei.c        |    2 
 drivers/video/fbdev/core/fbmon.c                   |    6 
 drivers/video/fbdev/edid.h                         |    2 
 fs/9p/vfs_super.c                                  |    6 
 fs/Makefile                                        |    3 
 fs/adfs/super.c                                    |    4 
 fs/affs/amigaffs.c                                 |    4 
 fs/affs/bitmap.c                                   |    8 
 fs/affs/super.c                                    |   20 
 fs/afs/super.c                                     |    4 
 fs/befs/ChangeLog                                  |    2 
 fs/befs/linuxvfs.c                                 |    6 
 fs/btrfs/ctree.h                                   |    2 
 fs/btrfs/dev-replace.c                             |    2 
 fs/btrfs/disk-io.c                                 |   12 
 fs/btrfs/extent_io.c                               |    6 
 fs/btrfs/inode.c                                   |    2 
 fs/btrfs/ioctl.c                                   |    6 
 fs/btrfs/root-tree.c                               |    2 
 fs/btrfs/super.c                                   |   60 -
 fs/btrfs/sysfs.c                                   |    4 
 fs/btrfs/volumes.c                                 |    6 
 fs/cachefiles/bind.c                               |    2 
 fs/ceph/super.c                                    |    8 
 fs/cifs/cifs_fs_sb.h                               |    2 
 fs/cifs/cifsfs.c                                   |   12 
 fs/cifs/cifsglob.h                                 |    4 
 fs/cifs/inode.c                                    |    2 
 fs/cifs/xattr.c                                    |    8 
 fs/coda/inode.c                                    |    4 
 fs/cramfs/inode.c                                  |    4 
 fs/dcache.c                                        |    8 
 fs/ecryptfs/main.c                                 |   10 
 fs/efs/super.c                                     |    6 
 fs/ext2/balloc.c                                   |    4 
 fs/ext2/ialloc.c                                   |    4 
 fs/ext2/super.c                                    |   30 
 fs/ext4/ext4_jbd2.c                                |    2 
 fs/ext4/file.c                                     |    2 
 fs/ext4/fsync.c                                    |    2 
 fs/ext4/ialloc.c                                   |    2 
 fs/ext4/inode.c                                    |    4 
 fs/ext4/mmp.c                                      |    2 
 fs/ext4/super.c                                    |  102 +
 fs/f2fs/checkpoint.c                               |    2 
 fs/f2fs/f2fs.h                                     |    2 
 fs/f2fs/gc.c                                       |    2 
 fs/f2fs/super.c                                    |   24 
 fs/fat/fatent.c                                    |    8 
 fs/fat/inode.c                                     |   12 
 fs/fat/misc.c                                      |    4 
 fs/fat/namei_msdos.c                               |    2 
 fs/filesystems.c                                   |    3 
 fs/freevxfs/vxfs_super.c                           |    4 
 fs/fs-writeback.c                                  |    2 
 fs/fs_context.c                                    |  501 +++++
 fs/fsopen.c                                        |  273 +++
 fs/fuse/inode.c                                    |   12 
 fs/gfs2/dir.c                                      |    3 
 fs/gfs2/glops.c                                    |    2 
 fs/gfs2/ops_fstype.c                               |   20 
 fs/gfs2/quota.c                                    |    2 
 fs/gfs2/recovery.c                                 |    2 
 fs/gfs2/super.c                                    |   14 
 fs/gfs2/sys.c                                      |    2 
 fs/gfs2/trans.c                                    |    2 
 fs/hfs/mdb.c                                       |   10 
 fs/hfs/super.c                                     |   18 
 fs/hfsplus/super.c                                 |   30 
 fs/hpfs/alloc.c                                    |    4 
 fs/hpfs/dir.c                                      |    2 
 fs/hpfs/map.c                                      |    2 
 fs/hpfs/super.c                                    |   20 
 fs/inode.c                                         |   10 
 fs/internal.h                                      |    4 
 fs/isofs/inode.c                                   |    4 
 fs/jffs2/fs.c                                      |   10 
 fs/jffs2/os-linux.h                                |    2 
 fs/jffs2/super.c                                   |    6 
 fs/jffs2/wbuf.c                                    |    4 
 fs/jfs/jfs_mount.c                                 |    2 
 fs/jfs/super.c                                     |   22 
 fs/kernfs/mount.c                                  |   90 +
 fs/libfs.c                                         |   22 
 fs/locks.c                                         |    2 
 fs/minix/inode.c                                   |    8 
 fs/mount.h                                         |    3 
 fs/namei.c                                         |    5 
 fs/namespace.c                                     |  508 ++++--
 fs/ncpfs/inode.c                                   |    4 
 fs/nfs/Makefile                                    |    6 
 fs/nfs/client.c                                    |   74 -
 fs/nfs/dir.c                                       |    2 
 fs/nfs/fs_context.c                                | 1499 ++++++++++++++++
 fs/nfs/fscache.c                                   |    2 
 fs/nfs/getroot.c                                   |   72 -
 fs/nfs/internal.h                                  |  131 +
 fs/nfs/namespace.c                                 |   76 +
 fs/nfs/nfs3_fs.h                                   |    2 
 fs/nfs/nfs3client.c                                |    6 
 fs/nfs/nfs3proc.c                                  |    2 
 fs/nfs/nfs4_fs.h                                   |    4 
 fs/nfs/nfs4client.c                                |   82 -
 fs/nfs/nfs4namespace.c                             |  208 +-
 fs/nfs/nfs4proc.c                                  |    3 
 fs/nfs/nfs4super.c                                 |  220 +-
 fs/nfs/proc.c                                      |    2 
 fs/nfs/super.c                                     | 1836 ++------------------
 fs/nilfs2/inode.c                                  |    4 
 fs/nilfs2/mdt.c                                    |    2 
 fs/nilfs2/segment.c                                |    2 
 fs/nilfs2/super.c                                  |   40 
 fs/nilfs2/the_nilfs.c                              |    6 
 fs/notify/fsnotify.c                               |    2 
 fs/nsfs.c                                          |    5 
 fs/ntfs/super.c                                    |   56 -
 fs/ocfs2/file.c                                    |    2 
 fs/ocfs2/super.c                                   |   38 
 fs/ocfs2/xattr.c                                   |    2 
 fs/openpromfs/inode.c                              |    4 
 fs/orangefs/super.c                                |    6 
 fs/overlayfs/super.c                               |   10 
 fs/pipe.c                                          |    3 
 fs/proc/inode.c                                    |   50 -
 fs/proc/internal.h                                 |    6 
 fs/proc/root.c                                     |  211 ++
 fs/proc_namespace.c                                |   10 
 fs/qnx4/inode.c                                    |    4 
 fs/qnx6/inode.c                                    |    4 
 fs/quota/quota.c                                   |    2 
 fs/reiserfs/inode.c                                |    4 
 fs/reiserfs/journal.c                              |    8 
 fs/reiserfs/prints.c                               |    6 
 fs/reiserfs/super.c                                |   34 
 fs/reiserfs/xattr.c                                |   10 
 fs/romfs/super.c                                   |    4 
 fs/squashfs/super.c                                |    4 
 fs/statfs.c                                        |    4 
 fs/super.c                                         |  277 ++-
 fs/sync.c                                          |    6 
 fs/sysfs/mount.c                                   |   59 -
 fs/sysv/balloc.c                                   |    2 
 fs/sysv/ialloc.c                                   |    2 
 fs/sysv/inode.c                                    |    4 
 fs/sysv/super.c                                    |    4 
 fs/ubifs/file.c                                    |    2 
 fs/ubifs/io.c                                      |    2 
 fs/ubifs/super.c                                   |   22 
 fs/ubifs/ubifs.h                                   |    4 
 fs/udf/super.c                                     |   18 
 fs/ufs/balloc.c                                    |    8 
 fs/ufs/ialloc.c                                    |   10 
 fs/ufs/super.c                                     |   52 -
 fs/xfs/xfs_mount.c                                 |    4 
 fs/xfs/xfs_quotaops.c                              |   10 
 fs/xfs/xfs_super.c                                 |   12 
 fs/xfs/xfs_super.h                                 |    2 
 include/linux/cgroup.h                             |    3 
 include/linux/dcache.h                             |    5 
 include/linux/fb.h                                 |    2 
 include/linux/fs.h                                 |   66 +
 include/linux/fs_context.h                         |   86 +
 include/linux/kernfs.h                             |   37 
 include/linux/lsm_hooks.h                          |   47 -
 include/linux/mount.h                              |    2 
 include/linux/nfs_xdr.h                            |    7 
 include/linux/sched.h                              |   29 
 include/linux/security.h                           |   39 
 include/linux/string.h                             |    1 
 include/linux/syscalls.h                           |    3 
 include/uapi/linux/bfs_fs.h                        |    2 
 include/uapi/linux/magic.h                         |    1 
 include/uapi/linux/prctl.h                         |    6 
 init/do_mounts.c                                   |    6 
 ipc/mqueue.c                                       |   90 +
 kernel/cgroup/cgroup-internal.h                    |   42 
 kernel/cgroup/cgroup-v1.c                          |  291 ++-
 kernel/cgroup/cgroup.c                             |  172 +-
 kernel/cgroup/cpuset.c                             |   58 -
 kernel/exit.c                                      |    1 
 kernel/fork.c                                      |    1 
 kernel/sys.c                                       |   38 
 kernel/sys_ni.c                                    |    4 
 mm/shmem.c                                         |   10 
 mm/util.c                                          |   24 
 samples/fsmount/test-fsmount.c                     |   92 +
 scripts/gdb/linux/constants.py.in                  |   12 
 scripts/gdb/linux/proc.py                          |    8 
 security/apparmor/include/lib.h                    |    2 
 security/security.c                                |   35 
 security/selinux/hooks.c                           |  201 ++
 .../selftests/mount/unprivileged-remount-test.c    |    8 
 200 files changed, 5839 insertions(+), 3415 deletions(-)
 create mode 100644 Documentation/filesystems/mounting.txt
 create mode 100644 fs/fs_context.c
 create mode 100644 fs/fsopen.c
 create mode 100644 fs/nfs/fs_context.c
 create mode 100644 include/linux/fs_context.h
 create mode 100644 samples/fsmount/test-fsmount.c

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH 01/27] Provide a function to create a NUL-terminated string from unterminated data [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
@ 2017-06-14 15:15 ` David Howells
  2017-06-14 15:15 ` [PATCH 02/27] VFS: Clean up whitespace in fs/namespace.c and fs/super.c " David Howells
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:15 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Provide a function, kmemdup_nul(), that will create a NUL-terminated string
from an unterminated character array where the length is known in advance.

This is better than kstrndup() in situations where we already know the
string length as the strnlen() in kstrndup() is superfluous.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 include/linux/string.h |    1 +
 mm/util.c              |   24 ++++++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/include/linux/string.h b/include/linux/string.h
index 537918f8a98e..3dd944cfe171 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -131,6 +131,7 @@ extern char *kstrdup(const char *s, gfp_t gfp) __malloc;
 extern const char *kstrdup_const(const char *s, gfp_t gfp);
 extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
 extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
+extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
 
 extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
diff --git a/mm/util.c b/mm/util.c
index 26be6407abd7..21ddf90f883d 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -83,6 +83,8 @@ EXPORT_SYMBOL(kstrdup_const);
  * @s: the string to duplicate
  * @max: read at most @max chars from @s
  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Note: Use kmemdup_nul() instead if the size is known exactly.
  */
 char *kstrndup(const char *s, size_t max, gfp_t gfp)
 {
@@ -121,6 +123,28 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
 EXPORT_SYMBOL(kmemdup);
 
 /**
+ * kmemdup_nul - Create a NUL-terminated string from unterminated data
+ * @s: The data to stringify
+ * @len: The size of the data
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
+{
+	char *buf;
+
+	if (!s)
+		return NULL;
+
+	buf = kmalloc_track_caller(len + 1, gfp);
+	if (buf) {
+		memcpy(buf, s, len);
+		buf[len] = '\0';
+	}
+	return buf;
+}
+EXPORT_SYMBOL(kmemdup_nul);
+
+/**
  * memdup_user - duplicate memory region from user space
  *
  * @src: source address in user space

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 02/27] VFS: Clean up whitespace in fs/namespace.c and fs/super.c [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
  2017-06-14 15:15 ` [PATCH 01/27] Provide a function to create a NUL-terminated string from unterminated data " David Howells
@ 2017-06-14 15:15 ` David Howells
  2017-06-14 15:15 ` [PATCH 03/27] VFS: Make get_mnt_ns() return the namespace " David Howells
                   ` (25 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:15 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Clean up line terminal whitespace in fs/namespace.c and fs/super.c.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/namespace.c |    4 ++--
 fs/super.c     |    4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index 8bd3e4d448b9..c076787871e7 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1656,7 +1656,7 @@ void __detach_mounts(struct dentry *dentry)
 	namespace_unlock();
 }
 
-/* 
+/*
  * Is the caller allowed to modify his namespace?
  */
 static inline bool may_mount(void)
@@ -2210,7 +2210,7 @@ static int do_loopback(struct path *path, const char *old_name,
 
 	err = -EINVAL;
 	if (mnt_ns_loop(old_path.dentry))
-		goto out; 
+		goto out;
 
 	mp = lock_mount(path);
 	err = PTR_ERR(mp);
diff --git a/fs/super.c b/fs/super.c
index adb0c0de428c..dfb56a9665d8 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -508,7 +508,7 @@ struct super_block *sget_userns(struct file_system_type *type,
 			return ERR_PTR(-ENOMEM);
 		goto retry;
 	}
-		
+
 	err = set(s, data);
 	if (err) {
 		spin_unlock(&sb_lock);
@@ -771,7 +771,7 @@ struct super_block *get_active_super(struct block_device *bdev)
 	spin_unlock(&sb_lock);
 	return NULL;
 }
- 
+
 struct super_block *user_get_super(dev_t dev)
 {
 	struct super_block *sb;

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 03/27] VFS: Make get_mnt_ns() return the namespace [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
  2017-06-14 15:15 ` [PATCH 01/27] Provide a function to create a NUL-terminated string from unterminated data " David Howells
  2017-06-14 15:15 ` [PATCH 02/27] VFS: Clean up whitespace in fs/namespace.c and fs/super.c " David Howells
@ 2017-06-14 15:15 ` David Howells
  2017-06-15  9:09   ` Al Viro
  2017-06-14 15:15 ` [PATCH 04/27] VFS: Make get_filesystem() return the affected filesystem " David Howells
                   ` (24 subsequent siblings)
  27 siblings, 1 reply; 53+ messages in thread
From: David Howells @ 2017-06-14 15:15 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Make get_mnt_ns() return the namespace it got a ref on for consistency with
other namespace ref getting functions.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/mount.h |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/mount.h b/fs/mount.h
index bf1fda6eed8f..02ef292a77d7 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -108,9 +108,10 @@ static inline void detach_mounts(struct dentry *dentry)
 	__detach_mounts(dentry);
 }
 
-static inline void get_mnt_ns(struct mnt_namespace *ns)
+static inline struct mnt_namespace *get_mnt_ns(struct mnt_namespace *ns)
 {
 	atomic_inc(&ns->count);
+	return ns;
 }
 
 extern seqlock_t mount_lock;

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 04/27] VFS: Make get_filesystem() return the affected filesystem [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (2 preceding siblings ...)
  2017-06-14 15:15 ` [PATCH 03/27] VFS: Make get_mnt_ns() return the namespace " David Howells
@ 2017-06-14 15:15 ` David Howells
  2017-06-14 15:16 ` [PATCH 05/27] VFS: Provide empty name qstr " David Howells
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:15 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Make get_filesystem() return a pointer to the filesystem on which it just
got a ref.

Suggested-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/filesystems.c   |    3 ++-
 include/linux/fs.h |    2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/filesystems.c b/fs/filesystems.c
index cac75547d35c..591e52d23ed4 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -33,9 +33,10 @@ static struct file_system_type *file_systems;
 static DEFINE_RWLOCK(file_systems_lock);
 
 /* WARNING: This can be used only if we _already_ own a reference */
-void get_filesystem(struct file_system_type *fs)
+struct file_system_type *get_filesystem(struct file_system_type *fs)
 {
 	__module_get(fs->owner);
+	return fs;
 }
 
 void put_filesystem(struct file_system_type *fs)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 803e5a9b2654..bc0c054894b9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2956,7 +2956,7 @@ extern int generic_block_fiemap(struct inode *inode,
 				struct fiemap_extent_info *fieinfo, u64 start,
 				u64 len, get_block_t *get_block);
 
-extern void get_filesystem(struct file_system_type *fs);
+extern struct file_system_type *get_filesystem(struct file_system_type *fs);
 extern void put_filesystem(struct file_system_type *fs);
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(struct block_device *);

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 05/27] VFS: Provide empty name qstr [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (3 preceding siblings ...)
  2017-06-14 15:15 ` [PATCH 04/27] VFS: Make get_filesystem() return the affected filesystem " David Howells
@ 2017-06-14 15:16 ` David Howells
  2017-06-14 15:16 ` [PATCH 06/27] Provide supplementary error message facility " David Howells
                   ` (22 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:16 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Provide an empty name (ie. "") qstr for general use.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/dcache.c            |    8 ++++++--
 fs/gfs2/dir.c          |    3 +--
 fs/namei.c             |    3 +--
 fs/nsfs.c              |    3 +--
 fs/pipe.c              |    3 +--
 include/linux/dcache.h |    5 +++++
 6 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index cddf39777835..d3da2a3ffd73 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -90,6 +90,11 @@ EXPORT_SYMBOL(rename_lock);
 
 static struct kmem_cache *dentry_cache __read_mostly;
 
+const struct qstr empty_name = QSTR_INIT("", 0);
+EXPORT_SYMBOL(empty_name);
+const struct qstr slash_name = QSTR_INIT("/", 1);
+EXPORT_SYMBOL(slash_name);
+
 /*
  * This is the single most critical data structure when it comes
  * to the dcache: the hashtable for lookups. Somebody should try
@@ -1580,8 +1585,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
 	 */
 	dentry->d_iname[DNAME_INLINE_LEN-1] = 0;
 	if (unlikely(!name)) {
-		static const struct qstr anon = QSTR_INIT("/", 1);
-		name = &anon;
+		name = &slash_name;
 		dname = dentry->d_iname;
 	} else if (name->len > DNAME_INLINE_LEN-1) {
 		size_t size = offsetof(struct external_name, name[1]);
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 79113219be5f..a5dfff6a033e 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -872,7 +872,6 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
 	struct buffer_head *bh;
 	struct gfs2_leaf *leaf;
 	struct gfs2_dirent *dent;
-	struct qstr name = { .name = "" };
 	struct timespec tv = current_time(inode);
 
 	error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
@@ -896,7 +895,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
 	leaf->lf_sec = cpu_to_be64(tv.tv_sec);
 	memset(leaf->lf_reserved2, 0, sizeof(leaf->lf_reserved2));
 	dent = (struct gfs2_dirent *)(leaf+1);
-	gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);
+	gfs2_qstr2dirent(&empty_name, bh->b_size - sizeof(struct gfs2_leaf), dent);
 	*pbh = bh;
 	return leaf;
 }
diff --git a/fs/namei.c b/fs/namei.c
index 6571a5f5112e..0d35760fee00 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3400,7 +3400,6 @@ static int do_last(struct nameidata *nd,
 
 struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag)
 {
-	static const struct qstr name = QSTR_INIT("/", 1);
 	struct dentry *child = NULL;
 	struct inode *dir = dentry->d_inode;
 	struct inode *inode;
@@ -3414,7 +3413,7 @@ struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag)
 	if (!dir->i_op->tmpfile)
 		goto out_err;
 	error = -ENOMEM;
-	child = d_alloc(dentry, &name);
+	child = d_alloc(dentry, &slash_name);
 	if (unlikely(!child))
 		goto out_err;
 	error = dir->i_op->tmpfile(dir, child, mode);
diff --git a/fs/nsfs.c b/fs/nsfs.c
index f3db56e83dd2..08127a2b8559 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -53,7 +53,6 @@ static void nsfs_evict(struct inode *inode)
 static void *__ns_get_path(struct path *path, struct ns_common *ns)
 {
 	struct vfsmount *mnt = nsfs_mnt;
-	struct qstr qname = { .name = "", };
 	struct dentry *dentry;
 	struct inode *inode;
 	unsigned long d;
@@ -85,7 +84,7 @@ static void *__ns_get_path(struct path *path, struct ns_common *ns)
 	inode->i_fop = &ns_file_operations;
 	inode->i_private = ns;
 
-	dentry = d_alloc_pseudo(mnt->mnt_sb, &qname);
+	dentry = d_alloc_pseudo(mnt->mnt_sb, &empty_name);
 	if (!dentry) {
 		iput(inode);
 		return ERR_PTR(-ENOMEM);
diff --git a/fs/pipe.c b/fs/pipe.c
index 73b84baf58f8..97e5be897753 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -739,13 +739,12 @@ int create_pipe_files(struct file **res, int flags)
 	struct inode *inode = get_pipe_inode();
 	struct file *f;
 	struct path path;
-	static struct qstr name = { .name = "" };
 
 	if (!inode)
 		return -ENFILE;
 
 	err = -ENOMEM;
-	path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &name);
+	path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &empty_name);
 	if (!path.dentry)
 		goto err_inode;
 	path.mnt = mntget(pipe_mnt);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index d2e38dc6172c..3f65a4fa72ed 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -55,6 +55,11 @@ struct qstr {
 
 #define QSTR_INIT(n,l) { { { .len = l } }, .name = n }
 
+extern const char empty_string[];
+extern const struct qstr empty_name;
+extern const char slash_string[];
+extern const struct qstr slash_name;
+
 struct dentry_stat_t {
 	long nr_dentry;
 	long nr_unused;

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 06/27] Provide supplementary error message facility [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (4 preceding siblings ...)
  2017-06-14 15:16 ` [PATCH 05/27] VFS: Provide empty name qstr " David Howells
@ 2017-06-14 15:16 ` David Howells
  2017-08-18  3:09   ` Kim Phillips
  2017-06-14 15:16 ` [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags " David Howells
                   ` (21 subsequent siblings)
  27 siblings, 1 reply; 53+ messages in thread
From: David Howells @ 2017-06-14 15:16 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Provide a way for the kernel to pass supplementary error messages to
userspace.  This will make it easier for userspace, particularly in
containers to find out what went wrong during mounts and automounts, but is
also made available to any other syscalls that want to use it.

Two prctl() functions are added for this:

 (1) int old_setting = prctl(PR_ERRMSG_ENABLE, int setting);

     Enable (setting == 1) or disable (setting == 0) the facility.
     Disabling the facility clears the error buffer.

 (2) int size = prctl(PR_ERRMSG_READ, char *buffer, int buf_size);

     Reads the next error string into the buffer.  The string is truncated
     if it won't fit.  Strings are discarded as they're read.

     If there isn't a string, ENODATA is indicated.

I've done it this way rather than a proc file because procfs might not be
accessible.

The interface inside the kernel is a pair of macros:

 (*) void errorf(const char *fmt, ...);
 (*) int invalf(const char *fmt, ...);

Both of them snprintf() the string into the current process's error message
buffer if the facility is enabled.  The string is truncated if it exceeds
the limit.  invalf() returns -EINVAL whereas errof() has no return.

Note that this is very crude and could be made to store multiple strings,
allocate storage as required and not duplicate unformatted strings that are
stored in the rodata section (like kvasprintf_const).  Unfortunately,
specially handling rodata strings wouldn't gain a lot as most strings are
likely to be in modules, where the string's life can be terminated by
rmmod.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 include/linux/sched.h      |   29 +++++++++++++++++++++++++++++
 include/uapi/linux/prctl.h |    6 ++++++
 kernel/exit.c              |    1 +
 kernel/fork.c              |    1 +
 kernel/sys.c               |   38 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 75 insertions(+)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2b69fc650201..a6002b60b0b9 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1051,6 +1051,8 @@ struct task_struct {
 	/* Used by LSM modules for access restriction: */
 	void				*security;
 #endif
+#define ERROR_MSG_SIZE 256
+	char				*error_msg;
 	/* CPU-specific state of this task: */
 	struct thread_struct		thread;
 
@@ -1573,4 +1575,31 @@ extern long sched_getaffinity(pid_t pid, struct cpumask *mask);
 #define TASK_SIZE_OF(tsk)	TASK_SIZE
 #endif
 
+/**
+ * errorf - Store supplementary error message
+ * @fmt: The format string
+ *
+ * Store the supplementary error message for the process if the process has
+ * enabled the facility.
+ */
+#define errorf(fmt, ...)			\
+	do {					\
+		if (current->error_msg)					\
+			snprintf(current->error_msg, ERROR_MSG_SIZE, fmt, ## __VA_ARGS__); \
+	} while(0)
+
+/**
+ * invalf - Store supplementary invalid argument error message
+ * @fmt: The format string
+ *
+ * Store the supplementary error message for the process if the process has
+ * enabled the facility and return -EINVAL.
+ */
+#define invalf(fmt, ...)			\
+	({					\
+		errorf(fmt, ## __VA_ARGS__);	\
+		-EINVAL;			\
+	})
+
+
 #endif
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index a8d0759a9e40..b1203850dac8 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -197,4 +197,10 @@ struct prctl_mm_map {
 # define PR_CAP_AMBIENT_LOWER		3
 # define PR_CAP_AMBIENT_CLEAR_ALL	4
 
+/*
+ * Control the supplementary error message gathering facility.
+ */
+#define PR_ERRMSG_ENABLE		48
+#define PR_ERRMSG_READ			49
+
 #endif /* _LINUX_PRCTL_H */
diff --git a/kernel/exit.c b/kernel/exit.c
index 516acdb0e0ec..31b8617aee04 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -932,6 +932,7 @@ void __noreturn do_exit(long code)
 		__this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied);
 	exit_rcu();
 	TASKS_RCU(__srcu_read_unlock(&tasks_rcu_exit_srcu, tasks_rcu_i));
+	kfree(tsk->error_msg);
 
 	do_task_dead();
 }
diff --git a/kernel/fork.c b/kernel/fork.c
index e53770d2bf95..177b4c82fcb9 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1912,6 +1912,7 @@ static __latent_entropy struct task_struct *copy_process(
 
 	trace_task_newtask(p, clone_flags);
 	uprobe_copy_process(p, clone_flags);
+	p->error_msg = NULL;
 
 	return p;
 
diff --git a/kernel/sys.c b/kernel/sys.c
index 8a94b4eabcaa..b784905c4806 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2295,6 +2295,44 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 	case PR_GET_FP_MODE:
 		error = GET_FP_MODE(me);
 		break;
+
+	case PR_ERRMSG_ENABLE:
+		switch (arg2) {
+		case 0:
+			if (!current->error_msg)
+				return 0;
+			kfree(current->error_msg);
+			current->error_msg = NULL;
+			return 1;
+		case 1:
+			if (current->error_msg)
+				return 1;
+			current->error_msg = kmalloc(ERROR_MSG_SIZE, GFP_KERNEL);
+			if (!current->error_msg)
+				return -ENOMEM;
+			current->error_msg[0] = 0;
+			return 0;
+		default:
+			error = -EINVAL;
+			break;
+		}
+		break;
+
+	case PR_ERRMSG_READ:
+		if (!arg2 || !arg3)
+			return -EINVAL;
+		if (!current->error_msg)
+			return -EINVAL;
+		if (!current->error_msg[0])
+			return -ENODATA;
+		error = strlen(current->error_msg);
+		if (arg3 < error)
+			error = arg3;
+		if (copy_to_user((char __user *)arg2, current->error_msg, error))
+			return -EFAULT;
+		current->error_msg[0] = 0;
+		return error;
+
 	default:
 		error = -EINVAL;
 		break;

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (5 preceding siblings ...)
  2017-06-14 15:16 ` [PATCH 06/27] Provide supplementary error message facility " David Howells
@ 2017-06-14 15:16 ` David Howells
  2017-06-15  9:39   ` Al Viro
  2017-06-14 15:16 ` [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context " David Howells
                   ` (20 subsequent siblings)
  27 siblings, 1 reply; 53+ messages in thread
From: David Howells @ 2017-06-14 15:16 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Differentiate the MS_* flags passed to mount(2) from the internal flags set
in the super_block's s_flags.  s_flags are now called SB_*, with the names
and the values for the moment mirroring the MS_* flags that they're
equivalent to.

Note that this shows up some interesting issues:

 (1) Some MS_* flags get translated to MNT_* flags (such as MS_NODEV ->
     MNT_NODEV) without passing this on to the filesystem, but some
     filesystems set such flags anyway.

 (2) The ->remount_fs() methods of some filesystems adjust the *flags
     argument by setting MS_* flags in it, such as MS_NOATIME - but these
     flags are then scrubbed by do_remount_sb() (only the occupants of
     MS_RMT_MASK are permitted: MS_RDONLY, MS_SYNCHRONOUS, MS_MANDLOCK,
     MS_I_VERSION and MS_LAZYTIME)

I'm not sure what's the best way to solve all these cases.

Suggested-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 Documentation/filesystems/porting                  |    2 
 drivers/base/devtmpfs.c                            |    4 -
 drivers/mtd/mtdsuper.c                             |    6 +
 drivers/staging/lustre/lustre/llite/file.c         |    2 
 drivers/staging/lustre/lustre/llite/llite_lib.c    |   16 ++-
 drivers/staging/lustre/lustre/llite/namei.c        |    2 
 drivers/video/fbdev/core/fbmon.c                   |    6 +
 drivers/video/fbdev/edid.h                         |    2 
 fs/9p/vfs_super.c                                  |    6 +
 fs/adfs/super.c                                    |    4 -
 fs/affs/amigaffs.c                                 |    4 -
 fs/affs/bitmap.c                                   |    8 +-
 fs/affs/super.c                                    |   20 ++--
 fs/afs/super.c                                     |    4 -
 fs/befs/ChangeLog                                  |    2 
 fs/befs/linuxvfs.c                                 |    6 +
 fs/btrfs/ctree.h                                   |    2 
 fs/btrfs/dev-replace.c                             |    2 
 fs/btrfs/disk-io.c                                 |   12 +-
 fs/btrfs/extent_io.c                               |    6 +
 fs/btrfs/inode.c                                   |    2 
 fs/btrfs/ioctl.c                                   |    6 +
 fs/btrfs/root-tree.c                               |    2 
 fs/btrfs/super.c                                   |   60 ++++++------
 fs/btrfs/sysfs.c                                   |    4 -
 fs/btrfs/volumes.c                                 |    6 +
 fs/cachefiles/bind.c                               |    2 
 fs/ceph/super.c                                    |    8 +-
 fs/cifs/cifs_fs_sb.h                               |    2 
 fs/cifs/cifsfs.c                                   |   12 +-
 fs/cifs/cifsglob.h                                 |    4 -
 fs/cifs/inode.c                                    |    2 
 fs/cifs/xattr.c                                    |    8 +-
 fs/coda/inode.c                                    |    4 -
 fs/cramfs/inode.c                                  |    4 -
 fs/ecryptfs/main.c                                 |   10 +-
 fs/efs/super.c                                     |    6 +
 fs/ext2/balloc.c                                   |    4 -
 fs/ext2/ialloc.c                                   |    4 -
 fs/ext2/super.c                                    |   30 +++---
 fs/ext4/ext4_jbd2.c                                |    2 
 fs/ext4/file.c                                     |    2 
 fs/ext4/fsync.c                                    |    2 
 fs/ext4/ialloc.c                                   |    2 
 fs/ext4/inode.c                                    |    4 -
 fs/ext4/mmp.c                                      |    2 
 fs/ext4/super.c                                    |  102 ++++++++++----------
 fs/f2fs/checkpoint.c                               |    2 
 fs/f2fs/f2fs.h                                     |    2 
 fs/f2fs/gc.c                                       |    2 
 fs/f2fs/super.c                                    |   24 ++---
 fs/fat/fatent.c                                    |    8 +-
 fs/fat/inode.c                                     |   12 +-
 fs/fat/misc.c                                      |    4 -
 fs/fat/namei_msdos.c                               |    2 
 fs/freevxfs/vxfs_super.c                           |    4 -
 fs/fs-writeback.c                                  |    2 
 fs/fuse/inode.c                                    |   12 +-
 fs/gfs2/glops.c                                    |    2 
 fs/gfs2/ops_fstype.c                               |   20 ++--
 fs/gfs2/quota.c                                    |    2 
 fs/gfs2/recovery.c                                 |    2 
 fs/gfs2/super.c                                    |   14 +--
 fs/gfs2/sys.c                                      |    2 
 fs/gfs2/trans.c                                    |    2 
 fs/hfs/mdb.c                                       |   10 +-
 fs/hfs/super.c                                     |   18 ++--
 fs/hfsplus/super.c                                 |   30 +++---
 fs/hpfs/alloc.c                                    |    4 -
 fs/hpfs/dir.c                                      |    2 
 fs/hpfs/map.c                                      |    2 
 fs/hpfs/super.c                                    |   20 ++--
 fs/inode.c                                         |   10 +-
 fs/isofs/inode.c                                   |    4 -
 fs/jffs2/fs.c                                      |   10 +-
 fs/jffs2/os-linux.h                                |    2 
 fs/jffs2/super.c                                   |    6 +
 fs/jffs2/wbuf.c                                    |    4 -
 fs/jfs/jfs_mount.c                                 |    2 
 fs/jfs/super.c                                     |   22 ++--
 fs/kernfs/mount.c                                  |    2 
 fs/libfs.c                                         |    6 +
 fs/locks.c                                         |    2 
 fs/minix/inode.c                                   |    8 +-
 fs/namei.c                                         |    2 
 fs/namespace.c                                     |   30 +++---
 fs/ncpfs/inode.c                                   |    4 -
 fs/nfs/dir.c                                       |    2 
 fs/nfs/fscache.c                                   |    2 
 fs/nfs/internal.h                                  |    2 
 fs/nfs/super.c                                     |   26 +++--
 fs/nilfs2/inode.c                                  |    4 -
 fs/nilfs2/mdt.c                                    |    2 
 fs/nilfs2/segment.c                                |    2 
 fs/nilfs2/super.c                                  |   40 ++++----
 fs/nilfs2/the_nilfs.c                              |    6 +
 fs/notify/fsnotify.c                               |    2 
 fs/nsfs.c                                          |    2 
 fs/ntfs/super.c                                    |   56 +++++------
 fs/ocfs2/file.c                                    |    2 
 fs/ocfs2/super.c                                   |   38 ++++---
 fs/ocfs2/xattr.c                                   |    2 
 fs/openpromfs/inode.c                              |    4 -
 fs/orangefs/super.c                                |    6 +
 fs/overlayfs/super.c                               |   10 +-
 fs/proc/inode.c                                    |    2 
 fs/proc/root.c                                     |    2 
 fs/proc_namespace.c                                |   10 +-
 fs/qnx4/inode.c                                    |    4 -
 fs/qnx6/inode.c                                    |    4 -
 fs/quota/quota.c                                   |    2 
 fs/reiserfs/inode.c                                |    4 -
 fs/reiserfs/journal.c                              |    8 +-
 fs/reiserfs/prints.c                               |    6 +
 fs/reiserfs/super.c                                |   34 +++----
 fs/reiserfs/xattr.c                                |   10 +-
 fs/romfs/super.c                                   |    4 -
 fs/squashfs/super.c                                |    4 -
 fs/statfs.c                                        |    4 -
 fs/super.c                                         |   68 +++++++------
 fs/sync.c                                          |    6 +
 fs/sysfs/mount.c                                   |    2 
 fs/sysv/balloc.c                                   |    2 
 fs/sysv/ialloc.c                                   |    2 
 fs/sysv/inode.c                                    |    4 -
 fs/sysv/super.c                                    |    4 -
 fs/ubifs/file.c                                    |    2 
 fs/ubifs/io.c                                      |    2 
 fs/ubifs/super.c                                   |   22 ++--
 fs/ubifs/ubifs.h                                   |    4 -
 fs/udf/super.c                                     |   18 ++--
 fs/ufs/balloc.c                                    |    8 +-
 fs/ufs/ialloc.c                                    |   10 +-
 fs/ufs/super.c                                     |   52 +++++-----
 fs/xfs/xfs_mount.c                                 |    4 -
 fs/xfs/xfs_quotaops.c                              |   10 +-
 fs/xfs/xfs_super.c                                 |   12 +-
 fs/xfs/xfs_super.h                                 |    2 
 include/linux/fb.h                                 |    2 
 include/linux/fs.h                                 |   47 +++++++--
 include/uapi/linux/bfs_fs.h                        |    2 
 init/do_mounts.c                                   |    6 +
 ipc/mqueue.c                                       |    2 
 mm/shmem.c                                         |   10 +-
 scripts/gdb/linux/constants.py.in                  |   12 +-
 scripts/gdb/linux/proc.py                          |    8 +-
 security/apparmor/include/lib.h                    |    2 
 security/selinux/hooks.c                           |    2 
 .../selftests/mount/unprivileged-remount-test.c    |    8 +-
 149 files changed, 699 insertions(+), 672 deletions(-)

diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 5fb17f49f7a2..93e0a2404532 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -228,7 +228,7 @@ anything from oops to silent memory corruption.
 ---
 [mandatory]
 
-	FS_NOMOUNT is gone.  If you use it - just set MS_NOUSER in flags
+	FS_NOMOUNT is gone.  If you use it - just set SB_NOUSER in flags
 (see rootfs for one kind of solution and bdev/socket/pipe for another).
 
 ---
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index d2fb9c8ed205..e831c115daf9 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -355,7 +355,7 @@ int devtmpfs_mount(const char *mntdir)
 	if (!thread)
 		return 0;
 
-	err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL);
+	err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", SB_SILENT, NULL);
 	if (err)
 		printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
 	else
@@ -381,7 +381,7 @@ static int devtmpfsd(void *p)
 	*err = sys_unshare(CLONE_NEWNS);
 	if (*err)
 		goto out;
-	*err = sys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options);
+	*err = sys_mount("devtmpfs", "/", "devtmpfs", SB_SILENT, options);
 	if (*err)
 		goto out;
 	sys_chdir("/.."); /* will traverse into overmounted root */
diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c
index e43fea896d1e..d58a61c09304 100644
--- a/drivers/mtd/mtdsuper.c
+++ b/drivers/mtd/mtdsuper.c
@@ -79,14 +79,14 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,
 	pr_debug("MTDSB: New superblock for device %d (\"%s\")\n",
 	      mtd->index, mtd->name);
 
-	ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
+	ret = fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
 	if (ret < 0) {
 		deactivate_locked_super(sb);
 		return ERR_PTR(ret);
 	}
 
 	/* go */
-	sb->s_flags |= MS_ACTIVE;
+	sb->s_flags |= SB_ACTIVE;
 	return dget(sb->s_root);
 
 	/* new mountpoint for an already mounted superblock */
@@ -202,7 +202,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,
 not_an_MTD_device:
 #endif /* CONFIG_BLOCK */
 
-	if (!(flags & MS_SILENT))
+	if (!(flags & SB_SILENT))
 		printk(KERN_NOTICE
 		       "MTD: Attempt to mount non-MTD device \"%s\"\n",
 		       dev_name);
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index 67c4b9cc6e75..93277927caeb 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -1014,7 +1014,7 @@ static bool file_is_noatime(const struct file *file)
 	if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
 		return true;
 
-	if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
+	if ((inode->i_sb->s_flags & SB_NODIRATIME) && S_ISDIR(inode->i_mode))
 		return true;
 
 	return false;
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index ca5040c69217..aeecbcf148aa 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -210,7 +210,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
 	data->ocd_ibits_known = MDS_INODELOCK_FULL;
 	data->ocd_version = LUSTRE_VERSION_CODE;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		data->ocd_connect_flags |= OBD_CONNECT_RDONLY;
 	if (sbi->ll_flags & LL_SBI_USER_XATTR)
 		data->ocd_connect_flags |= OBD_CONNECT_XATTR;
@@ -313,11 +313,11 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
 	}
 
 	if (data->ocd_connect_flags & OBD_CONNECT_ACL) {
-		sb->s_flags |= MS_POSIXACL;
+		sb->s_flags |= SB_POSIXACL;
 		sbi->ll_flags |= LL_SBI_ACL;
 	} else {
 		LCONSOLE_INFO("client wants to enable acl, but mdt not!\n");
-		sb->s_flags &= ~MS_POSIXACL;
+		sb->s_flags &= ~SB_POSIXACL;
 		sbi->ll_flags &= ~LL_SBI_ACL;
 	}
 
@@ -658,7 +658,7 @@ void ll_kill_super(struct super_block *sb)
 	struct ll_sb_info *sbi;
 
 	/* not init sb ?*/
-	if (!(sb->s_flags & MS_ACTIVE))
+	if (!(sb->s_flags & SB_ACTIVE))
 		return;
 
 	sbi = ll_s2sbi(sb);
@@ -2033,8 +2033,8 @@ int ll_remount_fs(struct super_block *sb, int *flags, char *data)
 	int err;
 	__u32 read_only;
 
-	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
-		read_only = *flags & MS_RDONLY;
+	if ((*flags & SB_RDONLY) != (sb->s_flags & SB_RDONLY)) {
+		read_only = *flags & SB_RDONLY;
 		err = obd_set_info_async(NULL, sbi->ll_md_exp,
 					 sizeof(KEY_READ_ONLY),
 					 KEY_READ_ONLY, sizeof(read_only),
@@ -2047,9 +2047,9 @@ int ll_remount_fs(struct super_block *sb, int *flags, char *data)
 		}
 
 		if (read_only)
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 		else
-			sb->s_flags &= ~MS_RDONLY;
+			sb->s_flags &= ~SB_RDONLY;
 
 		if (sbi->ll_flags & LL_SBI_VERBOSE)
 			LCONSOLE_WARN("Remounted %s %s\n", profilenm,
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index d583696e8378..aad773edfdd2 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -563,7 +563,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
 	}
 
 	if (it->it_op & IT_OPEN && it->it_flags & FMODE_WRITE &&
-	    dentry->d_sb->s_flags & MS_RDONLY)
+	    dentry->d_sb->s_flags & SB_RDONLY)
 		return ERR_PTR(-EROFS);
 
 	if (it->it_op & IT_CREAT)
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
index 687ebb053438..472468433107 100644
--- a/drivers/video/fbdev/core/fbmon.c
+++ b/drivers/video/fbdev/core/fbmon.c
@@ -311,14 +311,14 @@ static void get_dpms_capabilities(unsigned char flags,
 				  struct fb_monspecs *specs)
 {
 	specs->dpms = 0;
-	if (flags & DPMS_ACTIVE_OFF)
-		specs->dpms |= FB_DPMS_ACTIVE_OFF;
+	if (flags & DPSB_ACTIVE_OFF)
+		specs->dpms |= FB_DPSB_ACTIVE_OFF;
 	if (flags & DPMS_SUSPEND)
 		specs->dpms |= FB_DPMS_SUSPEND;
 	if (flags & DPMS_STANDBY)
 		specs->dpms |= FB_DPMS_STANDBY;
 	DPRINTK("      DPMS: Active %s, Suspend %s, Standby %s\n",
-	       (flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
+	       (flags & DPSB_ACTIVE_OFF) ? "yes" : "no",
 	       (flags & DPMS_SUSPEND)    ? "yes" : "no",
 	       (flags & DPMS_STANDBY)    ? "yes" : "no");
 }
diff --git a/drivers/video/fbdev/edid.h b/drivers/video/fbdev/edid.h
index d03a232d90b2..b6e23f4bb4f8 100644
--- a/drivers/video/fbdev/edid.h
+++ b/drivers/video/fbdev/edid.h
@@ -131,7 +131,7 @@
 #define MAX_PIXEL_CLOCK         (((int)block[ 9 ]) * 10)
 #define GTF_SUPPORT		block[10]
 
-#define DPMS_ACTIVE_OFF		(1 << 5)
+#define DPSB_ACTIVE_OFF		(1 << 5)
 #define DPMS_SUSPEND		(1 << 6)
 #define DPMS_STANDBY		(1 << 7)
 
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index a0965fb587a5..f126ac5021b6 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -95,13 +95,13 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
 	if (v9ses->cache)
 		sb->s_bdi->ra_pages = (VM_MAX_READAHEAD * 1024)/PAGE_SIZE;
 
-	sb->s_flags |= MS_ACTIVE | MS_DIRSYNC | MS_NOATIME;
+	sb->s_flags |= SB_ACTIVE | SB_DIRSYNC | SB_NOATIME;
 	if (!v9ses->cache)
-		sb->s_flags |= MS_SYNCHRONOUS;
+		sb->s_flags |= SB_SYNCHRONOUS;
 
 #ifdef CONFIG_9P_FS_POSIX_ACL
 	if ((v9ses->flags & V9FS_ACL_MASK) == V9FS_POSIX_ACL)
-		sb->s_flags |= MS_POSIXACL;
+		sb->s_flags |= SB_POSIXACL;
 #endif
 
 	save_mount_options(sb, data);
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index c9fdfb112933..cfda2c7caedc 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -213,7 +213,7 @@ static int parse_options(struct super_block *sb, char *options)
 static int adfs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_NODIRATIME;
+	*flags |= SB_NODIRATIME;
 	return parse_options(sb, data);
 }
 
@@ -372,7 +372,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 	struct inode *root;
 	int ret = -EINVAL;
 
-	sb->s_flags |= MS_NODIRATIME;
+	sb->s_flags |= SB_NODIRATIME;
 
 	asb = kzalloc(sizeof(*asb), GFP_KERNEL);
 	if (!asb)
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index b573c3b9a328..6d5b23ae339c 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -450,9 +450,9 @@ affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
 	vaf.fmt = fmt;
 	vaf.va = &args;
 	pr_crit("error (device %s): %s(): %pV\n", sb->s_id, function, &vaf);
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		pr_warn("Remounting filesystem read-only\n");
-	sb->s_flags |= MS_RDONLY;
+	sb->s_flags |= SB_RDONLY;
 	va_end(args);
 }
 
diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c
index 675148950fed..5e29a2e4546b 100644
--- a/fs/affs/bitmap.c
+++ b/fs/affs/bitmap.c
@@ -19,7 +19,7 @@ affs_count_free_blocks(struct super_block *sb)
 
 	pr_debug("%s()\n", __func__);
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return 0;
 
 	mutex_lock(&AFFS_SB(sb)->s_bmlock);
@@ -249,12 +249,12 @@ int affs_init_bitmap(struct super_block *sb, int *flags)
 	int i, res = 0;
 	struct affs_sb_info *sbi = AFFS_SB(sb);
 
-	if (*flags & MS_RDONLY)
+	if (*flags & SB_RDONLY)
 		return 0;
 
 	if (!AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->bm_flag) {
 		pr_notice("Bitmap invalid - mounting %s read only\n", sb->s_id);
-		*flags |= MS_RDONLY;
+		*flags |= SB_RDONLY;
 		return 0;
 	}
 
@@ -287,7 +287,7 @@ int affs_init_bitmap(struct super_block *sb, int *flags)
 		if (affs_checksum_block(sb, bh)) {
 			pr_warn("Bitmap %u invalid - mounting %s read only.\n",
 				bm->bm_key, sb->s_id);
-			*flags |= MS_RDONLY;
+			*flags |= SB_RDONLY;
 			goto out;
 		}
 		pr_debug("read bitmap block %d: %d\n", blk, bm->bm_key);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index c2c27a8f128e..7846615dcead 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -78,7 +78,7 @@ void affs_mark_sb_dirty(struct super_block *sb)
 	struct affs_sb_info *sbi = AFFS_SB(sb);
 	unsigned long delay;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 	       return;
 
 	spin_lock(&sbi->work_lock);
@@ -322,7 +322,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
 
 	sb->s_magic             = AFFS_SUPER_MAGIC;
 	sb->s_op                = &affs_sops;
-	sb->s_flags |= MS_NODIRATIME;
+	sb->s_flags |= SB_NODIRATIME;
 
 	sbi = kzalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
 	if (!sbi)
@@ -430,9 +430,9 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
 	 * not recommended.
 	 */
 	if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
-	     || chksum == MUFS_DCOFS) && !(sb->s_flags & MS_RDONLY)) {
+	     || chksum == MUFS_DCOFS) && !(sb->s_flags & SB_RDONLY)) {
 		pr_notice("Dircache FS - mounting %s read only\n", sb->s_id);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
 	switch (chksum) {
 	case MUFS_FS:
@@ -454,7 +454,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
 		/* fall thru */
 	case FS_OFS:
 		affs_set_opt(sbi->s_flags, SF_OFS);
-		sb->s_flags |= MS_NOEXEC;
+		sb->s_flags |= SB_NOEXEC;
 		break;
 	case MUFS_DCOFS:
 	case MUFS_INTLOFS:
@@ -463,7 +463,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
 	case FS_INTLOFS:
 		affs_set_opt(sbi->s_flags, SF_INTL);
 		affs_set_opt(sbi->s_flags, SF_OFS);
-		sb->s_flags |= MS_NOEXEC;
+		sb->s_flags |= SB_NOEXEC;
 		break;
 	default:
 		pr_err("Unknown filesystem on device %s: %08X\n",
@@ -479,7 +479,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
 			sig, sig[3] + '0', blocksize);
 	}
 
-	sb->s_flags |= MS_NODEV | MS_NOSUID;
+	sb->s_flags |= SB_NODEV | SB_NOSUID;
 
 	sbi->s_data_blksize = sb->s_blocksize;
 	if (affs_test_opt(sbi->s_flags, SF_OFS))
@@ -536,7 +536,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
 	pr_debug("%s(flags=0x%x,opts=\"%s\")\n", __func__, *flags, data);
 
 	sync_filesystem(sb);
-	*flags |= MS_NODIRATIME;
+	*flags |= SB_NODIRATIME;
 
 	memcpy(volume, sbi->s_volume, 32);
 	if (!parse_options(data, &uid, &gid, &mode, &reserved, &root_block,
@@ -564,10 +564,10 @@ affs_remount(struct super_block *sb, int *flags, char *data)
 	memcpy(sbi->s_volume, volume, 32);
 	spin_unlock(&sbi->symlink_lock);
 
-	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+	if ((*flags & SB_RDONLY) == (sb->s_flags & SB_RDONLY))
 		return 0;
 
-	if (*flags & MS_RDONLY)
+	if (*flags & SB_RDONLY)
 		affs_free_bitmap(sb);
 	else
 		res = affs_init_bitmap(sb, flags);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index c79633e5cfd8..f0df924d9e52 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -427,10 +427,10 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
 			goto error;
 		}
 		save_mount_options(sb, new_opts);
-		sb->s_flags |= MS_ACTIVE;
+		sb->s_flags |= SB_ACTIVE;
 	} else {
 		_debug("reuse");
-		ASSERTCMP(sb->s_flags, &, MS_ACTIVE);
+		ASSERTCMP(sb->s_flags, &, SB_ACTIVE);
 		afs_put_volume(vol);
 		kfree(as);
 	}
diff --git a/fs/befs/ChangeLog b/fs/befs/ChangeLog
index 75a461cfaca6..16f2dfe8c2f7 100644
--- a/fs/befs/ChangeLog
+++ b/fs/befs/ChangeLog
@@ -365,7 +365,7 @@ Version 0.4 (2001-10-28)
 	(fs/befs/super.c)
 
 * Tell the kernel to only mount befs read-only. 
-	By setting the MS_RDONLY flag in befs_read_super().
+	By setting the SB_RDONLY flag in befs_read_super().
 	Not that it was possible to write before. But now the kernel won't even try.
 	(fs/befs/super.c)
 
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 63e7c4760bfb..fd3b76b43be5 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -820,10 +820,10 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
 
 	befs_debug(sb, "---> %s", __func__);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		befs_warning(sb,
 			     "No write support. Marking filesystem read-only");
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
 
 	/*
@@ -930,7 +930,7 @@ static int
 befs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	if (!(*flags & MS_RDONLY))
+	if (!(*flags & SB_RDONLY))
 		return -EINVAL;
 	return 0;
 }
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 643c70d2b2e6..ec0ed650a768 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -2927,7 +2927,7 @@ static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info)
  */
 static inline int btrfs_need_cleaner_sleep(struct btrfs_fs_info *fs_info)
 {
-	return fs_info->sb->s_flags & MS_RDONLY || btrfs_fs_closing(fs_info);
+	return fs_info->sb->s_flags & SB_RDONLY || btrfs_fs_closing(fs_info);
 }
 
 static inline void free_fs_info(struct btrfs_fs_info *fs_info)
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 5fe1ca8abc70..50c45049c0eb 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -690,7 +690,7 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
 	u64 result;
 	int ret;
 
-	if (fs_info->sb->s_flags & MS_RDONLY)
+	if (fs_info->sb->s_flags & SB_RDONLY)
 		return -EROFS;
 
 	mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 8685d67185d0..f9387242a9c1 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2477,7 +2477,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
 		return ret;
 	}
 
-	if (fs_info->sb->s_flags & MS_RDONLY) {
+	if (fs_info->sb->s_flags & SB_RDONLY) {
 		ret = btrfs_commit_super(fs_info);
 		if (ret)
 			return ret;
@@ -2877,7 +2877,7 @@ int open_ctree(struct super_block *sb,
 
 	features = btrfs_super_compat_ro_flags(disk_super) &
 		~BTRFS_FEATURE_COMPAT_RO_SUPP;
-	if (!(sb->s_flags & MS_RDONLY) && features) {
+	if (!(sb->s_flags & SB_RDONLY) && features) {
 		btrfs_err(fs_info,
 	"cannot mount read-write because of unsupported optional features (%llx)",
 		       features);
@@ -3042,7 +3042,7 @@ int open_ctree(struct super_block *sb,
 		btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
 	if (fs_info->fs_devices->missing_devices >
 	     fs_info->num_tolerated_disk_barrier_failures &&
-	    !(sb->s_flags & MS_RDONLY)) {
+	    !(sb->s_flags & SB_RDONLY)) {
 		btrfs_warn(fs_info,
 "missing devices (%llu) exceeds the limit (%d), writeable mount is not allowed",
 			fs_info->fs_devices->missing_devices,
@@ -3105,7 +3105,7 @@ int open_ctree(struct super_block *sb,
 	if (ret)
 		goto fail_qgroup;
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		ret = btrfs_cleanup_fs_roots(fs_info);
 		if (ret)
 			goto fail_qgroup;
@@ -3131,7 +3131,7 @@ int open_ctree(struct super_block *sb,
 		goto fail_qgroup;
 	}
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return 0;
 
 	if (btrfs_test_opt(fs_info, CLEAR_CACHE) &&
@@ -3927,7 +3927,7 @@ void close_ctree(struct btrfs_fs_info *fs_info)
 
 	cancel_work_sync(&fs_info->async_reclaim_work);
 
-	if (!(fs_info->sb->s_flags & MS_RDONLY)) {
+	if (!(fs_info->sb->s_flags & SB_RDONLY)) {
 		/*
 		 * If the cleaner thread is stopped and there are
 		 * block groups queued for removal, the deletion will be
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index d8da3edf2ac3..0b37321c6326 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2006,7 +2006,7 @@ int repair_io_failure(struct btrfs_inode *inode, u64 start, u64 length,
 	struct btrfs_bio *bbio = NULL;
 	int ret;
 
-	ASSERT(!(fs_info->sb->s_flags & MS_RDONLY));
+	ASSERT(!(fs_info->sb->s_flags & SB_RDONLY));
 	BUG_ON(!mirror_num);
 
 	bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
@@ -2084,7 +2084,7 @@ int repair_eb_io_failure(struct btrfs_fs_info *fs_info,
 	unsigned long i, num_pages = num_extent_pages(eb->start, eb->len);
 	int ret = 0;
 
-	if (fs_info->sb->s_flags & MS_RDONLY)
+	if (fs_info->sb->s_flags & SB_RDONLY)
 		return -EROFS;
 
 	for (i = 0; i < num_pages; i++) {
@@ -2135,7 +2135,7 @@ int clean_io_failure(struct btrfs_inode *inode, u64 start, struct page *page,
 			failrec->start);
 		goto out;
 	}
-	if (fs_info->sb->s_flags & MS_RDONLY)
+	if (fs_info->sb->s_flags & SB_RDONLY)
 		goto out;
 
 	spin_lock(&inode->io_tree.lock);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 17cbe9306faf..0c2ff2880ba8 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5807,7 +5807,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
 
 	if (!IS_ERR(inode) && root != sub_root) {
 		down_read(&fs_info->cleanup_work_sem);
-		if (!(inode->i_sb->s_flags & MS_RDONLY))
+		if (!(inode->i_sb->s_flags & SB_RDONLY))
 			ret = btrfs_orphan_cleanup(sub_root);
 		up_read(&fs_info->cleanup_work_sem);
 		if (ret) {
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index e176375f374f..2d67ab243039 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1202,7 +1202,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
 	if (!i_done || ret)
 		goto out;
 
-	if (!(inode->i_sb->s_flags & MS_ACTIVE))
+	if (!(inode->i_sb->s_flags & SB_ACTIVE))
 		goto out;
 
 	/*
@@ -1359,7 +1359,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
 		 * make sure we stop running if someone unmounts
 		 * the FS
 		 */
-		if (!(inode->i_sb->s_flags & MS_ACTIVE))
+		if (!(inode->i_sb->s_flags & SB_ACTIVE))
 			break;
 
 		if (btrfs_defrag_cancelled(fs_info)) {
@@ -4435,7 +4435,7 @@ static long btrfs_ioctl_dev_replace(struct btrfs_fs_info *fs_info,
 
 	switch (p->cmd) {
 	case BTRFS_IOCTL_DEV_REPLACE_CMD_START:
-		if (fs_info->sb->s_flags & MS_RDONLY) {
+		if (fs_info->sb->s_flags & SB_RDONLY) {
 			ret = -EROFS;
 			goto out;
 		}
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index 7d6bc308bf43..4b55a40b8459 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -228,7 +228,7 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info)
 	int ret;
 	bool can_recover = true;
 
-	if (fs_info->sb->s_flags & MS_RDONLY)
+	if (fs_info->sb->s_flags & SB_RDONLY)
 		can_recover = false;
 
 	path = btrfs_alloc_path();
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 4f1cdd5058f1..43bf6d144025 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -102,11 +102,11 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info)
 {
 	struct super_block *sb = fs_info->sb;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return;
 
 	if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		btrfs_info(fs_info, "forced readonly");
 		/*
 		 * Note that a running device replace operation is not
@@ -136,9 +136,9 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function
 
 	/*
 	 * Special case: if the error is EROFS, and we're already
-	 * under MS_RDONLY, then it is safe here.
+	 * under SB_RDONLY, then it is safe here.
 	 */
-	if (errno == -EROFS && (sb->s_flags & MS_RDONLY))
+	if (errno == -EROFS && (sb->s_flags & SB_RDONLY))
   		return;
 
 #ifdef CONFIG_PRINTK
@@ -167,7 +167,7 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function
 	set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
 
 	/* Don't go through full error handling during mount */
-	if (sb->s_flags & MS_BORN)
+	if (sb->s_flags & SB_BORN)
 		btrfs_handle_error(fs_info);
 }
 
@@ -616,7 +616,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 			break;
 		case Opt_acl:
 #ifdef CONFIG_BTRFS_FS_POSIX_ACL
-			info->sb->s_flags |= MS_POSIXACL;
+			info->sb->s_flags |= SB_POSIXACL;
 			break;
 #else
 			btrfs_err(info, "support for ACL not compiled in!");
@@ -624,7 +624,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 			goto out;
 #endif
 		case Opt_noacl:
-			info->sb->s_flags &= ~MS_POSIXACL;
+			info->sb->s_flags &= ~SB_POSIXACL;
 			break;
 		case Opt_notreelog:
 			btrfs_set_and_info(info, NOTREELOG,
@@ -836,7 +836,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
 	/*
 	 * Extra check for current option against current flag
 	 */
-	if (btrfs_test_opt(info, NOLOGREPLAY) && !(new_flags & MS_RDONLY)) {
+	if (btrfs_test_opt(info, NOLOGREPLAY) && !(new_flags & SB_RDONLY)) {
 		btrfs_err(info,
 			  "nologreplay must be used with ro mount option");
 		ret = -EINVAL;
@@ -1132,9 +1132,9 @@ static int btrfs_fill_super(struct super_block *sb,
 	sb->s_xattr = btrfs_xattr_handlers;
 	sb->s_time_gran = 1;
 #ifdef CONFIG_BTRFS_FS_POSIX_ACL
-	sb->s_flags |= MS_POSIXACL;
+	sb->s_flags |= SB_POSIXACL;
 #endif
-	sb->s_flags |= MS_I_VERSION;
+	sb->s_flags |= SB_I_VERSION;
 	sb->s_iflags |= SB_I_CGROUPWB;
 
 	err = super_setup_bdi(sb);
@@ -1166,7 +1166,7 @@ static int btrfs_fill_super(struct super_block *sb,
 
 	save_mount_options(sb, data);
 	cleancache_init_fs(sb);
-	sb->s_flags |= MS_ACTIVE;
+	sb->s_flags |= SB_ACTIVE;
 	return 0;
 
 fail_close:
@@ -1261,7 +1261,7 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
 		seq_puts(seq, ",flushoncommit");
 	if (btrfs_test_opt(info, DISCARD))
 		seq_puts(seq, ",discard");
-	if (!(info->sb->s_flags & MS_POSIXACL))
+	if (!(info->sb->s_flags & SB_POSIXACL))
 		seq_puts(seq, ",noacl");
 	if (btrfs_test_opt(info, SPACE_CACHE))
 		seq_puts(seq, ",space_cache");
@@ -1390,11 +1390,11 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
 
 	mnt = vfs_kern_mount(&btrfs_fs_type, flags, device_name, newargs);
 	if (PTR_ERR_OR_ZERO(mnt) == -EBUSY) {
-		if (flags & MS_RDONLY) {
-			mnt = vfs_kern_mount(&btrfs_fs_type, flags & ~MS_RDONLY,
+		if (flags & SB_RDONLY) {
+			mnt = vfs_kern_mount(&btrfs_fs_type, flags & ~SB_RDONLY,
 					     device_name, newargs);
 		} else {
-			mnt = vfs_kern_mount(&btrfs_fs_type, flags | MS_RDONLY,
+			mnt = vfs_kern_mount(&btrfs_fs_type, flags | SB_RDONLY,
 					     device_name, newargs);
 			if (IS_ERR(mnt)) {
 				root = ERR_CAST(mnt);
@@ -1546,7 +1546,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
 	u64 subvol_objectid = 0;
 	int error = 0;
 
-	if (!(flags & MS_RDONLY))
+	if (!(flags & SB_RDONLY))
 		mode |= FMODE_WRITE;
 
 	error = btrfs_parse_early_options(data, mode, fs_type,
@@ -1600,13 +1600,13 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
 	if (error)
 		goto error_fs_info;
 
-	if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
+	if (!(flags & SB_RDONLY) && fs_devices->rw_devices == 0) {
 		error = -EACCES;
 		goto error_close_devices;
 	}
 
 	bdev = fs_devices->latest_bdev;
-	s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | MS_NOSEC,
+	s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | SB_NOSEC,
 		 fs_info);
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
@@ -1616,7 +1616,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
 	if (s->s_root) {
 		btrfs_close_devices(fs_devices);
 		free_fs_info(fs_info);
-		if ((flags ^ s->s_flags) & MS_RDONLY)
+		if ((flags ^ s->s_flags) & SB_RDONLY)
 			error = -EBUSY;
 	} else {
 		snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
@@ -1683,11 +1683,11 @@ static inline void btrfs_remount_begin(struct btrfs_fs_info *fs_info,
 {
 	if (btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) &&
 	    (!btrfs_raw_test_opt(fs_info->mount_opt, AUTO_DEFRAG) ||
-	     (flags & MS_RDONLY))) {
+	     (flags & SB_RDONLY))) {
 		/* wait for any defraggers to finish */
 		wait_event(fs_info->transaction_wait,
 			   (atomic_read(&fs_info->defrag_running) == 0));
-		if (flags & MS_RDONLY)
+		if (flags & SB_RDONLY)
 			sync_filesystem(fs_info->sb);
 	}
 }
@@ -1701,7 +1701,7 @@ static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info,
 	 */
 	if (btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) &&
 	    (!btrfs_raw_test_opt(fs_info->mount_opt, AUTO_DEFRAG) ||
-	     (fs_info->sb->s_flags & MS_RDONLY))) {
+	     (fs_info->sb->s_flags & SB_RDONLY))) {
 		btrfs_cleanup_defrag_inodes(fs_info);
 	}
 
@@ -1749,10 +1749,10 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 	btrfs_resize_thread_pool(fs_info,
 		fs_info->thread_pool_size, old_thread_pool_size);
 
-	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+	if ((*flags & SB_RDONLY) == (sb->s_flags & SB_RDONLY))
 		goto out;
 
-	if (*flags & MS_RDONLY) {
+	if (*flags & SB_RDONLY) {
 		/*
 		 * this also happens on 'umount -rf' or on shutdown, when
 		 * the filesystem is busy.
@@ -1764,10 +1764,10 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 		/* avoid complains from lockdep et al. */
 		up(&fs_info->uuid_tree_rescan_sem);
 
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 
 		/*
-		 * Setting MS_RDONLY will put the cleaner thread to
+		 * Setting SB_RDONLY will put the cleaner thread to
 		 * sleep at the next loop if it's already active.
 		 * If it's already asleep, we'll leave unused block
 		 * groups on disk until we're mounted read-write again
@@ -1838,7 +1838,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 				goto restore;
 			}
 		}
-		sb->s_flags &= ~MS_RDONLY;
+		sb->s_flags &= ~SB_RDONLY;
 
 		set_bit(BTRFS_FS_OPEN, &fs_info->flags);
 	}
@@ -1848,9 +1848,9 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 	return 0;
 
 restore:
-	/* We've hit an error - don't reset MS_RDONLY */
-	if (sb->s_flags & MS_RDONLY)
-		old_flags |= MS_RDONLY;
+	/* We've hit an error - don't reset SB_RDONLY */
+	if (sb->s_flags & SB_RDONLY)
+		old_flags |= SB_RDONLY;
 	sb->s_flags = old_flags;
 	fs_info->mount_opt = old_opts;
 	fs_info->compress_type = old_compress_type;
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index 1f157fba8940..194892dbfdb8 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -120,7 +120,7 @@ static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
 	if (!fs_info)
 		return -EPERM;
 
-	if (fs_info->sb->s_flags & MS_RDONLY)
+	if (fs_info->sb->s_flags & SB_RDONLY)
 		return -EROFS;
 
 	ret = kstrtoul(skip_spaces(buf), 0, &val);
@@ -388,7 +388,7 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
 	if (!fs_info)
 		return -EPERM;
 
-	if (fs_info->sb->s_flags & MS_RDONLY)
+	if (fs_info->sb->s_flags & SB_RDONLY)
 		return -EROFS;
 
 	/*
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 017b67daa3bb..045d34cab15a 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2327,7 +2327,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
 	int seeding_dev = 0;
 	int ret = 0;
 
-	if ((sb->s_flags & MS_RDONLY) && !fs_info->fs_devices->seeding)
+	if ((sb->s_flags & SB_RDONLY) && !fs_info->fs_devices->seeding)
 		return -EROFS;
 
 	bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,
@@ -2399,7 +2399,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
 	set_blocksize(device->bdev, 4096);
 
 	if (seeding_dev) {
-		sb->s_flags &= ~MS_RDONLY;
+		sb->s_flags &= ~SB_RDONLY;
 		ret = btrfs_prepare_sprout(fs_info);
 		BUG_ON(ret); /* -ENOMEM */
 	}
@@ -4075,7 +4075,7 @@ int btrfs_pause_balance(struct btrfs_fs_info *fs_info)
 
 int btrfs_cancel_balance(struct btrfs_fs_info *fs_info)
 {
-	if (fs_info->sb->s_flags & MS_RDONLY)
+	if (fs_info->sb->s_flags & SB_RDONLY)
 		return -EROFS;
 
 	mutex_lock(&fs_info->balance_mutex);
diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c
index 3ff867f87d73..fa963396063a 100644
--- a/fs/cachefiles/bind.c
+++ b/fs/cachefiles/bind.c
@@ -133,7 +133,7 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
 		goto error_unsupported;
 
 	ret = -EROFS;
-	if (root->d_sb->s_flags & MS_RDONLY)
+	if (root->d_sb->s_flags & SB_RDONLY)
 		goto error_unsupported;
 
 	/* determine the security of the on-disk cache as this governs
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index 8d7918ce694a..7b45cb7e8e48 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -299,11 +299,11 @@ static int parse_fsopt_token(char *c, void *private)
 		break;
 #ifdef CONFIG_CEPH_FS_POSIX_ACL
 	case Opt_acl:
-		fsopt->sb_flags |= MS_POSIXACL;
+		fsopt->sb_flags |= SB_POSIXACL;
 		break;
 #endif
 	case Opt_noacl:
-		fsopt->sb_flags &= ~MS_POSIXACL;
+		fsopt->sb_flags &= ~SB_POSIXACL;
 		break;
 	default:
 		BUG_ON(token);
@@ -481,7 +481,7 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
 		seq_puts(m, ",nopoolperm");
 
 #ifdef CONFIG_CEPH_FS_POSIX_ACL
-	if (fsopt->sb_flags & MS_POSIXACL)
+	if (fsopt->sb_flags & SB_POSIXACL)
 		seq_puts(m, ",acl");
 	else
 		seq_puts(m, ",noacl");
@@ -966,7 +966,7 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
 	dout("ceph_mount\n");
 
 #ifdef CONFIG_CEPH_FS_POSIX_ACL
-	flags |= MS_POSIXACL;
+	flags |= SB_POSIXACL;
 #endif
 	err = parse_mount_options(&fsopt, &opt, flags, data, dev_name);
 	if (err < 0) {
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index cbd216b57239..350fa55a1bf7 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -42,7 +42,7 @@
 #define CIFS_MOUNT_MULTIUSER	0x20000 /* multiuser mount */
 #define CIFS_MOUNT_STRICT_IO	0x40000 /* strict cache mode */
 #define CIFS_MOUNT_RWPIDFORWARD	0x80000 /* use pid forwarding for rw */
-#define CIFS_MOUNT_POSIXACL	0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */
+#define CIFS_MOUNT_POSIXACL	0x100000 /* mirror of SB_POSIXACL in mnt_cifs_flags */
 #define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
 #define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
 #define CIFS_MOUNT_MAP_SFM_CHR	0x800000 /* SFM/MAC mapping for illegal chars */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 9a1667e0e8d6..da6ab2b63d59 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -127,7 +127,7 @@ cifs_read_super(struct super_block *sb)
 	tcon = cifs_sb_master_tcon(cifs_sb);
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
-		sb->s_flags |= MS_POSIXACL;
+		sb->s_flags |= SB_POSIXACL;
 
 	if (tcon->ses->capabilities & tcon->ses->server->vals->cap_large_files)
 		sb->s_maxbytes = MAX_LFS_FILESIZE;
@@ -498,7 +498,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
 		seq_puts(s, ",cifsacl");
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
 		seq_puts(s, ",dynperm");
-	if (root->d_sb->s_flags & MS_POSIXACL)
+	if (root->d_sb->s_flags & SB_POSIXACL)
 		seq_puts(s, ",acl");
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
 		seq_puts(s, ",mfsymlinks");
@@ -574,7 +574,7 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root)
 static int cifs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_NODIRATIME;
+	*flags |= SB_NODIRATIME;
 	return 0;
 }
 
@@ -709,7 +709,7 @@ cifs_do_mount(struct file_system_type *fs_type,
 
 	rc = cifs_mount(cifs_sb, volume_info);
 	if (rc) {
-		if (!(flags & MS_SILENT))
+		if (!(flags & SB_SILENT))
 			cifs_dbg(VFS, "cifs_mount failed w/return code = %d\n",
 				 rc);
 		root = ERR_PTR(rc);
@@ -721,7 +721,7 @@ cifs_do_mount(struct file_system_type *fs_type,
 	mnt_data.flags = flags;
 
 	/* BB should we make this contingent on mount parm? */
-	flags |= MS_NODIRATIME | MS_NOATIME;
+	flags |= SB_NODIRATIME | SB_NOATIME;
 
 	sb = sget(fs_type, cifs_match_super, cifs_set_super, flags, &mnt_data);
 	if (IS_ERR(sb)) {
@@ -740,7 +740,7 @@ cifs_do_mount(struct file_system_type *fs_type,
 			goto out_super;
 		}
 
-		sb->s_flags |= MS_ACTIVE;
+		sb->s_flags |= SB_ACTIVE;
 	}
 
 	root = cifs_get_root(volume_info, sb);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index bcc7d9acad64..27b6ad7b4be8 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -557,8 +557,8 @@ struct smb_vol {
 			 CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
 			 CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID)
 
-#define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \
-		      MS_NODEV | MS_SYNCHRONOUS)
+#define CIFS_MS_MASK (SB_RDONLY | SB_MANDLOCK | SB_SYNCHRONOUS | \
+		      SB_NOEXEC | SB_NOSUID | SB_NODEV)
 
 struct cifs_mnt_data {
 	struct cifs_sb_info *cifs_sb;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 4d1fcd76d022..e6c64f4fda26 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -982,7 +982,7 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
 		}
 
 		cifs_fattr_to_inode(inode, fattr);
-		if (sb->s_flags & MS_NOATIME)
+		if (sb->s_flags & SB_NOATIME)
 			inode->i_flags |= S_NOATIME | S_NOCMTIME;
 		if (inode->i_state & I_NEW) {
 			inode->i_ino = hash;
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 3cb5c9e2d4e7..bf5abb951ed1 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -117,7 +117,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
 #ifdef CONFIG_CIFS_POSIX
 		if (!value)
 			goto out;
-		if (sb->s_flags & MS_POSIXACL)
+		if (sb->s_flags & SB_POSIXACL)
 			rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
 				value, (const int)size,
 				ACL_TYPE_ACCESS, cifs_sb->local_nls,
@@ -129,7 +129,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
 #ifdef CONFIG_CIFS_POSIX
 		if (!value)
 			goto out;
-		if (sb->s_flags & MS_POSIXACL)
+		if (sb->s_flags & SB_POSIXACL)
 			rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
 				value, (const int)size,
 				ACL_TYPE_DEFAULT, cifs_sb->local_nls,
@@ -268,7 +268,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
 
 	case XATTR_ACL_ACCESS:
 #ifdef CONFIG_CIFS_POSIX
-		if (sb->s_flags & MS_POSIXACL)
+		if (sb->s_flags & SB_POSIXACL)
 			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 				value, size, ACL_TYPE_ACCESS,
 				cifs_sb->local_nls,
@@ -278,7 +278,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
 
 	case XATTR_ACL_DEFAULT:
 #ifdef CONFIG_CIFS_POSIX
-		if (sb->s_flags & MS_POSIXACL)
+		if (sb->s_flags & SB_POSIXACL)
 			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 				value, size, ACL_TYPE_DEFAULT,
 				cifs_sb->local_nls,
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 6058df380cc0..3f76eb992070 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -95,7 +95,7 @@ void coda_destroy_inodecache(void)
 static int coda_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_NOATIME;
+	*flags |= SB_NOATIME;
 	return 0;
 }
 
@@ -187,7 +187,7 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
 	mutex_unlock(&vc->vc_mutex);
 
 	sb->s_fs_info = vc;
-	sb->s_flags |= MS_NOATIME;
+	sb->s_flags |= SB_NOATIME;
 	sb->s_blocksize = 4096;	/* XXXXX  what do we put here?? */
 	sb->s_blocksize_bits = 12;
 	sb->s_magic = CODA_SUPER_MAGIC;
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 7919967488cb..af6f7a6bbfbc 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -250,7 +250,7 @@ static void cramfs_kill_sb(struct super_block *sb)
 static int cramfs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_RDONLY;
+	*flags |= SB_RDONLY;
 	return 0;
 }
 
@@ -262,7 +262,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
 	struct cramfs_sb_info *sbi;
 	struct inode *root;
 
-	sb->s_flags |= MS_RDONLY;
+	sb->s_flags |= SB_RDONLY;
 
 	sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
 	if (!sbi)
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 9014479d0160..02430f2175dc 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -560,17 +560,17 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
 	 * Set the POSIX ACL flag based on whether they're enabled in the lower
 	 * mount.
 	 */
-	s->s_flags = flags & ~MS_POSIXACL;
-	s->s_flags |= path.dentry->d_sb->s_flags & MS_POSIXACL;
+	s->s_flags = flags & ~SB_POSIXACL;
+	s->s_flags |= path.dentry->d_sb->s_flags & SB_POSIXACL;
 
 	/**
 	 * Force a read-only eCryptfs mount when:
 	 *   1) The lower mount is ro
 	 *   2) The ecryptfs_encrypted_view mount option is specified
 	 */
-	if (path.dentry->d_sb->s_flags & MS_RDONLY ||
+	if (path.dentry->d_sb->s_flags & SB_RDONLY ||
 	    mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED)
-		s->s_flags |= MS_RDONLY;
+		s->s_flags |= SB_RDONLY;
 
 	s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
 	s->s_blocksize = path.dentry->d_sb->s_blocksize;
@@ -603,7 +603,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
 	ecryptfs_set_dentry_private(s->s_root, root_info);
 	root_info->lower_path = path;
 
-	s->s_flags |= MS_ACTIVE;
+	s->s_flags |= SB_ACTIVE;
 	return dget(s->s_root);
 
 out_free:
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 368f7dd21c61..3e74c3f59fec 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -115,7 +115,7 @@ static void destroy_inodecache(void)
 static int efs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_RDONLY;
+	*flags |= SB_RDONLY;
 	return 0;
 }
 
@@ -306,11 +306,11 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
 	}
 	brelse(bh);
 
-	if (!(s->s_flags & MS_RDONLY)) {
+	if (!(s->s_flags & SB_RDONLY)) {
 #ifdef DEBUG
 		pr_info("forcing read-only mode\n");
 #endif
-		s->s_flags |= MS_RDONLY;
+		s->s_flags |= SB_RDONLY;
 	}
 	s->s_op   = &efs_superblock_operations;
 	s->s_export_op = &efs_export_ops;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index d0bdb74f0e15..69df6f4a80d3 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -547,7 +547,7 @@ void ext2_free_blocks (struct inode * inode, unsigned long block,
 	}
 
 	mark_buffer_dirty(bitmap_bh);
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		sync_dirty_buffer(bitmap_bh);
 
 	group_adjust_blocks(sb, block_group, desc, bh2, group_freed);
@@ -1423,7 +1423,7 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal,
 	percpu_counter_sub(&sbi->s_freeblocks_counter, num);
 
 	mark_buffer_dirty(bitmap_bh);
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		sync_dirty_buffer(bitmap_bh);
 
 	*errp = 0;
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 395fc074c0db..7e9ea9ae2ae9 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -144,7 +144,7 @@ void ext2_free_inode (struct inode * inode)
 	else
 		ext2_release_inode(sb, block_group, is_directory);
 	mark_buffer_dirty(bitmap_bh);
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		sync_dirty_buffer(bitmap_bh);
 
 	brelse(bitmap_bh);
@@ -516,7 +516,7 @@ struct inode *ext2_new_inode(struct inode *dir, umode_t mode,
 	goto fail;
 got:
 	mark_buffer_dirty(bitmap_bh);
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		sync_dirty_buffer(bitmap_bh);
 	brelse(bitmap_bh);
 
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 9c2028b50e5c..d8dea9ad7b94 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -52,7 +52,7 @@ void ext2_error(struct super_block *sb, const char *function,
 	struct ext2_sb_info *sbi = EXT2_SB(sb);
 	struct ext2_super_block *es = sbi->s_es;
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		spin_lock(&sbi->s_lock);
 		sbi->s_mount_state |= EXT2_ERROR_FS;
 		es->s_state |= cpu_to_le16(EXT2_ERROR_FS);
@@ -75,7 +75,7 @@ void ext2_error(struct super_block *sb, const char *function,
 	if (test_opt(sb, ERRORS_RO)) {
 		ext2_msg(sb, KERN_CRIT,
 			     "error: remounting filesystem read-only");
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
 }
 
@@ -151,7 +151,7 @@ static void ext2_put_super (struct super_block * sb)
 		ext2_xattr_destroy_cache(sbi->s_mb_cache);
 		sbi->s_mb_cache = NULL;
 	}
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		struct ext2_super_block *es = sbi->s_es;
 
 		spin_lock(&sbi->s_lock);
@@ -655,7 +655,7 @@ static int ext2_setup_super (struct super_block * sb,
 		ext2_msg(sb, KERN_ERR,
 			"error: revision level too high, "
 			"forcing read-only mode");
-		res = MS_RDONLY;
+		res = SB_RDONLY;
 	}
 	if (read_only)
 		return res;
@@ -916,9 +916,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 	if (!parse_options((char *) data, sb))
 		goto failed_mount;
 
-	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
 		((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
-		 MS_POSIXACL : 0);
+		 SB_POSIXACL : 0);
 	sb->s_iflags |= SB_I_CGROUPWB;
 
 	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
@@ -940,7 +940,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 			le32_to_cpu(features));
 		goto failed_mount;
 	}
-	if (!(sb->s_flags & MS_RDONLY) &&
+	if (!(sb->s_flags & SB_RDONLY) &&
 	    (features = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){
 		ext2_msg(sb, KERN_ERR, "error: couldn't mount RDWR because of "
 		       "unsupported optional features (%x)",
@@ -1170,8 +1170,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 	if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
 		ext2_msg(sb, KERN_WARNING,
 			"warning: mounting ext3 filesystem as ext2");
-	if (ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY))
-		sb->s_flags |= MS_RDONLY;
+	if (ext2_setup_super (sb, es, sb->s_flags & SB_RDONLY))
+		sb->s_flags |= SB_RDONLY;
 	ext2_write_super(sb);
 	return 0;
 
@@ -1301,7 +1301,7 @@ static int ext2_unfreeze(struct super_block *sb)
 
 static void ext2_write_super(struct super_block *sb)
 {
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		ext2_sync_fs(sb, 1);
 }
 
@@ -1330,8 +1330,8 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
 		goto restore_opts;
 	}
 
-	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
-		((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
+		((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? SB_POSIXACL : 0);
 
 	es = sbi->s_es;
 	if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT2_MOUNT_DAX) {
@@ -1339,11 +1339,11 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
 			 "dax flag with busy inodes while remounting");
 		sbi->s_mount_opt ^= EXT2_MOUNT_DAX;
 	}
-	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {
+	if ((*flags & SB_RDONLY) == (sb->s_flags & SB_RDONLY)) {
 		spin_unlock(&sbi->s_lock);
 		return 0;
 	}
-	if (*flags & MS_RDONLY) {
+	if (*flags & SB_RDONLY) {
 		if (le16_to_cpu(es->s_state) & EXT2_VALID_FS ||
 		    !(sbi->s_mount_state & EXT2_VALID_FS)) {
 			spin_unlock(&sbi->s_lock);
@@ -1383,7 +1383,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
 		 */
 		sbi->s_mount_state = le16_to_cpu(es->s_state);
 		if (!ext2_setup_super (sb, es, 0))
-			sb->s_flags &= ~MS_RDONLY;
+			sb->s_flags &= ~SB_RDONLY;
 		spin_unlock(&sbi->s_lock);
 
 		ext2_write_super(sb);
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index dd106b1d5d89..bc0cbfb20d4a 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -47,7 +47,7 @@ static int ext4_journal_check_start(struct super_block *sb)
 	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
 		return -EIO;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return -EROFS;
 	WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
 	journal = EXT4_SB(sb)->s_journal;
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 831fd6beebf0..94e266ab885d 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -376,7 +376,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
 		return -EIO;
 
 	if (unlikely(!(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED) &&
-		     !(sb->s_flags & MS_RDONLY))) {
+		     !(sb->s_flags & SB_RDONLY))) {
 		sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED;
 		/*
 		 * Sample where the filesystem has been mounted and
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index 9d549608fd30..5a0b81a1d070 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -107,7 +107,7 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 
 	trace_ext4_sync_file_enter(file, datasync);
 
-	if (inode->i_sb->s_flags & MS_RDONLY) {
+	if (inode->i_sb->s_flags & SB_RDONLY) {
 		/* Make sure that we read updated s_mount_flags value */
 		smp_rmb();
 		if (EXT4_SB(inode->i_sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 98ac2f1f23b3..9e5251d6f5db 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -1313,7 +1313,7 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
 	int num, ret = 0, used_blks = 0;
 
 	/* This should not happen, but just to be sure check this */
-	if (sb->s_flags & MS_RDONLY) {
+	if (sb->s_flags & SB_RDONLY) {
 		ret = 1;
 		goto out;
 	}
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 1bd0bfa547f6..ba6dd151ba9c 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2694,7 +2694,7 @@ static int ext4_writepages(struct address_space *mapping,
 	 * If the filesystem has aborted, it is read-only, so return
 	 * right away instead of dumping stack traces later on that
 	 * will obscure the real source of the problem.  We test
-	 * EXT4_MF_FS_ABORTED instead of sb->s_flag's MS_RDONLY because
+	 * EXT4_MF_FS_ABORTED instead of sb->s_flag's SB_RDONLY because
 	 * the latter could be true if the filesystem is mounted
 	 * read-only, and in that case, ext4_writepages should
 	 * *never* be called, so if that ever happens, we would want
@@ -5071,7 +5071,7 @@ static int ext4_do_update_inode(handle_t *handle,
 
 	ext4_inode_csum_set(inode, raw_inode, ei);
 	spin_unlock(&ei->i_raw_lock);
-	if (inode->i_sb->s_flags & MS_LAZYTIME)
+	if (inode->i_sb->s_flags & SB_LAZYTIME)
 		ext4_update_other_inodes_time(inode->i_sb, inode->i_ino,
 					      bh->b_data);
 
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c
index eb9835638680..1f29d9473b5a 100644
--- a/fs/ext4/mmp.c
+++ b/fs/ext4/mmp.c
@@ -185,7 +185,7 @@ static int kmmpd(void *data)
 			goto exit_thread;
 		}
 
-		if (sb->s_flags & MS_RDONLY) {
+		if (sb->s_flags & SB_RDONLY) {
 			ext4_warning(sb, "kmmpd being stopped since filesystem "
 				     "has been remounted as readonly.");
 			goto exit_thread;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 0b177da9ea82..fdf0c5700004 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -402,7 +402,7 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
 
 static void ext4_handle_error(struct super_block *sb)
 {
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return;
 
 	if (!test_opt(sb, ERRORS_CONT)) {
@@ -419,7 +419,7 @@ static void ext4_handle_error(struct super_block *sb)
 		 * before ->s_flags update
 		 */
 		smp_wmb();
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
 	if (test_opt(sb, ERRORS_PANIC)) {
 		if (EXT4_SB(sb)->s_journal &&
@@ -585,7 +585,7 @@ void __ext4_std_error(struct super_block *sb, const char *function,
 	 * inside a transaction, then there's really no point in logging
 	 * an error. */
 	if (errno == -EROFS && journal_current_handle() == NULL &&
-	    (sb->s_flags & MS_RDONLY))
+	    (sb->s_flags & SB_RDONLY))
 		return;
 
 	if (ext4_error_ratelimit(sb)) {
@@ -625,7 +625,7 @@ void __ext4_abort(struct super_block *sb, const char *function,
 	       sb->s_id, function, line, &vaf);
 	va_end(args);
 
-	if ((sb->s_flags & MS_RDONLY) == 0) {
+	if ((sb->s_flags & SB_RDONLY) == 0) {
 		ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
 		EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
 		/*
@@ -633,7 +633,7 @@ void __ext4_abort(struct super_block *sb, const char *function,
 		 * before ->s_flags update
 		 */
 		smp_wmb();
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		if (EXT4_SB(sb)->s_journal)
 			jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
 		save_error_info(sb, function, line);
@@ -891,11 +891,11 @@ static void ext4_put_super(struct super_block *sb)
 	ext4_mb_release(sb);
 	ext4_ext_release(sb);
 
-	if (!(sb->s_flags & MS_RDONLY) && !aborted) {
+	if (!(sb->s_flags & SB_RDONLY) && !aborted) {
 		ext4_clear_feature_journal_needs_recovery(sb);
 		es->s_state = cpu_to_le16(sbi->s_mount_state);
 	}
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		ext4_commit_super(sb, 1);
 
 	for (i = 0; i < sbi->s_gdb_count; i++)
@@ -1657,13 +1657,13 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
 		sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
 		return 1;
 	case Opt_i_version:
-		sb->s_flags |= MS_I_VERSION;
+		sb->s_flags |= SB_I_VERSION;
 		return 1;
 	case Opt_lazytime:
-		sb->s_flags |= MS_LAZYTIME;
+		sb->s_flags |= SB_LAZYTIME;
 		return 1;
 	case Opt_nolazytime:
-		sb->s_flags &= ~MS_LAZYTIME;
+		sb->s_flags &= ~SB_LAZYTIME;
 		return 1;
 	}
 
@@ -2040,7 +2040,7 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
 		SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time);
 	if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME)
 		SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time);
-	if (sb->s_flags & MS_I_VERSION)
+	if (sb->s_flags & SB_I_VERSION)
 		SEQ_OPTS_PUTS("i_version");
 	if (nodefs || sbi->s_stripe)
 		SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe);
@@ -2079,7 +2079,7 @@ int ext4_seq_options_show(struct seq_file *seq, void *offset)
 	struct super_block *sb = seq->private;
 	int rc;
 
-	seq_puts(seq, (sb->s_flags & MS_RDONLY) ? "ro" : "rw");
+	seq_puts(seq, (sb->s_flags & SB_RDONLY) ? "ro" : "rw");
 	rc = _ext4_show_options(seq, sb, 1);
 	seq_puts(seq, "\n");
 	return rc;
@@ -2094,7 +2094,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
 	if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) {
 		ext4_msg(sb, KERN_ERR, "revision level too high, "
 			 "forcing read-only mode");
-		res = MS_RDONLY;
+		res = SB_RDONLY;
 	}
 	if (read_only)
 		goto done;
@@ -2347,7 +2347,7 @@ static int ext4_check_descriptors(struct super_block *sb,
 				 "Checksum for group %u failed (%u!=%u)",
 				 i, le16_to_cpu(ext4_group_desc_csum(sb, i,
 				     gdp)), le16_to_cpu(gdp->bg_checksum));
-			if (!(sb->s_flags & MS_RDONLY)) {
+			if (!(sb->s_flags & SB_RDONLY)) {
 				ext4_unlock_group(sb, i);
 				return 0;
 			}
@@ -2406,7 +2406,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
 
 	if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
 		/* don't clear list on RO mount w/ errors */
-		if (es->s_last_orphan && !(s_flags & MS_RDONLY)) {
+		if (es->s_last_orphan && !(s_flags & SB_RDONLY)) {
 			ext4_msg(sb, KERN_INFO, "Errors on filesystem, "
 				  "clearing orphan list.\n");
 			es->s_last_orphan = 0;
@@ -2415,13 +2415,13 @@ static void ext4_orphan_cleanup(struct super_block *sb,
 		return;
 	}
 
-	if (s_flags & MS_RDONLY) {
+	if (s_flags & SB_RDONLY) {
 		ext4_msg(sb, KERN_INFO, "orphan cleanup on readonly fs");
-		sb->s_flags &= ~MS_RDONLY;
+		sb->s_flags &= ~SB_RDONLY;
 	}
 #ifdef CONFIG_QUOTA
 	/* Needed for iput() to work correctly and not trash data */
-	sb->s_flags |= MS_ACTIVE;
+	sb->s_flags |= SB_ACTIVE;
 	/* Turn on quotas so that they are updated correctly */
 	for (i = 0; i < EXT4_MAXQUOTAS; i++) {
 		if (EXT4_SB(sb)->s_qf_names[i]) {
@@ -2496,7 +2496,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
 			dquot_quota_off(sb, i);
 	}
 #endif
-	sb->s_flags = s_flags; /* Restore MS_RDONLY status */
+	sb->s_flags = s_flags; /* Restore SB_RDONLY status */
 }
 
 /*
@@ -2698,7 +2698,7 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
 
 	if (ext4_has_feature_readonly(sb)) {
 		ext4_msg(sb, KERN_INFO, "filesystem is read-only");
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		return 1;
 	}
 
@@ -3095,7 +3095,7 @@ int ext4_register_li_request(struct super_block *sb,
 	}
 
 	if (first_not_zeroed == ngroups ||
-	    (sb->s_flags & MS_RDONLY) ||
+	    (sb->s_flags & SB_RDONLY) ||
 	    !test_opt(sb, INIT_INODE_TABLE))
 		goto out;
 
@@ -3581,8 +3581,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 		sb->s_iflags |= SB_I_CGROUPWB;
 	}
 
-	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
-		(test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
+	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
+		(test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0);
 
 	if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
 	    (ext4_has_compat_features(sb) ||
@@ -3628,7 +3628,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 	 * previously didn't change the revision level when setting the flags,
 	 * so there is a chance incompat flags are set on a rev 0 filesystem.
 	 */
-	if (!ext4_feature_set_ok(sb, (sb->s_flags & MS_RDONLY)))
+	if (!ext4_feature_set_ok(sb, (sb->s_flags & SB_RDONLY)))
 		goto failed_mount;
 
 	blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
@@ -3757,12 +3757,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 			sbi->s_hash_unsigned = 3;
 		else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
 #ifdef __CHAR_UNSIGNED__
-			if (!(sb->s_flags & MS_RDONLY))
+			if (!(sb->s_flags & SB_RDONLY))
 				es->s_flags |=
 					cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
 			sbi->s_hash_unsigned = 3;
 #else
-			if (!(sb->s_flags & MS_RDONLY))
+			if (!(sb->s_flags & SB_RDONLY))
 				es->s_flags |=
 					cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
 #endif
@@ -3962,7 +3962,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 	needs_recovery = (es->s_last_orphan != 0 ||
 			  ext4_has_feature_journal_needs_recovery(sb));
 
-	if (ext4_has_feature_mmp(sb) && !(sb->s_flags & MS_RDONLY))
+	if (ext4_has_feature_mmp(sb) && !(sb->s_flags & SB_RDONLY))
 		if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
 			goto failed_mount3a;
 
@@ -3974,7 +3974,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 		err = ext4_load_journal(sb, es, journal_devnum);
 		if (err)
 			goto failed_mount3a;
-	} else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
+	} else if (test_opt(sb, NOLOAD) && !(sb->s_flags & SB_RDONLY) &&
 		   ext4_has_feature_journal_needs_recovery(sb)) {
 		ext4_msg(sb, KERN_ERR, "required journal recovery "
 		       "suppressed and not mounted read-only");
@@ -4076,7 +4076,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 		goto failed_mount_wq;
 	}
 
-	if (DUMMY_ENCRYPTION_ENABLED(sbi) && !(sb->s_flags & MS_RDONLY) &&
+	if (DUMMY_ENCRYPTION_ENABLED(sbi) && !(sb->s_flags & SB_RDONLY) &&
 	    !ext4_has_feature_encrypt(sb)) {
 		ext4_set_feature_encrypt(sb);
 		ext4_commit_super(sb, 1);
@@ -4130,8 +4130,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 		goto failed_mount4;
 	}
 
-	if (ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY))
-		sb->s_flags |= MS_RDONLY;
+	if (ext4_setup_super(sb, es, sb->s_flags & SB_RDONLY))
+		sb->s_flags |= SB_RDONLY;
 
 	/* determine the minimum size of new large inodes, if present */
 	if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE &&
@@ -4218,7 +4218,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 
 #ifdef CONFIG_QUOTA
 	/* Enable quota usage during mount. */
-	if (ext4_has_feature_quota(sb) && !(sb->s_flags & MS_RDONLY)) {
+	if (ext4_has_feature_quota(sb) && !(sb->s_flags & SB_RDONLY)) {
 		err = ext4_enable_quotas(sb);
 		if (err)
 			goto failed_mount8;
@@ -4537,7 +4537,7 @@ static int ext4_load_journal(struct super_block *sb,
 	 * can get read-write access to the device.
 	 */
 	if (ext4_has_feature_journal_needs_recovery(sb)) {
-		if (sb->s_flags & MS_RDONLY) {
+		if (sb->s_flags & SB_RDONLY) {
 			ext4_msg(sb, KERN_INFO, "INFO: recovery "
 					"required on readonly filesystem");
 			if (really_read_only) {
@@ -4619,7 +4619,7 @@ static int ext4_commit_super(struct super_block *sb, int sync)
 	 * the clock is set in the future, and this will cause e2fsck
 	 * to complain and force a full file system check.
 	 */
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		es->s_wtime = cpu_to_le32(get_seconds());
 	if (sb->s_bdev->bd_part)
 		es->s_kbytes_written =
@@ -4693,7 +4693,7 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
 		goto out;
 
 	if (ext4_has_feature_journal_needs_recovery(sb) &&
-	    sb->s_flags & MS_RDONLY) {
+	    sb->s_flags & SB_RDONLY) {
 		ext4_clear_feature_journal_needs_recovery(sb);
 		ext4_commit_super(sb, 1);
 	}
@@ -4749,7 +4749,7 @@ int ext4_force_commit(struct super_block *sb)
 {
 	journal_t *journal;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return 0;
 
 	journal = EXT4_SB(sb)->s_journal;
@@ -4814,7 +4814,7 @@ static int ext4_freeze(struct super_block *sb)
 	int error = 0;
 	journal_t *journal;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return 0;
 
 	journal = EXT4_SB(sb)->s_journal;
@@ -4849,7 +4849,7 @@ static int ext4_freeze(struct super_block *sb)
  */
 static int ext4_unfreeze(struct super_block *sb)
 {
-	if ((sb->s_flags & MS_RDONLY) || ext4_forced_shutdown(EXT4_SB(sb)))
+	if ((sb->s_flags & SB_RDONLY) || ext4_forced_shutdown(EXT4_SB(sb)))
 		return 0;
 
 	if (EXT4_SB(sb)->s_journal) {
@@ -4968,8 +4968,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 	if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
 		ext4_abort(sb, "Abort forced by user");
 
-	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
-		(test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
+	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
+		(test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0);
 
 	es = sbi->s_es;
 
@@ -4978,16 +4978,16 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 		set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 	}
 
-	if (*flags & MS_LAZYTIME)
-		sb->s_flags |= MS_LAZYTIME;
+	if (*flags & SB_LAZYTIME)
+		sb->s_flags |= SB_LAZYTIME;
 
-	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
+	if ((*flags & SB_RDONLY) != (sb->s_flags & SB_RDONLY)) {
 		if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) {
 			err = -EROFS;
 			goto restore_opts;
 		}
 
-		if (*flags & MS_RDONLY) {
+		if (*flags & SB_RDONLY) {
 			err = sync_filesystem(sb);
 			if (err < 0)
 				goto restore_opts;
@@ -4999,7 +4999,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 			 * First of all, the unconditional stuff we have to do
 			 * to disable replay of the journal when we next remount
 			 */
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 
 			/*
 			 * OK, test if we are remounting a valid rw partition
@@ -5061,7 +5061,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 				ext4_clear_journal_err(sb, es);
 			sbi->s_mount_state = le16_to_cpu(es->s_state);
 			if (!ext4_setup_super(sb, es, 0))
-				sb->s_flags &= ~MS_RDONLY;
+				sb->s_flags &= ~SB_RDONLY;
 			if (ext4_has_feature_mmp(sb))
 				if (ext4_multi_mount_protect(sb,
 						le64_to_cpu(es->s_mmp_block))) {
@@ -5076,7 +5076,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 	 * Reinitialize lazy itable initialization thread based on
 	 * current settings
 	 */
-	if ((sb->s_flags & MS_RDONLY) || !test_opt(sb, INIT_INODE_TABLE))
+	if ((sb->s_flags & SB_RDONLY) || !test_opt(sb, INIT_INODE_TABLE))
 		ext4_unregister_li_request(sb);
 	else {
 		ext4_group_t first_not_zeroed;
@@ -5085,7 +5085,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 	}
 
 	ext4_setup_system_zone(sb);
-	if (sbi->s_journal == NULL && !(old_sb_flags & MS_RDONLY))
+	if (sbi->s_journal == NULL && !(old_sb_flags & SB_RDONLY))
 		ext4_commit_super(sb, 1);
 
 #ifdef CONFIG_QUOTA
@@ -5103,7 +5103,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 	}
 #endif
 
-	*flags = (*flags & ~MS_LAZYTIME) | (sb->s_flags & MS_LAZYTIME);
+	*flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
 	ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data);
 	kfree(orig_data);
 	return 0;
@@ -5647,7 +5647,7 @@ static inline int ext2_feature_set_ok(struct super_block *sb)
 {
 	if (ext4_has_unknown_ext2_incompat_features(sb))
 		return 0;
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return 1;
 	if (ext4_has_unknown_ext2_ro_compat_features(sb))
 		return 0;
@@ -5678,7 +5678,7 @@ static inline int ext3_feature_set_ok(struct super_block *sb)
 		return 0;
 	if (!ext4_has_feature_journal(sb))
 		return 0;
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return 1;
 	if (ext4_has_unknown_ext3_ro_compat_features(sb))
 		return 0;
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index ea9c317b5916..d1d7abed8977 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -29,7 +29,7 @@ struct kmem_cache *inode_entry_slab;
 void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
 {
 	set_ckpt_flags(sbi, CP_ERROR_FLAG);
-	sbi->sb->s_flags |= MS_RDONLY;
+	sbi->sb->s_flags |= SB_RDONLY;
 	if (!end_io)
 		f2fs_flush_merged_bios(sbi);
 }
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 2185c7a040a1..2dc9a03ffab6 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -2031,7 +2031,7 @@ static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync)
 
 static inline int f2fs_readonly(struct super_block *sb)
 {
-	return sb->s_flags & MS_RDONLY;
+	return sb->s_flags & SB_RDONLY;
 }
 
 static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 026522107ca3..4789c854e1b7 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -965,7 +965,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
 
 	cpc.reason = __get_cp_reason(sbi);
 gc_more:
-	if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE)))
+	if (unlikely(!(sbi->sb->s_flags & SB_ACTIVE)))
 		goto stop;
 	if (unlikely(f2fs_cp_error(sbi))) {
 		ret = -EIO;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 83355ec4a92c..7feaccbd7b35 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -580,10 +580,10 @@ static int parse_options(struct super_block *sb, char *options)
 #endif
 			break;
 		case Opt_lazytime:
-			sb->s_flags |= MS_LAZYTIME;
+			sb->s_flags |= SB_LAZYTIME;
 			break;
 		case Opt_nolazytime:
-			sb->s_flags &= ~MS_LAZYTIME;
+			sb->s_flags &= ~SB_LAZYTIME;
 			break;
 		default:
 			f2fs_msg(sb, KERN_ERR,
@@ -1064,7 +1064,7 @@ static void default_options(struct f2fs_sb_info *sbi)
 	set_opt(sbi, INLINE_DENTRY);
 	set_opt(sbi, EXTENT_CACHE);
 	set_opt(sbi, NOHEAP);
-	sbi->sb->s_flags |= MS_LAZYTIME;
+	sbi->sb->s_flags |= SB_LAZYTIME;
 	set_opt(sbi, FLUSH_MERGE);
 	if (f2fs_sb_mounted_blkzoned(sbi->sb)) {
 		set_opt_mode(sbi, F2FS_MOUNT_LFS);
@@ -1105,7 +1105,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
 	active_logs = sbi->active_logs;
 
 	/* recover superblocks we couldn't write due to previous RO mount */
-	if (!(*flags & MS_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) {
+	if (!(*flags & SB_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) {
 		err = f2fs_commit_super(sbi, false);
 		f2fs_msg(sb, KERN_INFO,
 			"Try to recover all the superblocks, ret: %d", err);
@@ -1125,7 +1125,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
 	 * Previous and new state of filesystem is RO,
 	 * so skip checking GC and FLUSH_MERGE conditions.
 	 */
-	if (f2fs_readonly(sb) && (*flags & MS_RDONLY))
+	if (f2fs_readonly(sb) && (*flags & SB_RDONLY))
 		goto skip;
 
 	/* disallow enable/disable extent_cache dynamically */
@@ -1141,7 +1141,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
 	 * or if background_gc = off is passed in mount
 	 * option. Also sync the filesystem.
 	 */
-	if ((*flags & MS_RDONLY) || !test_opt(sbi, BG_GC)) {
+	if ((*flags & SB_RDONLY) || !test_opt(sbi, BG_GC)) {
 		if (sbi->gc_thread) {
 			stop_gc_thread(sbi);
 			need_restart_gc = true;
@@ -1153,7 +1153,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
 		need_stop_gc = true;
 	}
 
-	if (*flags & MS_RDONLY) {
+	if (*flags & SB_RDONLY) {
 		writeback_inodes_sb(sb, WB_REASON_SYNC);
 		sync_inodes_sb(sb);
 
@@ -1167,7 +1167,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
 	 * We stop issue flush thread if FS is mounted as RO
 	 * or if flush_merge is not passed in mount option.
 	 */
-	if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
+	if ((*flags & SB_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
 		clear_opt(sbi, FLUSH_MERGE);
 		destroy_flush_cmd_control(sbi, false);
 	} else {
@@ -1177,8 +1177,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
 	}
 skip:
 	/* Update the POSIXACL Flag */
-	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
-		(test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
+	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
+		(test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
 
 	return 0;
 restore_gc:
@@ -1935,8 +1935,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_export_op = &f2fs_export_ops;
 	sb->s_magic = F2FS_SUPER_MAGIC;
 	sb->s_time_gran = 1;
-	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
-		(test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
+	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
+		(test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
 	memcpy(sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
 
 	/* init f2fs-specific super block info */
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index 1d9a8c4e9de0..a47d09d675ef 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -309,7 +309,7 @@ static void mark_fsinfo_dirty(struct super_block *sb)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
-	if (sb->s_flags & MS_RDONLY || sbi->fat_bits != 32)
+	if (sb->s_flags & SB_RDONLY || sbi->fat_bits != 32)
 		return;
 
 	__mark_inode_dirty(sbi->fsinfo_inode, I_DIRTY_SYNC);
@@ -392,7 +392,7 @@ static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs,
 			memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize);
 			set_buffer_uptodate(c_bh);
 			mark_buffer_dirty_inode(c_bh, sbi->fat_inode);
-			if (sb->s_flags & MS_SYNCHRONOUS)
+			if (sb->s_flags & SB_SYNCHRONOUS)
 				err = sync_dirty_buffer(c_bh);
 			brelse(c_bh);
 			if (err)
@@ -597,7 +597,7 @@ int fat_free_clusters(struct inode *inode, int cluster)
 		}
 
 		if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) {
-			if (sb->s_flags & MS_SYNCHRONOUS) {
+			if (sb->s_flags & SB_SYNCHRONOUS) {
 				err = fat_sync_bhs(bhs, nr_bhs);
 				if (err)
 					goto error;
@@ -612,7 +612,7 @@ int fat_free_clusters(struct inode *inode, int cluster)
 		fat_collect_bhs(bhs, &nr_bhs, &fatent);
 	} while (cluster != FAT_ENT_EOF);
 
-	if (sb->s_flags & MS_SYNCHRONOUS) {
+	if (sb->s_flags & SB_SYNCHRONOUS) {
 		err = fat_sync_bhs(bhs, nr_bhs);
 		if (err)
 			goto error;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index a2c05f2ada6d..fc3a678731da 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -657,7 +657,7 @@ static void fat_set_state(struct super_block *sb,
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
 	/* do not change any thing if mounted read only */
-	if ((sb->s_flags & MS_RDONLY) && !force)
+	if ((sb->s_flags & SB_RDONLY) && !force)
 		return;
 
 	/* do not change state if fs was dirty */
@@ -781,13 +781,13 @@ static int fat_remount(struct super_block *sb, int *flags, char *data)
 {
 	int new_rdonly;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	*flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME);
+	*flags |= SB_NODIRATIME | (sbi->options.isvfat ? 0 : SB_NOATIME);
 
 	sync_filesystem(sb);
 
 	/* make sure we update state on remount. */
-	new_rdonly = *flags & MS_RDONLY;
-	if (new_rdonly != (sb->s_flags & MS_RDONLY)) {
+	new_rdonly = *flags & SB_RDONLY;
+	if (new_rdonly != (sb->s_flags & SB_RDONLY)) {
 		if (new_rdonly)
 			fat_set_state(sb, 0, 0);
 		else
@@ -1352,7 +1352,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
 	if (opts->unicode_xlate)
 		opts->utf8 = 0;
 	if (opts->nfs == FAT_NFS_NOSTALE_RO) {
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		sb->s_export_op = &fat_export_ops_nostale;
 	}
 
@@ -1608,7 +1608,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 		return -ENOMEM;
 	sb->s_fs_info = sbi;
 
-	sb->s_flags |= MS_NODIRATIME;
+	sb->s_flags |= SB_NODIRATIME;
 	sb->s_magic = MSDOS_SUPER_MAGIC;
 	sb->s_op = &fat_sops;
 	sb->s_export_op = &fat_export_ops;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 8a8698119ff7..869865b2ab7a 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -32,8 +32,8 @@ void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
 
 	if (opts->errors == FAT_ERRORS_PANIC)
 		panic("FAT-fs (%s): fs panic from previous error\n", sb->s_id);
-	else if (opts->errors == FAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) {
-		sb->s_flags |= MS_RDONLY;
+	else if (opts->errors == FAT_ERRORS_RO && !(sb->s_flags & SB_RDONLY)) {
+		sb->s_flags |= SB_RDONLY;
 		fat_msg(sb, KERN_ERR, "Filesystem has been set read-only");
 	}
 }
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index 7d6a105d601b..d24d2758a363 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -646,7 +646,7 @@ static void setup(struct super_block *sb)
 {
 	MSDOS_SB(sb)->dir_ops = &msdos_dir_inode_operations;
 	sb->s_d_op = &msdos_dentry_operations;
-	sb->s_flags |= MS_NOATIME;
+	sb->s_flags |= SB_NOATIME;
 }
 
 static int msdos_fill_super(struct super_block *sb, void *data, int silent)
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index 455ce5b77e9b..f989efa051a0 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -116,7 +116,7 @@ vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
 static int vxfs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_RDONLY;
+	*flags |= SB_RDONLY;
 	return 0;
 }
 
@@ -220,7 +220,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 	int ret = -EINVAL;
 	u32 j;
 
-	sbp->s_flags |= MS_RDONLY;
+	sbp->s_flags |= SB_RDONLY;
 
 	infp = kzalloc(sizeof(*infp), GFP_KERNEL);
 	if (!infp) {
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 63ee2940775c..996171a5891b 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -490,7 +490,7 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
 
 	/* while holding I_WB_SWITCH, no one else can update the association */
 	spin_lock(&inode->i_lock);
-	if (!(inode->i_sb->s_flags & MS_ACTIVE) ||
+	if (!(inode->i_sb->s_flags & SB_ACTIVE) ||
 	    inode->i_state & (I_WB_SWITCH | I_FREEING) ||
 	    inode_to_wb(inode) == isw->new_wb) {
 		spin_unlock(&inode->i_lock);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 65c88379a3a1..642ef1e120c1 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -130,7 +130,7 @@ static void fuse_evict_inode(struct inode *inode)
 {
 	truncate_inode_pages_final(&inode->i_data);
 	clear_inode(inode);
-	if (inode->i_sb->s_flags & MS_ACTIVE) {
+	if (inode->i_sb->s_flags & SB_ACTIVE) {
 		struct fuse_conn *fc = get_fuse_conn(inode);
 		struct fuse_inode *fi = get_fuse_inode(inode);
 		fuse_queue_forget(fc, fi->forget, fi->nodeid, fi->nlookup);
@@ -141,7 +141,7 @@ static void fuse_evict_inode(struct inode *inode)
 static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	if (*flags & MS_MANDLOCK)
+	if (*flags & SB_MANDLOCK)
 		return -EINVAL;
 
 	return 0;
@@ -1056,10 +1056,10 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 	int is_bdev = sb->s_bdev != NULL;
 
 	err = -EINVAL;
-	if (sb->s_flags & MS_MANDLOCK)
+	if (sb->s_flags & SB_MANDLOCK)
 		goto err;
 
-	sb->s_flags &= ~(MS_NOSEC | MS_I_VERSION);
+	sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION);
 
 	if (!parse_fuse_opt(data, &d, is_bdev))
 		goto err;
@@ -1109,9 +1109,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 		goto err_dev_free;
 
 	/* Handle umasking inside the fuse code */
-	if (sb->s_flags & MS_POSIXACL)
+	if (sb->s_flags & SB_POSIXACL)
 		fc->dont_mask = 1;
-	sb->s_flags |= MS_POSIXACL;
+	sb->s_flags |= SB_POSIXACL;
 
 	fc->default_permissions = d.default_permissions;
 	fc->allow_other = d.allow_other;
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 5db59d444838..5a5a7b0038e5 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -544,7 +544,7 @@ static void iopen_go_callback(struct gfs2_glock *gl, bool remote)
 	struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object;
 	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
 
-	if (!remote || (sdp->sd_vfs->s_flags & MS_RDONLY))
+	if (!remote || (sdp->sd_vfs->s_flags & SB_RDONLY))
 		return;
 
 	if (gl->gl_demote_state == LM_ST_UNLOCKED &&
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index ed67548b286c..d74f7d561209 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1037,7 +1037,7 @@ void gfs2_online_uevent(struct gfs2_sbd *sdp)
 	char ro[20];
 	char spectator[20];
 	char *envp[] = { ro, spectator, NULL };
-	sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);
+	sprintf(ro, "RDONLY=%d", (sb->s_flags & SB_RDONLY) ? 1 : 0);
 	sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
 	kobject_uevent_env(&sdp->sd_kobj, KOBJ_ONLINE, envp);
 }
@@ -1065,15 +1065,15 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
 	sdp->sd_args = *args;
 
 	if (sdp->sd_args.ar_spectator) {
-                sb->s_flags |= MS_RDONLY;
+                sb->s_flags |= SB_RDONLY;
 		set_bit(SDF_RORECOVERY, &sdp->sd_flags);
 	}
 	if (sdp->sd_args.ar_posix_acl)
-		sb->s_flags |= MS_POSIXACL;
+		sb->s_flags |= SB_POSIXACL;
 	if (sdp->sd_args.ar_nobarrier)
 		set_bit(SDF_NOBARRIERS, &sdp->sd_flags);
 
-	sb->s_flags |= MS_NOSEC;
+	sb->s_flags |= SB_NOSEC;
 	sb->s_magic = GFS2_MAGIC;
 	sb->s_op = &gfs2_super_ops;
 	sb->s_d_op = &gfs2_dops;
@@ -1179,7 +1179,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
 		goto fail_per_node;
 	}
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		error = gfs2_make_fs_rw(sdp);
 		if (error) {
 			fs_err(sdp, "can't make FS RW: %d\n", error);
@@ -1257,7 +1257,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
 	struct gfs2_args args;
 	struct gfs2_sbd *sdp;
 
-	if (!(flags & MS_RDONLY))
+	if (!(flags & SB_RDONLY))
 		mode |= FMODE_WRITE;
 
 	bdev = blkdev_get_by_path(dev_name, mode, fs_type);
@@ -1313,15 +1313,15 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
 
 	if (s->s_root) {
 		error = -EBUSY;
-		if ((flags ^ s->s_flags) & MS_RDONLY)
+		if ((flags ^ s->s_flags) & SB_RDONLY)
 			goto error_super;
 	} else {
 		snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
 		sb_set_blocksize(s, block_size(bdev));
-		error = fill_super(s, &args, flags & MS_SILENT ? 1 : 0);
+		error = fill_super(s, &args, flags & SB_SILENT ? 1 : 0);
 		if (error)
 			goto error_super;
-		s->s_flags |= MS_ACTIVE;
+		s->s_flags |= SB_ACTIVE;
 		bdev->bd_super = s;
 	}
 
@@ -1365,7 +1365,7 @@ static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type,
 		pr_warn("gfs2 mount does not exist\n");
 		return ERR_CAST(s);
 	}
-	if ((flags ^ s->s_flags) & MS_RDONLY) {
+	if ((flags ^ s->s_flags) & SB_RDONLY) {
 		deactivate_locked_super(s);
 		return ERR_PTR(-EBUSY);
 	}
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index c2ca9566b764..83377410b00f 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -452,7 +452,7 @@ static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp)
 
 	*qdp = NULL;
 
-	if (sdp->sd_vfs->s_flags & MS_RDONLY)
+	if (sdp->sd_vfs->s_flags & SB_RDONLY)
 		return 0;
 
 	spin_lock(&qd_lock);
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index 113b6095a58d..1d65930fd3bc 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -522,7 +522,7 @@ void gfs2_recover_func(struct work_struct *work)
 			if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
 				ro = 1;
 		} else {
-			if (sdp->sd_vfs->s_flags & MS_RDONLY) {
+			if (sdp->sd_vfs->s_flags & SB_RDONLY) {
 				/* check if device itself is read-only */
 				ro = bdev_read_only(sdp->sd_vfs->s_bdev);
 				if (!ro) {
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 29b0473f6e74..0104eaaece38 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -893,7 +893,7 @@ static void gfs2_put_super(struct super_block *sb)
 	}
 	spin_unlock(&sdp->sd_jindex_spin);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		error = gfs2_make_fs_ro(sdp);
 		if (error)
 			gfs2_io_error(sdp);
@@ -1251,10 +1251,10 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
 		return -EINVAL;
 
 	if (sdp->sd_args.ar_spectator)
-		*flags |= MS_RDONLY;
+		*flags |= SB_RDONLY;
 
-	if ((sb->s_flags ^ *flags) & MS_RDONLY) {
-		if (*flags & MS_RDONLY)
+	if ((sb->s_flags ^ *flags) & SB_RDONLY) {
+		if (*flags & SB_RDONLY)
 			error = gfs2_make_fs_ro(sdp);
 		else
 			error = gfs2_make_fs_rw(sdp);
@@ -1264,9 +1264,9 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
 
 	sdp->sd_args = args;
 	if (sdp->sd_args.ar_posix_acl)
-		sb->s_flags |= MS_POSIXACL;
+		sb->s_flags |= SB_POSIXACL;
 	else
-		sb->s_flags &= ~MS_POSIXACL;
+		sb->s_flags &= ~SB_POSIXACL;
 	if (sdp->sd_args.ar_nobarrier)
 		set_bit(SDF_NOBARRIERS, &sdp->sd_flags);
 	else
@@ -1532,7 +1532,7 @@ static void gfs2_evict_inode(struct inode *inode)
 		return;
 	}
 
-	if (inode->i_nlink || (sb->s_flags & MS_RDONLY))
+	if (inode->i_nlink || (sb->s_flags & SB_RDONLY))
 		goto out;
 
 	/* Must not read inode block until block type has been verified */
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index 7a515345610c..26efdea944c0 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -656,7 +656,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
 	char *envp[] = { ro, spectator, NULL };
 	int sysfs_frees_sdp = 0;
 
-	sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);
+	sprintf(ro, "RDONLY=%d", (sb->s_flags & SB_RDONLY) ? 1 : 0);
 	sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
 
 	sdp->sd_kobj.kset = gfs2_kset;
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
index affef3c066e0..56389a0cc5d8 100644
--- a/fs/gfs2/trans.c
+++ b/fs/gfs2/trans.c
@@ -117,7 +117,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
 		kfree(tr);
 	up_read(&sdp->sd_log_flush_lock);
 
-	if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
+	if (sdp->sd_vfs->s_flags & SB_SYNCHRONOUS)
 		gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
 	if (alloced)
 		sb_end_intwrite(sdp->sd_vfs);
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
index 482081bcdf70..7d5a6bd38d22 100644
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -204,13 +204,13 @@ int hfs_mdb_get(struct super_block *sb)
 	attrib = mdb->drAtrb;
 	if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) {
 		pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended.  mounting read-only.\n");
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
 	if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) {
 		pr_warn("filesystem is marked locked, mounting read-only.\n");
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		/* Mark the volume uncleanly unmounted in case we crash */
 		attrib &= cpu_to_be16(~HFS_SB_ATTRIB_UNMNT);
 		attrib |= cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT);
@@ -259,7 +259,7 @@ void hfs_mdb_commit(struct super_block *sb)
 {
 	struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return;
 
 	lock_buffer(HFS_SB(sb)->mdb_bh);
@@ -334,7 +334,7 @@ void hfs_mdb_commit(struct super_block *sb)
 void hfs_mdb_close(struct super_block *sb)
 {
 	/* update volume attributes */
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return;
 	HFS_SB(sb)->mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
 	HFS_SB(sb)->mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index bf6304a350a6..16bda3b9bef3 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -71,7 +71,7 @@ void hfs_mark_mdb_dirty(struct super_block *sb)
 	struct hfs_sb_info *sbi = HFS_SB(sb);
 	unsigned long delay;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return;
 
 	spin_lock(&sbi->work_lock);
@@ -114,18 +114,18 @@ static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 static int hfs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_NODIRATIME;
-	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+	*flags |= SB_NODIRATIME;
+	if ((*flags & SB_RDONLY) == (sb->s_flags & SB_RDONLY))
 		return 0;
-	if (!(*flags & MS_RDONLY)) {
+	if (!(*flags & SB_RDONLY)) {
 		if (!(HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) {
 			pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended.  leaving read-only.\n");
-			sb->s_flags |= MS_RDONLY;
-			*flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
+			*flags |= SB_RDONLY;
 		} else if (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_SLOCK)) {
 			pr_warn("filesystem is marked locked, leaving read-only.\n");
-			sb->s_flags |= MS_RDONLY;
-			*flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
+			*flags |= SB_RDONLY;
 		}
 	}
 	return 0;
@@ -407,7 +407,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
 
 	sb->s_op = &hfs_super_operations;
 	sb->s_xattr = hfs_xattr_handlers;
-	sb->s_flags |= MS_NODIRATIME;
+	sb->s_flags |= SB_NODIRATIME;
 	mutex_init(&sbi->bitmap_lock);
 
 	res = hfs_mdb_get(sb);
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 67aedf4c2e7c..bad7d9abb587 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -264,7 +264,7 @@ void hfsplus_mark_mdb_dirty(struct super_block *sb)
 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
 	unsigned long delay;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return;
 
 	spin_lock(&sbi->work_lock);
@@ -284,7 +284,7 @@ static void hfsplus_put_super(struct super_block *sb)
 
 	cancel_delayed_work_sync(&sbi->sync_work);
 
-	if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
+	if (!(sb->s_flags & SB_RDONLY) && sbi->s_vhdr) {
 		struct hfsplus_vh *vhdr = sbi->s_vhdr;
 
 		vhdr->modify_date = hfsp_now2mt();
@@ -329,9 +329,9 @@ static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
 static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+	if ((*flags & SB_RDONLY) == (sb->s_flags & SB_RDONLY))
 		return 0;
-	if (!(*flags & MS_RDONLY)) {
+	if (!(*flags & SB_RDONLY)) {
 		struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
 		int force = 0;
 
@@ -340,20 +340,20 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
 
 		if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
 			pr_warn("filesystem was not cleanly unmounted, running fsck.hfsplus is recommended.  leaving read-only.\n");
-			sb->s_flags |= MS_RDONLY;
-			*flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
+			*flags |= SB_RDONLY;
 		} else if (force) {
 			/* nothing */
 		} else if (vhdr->attributes &
 				cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
 			pr_warn("filesystem is marked locked, leaving read-only.\n");
-			sb->s_flags |= MS_RDONLY;
-			*flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
+			*flags |= SB_RDONLY;
 		} else if (vhdr->attributes &
 				cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
 			pr_warn("filesystem is marked journaled, leaving read-only.\n");
-			sb->s_flags |= MS_RDONLY;
-			*flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
+			*flags |= SB_RDONLY;
 		}
 	}
 	return 0;
@@ -455,16 +455,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
 
 	if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
 		pr_warn("Filesystem was not cleanly unmounted, running fsck.hfsplus is recommended.  mounting read-only.\n");
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	} else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
 		/* nothing */
 	} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
 		pr_warn("Filesystem is marked locked, mounting read-only.\n");
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	} else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) &&
-			!(sb->s_flags & MS_RDONLY)) {
+			!(sb->s_flags & SB_RDONLY)) {
 		pr_warn("write access to a journaled filesystem is not supported, use the force option at your own risk, mounting read-only.\n");
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
 
 	err = -EINVAL;
@@ -535,7 +535,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
 	} else
 		hfs_find_exit(&fd);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		/*
 		 * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
 		 * all three are registered with Apple for our use
diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c
index d6a4b55d2ab0..30076ca5c7eb 100644
--- a/fs/hpfs/alloc.c
+++ b/fs/hpfs/alloc.c
@@ -538,7 +538,7 @@ int hpfs_trim_fs(struct super_block *s, u64 start, u64 end, u64 minlen, unsigned
 		return 0;
 	if (start < sbi->sb_dirband_start + sbi->sb_dirband_size && end > sbi->sb_dirband_start) {
 		hpfs_lock(s);
-		if (s->s_flags & MS_RDONLY) {
+		if (s->s_flags & SB_RDONLY) {
 			err = -EROFS;
 			goto unlock_1;
 		}
@@ -559,7 +559,7 @@ int hpfs_trim_fs(struct super_block *s, u64 start, u64 end, u64 minlen, unsigned
 	end_bmp = (end + 0x3fff) >> 14;
 	while (start_bmp < end_bmp && !err) {
 		hpfs_lock(s);
-		if (s->s_flags & MS_RDONLY) {
+		if (s->s_flags & SB_RDONLY) {
 			err = -EROFS;
 			goto unlock_2;
 		}
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 7b9150c2e75c..168b2944fa5d 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -264,7 +264,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned in
 	hpfs_result = hpfs_i(result);
 	if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino;
 
-	if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) {
+	if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & SB_RDONLY)) {
 		hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures");
 		goto bail1;
 	}
diff --git a/fs/hpfs/map.c b/fs/hpfs/map.c
index a136929189f0..33e4d41a34cc 100644
--- a/fs/hpfs/map.c
+++ b/fs/hpfs/map.c
@@ -287,7 +287,7 @@ struct dnode *hpfs_map_dnode(struct super_block *s, unsigned secno,
 					goto bail;
 				}
 				if (((31 + de->namelen + de->down*4 + 3) & ~3) != le16_to_cpu(de->length)) {
-					if (((31 + de->namelen + de->down*4 + 3) & ~3) < le16_to_cpu(de->length) && s->s_flags & MS_RDONLY) goto ok;
+					if (((31 + de->namelen + de->down*4 + 3) & ~3) < le16_to_cpu(de->length) && s->s_flags & SB_RDONLY) goto ok;
 					hpfs_error(s, "namelen does not match dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp);
 					goto bail;
 				}
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 82067ca22f2b..7d59bcafcd89 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -21,7 +21,7 @@
 
 static void mark_dirty(struct super_block *s, int remount)
 {
-	if (hpfs_sb(s)->sb_chkdsk && (remount || !(s->s_flags & MS_RDONLY))) {
+	if (hpfs_sb(s)->sb_chkdsk && (remount || !(s->s_flags & SB_RDONLY))) {
 		struct buffer_head *bh;
 		struct hpfs_spare_block *sb;
 		if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
@@ -41,7 +41,7 @@ static void unmark_dirty(struct super_block *s)
 {
 	struct buffer_head *bh;
 	struct hpfs_spare_block *sb;
-	if (s->s_flags & MS_RDONLY) return;
+	if (s->s_flags & SB_RDONLY) return;
 	sync_blockdev(s->s_bdev);
 	if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
 		sb->dirty = hpfs_sb(s)->sb_chkdsk > 1 - hpfs_sb(s)->sb_was_error;
@@ -73,14 +73,14 @@ void hpfs_error(struct super_block *s, const char *fmt, ...)
 			mark_dirty(s, 0);
 			panic("HPFS panic");
 		} else if (hpfs_sb(s)->sb_err == 1) {
-			if (s->s_flags & MS_RDONLY)
+			if (s->s_flags & SB_RDONLY)
 				pr_cont("; already mounted read-only\n");
 			else {
 				pr_cont("; remounting read-only\n");
 				mark_dirty(s, 0);
-				s->s_flags |= MS_RDONLY;
+				s->s_flags |= SB_RDONLY;
 			}
-		} else if (s->s_flags & MS_RDONLY)
+		} else if (s->s_flags & SB_RDONLY)
 				pr_cont("; going on - but anything won't be destroyed because it's read-only\n");
 		else
 			pr_cont("; corrupted filesystem mounted read/write - your computer will explode within 20 seconds ... but you wanted it so!\n");
@@ -457,7 +457,7 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
 
 	sync_filesystem(s);
 
-	*flags |= MS_NOATIME;
+	*flags |= SB_NOATIME;
 
 	hpfs_lock(s);
 	uid = sbi->sb_uid; gid = sbi->sb_gid;
@@ -488,7 +488,7 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
 	sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk;
 	sbi->sb_err = errs; sbi->sb_timeshift = timeshift;
 
-	if (!(*flags & MS_RDONLY)) mark_dirty(s, 1);
+	if (!(*flags & SB_RDONLY)) mark_dirty(s, 1);
 
 	hpfs_unlock(s);
 	return 0;
@@ -607,7 +607,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
 	}
 
 	/* Check version */
-	if (!(s->s_flags & MS_RDONLY) &&
+	if (!(s->s_flags & SB_RDONLY) &&
 	      superblock->funcversion != 2 && superblock->funcversion != 3) {
 		pr_err("Bad version %d,%d. Mount readonly to go around\n",
 			(int)superblock->version, (int)superblock->funcversion);
@@ -615,7 +615,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
 		goto bail4;
 	}
 
-	s->s_flags |= MS_NOATIME;
+	s->s_flags |= SB_NOATIME;
 
 	/* Fill superblock stuff */
 	s->s_magic = HPFS_SUPER_MAGIC;
@@ -666,7 +666,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
 		hpfs_error(s, "improperly stopped");
 	}
 
-	if (!(s->s_flags & MS_RDONLY)) {
+	if (!(s->s_flags & SB_RDONLY)) {
 		spareblock->dirty = 1;
 		spareblock->old_wrote = 0;
 		mark_buffer_dirty(bh2);
diff --git a/fs/inode.c b/fs/inode.c
index db5914783a71..799d0cf579ea 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -415,7 +415,7 @@ void inode_add_lru(struct inode *inode)
 {
 	if (!(inode->i_state & (I_DIRTY_ALL | I_SYNC |
 				I_FREEING | I_WILL_FREE)) &&
-	    !atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE)
+	    !atomic_read(&inode->i_count) && inode->i_sb->s_flags & SB_ACTIVE)
 		inode_lru_list_add(inode);
 }
 
@@ -594,7 +594,7 @@ static void dispose_list(struct list_head *head)
  * @sb:		superblock to operate on
  *
  * Make sure that no inodes with zero refcount are retained.  This is
- * called by superblock shutdown after having MS_ACTIVE flag removed,
+ * called by superblock shutdown after having SB_ACTIVE flag removed,
  * so any inode reaching zero refcount during or after that call will
  * be immediately evicted.
  */
@@ -1490,7 +1490,7 @@ static void iput_final(struct inode *inode)
 	else
 		drop = generic_drop_inode(inode);
 
-	if (!drop && (sb->s_flags & MS_ACTIVE)) {
+	if (!drop && (sb->s_flags & SB_ACTIVE)) {
 		inode_add_lru(inode);
 		spin_unlock(&inode->i_lock);
 		return;
@@ -1629,7 +1629,7 @@ int generic_update_time(struct inode *inode, struct timespec *time, int flags)
 	if (flags & S_MTIME)
 		inode->i_mtime = *time;
 
-	if (!(inode->i_sb->s_flags & MS_LAZYTIME) || (flags & S_VERSION))
+	if (!(inode->i_sb->s_flags & SB_LAZYTIME) || (flags & S_VERSION))
 		iflags |= I_DIRTY_SYNC;
 	__mark_inode_dirty(inode, iflags);
 	return 0;
@@ -1676,7 +1676,7 @@ bool __atime_needs_update(const struct path *path, struct inode *inode,
 
 	if (IS_NOATIME(inode))
 		return false;
-	if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
+	if ((inode->i_sb->s_flags & SB_NODIRATIME) && S_ISDIR(inode->i_mode))
 		return false;
 
 	if (mnt->mnt_flags & MNT_NOATIME)
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 020ba0936146..99f7313ce400 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -112,7 +112,7 @@ static void destroy_inodecache(void)
 static int isofs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	if (!(*flags & MS_RDONLY))
+	if (!(*flags & SB_RDONLY))
 		return -EROFS;
 	return 0;
 }
@@ -689,7 +689,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
 
 root_found:
 	/* We don't support read-write mounts */
-	if (!(s->s_flags & MS_RDONLY)) {
+	if (!(s->s_flags & SB_RDONLY)) {
 		error = -EACCES;
 		goto out_freebh;
 	}
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 76fa814df3d1..6dd5bf251e4c 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -395,24 +395,24 @@ int jffs2_do_remount_fs(struct super_block *sb, int *flags, char *data)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
 
-	if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY))
+	if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & SB_RDONLY))
 		return -EROFS;
 
 	/* We stop if it was running, then restart if it needs to.
 	   This also catches the case where it was stopped and this
 	   is just a remount to restart it.
 	   Flush the writebuffer, if neccecary, else we loose it */
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		jffs2_stop_garbage_collect_thread(c);
 		mutex_lock(&c->alloc_sem);
 		jffs2_flush_wbuf_pad(c);
 		mutex_unlock(&c->alloc_sem);
 	}
 
-	if (!(*flags & MS_RDONLY))
+	if (!(*flags & SB_RDONLY))
 		jffs2_start_garbage_collect_thread(c);
 
-	*flags |= MS_NOATIME;
+	*flags |= SB_NOATIME;
 	return 0;
 }
 
@@ -590,7 +590,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_blocksize = PAGE_SIZE;
 	sb->s_blocksize_bits = PAGE_SHIFT;
 	sb->s_magic = JFFS2_SUPER_MAGIC;
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		jffs2_start_garbage_collect_thread(c);
 	return 0;
 
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 824e61ede465..c2fbec19c616 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -59,7 +59,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 }
 
 
-#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
+#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & SB_RDONLY)
 
 #define SECTOR_ADDR(x) ( (((unsigned long)(x) / c->sector_size) * c->sector_size) )
 #ifndef CONFIG_JFFS2_FS_WRITEBUFFER
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 5ef21f4c4c77..6d86dcf04021 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -301,10 +301,10 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
 
 	sb->s_op = &jffs2_super_operations;
 	sb->s_export_op = &jffs2_export_ops;
-	sb->s_flags = sb->s_flags | MS_NOATIME;
+	sb->s_flags |= SB_NOATIME;
 	sb->s_xattr = jffs2_xattr_handlers;
 #ifdef CONFIG_JFFS2_FS_POSIX_ACL
-	sb->s_flags |= MS_POSIXACL;
+	sb->s_flags |= SB_POSIXACL;
 #endif
 	ret = jffs2_do_fill_super(sb, data, silent);
 	return ret;
@@ -342,7 +342,7 @@ static void jffs2_put_super (struct super_block *sb)
 static void jffs2_kill_sb(struct super_block *sb)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		jffs2_stop_garbage_collect_thread(c);
 	kill_mtd_super(sb);
 	kfree(c);
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index b25d28a21212..9d896a66798d 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -1162,7 +1162,7 @@ static void delayed_wbuf_sync(struct work_struct *work)
 	struct jffs2_sb_info *c = work_to_sb(work);
 	struct super_block *sb = OFNI_BS_2SFFJ(c);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		jffs2_dbg(1, "%s()\n", __func__);
 		jffs2_flush_wbuf_gc(c, 0);
 	}
@@ -1173,7 +1173,7 @@ void jffs2_dirty_trigger(struct jffs2_sb_info *c)
 	struct super_block *sb = OFNI_BS_2SFFJ(c);
 	unsigned long delay;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return;
 
 	delay = msecs_to_jiffies(dirty_writeback_interval * 10);
diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
index 9895595fd2f2..e64e938a92d4 100644
--- a/fs/jfs/jfs_mount.c
+++ b/fs/jfs/jfs_mount.c
@@ -362,7 +362,7 @@ static int chkSuper(struct super_block *sb)
 
 	/* validate fs state */
 	if (j_sb->s_state != cpu_to_le32(FM_CLEAN) &&
-	    !(sb->s_flags & MS_RDONLY)) {
+	    !(sb->s_flags & SB_RDONLY)) {
 		jfs_err("jfs_mount: Mount Failure: File System Dirty.");
 		rc = -EINVAL;
 		goto out;
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index e8aad7d87b8c..d2a90a0c906d 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -76,7 +76,7 @@ static void jfs_handle_error(struct super_block *sb)
 {
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return;
 
 	updateSuper(sb, FM_DIRTY);
@@ -87,7 +87,7 @@ static void jfs_handle_error(struct super_block *sb)
 	else if (sbi->flag & JFS_ERR_REMOUNT_RO) {
 		jfs_err("ERROR: (device %s): remounting filesystem as read-only",
 			sb->s_id);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
 
 	/* nothing is done for continue beyond marking the superblock dirty */
@@ -468,7 +468,7 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
 		return -EINVAL;
 
 	if (newLVSize) {
-		if (sb->s_flags & MS_RDONLY) {
+		if (sb->s_flags & SB_RDONLY) {
 			pr_err("JFS: resize requires volume to be mounted read-write\n");
 			return -EROFS;
 		}
@@ -477,7 +477,7 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
 			return rc;
 	}
 
-	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
+	if ((sb->s_flags & SB_RDONLY) && !(*flags & SB_RDONLY)) {
 		/*
 		 * Invalidate any previously read metadata.  fsck may have
 		 * changed the on-disk data since we mounted r/o
@@ -488,12 +488,12 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
 		ret = jfs_mount_rw(sb, 1);
 
 		/* mark the fs r/w for quota activity */
-		sb->s_flags &= ~MS_RDONLY;
+		sb->s_flags &= ~SB_RDONLY;
 
 		dquot_resume(sb, -1);
 		return ret;
 	}
-	if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) {
+	if ((!(sb->s_flags & SB_RDONLY)) && (*flags & SB_RDONLY)) {
 		rc = dquot_suspend(sb, -1);
 		if (rc < 0)
 			return rc;
@@ -502,7 +502,7 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
 		return rc;
 	}
 	if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY))
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			rc = jfs_umount_rw(sb);
 			if (rc)
 				return rc;
@@ -545,7 +545,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
 	sbi->flag = flag;
 
 #ifdef CONFIG_JFS_POSIX_ACL
-	sb->s_flags |= MS_POSIXACL;
+	sb->s_flags |= SB_POSIXACL;
 #endif
 
 	if (newLVSize) {
@@ -592,7 +592,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
 			jfs_err("jfs_mount failed w/return code = %d", rc);
 		goto out_mount_failed;
 	}
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		sbi->log = NULL;
 	else {
 		rc = jfs_mount_rw(sb, 0);
@@ -658,7 +658,7 @@ static int jfs_freeze(struct super_block *sb)
 	struct jfs_log *log = sbi->log;
 	int rc = 0;
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		txQuiesce(sb);
 		rc = lmLogShutdown(log);
 		if (rc) {
@@ -688,7 +688,7 @@ static int jfs_unfreeze(struct super_block *sb)
 	struct jfs_log *log = sbi->log;
 	int rc = 0;
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		rc = updateSuper(sb, FM_MOUNT);
 		if (rc) {
 			jfs_error(sb, "updateSuper failed\n");
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index d5b149a45be1..f1e0b15015b7 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -262,7 +262,7 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
 			deactivate_locked_super(sb);
 			return ERR_PTR(error);
 		}
-		sb->s_flags |= MS_ACTIVE;
+		sb->s_flags |= SB_ACTIVE;
 
 		mutex_lock(&kernfs_mutex);
 		list_add(&info->node, &root->supers);
diff --git a/fs/libfs.c b/fs/libfs.c
index a04395334bb1..32c159ed33dd 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -246,7 +246,7 @@ struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
 	struct inode *root;
 	struct qstr d_name = QSTR_INIT(name, strlen(name));
 
-	s = sget_userns(fs_type, NULL, set_anon_super, MS_KERNMOUNT|MS_NOUSER,
+	s = sget_userns(fs_type, NULL, set_anon_super, SB_KERNMOUNT|SB_NOUSER,
 			&init_user_ns, NULL);
 	if (IS_ERR(s))
 		return ERR_CAST(s);
@@ -277,7 +277,7 @@ struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
 	d_instantiate(dentry, root);
 	s->s_root = dentry;
 	s->s_d_op = dops;
-	s->s_flags |= MS_ACTIVE;
+	s->s_flags |= SB_ACTIVE;
 	return dget(s->s_root);
 
 Enomem:
@@ -578,7 +578,7 @@ int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *c
 	spin_lock(&pin_fs_lock);
 	if (unlikely(!*mount)) {
 		spin_unlock(&pin_fs_lock);
-		mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, NULL);
+		mnt = vfs_kern_mount(type, SB_KERNMOUNT, type->name, NULL);
 		if (IS_ERR(mnt))
 			return PTR_ERR(mnt);
 		spin_lock(&pin_fs_lock);
diff --git a/fs/locks.c b/fs/locks.c
index af2031a1fcff..f5075dd0b20f 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -140,7 +140,7 @@
 
 static inline bool is_remote_lock(struct file *filp)
 {
-	return likely(!(filp->f_path.dentry->d_sb->s_flags & MS_NOREMOTELOCK));
+	return likely(!(filp->f_path.dentry->d_sb->s_flags & SB_NOREMOTELOCK));
 }
 
 static bool lease_breaking(struct file_lock *fl)
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 6ac76b0434e9..489c364838d4 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -42,7 +42,7 @@ static void minix_put_super(struct super_block *sb)
 	int i;
 	struct minix_sb_info *sbi = minix_sb(sb);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		if (sbi->s_version != MINIX_V3)	 /* s_state is now out from V3 sb */
 			sbi->s_ms->s_state = sbi->s_mount_state;
 		mark_buffer_dirty(sbi->s_sbh);
@@ -125,9 +125,9 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
 
 	sync_filesystem(sb);
 	ms = sbi->s_ms;
-	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+	if ((*flags & SB_RDONLY) == (sb->s_flags & SB_RDONLY))
 		return 0;
-	if (*flags & MS_RDONLY) {
+	if (*flags & SB_RDONLY) {
 		if (ms->s_state & MINIX_VALID_FS ||
 		    !(sbi->s_mount_state & MINIX_VALID_FS))
 			return 0;
@@ -293,7 +293,7 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
 	if (!s->s_root)
 		goto out_no_root;
 
-	if (!(s->s_flags & MS_RDONLY)) {
+	if (!(s->s_flags & SB_RDONLY)) {
 		if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */
 			ms->s_state &= ~MINIX_VALID_FS;
 		mark_buffer_dirty(bh);
diff --git a/fs/namei.c b/fs/namei.c
index 0d35760fee00..9fe8ec83aedf 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -447,7 +447,7 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
 		umode_t mode = inode->i_mode;
 
 		/* Nobody gets write access to a read-only fs. */
-		if ((sb->s_flags & MS_RDONLY) &&
+		if ((sb->s_flags & SB_RDONLY) &&
 		    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
 			return -EROFS;
 	}
diff --git a/fs/namespace.c b/fs/namespace.c
index c076787871e7..9a7dbf7b716f 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -274,7 +274,7 @@ int __mnt_is_readonly(struct vfsmount *mnt)
 {
 	if (mnt->mnt_flags & MNT_READONLY)
 		return 1;
-	if (mnt->mnt_sb->s_flags & MS_RDONLY)
+	if (mnt->mnt_sb->s_flags & SB_RDONLY)
 		return 1;
 	return 0;
 }
@@ -970,7 +970,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
 	if (!mnt)
 		return ERR_PTR(-ENOMEM);
 
-	if (flags & MS_KERNMOUNT)
+	if (flags & SB_KERNMOUNT)
 		mnt->mnt.mnt_flags = MNT_INTERNAL;
 
 	root = mount_fs(type, flags, name, data);
@@ -1002,7 +1002,7 @@ vfs_submount(const struct dentry *mountpoint, struct file_system_type *type,
 	if (mountpoint->d_sb->s_user_ns != &init_user_ns)
 		return ERR_PTR(-EPERM);
 
-	return vfs_kern_mount(type, MS_SUBMOUNT, name, data);
+	return vfs_kern_mount(type, SB_SUBMOUNT, name, data);
 }
 EXPORT_SYMBOL_GPL(vfs_submount);
 
@@ -1592,8 +1592,8 @@ static int do_umount(struct mount *mnt, int flags)
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		down_write(&sb->s_umount);
-		if (!(sb->s_flags & MS_RDONLY))
-			retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
+		if (!(sb->s_flags & SB_RDONLY))
+			retval = do_remount_sb(sb, SB_RDONLY, NULL, 0);
 		up_write(&sb->s_umount);
 		return retval;
 	}
@@ -2117,7 +2117,7 @@ static void unlock_mount(struct mountpoint *where)
 
 static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp)
 {
-	if (mnt->mnt.mnt_sb->s_flags & MS_NOUSER)
+	if (mnt->mnt.mnt_sb->s_flags & SB_NOUSER)
 		return -EINVAL;
 
 	if (d_is_dir(mp->m_dentry) !=
@@ -2133,7 +2133,7 @@ static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp)
 
 static int flags_to_propagation_type(int flags)
 {
-	int type = flags & ~(MS_REC | MS_SILENT);
+	int type = flags & ~(MS_REC | SB_SILENT);
 
 	/* Fail if any non-propagation flags are set */
 	if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
@@ -2263,7 +2263,7 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
 	int error = 0;
 	int readonly_request = 0;
 
-	if (ms_flags & MS_RDONLY)
+	if (ms_flags & SB_RDONLY)
 		readonly_request = 1;
 	if (readonly_request == __mnt_is_readonly(mnt))
 		return 0;
@@ -2784,7 +2784,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
 				   type_page, flags, data_page);
 	if (!retval && !may_mount())
 		retval = -EPERM;
-	if (!retval && (flags & MS_MANDLOCK) && !may_mandlock())
+	if (!retval && (flags & SB_MANDLOCK) && !may_mandlock())
 		retval = -EPERM;
 	if (retval)
 		goto dput_out;
@@ -2806,7 +2806,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,
 		mnt_flags |= MNT_NODIRATIME;
 	if (flags & MS_STRICTATIME)
 		mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
-	if (flags & MS_RDONLY)
+	if (flags & SB_RDONLY)
 		mnt_flags |= MNT_READONLY;
 
 	/* The default atime for remount is preservation */
@@ -2817,9 +2817,9 @@ long do_mount(const char *dev_name, const char __user *dir_name,
 		mnt_flags |= path.mnt->mnt_flags & MNT_ATIME_MASK;
 	}
 
-	flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
-		   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
-		   MS_STRICTATIME | MS_NOREMOTELOCK | MS_SUBMOUNT);
+	flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | SB_ACTIVE | SB_BORN |
+		   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| SB_KERNMOUNT |
+		   MS_STRICTATIME | SB_NOREMOTELOCK | SB_SUBMOUNT);
 
 	if (flags & MS_REMOUNT)
 		retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
@@ -3287,7 +3287,7 @@ void put_mnt_ns(struct mnt_namespace *ns)
 struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
 {
 	struct vfsmount *mnt;
-	mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
+	mnt = vfs_kern_mount(type, SB_KERNMOUNT, type->name, data);
 	if (!IS_ERR(mnt)) {
 		/*
 		 * it is a longterm mount, don't release mnt until
@@ -3364,7 +3364,7 @@ static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new,
 		mnt_flags = mnt->mnt.mnt_flags;
 
 		/* Don't miss readonly hidden in the superblock flags */
-		if (mnt->mnt.mnt_sb->s_flags & MS_RDONLY)
+		if (mnt->mnt.mnt_sb->s_flags & SB_RDONLY)
 			mnt_flags |= MNT_LOCK_READONLY;
 
 		/* Verify the mount flags are equal to or more permissive
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 6d0f14c86099..0bb2c3887aeb 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -103,7 +103,7 @@ static void destroy_inodecache(void)
 static int ncp_remount(struct super_block *sb, int *flags, char* data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_NODIRATIME;
+	*flags |= SB_NODIRATIME;
 	return 0;
 }
 
@@ -547,7 +547,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
 	else
 		default_bufsize = 1024;
 
-	sb->s_flags |= MS_NODIRATIME;	/* probably even noatime */
+	sb->s_flags |= SB_NODIRATIME;	/* probably even noatime */
 	sb->s_maxbytes = 0xFFFFFFFFU;
 	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
 	sb->s_blocksize_bits = 10;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 32ccd7754f8a..37bc646f9d0b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1260,7 +1260,7 @@ static int nfs_dentry_delete(const struct dentry *dentry)
 		/* Unhash it, so that ->d_iput() would be called */
 		return 1;
 	}
-	if (!(dentry->d_sb->s_flags & MS_ACTIVE)) {
+	if (!(dentry->d_sb->s_flags & SB_ACTIVE)) {
 		/* Unhash it, so that ancestors of killed async unlink
 		 * files will be cleaned up during umount */
 		return 1;
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index d63bea8bbfbb..d88f9c27ec86 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -81,7 +81,7 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int
 		return;
 
 	key->nfs_client = nfss->nfs_client;
-	key->key.super.s_flags = sb->s_flags & NFS_MS_MASK;
+	key->key.super.s_flags = sb->s_flags & NFS_SB_MASK;
 	key->key.nfs_server.flags = nfss->flags;
 	key->key.nfs_server.rsize = nfss->rsize;
 	key->key.nfs_server.wsize = nfss->wsize;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 3e24392f2caa..ac9d59c6b181 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -8,7 +8,7 @@
 #include <linux/crc32.h>
 #include <linux/nfs_page.h>
 
-#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
+#define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
 
 struct nfs_string;
 
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index eceb4eabb064..b3095e87dd8c 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -812,10 +812,10 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
 	 * Display all mount option settings
 	 */
 	seq_printf(m, "\n\topts:\t");
-	seq_puts(m, root->d_sb->s_flags & MS_RDONLY ? "ro" : "rw");
-	seq_puts(m, root->d_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
-	seq_puts(m, root->d_sb->s_flags & MS_NOATIME ? ",noatime" : "");
-	seq_puts(m, root->d_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
+	seq_puts(m, root->d_sb->s_flags & SB_RDONLY ? "ro" : "rw");
+	seq_puts(m, root->d_sb->s_flags & SB_SYNCHRONOUS ? ",sync" : "");
+	seq_puts(m, root->d_sb->s_flags & SB_NOATIME ? ",noatime" : "");
+	seq_puts(m, root->d_sb->s_flags & SB_NODIRATIME ? ",nodiratime" : "");
 	nfs_show_mount_options(m, nfss, 1);
 
 	seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
@@ -2284,11 +2284,11 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 	/*
 	 * noac is a special case. It implies -o sync, but that's not
 	 * necessarily reflected in the mtab options. do_remount_sb
-	 * will clear MS_SYNCHRONOUS if -o sync wasn't specified in the
+	 * will clear SB_SYNCHRONOUS if -o sync wasn't specified in the
 	 * remount options, so we have to explicitly reset it.
 	 */
 	if (data->flags & NFS_MOUNT_NOAC)
-		*flags |= MS_SYNCHRONOUS;
+		*flags |= SB_SYNCHRONOUS;
 
 	/* compare new mount options with old ones */
 	error = nfs_compare_remount_data(nfss, data);
@@ -2337,7 +2337,7 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
 		/* The VFS shouldn't apply the umask to mode bits. We will do
 		 * so ourselves when necessary.
 		 */
-		sb->s_flags |= MS_POSIXACL;
+		sb->s_flags |= SB_POSIXACL;
 		sb->s_time_gran = 1;
 	}
 
@@ -2365,7 +2365,7 @@ static void nfs_clone_super(struct super_block *sb,
 		/* The VFS shouldn't apply the umask to mode bits. We will do
 		 * so ourselves when necessary.
 		 */
-		sb->s_flags |= MS_POSIXACL;
+		sb->s_flags |= SB_POSIXACL;
 	}
 
  	nfs_initialise_sb(sb);
@@ -2377,7 +2377,7 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n
 	const struct rpc_clnt *clnt_a = a->client;
 	const struct rpc_clnt *clnt_b = b->client;
 
-	if ((s->s_flags & NFS_MS_MASK) != (flags & NFS_MS_MASK))
+	if ((s->s_flags & NFS_SB_MASK) != (flags & NFS_SB_MASK))
 		goto Ebusy;
 	if (a->nfs_client != b->nfs_client)
 		goto Ebusy;
@@ -2571,11 +2571,11 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
 
 	/* -o noac implies -o sync */
 	if (server->flags & NFS_MOUNT_NOAC)
-		sb_mntdata.mntflags |= MS_SYNCHRONOUS;
+		sb_mntdata.mntflags |= SB_SYNCHRONOUS;
 
 	if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL)
-		if (mount_info->cloned->sb->s_flags & MS_SYNCHRONOUS)
-			sb_mntdata.mntflags |= MS_SYNCHRONOUS;
+		if (mount_info->cloned->sb->s_flags & SB_SYNCHRONOUS)
+			sb_mntdata.mntflags |= SB_SYNCHRONOUS;
 
 	/* Get a superblock - note that we may end up sharing one that already exists */
 	s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata);
@@ -2612,7 +2612,7 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
 	if (error)
 		goto error_splat_root;
 
-	s->s_flags |= MS_ACTIVE;
+	s->s_flags |= SB_ACTIVE;
 
 out:
 	return mntroot;
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 7ffe71a8dfb9..ca4be7f82749 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -174,7 +174,7 @@ static int nilfs_writepages(struct address_space *mapping,
 	struct inode *inode = mapping->host;
 	int err = 0;
 
-	if (inode->i_sb->s_flags & MS_RDONLY) {
+	if (inode->i_sb->s_flags & SB_RDONLY) {
 		nilfs_clear_dirty_pages(mapping, false);
 		return -EROFS;
 	}
@@ -191,7 +191,7 @@ static int nilfs_writepage(struct page *page, struct writeback_control *wbc)
 	struct inode *inode = page->mapping->host;
 	int err;
 
-	if (inode->i_sb->s_flags & MS_RDONLY) {
+	if (inode->i_sb->s_flags & SB_RDONLY) {
 		/*
 		 * It means that filesystem was remounted in read-only
 		 * mode because of error or metadata corruption. But we
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c
index 98835ed6bef4..e61fcbffa629 100644
--- a/fs/nilfs2/mdt.c
+++ b/fs/nilfs2/mdt.c
@@ -413,7 +413,7 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc)
 	struct super_block *sb;
 	int err = 0;
 
-	if (inode && (inode->i_sb->s_flags & MS_RDONLY)) {
+	if (inode && (inode->i_sb->s_flags & SB_RDONLY)) {
 		/*
 		 * It means that filesystem was remounted in read-only
 		 * mode because of error or metadata corruption. But we
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index febed1217b3f..d1b114fb47eb 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -1981,7 +1981,7 @@ static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci,
 					     struct the_nilfs *nilfs)
 {
 	struct nilfs_inode_info *ii, *n;
-	int during_mount = !(sci->sc_super->s_flags & MS_ACTIVE);
+	int during_mount = !(sci->sc_super->s_flags & SB_ACTIVE);
 	int defer_iput = false;
 
 	spin_lock(&nilfs->ns_inode_lock);
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 926682981d61..0ea2a7a5ea09 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -136,12 +136,12 @@ void __nilfs_error(struct super_block *sb, const char *function,
 
 	va_end(args);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		nilfs_set_error(sb);
 
 		if (nilfs_test_opt(nilfs, ERRORS_RO)) {
 			printk(KERN_CRIT "Remounting filesystem read-only\n");
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 		}
 	}
 
@@ -478,7 +478,7 @@ static void nilfs_put_super(struct super_block *sb)
 
 	nilfs_detach_log_writer(sb);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		down_write(&nilfs->ns_sem);
 		nilfs_cleanup_super(sb);
 		up_write(&nilfs->ns_sem);
@@ -578,7 +578,7 @@ static int nilfs_freeze(struct super_block *sb)
 	struct the_nilfs *nilfs = sb->s_fs_info;
 	int err;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return 0;
 
 	/* Mark super block clean */
@@ -592,7 +592,7 @@ static int nilfs_unfreeze(struct super_block *sb)
 {
 	struct the_nilfs *nilfs = sb->s_fs_info;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return 0;
 
 	down_write(&nilfs->ns_sem);
@@ -870,7 +870,7 @@ int nilfs_store_magic_and_option(struct super_block *sb,
 
 	/* FS independent flags */
 #ifdef NILFS_ATIME_DISABLE
-	sb->s_flags |= MS_NOATIME;
+	sb->s_flags |= SB_NOATIME;
 #endif
 
 	nilfs_set_default_options(sb, sbp);
@@ -898,7 +898,7 @@ int nilfs_check_feature_compatibility(struct super_block *sb,
 	}
 	features = le64_to_cpu(sbp->s_feature_compat_ro) &
 		~NILFS_FEATURE_COMPAT_RO_SUPP;
-	if (!(sb->s_flags & MS_RDONLY) && features) {
+	if (!(sb->s_flags & SB_RDONLY) && features) {
 		nilfs_msg(sb, KERN_ERR,
 			  "couldn't mount RDWR because of unsupported optional features (%llx)",
 			  (unsigned long long)features);
@@ -1083,7 +1083,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
 		goto failed_unload;
 	}
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		err = nilfs_attach_log_writer(sb, fsroot);
 		if (err)
 			goto failed_checkpoint;
@@ -1095,7 +1095,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
 
 	nilfs_put_root(fsroot);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		down_write(&nilfs->ns_sem);
 		nilfs_setup_super(sb, true);
 		up_write(&nilfs->ns_sem);
@@ -1134,7 +1134,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
 		err = -EINVAL;
 		goto restore_opts;
 	}
-	sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
+	sb->s_flags = (sb->s_flags & ~SB_POSIXACL);
 
 	err = -EINVAL;
 
@@ -1144,12 +1144,12 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
 		goto restore_opts;
 	}
 
-	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+	if ((*flags & SB_RDONLY) == (sb->s_flags & SB_RDONLY))
 		goto out;
-	if (*flags & MS_RDONLY) {
+	if (*flags & SB_RDONLY) {
 		/* Shutting down log writer */
 		nilfs_detach_log_writer(sb);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 
 		/*
 		 * Remounting a valid RW partition RDONLY, so set
@@ -1179,7 +1179,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
 			goto restore_opts;
 		}
 
-		sb->s_flags &= ~MS_RDONLY;
+		sb->s_flags &= ~SB_RDONLY;
 
 		root = NILFS_I(d_inode(sb->s_root))->i_root;
 		err = nilfs_attach_log_writer(sb, root);
@@ -1213,7 +1213,7 @@ static int nilfs_parse_snapshot_option(const char *option,
 	const char *msg = NULL;
 	int err;
 
-	if (!(sd->flags & MS_RDONLY)) {
+	if (!(sd->flags & SB_RDONLY)) {
 		msg = "read-only option is not specified";
 		goto parse_error;
 	}
@@ -1287,7 +1287,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
 	struct dentry *root_dentry;
 	int err, s_new = false;
 
-	if (!(flags & MS_RDONLY))
+	if (!(flags & SB_RDONLY))
 		mode |= FMODE_WRITE;
 
 	sd.bdev = blkdev_get_by_path(dev_name, mode, fs_type);
@@ -1328,17 +1328,17 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
 		snprintf(s->s_id, sizeof(s->s_id), "%pg", sd.bdev);
 		sb_set_blocksize(s, block_size(sd.bdev));
 
-		err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+		err = nilfs_fill_super(s, data, flags & SB_SILENT ? 1 : 0);
 		if (err)
 			goto failed_super;
 
-		s->s_flags |= MS_ACTIVE;
+		s->s_flags |= SB_ACTIVE;
 	} else if (!sd.cno) {
 		if (nilfs_tree_is_busy(s->s_root)) {
-			if ((flags ^ s->s_flags) & MS_RDONLY) {
+			if ((flags ^ s->s_flags) & SB_RDONLY) {
 				nilfs_msg(s, KERN_ERR,
 					  "the device already has a %s mount.",
-					  (s->s_flags & MS_RDONLY) ?
+					  (s->s_flags & SB_RDONLY) ?
 					  "read-only" : "read/write");
 				err = -EBUSY;
 				goto failed_super;
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 2dd75bf619ad..ee7ace356288 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -220,7 +220,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
 
 	if (!valid_fs) {
 		nilfs_msg(sb, KERN_WARNING, "mounting unchecked fs");
-		if (s_flags & MS_RDONLY) {
+		if (s_flags & SB_RDONLY) {
 			nilfs_msg(sb, KERN_INFO,
 				  "recovery required for readonly filesystem");
 			nilfs_msg(sb, KERN_INFO,
@@ -286,7 +286,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
 	if (valid_fs)
 		goto skip_recovery;
 
-	if (s_flags & MS_RDONLY) {
+	if (s_flags & SB_RDONLY) {
 		__u64 features;
 
 		if (nilfs_test_opt(nilfs, NORECOVERY)) {
@@ -309,7 +309,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
 			err = -EROFS;
 			goto failed_unload;
 		}
-		sb->s_flags &= ~MS_RDONLY;
+		sb->s_flags &= ~SB_RDONLY;
 	} else if (nilfs_test_opt(nilfs, NORECOVERY)) {
 		nilfs_msg(sb, KERN_ERR,
 			  "recovery cancelled because norecovery option was specified for a read/write mount");
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 01a9f0f007d4..3bb070ed86c3 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -67,7 +67,7 @@ void fsnotify_unmount_inodes(struct super_block *sb)
 
 		/*
 		 * If i_count is zero, the inode cannot have any watches and
-		 * doing an __iget/iput with MS_ACTIVE clear would actually
+		 * doing an __iget/iput with SB_ACTIVE clear would actually
 		 * evict all inodes with zero i_count from icache which is
 		 * unnecessarily violent and may in fact be illegal to do.
 		 */
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 08127a2b8559..38ab072aef51 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -254,5 +254,5 @@ void __init nsfs_init(void)
 	nsfs_mnt = kern_mount(&nsfs);
 	if (IS_ERR(nsfs_mnt))
 		panic("can't set nsfs up\n");
-	nsfs_mnt->mnt_sb->s_flags &= ~MS_NOUSER;
+	nsfs_mnt->mnt_sb->s_flags &= ~SB_NOUSER;
 }
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index ecb49870a680..de3226eae38d 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -473,7 +473,7 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
 
 #ifndef NTFS_RW
 	/* For read-only compiled driver, enforce read-only flag. */
-	*flags |= MS_RDONLY;
+	*flags |= SB_RDONLY;
 #else /* NTFS_RW */
 	/*
 	 * For the read-write compiled driver, if we are remounting read-write,
@@ -487,7 +487,7 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
 	 * When remounting read-only, mark the volume clean if no volume errors
 	 * have occurred.
 	 */
-	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
+	if ((sb->s_flags & SB_RDONLY) && !(*flags & SB_RDONLY)) {
 		static const char *es = ".  Cannot remount read-write.";
 
 		/* Remounting read-write. */
@@ -548,7 +548,7 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
 			NVolSetErrors(vol);
 			return -EROFS;
 		}
-	} else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) {
+	} else if (!(sb->s_flags & SB_RDONLY) && (*flags & SB_RDONLY)) {
 		/* Remounting read-only. */
 		if (!NVolErrors(vol)) {
 			if (ntfs_clear_volume_flags(vol, VOLUME_IS_DIRTY))
@@ -732,7 +732,7 @@ static struct buffer_head *read_ntfs_boot_sector(struct super_block *sb,
 		 * on a large sector device contains the whole boot loader or
 		 * just the first 512 bytes).
 		 */
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			ntfs_warning(sb, "Hot-fix: Recovering invalid primary "
 					"boot sector from backup copy.");
 			memcpy(bh_primary->b_data, bh_backup->b_data,
@@ -1789,7 +1789,7 @@ static bool load_system_files(ntfs_volume *vol)
 		static const char *es3 = ".  Run ntfsfix and/or chkdsk.";
 
 		/* If a read-write mount, convert it to a read-only mount. */
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
 					ON_ERRORS_CONTINUE))) {
 				ntfs_error(sb, "%s and neither on_errors="
@@ -1799,7 +1799,7 @@ static bool load_system_files(ntfs_volume *vol)
 						es3);
 				goto iput_mirr_err_out;
 			}
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			ntfs_error(sb, "%s.  Mounting read-only%s",
 					!vol->mftmirr_ino ? es1 : es2, es3);
 		} else
@@ -1928,7 +1928,7 @@ static bool load_system_files(ntfs_volume *vol)
 					(unsigned)le16_to_cpu(vol->vol_flags));
 		}
 		/* If a read-write mount, convert it to a read-only mount. */
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
 					ON_ERRORS_CONTINUE))) {
 				ntfs_error(sb, "%s and neither on_errors="
@@ -1937,7 +1937,7 @@ static bool load_system_files(ntfs_volume *vol)
 						es1, es2);
 				goto iput_vol_err_out;
 			}
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
 		} else
 			ntfs_warning(sb, "%s.  Will not be able to remount "
@@ -1961,7 +1961,7 @@ static bool load_system_files(ntfs_volume *vol)
 
 		es1 = !vol->logfile_ino ? es1a : es1b;
 		/* If a read-write mount, convert it to a read-only mount. */
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
 					ON_ERRORS_CONTINUE))) {
 				ntfs_error(sb, "%s and neither on_errors="
@@ -1974,7 +1974,7 @@ static bool load_system_files(ntfs_volume *vol)
 				}
 				goto iput_logfile_err_out;
 			}
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
 		} else
 			ntfs_warning(sb, "%s.  Will not be able to remount "
@@ -2010,7 +2010,7 @@ static bool load_system_files(ntfs_volume *vol)
 
 		es1 = err < 0 ? es1a : es1b;
 		/* If a read-write mount, convert it to a read-only mount. */
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
 					ON_ERRORS_CONTINUE))) {
 				ntfs_error(sb, "%s and neither on_errors="
@@ -2019,7 +2019,7 @@ static bool load_system_files(ntfs_volume *vol)
 						es1, es2);
 				goto iput_root_err_out;
 			}
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
 		} else
 			ntfs_warning(sb, "%s.  Will not be able to remount "
@@ -2028,7 +2028,7 @@ static bool load_system_files(ntfs_volume *vol)
 		NVolSetErrors(vol);
 	}
 	/* If (still) a read-write mount, mark the volume dirty. */
-	if (!(sb->s_flags & MS_RDONLY) &&
+	if (!(sb->s_flags & SB_RDONLY) &&
 			ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) {
 		static const char *es1 = "Failed to set dirty bit in volume "
 				"information flags";
@@ -2043,7 +2043,7 @@ static bool load_system_files(ntfs_volume *vol)
 			goto iput_root_err_out;
 		}
 		ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		/*
 		 * Do not set NVolErrors() because ntfs_remount() might manage
 		 * to set the dirty flag in which case all would be well.
@@ -2056,7 +2056,7 @@ static bool load_system_files(ntfs_volume *vol)
 	 * If (still) a read-write mount, set the NT4 compatibility flag on
 	 * newer NTFS version volumes.
 	 */
-	if (!(sb->s_flags & MS_RDONLY) && (vol->major_ver > 1) &&
+	if (!(sb->s_flags & SB_RDONLY) && (vol->major_ver > 1) &&
 			ntfs_set_volume_flags(vol, VOLUME_MOUNTED_ON_NT4)) {
 		static const char *es1 = "Failed to set NT4 compatibility flag";
 		static const char *es2 = ".  Run chkdsk.";
@@ -2070,12 +2070,12 @@ static bool load_system_files(ntfs_volume *vol)
 			goto iput_root_err_out;
 		}
 		ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		NVolSetErrors(vol);
 	}
 #endif
 	/* If (still) a read-write mount, empty the logfile. */
-	if (!(sb->s_flags & MS_RDONLY) &&
+	if (!(sb->s_flags & SB_RDONLY) &&
 			!ntfs_empty_logfile(vol->logfile_ino)) {
 		static const char *es1 = "Failed to empty $LogFile";
 		static const char *es2 = ".  Mount in Windows.";
@@ -2089,7 +2089,7 @@ static bool load_system_files(ntfs_volume *vol)
 			goto iput_root_err_out;
 		}
 		ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		NVolSetErrors(vol);
 	}
 #endif /* NTFS_RW */
@@ -2121,7 +2121,7 @@ static bool load_system_files(ntfs_volume *vol)
 		static const char *es2 = ".  Run chkdsk.";
 
 		/* If a read-write mount, convert it to a read-only mount. */
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
 					ON_ERRORS_CONTINUE))) {
 				ntfs_error(sb, "%s and neither on_errors="
@@ -2130,7 +2130,7 @@ static bool load_system_files(ntfs_volume *vol)
 						es1, es2);
 				goto iput_quota_err_out;
 			}
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
 		} else
 			ntfs_warning(sb, "%s.  Will not be able to remount "
@@ -2139,7 +2139,7 @@ static bool load_system_files(ntfs_volume *vol)
 		NVolSetErrors(vol);
 	}
 	/* If (still) a read-write mount, mark the quotas out of date. */
-	if (!(sb->s_flags & MS_RDONLY) &&
+	if (!(sb->s_flags & SB_RDONLY) &&
 			!ntfs_mark_quotas_out_of_date(vol)) {
 		static const char *es1 = "Failed to mark quotas out of date";
 		static const char *es2 = ".  Run chkdsk.";
@@ -2153,7 +2153,7 @@ static bool load_system_files(ntfs_volume *vol)
 			goto iput_quota_err_out;
 		}
 		ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		NVolSetErrors(vol);
 	}
 	/*
@@ -2165,7 +2165,7 @@ static bool load_system_files(ntfs_volume *vol)
 		static const char *es2 = ".  Run chkdsk.";
 
 		/* If a read-write mount, convert it to a read-only mount. */
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
 					ON_ERRORS_CONTINUE))) {
 				ntfs_error(sb, "%s and neither on_errors="
@@ -2174,7 +2174,7 @@ static bool load_system_files(ntfs_volume *vol)
 						es1, es2);
 				goto iput_usnjrnl_err_out;
 			}
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
 		} else
 			ntfs_warning(sb, "%s.  Will not be able to remount "
@@ -2183,7 +2183,7 @@ static bool load_system_files(ntfs_volume *vol)
 		NVolSetErrors(vol);
 	}
 	/* If (still) a read-write mount, stamp the transaction log. */
-	if (!(sb->s_flags & MS_RDONLY) && !ntfs_stamp_usnjrnl(vol)) {
+	if (!(sb->s_flags & SB_RDONLY) && !ntfs_stamp_usnjrnl(vol)) {
 		static const char *es1 = "Failed to stamp transaction log "
 				"($UsnJrnl)";
 		static const char *es2 = ".  Run chkdsk.";
@@ -2197,7 +2197,7 @@ static bool load_system_files(ntfs_volume *vol)
 			goto iput_usnjrnl_err_out;
 		}
 		ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		NVolSetErrors(vol);
 	}
 #endif /* NTFS_RW */
@@ -2314,7 +2314,7 @@ static void ntfs_put_super(struct super_block *sb)
 	 * If a read-write mount and no volume errors have occurred, mark the
 	 * volume clean.  Also, re-commit all affected inodes.
 	 */
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		if (!NVolErrors(vol)) {
 			if (ntfs_clear_volume_flags(vol, VOLUME_IS_DIRTY))
 				ntfs_warning(sb, "Failed to clear dirty bit "
@@ -2731,7 +2731,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
 	lockdep_off();
 	ntfs_debug("Entering.");
 #ifndef NTFS_RW
-	sb->s_flags |= MS_RDONLY;
+	sb->s_flags |= SB_RDONLY;
 #endif /* ! NTFS_RW */
 	/* Allocate a new ntfs_volume and place it in sb->s_fs_info. */
 	sb->s_fs_info = kmalloc(sizeof(ntfs_volume), GFP_NOFS);
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index bfeb647459d9..57bb8b978cd3 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -227,7 +227,7 @@ int ocfs2_should_update_atime(struct inode *inode,
 		return 0;
 
 	if ((inode->i_flags & S_NOATIME) ||
-	    ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)))
+	    ((inode->i_sb->s_flags & SB_NODIRATIME) && S_ISDIR(inode->i_mode)))
 		return 0;
 
 	/*
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index ca1646fbcaef..a869c2bc2f16 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -675,9 +675,9 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 	}
 
 	/* We're going to/from readonly mode. */
-	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
+	if ((*flags & SB_RDONLY) != (sb->s_flags & SB_RDONLY)) {
 		/* Disable quota accounting before remounting RO */
-		if (*flags & MS_RDONLY) {
+		if (*flags & SB_RDONLY) {
 			ret = ocfs2_susp_quotas(osb, 0);
 			if (ret < 0)
 				goto out;
@@ -691,8 +691,8 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 			goto unlock_osb;
 		}
 
-		if (*flags & MS_RDONLY) {
-			sb->s_flags |= MS_RDONLY;
+		if (*flags & SB_RDONLY) {
+			sb->s_flags |= SB_RDONLY;
 			osb->osb_flags |= OCFS2_OSB_SOFT_RO;
 		} else {
 			if (osb->osb_flags & OCFS2_OSB_ERROR_FS) {
@@ -709,14 +709,14 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 				ret = -EINVAL;
 				goto unlock_osb;
 			}
-			sb->s_flags &= ~MS_RDONLY;
+			sb->s_flags &= ~SB_RDONLY;
 			osb->osb_flags &= ~OCFS2_OSB_SOFT_RO;
 		}
 		trace_ocfs2_remount(sb->s_flags, osb->osb_flags, *flags);
 unlock_osb:
 		spin_unlock(&osb->osb_lock);
 		/* Enable quota accounting after remounting RW */
-		if (!ret && !(*flags & MS_RDONLY)) {
+		if (!ret && !(*flags & SB_RDONLY)) {
 			if (sb_any_quota_suspended(sb))
 				ret = ocfs2_susp_quotas(osb, 1);
 			else
@@ -724,7 +724,7 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 			if (ret < 0) {
 				/* Return back changes... */
 				spin_lock(&osb->osb_lock);
-				sb->s_flags |= MS_RDONLY;
+				sb->s_flags |= SB_RDONLY;
 				osb->osb_flags |= OCFS2_OSB_SOFT_RO;
 				spin_unlock(&osb->osb_lock);
 				goto out;
@@ -744,9 +744,9 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 		if (!ocfs2_is_hard_readonly(osb))
 			ocfs2_set_journal_params(osb);
 
-		sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+		sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
 			((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) ?
-							MS_POSIXACL : 0);
+							SB_POSIXACL : 0);
 	}
 out:
 	return ret;
@@ -1057,13 +1057,13 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
 	sb->s_magic = OCFS2_SUPER_MAGIC;
 
-	sb->s_flags = (sb->s_flags & ~(MS_POSIXACL | MS_NOSEC)) |
-		((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+	sb->s_flags = (sb->s_flags & ~(SB_POSIXACL | SB_NOSEC)) |
+		((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) ? SB_POSIXACL : 0);
 
-	/* Hard readonly mode only if: bdev_read_only, MS_RDONLY,
+	/* Hard readonly mode only if: bdev_read_only, SB_RDONLY,
 	 * heartbeat=none */
 	if (bdev_read_only(sb->s_bdev)) {
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			status = -EACCES;
 			mlog(ML_ERROR, "Readonly device detected but readonly "
 			     "mount was not specified.\n");
@@ -1098,7 +1098,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	}
 
 	if (!ocfs2_is_hard_readonly(osb)) {
-		if (sb->s_flags & MS_RDONLY)
+		if (sb->s_flags & SB_RDONLY)
 			ocfs2_set_ro_flag(osb, 0);
 	}
 
@@ -1179,7 +1179,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	/* Now we can initialize quotas because we can afford to wait
 	 * for cluster locks recovery now. That also means that truncation
 	 * log recovery can happen but that waits for proper quota setup */
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		status = ocfs2_enable_quotas(osb);
 		if (status < 0) {
 			/* We have to err-out specially here because
@@ -2057,7 +2057,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
 	sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
 	sb->s_xattr = ocfs2_xattr_handlers;
 	sb->s_time_gran = 1;
-	sb->s_flags |= MS_NOATIME;
+	sb->s_flags |= SB_NOATIME;
 	/* this is needed to support O_LARGEFILE */
 	cbits = le32_to_cpu(di->id2.i_super.s_clustersize_bits);
 	bbits = le32_to_cpu(di->id2.i_super.s_blocksize_bits);
@@ -2180,7 +2180,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
 		status = -EINVAL;
 		goto bail;
 	}
-	if (!(osb->sb->s_flags & MS_RDONLY) &&
+	if (!(osb->sb->s_flags & SB_RDONLY) &&
 	    (i = OCFS2_HAS_RO_COMPAT_FEATURE(osb->sb, ~OCFS2_FEATURE_RO_COMPAT_SUPP))) {
 		mlog(ML_ERROR, "couldn't mount RDWR because of "
 		     "unsupported optional features (%x).\n", i);
@@ -2568,13 +2568,13 @@ static int ocfs2_handle_error(struct super_block *sb)
 		rv = -EIO;
 	} else { /* default option */
 		rv = -EROFS;
-		if (sb->s_flags & MS_RDONLY &&
+		if (sb->s_flags & SB_RDONLY &&
 				(ocfs2_is_soft_readonly(osb) ||
 				 ocfs2_is_hard_readonly(osb)))
 			return rv;
 
 		pr_crit("OCFS2: File system is now read-only.\n");
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 		ocfs2_set_ro_flag(osb, 0);
 	}
 
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 3c5384d9b3a5..deb31f986c26 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -901,7 +901,7 @@ static int ocfs2_xattr_list_entry(struct super_block *sb,
 
 	case OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS:
 	case OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT:
-		if (!(sb->s_flags & MS_POSIXACL))
+		if (!(sb->s_flags & SB_POSIXACL))
 			return 0;
 		break;
 
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 13215f26e321..2200662a9bf1 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -369,7 +369,7 @@ static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
 static int openprom_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_NOATIME;
+	*flags |= SB_NOATIME;
 	return 0;
 }
 
@@ -386,7 +386,7 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent)
 	struct op_inode_info *oi;
 	int ret;
 
-	s->s_flags |= MS_NOATIME;
+	s->s_flags |= SB_NOATIME;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = OPENPROM_SUPER_MAGIC;
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
index 5c7c273e17ec..4ad41f0872f6 100644
--- a/fs/orangefs/super.c
+++ b/fs/orangefs/super.c
@@ -46,7 +46,7 @@ static int parse_mount_options(struct super_block *sb, char *options,
 	 * Force any potential flags that might be set from the mount
 	 * to zero, ie, initialize to unset.
 	 */
-	sb->s_flags &= ~MS_POSIXACL;
+	sb->s_flags &= ~SB_POSIXACL;
 	orangefs_sb->flags &= ~ORANGEFS_OPT_INTR;
 	orangefs_sb->flags &= ~ORANGEFS_OPT_LOCAL_LOCK;
 
@@ -59,7 +59,7 @@ static int parse_mount_options(struct super_block *sb, char *options,
 		token = match_token(p, tokens, args);
 		switch (token) {
 		case Opt_acl:
-			sb->s_flags |= MS_POSIXACL;
+			sb->s_flags |= SB_POSIXACL;
 			break;
 		case Opt_intr:
 			orangefs_sb->flags |= ORANGEFS_OPT_INTR;
@@ -510,7 +510,7 @@ struct dentry *orangefs_mount(struct file_system_type *fst,
 
 	ret = orangefs_fill_sb(sb,
 	      &new_op->downcall.resp.fs_mount, data,
-	      flags & MS_SILENT ? 1 : 0);
+	      flags & SB_SILENT ? 1 : 0);
 
 	if (ret) {
 		d = ERR_PTR(ret);
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 4882ffb37bae..5315d3aaba2f 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -256,7 +256,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data)
 {
 	struct ovl_fs *ufs = sb->s_fs_info;
 
-	if (!(*flags & MS_RDONLY) && (!ufs->upper_mnt || !ufs->workdir))
+	if (!(*flags & SB_RDONLY) && (!ufs->upper_mnt || !ufs->workdir))
 		return -EROFS;
 
 	return 0;
@@ -778,7 +778,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 			goto out_free_config;
 
 		/* Upper fs should not be r/o */
-		if (upperpath.mnt->mnt_sb->s_flags & MS_RDONLY) {
+		if (upperpath.mnt->mnt_sb->s_flags & SB_RDONLY) {
 			pr_err("overlayfs: upper fs is r/o, try multi-lower layers mount\n");
 			err = -EINVAL;
 			goto out_put_upperpath;
@@ -859,7 +859,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 		if (IS_ERR(ufs->workdir)) {
 			pr_warn("overlayfs: failed to create directory %s/%s (errno: %i); mounting read-only\n",
 				ufs->config.workdir, OVL_WORKDIR_NAME, -err);
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			ufs->workdir = NULL;
 		}
 
@@ -937,7 +937,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
 	/* If the upper fs is nonexistent, we mark overlayfs r/o too */
 	if (!ufs->upper_mnt)
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	else if (ufs->upper_mnt->mnt_sb != ufs->same_sb)
 		ufs->same_sb = NULL;
 
@@ -962,7 +962,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_op = &ovl_super_operations;
 	sb->s_xattr = ovl_xattr_handlers;
 	sb->s_fs_info = ufs;
-	sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK;
+	sb->s_flags |= SB_POSIXACL | SB_NOREMOTELOCK;
 
 	root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
 	if (!root_dentry)
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index e250910cffc8..0163d71d5887 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -482,7 +482,7 @@ int proc_fill_super(struct super_block *s, void *data, int silent)
 
 	/* User space would break if executables or devices appear on proc */
 	s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
-	s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC;
+	s->s_flags |= SB_NODIRATIME | SB_NOSUID | SB_NOEXEC;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = PROC_SUPER_MAGIC;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index deecb397daa3..fd91901a299e 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -90,7 +90,7 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
 {
 	struct pid_namespace *ns;
 
-	if (flags & MS_KERNMOUNT) {
+	if (flags & SB_KERNMOUNT) {
 		ns = data;
 		data = NULL;
 	} else {
diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c
index b5713fefb4c1..7337f6be0706 100644
--- a/fs/proc_namespace.c
+++ b/fs/proc_namespace.c
@@ -44,10 +44,10 @@ struct proc_fs_info {
 static int show_sb_opts(struct seq_file *m, struct super_block *sb)
 {
 	static const struct proc_fs_info fs_info[] = {
-		{ MS_SYNCHRONOUS, ",sync" },
-		{ MS_DIRSYNC, ",dirsync" },
-		{ MS_MANDLOCK, ",mand" },
-		{ MS_LAZYTIME, ",lazytime" },
+		{ SB_SYNCHRONOUS, ",sync" },
+		{ SB_DIRSYNC, ",dirsync" },
+		{ SB_MANDLOCK, ",mand" },
+		{ SB_LAZYTIME, ",lazytime" },
 		{ 0, NULL }
 	};
 	const struct proc_fs_info *fs_infop;
@@ -178,7 +178,7 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
 	} else {
 		mangle(m, r->mnt_devname ? r->mnt_devname : "none");
 	}
-	seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
+	seq_puts(m, sb->s_flags & SB_RDONLY ? " ro" : " rw");
 	err = show_sb_opts(m, sb);
 	if (err)
 		goto out;
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 3a67cfb142d8..3d46fe302fcb 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -47,7 +47,7 @@ static int qnx4_remount(struct super_block *sb, int *flags, char *data)
 	sync_filesystem(sb);
 	qs = qnx4_sb(sb);
 	qs->Version = QNX4_VERSION;
-	*flags |= MS_RDONLY;
+	*flags |= SB_RDONLY;
 	return 0;
 }
 
@@ -199,7 +199,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
 
 	s->s_op = &qnx4_sops;
 	s->s_magic = QNX4_SUPER_MAGIC;
-	s->s_flags |= MS_RDONLY;	/* Yup, read-only yet */
+	s->s_flags |= SB_RDONLY;	/* Yup, read-only yet */
 
 	/* Check the superblock signature. Since the qnx4 code is
 	   dangerous, we should leave as quickly as possible
diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c
index 1192422a1c56..4aeb26bcb4d0 100644
--- a/fs/qnx6/inode.c
+++ b/fs/qnx6/inode.c
@@ -56,7 +56,7 @@ static int qnx6_show_options(struct seq_file *seq, struct dentry *root)
 static int qnx6_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_RDONLY;
+	*flags |= SB_RDONLY;
 	return 0;
 }
 
@@ -427,7 +427,7 @@ static int qnx6_fill_super(struct super_block *s, void *data, int silent)
 	}
 	s->s_op = &qnx6_sops;
 	s->s_magic = QNX6_SUPER_MAGIC;
-	s->s_flags |= MS_RDONLY;        /* Yup, read-only yet */
+	s->s_flags |= SB_RDONLY;        /* Yup, read-only yet */
 
 	/* ease the later tree level calculations */
 	sbi = QNX6_SB(s);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 07e08c7d05ca..de9aec3ee26e 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -753,7 +753,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
 	case Q_XGETNEXTQUOTA:
 		return quota_getnextxquota(sb, type, id, addr);
 	case Q_XQUOTASYNC:
-		if (sb->s_flags & MS_RDONLY)
+		if (sb->s_flags & SB_RDONLY)
 			return -EROFS;
 		/* XFS quotas are fully coherent now, making this call a noop */
 		return 0;
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 873fc04e9403..a227e7de1520 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1776,7 +1776,7 @@ int reiserfs_write_inode(struct inode *inode, struct writeback_control *wbc)
 	struct reiserfs_transaction_handle th;
 	int jbegin_count = 1;
 
-	if (inode->i_sb->s_flags & MS_RDONLY)
+	if (inode->i_sb->s_flags & SB_RDONLY)
 		return -EROFS;
 	/*
 	 * memory pressure can sometimes initiate write_inode calls with
@@ -2106,7 +2106,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
 			journal_end(th);
 			goto out_inserted_sd;
 		}
-	} else if (inode->i_sb->s_flags & MS_POSIXACL) {
+	} else if (inode->i_sb->s_flags & SB_POSIXACL) {
 		reiserfs_warning(inode->i_sb, "jdm-13090",
 				 "ACLs aren't enabled in the fs, "
 				 "but vfs thinks they are!");
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 39bb1e838d8d..2ed304ee5b4c 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -1918,7 +1918,7 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
 	 * we only want to flush out transactions if we were
 	 * called with error == 0
 	 */
-	if (!error && !(sb->s_flags & MS_RDONLY)) {
+	if (!error && !(sb->s_flags & SB_RDONLY)) {
 		/* end the current trans */
 		BUG_ON(!th->t_trans_id);
 		do_journal_end(th, FLUSH_ALL);
@@ -1959,7 +1959,7 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
 	/*
 	 * Cancel flushing of old commits. Note that neither of these works
 	 * will be requeued because superblock is being shutdown and doesn't
-	 * have MS_ACTIVE set.
+	 * have SB_ACTIVE set.
 	 */
 	reiserfs_cancel_old_flush(sb);
 	/* wait for all commits to finish */
@@ -4301,7 +4301,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, int flags)
 		 * Avoid queueing work when sb is being shut down. Transaction
 		 * will be flushed on journal shutdown.
 		 */
-		if (sb->s_flags & MS_ACTIVE)
+		if (sb->s_flags & SB_ACTIVE)
 			queue_delayed_work(REISERFS_SB(sb)->commit_wq,
 					   &journal->j_work, HZ / 10);
 	}
@@ -4392,7 +4392,7 @@ void reiserfs_abort_journal(struct super_block *sb, int errno)
 	if (!journal->j_errno)
 		journal->j_errno = errno;
 
-	sb->s_flags |= MS_RDONLY;
+	sb->s_flags |= SB_RDONLY;
 	set_bit(J_ABORTED, &journal->j_state);
 
 #ifdef CONFIG_REISERFS_CHECK
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
index 4f3f928076f3..696069ac16b5 100644
--- a/fs/reiserfs/prints.c
+++ b/fs/reiserfs/prints.c
@@ -386,11 +386,11 @@ void __reiserfs_error(struct super_block *sb, const char *id,
 		printk(KERN_CRIT "REISERFS error (device %s): %s: %s\n",
 		       sb->s_id, function, error_buf);
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return;
 
 	reiserfs_info(sb, "Remounting filesystem read-only\n");
-	sb->s_flags |= MS_RDONLY;
+	sb->s_flags |= SB_RDONLY;
 	reiserfs_abort_journal(sb, -EIO);
 }
 
@@ -409,7 +409,7 @@ void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...)
 	printk(KERN_CRIT "REISERFS abort (device %s): %s\n", sb->s_id,
 	       error_buf);
 
-	sb->s_flags |= MS_RDONLY;
+	sb->s_flags |= SB_RDONLY;
 	reiserfs_abort_journal(sb, errno);
 }
 
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 685f1e056998..775ec50f3fb2 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -121,7 +121,7 @@ void reiserfs_schedule_old_flush(struct super_block *s)
 	 * Avoid scheduling flush when sb is being shut down. It can race
 	 * with journal shutdown and free still queued delayed work.
 	 */
-	if (s->s_flags & MS_RDONLY || !(s->s_flags & MS_ACTIVE))
+	if (s->s_flags & SB_RDONLY || !(s->s_flags & SB_ACTIVE))
 		return;
 
 	spin_lock(&sbi->old_work_lock);
@@ -151,7 +151,7 @@ static int reiserfs_freeze(struct super_block *s)
 	reiserfs_cancel_old_flush(s);
 
 	reiserfs_write_lock(s);
-	if (!(s->s_flags & MS_RDONLY)) {
+	if (!(s->s_flags & SB_RDONLY)) {
 		int err = journal_begin(&th, s, 1);
 		if (err) {
 			reiserfs_block_writes(&th);
@@ -252,11 +252,11 @@ static int finish_unfinished(struct super_block *s)
 
 #ifdef CONFIG_QUOTA
 	/* Needed for iput() to work correctly and not trash data */
-	if (s->s_flags & MS_ACTIVE) {
+	if (s->s_flags & SB_ACTIVE) {
 		ms_active_set = 0;
 	} else {
 		ms_active_set = 1;
-		s->s_flags |= MS_ACTIVE;
+		s->s_flags |= SB_ACTIVE;
 	}
 	/* Turn on quotas so that they are updated correctly */
 	for (i = 0; i < REISERFS_MAXQUOTAS; i++) {
@@ -411,7 +411,7 @@ static int finish_unfinished(struct super_block *s)
 	reiserfs_write_lock(s);
 	if (ms_active_set)
 		/* Restore the flag back */
-		s->s_flags &= ~MS_ACTIVE;
+		s->s_flags &= ~SB_ACTIVE;
 #endif
 	pathrelse(&path);
 	if (done)
@@ -599,7 +599,7 @@ static void reiserfs_put_super(struct super_block *s)
 	 * change file system state to current state if it was mounted
 	 * with read-write permissions
 	 */
-	if (!(s->s_flags & MS_RDONLY)) {
+	if (!(s->s_flags & SB_RDONLY)) {
 		if (!journal_begin(&th, s, 10)) {
 			reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
 						     1);
@@ -700,7 +700,7 @@ static void reiserfs_dirty_inode(struct inode *inode, int flags)
 
 	int err = 0;
 
-	if (inode->i_sb->s_flags & MS_RDONLY) {
+	if (inode->i_sb->s_flags & SB_RDONLY) {
 		reiserfs_warning(inode->i_sb, "clm-6006",
 				 "writing inode %lu on readonly FS",
 				 inode->i_ino);
@@ -1521,11 +1521,11 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
 			goto out_err_unlock;
 	}
 
-	if (*mount_flags & MS_RDONLY) {
+	if (*mount_flags & SB_RDONLY) {
 		reiserfs_write_unlock(s);
 		reiserfs_xattr_init(s, *mount_flags);
 		/* remount read-only */
-		if (s->s_flags & MS_RDONLY)
+		if (s->s_flags & SB_RDONLY)
 			/* it is read-only already */
 			goto out_ok_unlocked;
 
@@ -1551,7 +1551,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
 		journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));
 	} else {
 		/* remount read-write */
-		if (!(s->s_flags & MS_RDONLY)) {
+		if (!(s->s_flags & SB_RDONLY)) {
 			reiserfs_write_unlock(s);
 			reiserfs_xattr_init(s, *mount_flags);
 			goto out_ok_unlocked;	/* We are read-write already */
@@ -1567,7 +1567,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
 		REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
 
 		/* now it is safe to call journal_begin */
-		s->s_flags &= ~MS_RDONLY;
+		s->s_flags &= ~SB_RDONLY;
 		err = journal_begin(&th, s, 10);
 		if (err)
 			goto out_err_unlock;
@@ -1575,7 +1575,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
 		/* Mount a partition which is read-only, read-write */
 		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
 		REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
-		s->s_flags &= ~MS_RDONLY;
+		s->s_flags &= ~SB_RDONLY;
 		set_sb_umount_state(rs, REISERFS_ERROR_FS);
 		if (!old_format_only(s))
 			set_sb_mnt_count(rs, sb_mnt_count(rs) + 1);
@@ -1590,7 +1590,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
 		goto out_err_unlock;
 
 	reiserfs_write_unlock(s);
-	if (!(*mount_flags & MS_RDONLY)) {
+	if (!(*mount_flags & SB_RDONLY)) {
 		dquot_resume(s, -1);
 		reiserfs_write_lock(s);
 		finish_unfinished(s);
@@ -1857,7 +1857,7 @@ static int what_hash(struct super_block *s)
 	 * the super
 	 */
 	if (code != UNSET_HASH &&
-	    !(s->s_flags & MS_RDONLY) &&
+	    !(s->s_flags & SB_RDONLY) &&
 	    code != sb_hash_function_code(SB_DISK_SUPER_BLOCK(s))) {
 		set_sb_hash_function_code(SB_DISK_SUPER_BLOCK(s), code);
 	}
@@ -2056,10 +2056,10 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
 	if (replay_only(s))
 		goto error_unlocked;
 
-	if (bdev_read_only(s->s_bdev) && !(s->s_flags & MS_RDONLY)) {
+	if (bdev_read_only(s->s_bdev) && !(s->s_flags & SB_RDONLY)) {
 		SWARN(silent, s, "clm-7000",
 		      "Detected readonly device, marking FS readonly");
-		s->s_flags |= MS_RDONLY;
+		s->s_flags |= SB_RDONLY;
 	}
 	args.objectid = REISERFS_ROOT_OBJECTID;
 	args.dirid = REISERFS_ROOT_PARENT_OBJECTID;
@@ -2105,7 +2105,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
 	else
 		set_bit(REISERFS_3_6, &sbi->s_properties);
 
-	if (!(s->s_flags & MS_RDONLY)) {
+	if (!(s->s_flags & SB_RDONLY)) {
 
 		errval = journal_begin(&th, s, 1);
 		if (errval) {
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index e87aa21c30de..418031941ab2 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -958,7 +958,7 @@ int reiserfs_lookup_privroot(struct super_block *s)
 
 /*
  * We need to take a copy of the mount flags since things like
- * MS_RDONLY don't get set until *after* we're called.
+ * SB_RDONLY don't get set until *after* we're called.
  * mount_flags != mount_options
  */
 int reiserfs_xattr_init(struct super_block *s, int mount_flags)
@@ -970,7 +970,7 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
 	if (err)
 		goto error;
 
-	if (d_really_is_negative(privroot) && !(mount_flags & MS_RDONLY)) {
+	if (d_really_is_negative(privroot) && !(mount_flags & SB_RDONLY)) {
 		inode_lock(d_inode(s->s_root));
 		err = create_privroot(REISERFS_SB(s)->priv_root);
 		inode_unlock(d_inode(s->s_root));
@@ -998,11 +998,11 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
 		clear_bit(REISERFS_POSIXACL, &REISERFS_SB(s)->s_mount_opt);
 	}
 
-	/* The super_block MS_POSIXACL must mirror the (no)acl mount option. */
+	/* The super_block SB_POSIXACL must mirror the (no)acl mount option. */
 	if (reiserfs_posixacl(s))
-		s->s_flags |= MS_POSIXACL;
+		s->s_flags |= SB_POSIXACL;
 	else
-		s->s_flags &= ~MS_POSIXACL;
+		s->s_flags &= ~SB_POSIXACL;
 
 	return err;
 }
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index 0186fe6d39f3..8f06fd1f3d69 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -451,7 +451,7 @@ static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 static int romfs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_RDONLY;
+	*flags |= SB_RDONLY;
 	return 0;
 }
 
@@ -502,7 +502,7 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent)
 
 	sb->s_maxbytes = 0xFFFFFFFF;
 	sb->s_magic = ROMFS_MAGIC;
-	sb->s_flags |= MS_RDONLY | MS_NOATIME;
+	sb->s_flags |= SB_RDONLY | SB_NOATIME;
 	sb->s_op = &romfs_super_ops;
 
 #ifdef CONFIG_ROMFS_ON_MTD
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index cf01e15a7b16..8a73b97217c8 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -195,7 +195,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
 		(u64) le64_to_cpu(sblk->id_table_start));
 
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
-	sb->s_flags |= MS_RDONLY;
+	sb->s_flags |= SB_RDONLY;
 	sb->s_op = &squashfs_super_ops;
 
 	err = -ENOMEM;
@@ -373,7 +373,7 @@ static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 static int squashfs_remount(struct super_block *sb, int *flags, char *data)
 {
 	sync_filesystem(sb);
-	*flags |= MS_RDONLY;
+	*flags |= SB_RDONLY;
 	return 0;
 }
 
diff --git a/fs/statfs.c b/fs/statfs.c
index 4e4623c7a126..b1d5f195943c 100644
--- a/fs/statfs.c
+++ b/fs/statfs.c
@@ -34,9 +34,9 @@ static int flags_by_mnt(int mnt_flags)
 static int flags_by_sb(int s_flags)
 {
 	int flags = 0;
-	if (s_flags & MS_SYNCHRONOUS)
+	if (s_flags & SB_SYNCHRONOUS)
 		flags |= ST_SYNCHRONOUS;
-	if (s_flags & MS_MANDLOCK)
+	if (s_flags & SB_MANDLOCK)
 		flags |= ST_MANDLOCK;
 	return flags;
 }
diff --git a/fs/super.c b/fs/super.c
index dfb56a9665d8..e55911d31821 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -361,7 +361,7 @@ static int grab_super(struct super_block *s) __releases(sb_lock)
 	s->s_count++;
 	spin_unlock(&sb_lock);
 	down_write(&s->s_umount);
-	if ((s->s_flags & MS_BORN) && atomic_inc_not_zero(&s->s_active)) {
+	if ((s->s_flags & SB_BORN) && atomic_inc_not_zero(&s->s_active)) {
 		put_super(s);
 		return 1;
 	}
@@ -391,7 +391,7 @@ bool trylock_super(struct super_block *sb)
 {
 	if (down_read_trylock(&sb->s_umount)) {
 		if (!hlist_unhashed(&sb->s_instances) &&
-		    sb->s_root && (sb->s_flags & MS_BORN))
+		    sb->s_root && (sb->s_flags & SB_BORN))
 			return true;
 		up_read(&sb->s_umount);
 	}
@@ -420,7 +420,7 @@ void generic_shutdown_super(struct super_block *sb)
 	if (sb->s_root) {
 		shrink_dcache_for_umount(sb);
 		sync_filesystem(sb);
-		sb->s_flags &= ~MS_ACTIVE;
+		sb->s_flags &= ~SB_ACTIVE;
 
 		fsnotify_unmount_inodes(sb);
 		cgroup_writeback_umount();
@@ -473,7 +473,7 @@ struct super_block *sget_userns(struct file_system_type *type,
 	struct super_block *old;
 	int err;
 
-	if (!(flags & (MS_KERNMOUNT|MS_SUBMOUNT)) &&
+	if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) &&
 	    !(type->fs_flags & FS_USERNS_MOUNT) &&
 	    !capable(CAP_SYS_ADMIN))
 		return ERR_PTR(-EPERM);
@@ -503,7 +503,7 @@ struct super_block *sget_userns(struct file_system_type *type,
 	}
 	if (!s) {
 		spin_unlock(&sb_lock);
-		s = alloc_super(type, (flags & ~MS_SUBMOUNT), user_ns);
+		s = alloc_super(type, (flags & ~SB_SUBMOUNT), user_ns);
 		if (!s)
 			return ERR_PTR(-ENOMEM);
 		goto retry;
@@ -548,11 +548,11 @@ struct super_block *sget(struct file_system_type *type,
 	 * mount through to here so always use &init_user_ns
 	 * until that changes.
 	 */
-	if (flags & MS_SUBMOUNT)
+	if (flags & SB_SUBMOUNT)
 		user_ns = &init_user_ns;
 
 	/* Ensure the requestor has permissions over the target filesystem */
-	if (!(flags & (MS_KERNMOUNT|MS_SUBMOUNT)) && !ns_capable(user_ns, CAP_SYS_ADMIN))
+	if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) && !ns_capable(user_ns, CAP_SYS_ADMIN))
 		return ERR_PTR(-EPERM);
 
 	return sget_userns(type, test, set, flags, user_ns, data);
@@ -595,7 +595,7 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg)
 		spin_unlock(&sb_lock);
 
 		down_read(&sb->s_umount);
-		if (sb->s_root && (sb->s_flags & MS_BORN))
+		if (sb->s_root && (sb->s_flags & SB_BORN))
 			f(sb, arg);
 		up_read(&sb->s_umount);
 
@@ -629,7 +629,7 @@ void iterate_supers_type(struct file_system_type *type,
 		spin_unlock(&sb_lock);
 
 		down_read(&sb->s_umount);
-		if (sb->s_root && (sb->s_flags & MS_BORN))
+		if (sb->s_root && (sb->s_flags & SB_BORN))
 			f(sb, arg);
 		up_read(&sb->s_umount);
 
@@ -665,7 +665,7 @@ static struct super_block *__get_super(struct block_device *bdev, bool excl)
 			else
 				down_write(&sb->s_umount);
 			/* still alive? */
-			if (sb->s_root && (sb->s_flags & MS_BORN))
+			if (sb->s_root && (sb->s_flags & SB_BORN))
 				return sb;
 			if (!excl)
 				up_read(&sb->s_umount);
@@ -786,7 +786,7 @@ struct super_block *user_get_super(dev_t dev)
 			spin_unlock(&sb_lock);
 			down_read(&sb->s_umount);
 			/* still alive? */
-			if (sb->s_root && (sb->s_flags & MS_BORN))
+			if (sb->s_root && (sb->s_flags & SB_BORN))
 				return sb;
 			up_read(&sb->s_umount);
 			/* nope, got unmounted */
@@ -802,7 +802,7 @@ struct super_block *user_get_super(dev_t dev)
 /**
  *	do_remount_sb - asks filesystem to change mount options.
  *	@sb:	superblock in question
- *	@flags:	numeric part of options
+ *	@flags:	MS_* flags translated into SB_* flags
  *	@data:	the rest of options
  *      @force: whether or not to force the change
  *
@@ -817,11 +817,11 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 		return -EBUSY;
 
 #ifdef CONFIG_BLOCK
-	if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
+	if (!(flags & SB_RDONLY) && bdev_read_only(sb->s_bdev))
 		return -EACCES;
 #endif
 
-	remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY);
+	remount_ro = (flags & SB_RDONLY) && !(sb->s_flags & SB_RDONLY);
 
 	if (remount_ro) {
 		if (!hlist_empty(&sb->s_pins)) {
@@ -832,7 +832,7 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 				return 0;
 			if (sb->s_writers.frozen != SB_UNFROZEN)
 				return -EBUSY;
-			remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY);
+			remount_ro = (flags & SB_RDONLY) && !(sb->s_flags & SB_RDONLY);
 		}
 	}
 	shrink_dcache_sb(sb);
@@ -893,12 +893,12 @@ static void do_emergency_remount(struct work_struct *work)
 		sb->s_count++;
 		spin_unlock(&sb_lock);
 		down_write(&sb->s_umount);
-		if (sb->s_root && sb->s_bdev && (sb->s_flags & MS_BORN) &&
-		    !(sb->s_flags & MS_RDONLY)) {
+		if (sb->s_root && sb->s_bdev && (sb->s_flags & SB_BORN) &&
+		    !(sb->s_flags & SB_RDONLY)) {
 			/*
 			 * What lock protects sb->s_flags??
 			 */
-			do_remount_sb(sb, MS_RDONLY, NULL, 1);
+			do_remount_sb(sb, SB_RDONLY, NULL, 1);
 		}
 		up_write(&sb->s_umount);
 		spin_lock(&sb_lock);
@@ -1024,7 +1024,7 @@ struct dentry *mount_ns(struct file_system_type *fs_type,
 	/* Don't allow mounting unless the caller has CAP_SYS_ADMIN
 	 * over the namespace.
 	 */
-	if (!(flags & MS_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN))
+	if (!(flags & SB_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN))
 		return ERR_PTR(-EPERM);
 
 	sb = sget_userns(fs_type, ns_test_super, ns_set_super, flags,
@@ -1034,13 +1034,13 @@ struct dentry *mount_ns(struct file_system_type *fs_type,
 
 	if (!sb->s_root) {
 		int err;
-		err = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
+		err = fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
 		if (err) {
 			deactivate_locked_super(sb);
 			return ERR_PTR(err);
 		}
 
-		sb->s_flags |= MS_ACTIVE;
+		sb->s_flags |= SB_ACTIVE;
 	}
 
 	return dget(sb->s_root);
@@ -1072,7 +1072,7 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
 	fmode_t mode = FMODE_READ | FMODE_EXCL;
 	int error = 0;
 
-	if (!(flags & MS_RDONLY))
+	if (!(flags & SB_RDONLY))
 		mode |= FMODE_WRITE;
 
 	bdev = blkdev_get_by_path(dev_name, mode, fs_type);
@@ -1090,14 +1090,14 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
 		error = -EBUSY;
 		goto error_bdev;
 	}
-	s = sget(fs_type, test_bdev_super, set_bdev_super, flags | MS_NOSEC,
+	s = sget(fs_type, test_bdev_super, set_bdev_super, flags | SB_NOSEC,
 		 bdev);
 	mutex_unlock(&bdev->bd_fsfreeze_mutex);
 	if (IS_ERR(s))
 		goto error_s;
 
 	if (s->s_root) {
-		if ((flags ^ s->s_flags) & MS_RDONLY) {
+		if ((flags ^ s->s_flags) & SB_RDONLY) {
 			deactivate_locked_super(s);
 			error = -EBUSY;
 			goto error_bdev;
@@ -1117,13 +1117,13 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
 		s->s_mode = mode;
 		snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
 		sb_set_blocksize(s, block_size(bdev));
-		error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+		error = fill_super(s, data, flags & SB_SILENT ? 1 : 0);
 		if (error) {
 			deactivate_locked_super(s);
 			goto error;
 		}
 
-		s->s_flags |= MS_ACTIVE;
+		s->s_flags |= SB_ACTIVE;
 		bdev->bd_super = s;
 	}
 
@@ -1163,12 +1163,12 @@ struct dentry *mount_nodev(struct file_system_type *fs_type,
 	if (IS_ERR(s))
 		return ERR_CAST(s);
 
-	error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+	error = fill_super(s, data, flags & SB_SILENT ? 1 : 0);
 	if (error) {
 		deactivate_locked_super(s);
 		return ERR_PTR(error);
 	}
-	s->s_flags |= MS_ACTIVE;
+	s->s_flags |= SB_ACTIVE;
 	return dget(s->s_root);
 }
 EXPORT_SYMBOL(mount_nodev);
@@ -1189,12 +1189,12 @@ struct dentry *mount_single(struct file_system_type *fs_type,
 	if (IS_ERR(s))
 		return ERR_CAST(s);
 	if (!s->s_root) {
-		error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+		error = fill_super(s, data, flags & SB_SILENT ? 1 : 0);
 		if (error) {
 			deactivate_locked_super(s);
 			return ERR_PTR(error);
 		}
-		s->s_flags |= MS_ACTIVE;
+		s->s_flags |= SB_ACTIVE;
 	} else {
 		do_remount_sb(s, flags, data, 0);
 	}
@@ -1228,7 +1228,7 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
 	sb = root->d_sb;
 	BUG_ON(!sb);
 	WARN_ON(!sb->s_bdi);
-	sb->s_flags |= MS_BORN;
+	sb->s_flags |= SB_BORN;
 
 	error = security_sb_kern_mount(sb, flags, secdata);
 	if (error)
@@ -1435,12 +1435,12 @@ int freeze_super(struct super_block *sb)
 		return -EBUSY;
 	}
 
-	if (!(sb->s_flags & MS_BORN)) {
+	if (!(sb->s_flags & SB_BORN)) {
 		up_write(&sb->s_umount);
 		return 0;	/* sic - it's "nothing to do" */
 	}
 
-	if (sb->s_flags & MS_RDONLY) {
+	if (sb->s_flags & SB_RDONLY) {
 		/* Nothing to do really... */
 		sb->s_writers.frozen = SB_FREEZE_COMPLETE;
 		up_write(&sb->s_umount);
@@ -1503,7 +1503,7 @@ int thaw_super(struct super_block *sb)
 		return -EINVAL;
 	}
 
-	if (sb->s_flags & MS_RDONLY) {
+	if (sb->s_flags & SB_RDONLY) {
 		sb->s_writers.frozen = SB_UNFROZEN;
 		goto out;
 	}
diff --git a/fs/sync.c b/fs/sync.c
index 11ba023434b1..4d5557958a40 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -57,7 +57,7 @@ int sync_filesystem(struct super_block *sb)
 	/*
 	 * No point in syncing out anything if the filesystem is read-only.
 	 */
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return 0;
 
 	ret = __sync_filesystem(sb, 0);
@@ -69,13 +69,13 @@ EXPORT_SYMBOL(sync_filesystem);
 
 static void sync_inodes_one_sb(struct super_block *sb, void *arg)
 {
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		sync_inodes_sb(sb);
 }
 
 static void sync_fs_one_sb(struct super_block *sb, void *arg)
 {
-	if (!(sb->s_flags & MS_RDONLY) && sb->s_op->sync_fs)
+	if (!(sb->s_flags & SB_RDONLY) && sb->s_op->sync_fs)
 		sb->s_op->sync_fs(sb, *(int *)arg);
 }
 
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 20b8f82e115b..fb49510c5dcf 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -30,7 +30,7 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 	void *ns;
 	bool new_sb;
 
-	if (!(flags & MS_KERNMOUNT)) {
+	if (!(flags & SB_KERNMOUNT)) {
 		if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET))
 			return ERR_PTR(-EPERM);
 	}
diff --git a/fs/sysv/balloc.c b/fs/sysv/balloc.c
index 921c053fc052..aa69fa9d523a 100644
--- a/fs/sysv/balloc.c
+++ b/fs/sysv/balloc.c
@@ -231,7 +231,7 @@ unsigned long sysv_count_free_blocks(struct super_block * sb)
 Ecount:
 	printk("sysv_count_free_blocks: free block count was %d, "
 		"correcting to %d\n", sb_count, count);
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		*sbi->s_free_blocks = cpu_to_fs32(sbi, count);
 		dirty_sb(sb);
 	}
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 53f1b78996dd..733896b93943 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -220,7 +220,7 @@ unsigned long sysv_count_free_inodes(struct super_block * sb)
 	printk("sysv_count_free_inodes: "
 		"free inode count was %d, correcting to %d\n",
 		sb_count, count);
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		*sbi->s_sb_total_free_inodes = cpu_to_fs16(SYSV_SB(sb), count);
 		dirty_sb(sb);
 	}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 858fb72f9e0f..05961e8bd6dd 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -62,7 +62,7 @@ static int sysv_remount(struct super_block *sb, int *flags, char *data)
 
 	sync_filesystem(sb);
 	if (sbi->s_forced_ro)
-		*flags |= MS_RDONLY;
+		*flags |= SB_RDONLY;
 	return 0;
 }
 
@@ -70,7 +70,7 @@ static void sysv_put_super(struct super_block *sb)
 {
 	struct sysv_sb_info *sbi = SYSV_SB(sb);
 
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		/* XXX ext2 also updates the state here */
 		mark_buffer_dirty(sbi->s_bh1);
 		if (sbi->s_bh1 != sbi->s_bh2)
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index eda10959714f..a2a058512501 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -216,7 +216,7 @@ static int detect_sysv(struct sysv_sb_info *sbi, struct buffer_head *bh)
  	if (fs16_to_cpu(sbi, sbd->s_nfree) == 0xffff) {
  		sbi->s_type = FSTYPE_AFS;
 		sbi->s_forced_ro = 1;
- 		if (!(sb->s_flags & MS_RDONLY)) {
+ 		if (!(sb->s_flags & SB_RDONLY)) {
  			printk("SysV FS: SCO EAFS on %s detected, " 
  				"forcing read-only mode.\n", 
  				sb->s_id);
@@ -333,7 +333,7 @@ static int complete_read_super(struct super_block *sb, int silent, int size)
 	/* set up enough so that it can read an inode */
 	sb->s_op = &sysv_sops;
 	if (sbi->s_forced_ro)
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	if (sbi->s_truncate)
 		sb->s_d_op = &sysv_dentry_operations;
 	root_inode = sysv_iget(sb, SYSV_ROOT_INO);
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 2cda3d67e2d0..fca98aa09086 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1398,7 +1398,7 @@ int ubifs_update_time(struct inode *inode, struct timespec *time,
 	if (flags & S_MTIME)
 		inode->i_mtime = *time;
 
-	if (!(inode->i_sb->s_flags & MS_LAZYTIME))
+	if (!(inode->i_sb->s_flags & SB_LAZYTIME))
 		iflags |= I_DIRTY_SYNC;
 
 	release = ui->dirty;
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index 3be28900bf37..fe77e9625e84 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -84,7 +84,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
 	if (!c->ro_error) {
 		c->ro_error = 1;
 		c->no_chk_data_crc = 0;
-		c->vfs_sb->s_flags |= MS_RDONLY;
+		c->vfs_sb->s_flags |= SB_RDONLY;
 		ubifs_warn(c, "switched to read-only mode, error %d", err);
 		dump_stack();
 	}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index cf4cc99b75b5..8ea1878c51b6 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -963,7 +963,7 @@ static int parse_standard_option(const char *option)
 
 	pr_notice("UBIFS: parse %s\n", option);
 	if (!strcmp(option, "sync"))
-		return MS_SYNCHRONOUS;
+		return SB_SYNCHRONOUS;
 	return 0;
 }
 
@@ -1152,9 +1152,9 @@ static int mount_ubifs(struct ubifs_info *c)
 	long long x, y;
 	size_t sz;
 
-	c->ro_mount = !!(c->vfs_sb->s_flags & MS_RDONLY);
-	/* Suppress error messages while probing if MS_SILENT is set */
-	c->probing = !!(c->vfs_sb->s_flags & MS_SILENT);
+	c->ro_mount = !!(c->vfs_sb->s_flags & SB_RDONLY);
+	/* Suppress error messages while probing if SB_SILENT is set */
+	c->probing = !!(c->vfs_sb->s_flags & SB_SILENT);
 
 	err = init_constants_early(c);
 	if (err)
@@ -1845,7 +1845,7 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
 		return err;
 	}
 
-	if (c->ro_mount && !(*flags & MS_RDONLY)) {
+	if (c->ro_mount && !(*flags & SB_RDONLY)) {
 		if (c->ro_error) {
 			ubifs_msg(c, "cannot re-mount R/W due to prior errors");
 			return -EROFS;
@@ -1857,7 +1857,7 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
 		err = ubifs_remount_rw(c);
 		if (err)
 			return err;
-	} else if (!c->ro_mount && (*flags & MS_RDONLY)) {
+	} else if (!c->ro_mount && (*flags & SB_RDONLY)) {
 		if (c->ro_error) {
 			ubifs_msg(c, "cannot re-mount R/O due to prior errors");
 			return -EROFS;
@@ -2112,7 +2112,7 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
 	 */
 	ubi = open_ubi(name, UBI_READONLY);
 	if (IS_ERR(ubi)) {
-		if (!(flags & MS_SILENT))
+		if (!(flags & SB_SILENT))
 			pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
 			       current->pid, name, (int)PTR_ERR(ubi));
 		return ERR_CAST(ubi);
@@ -2138,18 +2138,18 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
 		kfree(c);
 		/* A new mount point for already mounted UBIFS */
 		dbg_gen("this ubi volume is already mounted");
-		if (!!(flags & MS_RDONLY) != c1->ro_mount) {
+		if (!!(flags & SB_RDONLY) != c1->ro_mount) {
 			err = -EBUSY;
 			goto out_deact;
 		}
 	} else {
-		err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
+		err = ubifs_fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
 		if (err)
 			goto out_deact;
 		/* We do not support atime */
-		sb->s_flags |= MS_ACTIVE;
+		sb->s_flags |= SB_ACTIVE;
 #ifndef CONFIG_UBIFS_ATIME_SUPPORT
-		sb->s_flags |= MS_NOATIME;
+		sb->s_flags |= SB_NOATIME;
 #else
 		ubifs_msg(c, "full atime support is enabled.");
 #endif
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 298b4d89eee9..be9294e12ca7 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1202,7 +1202,7 @@ struct ubifs_debug_info;
  * @need_recovery: %1 if the file-system needs recovery
  * @replaying: %1 during journal replay
  * @mounting: %1 while mounting
- * @probing: %1 while attempting to mount if MS_SILENT mount flag is set
+ * @probing: %1 while attempting to mount if SB_SILENT mount flag is set
  * @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
  * @replay_list: temporary list used during journal replay
  * @replay_buds: list of buds to replay
@@ -1854,7 +1854,7 @@ __printf(2, 3)
 void ubifs_warn(const struct ubifs_info *c, const char *fmt, ...);
 /*
  * A conditional variant of 'ubifs_err()' which doesn't output anything
- * if probing (ie. MS_SILENT set).
+ * if probing (ie. SB_SILENT set).
  */
 #define ubifs_errc(c, fmt, ...)						\
 do {									\
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 14b4bc1f6801..cd3b797eafa6 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -654,7 +654,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
 	sync_filesystem(sb);
 	if (lvidiu) {
 		int write_rev = le16_to_cpu(lvidiu->minUDFWriteRev);
-		if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY))
+		if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & SB_RDONLY))
 			return -EACCES;
 	}
 
@@ -677,10 +677,10 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
 	sbi->s_dmode = uopt.dmode;
 	write_unlock(&sbi->s_cred_lock);
 
-	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+	if ((*flags & SB_RDONLY) == (sb->s_flags & SB_RDONLY))
 		goto out_unlock;
 
-	if (*flags & MS_RDONLY)
+	if (*flags & SB_RDONLY)
 		udf_close_lvid(sb);
 	else
 		udf_open_lvid(sb);
@@ -1021,7 +1021,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition,
 
 		fe = udf_iget_special(sb, &addr);
 		if (IS_ERR(fe)) {
-			if (sb->s_flags & MS_RDONLY)
+			if (sb->s_flags & SB_RDONLY)
 				udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n");
 			else {
 				udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n");
@@ -1345,7 +1345,7 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
 		 * writing to it (we overwrite blocks instead of relocating
 		 * them).
 		 */
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			ret = -EACCES;
 			goto out_bh;
 		}
@@ -2209,7 +2209,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
 			ret = -EINVAL;
 			goto error_out;
 		} else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION &&
-			   !(sb->s_flags & MS_RDONLY)) {
+			   !(sb->s_flags & SB_RDONLY)) {
 			ret = -EACCES;
 			goto error_out;
 		}
@@ -2230,7 +2230,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
 
 	if (sbi->s_partmaps[sbi->s_partition].s_partition_flags &
 			UDF_PART_FLAG_READ_ONLY &&
-	    !(sb->s_flags & MS_RDONLY)) {
+	    !(sb->s_flags & SB_RDONLY)) {
 		ret = -EACCES;
 		goto error_out;
 	}
@@ -2249,7 +2249,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
 			 le16_to_cpu(ts.year), ts.month, ts.day,
 			 ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone));
 	}
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		udf_open_lvid(sb);
 		lvid_open = true;
 	}
@@ -2336,7 +2336,7 @@ static void udf_put_super(struct super_block *sb)
 	if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
 		unload_nls(sbi->s_nls_map);
 #endif
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		udf_close_lvid(sb);
 	brelse(sbi->s_lvid_bh);
 	udf_sb_free_partitions(sb);
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index a0376a2c1c29..8330cc056738 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -113,7 +113,7 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
 	
 	ubh_mark_buffer_dirty (USPI_UBH(uspi));
 	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		ubh_sync_block(UCPI_UBH(ucpi));
 	ufs_mark_sb_dirty(sb);
 
@@ -202,7 +202,7 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
 
 	ubh_mark_buffer_dirty (USPI_UBH(uspi));
 	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		ubh_sync_block(UCPI_UBH(ucpi));
 
 	if (overflow) {
@@ -553,7 +553,7 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
 	
 	ubh_mark_buffer_dirty (USPI_UBH(uspi));
 	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		ubh_sync_block(UCPI_UBH(ucpi));
 	ufs_mark_sb_dirty(sb);
 
@@ -671,7 +671,7 @@ static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
 succed:
 	ubh_mark_buffer_dirty (USPI_UBH(uspi));
 	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		ubh_sync_block(UCPI_UBH(ucpi));
 	ufs_mark_sb_dirty(sb);
 
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index d1dd8cc33179..a432b15d5458 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -111,7 +111,7 @@ void ufs_free_inode (struct inode * inode)
 
 	ubh_mark_buffer_dirty (USPI_UBH(uspi));
 	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		ubh_sync_block(UCPI_UBH(ucpi));
 	
 	ufs_mark_sb_dirty(sb);
@@ -145,14 +145,14 @@ static void ufs2_init_inodes_chunk(struct super_block *sb,
 		set_buffer_uptodate(bh);
 		mark_buffer_dirty(bh);
 		unlock_buffer(bh);
-		if (sb->s_flags & MS_SYNCHRONOUS)
+		if (sb->s_flags & SB_SYNCHRONOUS)
 			sync_dirty_buffer(bh);
 		brelse(bh);
 	}
 
 	fs32_add(sb, &ucg->cg_u.cg_u2.cg_initediblk, uspi->s_inopb);
 	ubh_mark_buffer_dirty(UCPI_UBH(ucpi));
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		ubh_sync_block(UCPI_UBH(ucpi));
 
 	UFSD("EXIT\n");
@@ -283,7 +283,7 @@ struct inode *ufs_new_inode(struct inode *dir, umode_t mode)
 	}
 	ubh_mark_buffer_dirty (USPI_UBH(uspi));
 	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		ubh_sync_block(UCPI_UBH(ucpi));
 	ufs_mark_sb_dirty(sb);
 
@@ -329,7 +329,7 @@ struct inode *ufs_new_inode(struct inode *dir, umode_t mode)
 		ufs2_inode->ui_birthnsec = cpu_to_fs32(sb, ts.tv_nsec);
 		mark_buffer_dirty(bh);
 		unlock_buffer(bh);
-		if (sb->s_flags & MS_SYNCHRONOUS)
+		if (sb->s_flags & SB_SYNCHRONOUS)
 			sync_dirty_buffer(bh);
 		brelse(bh);
 	}
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 29ecaf739449..221d1109ec99 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -278,11 +278,11 @@ void ufs_error (struct super_block * sb, const char * function,
 	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(uspi);
 	
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		usb1->fs_clean = UFS_FSBAD;
 		ubh_mark_buffer_dirty(USPI_UBH(uspi));
 		ufs_mark_sb_dirty(sb);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
 	va_start(args, fmt);
 	vaf.fmt = fmt;
@@ -312,7 +312,7 @@ void ufs_panic (struct super_block * sb, const char * function,
 	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(uspi);
 	
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		usb1->fs_clean = UFS_FSBAD;
 		ubh_mark_buffer_dirty(USPI_UBH(uspi));
 		ufs_mark_sb_dirty(sb);
@@ -320,7 +320,7 @@ void ufs_panic (struct super_block * sb, const char * function,
 	va_start(args, fmt);
 	vaf.fmt = fmt;
 	vaf.va = &args;
-	sb->s_flags |= MS_RDONLY;
+	sb->s_flags |= SB_RDONLY;
 	pr_crit("panic (device %s): %s: %pV\n",
 		sb->s_id, function, &vaf);
 	va_end(args);
@@ -734,7 +734,7 @@ static void ufs_put_super(struct super_block *sb)
 
 	UFSD("ENTER\n");
 
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		ufs_put_super_internal(sb);
 	cancel_delayed_work_sync(&sbi->sync_work);
 
@@ -768,7 +768,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 	UFSD("ENTER\n");
 
 #ifndef CONFIG_UFS_FS_WRITE
-	if (!(sb->s_flags & MS_RDONLY)) {
+	if (!(sb->s_flags & SB_RDONLY)) {
 		pr_err("ufs was compiled with read-only support, can't be mounted as read-write\n");
 		return -EROFS;
 	}
@@ -780,7 +780,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_fs_info = sbi;
 	sbi->sb = sb;
 
-	UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY));
+	UFSD("flag %u\n", (int)(sb->s_flags & SB_RDONLY));
 	
 	mutex_init(&sbi->s_lock);
 	spin_lock_init(&sbi->work_lock);
@@ -877,10 +877,10 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 		uspi->s_sbsize = super_block_size = 2048;
 		uspi->s_sbbase = 0;
 		flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!silent)
 				pr_info("ufstype=old is supported read-only\n");
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 		}
 		break;
 	
@@ -893,10 +893,10 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 		uspi->s_sbbase = 0;
 		uspi->s_dirblksize = 1024;
 		flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!silent)
 				pr_info("ufstype=nextstep is supported read-only\n");
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 		}
 		break;
 	
@@ -909,10 +909,10 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 		uspi->s_sbbase = 0;
 		uspi->s_dirblksize = 1024;
 		flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!silent)
 				pr_info("ufstype=nextstep-cd is supported read-only\n");
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 		}
 		break;
 	
@@ -925,10 +925,10 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 		uspi->s_sbbase = 0;
 		uspi->s_dirblksize = 1024;
 		flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!silent)
 				pr_info("ufstype=openstep is supported read-only\n");
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 		}
 		break;
 	
@@ -940,10 +940,10 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 		uspi->s_sbsize = super_block_size = 2048;
 		uspi->s_sbbase = 0;
 		flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
-		if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->s_flags & SB_RDONLY)) {
 			if (!silent)
 				pr_info("ufstype=hp is supported read-only\n");
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
  		}
  		break;
 	default:
@@ -1093,21 +1093,21 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 			break;
 		case UFS_FSACTIVE:
 			pr_err("%s(): fs is active\n", __func__);
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			break;
 		case UFS_FSBAD:
 			pr_err("%s(): fs is bad\n", __func__);
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			break;
 		default:
 			pr_err("%s(): can't grok fs_clean 0x%x\n",
 			       __func__, usb1->fs_clean);
-			sb->s_flags |= MS_RDONLY;
+			sb->s_flags |= SB_RDONLY;
 			break;
 		}
 	} else {
 		pr_err("%s(): fs needs fsck\n", __func__);
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	}
 
 	/*
@@ -1228,7 +1228,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 	/*
 	 * Read cylinder group structures
 	 */
-	if (!(sb->s_flags & MS_RDONLY))
+	if (!(sb->s_flags & SB_RDONLY))
 		if (!ufs_read_cylinder_structures(sb))
 			goto failed;
 
@@ -1283,7 +1283,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
 		return -EINVAL;
 	}
 
-	if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {
+	if ((*mount_flags & SB_RDONLY) == (sb->s_flags & SB_RDONLY)) {
 		UFS_SB(sb)->s_mount_opt = new_mount_opt;
 		mutex_unlock(&UFS_SB(sb)->s_lock);
 		return 0;
@@ -1292,7 +1292,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
 	/*
 	 * fs was mouted as rw, remounting ro
 	 */
-	if (*mount_flags & MS_RDONLY) {
+	if (*mount_flags & SB_RDONLY) {
 		ufs_put_super_internal(sb);
 		usb1->fs_time = cpu_to_fs32(sb, get_seconds());
 		if ((flags & UFS_ST_MASK) == UFS_ST_SUN
@@ -1301,7 +1301,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
 			ufs_set_fs_state(sb, usb1, usb3,
 				UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
 		ubh_mark_buffer_dirty (USPI_UBH(uspi));
-		sb->s_flags |= MS_RDONLY;
+		sb->s_flags |= SB_RDONLY;
 	} else {
 	/*
 	 * fs was mounted as ro, remounting rw
@@ -1325,7 +1325,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
 			mutex_unlock(&UFS_SB(sb)->s_lock);
 			return -EPERM;
 		}
-		sb->s_flags &= ~MS_RDONLY;
+		sb->s_flags &= ~SB_RDONLY;
 #endif
 	}
 	UFS_SB(sb)->s_mount_opt = new_mount_opt;
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 2eaf81859166..09f5e7d6f077 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -946,7 +946,7 @@ xfs_mountfs(
 	 * of inodes before we're done replaying log items on those
 	 * inodes.
 	 */
-	mp->m_super->s_flags |= MS_ACTIVE;
+	mp->m_super->s_flags |= SB_ACTIVE;
 
 	/*
 	 * Finish recovering the file system.  This part needed to be delayed
@@ -1023,7 +1023,7 @@ xfs_mountfs(
  out_quota:
 	xfs_qm_unmount_quotas(mp);
  out_rtunmount:
-	mp->m_super->s_flags &= ~MS_ACTIVE;
+	mp->m_super->s_flags &= ~SB_ACTIVE;
 	xfs_rtunmount_inodes(mp);
  out_rele_rip:
 	IRELE(rip);
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index f82d79a8c694..295b5e22dd79 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -125,7 +125,7 @@ xfs_fs_set_info(
 	struct xfs_mount *mp = XFS_M(sb);
 	struct qc_dqblk newlim;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return -EROFS;
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
@@ -175,7 +175,7 @@ xfs_quota_enable(
 {
 	struct xfs_mount	*mp = XFS_M(sb);
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return -EROFS;
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
@@ -190,7 +190,7 @@ xfs_quota_disable(
 {
 	struct xfs_mount	*mp = XFS_M(sb);
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return -EROFS;
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
@@ -208,7 +208,7 @@ xfs_fs_rm_xquota(
 	struct xfs_mount	*mp = XFS_M(sb);
 	unsigned int		flags = 0;
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return -EROFS;
 
 	if (XFS_IS_QUOTA_ON(mp))
@@ -280,7 +280,7 @@ xfs_fs_set_dqblk(
 {
 	struct xfs_mount	*mp = XFS_M(sb);
 
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		return -EROFS;
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 455a575f101d..59902fa2d775 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -210,11 +210,11 @@ xfs_parseargs(
 	/*
 	 * Copy binary VFS mount flags we are interested in.
 	 */
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & SB_RDONLY)
 		mp->m_flags |= XFS_MOUNT_RDONLY;
-	if (sb->s_flags & MS_DIRSYNC)
+	if (sb->s_flags & SB_DIRSYNC)
 		mp->m_flags |= XFS_MOUNT_DIRSYNC;
-	if (sb->s_flags & MS_SYNCHRONOUS)
+	if (sb->s_flags & SB_SYNCHRONOUS)
 		mp->m_flags |= XFS_MOUNT_WSYNC;
 
 	/*
@@ -1295,7 +1295,7 @@ xfs_fs_remount(
 	}
 
 	/* ro -> rw */
-	if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) {
+	if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & SB_RDONLY)) {
 		if (mp->m_flags & XFS_MOUNT_NORECOVERY) {
 			xfs_warn(mp,
 		"ro->rw transition prohibited on norecovery mount");
@@ -1351,7 +1351,7 @@ xfs_fs_remount(
 	}
 
 	/* rw -> ro */
-	if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) {
+	if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & SB_RDONLY)) {
 		/* Free the per-AG metadata reservation pool. */
 		error = xfs_fs_unreserve_ag_blocks(mp);
 		if (error) {
@@ -1620,7 +1620,7 @@ xfs_fs_fill_super(
 
 	/* version 5 superblocks support inode version counters. */
 	if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5)
-		sb->s_flags |= MS_I_VERSION;
+		sb->s_flags |= SB_I_VERSION;
 
 	if (mp->m_flags & XFS_MOUNT_DAX) {
 		xfs_warn(mp,
diff --git a/fs/xfs/xfs_super.h b/fs/xfs/xfs_super.h
index 5f2f32408011..fcc5dfc70aa0 100644
--- a/fs/xfs/xfs_super.h
+++ b/fs/xfs/xfs_super.h
@@ -30,7 +30,7 @@ extern void xfs_qm_exit(void);
 
 #ifdef CONFIG_XFS_POSIX_ACL
 # define XFS_ACL_STRING		"ACLs, "
-# define set_posix_acl_flag(sb)	((sb)->s_flags |= MS_POSIXACL)
+# define set_posix_acl_flag(sb)	((sb)->s_flags |= SB_POSIXACL)
 #else
 # define XFS_ACL_STRING
 # define set_posix_acl_flag(sb)	do { } while (0)
diff --git a/include/linux/fb.h b/include/linux/fb.h
index a964d076b4dc..c8a110277ffd 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -23,7 +23,7 @@ struct videomode;
 struct device_node;
 
 /* Definitions below are used in the parsed monitor specs */
-#define FB_DPMS_ACTIVE_OFF	1
+#define FB_DPSB_ACTIVE_OFF	1
 #define FB_DPMS_SUSPEND		2
 #define FB_DPMS_STANDBY		4
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index bc0c054894b9..3138da4491da 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1257,6 +1257,33 @@ extern int send_sigurg(struct fown_struct *fown);
 struct mm_struct;
 
 /*
+ * sb->s_flags.  Note that these mirror the equivalent MS_* flags where
+ * represented in both.
+ */
+#define SB_RDONLY	 1	/* Mount read-only */
+#define SB_NOSUID	 2	/* Ignore suid and sgid bits */
+#define SB_NODEV	 4	/* Disallow access to device special files */
+#define SB_NOEXEC	 8	/* Disallow program execution */
+#define SB_SYNCHRONOUS	16	/* Writes are synced at once */
+#define SB_MANDLOCK	64	/* Allow mandatory locks on an FS */
+#define SB_DIRSYNC	128	/* Directory modifications are synchronous */
+#define SB_NOATIME	1024	/* Do not update access times. */
+#define SB_NODIRATIME	2048	/* Do not update directory access times */
+#define SB_SILENT	32768
+#define SB_POSIXACL	(1<<16)	/* VFS does not apply the umask */
+#define SB_KERNMOUNT	(1<<22) /* this is a kern_mount call */
+#define SB_I_VERSION	(1<<23) /* Update inode I_version field */
+#define SB_LAZYTIME	(1<<25) /* Update the on-disk [acm]times lazily */
+
+/* These sb flags are internal to the kernel */
+#define SB_SUBMOUNT     (1<<26)
+#define SB_NOREMOTELOCK	(1<<27)
+#define SB_NOSEC	(1<<28)
+#define SB_BORN		(1<<29)
+#define SB_ACTIVE	(1<<30)
+#define SB_NOUSER	(1<<31)
+
+/*
  *	Umount options
  */
 
@@ -1833,7 +1860,7 @@ struct super_operations {
  * possible to override it selectively if you really wanted to with some
  * ioctl() that is not currently implemented.
  *
- * Exception: MS_RDONLY is always applied to the entire file system.
+ * Exception: SB_RDONLY is always applied to the entire file system.
  *
  * Unfortunately, it is possible to change a filesystems flags with it mounted
  * with files in use.  This means that all of the inodes will not have their
@@ -1842,19 +1869,19 @@ struct super_operations {
  */
 #define __IS_FLG(inode, flg)	((inode)->i_sb->s_flags & (flg))
 
-#define IS_RDONLY(inode)	((inode)->i_sb->s_flags & MS_RDONLY)
-#define IS_SYNC(inode)		(__IS_FLG(inode, MS_SYNCHRONOUS) || \
+#define IS_RDONLY(inode)	((inode)->i_sb->s_flags & SB_RDONLY)
+#define IS_SYNC(inode)		(__IS_FLG(inode, SB_SYNCHRONOUS) || \
 					((inode)->i_flags & S_SYNC))
-#define IS_DIRSYNC(inode)	(__IS_FLG(inode, MS_SYNCHRONOUS|MS_DIRSYNC) || \
+#define IS_DIRSYNC(inode)	(__IS_FLG(inode, SB_SYNCHRONOUS|SB_DIRSYNC) || \
 					((inode)->i_flags & (S_SYNC|S_DIRSYNC)))
-#define IS_MANDLOCK(inode)	__IS_FLG(inode, MS_MANDLOCK)
-#define IS_NOATIME(inode)	__IS_FLG(inode, MS_RDONLY|MS_NOATIME)
-#define IS_I_VERSION(inode)	__IS_FLG(inode, MS_I_VERSION)
+#define IS_MANDLOCK(inode)	__IS_FLG(inode, SB_MANDLOCK)
+#define IS_NOATIME(inode)	__IS_FLG(inode, SB_RDONLY|SB_NOATIME)
+#define IS_I_VERSION(inode)	__IS_FLG(inode, SB_I_VERSION)
 
 #define IS_NOQUOTA(inode)	((inode)->i_flags & S_NOQUOTA)
 #define IS_APPEND(inode)	((inode)->i_flags & S_APPEND)
 #define IS_IMMUTABLE(inode)	((inode)->i_flags & S_IMMUTABLE)
-#define IS_POSIXACL(inode)	__IS_FLG(inode, MS_POSIXACL)
+#define IS_POSIXACL(inode)	__IS_FLG(inode, SB_POSIXACL)
 
 #define IS_DEADDIR(inode)	((inode)->i_flags & S_DEAD)
 #define IS_NOCMTIME(inode)	((inode)->i_flags & S_NOCMTIME)
@@ -2152,7 +2179,7 @@ static inline int __mandatory_lock(struct inode *ino)
 }
 
 /*
- * ... and these candidates should be on MS_MANDLOCK mounted fs,
+ * ... and these candidates should be on SB_MANDLOCK mounted fs,
  * otherwise these will be advisory locks
  */
 
@@ -3168,7 +3195,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
 
 static inline void inode_has_no_xattr(struct inode *inode)
 {
-	if (!is_sxid(inode->i_mode) && (inode->i_sb->s_flags & MS_NOSEC))
+	if (!is_sxid(inode->i_mode) && (inode->i_sb->s_flags & SB_NOSEC))
 		inode->i_flags |= S_NOSEC;
 }
 
diff --git a/include/uapi/linux/bfs_fs.h b/include/uapi/linux/bfs_fs.h
index 1c0b355aa515..1eef6b9e6b67 100644
--- a/include/uapi/linux/bfs_fs.h
+++ b/include/uapi/linux/bfs_fs.h
@@ -75,7 +75,7 @@ struct bfs_super_block {
 #define BFS_FILEBLOCKS(ip) \
         ((ip)->i_sblock == 0 ? 0 : (le32_to_cpu((ip)->i_eblock) + 1) -  le32_to_cpu((ip)->i_sblock))
 #define BFS_UNCLEAN(bfs_sb, sb)	\
-	((le32_to_cpu(bfs_sb->s_from) != -1) && (le32_to_cpu(bfs_sb->s_to) != -1) && !(sb->s_flags & MS_RDONLY))
+	((le32_to_cpu(bfs_sb->s_from) != -1) && (le32_to_cpu(bfs_sb->s_to) != -1) && !(sb->s_flags & SB_RDONLY))
 
 
 #endif	/* _LINUX_BFS_FS_H */
diff --git a/init/do_mounts.c b/init/do_mounts.c
index c2de5104aad2..d7d6c25efd4f 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -373,7 +373,7 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data)
 	printk(KERN_INFO
 	       "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
 	       s->s_type->name,
-	       s->s_flags & MS_RDONLY ?  " readonly" : "",
+	       s->s_flags & SB_RDONLY ?  " readonly" : "",
 	       MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
 	return 0;
 }
@@ -420,8 +420,8 @@ void __init mount_block_root(char *name, int flags)
 #endif
 		panic("VFS: Unable to mount root fs on %s", b);
 	}
-	if (!(flags & MS_RDONLY)) {
-		flags |= MS_RDONLY;
+	if (!(flags & SB_RDONLY)) {
+		flags |= SB_RDONLY;
 		goto retry;
 	}
 
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index e8d41ff57241..9e3a0aab4416 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -331,7 +331,7 @@ static struct dentry *mqueue_mount(struct file_system_type *fs_type,
 			 void *data)
 {
 	struct ipc_namespace *ns;
-	if (flags & MS_KERNMOUNT) {
+	if (flags & SB_KERNMOUNT) {
 		ns = data;
 		data = NULL;
 	} else {
diff --git a/mm/shmem.c b/mm/shmem.c
index e67d6ba4e98e..22b55d4c6513 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3726,7 +3726,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
 	 * tmpfs instance, limiting inodes to one per page of lowmem;
 	 * but the internal instance is left unlimited.
 	 */
-	if (!(sb->s_flags & MS_KERNMOUNT)) {
+	if (!(sb->s_flags & SB_KERNMOUNT)) {
 		sbinfo->max_blocks = shmem_default_max_blocks();
 		sbinfo->max_inodes = shmem_default_max_inodes();
 		if (shmem_parse_options(data, sbinfo, false)) {
@@ -3734,12 +3734,12 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
 			goto failed;
 		}
 	} else {
-		sb->s_flags |= MS_NOUSER;
+		sb->s_flags |= SB_NOUSER;
 	}
 	sb->s_export_op = &shmem_export_ops;
-	sb->s_flags |= MS_NOSEC;
+	sb->s_flags |= SB_NOSEC;
 #else
-	sb->s_flags |= MS_NOUSER;
+	sb->s_flags |= SB_NOUSER;
 #endif
 
 	spin_lock_init(&sbinfo->stat_lock);
@@ -3759,7 +3759,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_xattr = shmem_xattr_handlers;
 #endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
-	sb->s_flags |= MS_POSIXACL;
+	sb->s_flags |= SB_POSIXACL;
 #endif
 
 	inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
index 7986f4e0da12..b73cfd1b860a 100644
--- a/scripts/gdb/linux/constants.py.in
+++ b/scripts/gdb/linux/constants.py.in
@@ -36,12 +36,12 @@
 import gdb
 
 /* linux/fs.h */
-LX_VALUE(MS_RDONLY)
-LX_VALUE(MS_SYNCHRONOUS)
-LX_VALUE(MS_MANDLOCK)
-LX_VALUE(MS_DIRSYNC)
-LX_VALUE(MS_NOATIME)
-LX_VALUE(MS_NODIRATIME)
+LX_VALUE(SB_RDONLY)
+LX_VALUE(SB_SYNCHRONOUS)
+LX_VALUE(SB_MANDLOCK)
+LX_VALUE(SB_DIRSYNC)
+LX_VALUE(SB_NOATIME)
+LX_VALUE(SB_NODIRATIME)
 
 /* linux/mount.h */
 LX_VALUE(MNT_NOSUID)
diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
index 38b1f09d1cd9..10f724d9601b 100644
--- a/scripts/gdb/linux/proc.py
+++ b/scripts/gdb/linux/proc.py
@@ -113,9 +113,9 @@ def info_opts(lst, opt):
     return opts
 
 
-FS_INFO = {constants.LX_MS_SYNCHRONOUS: ",sync",
-           constants.LX_MS_MANDLOCK: ",mand",
-           constants.LX_MS_DIRSYNC: ",dirsync",
+FS_INFO = {constants.LX_SB_SYNCHRONOUS: ",sync",
+           constants.LX_SB_MANDLOCK: ",mand",
+           constants.LX_SB_DIRSYNC: ",dirsync",
            constants.LX_MS_NOATIME: ",noatime",
            constants.LX_MS_NODIRATIME: ",nodiratime"}
 
@@ -183,7 +183,7 @@ values of that process namespace"""
             fstype = superblock['s_type']['name'].string()
             s_flags = int(superblock['s_flags'])
             m_flags = int(vfs['mnt']['mnt_flags'])
-            rd = "ro" if (s_flags & constants.LX_MS_RDONLY) else "rw"
+            rd = "ro" if (s_flags & constants.LX_SB_RDONLY) else "rw"
 
             gdb.write(
                 "{} {} {} {}{}{} 0 0\n"
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index 550a700563b4..32ceaa78f817 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -96,7 +96,7 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
 
 static inline bool path_mediated_fs(struct dentry *dentry)
 {
-	return !(dentry->d_sb->s_flags & MS_NOUSER);
+	return !(dentry->d_sb->s_flags & SB_NOUSER);
 }
 
 /* struct aa_policy - common part of both namespaces and profiles
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e67a526d1f30..7e498b16aed3 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2785,7 +2785,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 		return rc;
 
 	/* Allow all mounts performed by the kernel */
-	if (flags & MS_KERNMOUNT)
+	if (flags & SB_KERNMOUNT)
 		return 0;
 
 	ad.type = LSM_AUDIT_DATA_DENTRY;
diff --git a/tools/testing/selftests/mount/unprivileged-remount-test.c b/tools/testing/selftests/mount/unprivileged-remount-test.c
index 517785052f1c..65489157f8d7 100644
--- a/tools/testing/selftests/mount/unprivileged-remount-test.c
+++ b/tools/testing/selftests/mount/unprivileged-remount-test.c
@@ -129,7 +129,7 @@ static int read_mnt_flags(const char *path)
 	}
 	mnt_flags = 0;
 	if (stat.f_flag & ST_RDONLY)
-		mnt_flags |= MS_RDONLY;
+		mnt_flags |= SB_RDONLY;
 	if (stat.f_flag & ST_NOSUID)
 		mnt_flags |= MS_NOSUID;
 	if (stat.f_flag & ST_NODEV)
@@ -143,7 +143,7 @@ static int read_mnt_flags(const char *path)
 	if (stat.f_flag & ST_RELATIME)
 		mnt_flags |= MS_RELATIME;
 	if (stat.f_flag & ST_SYNCHRONOUS)
-		mnt_flags |= MS_SYNCHRONOUS;
+		mnt_flags |= SB_SYNCHRONOUS;
 	if (stat.f_flag & ST_MANDLOCK)
 		mnt_flags |= ST_MANDLOCK;
 
@@ -317,8 +317,8 @@ static bool test_priv_mount_unpriv_remount(void)
 
 int main(int argc, char **argv)
 {
-	if (!test_unpriv_remount_simple(MS_RDONLY)) {
-		die("MS_RDONLY malfunctions\n");
+	if (!test_unpriv_remount_simple(SB_RDONLY)) {
+		die("SB_RDONLY malfunctions\n");
 	}
 	if (!test_unpriv_remount("devpts", "newinstance", MS_NODEV, MS_NODEV, 0)) {
 		die("MS_NODEV malfunctions\n");

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (6 preceding siblings ...)
  2017-06-14 15:16 ` [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags " David Howells
@ 2017-06-14 15:16 ` David Howells
  2017-06-14 18:02   ` Randy Dunlap
                     ` (3 more replies)
  2017-06-14 15:16 ` [PATCH 09/27] VFS: Add LSM hooks for filesystem context [ver #5] David Howells
                   ` (19 subsequent siblings)
  27 siblings, 4 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:16 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Introduce a filesystem context concept to be used during superblock
creation for mount and superblock reconfiguration for remount.  This is
allocated at the beginning of the mount procedure and into it is placed:

 (1) Filesystem type.

 (2) Namespaces.

 (3) Device name.

 (4) Superblock flags (MS_*).

 (5) Security details.

 (6) Filesystem-specific data, as set by the mount options.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 Documentation/filesystems/mounting.txt |  436 ++++++++++++++++++++++++++++++++
 include/linux/fs_context.h             |   72 +++++
 2 files changed, 508 insertions(+)
 create mode 100644 Documentation/filesystems/mounting.txt
 create mode 100644 include/linux/fs_context.h

diff --git a/Documentation/filesystems/mounting.txt b/Documentation/filesystems/mounting.txt
new file mode 100644
index 000000000000..315a5a4ff5cc
--- /dev/null
+++ b/Documentation/filesystems/mounting.txt
@@ -0,0 +1,436 @@
+			      ===================
+			      FILESYSTEM MOUNTING
+			      ===================
+
+CONTENTS
+
+ (1) Overview.
+
+ (2) The filesystem context.
+
+ (3) The filesystem context operations.
+
+ (4) Filesystem context security.
+
+ (5) VFS filesystem context operations.
+
+
+========
+OVERVIEW
+========
+
+The creation of new mounts is now to be done in a multistep process:
+
+ (1) Create a filesystem context.
+
+ (2) Parse the options and attach them to the context.  Options may be passed
+     individually from userspace.
+
+ (3) Validate and pre-process the context.
+
+ (4) Get or create a superblock and mountable root.
+
+ (5) Perform the mount.
+
+ (6) Return an error message attached to the context.
+
+ (7) Destroy the context.
+
+To support this, the file_system_type struct gains two new fields:
+
+	unsigned short fs_context_size;
+
+which indicates the total amount of space that should be allocated for context
+data (see the Filesystem Context section), and:
+
+	int (*init_fs_context)(struct fs_context *fc, struct super_block *src_sb);
+
+which is invoked to set up the filesystem-specific parts of a filesystem
+context, including the additional space.  The src_sb parameter is used to
+convey the superblock from which the filesystem may draw extra information
+(such as namespaces), for submount (FS_CONTEXT_FOR_SUBMOUNT) or remount
+(FS_CONTEXT_FOR_REMOUNT) purposes or it will be NULL.
+
+Note that security initialisation is done *after* the filesystem is called so
+that the namespaces may be adjusted first.
+
+And the super_operations struct gains one:
+
+	int (*remount_fs_fc) (struct super_block *, struct fs_context *);
+
+This shadows the ->remount_fs() operation and takes a prepared filesystem
+context instead of the mount flags and data page.  It may modify the ms_flags
+in the context for the caller to pick up.
+
+[NOTE] remount_fs_fc is intended as a replacement for remount_fs.
+
+
+======================
+THE FILESYSTEM CONTEXT
+======================
+
+The creation and reconfiguration of a superblock is governed by a filesystem
+context.  This is represented by the fs_context structure:
+
+	struct fs_context {
+		const struct fs_context_operations *ops;
+		struct file_system_type *fs;
+		struct dentry		*root;
+		struct user_namespace	*user_ns;
+		struct net		*net_ns;
+		const struct cred	*cred;
+		char			*device;
+		void			*security;
+		unsigned int		sb_flags;
+		bool			sloppy;
+		bool			silent;
+		bool			degraded;
+		enum fs_context_purpose	purpose : 8;
+	};
+
+When the VFS creates this, it allocates ->fs_context_size bytes (as specified
+by the file_system_type object) to hold both the fs_context struct and any
+extra data required by the filesystem.  The fs_context struct is placed at the
+beginning of this space.  Any extra space beyond that is for use by the
+filesystem.  The filesystem should wrap the struct in its own, e.g.:
+
+	struct nfs_fs_context {
+		struct fs_context fc;
+		...
+	};
+
+placing the fs_context struct first.  container_of() can then be used.  The
+file_system_type would be initialised thus:
+
+	struct file_system_type nfs = {
+		...
+		.fs_context_size	= sizeof(struct nfs_fs_context),
+		.init_fs_context	= nfs_init_fs_context,
+		...
+	};
+
+The fs_context fields are as follows:
+
+ (*) const struct fs_context_operations *ops
+
+     These are operations that can be done on a filesystem context (see
+     below).  This must be set by the ->init_fs_context() file_system_type
+     operation.
+
+ (*) struct file_system_type *fs
+
+     A pointer to the file_system_type of the filesystem that is being
+     constructed or reconfigured.  This retains a ref on the type owner.
+
+ (*) struct dentry *root
+
+     A pointer to the root of the mountable tree (and indirectly, the
+     superblock thereof).  This is filled in by the ->get_tree() op.
+
+ (*) struct user_namespace *user_ns
+ (*) struct net *net_ns
+
+     This is a subset of the namespaces in use by the invoking process.  This
+     retains a ref on each namespace.  The subscribed namespaces may be
+     replaced by the filesystem to reflect other sources, such as the parent
+     mount superblock on an automount.
+
+ (*) struct cred *cred
+
+     The mounter's credentials.  This retains a ref on the credentials.
+
+ (*) char *device
+
+     This is the device to be mounted.  It may be a block device
+     (e.g. /dev/sda1) or something more exotic, such as the "host:/path" that
+     NFS desires.
+
+ (*) void *security
+
+     A place for the LSMs to hang their security data for the superblock.  The
+     relevant security operations are described below.
+
+ (*) unsigned int sb_flags
+
+     This holds the MS_* flags mount flags.
+
+ (*) bool sloppy
+ (*) bool silent
+
+     These are set if the sloppy or silent mount options are given.
+
+     [NOTE] sloppy is probably unnecessary when userspace passes over one
+     option at a time since the error can just be ignored if userspace deems it
+     to be unimportant.
+
+     [NOTE] silent is probably redundant with ms_flags & MS_SILENT.
+
+ (*) bool degraded
+
+     This is set if any preallocated resources in the context have been used
+     up, thereby rendering it unreusable for the ->get_tree() op.
+
+ (*) enum fs_context_purpose
+
+     This indicates the purpose for which the context is intended.  The
+     available values are:
+
+	FS_CONTEXT_FOR_NEW	-- New mount
+	FS_CONTEXT_FOR_SUBMOUNT	-- New automatic submount of extant mount
+	FS_CONTEXT_FOR_REMOUNT	-- Change an existing mount
+
+The mount context is created by calling vfs_new_fs_context(), vfs_sb_reconfig()
+or vfs_dup_fs_context() and is destroyed with put_fs_context().  Note that the
+structure is not refcounted.
+
+VFS, security and filesystem mount options are set individually with
+vfs_parse_mount_option().  Options provided by the old mount(2) system call as
+a page of data can be parsed with generic_monolithic_mount_data().
+
+When mounting, the filesystem is allowed to take data from any of the pointers
+and attach it to the superblock (or whatever), provided it clears the pointer
+in the mount context.
+
+The filesystem is also allowed to allocate resources and pin them with the
+mount context.  For instance, NFS might pin the appropriate protocol version
+module.
+
+
+=================================
+THE FILESYSTEM CONTEXT OPERATIONS
+=================================
+
+The filesystem context points to a table of operations:
+
+	struct fs_context_operations {
+		void (*free)(struct fs_context *fc);
+		int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
+		int (*parse_option)(struct fs_context *fc, char *p);
+		int (*monolithic_mount_data)(struct fs_context *fc, void *data);
+		int (*validate)(struct fs_context *fc);
+		int (*get_tree)(struct fs_context *fc);
+	};
+
+These operations are invoked by the various stages of the mount procedure to
+manage the filesystem context.  They are as follows:
+
+ (*) void (*free)(struct fs_context *fc);
+
+     Called to clean up the filesystem-specific part of the filesystem context
+     when the context is destroyed.  It should be aware that parts of the
+     context may have been removed and NULL'd out by ->get_tree().
+
+ (*) int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
+
+     Called when a filesystem context has been duplicated to get any refs or
+     copy any non-referenced resources held in the filesystem-specific part of
+     the filesystem context.  An error may be returned to indicate failure to
+     do this.
+
+     [!] Note that even if this fails, put_fs_context() will be called
+	 immediately thereafter, so ->dup() *must* make the
+	 filesystem-specific part safe for ->free().
+
+ (*) int (*parse_option)(struct fs_context *fc, char *p);
+
+     Called when an option is to be added to the filesystem context.  p points
+     to the option string, likely in "key[=val]" format.  VFS-specific options
+     will have been weeded out and fc->sb_flags updated in the context.
+     Security options will also have been weeded out and fc->security updated.
+
+     If successful, 0 should be returned and a negative error code otherwise.
+     If an ambiguous error (such as -EINVAL) is returned, sb_cfg_error() or
+     sb_cfg_inval() should be used to provide a string that provides more
+     information.
+
+ (*) int (*monolithic_mount_data)(struct fs_context *fc, void *data);
+
+     Called when the mount(2) system call is invoked to pass the entire data
+     page in one go.  If this is expected to be just a list of "key[=val]"
+     items separated by commas, then this may be set to NULL.
+
+     The return value is as for ->parse_option().
+
+     If the filesystem (eg. NFS) needs to examine the data first and then finds
+     it's the standard key-val list then it may pass it off to
+     generic_monolithic_mount_data().
+
+ (*) int (*validate)(struct fs_context *fc);
+
+     Called when all the options have been applied and the mount is about to
+     take place.  It is should check for inconsistencies from mount options and
+     it is also allowed to do preliminary resource acquisition.  For instance,
+     the core NFS module could load the NFS protocol module here.
+
+     Note that if fc->mount_type == FS_CONTEXT_FOR_REMOUNT, some of the options
+     necessary for a new mount may not be set.
+
+     The return value is as for ->parse_option().
+
+ (*) int (*get_tree)(struct fs_context *fc);
+
+     Called to get or create the mountable root and superblock, using the
+     information stored in the filesystem context (remounts go
+     via a different vector).  It may detach any resources it desires from the
+     filesystem context and transfer them to the superblock it
+     creates.
+
+     On success it should set fc->root to the mountable root.
+
+     In the case of an error, it should return a negative error code and
+     consider invoking sb_cfg_inval() or sb_cfg_error().
+
+
+=========================================
+FILESYSTEM CONTEXT SECURITY
+========================================
+
+The filesystem context contains a security points that the LSMs
+can use for building up a security context for the superblock to be mounted.
+There are a number of operations used by the new mount code for this purpose:
+
+ (*) int security_fs_context_alloc(struct fs_context *fc,
+				  struct super_block *src_sb);
+
+     Called to initialise fc->security (which is preset to NULL) and allocate
+     any resources needed.  It should return 0 on success and a negative error
+     code on failure.
+
+     src_sb is non-NULL in the case of a remount (FS_CONTEXT_FOR_REMOUNT) in
+     which case it indicates the superblock to be remounted or in the case of a
+     submount (FS_CONTEXT_FOR_SUBMOUNT) in which case it indicates the parent
+     superblock.
+
+ (*) int security_fs_context_dup(struct fs_context *fc,
+				struct fs_context *src_mc);
+
+     Called to initialise fc->security (which is preset to NULL) and allocate
+     any resources needed.  The original filesystem context is
+     pointed to by src_mc and may be used for reference.  It should return 0 on
+     success and a negative error code on failure.
+
+ (*) void security_fs_context_free(struct fs_context *fc);
+
+     Called to clean up anything attached to fc->security.  Note that the
+     contents may have been transferred to a superblock and the pointer NULL'd
+     out during mount.
+
+ (*) int security_fs_context_parse_option(struct fs_context *fc, char *opt);
+
+     Called for each mount option.  The mount options are in "key[=val]" form.
+     An active LSM may reject one with an error, pass one over and return 0 or
+     consume one and return 1.  If consumed, the option isn't passed on to the
+     filesystem.
+
+     If it returns an error, more information can be returned with
+     sb_cfg_inval() or sb_cfg_error().
+
+ (*) int security_sb_get_tree(struct fs_context *fc);
+
+     Called during the mount procedure to verify that the specified superblock
+     is allowed to be mounted and to transfer the security data there.
+
+     On success, it should return 0; otherwise it should return an error and
+     perhaps call invalf() or errorf() to indicate the problem.  It should not
+     return -ENOMEM as this should be taken care of in advance.
+
+     [NOTE] Should I add a security_fs_context_validate() operation so that the
+     LSM has the opportunity to allocate stuff and check the options as a
+     whole?
+
+
+=================================
+VFS FILESYSTEM CONTEXT OPERATIONS
+=================================
+
+There are four operations for creating a filesystem context and
+one for destroying a context:
+
+ (*) struct fs_context *__vfs_new_fs_context(struct file_system_type *fs_type,
+					     struct super_block *src_sb;
+					     unsigned int ms_flags);
+
+     Create a filesystem context given a filesystem type pointer.
+     This allocates the filesystem context, sets the flags,
+     initialises the security and calls fs_type->init_fs_context() to initialise
+     the filesystem context.
+
+     src_sb can be NULL or it may indicate a superblock that is going to be
+     remounted (FS_CONTEXT_FOR_REMOUNT) or a superblock that is the parent of a
+     submount (FS_CONTEXT_FOR_SUBMOUNT).  This superblock is provided as a
+     source of namespace information.
+
+ (*) struct fs_context *vfs_sb_reconfig(struct vfsmount *mnt,
+					unsigned int ms_flags);
+
+     Create a filesystem context from the same filesystem as an
+     extant mount and initialise the mount parameters from the superblock
+     underlying that mount.  This is for use by remount.
+
+ (*) struct fs_context *vfs_new_fs_context(const char *fs_name);
+
+     Create a filesystem context given a filesystem name.  It is assumed that
+     the mount flags will be passed in as text options or set directly later.
+     This is intended to be called from sys_mount() or sys_fsopen().  This
+     copies current's namespaces to the context.
+
+ (*) struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc);
+
+     Duplicate a filesystem context, copying any options noted and duplicating
+     or additionally referencing any resources held therein.  This is
+     available for use where a filesystem has to get a mount within a mount,
+     such as NFS4 does by internally mounting the root of the target server
+     and then doing a private pathwalk to the target directory.
+
+ (*) void put_fs_context(struct fs_context *fc);
+
+     Destroy a filesystem context, releasing any resources it holds.  This
+     calls the ->free() operation.  This is intended to be called by anyone
+     who created a filesystem context.
+
+     [!] filesystem contexts are not refcounted, so this causes unconditional
+	 destruction.
+
+In all the above operations, apart from the put op, the return is a mount
+context pointer or a negative error code.  No error string is saved as the
+error string is only guaranteed as long as the file_system_type is pinned (and
+thus the module).
+
+In the remaining operations, if an error occurs, a negative error code is
+returned and, if not obvious, fc->error_msg may have been set to point to a
+useful string.  This string should not be freed.
+
+ (*) int vfs_get_tree(struct fs_context *fc);
+
+     Get or create the mountable root and superblock, using the parameters in
+     the filesystem context to select/configure the superblock.  This invokes
+     the ->validate() op and then the ->get_tree() op.
+
+     [NOTE] ->validate() can probably be rolled into ->get_tree() and
+     ->remount_fs_fc().
+
+ (*) struct vfsmount *vfs_kern_mount_fc(struct fs_context *fc);
+
+     Create a mount given the parameters in the specified filesystem context.
+
+ (*) struct vfsmount *vfs_submount_fc(const struct dentry *mountpoint,
+				      struct fs_context *fc);
+
+     Create a mount given a filesystem context and set MS_SUBMOUNT on it.  A
+     wrapper around vfs_kern_mount_fc().  This is intended to be called from
+     filesystems that have automount points (NFS, AFS, ...).
+
+ (*) int vfs_parse_mount_option(struct fs_context *fc, char *data);
+
+     Supply a single mount option to the filesystem context.  The mount option
+     should likely be in a "key[=val]" string form.  The option is first
+     checked to see if it corresponds to a standard mount flag (in which case
+     it is used to mark an MS_xxx flag and consumed) or a security option (in
+     which case the LSM consumes it) before it is passed on to the filesystem.
+
+ (*) int generic_monolithic_mount_data(struct fs_context *fc, void *data);
+
+     Parse a sys_mount() data page, assuming the form to be a text list
+     consisting of key[=val] options separated by commas.  Each item in the
+     list is passed to vfs_mount_option().  This is the default when the
+     ->monolithic_mount_data() operation is NULL.
diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h
new file mode 100644
index 000000000000..429c40be2c9e
--- /dev/null
+++ b/include/linux/fs_context.h
@@ -0,0 +1,72 @@
+/* Filesystem superblock creation and reconfiguration context.
+ *
+ * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_FS_CONTEXT_H
+#define _LINUX_FS_CONTEXT_H
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+struct cred;
+struct dentry;
+struct file_operations;
+struct file_system_type;
+struct mnt_namespace;
+struct net;
+struct pid_namespace;
+struct super_block;
+struct user_namespace;
+struct vfsmount;
+
+enum fs_context_purpose {
+	FS_CONTEXT_FOR_NEW,	/* New superblock for direct mount */
+	FS_CONTEXT_FOR_SUBMOUNT,	/* New superblock for automatic submount */
+	FS_CONTEXT_FOR_REMOUNT,	/* Superblock reconfiguration for remount */
+};
+
+/*
+ * Filesystem context as allocated and constructed by the ->init_fs_context()
+ * file_system_type operation.  The size of the object allocated is specified
+ * in struct file_system_type::fs_context_size and this must include sufficient
+ * space for the fs_context struct.
+ *
+ * Superblock creation fills in ->root whereas reconfiguration begins with this
+ * already set.
+ *
+ * See Documentation/filesystems/mounting.txt
+ */
+struct fs_context {
+	const struct fs_context_operations *ops;
+	struct file_system_type	*fs_type;
+	struct dentry		*root;		/* The root and superblock */
+	struct user_namespace	*user_ns;	/* The user namespace for this mount */
+	struct net		*net_ns;	/* The network namespace for this mount */
+	const struct cred	*cred;		/* The mounter's credentials */
+	char			*device;	/* The device name or mount target */
+	char			*subtype;	/* The subtype to set on the superblock */
+	void			*security;	/* The LSM context */
+	unsigned int		sb_flags;	/* The superblock flags (MS_*) */
+	bool			sloppy;		/* Unrecognised options are okay */
+	bool			silent;
+	bool			degraded;	/* True if the context can't be reused */
+	enum fs_context_purpose	purpose : 8;
+};
+
+struct fs_context_operations {
+	void (*free)(struct fs_context *fc);
+	int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
+	int (*parse_option)(struct fs_context *fc, char *p);
+	int (*monolithic_mount_data)(struct fs_context *fc, void *data);
+	int (*validate)(struct fs_context *fc);
+	int (*get_tree)(struct fs_context *fc);
+};
+
+#endif /* _LINUX_FS_CONTEXT_H */

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 09/27] VFS: Add LSM hooks for filesystem context [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (7 preceding siblings ...)
  2017-06-14 15:16 ` [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context " David Howells
@ 2017-06-14 15:16 ` David Howells
  2017-06-14 15:16 ` [PATCH 10/27] VFS: Implement a filesystem superblock creation/configuration " David Howells
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:16 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Add LSM hooks for use by the filesystem context code.  This includes:

 (1) Hooks to handle allocation, duplication and freeing of the security
     record attached to a filesystem context.

 (2) A hook to snoop a mount options in key[=val] form.  If the LSM decides
     it wants to handle it, it can suppress the option being passed to the
     filesystem.  Note that 'val' may include commas and binary data with
     the fsopen patch.

 (3) A hook to transfer the security from the context to a newly created
     superblock.

 (4) A hook to rule on whether a path point can be used as a mountpoint.

These are intended to replace:

	security_sb_copy_data
	security_sb_kern_mount
	security_sb_mount
	security_sb_set_mnt_opts
	security_sb_clone_mnt_opts
	security_sb_parse_opts_str

Signed-off-by: David Howells <dhowells@redhat.com>
cc: linux-security-module@vger.kernel.org
---

 include/linux/lsm_hooks.h |   45 +++++++++++
 include/linux/security.h  |   33 ++++++++
 security/security.c       |   30 +++++++
 security/selinux/hooks.c  |  181 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 289 insertions(+)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 080f34e66017..62500658cc9f 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -75,6 +75,38 @@
  *	should enable secure mode.
  *	@bprm contains the linux_binprm structure.
  *
+ * Security hooks for mount using fd context.
+ *
+ * @fs_context_alloc:
+ *	Allocate and attach a security structure to sc->security.  This pointer
+ *	is initialised to NULL by the caller.
+ *	@fc indicates the new filesystem context.
+ *	@src_sb indicates the source superblock of a submount.
+ * @fs_context_dup:
+ *	Allocate and attach a security structure to sc->security.  This pointer
+ *	is initialised to NULL by the caller.
+ *	@fc indicates the new filesystem context.
+ *	@src_fc indicates the original filesystem context.
+ * @fs_context_free:
+ *	Clean up a filesystem context.
+ *	@fc indicates the filesystem context.
+ * @fs_context_parse_option:
+ *	Userspace provided an option to configure a superblock.  The LSM may
+ *	reject it with an error and may use it for itself, in which case it
+ *	should return 1; otherwise it should return 0 to pass it on to the
+ *	filesystem.
+ *	@fc indicates the filesystem context.
+ *	@p indicates the option in "key[=val]" form.
+ * @sb_get_tree:
+ *	Assign the security to a newly created superblock.
+ *	@fc indicates the filesystem context.
+ *	@fc->root indicates the root that will be mounted.
+ *	@fc->root->d_sb points to the superblock.
+ * @sb_mountpoint:
+ *	Equivalent of sb_mount, but with an fs_context.
+ *	@fc indicates the filesystem context.
+ *	@mountpoint indicates the path on which the mount will take place.
+ *
  * Security hooks for filesystem operations.
  *
  * @sb_alloc_security:
@@ -1372,6 +1404,13 @@ union security_list_options {
 	void (*bprm_committing_creds)(struct linux_binprm *bprm);
 	void (*bprm_committed_creds)(struct linux_binprm *bprm);
 
+	int (*fs_context_alloc)(struct fs_context *fc, struct super_block *src_sb);
+	int (*fs_context_dup)(struct fs_context *fc, struct fs_context *src_sc);
+	void (*fs_context_free)(struct fs_context *fc);
+	int (*fs_context_parse_option)(struct fs_context *fc, char *opt);
+	int (*sb_get_tree)(struct fs_context *fc);
+	int (*sb_mountpoint)(struct fs_context *fc, struct path *mountpoint);
+
 	int (*sb_alloc_security)(struct super_block *sb);
 	void (*sb_free_security)(struct super_block *sb);
 	int (*sb_copy_data)(char *orig, char *copy);
@@ -1683,6 +1722,12 @@ struct security_hook_heads {
 	struct list_head bprm_secureexec;
 	struct list_head bprm_committing_creds;
 	struct list_head bprm_committed_creds;
+	struct list_head fs_context_alloc;
+	struct list_head fs_context_dup;
+	struct list_head fs_context_free;
+	struct list_head fs_context_parse_option;
+	struct list_head sb_get_tree;
+	struct list_head sb_mountpoint;
 	struct list_head sb_alloc_security;
 	struct list_head sb_free_security;
 	struct list_head sb_copy_data;
diff --git a/include/linux/security.h b/include/linux/security.h
index af675b576645..e7c774fdffd9 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -55,6 +55,7 @@ struct msg_queue;
 struct xattr;
 struct xfrm_sec_ctx;
 struct mm_struct;
+struct fs_context;
 
 /* If capable should audit the security request */
 #define SECURITY_CAP_NOAUDIT 0
@@ -224,6 +225,12 @@ int security_bprm_check(struct linux_binprm *bprm);
 void security_bprm_committing_creds(struct linux_binprm *bprm);
 void security_bprm_committed_creds(struct linux_binprm *bprm);
 int security_bprm_secureexec(struct linux_binprm *bprm);
+int security_fs_context_alloc(struct fs_context *fc, struct super_block *sb);
+int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc);
+void security_fs_context_free(struct fs_context *fc);
+int security_fs_context_parse_option(struct fs_context *fc, char *opt);
+int security_sb_get_tree(struct fs_context *fc);
+int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint);
 int security_sb_alloc(struct super_block *sb);
 void security_sb_free(struct super_block *sb);
 int security_sb_copy_data(char *orig, char *copy);
@@ -520,6 +527,32 @@ static inline int security_bprm_secureexec(struct linux_binprm *bprm)
 	return cap_bprm_secureexec(bprm);
 }
 
+static inline int security_fs_context_alloc(struct fs_context *fc,
+					    struct super_block *src_sb)
+{
+	return 0;
+}
+static inline int security_fs_context_dup(struct fs_context *fc,
+					  struct fs_context *src_fc)
+{
+	return 0;
+}
+static inline void security_fs_context_free(struct fs_context *fc)
+{
+}
+static inline int security_fs_context_parse_option(struct fs_context *fc, char *opt)
+{
+	return 0;
+}
+static inline int security_sb_get_tree(struct fs_context *fc)
+{
+	return 0;
+}
+static inline int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint)
+{
+	return 0;
+}
+
 static inline int security_sb_alloc(struct super_block *sb)
 {
 	return 0;
diff --git a/security/security.c b/security/security.c
index b9fea3999cf8..27b195966cad 100644
--- a/security/security.c
+++ b/security/security.c
@@ -316,6 +316,36 @@ int security_bprm_secureexec(struct linux_binprm *bprm)
 	return call_int_hook(bprm_secureexec, 0, bprm);
 }
 
+int security_fs_context_alloc(struct fs_context *fc, struct super_block *src_sb)
+{
+	return call_int_hook(fs_context_alloc, 0, fc, src_sb);
+}
+
+int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
+{
+	return call_int_hook(fs_context_dup, 0, fc, src_fc);
+}
+
+void security_fs_context_free(struct fs_context *fc)
+{
+	call_void_hook(fs_context_free, fc);
+}
+
+int security_fs_context_parse_option(struct fs_context *fc, char *opt)
+{
+	return call_int_hook(fs_context_parse_option, 0, fc, opt);
+}
+
+int security_sb_get_tree(struct fs_context *fc)
+{
+	return call_int_hook(sb_get_tree, 0, fc);
+}
+
+int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint)
+{
+	return call_int_hook(sb_mountpoint, 0, fc, mountpoint);
+}
+
 int security_sb_alloc(struct super_block *sb)
 {
 	return call_int_hook(sb_alloc_security, 0, sb);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7e498b16aed3..c93a21119fe3 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -47,6 +47,7 @@
 #include <linux/fdtable.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/fs_context.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/tty.h>
@@ -2826,6 +2827,179 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
 				   FILESYSTEM__UNMOUNT, NULL);
 }
 
+/* fsopen mount context operations */
+
+static int selinux_fs_context_alloc(struct fs_context *fc,
+				    struct super_block *src_sb)
+{
+	struct security_mnt_opts *opts;
+
+	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+	if (!opts)
+		return -ENOMEM;
+
+	fc->security = opts;
+	return 0;
+}
+
+static int selinux_fs_context_dup(struct fs_context *fc,
+				  struct fs_context *src_fc)
+{
+	const struct security_mnt_opts *src = src_fc->security;
+	struct security_mnt_opts *opts;
+	int i, n;
+
+	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+	if (!opts)
+		return -ENOMEM;
+	fc->security = opts;
+
+	if (!src || !src->num_mnt_opts)
+		return 0;
+	n = opts->num_mnt_opts = src->num_mnt_opts;
+
+	if (src->mnt_opts) {
+		opts->mnt_opts = kcalloc(n, sizeof(char *), GFP_KERNEL);
+		if (!opts->mnt_opts)
+			return -ENOMEM;
+
+		for (i = 0; i < n; i++) {
+			if (src->mnt_opts[i]) {
+				opts->mnt_opts[i] = kstrdup(src->mnt_opts[i],
+							    GFP_KERNEL);
+				if (!opts->mnt_opts[i])
+					return -ENOMEM;
+			}
+		}
+	}
+
+	if (src->mnt_opts_flags) {
+		opts->mnt_opts_flags = kmemdup(src->mnt_opts_flags,
+					       n * sizeof(int), GFP_KERNEL);
+		if (!opts->mnt_opts_flags)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void selinux_fs_context_free(struct fs_context *fc)
+{
+	struct security_mnt_opts *opts = fc->security;
+
+	security_free_mnt_opts(opts);
+	fc->security = NULL;
+}
+
+static int selinux_fs_context_parse_option(struct fs_context *fc, char *opt)
+{
+	struct security_mnt_opts *opts = fc->security;
+	substring_t args[MAX_OPT_ARGS];
+	unsigned int have;
+	char *c, **oo;
+	int token, ctx, i, *of;
+
+	token = match_token(opt, tokens, args);
+	if (token == Opt_error)
+		return 0; /* Doesn't belong to us. */
+
+	have = 0;
+	for (i = 0; i < opts->num_mnt_opts; i++)
+		have |= 1 << opts->mnt_opts_flags[i];
+	if (have & (1 << token))
+		return invalf("SELinux: Duplicate mount options");
+
+	switch (token) {
+	case Opt_context:
+		if (have & (1 << Opt_defcontext))
+			goto incompatible;
+		ctx = CONTEXT_MNT;
+		goto copy_context_string;
+
+	case Opt_fscontext:
+		ctx = FSCONTEXT_MNT;
+		goto copy_context_string;
+
+	case Opt_rootcontext:
+		ctx = ROOTCONTEXT_MNT;
+		goto copy_context_string;
+
+	case Opt_defcontext:
+		if (have & (1 << Opt_context))
+			goto incompatible;
+		ctx = DEFCONTEXT_MNT;
+		goto copy_context_string;
+
+	case Opt_labelsupport:
+		return 1;
+
+	default:
+		return invalf("SELinux: Unknown mount option");
+	}
+
+copy_context_string:
+	if (opts->num_mnt_opts > 3)
+		return invalf("SELinux: Too many options");
+
+	of = krealloc(opts->mnt_opts_flags,
+		      (opts->num_mnt_opts + 1) * sizeof(int), GFP_KERNEL);
+	if (!of)
+		return -ENOMEM;
+	of[opts->num_mnt_opts] = 0;
+	opts->mnt_opts_flags = of;
+
+	oo = krealloc(opts->mnt_opts,
+		      (opts->num_mnt_opts + 1) * sizeof(char *), GFP_KERNEL);
+	if (!oo)
+		return -ENOMEM;
+	oo[opts->num_mnt_opts] = NULL;
+	opts->mnt_opts = oo;
+
+	c = match_strdup(&args[0]);
+	if (!c)
+		return -ENOMEM;
+	opts->mnt_opts[opts->num_mnt_opts] = c;
+	opts->mnt_opts_flags[opts->num_mnt_opts] = ctx;
+	opts->num_mnt_opts++;
+	return 1;
+
+incompatible:
+	return invalf("SELinux: Incompatible mount options");
+}
+
+static int selinux_sb_get_tree(struct fs_context *fc)
+{
+	const struct cred *cred = current_cred();
+	struct common_audit_data ad;
+	int rc;
+
+	rc = selinux_set_mnt_opts(fc->root->d_sb, fc->security, 0, NULL);
+	if (rc)
+		return rc;
+
+	/* Allow all mounts performed by the kernel */
+	if (fc->sb_flags & MS_KERNMOUNT)
+		return 0;
+
+	ad.type = LSM_AUDIT_DATA_DENTRY;
+	ad.u.dentry = fc->root;
+	rc = superblock_has_perm(cred, fc->root->d_sb, FILESYSTEM__MOUNT, &ad);
+	if (rc < 0)
+		errorf("SELinux: Mount of superblock not permitted");
+	return rc;
+}
+
+static int selinux_sb_mountpoint(struct fs_context *fc, struct path *mountpoint)
+{
+	const struct cred *cred = current_cred();
+	int ret;
+
+	ret = path_has_perm(cred, mountpoint, FILE__MOUNTON);
+	if (ret < 0)
+		errorf("SELinux: Mount on mountpoint not permitted");
+	return ret;
+}
+
 /* inode security operations */
 
 static int selinux_inode_alloc_security(struct inode *inode)
@@ -6154,6 +6328,13 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
 	LSM_HOOK_INIT(bprm_secureexec, selinux_bprm_secureexec),
 
+	LSM_HOOK_INIT(fs_context_alloc, selinux_fs_context_alloc),
+	LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
+	LSM_HOOK_INIT(fs_context_free, selinux_fs_context_free),
+	LSM_HOOK_INIT(fs_context_parse_option, selinux_fs_context_parse_option),
+	LSM_HOOK_INIT(sb_get_tree, selinux_sb_get_tree),
+	LSM_HOOK_INIT(sb_mountpoint, selinux_sb_mountpoint),
+
 	LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
 	LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
 	LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 10/27] VFS: Implement a filesystem superblock creation/configuration context [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (8 preceding siblings ...)
  2017-06-14 15:16 ` [PATCH 09/27] VFS: Add LSM hooks for filesystem context [ver #5] David Howells
@ 2017-06-14 15:16 ` David Howells
  2017-06-14 15:17 ` [PATCH 11/27] VFS: Remove unused code after filesystem context changes " David Howells
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:16 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Implement a filesystem context concept to be used during superblock
creation for mount and superblock reconfiguration for remount.

The mounting procedure then becomes:

 (1) Allocate new fs_context context.

 (2) Configure the context.

 (3) Create superblock.

 (4) Mount the superblock any number of times.

 (5) Destroy the context.

Rather than calling fs_type->mount(), an fs_context struct is created and
fs_type->init_fs_context() is called to set it up.
fs_type->fs_context_size says how much space should be allocated for the
config context.  The fs_context struct is placed at the beginning and any
extra space is for the filesystem's use.

A set of operations has to be set by ->init_fs_context() to provide
freeing, duplication, option parsing, binary data parsing, validation,
mounting and superblock filling.

Legacy filesystems are supported by the provision of a set of legacy
fs_context operations that build up a list of mount options and then invoke
fs_type->mount() from within the fs_context ->get_tree() operation.  This
allows all filesystems to be accessed using fs_context.

It should be noted that, whilst this patch adds a lot of lines of code,
there is quite a bit of duplication with existing code that can be
eliminated should all filesystems be converted over.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/Makefile                |    3 
 fs/fs_context.c            |  501 ++++++++++++++++++++++++++++++++++++++++++++
 fs/internal.h              |    2 
 fs/libfs.c                 |   18 +-
 fs/namespace.c             |  399 ++++++++++++++++++++++++++---------
 fs/super.c                 |  158 ++++++++++++--
 include/linux/fs.h         |   17 +
 include/linux/fs_context.h |   12 +
 include/linux/mount.h      |    2 
 9 files changed, 992 insertions(+), 120 deletions(-)
 create mode 100644 fs/fs_context.c

diff --git a/fs/Makefile b/fs/Makefile
index 7bbaca9c67b1..ffe728cc15e1 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -11,7 +11,8 @@ obj-y :=	open.o read_write.o file_table.o super.o \
 		attr.o bad_inode.o file.o filesystems.o namespace.o \
 		seq_file.o xattr.o libfs.o fs-writeback.o \
 		pnode.o splice.o sync.o utimes.o \
-		stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
+		stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
+		fs_context.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=	buffer.o block_dev.o direct-io.o mpage.o
diff --git a/fs/fs_context.c b/fs/fs_context.c
new file mode 100644
index 000000000000..98ba65d49b21
--- /dev/null
+++ b/fs/fs_context.c
@@ -0,0 +1,501 @@
+/* Provide a way to create a superblock configuration context within the kernel
+ * that allows a superblock to be set up prior to mounting.
+ *
+ * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/fs_context.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/nsproxy.h>
+#include <linux/slab.h>
+#include <linux/magic.h>
+#include <linux/security.h>
+#include <linux/parser.h>
+#include <linux/mnt_namespace.h>
+#include <linux/pid_namespace.h>
+#include <linux/user_namespace.h>
+#include <net/net_namespace.h>
+#include "mount.h"
+
+struct legacy_fs_context {
+	struct fs_context	fc;
+	char			*legacy_data;	/* Data page for legacy filesystems */
+	char			*secdata;
+	unsigned int		data_usage;
+};
+
+static const struct fs_context_operations legacy_fs_context_ops;
+
+static const match_table_t common_set_mount_options = {
+	{ MS_DIRSYNC,		"dirsync" },
+	{ MS_I_VERSION,		"iversion" },
+	{ MS_LAZYTIME,		"lazytime" },
+	{ MS_MANDLOCK,		"mand" },
+	{ MS_POSIXACL,		"posixacl" },
+	{ MS_RDONLY,		"ro" },
+	{ MS_REC,		"rec" },
+	{ MS_SYNCHRONOUS,	"sync" },
+	{ MS_VERBOSE,		"verbose" },
+	{ },
+};
+
+static const match_table_t common_clear_mount_options = {
+	{ MS_LAZYTIME,		"nolazytime" },
+	{ MS_MANDLOCK,		"nomand" },
+	{ MS_RDONLY,		"rw" },
+	{ MS_SILENT,		"silent" },
+	{ MS_SYNCHRONOUS,	"async" },
+	{ },
+};
+
+static const match_table_t forbidden_mount_options = {
+	{ MS_BIND,		"bind" },
+	{ MS_MOVE,		"move" },
+	{ MS_PRIVATE,		"private" },
+	{ MS_REMOUNT,		"remount" },
+	{ MS_SHARED,		"shared" },
+	{ MS_SLAVE,		"slave" },
+	{ MS_UNBINDABLE,	"unbindable" },
+	{ MS_NOATIME,		"noatime" },
+	{ MS_RELATIME,		"relatime" },
+	{ MS_RELATIME,		"norelatime" },
+	{ MS_STRICTATIME,	"strictatime" },
+	{ MS_STRICTATIME,	"nostrictatime" },
+	{ MS_NODIRATIME,	"nodiratime" },
+	{ MS_NODEV,		"dev" },
+	{ MS_NODEV,		"nodev" },
+	{ MS_NOEXEC,		"exec" },
+	{ MS_NOEXEC,		"noexec" },
+	{ MS_NOSUID,		"suid" },
+	{ MS_NOSUID,		"nosuid" },
+	{ },
+};
+
+/*
+ * Check for a common mount option.
+ */
+static int vfs_parse_ms_mount_option(struct fs_context *fc, char *data)
+{
+	substring_t args[MAX_OPT_ARGS];
+	unsigned int token;
+
+	token = match_token(data, common_set_mount_options, args);
+	if (token) {
+		fc->sb_flags |= token;
+		return 1;
+	}
+
+	token = match_token(data, common_clear_mount_options, args);
+	if (token) {
+		fc->sb_flags &= ~token;
+		return 1;
+	}
+
+	token = match_token(data, forbidden_mount_options, args);
+	if (token)
+		return invalf("VFS: Mount option, not superblock option");
+
+	return 0;
+}
+
+/**
+ * vfs_parse_mount_option - Add a single mount option to a superblock config
+ * @fc: The filesystem context to modify
+ * @p: The option to apply.
+ *
+ * A single mount option in string form is applied to the filesystem context
+ * being set up.  Certain standard options (for example "ro") are translated
+ * into flag bits without going to the filesystem.  The active security module
+ * is allowed to observe and poach options.  Any other options are passed over
+ * to the filesystem to parse.
+ *
+ * This may be called multiple times for a context.
+ *
+ * Returns 0 on success and a negative error code on failure.  In the event of
+ * failure, supplementary error information may have been set.
+ */
+int vfs_parse_mount_option(struct fs_context *fc, char *p)
+{
+	int ret;
+
+	ret = vfs_parse_ms_mount_option(fc, p);
+	if (ret < 0)
+		return ret;
+	if (ret == 1)
+		return 0;
+
+	ret = security_fs_context_parse_option(fc, p);
+	if (ret < 0)
+		return ret;
+	if (ret == 1)
+		return 0;
+
+	if (fc->ops->parse_option)
+		return fc->ops->parse_option(fc, p);
+
+	return invalf("VFS: FS takes no options");
+}
+EXPORT_SYMBOL(vfs_parse_mount_option);
+
+/**
+ * generic_monolithic_mount_data - Parse key[=val][,key[=val]]* mount data
+ * @mc: The superblock configuration to fill in.
+ * @data: The data to parse
+ *
+ * Parse a blob of data that's in key[=val][,key[=val]]* form.  This can be
+ * called from the ->monolithic_mount_data() fs_context operation.
+ *
+ * Returns 0 on success or the error returned by the ->parse_option() fs_context
+ * operation on failure.
+ */
+int generic_monolithic_mount_data(struct fs_context *ctx, void *data)
+{
+	char *options = data, *p;
+	int ret;
+
+	if (!options)
+		return 0;
+
+	while ((p = strsep(&options, ",")) != NULL) {
+		if (*p) {
+			ret = vfs_parse_mount_option(ctx, p);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(generic_monolithic_mount_data);
+
+/**
+ * vfs_new_fs_context - Create a filesystem context.
+ * @fs_type: The filesystem type.
+ * @src_sb: A superblock from which this one derives (or NULL)
+ * @sb_flags: Superblock flags and op flags (such as MS_REMOUNT)
+ * @purpose: The purpose that this configuration shall be used for.
+ *
+ * Open a filesystem and create a mount context.  The mount context is
+ * initialised with the supplied flags and, if a submount/automount from
+ * another superblock (@src_sb), may have parameters such as namespaces copied
+ * across from that superblock.
+ */
+struct fs_context *vfs_new_fs_context(struct file_system_type *fs_type,
+				      struct super_block *src_sb,
+				      unsigned int sb_flags,
+				      enum fs_context_purpose purpose)
+{
+	struct fs_context *fc;
+	size_t fc_size = fs_type->fs_context_size;
+	int ret;
+
+	BUG_ON(fs_type->init_fs_context && fc_size < sizeof(*fc));
+
+	if (!fs_type->init_fs_context)
+		fc_size = sizeof(struct legacy_fs_context);
+
+	fc = kzalloc(fc_size, GFP_KERNEL);
+	if (!fc)
+		return ERR_PTR(-ENOMEM);
+
+	fc->purpose	= purpose;
+	fc->sb_flags	= sb_flags;
+	fc->fs_type	= get_filesystem(fs_type);
+	fc->cred	= get_current_cred();
+
+	switch (purpose) {
+	case FS_CONTEXT_FOR_NEW:
+		fc->user_ns = get_user_ns(fc->cred->user_ns);
+		fc->net_ns = get_net(current->nsproxy->net_ns);
+		break;
+	case FS_CONTEXT_FOR_SUBMOUNT:
+		fc->user_ns = get_user_ns(src_sb->s_user_ns);
+		fc->net_ns = get_net(current->nsproxy->net_ns);
+		break;
+	case FS_CONTEXT_FOR_REMOUNT:
+		/* We don't pin any namespaces as the superblock's
+		 * subscriptions cannot be changed at this point.
+		 */
+		break;
+	}
+
+
+	/* TODO: Make all filesystems support this unconditionally */
+	if (fc->fs_type->init_fs_context) {
+		ret = fc->fs_type->init_fs_context(fc, src_sb);
+		if (ret < 0)
+			goto err_fc;
+	} else {
+		fc->ops = &legacy_fs_context_ops;
+	}
+
+	/* Do the security check last because ->init_fs_context may change the
+	 * namespace subscriptions.
+	 */
+	ret = security_fs_context_alloc(fc, src_sb);
+	if (ret < 0)
+		goto err_fc;
+
+	return fc;
+
+err_fc:
+	put_fs_context(fc);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vfs_new_fs_context);
+
+/**
+ * vfs_sb_reconfig - Create a filesystem context for remount/reconfiguration
+ * @mnt: The mountpoint to open
+ * @sb_flags: Superblock flags and op flags (such as MS_REMOUNT)
+ *
+ * Open a mounted filesystem and create a filesystem context such that a
+ * remount can be effected.
+ */
+struct fs_context *vfs_sb_reconfig(struct vfsmount *mnt,
+				   unsigned int sb_flags)
+{
+	return vfs_new_fs_context(mnt->mnt_sb->s_type, mnt->mnt_sb,
+				  sb_flags, FS_CONTEXT_FOR_REMOUNT);
+}
+
+/**
+ * vfs_dup_fc_config: Duplicate a filesytem context.
+ * @src_fc: The context to copy.
+ */
+struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)
+{
+	struct fs_context *fc;
+	size_t fc_size;
+	int ret;
+
+	if (!src_fc->ops->dup)
+		return ERR_PTR(-ENOTSUPP);
+
+	fc_size = src_fc->fs_type->fs_context_size;
+	if (!src_fc->fs_type->init_fs_context)
+		fc_size = sizeof(struct legacy_fs_context);
+
+	fc = kmemdup(src_fc, src_fc->fs_type->fs_context_size, GFP_KERNEL);
+	if (!fc)
+		return ERR_PTR(-ENOMEM);
+
+	fc->device	= NULL;
+	fc->security	= NULL;
+	get_filesystem(fc->fs_type);
+	get_net(fc->net_ns);
+	get_user_ns(fc->user_ns);
+	get_cred(fc->cred);
+
+	/* Can't call put until we've called ->dup */
+	ret = fc->ops->dup(fc, src_fc);
+	if (ret < 0)
+		goto err_fc;
+
+	ret = security_fs_context_dup(fc, src_fc);
+	if (ret < 0)
+		goto err_fc;
+	return fc;
+
+err_fc:
+	put_fs_context(fc);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vfs_dup_fs_context);
+
+/**
+ * put_fs_context - Dispose of a superblock configuration context.
+ * @sc: The context to dispose of.
+ */
+void put_fs_context(struct fs_context *fc)
+{
+	struct super_block *sb;
+
+	if (fc->root) {
+		sb = fc->root->d_sb;
+		dput(fc->root);
+		fc->root = NULL;
+		deactivate_super(sb);
+	}
+
+	if (fc->ops && fc->ops->free)
+		fc->ops->free(fc);
+
+	security_fs_context_free(fc);
+	if (fc->net_ns)
+		put_net(fc->net_ns);
+	put_user_ns(fc->user_ns);
+	if (fc->cred)
+		put_cred(fc->cred);
+	kfree(fc->subtype);
+	put_filesystem(fc->fs_type);
+	kfree(fc->device);
+	kfree(fc);
+}
+EXPORT_SYMBOL(put_fs_context);
+
+/*
+ * Free the config for a filesystem that doesn't support fs_context.
+ */
+static void legacy_fs_context_free(struct fs_context *fc)
+{
+	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+
+	free_secdata(ctx->secdata);
+	kfree(ctx->legacy_data);
+}
+
+/*
+ * Duplicate a legacy config.
+ */
+static int legacy_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
+{
+	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+	struct legacy_fs_context *src_ctx = container_of(src_fc, struct legacy_fs_context, fc);
+
+	ctx->legacy_data = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!ctx->legacy_data)
+		return -ENOMEM;
+	memcpy(ctx->legacy_data, src_ctx->legacy_data, sizeof(PAGE_SIZE));
+	return 0;
+}
+
+/*
+ * Add an option to a legacy config.  We build up a comma-separated list of
+ * options.
+ */
+static int legacy_parse_option(struct fs_context *fc, char *p)
+{
+	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+	unsigned int usage = ctx->data_usage;
+	size_t len = strlen(p);
+
+	if (len > PAGE_SIZE - 2 - usage)
+		return invalf("VFS: Insufficient data buffer space");
+	if (memchr(p, ',', len) != NULL)
+		return invalf("VFS: Options cannot contain commas");
+	if (!ctx->legacy_data) {
+		ctx->legacy_data = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		if (!ctx->legacy_data)
+			return -ENOMEM;
+	}
+
+	ctx->legacy_data[usage++] = ',';
+	memcpy(ctx->legacy_data + usage, p, len);
+	usage += len;
+	ctx->legacy_data[usage] = '\0';
+	ctx->data_usage = usage;
+	return 0;
+}
+
+/*
+ * Add monolithic mount data.
+ */
+static int legacy_monolithic_mount_data(struct fs_context *fc, void *data)
+{
+	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+
+	if (ctx->data_usage != 0)
+		return invalf("VFS: Can't mix monolithic and individual options");
+	if (!data)
+		return 0;
+	if (!ctx->legacy_data) {
+		ctx->legacy_data = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		if (!ctx->legacy_data)
+			return -ENOMEM;
+	}
+
+	memcpy(ctx->legacy_data, data, PAGE_SIZE);
+	ctx->data_usage = PAGE_SIZE;
+	return 0;
+}
+
+/*
+ * Use the legacy mount validation step to strip out and process security
+ * config options.
+ */
+static int legacy_validate(struct fs_context *fc)
+{
+	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+
+	if (!ctx->legacy_data || ctx->fc.fs_type->fs_flags & FS_BINARY_MOUNTDATA)
+		return 0;
+
+	ctx->secdata = alloc_secdata();
+	if (!ctx->secdata)
+		return -ENOMEM;
+
+	return security_sb_copy_data(ctx->legacy_data, ctx->secdata);
+}
+
+/*
+ * Determine the superblock subtype.
+ */
+static int legacy_set_subtype(struct fs_context *fc)
+{
+	const char *subtype = strchr(fc->fs_type->name, '.');
+
+	if (subtype) {
+		subtype++;
+		if (!subtype[0])
+			return -EINVAL;
+	} else {
+		subtype = "";
+	}
+
+	fc->subtype = kstrdup(subtype, GFP_KERNEL);
+	if (!fc->subtype)
+		return -ENOMEM;
+	return 0;
+}
+
+/*
+ * Get a mountable root with the legacy mount command.
+ */
+static int legacy_get_tree(struct fs_context *fc)
+{
+	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+	struct super_block *sb;
+	struct dentry *root;
+	int ret;
+
+	root = ctx->fc.fs_type->mount(ctx->fc.fs_type, ctx->fc.sb_flags,
+				      ctx->fc.device, ctx->legacy_data);
+	if (IS_ERR(root))
+		return PTR_ERR(root);
+
+	sb = root->d_sb;
+	BUG_ON(!sb);
+
+	if ((ctx->fc.fs_type->fs_flags & FS_HAS_SUBTYPE) &&
+	    !fc->subtype) {
+		ret = legacy_set_subtype(fc);
+		if (ret < 0)
+			goto err_sb;
+	}
+
+	ctx->fc.root = root;
+	return 0;
+
+err_sb:
+	dput(root);
+	deactivate_locked_super(sb);
+	return ret;
+}
+
+static const struct fs_context_operations legacy_fs_context_ops = {
+	.free			= legacy_fs_context_free,
+	.dup			= legacy_fs_context_dup,
+	.parse_option		= legacy_parse_option,
+	.monolithic_mount_data	= legacy_monolithic_mount_data,
+	.validate		= legacy_validate,
+	.get_tree		= legacy_get_tree,
+};
diff --git a/fs/internal.h b/fs/internal.h
index 9676fe11c093..08d7816f8686 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -87,7 +87,7 @@ extern struct file *get_empty_filp(void);
 /*
  * super.c
  */
-extern int do_remount_sb(struct super_block *, int, void *, int);
+extern int do_remount_sb(struct super_block *, int, void *, int, struct fs_context *);
 extern bool trylock_super(struct super_block *sb);
 extern struct dentry *mount_fs(struct file_system_type *,
 			       int, const char *, void *);
diff --git a/fs/libfs.c b/fs/libfs.c
index 32c159ed33dd..21d1e6231707 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -9,6 +9,7 @@
 #include <linux/slab.h>
 #include <linux/cred.h>
 #include <linux/mount.h>
+#include <linux/fs_context.h>
 #include <linux/vfs.h>
 #include <linux/quotaops.h>
 #include <linux/mutex.h>
@@ -574,13 +575,28 @@ static DEFINE_SPINLOCK(pin_fs_lock);
 
 int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *count)
 {
+	struct fs_context *fc;
 	struct vfsmount *mnt = NULL;
+	int ret;
+
 	spin_lock(&pin_fs_lock);
 	if (unlikely(!*mount)) {
 		spin_unlock(&pin_fs_lock);
-		mnt = vfs_kern_mount(type, SB_KERNMOUNT, type->name, NULL);
+
+		fc = vfs_new_fs_context(type, NULL, SB_KERNMOUNT,
+					FS_CONTEXT_FOR_NEW);
+		if (IS_ERR(fc))
+			return PTR_ERR(fc);
+
+		ret = vfs_get_tree(fc);
+		if (ret < 0)
+			return ret;
+
+		mnt = vfs_kern_mount_fc(fc);
+		put_fs_context(fc);
 		if (IS_ERR(mnt))
 			return PTR_ERR(mnt);
+
 		spin_lock(&pin_fs_lock);
 		if (!*mount)
 			*mount = mnt;
diff --git a/fs/namespace.c b/fs/namespace.c
index 9a7dbf7b716f..cd44283dee99 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -25,7 +25,9 @@
 #include <linux/magic.h>
 #include <linux/bootmem.h>
 #include <linux/task_work.h>
+#include <linux/file.h>
 #include <linux/sched/task.h>
+#include <linux/fs_context.h>
 
 #include "pnode.h"
 #include "internal.h"
@@ -957,55 +959,6 @@ static struct mount *skip_mnt_tree(struct mount *p)
 	return p;
 }
 
-struct vfsmount *
-vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
-{
-	struct mount *mnt;
-	struct dentry *root;
-
-	if (!type)
-		return ERR_PTR(-ENODEV);
-
-	mnt = alloc_vfsmnt(name);
-	if (!mnt)
-		return ERR_PTR(-ENOMEM);
-
-	if (flags & SB_KERNMOUNT)
-		mnt->mnt.mnt_flags = MNT_INTERNAL;
-
-	root = mount_fs(type, flags, name, data);
-	if (IS_ERR(root)) {
-		mnt_free_id(mnt);
-		free_vfsmnt(mnt);
-		return ERR_CAST(root);
-	}
-
-	mnt->mnt.mnt_root = root;
-	mnt->mnt.mnt_sb = root->d_sb;
-	mnt->mnt_mountpoint = mnt->mnt.mnt_root;
-	mnt->mnt_parent = mnt;
-	lock_mount_hash();
-	list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
-	unlock_mount_hash();
-	return &mnt->mnt;
-}
-EXPORT_SYMBOL_GPL(vfs_kern_mount);
-
-struct vfsmount *
-vfs_submount(const struct dentry *mountpoint, struct file_system_type *type,
-	     const char *name, void *data)
-{
-	/* Until it is worked out how to pass the user namespace
-	 * through from the parent mount to the submount don't support
-	 * unprivileged mounts with submounts.
-	 */
-	if (mountpoint->d_sb->s_user_ns != &init_user_ns)
-		return ERR_PTR(-EPERM);
-
-	return vfs_kern_mount(type, SB_SUBMOUNT, name, data);
-}
-EXPORT_SYMBOL_GPL(vfs_submount);
-
 static struct mount *clone_mnt(struct mount *old, struct dentry *root,
 					int flag)
 {
@@ -1593,7 +1546,7 @@ static int do_umount(struct mount *mnt, int flags)
 			return -EPERM;
 		down_write(&sb->s_umount);
 		if (!(sb->s_flags & SB_RDONLY))
-			retval = do_remount_sb(sb, SB_RDONLY, NULL, 0);
+			retval = do_remount_sb(sb, SB_RDONLY, NULL, 0, NULL);
 		up_write(&sb->s_umount);
 		return retval;
 	}
@@ -2133,7 +2086,7 @@ static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp)
 
 static int flags_to_propagation_type(int flags)
 {
-	int type = flags & ~(MS_REC | SB_SILENT);
+	int type = flags & ~(MS_REC | MS_SILENT);
 
 	/* Fail if any non-propagation flags are set */
 	if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
@@ -2276,6 +2229,20 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
 }
 
 /*
+ * Parse the monolithic page of mount data given to sys_mount().
+ */
+static int parse_monolithic_mount_data(struct fs_context *fc, void *data)
+{
+	int (*monolithic_mount_data)(struct fs_context *, void *);
+
+	monolithic_mount_data = fc->ops->monolithic_mount_data;
+	if (!monolithic_mount_data)
+		monolithic_mount_data = generic_monolithic_mount_data;
+
+	return monolithic_mount_data(fc, data);
+}
+
+/*
  * change filesystem flags. dir should be a physical root of filesystem.
  * If you've mounted a non-root directory somewhere and want to do remount
  * on it - tough luck.
@@ -2283,9 +2250,11 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
 static int do_remount(struct path *path, int flags, int mnt_flags,
 		      void *data)
 {
+	struct fs_context *fc = NULL;
 	int err;
 	struct super_block *sb = path->mnt->mnt_sb;
 	struct mount *mnt = real_mount(path->mnt);
+	struct file_system_type *type = sb->s_type;
 
 	if (!check_mnt(mnt))
 		return -EINVAL;
@@ -2320,9 +2289,25 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
 		return -EPERM;
 	}
 
-	err = security_sb_remount(sb, data);
-	if (err)
-		return err;
+	if (type->init_fs_context) {
+		fc = vfs_sb_reconfig(path->mnt, flags);
+		if (IS_ERR(fc))
+			return PTR_ERR(fc);
+
+		err = parse_monolithic_mount_data(fc, data);
+		if (err < 0)
+			goto err_fc;
+
+		if (fc->ops->validate) {
+			err = fc->ops->validate(fc);
+			if (err < 0)
+				goto err_fc;
+		}
+	} else {
+		err = security_sb_remount(sb, data);
+		if (err)
+			return err;
+	}
 
 	down_write(&sb->s_umount);
 	if (flags & MS_BIND)
@@ -2330,7 +2315,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
 	else if (!capable(CAP_SYS_ADMIN))
 		err = -EPERM;
 	else
-		err = do_remount_sb(sb, flags, data, 0);
+		err = do_remount_sb(sb, flags, data, 0, fc);
 	if (!err) {
 		lock_mount_hash();
 		mnt_flags |= mnt->mnt.mnt_flags & ~MNT_USER_SETTABLE_MASK;
@@ -2339,6 +2324,9 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
 		unlock_mount_hash();
 	}
 	up_write(&sb->s_umount);
+err_fc:
+	if (fc)
+		put_fs_context(fc);
 	return err;
 }
 
@@ -2422,29 +2410,6 @@ static int do_move_mount(struct path *path, const char *old_name)
 	return err;
 }
 
-static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
-{
-	int err;
-	const char *subtype = strchr(fstype, '.');
-	if (subtype) {
-		subtype++;
-		err = -EINVAL;
-		if (!subtype[0])
-			goto err;
-	} else
-		subtype = "";
-
-	mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
-	err = -ENOMEM;
-	if (!mnt->mnt_sb->s_subtype)
-		goto err;
-	return mnt;
-
- err:
-	mntput(mnt);
-	return ERR_PTR(err);
-}
-
 /*
  * add a mount into a namespace's mount tree
  */
@@ -2492,40 +2457,91 @@ static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags)
 static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags);
 
 /*
- * create a new mount for userspace and request it to be added into the
- * namespace's tree
+ * Create a new mount using a superblock configuration and request it
+ * be added to the namespace tree.
  */
-static int do_new_mount(struct path *path, const char *fstype, int flags,
-			int mnt_flags, const char *name, void *data)
+static int do_new_mount_fc(struct fs_context *fc, struct path *mountpoint,
+			   unsigned int mnt_flags)
 {
-	struct file_system_type *type;
 	struct vfsmount *mnt;
-	int err;
-
-	if (!fstype)
-		return -EINVAL;
-
-	type = get_fs_type(fstype);
-	if (!type)
-		return -ENODEV;
+	int ret;
 
-	mnt = vfs_kern_mount(type, flags, name, data);
-	if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
-	    !mnt->mnt_sb->s_subtype)
-		mnt = fs_set_subtype(mnt, fstype);
+	ret = security_sb_mountpoint(fc, mountpoint);
+	if (ret < 0)
+		return ret;;
 
-	put_filesystem(type);
+	mnt = vfs_kern_mount_fc(fc);
 	if (IS_ERR(mnt))
 		return PTR_ERR(mnt);
 
+	ret = -EPERM;
 	if (mount_too_revealing(mnt, &mnt_flags)) {
-		mntput(mnt);
-		return -EPERM;
+		errorf("VFS: Mount too revealing");
+		goto err_mnt;
 	}
 
-	err = do_add_mount(real_mount(mnt), path, mnt_flags);
+	ret = do_add_mount(real_mount(mnt), mountpoint, mnt_flags);
+	if (ret < 0) {
+		errorf("VFS: Failed to add mount");
+		goto err_mnt;
+	}
+	return ret;
+
+err_mnt:
+	mntput(mnt);
+	return ret;
+}
+
+/*
+ * create a new mount for userspace and request it to be added into the
+ * namespace's tree
+ */
+static int do_new_mount(struct path *mountpoint, const char *fstype,
+			int ms_flags, int mnt_flags, const char *name,
+			void *data)
+{
+	struct file_system_type *fs_type;
+	struct fs_context *fc;
+	int err = -EINVAL;
+
+	if (!fstype)
+		goto err;
+
+	err = -ENODEV;
+	fs_type = get_fs_type(fstype);
+	if (!fs_type)
+		goto err;
+
+	fc = vfs_new_fs_context(fs_type, NULL, ms_flags, FS_CONTEXT_FOR_NEW);
+	put_filesystem(fs_type);
+	if (IS_ERR(fc)) {
+		err = PTR_ERR(fc);
+		goto err;
+	}
+
+	err = -ENOMEM;
+	fc->device = kstrdup(name, GFP_KERNEL);
+	if (!fc->device)
+		goto err_fc;
+
+	err = parse_monolithic_mount_data(fc, data);
+	if (err < 0)
+		goto err_fc;
+
+	err = vfs_get_tree(fc);
+	if (err < 0)
+		goto err_fc;
+
+	err = do_new_mount_fc(fc, mountpoint, mnt_flags);
 	if (err)
-		mntput(mnt);
+		goto err_fc;
+
+	put_fs_context(fc);
+	return 0;
+
+err_fc:
+	put_fs_context(fc);
+err:
 	return err;
 }
 
@@ -3058,6 +3074,172 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
 	return ret;
 }
 
+/**
+ * vfs_get_tree - Get the mountable root
+ * @sc: The superblock configuration context.
+ *
+ * The filesystem is invoked to get or create a superblock which can then later
+ * be used for mounting.  The filesystem places a pointer to the root to be
+ * used for mounting in @fc->root.
+ */
+int vfs_get_tree(struct fs_context *fc)
+{
+	struct super_block *sb;
+	int ret;
+
+	if (fc->root)
+		return -EBUSY;
+
+	if (fc->ops->validate) {
+		ret = fc->ops->validate(fc);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* The filesystem may transfer preallocated resources from the
+	 * configuration context to the superblock, thereby rendering the
+	 * config unusable for another attempt at creation if this one fails.
+	 */
+	if (fc->degraded)
+		return invalf("VFS: The config is degraded");
+
+	/* Get the mountable root in fc->root, with a ref on the root and a ref
+	 * on the superblock.
+	 */
+	ret = fc->ops->get_tree(fc);
+	if (ret < 0)
+		return ret;
+
+	BUG_ON(!fc->root);
+	sb = fc->root->d_sb;
+	WARN_ON(!sb->s_bdi);
+
+	ret = security_sb_get_tree(fc);
+	if (ret < 0)
+		goto err_sb;
+
+	ret = -ENOMEM;
+	if (fc->subtype && !sb->s_subtype) {
+		sb->s_subtype = kstrdup(fc->subtype, GFP_KERNEL);
+		if (!sb->s_subtype)
+			goto err_sb;
+	}
+
+	sb->s_flags |= MS_BORN;
+
+	/* Filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
+	 * but s_maxbytes was an unsigned long long for many releases.  Throw
+	 * this warning for a little while to try and catch filesystems that
+	 * violate this rule.
+	 */
+	WARN(sb->s_maxbytes < 0,
+	     "%s set sb->s_maxbytes to negative value (%lld)\n",
+	     fc->fs_type->name, sb->s_maxbytes);
+
+	up_write(&sb->s_umount);
+	return 0;
+
+err_sb:
+	dput(fc->root);
+	fc->root = NULL;
+	deactivate_locked_super(sb);
+	return ret;
+}
+EXPORT_SYMBOL(vfs_get_tree);
+
+/**
+ * vfs_kern_mount_fc - Create a mount for a configured superblock
+ * sc: The configuration context with the superblock attached
+ *
+ * Create a mount to an already configured superblock.  If necessary, the
+ * caller should invoke vfs_create_super() before calling this.
+ */
+struct vfsmount *vfs_kern_mount_fc(struct fs_context *fc)
+{
+	struct mount *mnt;
+
+	if (!fc->root)
+		return ERR_PTR(invalf("VFS: Root must be obtained before mount"));
+
+	mnt = alloc_vfsmnt(fc->device ?: "none");
+	if (!mnt)
+		return ERR_PTR(-ENOMEM);
+
+	if (fc->sb_flags & SB_KERNMOUNT)
+		mnt->mnt.mnt_flags = MNT_INTERNAL;
+
+	atomic_inc(&fc->root->d_sb->s_active);
+	mnt->mnt.mnt_sb		= fc->root->d_sb;
+	mnt->mnt.mnt_root	= dget(fc->root);
+	mnt->mnt_mountpoint	= mnt->mnt.mnt_root;
+	mnt->mnt_parent		= mnt;
+
+	lock_mount_hash();
+	list_add_tail(&mnt->mnt_instance, &mnt->mnt.mnt_sb->s_mounts);
+	unlock_mount_hash();
+	return &mnt->mnt;
+}
+EXPORT_SYMBOL_GPL(vfs_kern_mount_fc);
+
+struct vfsmount *vfs_kern_mount(struct file_system_type *type,
+				int flags, const char *name, void *data)
+{
+	struct fs_context *fc;
+	struct vfsmount *mnt;
+	int ret;
+
+	if (!type)
+		return ERR_PTR(-EINVAL);
+
+	fc = vfs_new_fs_context(type, NULL, flags, FS_CONTEXT_FOR_NEW);
+	if (IS_ERR(fc))
+		return ERR_CAST(fc);
+
+	if (name) {
+		ret = -ENOMEM;
+		fc->device = kstrdup(name, GFP_KERNEL);
+		if (!fc->device)
+			goto err_fc;
+	}
+
+	ret = parse_monolithic_mount_data(fc, data);
+	if (ret < 0)
+		goto err_fc;
+
+	ret = vfs_get_tree(fc);
+	if (ret < 0)
+		goto err_fc;
+
+	mnt = vfs_kern_mount_fc(fc);
+	if (IS_ERR(mnt)) {
+		ret = PTR_ERR(mnt);
+		goto err_fc;
+	}
+
+	put_fs_context(fc);
+	return mnt;
+
+err_fc:
+	put_fs_context(fc);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(vfs_kern_mount);
+
+struct vfsmount *
+vfs_submount(const struct dentry *mountpoint, struct file_system_type *type,
+	     const char *name, void *data)
+{
+	/* Until it is worked out how to pass the user namespace
+	 * through from the parent mount to the submount don't support
+	 * unprivileged mounts with submounts.
+	 */
+	if (mountpoint->d_sb->s_user_ns != &init_user_ns)
+		return ERR_PTR(-EPERM);
+
+	return vfs_kern_mount(type, MS_SUBMOUNT, name, data);
+}
+EXPORT_SYMBOL_GPL(vfs_submount);
+
 /*
  * Return true if path is reachable from root
  *
@@ -3299,6 +3481,23 @@ struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
 }
 EXPORT_SYMBOL_GPL(kern_mount_data);
 
+struct vfsmount *kern_mount_data_fc(struct fs_context *fc)
+{
+	struct vfsmount *mnt;
+
+	fc->sb_flags = SB_KERNMOUNT;
+	mnt = vfs_kern_mount_fc(fc);
+	if (!IS_ERR(mnt)) {
+		/*
+		 * it is a longterm mount, don't release mnt until
+		 * we unmount before file sys is unregistered
+		*/
+		real_mount(mnt)->mnt_ns = MNT_NS_INTERNAL;
+	}
+	return mnt;
+}
+EXPORT_SYMBOL_GPL(kern_mount_data_fc);
+
 void kern_unmount(struct vfsmount *mnt)
 {
 	/* release long term mount so mount point can be released */
diff --git a/fs/super.c b/fs/super.c
index e55911d31821..8ef5222d6932 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -34,6 +34,7 @@
 #include <linux/fsnotify.h>
 #include <linux/lockdep.h>
 #include <linux/user_namespace.h>
+#include <linux/fs_context.h>
 #include "internal.h"
 
 
@@ -173,16 +174,13 @@ static void destroy_super(struct super_block *s)
 }
 
 /**
- *	alloc_super	-	create new superblock
- *	@type:	filesystem type superblock should belong to
- *	@flags: the mount flags
- *	@user_ns: User namespace for the super_block
+ *	alloc_super - Create new superblock
+ *	@sc: The filesystem configuration context
  *
  *	Allocates and initializes a new &struct super_block.  alloc_super()
  *	returns a pointer new superblock or %NULL if allocation had failed.
  */
-static struct super_block *alloc_super(struct file_system_type *type, int flags,
-				       struct user_namespace *user_ns)
+static struct super_block *alloc_super(struct fs_context *fc)
 {
 	struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);
 	static const struct super_operations default_op;
@@ -192,7 +190,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
 		return NULL;
 
 	INIT_LIST_HEAD(&s->s_mounts);
-	s->s_user_ns = get_user_ns(user_ns);
+	s->s_user_ns = get_user_ns(fc->user_ns);
 
 	if (security_sb_alloc(s))
 		goto fail;
@@ -200,12 +198,12 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
 	for (i = 0; i < SB_FREEZE_LEVELS; i++) {
 		if (__percpu_init_rwsem(&s->s_writers.rw_sem[i],
 					sb_writers_name[i],
-					&type->s_writers_key[i]))
+					&fc->fs_type->s_writers_key[i]))
 			goto fail;
 	}
 	init_waitqueue_head(&s->s_writers.wait_unfrozen);
 	s->s_bdi = &noop_backing_dev_info;
-	s->s_flags = flags;
+	s->s_flags = fc->sb_flags;
 	if (s->s_user_ns != &init_user_ns)
 		s->s_iflags |= SB_I_NODEV;
 	INIT_HLIST_NODE(&s->s_instances);
@@ -222,7 +220,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
 		goto fail;
 
 	init_rwsem(&s->s_umount);
-	lockdep_set_class(&s->s_umount, &type->s_umount_key);
+	lockdep_set_class(&s->s_umount, &fc->fs_type->s_umount_key);
 	/*
 	 * sget() can have s_umount recursion.
 	 *
@@ -242,7 +240,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
 	s->s_count = 1;
 	atomic_set(&s->s_active, 1);
 	mutex_init(&s->s_vfs_rename_mutex);
-	lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key);
+	lockdep_set_class(&s->s_vfs_rename_mutex, &fc->fs_type->s_vfs_rename_key);
 	mutex_init(&s->s_dquot.dqio_mutex);
 	s->s_maxbytes = MAX_NON_LFS;
 	s->s_op = &default_op;
@@ -455,6 +453,79 @@ void generic_shutdown_super(struct super_block *sb)
 EXPORT_SYMBOL(generic_shutdown_super);
 
 /**
+ *	sget_fc - Find or create a superblock
+ *	@fc:	Configuration context.
+ *	@test:	comparison callback
+ *	@set:	setup callback
+ */
+struct super_block *sget_fc(struct fs_context *fc,
+			    int (*test)(struct super_block *, struct fs_context *),
+			    int (*set)(struct super_block *, struct fs_context *))
+{
+	struct super_block *s = NULL;
+	struct super_block *old;
+	int err;
+
+	if (!(fc->sb_flags & MS_KERNMOUNT) &&
+	    fc->purpose != FS_CONTEXT_FOR_SUBMOUNT) {
+		if (!(fc->fs_type->fs_flags & FS_USERNS_MOUNT) &&
+		    !capable(CAP_SYS_ADMIN))
+			return ERR_PTR(-EPERM);
+		else if (!ns_capable(fc->user_ns, CAP_SYS_ADMIN))
+			return ERR_PTR(-EPERM);
+	}
+
+retry:
+	spin_lock(&sb_lock);
+	if (test) {
+		hlist_for_each_entry(old, &fc->fs_type->fs_supers, s_instances) {
+			if (!test(old, fc))
+				continue;
+			if (fc->user_ns != old->s_user_ns) {
+				spin_unlock(&sb_lock);
+				if (s) {
+					up_write(&s->s_umount);
+					destroy_super(s);
+				}
+				return ERR_PTR(-EBUSY);
+			}
+			if (!grab_super(old))
+				goto retry;
+			if (s) {
+				up_write(&s->s_umount);
+				destroy_super(s);
+				s = NULL;
+			}
+			return old;
+		}
+	}
+	if (!s) {
+		spin_unlock(&sb_lock);
+		s = alloc_super(fc);
+		if (!s)
+			return ERR_PTR(-ENOMEM);
+		goto retry;
+	}
+
+	err = set(s, fc);
+	if (err) {
+		spin_unlock(&sb_lock);
+		up_write(&s->s_umount);
+		destroy_super(s);
+		return ERR_PTR(err);
+	}
+	s->s_type = fc->fs_type;
+	strlcpy(s->s_id, s->s_type->name, sizeof(s->s_id));
+	list_add_tail(&s->s_list, &super_blocks);
+	hlist_add_head(&s->s_instances, &s->s_type->fs_supers);
+	spin_unlock(&sb_lock);
+	get_filesystem(s->s_type);
+	register_shrinker(&s->s_shrink);
+	return s;
+}
+EXPORT_SYMBOL(sget_fc);
+
+/**
  *	sget_userns -	find or create a superblock
  *	@type:	filesystem type superblock should belong to
  *	@test:	comparison callback
@@ -503,7 +574,14 @@ struct super_block *sget_userns(struct file_system_type *type,
 	}
 	if (!s) {
 		spin_unlock(&sb_lock);
-		s = alloc_super(type, (flags & ~SB_SUBMOUNT), user_ns);
+		{
+			struct fs_context fc = {
+				.fs_type	= type,
+				.sb_flags	= flags & ~SB_SUBMOUNT,
+				.user_ns	= user_ns,
+			};
+			s = alloc_super(&fc);
+		}
 		if (!s)
 			return ERR_PTR(-ENOMEM);
 		goto retry;
@@ -805,10 +883,13 @@ struct super_block *user_get_super(dev_t dev)
  *	@flags:	MS_* flags translated into SB_* flags
  *	@data:	the rest of options
  *      @force: whether or not to force the change
+ *	@fc:	the superblock config for filesystems that support it
+ *		(NULL if called from emergency or umount)
  *
  *	Alters the mount options of a mounted file system.
  */
-int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
+int do_remount_sb(struct super_block *sb, int flags, void *data, int force,
+		  struct fs_context *fc)
 {
 	int retval;
 	int remount_ro;
@@ -850,8 +931,14 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 		}
 	}
 
-	if (sb->s_op->remount_fs) {
-		retval = sb->s_op->remount_fs(sb, &flags, data);
+	if (sb->s_op->remount_fs_fc ||
+	    sb->s_op->remount_fs) {
+		if (sb->s_op->remount_fs_fc) {
+		    retval = sb->s_op->remount_fs_fc(sb, fc);
+		    flags = fc->sb_flags;
+		} else {
+			retval = sb->s_op->remount_fs(sb, &flags, data);
+		}
 		if (retval) {
 			if (!force)
 				goto cancel_readonly;
@@ -898,7 +985,7 @@ static void do_emergency_remount(struct work_struct *work)
 			/*
 			 * What lock protects sb->s_flags??
 			 */
-			do_remount_sb(sb, SB_RDONLY, NULL, 1);
+			do_remount_sb(sb, SB_RDONLY, NULL, 1, NULL);
 		}
 		up_write(&sb->s_umount);
 		spin_lock(&sb_lock);
@@ -1048,6 +1135,43 @@ struct dentry *mount_ns(struct file_system_type *fs_type,
 
 EXPORT_SYMBOL(mount_ns);
 
+int mount_ns_fc(struct fs_context *fc,
+		int (*fill_super)(struct super_block *sb, struct fs_context *fc),
+		void *ns)
+{
+	struct super_block *sb;
+
+	/* Don't allow mounting unless the caller has CAP_SYS_ADMIN
+	 * over the namespace.
+	 */
+	if (!(fc->sb_flags & SB_KERNMOUNT) &&
+	    !ns_capable(fc->user_ns, CAP_SYS_ADMIN))
+		return -EPERM;
+
+	sb = sget_userns(fc->fs_type, ns_test_super, ns_set_super,
+			 fc->sb_flags, fc->user_ns, ns);
+	if (IS_ERR(sb))
+		return PTR_ERR(sb);
+
+	if (!sb->s_root) {
+		int err;
+		err = fill_super(sb, fc);
+		if (err) {
+			deactivate_locked_super(sb);
+			return err;
+		}
+
+		sb->s_flags |= SB_ACTIVE;
+	}
+
+	if (!fc->root) {
+		fc->root = sb->s_root;
+		dget(sb->s_root);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(mount_ns_fc);
+
 #ifdef CONFIG_BLOCK
 static int set_bdev_super(struct super_block *s, void *data)
 {
@@ -1196,7 +1320,7 @@ struct dentry *mount_single(struct file_system_type *fs_type,
 		}
 		s->s_flags |= SB_ACTIVE;
 	} else {
-		do_remount_sb(s, flags, data, 0);
+		do_remount_sb(s, flags, data, 0, NULL);
 	}
 	return dget(s->s_root);
 }
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3138da4491da..9fd6555122da 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -54,6 +54,7 @@ struct workqueue_struct;
 struct iov_iter;
 struct fscrypt_info;
 struct fscrypt_operations;
+struct fs_context;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
@@ -701,6 +702,11 @@ static inline void inode_unlock(struct inode *inode)
 	up_write(&inode->i_rwsem);
 }
 
+static inline int inode_lock_killable(struct inode *inode)
+{
+	return down_write_killable(&inode->i_rwsem);
+}
+
 static inline void inode_lock_shared(struct inode *inode)
 {
 	down_read(&inode->i_rwsem);
@@ -1814,6 +1820,7 @@ struct super_operations {
 	int (*unfreeze_fs) (struct super_block *);
 	int (*statfs) (struct dentry *, struct kstatfs *);
 	int (*remount_fs) (struct super_block *, int *, char *);
+	int (*remount_fs_fc) (struct super_block *, struct fs_context *);
 	void (*umount_begin) (struct super_block *);
 
 	int (*show_options)(struct seq_file *, struct dentry *);
@@ -2048,8 +2055,10 @@ struct file_system_type {
 #define FS_HAS_SUBTYPE		4
 #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
+	unsigned short fs_context_size;	/* Size of superblock config context to allocate */
 	struct dentry *(*mount) (struct file_system_type *, int,
 		       const char *, void *);
+	int (*init_fs_context)(struct fs_context *, struct super_block *);
 	void (*kill_sb) (struct super_block *);
 	struct module *owner;
 	struct file_system_type * next;
@@ -2067,6 +2076,10 @@ struct file_system_type {
 
 #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME)
 
+extern int mount_ns_fc(struct fs_context *fc,
+		       int (*fill_super)(struct super_block *sb,
+					 struct fs_context *fc),
+		       void *ns);
 extern struct dentry *mount_ns(struct file_system_type *fs_type,
 	int flags, void *data, void *ns, struct user_namespace *user_ns,
 	int (*fill_super)(struct super_block *, void *, int));
@@ -2089,6 +2102,9 @@ void deactivate_locked_super(struct super_block *sb);
 int set_anon_super(struct super_block *s, void *data);
 int get_anon_bdev(dev_t *);
 void free_anon_bdev(dev_t);
+struct super_block *sget_fc(struct fs_context *fc,
+			    int (*test)(struct super_block *, struct fs_context *),
+			    int (*set)(struct super_block *, struct fs_context *));
 struct super_block *sget_userns(struct file_system_type *type,
 			int (*test)(struct super_block *,void *),
 			int (*set)(struct super_block *,void *),
@@ -2133,6 +2149,7 @@ extern int register_filesystem(struct file_system_type *);
 extern int unregister_filesystem(struct file_system_type *);
 extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data);
 #define kern_mount(type) kern_mount_data(type, NULL)
+extern struct vfsmount *kern_mount_data_fc(struct fs_context *);
 extern void kern_unmount(struct vfsmount *mnt);
 extern int may_umount_tree(struct vfsmount *);
 extern int may_umount(struct vfsmount *);
diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h
index 429c40be2c9e..d29fb7b287fd 100644
--- a/include/linux/fs_context.h
+++ b/include/linux/fs_context.h
@@ -69,4 +69,16 @@ struct fs_context_operations {
 	int (*get_tree)(struct fs_context *fc);
 };
 
+extern struct fs_context *vfs_new_fs_context(struct file_system_type *fs_type,
+					     struct super_block *src_sb,
+					     unsigned int ms_flags,
+					     enum fs_context_purpose purpose);
+extern struct fs_context *vfs_sb_reconfig(struct vfsmount *mnt,
+					  unsigned int ms_flags);
+extern struct fs_context *vfs_dup_fs_context(struct fs_context *src);
+extern int vfs_parse_mount_option(struct fs_context *fc, char *data);
+extern int generic_monolithic_mount_data(struct fs_context *fc, void *data);
+extern int vfs_get_tree(struct fs_context *fc);
+extern void put_fs_context(struct fs_context *fc);
+
 #endif /* _LINUX_FS_CONTEXT_H */
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 8e0352af06b7..c990906ccced 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -20,6 +20,7 @@ struct super_block;
 struct vfsmount;
 struct dentry;
 struct mnt_namespace;
+struct fs_context;
 
 #define MNT_NOSUID	0x01
 #define MNT_NODEV	0x02
@@ -90,6 +91,7 @@ struct file_system_type;
 extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
 				      int flags, const char *name,
 				      void *data);
+extern struct vfsmount *vfs_kern_mount_fc(struct fs_context *fc);
 extern struct vfsmount *vfs_submount(const struct dentry *mountpoint,
 				     struct file_system_type *type,
 				     const char *name, void *data);

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 11/27] VFS: Remove unused code after filesystem context changes [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (9 preceding siblings ...)
  2017-06-14 15:16 ` [PATCH 10/27] VFS: Implement a filesystem superblock creation/configuration " David Howells
@ 2017-06-14 15:17 ` David Howells
  2017-06-14 15:17 ` [PATCH 12/27] VFS: Implement fsopen() to prepare for a mount " David Howells
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:17 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Remove code that is now unused after the filesystem context changes.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/internal.h             |    2 --
 fs/super.c                |   53 ---------------------------------------------
 include/linux/lsm_hooks.h |    2 --
 include/linux/security.h  |    6 -----
 security/security.c       |    5 ----
 security/selinux/hooks.c  |   22 +------------------
 6 files changed, 1 insertion(+), 89 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index 08d7816f8686..da679deec12f 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -89,8 +89,6 @@ extern struct file *get_empty_filp(void);
  */
 extern int do_remount_sb(struct super_block *, int, void *, int, struct fs_context *);
 extern bool trylock_super(struct super_block *sb);
-extern struct dentry *mount_fs(struct file_system_type *,
-			       int, const char *, void *);
 extern struct super_block *user_get_super(dev_t);
 
 /*
diff --git a/fs/super.c b/fs/super.c
index 8ef5222d6932..3a83e783a5d2 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1326,59 +1326,6 @@ struct dentry *mount_single(struct file_system_type *fs_type,
 }
 EXPORT_SYMBOL(mount_single);
 
-struct dentry *
-mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
-{
-	struct dentry *root;
-	struct super_block *sb;
-	char *secdata = NULL;
-	int error = -ENOMEM;
-
-	if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
-		secdata = alloc_secdata();
-		if (!secdata)
-			goto out;
-
-		error = security_sb_copy_data(data, secdata);
-		if (error)
-			goto out_free_secdata;
-	}
-
-	root = type->mount(type, flags, name, data);
-	if (IS_ERR(root)) {
-		error = PTR_ERR(root);
-		goto out_free_secdata;
-	}
-	sb = root->d_sb;
-	BUG_ON(!sb);
-	WARN_ON(!sb->s_bdi);
-	sb->s_flags |= SB_BORN;
-
-	error = security_sb_kern_mount(sb, flags, secdata);
-	if (error)
-		goto out_sb;
-
-	/*
-	 * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
-	 * but s_maxbytes was an unsigned long long for many releases. Throw
-	 * this warning for a little while to try and catch filesystems that
-	 * violate this rule.
-	 */
-	WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
-		"negative value (%lld)\n", type->name, sb->s_maxbytes);
-
-	up_write(&sb->s_umount);
-	free_secdata(secdata);
-	return root;
-out_sb:
-	dput(root);
-	deactivate_locked_super(sb);
-out_free_secdata:
-	free_secdata(secdata);
-out:
-	return ERR_PTR(error);
-}
-
 /*
  * Setup private BDI for given superblock. It gets automatically cleaned up
  * in generic_shutdown_super().
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 62500658cc9f..9bddbb28a2fc 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1415,7 +1415,6 @@ union security_list_options {
 	void (*sb_free_security)(struct super_block *sb);
 	int (*sb_copy_data)(char *orig, char *copy);
 	int (*sb_remount)(struct super_block *sb, void *data);
-	int (*sb_kern_mount)(struct super_block *sb, int flags, void *data);
 	int (*sb_show_options)(struct seq_file *m, struct super_block *sb);
 	int (*sb_statfs)(struct dentry *dentry);
 	int (*sb_mount)(const char *dev_name, const struct path *path,
@@ -1732,7 +1731,6 @@ struct security_hook_heads {
 	struct list_head sb_free_security;
 	struct list_head sb_copy_data;
 	struct list_head sb_remount;
-	struct list_head sb_kern_mount;
 	struct list_head sb_show_options;
 	struct list_head sb_statfs;
 	struct list_head sb_mount;
diff --git a/include/linux/security.h b/include/linux/security.h
index e7c774fdffd9..26b4de453ead 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -235,7 +235,6 @@ int security_sb_alloc(struct super_block *sb);
 void security_sb_free(struct super_block *sb);
 int security_sb_copy_data(char *orig, char *copy);
 int security_sb_remount(struct super_block *sb, void *data);
-int security_sb_kern_mount(struct super_block *sb, int flags, void *data);
 int security_sb_show_options(struct seq_file *m, struct super_block *sb);
 int security_sb_statfs(struct dentry *dentry);
 int security_sb_mount(const char *dev_name, const struct path *path,
@@ -571,11 +570,6 @@ static inline int security_sb_remount(struct super_block *sb, void *data)
 	return 0;
 }
 
-static inline int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
-{
-	return 0;
-}
-
 static inline int security_sb_show_options(struct seq_file *m,
 					   struct super_block *sb)
 {
diff --git a/security/security.c b/security/security.c
index 27b195966cad..c2aa121a8ca4 100644
--- a/security/security.c
+++ b/security/security.c
@@ -367,11 +367,6 @@ int security_sb_remount(struct super_block *sb, void *data)
 	return call_int_hook(sb_remount, 0, sb, data);
 }
 
-int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
-{
-	return call_int_hook(sb_kern_mount, 0, sb, flags, data);
-}
-
 int security_sb_show_options(struct seq_file *m, struct super_block *sb)
 {
 	return call_int_hook(sb_show_options, 0, m, sb);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c93a21119fe3..f146087a608d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2775,25 +2775,6 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
 	goto out_free_opts;
 }
 
-static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
-{
-	const struct cred *cred = current_cred();
-	struct common_audit_data ad;
-	int rc;
-
-	rc = superblock_doinit(sb, data);
-	if (rc)
-		return rc;
-
-	/* Allow all mounts performed by the kernel */
-	if (flags & SB_KERNMOUNT)
-		return 0;
-
-	ad.type = LSM_AUDIT_DATA_DENTRY;
-	ad.u.dentry = sb->s_root;
-	return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
-}
-
 static int selinux_sb_statfs(struct dentry *dentry)
 {
 	const struct cred *cred = current_cred();
@@ -2978,7 +2959,7 @@ static int selinux_sb_get_tree(struct fs_context *fc)
 		return rc;
 
 	/* Allow all mounts performed by the kernel */
-	if (fc->sb_flags & MS_KERNMOUNT)
+	if (fc->sb_flags & SB_KERNMOUNT)
 		return 0;
 
 	ad.type = LSM_AUDIT_DATA_DENTRY;
@@ -6339,7 +6320,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
 	LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
 	LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
-	LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
 	LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
 	LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs),
 	LSM_HOOK_INIT(sb_mount, selinux_mount),

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 12/27] VFS: Implement fsopen() to prepare for a mount [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (10 preceding siblings ...)
  2017-06-14 15:17 ` [PATCH 11/27] VFS: Remove unused code after filesystem context changes " David Howells
@ 2017-06-14 15:17 ` David Howells
  2017-06-14 15:17 ` [PATCH 13/27] VFS: Implement fsmount() to effect a pre-configured " David Howells
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:17 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Provide an fsopen() system call that starts the process of preparing to
mount, using an fd as a context handle.  fsopen() is given the name of the
filesystem that will be used:

	int mfd = fsopen(const char *fsname, int reserved,
			 int open_flags);

where reserved should be -1 for the moment (it will be used to pass the
namespace information in future) and open_flags can be 0 or O_CLOEXEC.

For example:

	mfd = fsopen("ext4", -1, O_CLOEXEC);
	write(mfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
	write(mfd, "o noatime");
	write(mfd, "o acl");
	write(mfd, "o user_attr");
	write(mfd, "o iversion");
	write(mfd, "o ");
	write(mfd, "r /my/container"); // root inside the fs
	write(mfd, "x create"); // create the superblock
	fsmount(mfd, container_fd, "/mnt", AT_NO_FOLLOW);

	mfd = fsopen("afs", -1);
	write(mfd, "s %grand.central.org:root.cell");
	write(mfd, "o cell=grand.central.org");
	write(mfd, "r /");
	write(mfd, "x create");
	fsmount(mfd, AT_FDCWD, "/mnt", 0);

If an error is reported at any step, an error message may be available to be
read() back (ENODATA will be reported if there isn't an error available) in
the form:

	"e <subsys>:<problem>"
	"e SELinux:Mount on mountpoint not permitted"

Once fsmount() has been called, further write() calls will incur EBUSY,
even if the fsmount() fails.  read() is still possible to retrieve error
information.

The fsopen() syscall creates a mount context and hangs it of the fd that it
returns.

Netlink is not used because it is optional.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 arch/x86/entry/syscalls/syscall_32.tbl |    1 
 arch/x86/entry/syscalls/syscall_64.tbl |    1 
 fs/Makefile                            |    2 
 fs/fsopen.c                            |  273 ++++++++++++++++++++++++++++++++
 include/linux/fs_context.h             |    2 
 include/linux/syscalls.h               |    1 
 include/uapi/linux/magic.h             |    1 
 kernel/sys_ni.c                        |    3 
 8 files changed, 283 insertions(+), 1 deletion(-)
 create mode 100644 fs/fsopen.c

diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 448ac2161112..9bf8d4c62f85 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -391,3 +391,4 @@
 382	i386	pkey_free		sys_pkey_free
 383	i386	statx			sys_statx
 384	i386	arch_prctl		sys_arch_prctl			compat_sys_arch_prctl
+385	i386	fsopen			sys_fsopen
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 5aef183e2f85..9b198c5fc412 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -339,6 +339,7 @@
 330	common	pkey_alloc		sys_pkey_alloc
 331	common	pkey_free		sys_pkey_free
 332	common	statx			sys_statx
+333	common	fsopen			sys_fsopen
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/fs/Makefile b/fs/Makefile
index ffe728cc15e1..c42d1d9351a6 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -12,7 +12,7 @@ obj-y :=	open.o read_write.o file_table.o super.o \
 		seq_file.o xattr.o libfs.o fs-writeback.o \
 		pnode.o splice.o sync.o utimes.o \
 		stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
-		fs_context.o
+		fs_context.o fsopen.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=	buffer.o block_dev.o direct-io.o mpage.o
diff --git a/fs/fsopen.c b/fs/fsopen.c
new file mode 100644
index 000000000000..5278eb402072
--- /dev/null
+++ b/fs/fsopen.c
@@ -0,0 +1,273 @@
+/* Filesystem access-by-fd.
+ *
+ * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/fs_context.h>
+#include <linux/mount.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/file.h>
+#include <linux/magic.h>
+#include <linux/syscalls.h>
+
+static struct vfsmount *fs_fs_mnt __read_mostly;
+
+static int fs_fs_release(struct inode *inode, struct file *file)
+{
+	struct fs_context *fc = file->private_data;
+
+	file->private_data = NULL;
+
+	put_fs_context(fc);
+	return 0;
+}
+
+/*
+ * Userspace writes configuration data and commands to the fd and we parse it
+ * here.  For the moment, we assume a single option or command per write.  Each
+ * line written is of the form
+ *
+ *	<option_type><space><stuff...>
+ *
+ *	d /dev/sda1				-- Device name
+ *	o noatime				-- Option without value
+ *	o cell=grand.central.org		-- Option with value
+ *	r /					-- Dir within device to mount
+ *	x create				-- Create a superblock
+ */
+static ssize_t fs_fs_write(struct file *file,
+			   const char __user *_buf, size_t len, loff_t *pos)
+{
+	struct fs_context *fc = file->private_data;
+	struct inode *inode = file_inode(file);
+	char opt[2], *data;
+	ssize_t ret;
+
+	if (len < 3 || len > 4095)
+		return -EINVAL;
+
+	if (copy_from_user(opt, _buf, 2) != 0)
+		return -EFAULT;
+	switch (opt[0]) {
+	case 's':
+	case 'o':
+	case 'x':
+		break;
+	default:
+		goto err_bad_cmd;
+	}
+	if (opt[1] != ' ')
+		goto err_bad_cmd;
+
+	data = memdup_user_nul(_buf + 2, len - 2);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	/* From this point onwards we need to lock the fd against someone
+	 * trying to mount it.
+	 */
+	ret = inode_lock_killable(inode);
+	if (ret < 0)
+		goto err_free;
+
+	ret = -EINVAL;
+	switch (opt[0]) {
+	case 's':
+		if (fc->device)
+			goto err_unlock;
+		fc->device = data;
+		data = NULL;
+		break;
+
+	case 'o':
+		ret = vfs_parse_mount_option(fc, data);
+		if (ret < 0)
+			goto err_unlock;
+		break;
+
+	case 'x':
+		if (strcmp(data, "create") == 0) {
+			ret = vfs_get_tree(fc);
+		} else {
+			ret = invalf("VFS: Invalid command");
+		}
+		if (ret < 0)
+			goto err_unlock;
+		break;
+
+	default:
+		goto err_unlock;
+	}
+
+	ret = len;
+err_unlock:
+	inode_unlock(inode);
+err_free:
+	kfree(data);
+	return ret;
+err_bad_cmd:
+	return invalf("VFS: Unsupported write spec");
+}
+
+const struct file_operations fs_fs_fops = {
+	.write		= fs_fs_write,
+	.release	= fs_fs_release,
+	.llseek		= no_llseek,
+};
+
+/*
+ * Indicate the name we want to display the filesystem file as.
+ */
+static char *fs_fs_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+	return dynamic_dname(dentry, buffer, buflen, "fs:[%lu]",
+			     d_inode(dentry)->i_ino);
+}
+
+static const struct dentry_operations fs_fs_dentry_operations = {
+	.d_dname	= fs_fs_dname,
+};
+
+/*
+ * Create a file that can be used to configure a new mount.
+ */
+static struct file *create_fs_file(struct fs_context *fc)
+{
+	struct inode *inode;
+	struct file *f;
+	struct path path;
+	int ret;
+
+	inode = alloc_anon_inode(fs_fs_mnt->mnt_sb);
+	if (!inode)
+		return ERR_PTR(-ENFILE);
+	inode->i_fop = &fs_fs_fops;
+
+	ret = -ENOMEM;
+	path.dentry = d_alloc_pseudo(fs_fs_mnt->mnt_sb, &empty_name);
+	if (!path.dentry)
+		goto err_inode;
+	path.mnt = mntget(fs_fs_mnt);
+
+	d_instantiate(path.dentry, inode);
+
+	f = alloc_file(&path, FMODE_READ | FMODE_WRITE, &fs_fs_fops);
+	if (IS_ERR(f)) {
+		ret = PTR_ERR(f);
+		goto err_file;
+	}
+
+	f->private_data = fc;
+	return f;
+
+err_file:
+	path_put(&path);
+	return ERR_PTR(ret);
+
+err_inode:
+	iput(inode);
+	return ERR_PTR(ret);
+}
+
+ const struct super_operations fs_fs_ops = {
+	.drop_inode	= generic_delete_inode,
+	.destroy_inode	= free_inode_nonrcu,
+	.statfs		= simple_statfs,
+};
+
+static struct dentry *fs_fs_mount(struct file_system_type *fs_type,
+				  int flags, const char *dev_name,
+				  void *data)
+{
+	return mount_pseudo(fs_type, "fs_fs:", &fs_fs_ops,
+			    &fs_fs_dentry_operations, FS_FS_MAGIC);
+}
+
+static struct file_system_type fs_fs_type = {
+	.name		= "fs_fs",
+	.mount		= fs_fs_mount,
+	.kill_sb	= kill_anon_super,
+};
+
+static int __init init_fs_fs(void)
+{
+	int ret;
+
+	ret = register_filesystem(&fs_fs_type);
+	if (ret < 0)
+		panic("Cannot register fs_fs\n");
+
+	fs_fs_mnt = kern_mount(&fs_fs_type);
+	if (IS_ERR(fs_fs_mnt))
+		panic("Cannot mount fs_fs: %ld\n", PTR_ERR(fs_fs_mnt));
+	return 0;
+}
+
+fs_initcall(init_fs_fs);
+
+/*
+ * Open a filesystem by name so that it can be configured for mounting.
+ *
+ * We are allowed to specify a container in which the filesystem will be
+ * opened, thereby indicating which namespaces will be used (notably, which
+ * network namespace will be used for network filesystems).
+ */
+SYSCALL_DEFINE3(fsopen, const char __user *, _fs_name, int, reserved,
+		unsigned int, flags)
+{
+	struct file_system_type *fs_type;
+	struct fs_context *fc;
+	struct file *file;
+	const char *fs_name;
+	int fd, ret;
+
+	if (flags & ~O_CLOEXEC || reserved != -1)
+		return -EINVAL;
+
+	fs_name = strndup_user(_fs_name, PAGE_SIZE);
+	if (IS_ERR(fs_name))
+		return PTR_ERR(fs_name);
+
+	fs_type = get_fs_type(fs_name);
+	kfree(fs_name);
+	if (!fs_type)
+		return -ENODEV;
+
+	fc = vfs_new_fs_context(fs_type, NULL, 0, FS_CONTEXT_FOR_NEW);
+	put_filesystem(fs_type);
+	if (IS_ERR(fc))
+		return PTR_ERR(fc);
+
+	ret = -ENOTSUPP;
+	if (!fc->ops)
+		goto err_fc;
+
+	file = create_fs_file(fc);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto err_fc;
+	}
+
+	ret = get_unused_fd_flags(flags & O_CLOEXEC);
+	if (ret < 0)
+		goto err_file;
+
+	fd = ret;
+	fd_install(fd, file);
+	return fd;
+
+err_file:
+	fput(file);
+	return ret;
+
+err_fc:
+	put_fs_context(fc);
+	return ret;
+}
diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h
index d29fb7b287fd..7f542a00a334 100644
--- a/include/linux/fs_context.h
+++ b/include/linux/fs_context.h
@@ -81,4 +81,6 @@ extern int generic_monolithic_mount_data(struct fs_context *fc, void *data);
 extern int vfs_get_tree(struct fs_context *fc);
 extern void put_fs_context(struct fs_context *fc);
 
+extern const struct file_operations fs_fs_fops;
+
 #endif /* _LINUX_FS_CONTEXT_H */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 980c3c9b06f8..91ec8802ad5d 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -905,5 +905,6 @@ asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);
 asmlinkage long sys_pkey_free(int pkey);
 asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags,
 			  unsigned mask, struct statx __user *buffer);
+asmlinkage long sys_fsopen(const char *fs_name, int containerfd, unsigned int flags);
 
 #endif
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index e230af2e6855..88ae83492f7c 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -84,5 +84,6 @@
 #define UDF_SUPER_MAGIC		0x15013346
 #define BALLOON_KVM_MAGIC	0x13661366
 #define ZSMALLOC_MAGIC		0x58295829
+#define FS_FS_MAGIC		0x66736673
 
 #endif /* __LINUX_MAGIC_H__ */
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 8acef8576ce9..de1dc63e7e47 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -258,3 +258,6 @@ cond_syscall(sys_membarrier);
 cond_syscall(sys_pkey_mprotect);
 cond_syscall(sys_pkey_alloc);
 cond_syscall(sys_pkey_free);
+
+/* fd-based mount */
+cond_syscall(sys_fsopen);

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 13/27] VFS: Implement fsmount() to effect a pre-configured mount [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (11 preceding siblings ...)
  2017-06-14 15:17 ` [PATCH 12/27] VFS: Implement fsopen() to prepare for a mount " David Howells
@ 2017-06-14 15:17 ` David Howells
  2017-06-14 15:17 ` [PATCH 14/27] VFS: Add a sample program for fsopen/fsmount " David Howells
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:17 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Provide a system call by which a filesystem opened with fsopen() and
configured by a series of writes can be mounted:

	int ret = fsmount(int fsfd, int dfd, const char *path,
			  unsigned int at_flags, unsigned int flags);

where fsfd is the fd returned by fsopen(), dfd, path and at_flags locate
the mountpoint and flags are the applicable MS_* flags.  dfd can be
AT_FDCWD or an fd open to a directory.

In the event that fsmount() fails, it may be possible to get an error
message by calling read().  If no message is available, ENODATA will be
reported.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 arch/x86/entry/syscalls/syscall_32.tbl |    1 
 arch/x86/entry/syscalls/syscall_64.tbl |    1 
 fs/namespace.c                         |   85 ++++++++++++++++++++++++++++++++
 include/linux/syscalls.h               |    2 +
 kernel/sys_ni.c                        |    1 
 5 files changed, 90 insertions(+)

diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 9bf8d4c62f85..abe6ea95e0e6 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -392,3 +392,4 @@
 383	i386	statx			sys_statx
 384	i386	arch_prctl		sys_arch_prctl			compat_sys_arch_prctl
 385	i386	fsopen			sys_fsopen
+386	i386	fsmount			sys_fsmount
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 9b198c5fc412..0977c5079831 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -340,6 +340,7 @@
 331	common	pkey_free		sys_pkey_free
 332	common	statx			sys_statx
 333	common	fsopen			sys_fsopen
+334	common	fsmount			sys_fsmount
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/fs/namespace.c b/fs/namespace.c
index cd44283dee99..9158b67936a5 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3241,6 +3241,91 @@ vfs_submount(const struct dentry *mountpoint, struct file_system_type *type,
 EXPORT_SYMBOL_GPL(vfs_submount);
 
 /*
+ * Mount a new, prepared superblock (specified by fs_fd) on the location
+ * specified by dfd and dir_name.  dfd can be AT_FDCWD, a dir fd or a container
+ * fd.  This cannot be used for binding, moving or remounting mounts.
+ */
+SYSCALL_DEFINE5(fsmount, int, fs_fd, int, dfd, const char __user *, dir_name,
+		unsigned int, at_flags, unsigned int, flags)
+{
+	struct fs_context *fc;
+	struct path mountpoint;
+	struct fd f;
+	unsigned int lookup_flags, mnt_flags = 0;
+	long ret;
+
+	if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
+			  AT_EMPTY_PATH)) != 0)
+		return -EINVAL;
+
+	if (flags & ~(MS_RDONLY | MS_NOSUID | MS_NODEV | MS_NOEXEC |
+		      MS_NOATIME | MS_NODIRATIME | MS_RELATIME | MS_STRICTATIME))
+		return -EINVAL;
+
+	if (flags & MS_RDONLY)
+		mnt_flags |= MNT_READONLY;
+	if (flags & MS_NOSUID)
+		mnt_flags |= MNT_NOSUID;
+	if (flags & MS_NODEV)
+		mnt_flags |= MNT_NODEV;
+	if (flags & MS_NOEXEC)
+		mnt_flags |= MNT_NOEXEC;
+	if (flags & MS_NODIRATIME)
+		mnt_flags |= MNT_NODIRATIME;
+
+	if (flags & MS_STRICTATIME) {
+		if (flags & MS_NOATIME)
+			return -EINVAL;
+	} else if (flags & MS_NOATIME) {
+		mnt_flags |= MNT_NOATIME;
+	} else {
+		mnt_flags |= MNT_RELATIME;
+	}
+
+	f = fdget(fs_fd);
+	if (!f.file)
+		return -EBADF;
+
+	ret = -EINVAL;
+	if (f.file->f_op != &fs_fs_fops)
+		goto err_fsfd;
+
+	fc = f.file->private_data;
+
+	ret = -EPERM;
+	if (!may_mount() ||
+	    ((fc->sb_flags & MS_MANDLOCK) && !may_mandlock()))
+		goto err_fsfd;
+
+	/* There must be a valid superblock or we can't mount it */
+	if (!fc->root) {
+		ret = invalf("VFS: Root must be obtained before mount");
+		goto err_fsfd;
+	}
+
+	/* Find the mountpoint.  A container can be specified in dfd. */
+	lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
+	if (at_flags & AT_SYMLINK_NOFOLLOW)
+		lookup_flags &= ~LOOKUP_FOLLOW;
+	if (at_flags & AT_NO_AUTOMOUNT)
+		lookup_flags &= ~LOOKUP_AUTOMOUNT;
+	if (at_flags & AT_EMPTY_PATH)
+		lookup_flags |= LOOKUP_EMPTY;
+	ret = user_path_at(dfd, dir_name, lookup_flags, &mountpoint);
+	if (ret < 0) {
+		errorf("VFS: Mountpoint lookup failed");
+		goto err_fsfd;
+	}
+
+	ret = do_new_mount_fc(fc, &mountpoint, mnt_flags);
+
+	path_put(&mountpoint);
+err_fsfd:
+	fdput(f);
+	return ret;
+}
+
+/*
  * Return true if path is reachable from root
  *
  * namespace_sem or mount_lock is held
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 91ec8802ad5d..07e4f775f24d 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -906,5 +906,7 @@ asmlinkage long sys_pkey_free(int pkey);
 asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags,
 			  unsigned mask, struct statx __user *buffer);
 asmlinkage long sys_fsopen(const char *fs_name, int containerfd, unsigned int flags);
+asmlinkage long sys_fsmount(int fsfd, int dfd, const char *path, unsigned int at_flags,
+			    unsigned int flags);
 
 #endif
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index de1dc63e7e47..a0fe764bd5dd 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -261,3 +261,4 @@ cond_syscall(sys_pkey_free);
 
 /* fd-based mount */
 cond_syscall(sys_fsopen);
+cond_syscall(sys_fsmount);

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 14/27] VFS: Add a sample program for fsopen/fsmount [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (12 preceding siblings ...)
  2017-06-14 15:17 ` [PATCH 13/27] VFS: Implement fsmount() to effect a pre-configured " David Howells
@ 2017-06-14 15:17 ` David Howells
  2017-06-14 15:17 ` [PATCH 15/27] procfs: Move proc_fill_super() to fs/proc/root.c " David Howells
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:17 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Add a sample program for driving fsopen/fsmount.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 samples/fsmount/test-fsmount.c |   92 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 samples/fsmount/test-fsmount.c

diff --git a/samples/fsmount/test-fsmount.c b/samples/fsmount/test-fsmount.c
new file mode 100644
index 000000000000..30caad8e05a3
--- /dev/null
+++ b/samples/fsmount/test-fsmount.c
@@ -0,0 +1,92 @@
+/* fd-based mount test.
+ *
+ * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+
+#define PR_ERRMSG_ENABLE		48
+#define PR_ERRMSG_READ			49
+
+#define E(x) do { if ((x) == -1) { perror(#x); exit(1); } } while(0)
+
+static __attribute__((noreturn))
+void mount_error(int fd, const char *s)
+{
+	char buf[4096];
+	int err, n, perr;
+
+	do {
+		err = errno;
+		errno = 0;
+		n = prctl(PR_ERRMSG_READ, buf, sizeof(buf));
+		perr = errno;
+		errno = err;
+		if (n > 0) {
+			fprintf(stderr, "Error: '%s': %*.*s: %m\n", s, n, n, buf);
+		} else {
+			fprintf(stderr, "%s: %m\n", s);
+		}
+	} while (perr == 0);
+	exit(1);
+}
+
+#define E_write(fd, s)							\
+	do {								\
+		if (write(fd, s, sizeof(s) - 1) == -1)			\
+			mount_error(fd, s);				\
+	} while (0)
+
+static inline int fsopen(const char *fs_name, int reserved, int flags)
+{
+	return syscall(333, fs_name, reserved, flags);
+}
+
+static inline int fsmount(int fsfd, int dfd, const char *path,
+			  unsigned int at_flags, unsigned int flags)
+{
+	return syscall(334, fsfd, dfd, path, at_flags, flags);
+}
+
+int main()
+{
+	int mfd;
+
+	if (prctl(PR_ERRMSG_ENABLE, 1) < 0) {
+		perror("prctl/en");
+		exit(1);
+	}
+
+	/* Mount an NFS filesystem */
+	mfd = fsopen("nfs4", -1, 0);
+	if (mfd == -1) {
+		perror("fsopen");
+		exit(1);
+	}
+
+	E_write(mfd, "s warthog:/data");
+	E_write(mfd, "o fsc");
+	E_write(mfd, "o sync");
+	E_write(mfd, "o intr");
+	E_write(mfd, "o vers=4.2");
+	E_write(mfd, "o addr=90.155.74.18");
+	E_write(mfd, "o clientaddr=90.155.74.21");
+	E_write(mfd, "x create");
+	if (fsmount(mfd, AT_FDCWD, "/mnt", 0, 0) < 0)
+		mount_error(mfd, "fsmount");
+	E(close(mfd));
+
+	exit(0);
+}

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 15/27] procfs: Move proc_fill_super() to fs/proc/root.c [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (13 preceding siblings ...)
  2017-06-14 15:17 ` [PATCH 14/27] VFS: Add a sample program for fsopen/fsmount " David Howells
@ 2017-06-14 15:17 ` David Howells
  2017-06-14 15:17 ` [PATCH 16/27] proc: Add fs_context support to procfs " David Howells
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:17 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Move proc_fill_super() to fs/proc/root.c as that's where the other
superblock stuff is.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/proc/inode.c    |   48 +-----------------------------------------------
 fs/proc/internal.h |    4 +---
 fs/proc/root.c     |   48 +++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 49 insertions(+), 51 deletions(-)

diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 0163d71d5887..a4bf66af0ba9 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -22,7 +22,6 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/mount.h>
-#include <linux/magic.h>
 
 #include <linux/uaccess.h>
 
@@ -113,7 +112,7 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
 	return 0;
 }
 
-static const struct super_operations proc_sops = {
+const struct super_operations proc_sops = {
 	.alloc_inode	= proc_alloc_inode,
 	.destroy_inode	= proc_destroy_inode,
 	.drop_inode	= generic_delete_inode,
@@ -470,48 +469,3 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
 	       pde_put(de);
 	return inode;
 }
-
-int proc_fill_super(struct super_block *s, void *data, int silent)
-{
-	struct pid_namespace *ns = get_pid_ns(s->s_fs_info);
-	struct inode *root_inode;
-	int ret;
-
-	if (!proc_parse_options(data, ns))
-		return -EINVAL;
-
-	/* User space would break if executables or devices appear on proc */
-	s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
-	s->s_flags |= SB_NODIRATIME | SB_NOSUID | SB_NOEXEC;
-	s->s_blocksize = 1024;
-	s->s_blocksize_bits = 10;
-	s->s_magic = PROC_SUPER_MAGIC;
-	s->s_op = &proc_sops;
-	s->s_time_gran = 1;
-
-	/*
-	 * procfs isn't actually a stacking filesystem; however, there is
-	 * too much magic going on inside it to permit stacking things on
-	 * top of it
-	 */
-	s->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
-	
-	pde_get(&proc_root);
-	root_inode = proc_get_inode(s, &proc_root);
-	if (!root_inode) {
-		pr_err("proc_fill_super: get root inode failed\n");
-		return -ENOMEM;
-	}
-
-	s->s_root = d_make_root(root_inode);
-	if (!s->s_root) {
-		pr_err("proc_fill_super: allocate dentry failed\n");
-		return -ENOMEM;
-	}
-
-	ret = proc_setup_self(s);
-	if (ret) {
-		return ret;
-	}
-	return proc_setup_thread_self(s);
-}
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index c5ae09b6c726..b681533f59dd 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -197,13 +197,12 @@ struct pde_opener {
 	struct completion *c;
 };
 extern const struct inode_operations proc_link_inode_operations;
-
 extern const struct inode_operations proc_pid_link_inode_operations;
+extern const struct super_operations proc_sops;
 
 extern void proc_init_inodecache(void);
 void set_proc_pid_nlink(void);
 extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *);
-extern int proc_fill_super(struct super_block *, void *data, int flags);
 extern void proc_entry_rundown(struct proc_dir_entry *);
 
 /*
@@ -261,7 +260,6 @@ static inline void proc_tty_init(void) {}
  * root.c
  */
 extern struct proc_dir_entry proc_root;
-extern int proc_parse_options(char *options, struct pid_namespace *pid);
 
 extern void proc_self_init(void);
 extern int proc_remount(struct super_block *, int *, char *);
diff --git a/fs/proc/root.c b/fs/proc/root.c
index fd91901a299e..3dd3838d9e08 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -22,6 +22,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/parser.h>
 #include <linux/cred.h>
+#include <linux/magic.h>
 
 #include "internal.h"
 
@@ -35,7 +36,7 @@ static const match_table_t tokens = {
 	{Opt_err, NULL},
 };
 
-int proc_parse_options(char *options, struct pid_namespace *pid)
+static int proc_parse_options(char *options, struct pid_namespace *pid)
 {
 	char *p;
 	substring_t args[MAX_OPT_ARGS];
@@ -77,6 +78,51 @@ int proc_parse_options(char *options, struct pid_namespace *pid)
 	return 1;
 }
 
+static int proc_fill_super(struct super_block *s, void *data, int silent)
+{
+	struct pid_namespace *ns = get_pid_ns(s->s_fs_info);
+	struct inode *root_inode;
+	int ret;
+
+	if (!proc_parse_options(data, ns))
+		return -EINVAL;
+
+	/* User space would break if executables or devices appear on proc */
+	s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
+	s->s_flags |= SB_NODIRATIME | SB_NOSUID | SB_NOEXEC;
+	s->s_blocksize = 1024;
+	s->s_blocksize_bits = 10;
+	s->s_magic = PROC_SUPER_MAGIC;
+	s->s_op = &proc_sops;
+	s->s_time_gran = 1;
+
+	/*
+	 * procfs isn't actually a stacking filesystem; however, there is
+	 * too much magic going on inside it to permit stacking things on
+	 * top of it
+	 */
+	s->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
+	
+	pde_get(&proc_root);
+	root_inode = proc_get_inode(s, &proc_root);
+	if (!root_inode) {
+		pr_err("proc_fill_super: get root inode failed\n");
+		return -ENOMEM;
+	}
+
+	s->s_root = d_make_root(root_inode);
+	if (!s->s_root) {
+		pr_err("proc_fill_super: allocate dentry failed\n");
+		return -ENOMEM;
+	}
+
+	ret = proc_setup_self(s);
+	if (ret) {
+		return ret;
+	}
+	return proc_setup_thread_self(s);
+}
+
 int proc_remount(struct super_block *sb, int *flags, char *data)
 {
 	struct pid_namespace *pid = sb->s_fs_info;

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 16/27] proc: Add fs_context support to procfs [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (14 preceding siblings ...)
  2017-06-14 15:17 ` [PATCH 15/27] procfs: Move proc_fill_super() to fs/proc/root.c " David Howells
@ 2017-06-14 15:17 ` David Howells
  2017-06-15 10:14   ` Al Viro
  2017-06-14 15:17 ` [PATCH 17/27] NFS: Move mount parameterisation bits into their own file " David Howells
                   ` (11 subsequent siblings)
  27 siblings, 1 reply; 53+ messages in thread
From: David Howells @ 2017-06-14 15:17 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Add fs_context support to procfs.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/proc/inode.c    |    2 -
 fs/proc/internal.h |    2 -
 fs/proc/root.c     |  175 ++++++++++++++++++++++++++++++++++------------------
 3 files changed, 116 insertions(+), 63 deletions(-)

diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index a4bf66af0ba9..a642bee67a53 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -118,7 +118,7 @@ const struct super_operations proc_sops = {
 	.drop_inode	= generic_delete_inode,
 	.evict_inode	= proc_evict_inode,
 	.statfs		= simple_statfs,
-	.remount_fs	= proc_remount,
+	.remount_fs_fc	= proc_remount,
 	.show_options	= proc_show_options,
 };
 
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index b681533f59dd..78d1e4ff5f76 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -262,7 +262,7 @@ static inline void proc_tty_init(void) {}
 extern struct proc_dir_entry proc_root;
 
 extern void proc_self_init(void);
-extern int proc_remount(struct super_block *, int *, char *);
+extern int proc_remount(struct super_block *, struct fs_context *);
 
 /*
  * task_[no]mmu.c
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 3dd3838d9e08..22d8e8f20c38 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -18,14 +18,23 @@
 #include <linux/module.h>
 #include <linux/bitops.h>
 #include <linux/user_namespace.h>
-#include <linux/mount.h>
+#include <linux/fs_context.h>
 #include <linux/pid_namespace.h>
 #include <linux/parser.h>
 #include <linux/cred.h>
 #include <linux/magic.h>
+#include <linux/slab.h>
 
 #include "internal.h"
 
+struct proc_fs_context {
+	struct fs_context	fc;
+	struct pid_namespace	*pid_ns;
+	unsigned long		mask;
+	int			hidepid;
+	int			gid;
+};
+
 enum {
 	Opt_gid, Opt_hidepid, Opt_err,
 };
@@ -36,56 +45,60 @@ static const match_table_t tokens = {
 	{Opt_err, NULL},
 };
 
-static int proc_parse_options(char *options, struct pid_namespace *pid)
+static int proc_parse_mount_option(struct fs_context *fc, char *p)
 {
-	char *p;
+	struct proc_fs_context *ctx = container_of(fc, struct proc_fs_context, fc);
 	substring_t args[MAX_OPT_ARGS];
-	int option;
-
-	if (!options)
-		return 1;
-
-	while ((p = strsep(&options, ",")) != NULL) {
-		int token;
-		if (!*p)
-			continue;
-
-		args[0].to = args[0].from = NULL;
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_gid:
-			if (match_int(&args[0], &option))
-				return 0;
-			pid->pid_gid = make_kgid(current_user_ns(), option);
-			break;
-		case Opt_hidepid:
-			if (match_int(&args[0], &option))
-				return 0;
-			if (option < HIDEPID_OFF ||
-			    option > HIDEPID_INVISIBLE) {
-				pr_err("proc: hidepid value must be between 0 and 2.\n");
-				return 0;
-			}
-			pid->hide_pid = option;
-			break;
-		default:
-			pr_err("proc: unrecognized mount option \"%s\" "
-			       "or missing value\n", p);
-			return 0;
+	int token;
+
+	args[0].to = args[0].from = NULL;
+	token = match_token(p, tokens, args);
+	switch (token) {
+	case Opt_gid:
+		if (match_int(&args[0], &ctx->gid))
+			return invalf("procfs: Unparseable gid= argument");
+		break;
+
+	case Opt_hidepid:
+		if (match_int(&args[0], &ctx->hidepid))
+			return invalf("procfs: Unparseable hidepid= argument");
+		if (ctx->hidepid < HIDEPID_OFF ||
+		    ctx->hidepid > HIDEPID_INVISIBLE) {
+			pr_err("proc: hidepid value must be between 0 and 2.\n");
+			return invalf("procfs: Invalid hidepid= argument");
 		}
+		break;
+
+	default:
+		pr_err("proc: unrecognized mount option \"%s\" "
+		       "or missing value\n", p);
+		return invalf("procfs: Invalid mount option or missing value");
 	}
 
-	return 1;
+	ctx->mask |= 1 << token;
+	return 0;
+}
+
+static void proc_set_options(struct super_block *s,
+			     struct fs_context *fc,
+			     struct pid_namespace *pid_ns,
+			     struct user_namespace *user_ns)
+{
+	struct proc_fs_context *ctx = container_of(fc, struct proc_fs_context, fc);
+
+	if (ctx->mask & (1 << Opt_gid))
+		pid_ns->pid_gid = make_kgid(user_ns, ctx->gid);
+	if (ctx->mask & (1 << Opt_hidepid))
+		pid_ns->hide_pid = ctx->hidepid;
 }
 
-static int proc_fill_super(struct super_block *s, void *data, int silent)
+static int proc_fill_super(struct super_block *s, struct fs_context *fc)
 {
-	struct pid_namespace *ns = get_pid_ns(s->s_fs_info);
+	struct pid_namespace *pid_ns = get_pid_ns(s->s_fs_info);
 	struct inode *root_inode;
 	int ret;
 
-	if (!proc_parse_options(data, ns))
-		return -EINVAL;
+	proc_set_options(s, fc, pid_ns, current_user_ns());
 
 	/* User space would break if executables or devices appear on proc */
 	s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
@@ -102,7 +115,7 @@ static int proc_fill_super(struct super_block *s, void *data, int silent)
 	 * top of it
 	 */
 	s->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
-	
+
 	pde_get(&proc_root);
 	root_inode = proc_get_inode(s, &proc_root);
 	if (!root_inode) {
@@ -123,27 +136,45 @@ static int proc_fill_super(struct super_block *s, void *data, int silent)
 	return proc_setup_thread_self(s);
 }
 
-int proc_remount(struct super_block *sb, int *flags, char *data)
+int proc_remount(struct super_block *sb, struct fs_context *fc)
 {
 	struct pid_namespace *pid = sb->s_fs_info;
 
 	sync_filesystem(sb);
-	return !proc_parse_options(data, pid);
+
+	if (fc)
+		proc_set_options(sb, fc, pid, current_user_ns());
+	return 0;
 }
 
-static struct dentry *proc_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+static int proc_get_tree(struct fs_context *fc)
 {
-	struct pid_namespace *ns;
+	struct proc_fs_context *ctx = container_of(fc, struct proc_fs_context, fc);
 
-	if (flags & SB_KERNMOUNT) {
-		ns = data;
-		data = NULL;
-	} else {
-		ns = task_active_pid_ns(current);
-	}
+	return mount_ns_fc(fc, proc_fill_super, ctx->pid_ns);
+}
+
+static void proc_fs_context_free(struct fs_context *fc)
+{
+	struct proc_fs_context *ctx = container_of(fc, struct proc_fs_context, fc);
 
-	return mount_ns(fs_type, flags, data, ns, ns->user_ns, proc_fill_super);
+	if (ctx->pid_ns)
+		put_pid_ns(ctx->pid_ns);
+}
+
+static const struct fs_context_operations proc_fs_context_ops = {
+	.free		= proc_fs_context_free,
+	.parse_option	= proc_parse_mount_option,
+	.get_tree	= proc_get_tree,
+};
+
+static int proc_init_fs_context(struct fs_context *fc, struct super_block *src_sb)
+{
+	struct proc_fs_context *ctx = container_of(fc, struct proc_fs_context, fc);
+
+	ctx->pid_ns = get_pid_ns(task_active_pid_ns(current));
+	ctx->fc.ops = &proc_fs_context_ops;
+	return 0;
 }
 
 static void proc_kill_sb(struct super_block *sb)
@@ -161,7 +192,8 @@ static void proc_kill_sb(struct super_block *sb)
 
 static struct file_system_type proc_fs_type = {
 	.name		= "proc",
-	.mount		= proc_mount,
+	.fs_context_size	= sizeof(struct proc_fs_context),
+	.init_fs_context	= proc_init_fs_context,
 	.kill_sb	= proc_kill_sb,
 	.fs_flags	= FS_USERNS_MOUNT,
 };
@@ -209,7 +241,7 @@ static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentr
 {
 	if (!proc_pid_lookup(dir, dentry, flags))
 		return NULL;
-	
+
 	return proc_lookup(dir, dentry, flags);
 }
 
@@ -248,12 +280,12 @@ static const struct inode_operations proc_root_inode_operations = {
  * This is the root "inode" in the /proc tree..
  */
 struct proc_dir_entry proc_root = {
-	.low_ino	= PROC_ROOT_INO, 
-	.namelen	= 5, 
-	.mode		= S_IFDIR | S_IRUGO | S_IXUGO, 
-	.nlink		= 2, 
+	.low_ino	= PROC_ROOT_INO,
+	.namelen	= 5,
+	.mode		= S_IFDIR | S_IRUGO | S_IXUGO,
+	.nlink		= 2,
 	.count		= ATOMIC_INIT(1),
-	.proc_iops	= &proc_root_inode_operations, 
+	.proc_iops	= &proc_root_inode_operations,
 	.proc_fops	= &proc_root_operations,
 	.parent		= &proc_root,
 	.subdir		= RB_ROOT,
@@ -262,9 +294,30 @@ struct proc_dir_entry proc_root = {
 
 int pid_ns_prepare_proc(struct pid_namespace *ns)
 {
+	struct proc_fs_context *ctx;
+	struct fs_context *fc;
 	struct vfsmount *mnt;
+	int ret;
+
+	fc = vfs_new_fs_context(&proc_fs_type, NULL, 0, FS_CONTEXT_FOR_NEW);
+	if (IS_ERR(fc))
+		return PTR_ERR(fc);
+
+	ctx = container_of(fc, struct proc_fs_context, fc);
+	if (ctx->pid_ns != ns) {
+		put_pid_ns(ctx->pid_ns);
+		get_pid_ns(ns);
+		ctx->pid_ns = ns;
+	}
+
+	ret = vfs_get_tree(fc);
+	if (ret < 0) {
+		put_fs_context(fc);
+		return ret;
+	}
 
-	mnt = kern_mount_data(&proc_fs_type, ns);
+	mnt = kern_mount_data_fc(fc);
+	put_fs_context(fc);
 	if (IS_ERR(mnt))
 		return PTR_ERR(mnt);
 

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 17/27] NFS: Move mount parameterisation bits into their own file [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (15 preceding siblings ...)
  2017-06-14 15:17 ` [PATCH 16/27] proc: Add fs_context support to procfs " David Howells
@ 2017-06-14 15:17 ` David Howells
  2017-06-14 15:18 ` [PATCH 18/27] NFS: Constify mount argument match tables " David Howells
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:17 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Split various bits relating to mount parameterisation out from
fs/nfs/super.c into their own file to form the basis of filesystem context
handling for NFS.

No other changes are made to the code beyond removing 'static' qualifiers.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/nfs/Makefile     |    6 
 fs/nfs/fs_context.c | 1398 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nfs/internal.h   |   30 +
 fs/nfs/super.c      | 1391 ---------------------------------------------------
 4 files changed, 1431 insertions(+), 1394 deletions(-)
 create mode 100644 fs/nfs/fs_context.c

diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 98f4e5728a67..dd949b728d9f 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -5,9 +5,9 @@
 obj-$(CONFIG_NFS_FS) += nfs.o
 
 CFLAGS_nfstrace.o += -I$(src)
-nfs-y 			:= client.o dir.o file.o getroot.o inode.o super.o \
-			   io.o direct.o pagelist.o read.o symlink.o unlink.o \
-			   write.o namespace.o mount_clnt.o nfstrace.o
+nfs-y 	:= client.o dir.o file.o getroot.o inode.o super.o \
+	   io.o direct.o pagelist.o read.o symlink.o unlink.o \
+	   write.o namespace.o mount_clnt.o nfstrace.o fs_context.o
 nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
 nfs-$(CONFIG_SYSCTL)	+= sysctl.o
 nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
new file mode 100644
index 000000000000..3e2fe57b9b07
--- /dev/null
+++ b/fs/nfs/fs_context.c
@@ -0,0 +1,1398 @@
+/* NFS mount handling.
+ *
+ * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Split from fs/nfs/super.c:
+ *
+ *  Copyright (C) 1992  Rick Sladkey
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/parser.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs4_mount.h>
+#include "nfs.h"
+#include "internal.h"
+
+#define NFSDBG_FACILITY		NFSDBG_MOUNT
+
+#if IS_ENABLED(CONFIG_NFS_V3)
+#define NFS_DEFAULT_VERSION 3
+#else
+#define NFS_DEFAULT_VERSION 2
+#endif
+
+enum {
+	/* Mount options that take no arguments */
+	Opt_soft, Opt_hard,
+	Opt_posix, Opt_noposix,
+	Opt_cto, Opt_nocto,
+	Opt_ac, Opt_noac,
+	Opt_lock, Opt_nolock,
+	Opt_udp, Opt_tcp, Opt_rdma,
+	Opt_acl, Opt_noacl,
+	Opt_rdirplus, Opt_nordirplus,
+	Opt_sharecache, Opt_nosharecache,
+	Opt_resvport, Opt_noresvport,
+	Opt_fscache, Opt_nofscache,
+	Opt_migration, Opt_nomigration,
+
+	/* Mount options that take integer arguments */
+	Opt_port,
+	Opt_rsize, Opt_wsize, Opt_bsize,
+	Opt_timeo, Opt_retrans,
+	Opt_acregmin, Opt_acregmax,
+	Opt_acdirmin, Opt_acdirmax,
+	Opt_actimeo,
+	Opt_namelen,
+	Opt_mountport,
+	Opt_mountvers,
+	Opt_minorversion,
+
+	/* Mount options that take string arguments */
+	Opt_nfsvers,
+	Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
+	Opt_addr, Opt_mountaddr, Opt_clientaddr,
+	Opt_lookupcache,
+	Opt_fscache_uniq,
+	Opt_local_lock,
+
+	/* Special mount options */
+	Opt_userspace, Opt_deprecated, Opt_sloppy,
+
+	Opt_err
+};
+
+static const match_table_t nfs_mount_option_tokens = {
+	{ Opt_userspace, "bg" },
+	{ Opt_userspace, "fg" },
+	{ Opt_userspace, "retry=%s" },
+
+	{ Opt_sloppy, "sloppy" },
+
+	{ Opt_soft, "soft" },
+	{ Opt_hard, "hard" },
+	{ Opt_deprecated, "intr" },
+	{ Opt_deprecated, "nointr" },
+	{ Opt_posix, "posix" },
+	{ Opt_noposix, "noposix" },
+	{ Opt_cto, "cto" },
+	{ Opt_nocto, "nocto" },
+	{ Opt_ac, "ac" },
+	{ Opt_noac, "noac" },
+	{ Opt_lock, "lock" },
+	{ Opt_nolock, "nolock" },
+	{ Opt_udp, "udp" },
+	{ Opt_tcp, "tcp" },
+	{ Opt_rdma, "rdma" },
+	{ Opt_acl, "acl" },
+	{ Opt_noacl, "noacl" },
+	{ Opt_rdirplus, "rdirplus" },
+	{ Opt_nordirplus, "nordirplus" },
+	{ Opt_sharecache, "sharecache" },
+	{ Opt_nosharecache, "nosharecache" },
+	{ Opt_resvport, "resvport" },
+	{ Opt_noresvport, "noresvport" },
+	{ Opt_fscache, "fsc" },
+	{ Opt_nofscache, "nofsc" },
+	{ Opt_migration, "migration" },
+	{ Opt_nomigration, "nomigration" },
+
+	{ Opt_port, "port=%s" },
+	{ Opt_rsize, "rsize=%s" },
+	{ Opt_wsize, "wsize=%s" },
+	{ Opt_bsize, "bsize=%s" },
+	{ Opt_timeo, "timeo=%s" },
+	{ Opt_retrans, "retrans=%s" },
+	{ Opt_acregmin, "acregmin=%s" },
+	{ Opt_acregmax, "acregmax=%s" },
+	{ Opt_acdirmin, "acdirmin=%s" },
+	{ Opt_acdirmax, "acdirmax=%s" },
+	{ Opt_actimeo, "actimeo=%s" },
+	{ Opt_namelen, "namlen=%s" },
+	{ Opt_mountport, "mountport=%s" },
+	{ Opt_mountvers, "mountvers=%s" },
+	{ Opt_minorversion, "minorversion=%s" },
+
+	{ Opt_nfsvers, "nfsvers=%s" },
+	{ Opt_nfsvers, "vers=%s" },
+
+	{ Opt_sec, "sec=%s" },
+	{ Opt_proto, "proto=%s" },
+	{ Opt_mountproto, "mountproto=%s" },
+	{ Opt_addr, "addr=%s" },
+	{ Opt_clientaddr, "clientaddr=%s" },
+	{ Opt_mounthost, "mounthost=%s" },
+	{ Opt_mountaddr, "mountaddr=%s" },
+
+	{ Opt_lookupcache, "lookupcache=%s" },
+	{ Opt_fscache_uniq, "fsc=%s" },
+	{ Opt_local_lock, "local_lock=%s" },
+
+	/* The following needs to be listed after all other options */
+	{ Opt_nfsvers, "v%s" },
+
+	{ Opt_err, NULL }
+};
+
+enum {
+	Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma,
+	Opt_xprt_rdma6,
+
+	Opt_xprt_err
+};
+
+static const match_table_t nfs_xprt_protocol_tokens = {
+	{ Opt_xprt_udp, "udp" },
+	{ Opt_xprt_udp6, "udp6" },
+	{ Opt_xprt_tcp, "tcp" },
+	{ Opt_xprt_tcp6, "tcp6" },
+	{ Opt_xprt_rdma, "rdma" },
+	{ Opt_xprt_rdma6, "rdma6" },
+
+	{ Opt_xprt_err, NULL }
+};
+
+enum {
+	Opt_sec_none, Opt_sec_sys,
+	Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p,
+	Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp,
+	Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp,
+
+	Opt_sec_err
+};
+
+static const match_table_t nfs_secflavor_tokens = {
+	{ Opt_sec_none, "none" },
+	{ Opt_sec_none, "null" },
+	{ Opt_sec_sys, "sys" },
+
+	{ Opt_sec_krb5, "krb5" },
+	{ Opt_sec_krb5i, "krb5i" },
+	{ Opt_sec_krb5p, "krb5p" },
+
+	{ Opt_sec_lkey, "lkey" },
+	{ Opt_sec_lkeyi, "lkeyi" },
+	{ Opt_sec_lkeyp, "lkeyp" },
+
+	{ Opt_sec_spkm, "spkm3" },
+	{ Opt_sec_spkmi, "spkm3i" },
+	{ Opt_sec_spkmp, "spkm3p" },
+
+	{ Opt_sec_err, NULL }
+};
+
+enum {
+	Opt_lookupcache_all, Opt_lookupcache_positive,
+	Opt_lookupcache_none,
+
+	Opt_lookupcache_err
+};
+
+static match_table_t nfs_lookupcache_tokens = {
+	{ Opt_lookupcache_all, "all" },
+	{ Opt_lookupcache_positive, "pos" },
+	{ Opt_lookupcache_positive, "positive" },
+	{ Opt_lookupcache_none, "none" },
+
+	{ Opt_lookupcache_err, NULL }
+};
+
+enum {
+	Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
+	Opt_local_lock_none,
+
+	Opt_local_lock_err
+};
+
+static match_table_t nfs_local_lock_tokens = {
+	{ Opt_local_lock_all, "all" },
+	{ Opt_local_lock_flock, "flock" },
+	{ Opt_local_lock_posix, "posix" },
+	{ Opt_local_lock_none, "none" },
+
+	{ Opt_local_lock_err, NULL }
+};
+
+enum {
+	Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
+	Opt_vers_4_1, Opt_vers_4_2,
+
+	Opt_vers_err
+};
+
+static match_table_t nfs_vers_tokens = {
+	{ Opt_vers_2, "2" },
+	{ Opt_vers_3, "3" },
+	{ Opt_vers_4, "4" },
+	{ Opt_vers_4_0, "4.0" },
+	{ Opt_vers_4_1, "4.1" },
+	{ Opt_vers_4_2, "4.2" },
+
+	{ Opt_vers_err, NULL }
+};
+
+struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
+{
+	struct nfs_parsed_mount_data *data;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (data) {
+		data->timeo		= NFS_UNSPEC_TIMEO;
+		data->retrans		= NFS_UNSPEC_RETRANS;
+		data->acregmin		= NFS_DEF_ACREGMIN;
+		data->acregmax		= NFS_DEF_ACREGMAX;
+		data->acdirmin		= NFS_DEF_ACDIRMIN;
+		data->acdirmax		= NFS_DEF_ACDIRMAX;
+		data->mount_server.port	= NFS_UNSPEC_PORT;
+		data->nfs_server.port	= NFS_UNSPEC_PORT;
+		data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+		data->selected_flavor	= RPC_AUTH_MAXFLAVOR;
+		data->minorversion	= 0;
+		data->need_mount	= true;
+		data->net		= current->nsproxy->net_ns;
+		security_init_mnt_opts(&data->lsm_opts);
+	}
+	return data;
+}
+
+void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
+{
+	if (data) {
+		kfree(data->client_address);
+		kfree(data->mount_server.hostname);
+		kfree(data->nfs_server.export_path);
+		kfree(data->nfs_server.hostname);
+		kfree(data->fscache_uniq);
+		security_free_mnt_opts(&data->lsm_opts);
+		kfree(data);
+	}
+}
+
+/*
+ * Sanity-check a server address provided by the mount command.
+ *
+ * Address family must be initialized, and address must not be
+ * the ANY address for that family.
+ */
+static int nfs_verify_server_address(struct sockaddr *addr)
+{
+	switch (addr->sa_family) {
+	case AF_INET: {
+		struct sockaddr_in *sa = (struct sockaddr_in *)addr;
+		return sa->sin_addr.s_addr != htonl(INADDR_ANY);
+	}
+	case AF_INET6: {
+		struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr;
+		return !ipv6_addr_any(sa);
+	}
+	}
+
+	dfprintk(MOUNT, "NFS: Invalid IP address specified\n");
+	return 0;
+}
+
+/*
+ * Sanity check the NFS transport protocol.
+ *
+ */
+static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
+{
+	switch (mnt->nfs_server.protocol) {
+	case XPRT_TRANSPORT_UDP:
+	case XPRT_TRANSPORT_TCP:
+	case XPRT_TRANSPORT_RDMA:
+		break;
+	default:
+		mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+	}
+}
+
+/*
+ * For text based NFSv2/v3 mounts, the mount protocol transport default
+ * settings should depend upon the specified NFS transport.
+ */
+static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
+{
+	nfs_validate_transport_protocol(mnt);
+
+	if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP ||
+	    mnt->mount_server.protocol == XPRT_TRANSPORT_TCP)
+			return;
+	switch (mnt->nfs_server.protocol) {
+	case XPRT_TRANSPORT_UDP:
+		mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+		break;
+	case XPRT_TRANSPORT_TCP:
+	case XPRT_TRANSPORT_RDMA:
+		mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
+	}
+}
+
+/*
+ * Add 'flavor' to 'auth_info' if not already present.
+ * Returns true if 'flavor' ends up in the list, false otherwise
+ */
+static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
+			      rpc_authflavor_t flavor)
+{
+	unsigned int i;
+	unsigned int max_flavor_len = ARRAY_SIZE(auth_info->flavors);
+
+	/* make sure this flavor isn't already in the list */
+	for (i = 0; i < auth_info->flavor_len; i++) {
+		if (flavor == auth_info->flavors[i])
+			return true;
+	}
+
+	if (auth_info->flavor_len + 1 >= max_flavor_len) {
+		dfprintk(MOUNT, "NFS: too many sec= flavors\n");
+		return false;
+	}
+
+	auth_info->flavors[auth_info->flavor_len++] = flavor;
+	return true;
+}
+
+/*
+ * Parse the value of the 'sec=' option.
+ */
+static int nfs_parse_security_flavors(char *value,
+				      struct nfs_parsed_mount_data *mnt)
+{
+	substring_t args[MAX_OPT_ARGS];
+	rpc_authflavor_t pseudoflavor;
+	char *p;
+
+	dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
+
+	while ((p = strsep(&value, ":")) != NULL) {
+		switch (match_token(p, nfs_secflavor_tokens, args)) {
+		case Opt_sec_none:
+			pseudoflavor = RPC_AUTH_NULL;
+			break;
+		case Opt_sec_sys:
+			pseudoflavor = RPC_AUTH_UNIX;
+			break;
+		case Opt_sec_krb5:
+			pseudoflavor = RPC_AUTH_GSS_KRB5;
+			break;
+		case Opt_sec_krb5i:
+			pseudoflavor = RPC_AUTH_GSS_KRB5I;
+			break;
+		case Opt_sec_krb5p:
+			pseudoflavor = RPC_AUTH_GSS_KRB5P;
+			break;
+		case Opt_sec_lkey:
+			pseudoflavor = RPC_AUTH_GSS_LKEY;
+			break;
+		case Opt_sec_lkeyi:
+			pseudoflavor = RPC_AUTH_GSS_LKEYI;
+			break;
+		case Opt_sec_lkeyp:
+			pseudoflavor = RPC_AUTH_GSS_LKEYP;
+			break;
+		case Opt_sec_spkm:
+			pseudoflavor = RPC_AUTH_GSS_SPKM;
+			break;
+		case Opt_sec_spkmi:
+			pseudoflavor = RPC_AUTH_GSS_SPKMI;
+			break;
+		case Opt_sec_spkmp:
+			pseudoflavor = RPC_AUTH_GSS_SPKMP;
+			break;
+		default:
+			dfprintk(MOUNT,
+				 "NFS: sec= option '%s' not recognized\n", p);
+			return 0;
+		}
+
+		if (!nfs_auth_info_add(&mnt->auth_info, pseudoflavor))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int nfs_parse_version_string(char *string,
+		struct nfs_parsed_mount_data *mnt,
+		substring_t *args)
+{
+	mnt->flags &= ~NFS_MOUNT_VER3;
+	switch (match_token(string, nfs_vers_tokens, args)) {
+	case Opt_vers_2:
+		mnt->version = 2;
+		break;
+	case Opt_vers_3:
+		mnt->flags |= NFS_MOUNT_VER3;
+		mnt->version = 3;
+		break;
+	case Opt_vers_4:
+		/* Backward compatibility option. In future,
+		 * the mount program should always supply
+		 * a NFSv4 minor version number.
+		 */
+		mnt->version = 4;
+		break;
+	case Opt_vers_4_0:
+		mnt->version = 4;
+		mnt->minorversion = 0;
+		break;
+	case Opt_vers_4_1:
+		mnt->version = 4;
+		mnt->minorversion = 1;
+		break;
+	case Opt_vers_4_2:
+		mnt->version = 4;
+		mnt->minorversion = 2;
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int nfs_get_option_str(substring_t args[], char **option)
+{
+	kfree(*option);
+	*option = match_strdup(args);
+	return !*option;
+}
+
+static int nfs_get_option_ul(substring_t args[], unsigned long *option)
+{
+	int rc;
+	char *string;
+
+	string = match_strdup(args);
+	if (string == NULL)
+		return -ENOMEM;
+	rc = kstrtoul(string, 10, option);
+	kfree(string);
+
+	return rc;
+}
+
+static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
+		unsigned long l_bound, unsigned long u_bound)
+{
+	int ret;
+
+	ret = nfs_get_option_ul(args, option);
+	if (ret != 0)
+		return ret;
+	if (*option < l_bound || *option > u_bound)
+		return -ERANGE;
+	return 0;
+}
+
+/*
+ * Error-check and convert a string of mount options from user space into
+ * a data structure.  The whole mount string is processed; bad options are
+ * skipped as they are encountered.  If there were no errors, return 1;
+ * otherwise return 0 (zero).
+ */
+int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
+{
+	char *p, *string, *secdata;
+	int rc, sloppy = 0, invalid_option = 0;
+	unsigned short protofamily = AF_UNSPEC;
+	unsigned short mountfamily = AF_UNSPEC;
+
+	if (!raw) {
+		dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
+		return 1;
+	}
+	dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
+
+	secdata = alloc_secdata();
+	if (!secdata)
+		goto out_nomem;
+
+	rc = security_sb_copy_data(raw, secdata);
+	if (rc)
+		goto out_security_failure;
+
+	rc = security_sb_parse_opts_str(secdata, &mnt->lsm_opts);
+	if (rc)
+		goto out_security_failure;
+
+	free_secdata(secdata);
+
+	while ((p = strsep(&raw, ",")) != NULL) {
+		substring_t args[MAX_OPT_ARGS];
+		unsigned long option;
+		int token;
+
+		if (!*p)
+			continue;
+
+		dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
+
+		token = match_token(p, nfs_mount_option_tokens, args);
+		switch (token) {
+
+		/*
+		 * boolean options:  foo/nofoo
+		 */
+		case Opt_soft:
+			mnt->flags |= NFS_MOUNT_SOFT;
+			break;
+		case Opt_hard:
+			mnt->flags &= ~NFS_MOUNT_SOFT;
+			break;
+		case Opt_posix:
+			mnt->flags |= NFS_MOUNT_POSIX;
+			break;
+		case Opt_noposix:
+			mnt->flags &= ~NFS_MOUNT_POSIX;
+			break;
+		case Opt_cto:
+			mnt->flags &= ~NFS_MOUNT_NOCTO;
+			break;
+		case Opt_nocto:
+			mnt->flags |= NFS_MOUNT_NOCTO;
+			break;
+		case Opt_ac:
+			mnt->flags &= ~NFS_MOUNT_NOAC;
+			break;
+		case Opt_noac:
+			mnt->flags |= NFS_MOUNT_NOAC;
+			break;
+		case Opt_lock:
+			mnt->flags &= ~NFS_MOUNT_NONLM;
+			mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+					NFS_MOUNT_LOCAL_FCNTL);
+			break;
+		case Opt_nolock:
+			mnt->flags |= NFS_MOUNT_NONLM;
+			mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+				       NFS_MOUNT_LOCAL_FCNTL);
+			break;
+		case Opt_udp:
+			mnt->flags &= ~NFS_MOUNT_TCP;
+			mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+			break;
+		case Opt_tcp:
+			mnt->flags |= NFS_MOUNT_TCP;
+			mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+			break;
+		case Opt_rdma:
+			mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
+			mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+			xprt_load_transport(p);
+			break;
+		case Opt_acl:
+			mnt->flags &= ~NFS_MOUNT_NOACL;
+			break;
+		case Opt_noacl:
+			mnt->flags |= NFS_MOUNT_NOACL;
+			break;
+		case Opt_rdirplus:
+			mnt->flags &= ~NFS_MOUNT_NORDIRPLUS;
+			break;
+		case Opt_nordirplus:
+			mnt->flags |= NFS_MOUNT_NORDIRPLUS;
+			break;
+		case Opt_sharecache:
+			mnt->flags &= ~NFS_MOUNT_UNSHARED;
+			break;
+		case Opt_nosharecache:
+			mnt->flags |= NFS_MOUNT_UNSHARED;
+			break;
+		case Opt_resvport:
+			mnt->flags &= ~NFS_MOUNT_NORESVPORT;
+			break;
+		case Opt_noresvport:
+			mnt->flags |= NFS_MOUNT_NORESVPORT;
+			break;
+		case Opt_fscache:
+			mnt->options |= NFS_OPTION_FSCACHE;
+			kfree(mnt->fscache_uniq);
+			mnt->fscache_uniq = NULL;
+			break;
+		case Opt_nofscache:
+			mnt->options &= ~NFS_OPTION_FSCACHE;
+			kfree(mnt->fscache_uniq);
+			mnt->fscache_uniq = NULL;
+			break;
+		case Opt_migration:
+			mnt->options |= NFS_OPTION_MIGRATION;
+			break;
+		case Opt_nomigration:
+			mnt->options &= NFS_OPTION_MIGRATION;
+			break;
+
+		/*
+		 * options that take numeric values
+		 */
+		case Opt_port:
+			if (nfs_get_option_ul(args, &option) ||
+			    option > USHRT_MAX)
+				goto out_invalid_value;
+			mnt->nfs_server.port = option;
+			break;
+		case Opt_rsize:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			mnt->rsize = option;
+			break;
+		case Opt_wsize:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			mnt->wsize = option;
+			break;
+		case Opt_bsize:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			mnt->bsize = option;
+			break;
+		case Opt_timeo:
+			if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
+				goto out_invalid_value;
+			mnt->timeo = option;
+			break;
+		case Opt_retrans:
+			if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
+				goto out_invalid_value;
+			mnt->retrans = option;
+			break;
+		case Opt_acregmin:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			mnt->acregmin = option;
+			break;
+		case Opt_acregmax:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			mnt->acregmax = option;
+			break;
+		case Opt_acdirmin:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			mnt->acdirmin = option;
+			break;
+		case Opt_acdirmax:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			mnt->acdirmax = option;
+			break;
+		case Opt_actimeo:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			mnt->acregmin = mnt->acregmax =
+			mnt->acdirmin = mnt->acdirmax = option;
+			break;
+		case Opt_namelen:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			mnt->namlen = option;
+			break;
+		case Opt_mountport:
+			if (nfs_get_option_ul(args, &option) ||
+			    option > USHRT_MAX)
+				goto out_invalid_value;
+			mnt->mount_server.port = option;
+			break;
+		case Opt_mountvers:
+			if (nfs_get_option_ul(args, &option) ||
+			    option < NFS_MNT_VERSION ||
+			    option > NFS_MNT3_VERSION)
+				goto out_invalid_value;
+			mnt->mount_server.version = option;
+			break;
+		case Opt_minorversion:
+			if (nfs_get_option_ul(args, &option))
+				goto out_invalid_value;
+			if (option > NFS4_MAX_MINOR_VERSION)
+				goto out_invalid_value;
+			mnt->minorversion = option;
+			break;
+
+		/*
+		 * options that take text values
+		 */
+		case Opt_nfsvers:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+			rc = nfs_parse_version_string(string, mnt, args);
+			kfree(string);
+			if (!rc)
+				goto out_invalid_value;
+			break;
+		case Opt_sec:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+			rc = nfs_parse_security_flavors(string, mnt);
+			kfree(string);
+			if (!rc) {
+				dfprintk(MOUNT, "NFS:   unrecognized "
+						"security flavor\n");
+				return 0;
+			}
+			break;
+		case Opt_proto:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+			token = match_token(string,
+					    nfs_xprt_protocol_tokens, args);
+
+			protofamily = AF_INET;
+			switch (token) {
+			case Opt_xprt_udp6:
+				protofamily = AF_INET6;
+			case Opt_xprt_udp:
+				mnt->flags &= ~NFS_MOUNT_TCP;
+				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+				break;
+			case Opt_xprt_tcp6:
+				protofamily = AF_INET6;
+			case Opt_xprt_tcp:
+				mnt->flags |= NFS_MOUNT_TCP;
+				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+				break;
+			case Opt_xprt_rdma6:
+				protofamily = AF_INET6;
+			case Opt_xprt_rdma:
+				/* vector side protocols to TCP */
+				mnt->flags |= NFS_MOUNT_TCP;
+				mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+				xprt_load_transport(string);
+				break;
+			default:
+				dfprintk(MOUNT, "NFS:   unrecognized "
+						"transport protocol\n");
+				kfree(string);
+				return 0;
+			}
+			kfree(string);
+			break;
+		case Opt_mountproto:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+			token = match_token(string,
+					    nfs_xprt_protocol_tokens, args);
+			kfree(string);
+
+			mountfamily = AF_INET;
+			switch (token) {
+			case Opt_xprt_udp6:
+				mountfamily = AF_INET6;
+			case Opt_xprt_udp:
+				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+				break;
+			case Opt_xprt_tcp6:
+				mountfamily = AF_INET6;
+			case Opt_xprt_tcp:
+				mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
+				break;
+			case Opt_xprt_rdma: /* not used for side protocols */
+			default:
+				dfprintk(MOUNT, "NFS:   unrecognized "
+						"transport protocol\n");
+				return 0;
+			}
+			break;
+		case Opt_addr:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+			mnt->nfs_server.addrlen =
+				rpc_pton(mnt->net, string, strlen(string),
+					(struct sockaddr *)
+					&mnt->nfs_server.address,
+					sizeof(mnt->nfs_server.address));
+			kfree(string);
+			if (mnt->nfs_server.addrlen == 0)
+				goto out_invalid_address;
+			break;
+		case Opt_clientaddr:
+			if (nfs_get_option_str(args, &mnt->client_address))
+				goto out_nomem;
+			break;
+		case Opt_mounthost:
+			if (nfs_get_option_str(args,
+					       &mnt->mount_server.hostname))
+				goto out_nomem;
+			break;
+		case Opt_mountaddr:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+			mnt->mount_server.addrlen =
+				rpc_pton(mnt->net, string, strlen(string),
+					(struct sockaddr *)
+					&mnt->mount_server.address,
+					sizeof(mnt->mount_server.address));
+			kfree(string);
+			if (mnt->mount_server.addrlen == 0)
+				goto out_invalid_address;
+			break;
+		case Opt_lookupcache:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+			token = match_token(string,
+					nfs_lookupcache_tokens, args);
+			kfree(string);
+			switch (token) {
+				case Opt_lookupcache_all:
+					mnt->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
+					break;
+				case Opt_lookupcache_positive:
+					mnt->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
+					mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
+					break;
+				case Opt_lookupcache_none:
+					mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
+					break;
+				default:
+					dfprintk(MOUNT, "NFS:   invalid "
+							"lookupcache argument\n");
+					return 0;
+			};
+			break;
+		case Opt_fscache_uniq:
+			if (nfs_get_option_str(args, &mnt->fscache_uniq))
+				goto out_nomem;
+			mnt->options |= NFS_OPTION_FSCACHE;
+			break;
+		case Opt_local_lock:
+			string = match_strdup(args);
+			if (string == NULL)
+				goto out_nomem;
+			token = match_token(string, nfs_local_lock_tokens,
+					args);
+			kfree(string);
+			switch (token) {
+			case Opt_local_lock_all:
+				mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+					       NFS_MOUNT_LOCAL_FCNTL);
+				break;
+			case Opt_local_lock_flock:
+				mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
+				break;
+			case Opt_local_lock_posix:
+				mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
+				break;
+			case Opt_local_lock_none:
+				mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+						NFS_MOUNT_LOCAL_FCNTL);
+				break;
+			default:
+				dfprintk(MOUNT, "NFS:	invalid	"
+						"local_lock argument\n");
+				return 0;
+			};
+			break;
+
+		/*
+		 * Special options
+		 */
+		case Opt_sloppy:
+			sloppy = 1;
+			dfprintk(MOUNT, "NFS:   relaxing parsing rules\n");
+			break;
+		case Opt_userspace:
+		case Opt_deprecated:
+			dfprintk(MOUNT, "NFS:   ignoring mount option "
+					"'%s'\n", p);
+			break;
+
+		default:
+			invalid_option = 1;
+			dfprintk(MOUNT, "NFS:   unrecognized mount option "
+					"'%s'\n", p);
+		}
+	}
+
+	if (!sloppy && invalid_option)
+		return 0;
+
+	if (mnt->minorversion && mnt->version != 4)
+		goto out_minorversion_mismatch;
+
+	if (mnt->options & NFS_OPTION_MIGRATION &&
+	    (mnt->version != 4 || mnt->minorversion != 0))
+		goto out_migration_misuse;
+
+	/*
+	 * verify that any proto=/mountproto= options match the address
+	 * families in the addr=/mountaddr= options.
+	 */
+	if (protofamily != AF_UNSPEC &&
+	    protofamily != mnt->nfs_server.address.ss_family)
+		goto out_proto_mismatch;
+
+	if (mountfamily != AF_UNSPEC) {
+		if (mnt->mount_server.addrlen) {
+			if (mountfamily != mnt->mount_server.address.ss_family)
+				goto out_mountproto_mismatch;
+		} else {
+			if (mountfamily != mnt->nfs_server.address.ss_family)
+				goto out_mountproto_mismatch;
+		}
+	}
+
+	return 1;
+
+out_mountproto_mismatch:
+	printk(KERN_INFO "NFS: mount server address does not match mountproto= "
+			 "option\n");
+	return 0;
+out_proto_mismatch:
+	printk(KERN_INFO "NFS: server address does not match proto= option\n");
+	return 0;
+out_invalid_address:
+	printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
+	return 0;
+out_invalid_value:
+	printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
+	return 0;
+out_minorversion_mismatch:
+	printk(KERN_INFO "NFS: mount option vers=%u does not support "
+			 "minorversion=%u\n", mnt->version, mnt->minorversion);
+	return 0;
+out_migration_misuse:
+	printk(KERN_INFO
+		"NFS: 'migration' not supported for this NFS version\n");
+	return 0;
+out_nomem:
+	printk(KERN_INFO "NFS: not enough memory to parse option\n");
+	return 0;
+out_security_failure:
+	free_secdata(secdata);
+	printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
+	return 0;
+}
+
+/*
+ * Split "dev_name" into "hostname:export_path".
+ *
+ * The leftmost colon demarks the split between the server's hostname
+ * and the export path.  If the hostname starts with a left square
+ * bracket, then it may contain colons.
+ *
+ * Note: caller frees hostname and export path, even on error.
+ */
+static int nfs_parse_devname(const char *dev_name,
+			     char **hostname, size_t maxnamlen,
+			     char **export_path, size_t maxpathlen)
+{
+	size_t len;
+	char *end;
+
+	/* Is the host name protected with square brakcets? */
+	if (*dev_name == '[') {
+		end = strchr(++dev_name, ']');
+		if (end == NULL || end[1] != ':')
+			goto out_bad_devname;
+
+		len = end - dev_name;
+		end++;
+	} else {
+		char *comma;
+
+		end = strchr(dev_name, ':');
+		if (end == NULL)
+			goto out_bad_devname;
+		len = end - dev_name;
+
+		/* kill possible hostname list: not supported */
+		comma = strchr(dev_name, ',');
+		if (comma != NULL && comma < end)
+			*comma = 0;
+	}
+
+	if (len > maxnamlen)
+		goto out_hostname;
+
+	/* N.B. caller will free nfs_server.hostname in all cases */
+	*hostname = kstrndup(dev_name, len, GFP_KERNEL);
+	if (*hostname == NULL)
+		goto out_nomem;
+	len = strlen(++end);
+	if (len > maxpathlen)
+		goto out_path;
+	*export_path = kstrndup(end, len, GFP_KERNEL);
+	if (!*export_path)
+		goto out_nomem;
+
+	dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
+	return 0;
+
+out_bad_devname:
+	dfprintk(MOUNT, "NFS: device name not in host:path format\n");
+	return -EINVAL;
+
+out_nomem:
+	dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
+	return -ENOMEM;
+
+out_hostname:
+	dfprintk(MOUNT, "NFS: server hostname too long\n");
+	return -ENAMETOOLONG;
+
+out_path:
+	dfprintk(MOUNT, "NFS: export pathname too long\n");
+	return -ENAMETOOLONG;
+}
+
+/*
+ * Validate the NFS2/NFS3 mount data
+ * - fills in the mount root filehandle
+ *
+ * For option strings, user space handles the following behaviors:
+ *
+ * + DNS: mapping server host name to IP address ("addr=" option)
+ *
+ * + failure mode: how to behave if a mount request can't be handled
+ *   immediately ("fg/bg" option)
+ *
+ * + retry: how often to retry a mount request ("retry=" option)
+ *
+ * + breaking back: trying proto=udp after proto=tcp, v2 after v3,
+ *   mountproto=tcp after mountproto=udp, and so on
+ */
+static int nfs23_validate_mount_data(void *options,
+				     struct nfs_parsed_mount_data *args,
+				     struct nfs_fh *mntfh,
+				     const char *dev_name)
+{
+	struct nfs_mount_data *data = (struct nfs_mount_data *)options;
+	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+	int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
+
+	if (data == NULL)
+		goto out_no_data;
+
+	args->version = NFS_DEFAULT_VERSION;
+	switch (data->version) {
+	case 1:
+		data->namlen = 0;
+	case 2:
+		data->bsize = 0;
+	case 3:
+		if (data->flags & NFS_MOUNT_VER3)
+			goto out_no_v3;
+		data->root.size = NFS2_FHSIZE;
+		memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
+		/* Turn off security negotiation */
+		extra_flags |= NFS_MOUNT_SECFLAVOUR;
+	case 4:
+		if (data->flags & NFS_MOUNT_SECFLAVOUR)
+			goto out_no_sec;
+	case 5:
+		memset(data->context, 0, sizeof(data->context));
+	case 6:
+		if (data->flags & NFS_MOUNT_VER3) {
+			if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
+				goto out_invalid_fh;
+			mntfh->size = data->root.size;
+			args->version = 3;
+		} else {
+			mntfh->size = NFS2_FHSIZE;
+			args->version = 2;
+		}
+
+
+		memcpy(mntfh->data, data->root.data, mntfh->size);
+		if (mntfh->size < sizeof(mntfh->data))
+			memset(mntfh->data + mntfh->size, 0,
+			       sizeof(mntfh->data) - mntfh->size);
+
+		/*
+		 * Translate to nfs_parsed_mount_data, which nfs_fill_super
+		 * can deal with.
+		 */
+		args->flags		= data->flags & NFS_MOUNT_FLAGMASK;
+		args->flags		|= extra_flags;
+		args->rsize		= data->rsize;
+		args->wsize		= data->wsize;
+		args->timeo		= data->timeo;
+		args->retrans		= data->retrans;
+		args->acregmin		= data->acregmin;
+		args->acregmax		= data->acregmax;
+		args->acdirmin		= data->acdirmin;
+		args->acdirmax		= data->acdirmax;
+		args->need_mount	= false;
+
+		memcpy(sap, &data->addr, sizeof(data->addr));
+		args->nfs_server.addrlen = sizeof(data->addr);
+		args->nfs_server.port = ntohs(data->addr.sin_port);
+		if (!nfs_verify_server_address(sap))
+			goto out_no_address;
+
+		if (!(data->flags & NFS_MOUNT_TCP))
+			args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+		/* N.B. caller will free nfs_server.hostname in all cases */
+		args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
+		args->namlen		= data->namlen;
+		args->bsize		= data->bsize;
+
+		if (data->flags & NFS_MOUNT_SECFLAVOUR)
+			args->selected_flavor = data->pseudoflavor;
+		else
+			args->selected_flavor = RPC_AUTH_UNIX;
+		if (!args->nfs_server.hostname)
+			goto out_nomem;
+
+		if (!(data->flags & NFS_MOUNT_NONLM))
+			args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
+					 NFS_MOUNT_LOCAL_FCNTL);
+		else
+			args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
+					NFS_MOUNT_LOCAL_FCNTL);
+		/*
+		 * The legacy version 6 binary mount data from userspace has a
+		 * field used only to transport selinux information into the
+		 * the kernel.  To continue to support that functionality we
+		 * have a touch of selinux knowledge here in the NFS code. The
+		 * userspace code converted context=blah to just blah so we are
+		 * converting back to the full string selinux understands.
+		 */
+		if (data->context[0]){
+#ifdef CONFIG_SECURITY_SELINUX
+			int rc;
+			char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL);
+			if (!opts_str)
+				return -ENOMEM;
+			strcpy(opts_str, "context=");
+			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
+			strcat(opts_str, &data->context[0]);
+			rc = security_sb_parse_opts_str(opts_str, &args->lsm_opts);
+			kfree(opts_str);
+			if (rc)
+				return rc;
+#else
+			return -EINVAL;
+#endif
+		}
+
+		break;
+	default:
+		return NFS_TEXT_DATA;
+	}
+
+	return 0;
+
+out_no_data:
+	dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
+	return -EINVAL;
+
+out_no_v3:
+	dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n",
+		 data->version);
+	return -EINVAL;
+
+out_no_sec:
+	dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n");
+	return -EINVAL;
+
+out_nomem:
+	dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n");
+	return -ENOMEM;
+
+out_no_address:
+	dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
+	return -EINVAL;
+
+out_invalid_fh:
+	dfprintk(MOUNT, "NFS: invalid root filehandle\n");
+	return -EINVAL;
+}
+
+#if IS_ENABLED(CONFIG_NFS_V4)
+
+static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
+{
+	args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
+			 NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
+}
+
+/*
+ * Validate NFSv4 mount options
+ */
+static int nfs4_validate_mount_data(void *options,
+				    struct nfs_parsed_mount_data *args,
+				    const char *dev_name)
+{
+	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+	struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
+	char *c;
+
+	if (data == NULL)
+		goto out_no_data;
+
+	args->version = 4;
+
+	switch (data->version) {
+	case 1:
+		if (data->host_addrlen > sizeof(args->nfs_server.address))
+			goto out_no_address;
+		if (data->host_addrlen == 0)
+			goto out_no_address;
+		args->nfs_server.addrlen = data->host_addrlen;
+		if (copy_from_user(sap, data->host_addr, data->host_addrlen))
+			return -EFAULT;
+		if (!nfs_verify_server_address(sap))
+			goto out_no_address;
+		args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
+
+		if (data->auth_flavourlen) {
+			rpc_authflavor_t pseudoflavor;
+			if (data->auth_flavourlen > 1)
+				goto out_inval_auth;
+			if (copy_from_user(&pseudoflavor,
+					   data->auth_flavours,
+					   sizeof(pseudoflavor)))
+				return -EFAULT;
+			args->selected_flavor = pseudoflavor;
+		} else
+			args->selected_flavor = RPC_AUTH_UNIX;
+
+		c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
+		if (IS_ERR(c))
+			return PTR_ERR(c);
+		args->nfs_server.hostname = c;
+
+		c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
+		if (IS_ERR(c))
+			return PTR_ERR(c);
+		args->nfs_server.export_path = c;
+		dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
+
+		c = strndup_user(data->client_addr.data, 16);
+		if (IS_ERR(c))
+			return PTR_ERR(c);
+		args->client_address = c;
+
+		/*
+		 * Translate to nfs_parsed_mount_data, which nfs4_fill_super
+		 * can deal with.
+		 */
+
+		args->flags	= data->flags & NFS4_MOUNT_FLAGMASK;
+		args->rsize	= data->rsize;
+		args->wsize	= data->wsize;
+		args->timeo	= data->timeo;
+		args->retrans	= data->retrans;
+		args->acregmin	= data->acregmin;
+		args->acregmax	= data->acregmax;
+		args->acdirmin	= data->acdirmin;
+		args->acdirmax	= data->acdirmax;
+		args->nfs_server.protocol = data->proto;
+		nfs_validate_transport_protocol(args);
+		if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+			goto out_invalid_transport_udp;
+
+		break;
+	default:
+		return NFS_TEXT_DATA;
+	}
+
+	return 0;
+
+out_no_data:
+	dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
+	return -EINVAL;
+
+out_inval_auth:
+	dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n",
+		 data->auth_flavourlen);
+	return -EINVAL;
+
+out_no_address:
+	dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
+	return -EINVAL;
+
+out_invalid_transport_udp:
+	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
+	return -EINVAL;
+}
+
+int nfs_validate_mount_data(struct file_system_type *fs_type,
+			    void *options,
+			    struct nfs_parsed_mount_data *args,
+			    struct nfs_fh *mntfh,
+			    const char *dev_name)
+{
+	if (fs_type == &nfs_fs_type)
+		return nfs23_validate_mount_data(options, args, mntfh, dev_name);
+	return nfs4_validate_mount_data(options, args, dev_name);
+}
+#else
+int nfs_validate_mount_data(struct file_system_type *fs_type,
+			    void *options,
+			    struct nfs_parsed_mount_data *args,
+			    struct nfs_fh *mntfh,
+			    const char *dev_name)
+{
+	return nfs23_validate_mount_data(options, args, mntfh, dev_name);
+}
+#endif
+
+int nfs_validate_text_mount_data(void *options,
+				 struct nfs_parsed_mount_data *args,
+				 const char *dev_name)
+{
+	int port = 0;
+	int max_namelen = PAGE_SIZE;
+	int max_pathlen = NFS_MAXPATHLEN;
+	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+
+	if (nfs_parse_mount_options((char *)options, args) == 0)
+		return -EINVAL;
+
+	if (!nfs_verify_server_address(sap))
+		goto out_no_address;
+
+	if (args->version == 4) {
+#if IS_ENABLED(CONFIG_NFS_V4)
+		port = NFS_PORT;
+		max_namelen = NFS4_MAXNAMLEN;
+		max_pathlen = NFS4_MAXPATHLEN;
+		nfs_validate_transport_protocol(args);
+		if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+			goto out_invalid_transport_udp;
+		nfs4_validate_mount_flags(args);
+#else
+		goto out_v4_not_compiled;
+#endif /* CONFIG_NFS_V4 */
+	} else
+		nfs_set_mount_transport_protocol(args);
+
+	nfs_set_port(sap, &args->nfs_server.port, port);
+
+	return nfs_parse_devname(dev_name,
+				   &args->nfs_server.hostname,
+				   max_namelen,
+				   &args->nfs_server.export_path,
+				   max_pathlen);
+
+#if !IS_ENABLED(CONFIG_NFS_V4)
+out_v4_not_compiled:
+	dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
+	return -EPROTONOSUPPORT;
+#else
+out_invalid_transport_udp:
+	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
+	return -EINVAL;
+#endif /* !CONFIG_NFS_V4 */
+
+out_no_address:
+	dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
+	return -EINVAL;
+}
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index ac9d59c6b181..cc9753366b88 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -6,6 +6,7 @@
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/crc32.h>
+#include <linux/sunrpc/addr.h>
 #include <linux/nfs_page.h>
 
 #define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
@@ -229,6 +230,22 @@ extern struct svc_version nfs4_callback_version1;
 extern struct svc_version nfs4_callback_version4;
 
 struct nfs_pageio_descriptor;
+
+/* mount.c */
+#define NFS_TEXT_DATA		1
+
+extern struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void);
+extern void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data);
+extern int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt);
+extern int nfs_validate_mount_data(struct file_system_type *fs_type,
+				   void *options,
+				   struct nfs_parsed_mount_data *args,
+				   struct nfs_fh *mntfh,
+				   const char *dev_name);
+extern int nfs_validate_text_mount_data(void *options,
+					struct nfs_parsed_mount_data *args,
+					const char *dev_name);
+
 /* pagelist.c */
 extern int __init nfs_init_nfspagecache(void);
 extern void nfs_destroy_nfspagecache(void);
@@ -766,3 +783,16 @@ static inline bool nfs_error_is_fatal(int err)
 		return false;
 	}
 }
+
+/*
+ * Select between a default port value and a user-specified port value.
+ * If a zero value is set, then autobind will be used.
+ */
+static inline void nfs_set_port(struct sockaddr *sap, int *port,
+				const unsigned short default_port)
+{
+	if (*port == NFS_UNSPEC_PORT)
+		*port = default_port;
+
+	rpc_set_port(sap, *port);
+}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index b3095e87dd8c..e2d1e1baf3e8 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -68,223 +68,6 @@
 #include "nfs.h"
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
-#define NFS_TEXT_DATA		1
-
-#if IS_ENABLED(CONFIG_NFS_V3)
-#define NFS_DEFAULT_VERSION 3
-#else
-#define NFS_DEFAULT_VERSION 2
-#endif
-
-enum {
-	/* Mount options that take no arguments */
-	Opt_soft, Opt_hard,
-	Opt_posix, Opt_noposix,
-	Opt_cto, Opt_nocto,
-	Opt_ac, Opt_noac,
-	Opt_lock, Opt_nolock,
-	Opt_udp, Opt_tcp, Opt_rdma,
-	Opt_acl, Opt_noacl,
-	Opt_rdirplus, Opt_nordirplus,
-	Opt_sharecache, Opt_nosharecache,
-	Opt_resvport, Opt_noresvport,
-	Opt_fscache, Opt_nofscache,
-	Opt_migration, Opt_nomigration,
-
-	/* Mount options that take integer arguments */
-	Opt_port,
-	Opt_rsize, Opt_wsize, Opt_bsize,
-	Opt_timeo, Opt_retrans,
-	Opt_acregmin, Opt_acregmax,
-	Opt_acdirmin, Opt_acdirmax,
-	Opt_actimeo,
-	Opt_namelen,
-	Opt_mountport,
-	Opt_mountvers,
-	Opt_minorversion,
-
-	/* Mount options that take string arguments */
-	Opt_nfsvers,
-	Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
-	Opt_addr, Opt_mountaddr, Opt_clientaddr,
-	Opt_lookupcache,
-	Opt_fscache_uniq,
-	Opt_local_lock,
-
-	/* Special mount options */
-	Opt_userspace, Opt_deprecated, Opt_sloppy,
-
-	Opt_err
-};
-
-static const match_table_t nfs_mount_option_tokens = {
-	{ Opt_userspace, "bg" },
-	{ Opt_userspace, "fg" },
-	{ Opt_userspace, "retry=%s" },
-
-	{ Opt_sloppy, "sloppy" },
-
-	{ Opt_soft, "soft" },
-	{ Opt_hard, "hard" },
-	{ Opt_deprecated, "intr" },
-	{ Opt_deprecated, "nointr" },
-	{ Opt_posix, "posix" },
-	{ Opt_noposix, "noposix" },
-	{ Opt_cto, "cto" },
-	{ Opt_nocto, "nocto" },
-	{ Opt_ac, "ac" },
-	{ Opt_noac, "noac" },
-	{ Opt_lock, "lock" },
-	{ Opt_nolock, "nolock" },
-	{ Opt_udp, "udp" },
-	{ Opt_tcp, "tcp" },
-	{ Opt_rdma, "rdma" },
-	{ Opt_acl, "acl" },
-	{ Opt_noacl, "noacl" },
-	{ Opt_rdirplus, "rdirplus" },
-	{ Opt_nordirplus, "nordirplus" },
-	{ Opt_sharecache, "sharecache" },
-	{ Opt_nosharecache, "nosharecache" },
-	{ Opt_resvport, "resvport" },
-	{ Opt_noresvport, "noresvport" },
-	{ Opt_fscache, "fsc" },
-	{ Opt_nofscache, "nofsc" },
-	{ Opt_migration, "migration" },
-	{ Opt_nomigration, "nomigration" },
-
-	{ Opt_port, "port=%s" },
-	{ Opt_rsize, "rsize=%s" },
-	{ Opt_wsize, "wsize=%s" },
-	{ Opt_bsize, "bsize=%s" },
-	{ Opt_timeo, "timeo=%s" },
-	{ Opt_retrans, "retrans=%s" },
-	{ Opt_acregmin, "acregmin=%s" },
-	{ Opt_acregmax, "acregmax=%s" },
-	{ Opt_acdirmin, "acdirmin=%s" },
-	{ Opt_acdirmax, "acdirmax=%s" },
-	{ Opt_actimeo, "actimeo=%s" },
-	{ Opt_namelen, "namlen=%s" },
-	{ Opt_mountport, "mountport=%s" },
-	{ Opt_mountvers, "mountvers=%s" },
-	{ Opt_minorversion, "minorversion=%s" },
-
-	{ Opt_nfsvers, "nfsvers=%s" },
-	{ Opt_nfsvers, "vers=%s" },
-
-	{ Opt_sec, "sec=%s" },
-	{ Opt_proto, "proto=%s" },
-	{ Opt_mountproto, "mountproto=%s" },
-	{ Opt_addr, "addr=%s" },
-	{ Opt_clientaddr, "clientaddr=%s" },
-	{ Opt_mounthost, "mounthost=%s" },
-	{ Opt_mountaddr, "mountaddr=%s" },
-
-	{ Opt_lookupcache, "lookupcache=%s" },
-	{ Opt_fscache_uniq, "fsc=%s" },
-	{ Opt_local_lock, "local_lock=%s" },
-
-	/* The following needs to be listed after all other options */
-	{ Opt_nfsvers, "v%s" },
-
-	{ Opt_err, NULL }
-};
-
-enum {
-	Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma,
-	Opt_xprt_rdma6,
-
-	Opt_xprt_err
-};
-
-static const match_table_t nfs_xprt_protocol_tokens = {
-	{ Opt_xprt_udp, "udp" },
-	{ Opt_xprt_udp6, "udp6" },
-	{ Opt_xprt_tcp, "tcp" },
-	{ Opt_xprt_tcp6, "tcp6" },
-	{ Opt_xprt_rdma, "rdma" },
-	{ Opt_xprt_rdma6, "rdma6" },
-
-	{ Opt_xprt_err, NULL }
-};
-
-enum {
-	Opt_sec_none, Opt_sec_sys,
-	Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p,
-	Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp,
-	Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp,
-
-	Opt_sec_err
-};
-
-static const match_table_t nfs_secflavor_tokens = {
-	{ Opt_sec_none, "none" },
-	{ Opt_sec_none, "null" },
-	{ Opt_sec_sys, "sys" },
-
-	{ Opt_sec_krb5, "krb5" },
-	{ Opt_sec_krb5i, "krb5i" },
-	{ Opt_sec_krb5p, "krb5p" },
-
-	{ Opt_sec_lkey, "lkey" },
-	{ Opt_sec_lkeyi, "lkeyi" },
-	{ Opt_sec_lkeyp, "lkeyp" },
-
-	{ Opt_sec_spkm, "spkm3" },
-	{ Opt_sec_spkmi, "spkm3i" },
-	{ Opt_sec_spkmp, "spkm3p" },
-
-	{ Opt_sec_err, NULL }
-};
-
-enum {
-	Opt_lookupcache_all, Opt_lookupcache_positive,
-	Opt_lookupcache_none,
-
-	Opt_lookupcache_err
-};
-
-static match_table_t nfs_lookupcache_tokens = {
-	{ Opt_lookupcache_all, "all" },
-	{ Opt_lookupcache_positive, "pos" },
-	{ Opt_lookupcache_positive, "positive" },
-	{ Opt_lookupcache_none, "none" },
-
-	{ Opt_lookupcache_err, NULL }
-};
-
-enum {
-	Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
-	Opt_local_lock_none,
-
-	Opt_local_lock_err
-};
-
-static match_table_t nfs_local_lock_tokens = {
-	{ Opt_local_lock_all, "all" },
-	{ Opt_local_lock_flock, "flock" },
-	{ Opt_local_lock_posix, "posix" },
-	{ Opt_local_lock_none, "none" },
-
-	{ Opt_local_lock_err, NULL }
-};
-
-enum {
-	Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
-	Opt_vers_4_1, Opt_vers_4_2,
-
-	Opt_vers_err
-};
-
-static match_table_t nfs_vers_tokens = {
-	{ Opt_vers_2, "2" },
-	{ Opt_vers_3, "3" },
-	{ Opt_vers_4, "4" },
-	{ Opt_vers_4_0, "4.0" },
-	{ Opt_vers_4_1, "4.1" },
-	{ Opt_vers_4_2, "4.2" },
-
-	{ Opt_vers_err, NULL }
-};
 
 static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type,
 		int flags, const char *dev_name, void *raw_data);
@@ -324,10 +107,6 @@ const struct super_operations nfs_sops = {
 EXPORT_SYMBOL_GPL(nfs_sops);
 
 #if IS_ENABLED(CONFIG_NFS_V4)
-static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *);
-static int nfs4_validate_mount_data(void *options,
-	struct nfs_parsed_mount_data *args, const char *dev_name);
-
 struct file_system_type nfs4_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "nfs4",
@@ -910,141 +689,6 @@ void nfs_umount_begin(struct super_block *sb)
 }
 EXPORT_SYMBOL_GPL(nfs_umount_begin);
 
-static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
-{
-	struct nfs_parsed_mount_data *data;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (data) {
-		data->timeo		= NFS_UNSPEC_TIMEO;
-		data->retrans		= NFS_UNSPEC_RETRANS;
-		data->acregmin		= NFS_DEF_ACREGMIN;
-		data->acregmax		= NFS_DEF_ACREGMAX;
-		data->acdirmin		= NFS_DEF_ACDIRMIN;
-		data->acdirmax		= NFS_DEF_ACDIRMAX;
-		data->mount_server.port	= NFS_UNSPEC_PORT;
-		data->nfs_server.port	= NFS_UNSPEC_PORT;
-		data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-		data->selected_flavor	= RPC_AUTH_MAXFLAVOR;
-		data->minorversion	= 0;
-		data->need_mount	= true;
-		data->net		= current->nsproxy->net_ns;
-		security_init_mnt_opts(&data->lsm_opts);
-	}
-	return data;
-}
-
-static void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
-{
-	if (data) {
-		kfree(data->client_address);
-		kfree(data->mount_server.hostname);
-		kfree(data->nfs_server.export_path);
-		kfree(data->nfs_server.hostname);
-		kfree(data->fscache_uniq);
-		security_free_mnt_opts(&data->lsm_opts);
-		kfree(data);
-	}
-}
-
-/*
- * Sanity-check a server address provided by the mount command.
- *
- * Address family must be initialized, and address must not be
- * the ANY address for that family.
- */
-static int nfs_verify_server_address(struct sockaddr *addr)
-{
-	switch (addr->sa_family) {
-	case AF_INET: {
-		struct sockaddr_in *sa = (struct sockaddr_in *)addr;
-		return sa->sin_addr.s_addr != htonl(INADDR_ANY);
-	}
-	case AF_INET6: {
-		struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr;
-		return !ipv6_addr_any(sa);
-	}
-	}
-
-	dfprintk(MOUNT, "NFS: Invalid IP address specified\n");
-	return 0;
-}
-
-/*
- * Select between a default port value and a user-specified port value.
- * If a zero value is set, then autobind will be used.
- */
-static void nfs_set_port(struct sockaddr *sap, int *port,
-				 const unsigned short default_port)
-{
-	if (*port == NFS_UNSPEC_PORT)
-		*port = default_port;
-
-	rpc_set_port(sap, *port);
-}
-
-/*
- * Sanity check the NFS transport protocol.
- *
- */
-static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
-{
-	switch (mnt->nfs_server.protocol) {
-	case XPRT_TRANSPORT_UDP:
-	case XPRT_TRANSPORT_TCP:
-	case XPRT_TRANSPORT_RDMA:
-		break;
-	default:
-		mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-	}
-}
-
-/*
- * For text based NFSv2/v3 mounts, the mount protocol transport default
- * settings should depend upon the specified NFS transport.
- */
-static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
-{
-	nfs_validate_transport_protocol(mnt);
-
-	if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP ||
-	    mnt->mount_server.protocol == XPRT_TRANSPORT_TCP)
-			return;
-	switch (mnt->nfs_server.protocol) {
-	case XPRT_TRANSPORT_UDP:
-		mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
-		break;
-	case XPRT_TRANSPORT_TCP:
-	case XPRT_TRANSPORT_RDMA:
-		mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
-	}
-}
-
-/*
- * Add 'flavor' to 'auth_info' if not already present.
- * Returns true if 'flavor' ends up in the list, false otherwise
- */
-static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
-			      rpc_authflavor_t flavor)
-{
-	unsigned int i;
-	unsigned int max_flavor_len = ARRAY_SIZE(auth_info->flavors);
-
-	/* make sure this flavor isn't already in the list */
-	for (i = 0; i < auth_info->flavor_len; i++) {
-		if (flavor == auth_info->flavors[i])
-			return true;
-	}
-
-	if (auth_info->flavor_len + 1 >= max_flavor_len) {
-		dfprintk(MOUNT, "NFS: too many sec= flavors\n");
-		return false;
-	}
-
-	auth_info->flavors[auth_info->flavor_len++] = flavor;
-	return true;
-}
-
 /*
  * Return true if 'match' is in auth_info or auth_info is empty.
  * Return false otherwise.
@@ -1066,623 +710,6 @@ bool nfs_auth_info_match(const struct nfs_auth_info *auth_info,
 EXPORT_SYMBOL_GPL(nfs_auth_info_match);
 
 /*
- * Parse the value of the 'sec=' option.
- */
-static int nfs_parse_security_flavors(char *value,
-				      struct nfs_parsed_mount_data *mnt)
-{
-	substring_t args[MAX_OPT_ARGS];
-	rpc_authflavor_t pseudoflavor;
-	char *p;
-
-	dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
-
-	while ((p = strsep(&value, ":")) != NULL) {
-		switch (match_token(p, nfs_secflavor_tokens, args)) {
-		case Opt_sec_none:
-			pseudoflavor = RPC_AUTH_NULL;
-			break;
-		case Opt_sec_sys:
-			pseudoflavor = RPC_AUTH_UNIX;
-			break;
-		case Opt_sec_krb5:
-			pseudoflavor = RPC_AUTH_GSS_KRB5;
-			break;
-		case Opt_sec_krb5i:
-			pseudoflavor = RPC_AUTH_GSS_KRB5I;
-			break;
-		case Opt_sec_krb5p:
-			pseudoflavor = RPC_AUTH_GSS_KRB5P;
-			break;
-		case Opt_sec_lkey:
-			pseudoflavor = RPC_AUTH_GSS_LKEY;
-			break;
-		case Opt_sec_lkeyi:
-			pseudoflavor = RPC_AUTH_GSS_LKEYI;
-			break;
-		case Opt_sec_lkeyp:
-			pseudoflavor = RPC_AUTH_GSS_LKEYP;
-			break;
-		case Opt_sec_spkm:
-			pseudoflavor = RPC_AUTH_GSS_SPKM;
-			break;
-		case Opt_sec_spkmi:
-			pseudoflavor = RPC_AUTH_GSS_SPKMI;
-			break;
-		case Opt_sec_spkmp:
-			pseudoflavor = RPC_AUTH_GSS_SPKMP;
-			break;
-		default:
-			dfprintk(MOUNT,
-				 "NFS: sec= option '%s' not recognized\n", p);
-			return 0;
-		}
-
-		if (!nfs_auth_info_add(&mnt->auth_info, pseudoflavor))
-			return 0;
-	}
-
-	return 1;
-}
-
-static int nfs_parse_version_string(char *string,
-		struct nfs_parsed_mount_data *mnt,
-		substring_t *args)
-{
-	mnt->flags &= ~NFS_MOUNT_VER3;
-	switch (match_token(string, nfs_vers_tokens, args)) {
-	case Opt_vers_2:
-		mnt->version = 2;
-		break;
-	case Opt_vers_3:
-		mnt->flags |= NFS_MOUNT_VER3;
-		mnt->version = 3;
-		break;
-	case Opt_vers_4:
-		/* Backward compatibility option. In future,
-		 * the mount program should always supply
-		 * a NFSv4 minor version number.
-		 */
-		mnt->version = 4;
-		break;
-	case Opt_vers_4_0:
-		mnt->version = 4;
-		mnt->minorversion = 0;
-		break;
-	case Opt_vers_4_1:
-		mnt->version = 4;
-		mnt->minorversion = 1;
-		break;
-	case Opt_vers_4_2:
-		mnt->version = 4;
-		mnt->minorversion = 2;
-		break;
-	default:
-		return 0;
-	}
-	return 1;
-}
-
-static int nfs_get_option_str(substring_t args[], char **option)
-{
-	kfree(*option);
-	*option = match_strdup(args);
-	return !*option;
-}
-
-static int nfs_get_option_ul(substring_t args[], unsigned long *option)
-{
-	int rc;
-	char *string;
-
-	string = match_strdup(args);
-	if (string == NULL)
-		return -ENOMEM;
-	rc = kstrtoul(string, 10, option);
-	kfree(string);
-
-	return rc;
-}
-
-static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
-		unsigned long l_bound, unsigned long u_bound)
-{
-	int ret;
-
-	ret = nfs_get_option_ul(args, option);
-	if (ret != 0)
-		return ret;
-	if (*option < l_bound || *option > u_bound)
-		return -ERANGE;
-	return 0;
-}
-
-/*
- * Error-check and convert a string of mount options from user space into
- * a data structure.  The whole mount string is processed; bad options are
- * skipped as they are encountered.  If there were no errors, return 1;
- * otherwise return 0 (zero).
- */
-static int nfs_parse_mount_options(char *raw,
-				   struct nfs_parsed_mount_data *mnt)
-{
-	char *p, *string, *secdata;
-	int rc, sloppy = 0, invalid_option = 0;
-	unsigned short protofamily = AF_UNSPEC;
-	unsigned short mountfamily = AF_UNSPEC;
-
-	if (!raw) {
-		dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
-		return 1;
-	}
-	dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
-
-	secdata = alloc_secdata();
-	if (!secdata)
-		goto out_nomem;
-
-	rc = security_sb_copy_data(raw, secdata);
-	if (rc)
-		goto out_security_failure;
-
-	rc = security_sb_parse_opts_str(secdata, &mnt->lsm_opts);
-	if (rc)
-		goto out_security_failure;
-
-	free_secdata(secdata);
-
-	while ((p = strsep(&raw, ",")) != NULL) {
-		substring_t args[MAX_OPT_ARGS];
-		unsigned long option;
-		int token;
-
-		if (!*p)
-			continue;
-
-		dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
-
-		token = match_token(p, nfs_mount_option_tokens, args);
-		switch (token) {
-
-		/*
-		 * boolean options:  foo/nofoo
-		 */
-		case Opt_soft:
-			mnt->flags |= NFS_MOUNT_SOFT;
-			break;
-		case Opt_hard:
-			mnt->flags &= ~NFS_MOUNT_SOFT;
-			break;
-		case Opt_posix:
-			mnt->flags |= NFS_MOUNT_POSIX;
-			break;
-		case Opt_noposix:
-			mnt->flags &= ~NFS_MOUNT_POSIX;
-			break;
-		case Opt_cto:
-			mnt->flags &= ~NFS_MOUNT_NOCTO;
-			break;
-		case Opt_nocto:
-			mnt->flags |= NFS_MOUNT_NOCTO;
-			break;
-		case Opt_ac:
-			mnt->flags &= ~NFS_MOUNT_NOAC;
-			break;
-		case Opt_noac:
-			mnt->flags |= NFS_MOUNT_NOAC;
-			break;
-		case Opt_lock:
-			mnt->flags &= ~NFS_MOUNT_NONLM;
-			mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
-					NFS_MOUNT_LOCAL_FCNTL);
-			break;
-		case Opt_nolock:
-			mnt->flags |= NFS_MOUNT_NONLM;
-			mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
-				       NFS_MOUNT_LOCAL_FCNTL);
-			break;
-		case Opt_udp:
-			mnt->flags &= ~NFS_MOUNT_TCP;
-			mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
-			break;
-		case Opt_tcp:
-			mnt->flags |= NFS_MOUNT_TCP;
-			mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-			break;
-		case Opt_rdma:
-			mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
-			mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
-			xprt_load_transport(p);
-			break;
-		case Opt_acl:
-			mnt->flags &= ~NFS_MOUNT_NOACL;
-			break;
-		case Opt_noacl:
-			mnt->flags |= NFS_MOUNT_NOACL;
-			break;
-		case Opt_rdirplus:
-			mnt->flags &= ~NFS_MOUNT_NORDIRPLUS;
-			break;
-		case Opt_nordirplus:
-			mnt->flags |= NFS_MOUNT_NORDIRPLUS;
-			break;
-		case Opt_sharecache:
-			mnt->flags &= ~NFS_MOUNT_UNSHARED;
-			break;
-		case Opt_nosharecache:
-			mnt->flags |= NFS_MOUNT_UNSHARED;
-			break;
-		case Opt_resvport:
-			mnt->flags &= ~NFS_MOUNT_NORESVPORT;
-			break;
-		case Opt_noresvport:
-			mnt->flags |= NFS_MOUNT_NORESVPORT;
-			break;
-		case Opt_fscache:
-			mnt->options |= NFS_OPTION_FSCACHE;
-			kfree(mnt->fscache_uniq);
-			mnt->fscache_uniq = NULL;
-			break;
-		case Opt_nofscache:
-			mnt->options &= ~NFS_OPTION_FSCACHE;
-			kfree(mnt->fscache_uniq);
-			mnt->fscache_uniq = NULL;
-			break;
-		case Opt_migration:
-			mnt->options |= NFS_OPTION_MIGRATION;
-			break;
-		case Opt_nomigration:
-			mnt->options &= NFS_OPTION_MIGRATION;
-			break;
-
-		/*
-		 * options that take numeric values
-		 */
-		case Opt_port:
-			if (nfs_get_option_ul(args, &option) ||
-			    option > USHRT_MAX)
-				goto out_invalid_value;
-			mnt->nfs_server.port = option;
-			break;
-		case Opt_rsize:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			mnt->rsize = option;
-			break;
-		case Opt_wsize:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			mnt->wsize = option;
-			break;
-		case Opt_bsize:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			mnt->bsize = option;
-			break;
-		case Opt_timeo:
-			if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
-				goto out_invalid_value;
-			mnt->timeo = option;
-			break;
-		case Opt_retrans:
-			if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
-				goto out_invalid_value;
-			mnt->retrans = option;
-			break;
-		case Opt_acregmin:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			mnt->acregmin = option;
-			break;
-		case Opt_acregmax:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			mnt->acregmax = option;
-			break;
-		case Opt_acdirmin:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			mnt->acdirmin = option;
-			break;
-		case Opt_acdirmax:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			mnt->acdirmax = option;
-			break;
-		case Opt_actimeo:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			mnt->acregmin = mnt->acregmax =
-			mnt->acdirmin = mnt->acdirmax = option;
-			break;
-		case Opt_namelen:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			mnt->namlen = option;
-			break;
-		case Opt_mountport:
-			if (nfs_get_option_ul(args, &option) ||
-			    option > USHRT_MAX)
-				goto out_invalid_value;
-			mnt->mount_server.port = option;
-			break;
-		case Opt_mountvers:
-			if (nfs_get_option_ul(args, &option) ||
-			    option < NFS_MNT_VERSION ||
-			    option > NFS_MNT3_VERSION)
-				goto out_invalid_value;
-			mnt->mount_server.version = option;
-			break;
-		case Opt_minorversion:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			if (option > NFS4_MAX_MINOR_VERSION)
-				goto out_invalid_value;
-			mnt->minorversion = option;
-			break;
-
-		/*
-		 * options that take text values
-		 */
-		case Opt_nfsvers:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			rc = nfs_parse_version_string(string, mnt, args);
-			kfree(string);
-			if (!rc)
-				goto out_invalid_value;
-			break;
-		case Opt_sec:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			rc = nfs_parse_security_flavors(string, mnt);
-			kfree(string);
-			if (!rc) {
-				dfprintk(MOUNT, "NFS:   unrecognized "
-						"security flavor\n");
-				return 0;
-			}
-			break;
-		case Opt_proto:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			token = match_token(string,
-					    nfs_xprt_protocol_tokens, args);
-
-			protofamily = AF_INET;
-			switch (token) {
-			case Opt_xprt_udp6:
-				protofamily = AF_INET6;
-			case Opt_xprt_udp:
-				mnt->flags &= ~NFS_MOUNT_TCP;
-				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
-				break;
-			case Opt_xprt_tcp6:
-				protofamily = AF_INET6;
-			case Opt_xprt_tcp:
-				mnt->flags |= NFS_MOUNT_TCP;
-				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-				break;
-			case Opt_xprt_rdma6:
-				protofamily = AF_INET6;
-			case Opt_xprt_rdma:
-				/* vector side protocols to TCP */
-				mnt->flags |= NFS_MOUNT_TCP;
-				mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
-				xprt_load_transport(string);
-				break;
-			default:
-				dfprintk(MOUNT, "NFS:   unrecognized "
-						"transport protocol\n");
-				kfree(string);
-				return 0;
-			}
-			kfree(string);
-			break;
-		case Opt_mountproto:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			token = match_token(string,
-					    nfs_xprt_protocol_tokens, args);
-			kfree(string);
-
-			mountfamily = AF_INET;
-			switch (token) {
-			case Opt_xprt_udp6:
-				mountfamily = AF_INET6;
-			case Opt_xprt_udp:
-				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
-				break;
-			case Opt_xprt_tcp6:
-				mountfamily = AF_INET6;
-			case Opt_xprt_tcp:
-				mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
-				break;
-			case Opt_xprt_rdma: /* not used for side protocols */
-			default:
-				dfprintk(MOUNT, "NFS:   unrecognized "
-						"transport protocol\n");
-				return 0;
-			}
-			break;
-		case Opt_addr:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			mnt->nfs_server.addrlen =
-				rpc_pton(mnt->net, string, strlen(string),
-					(struct sockaddr *)
-					&mnt->nfs_server.address,
-					sizeof(mnt->nfs_server.address));
-			kfree(string);
-			if (mnt->nfs_server.addrlen == 0)
-				goto out_invalid_address;
-			break;
-		case Opt_clientaddr:
-			if (nfs_get_option_str(args, &mnt->client_address))
-				goto out_nomem;
-			break;
-		case Opt_mounthost:
-			if (nfs_get_option_str(args,
-					       &mnt->mount_server.hostname))
-				goto out_nomem;
-			break;
-		case Opt_mountaddr:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			mnt->mount_server.addrlen =
-				rpc_pton(mnt->net, string, strlen(string),
-					(struct sockaddr *)
-					&mnt->mount_server.address,
-					sizeof(mnt->mount_server.address));
-			kfree(string);
-			if (mnt->mount_server.addrlen == 0)
-				goto out_invalid_address;
-			break;
-		case Opt_lookupcache:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			token = match_token(string,
-					nfs_lookupcache_tokens, args);
-			kfree(string);
-			switch (token) {
-				case Opt_lookupcache_all:
-					mnt->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
-					break;
-				case Opt_lookupcache_positive:
-					mnt->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
-					mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
-					break;
-				case Opt_lookupcache_none:
-					mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
-					break;
-				default:
-					dfprintk(MOUNT, "NFS:   invalid "
-							"lookupcache argument\n");
-					return 0;
-			};
-			break;
-		case Opt_fscache_uniq:
-			if (nfs_get_option_str(args, &mnt->fscache_uniq))
-				goto out_nomem;
-			mnt->options |= NFS_OPTION_FSCACHE;
-			break;
-		case Opt_local_lock:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			token = match_token(string, nfs_local_lock_tokens,
-					args);
-			kfree(string);
-			switch (token) {
-			case Opt_local_lock_all:
-				mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
-					       NFS_MOUNT_LOCAL_FCNTL);
-				break;
-			case Opt_local_lock_flock:
-				mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
-				break;
-			case Opt_local_lock_posix:
-				mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
-				break;
-			case Opt_local_lock_none:
-				mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
-						NFS_MOUNT_LOCAL_FCNTL);
-				break;
-			default:
-				dfprintk(MOUNT, "NFS:	invalid	"
-						"local_lock argument\n");
-				return 0;
-			};
-			break;
-
-		/*
-		 * Special options
-		 */
-		case Opt_sloppy:
-			sloppy = 1;
-			dfprintk(MOUNT, "NFS:   relaxing parsing rules\n");
-			break;
-		case Opt_userspace:
-		case Opt_deprecated:
-			dfprintk(MOUNT, "NFS:   ignoring mount option "
-					"'%s'\n", p);
-			break;
-
-		default:
-			invalid_option = 1;
-			dfprintk(MOUNT, "NFS:   unrecognized mount option "
-					"'%s'\n", p);
-		}
-	}
-
-	if (!sloppy && invalid_option)
-		return 0;
-
-	if (mnt->minorversion && mnt->version != 4)
-		goto out_minorversion_mismatch;
-
-	if (mnt->options & NFS_OPTION_MIGRATION &&
-	    (mnt->version != 4 || mnt->minorversion != 0))
-		goto out_migration_misuse;
-
-	/*
-	 * verify that any proto=/mountproto= options match the address
-	 * families in the addr=/mountaddr= options.
-	 */
-	if (protofamily != AF_UNSPEC &&
-	    protofamily != mnt->nfs_server.address.ss_family)
-		goto out_proto_mismatch;
-
-	if (mountfamily != AF_UNSPEC) {
-		if (mnt->mount_server.addrlen) {
-			if (mountfamily != mnt->mount_server.address.ss_family)
-				goto out_mountproto_mismatch;
-		} else {
-			if (mountfamily != mnt->nfs_server.address.ss_family)
-				goto out_mountproto_mismatch;
-		}
-	}
-
-	return 1;
-
-out_mountproto_mismatch:
-	printk(KERN_INFO "NFS: mount server address does not match mountproto= "
-			 "option\n");
-	return 0;
-out_proto_mismatch:
-	printk(KERN_INFO "NFS: server address does not match proto= option\n");
-	return 0;
-out_invalid_address:
-	printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
-	return 0;
-out_invalid_value:
-	printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
-	return 0;
-out_minorversion_mismatch:
-	printk(KERN_INFO "NFS: mount option vers=%u does not support "
-			 "minorversion=%u\n", mnt->version, mnt->minorversion);
-	return 0;
-out_migration_misuse:
-	printk(KERN_INFO
-		"NFS: 'migration' not supported for this NFS version\n");
-	return 0;
-out_nomem:
-	printk(KERN_INFO "NFS: not enough memory to parse option\n");
-	return 0;
-out_security_failure:
-	free_secdata(secdata);
-	printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
-	return 0;
-}
-
-/*
  * Ensure that a specified authtype in args->auth_info is supported by
  * the server. Returns 0 and sets args->selected_flavor if it's ok, and
  * -EACCES if not.
@@ -1881,317 +908,6 @@ struct dentry *nfs_try_mount(int flags, const char *dev_name,
 }
 EXPORT_SYMBOL_GPL(nfs_try_mount);
 
-/*
- * Split "dev_name" into "hostname:export_path".
- *
- * The leftmost colon demarks the split between the server's hostname
- * and the export path.  If the hostname starts with a left square
- * bracket, then it may contain colons.
- *
- * Note: caller frees hostname and export path, even on error.
- */
-static int nfs_parse_devname(const char *dev_name,
-			     char **hostname, size_t maxnamlen,
-			     char **export_path, size_t maxpathlen)
-{
-	size_t len;
-	char *end;
-
-	/* Is the host name protected with square brakcets? */
-	if (*dev_name == '[') {
-		end = strchr(++dev_name, ']');
-		if (end == NULL || end[1] != ':')
-			goto out_bad_devname;
-
-		len = end - dev_name;
-		end++;
-	} else {
-		char *comma;
-
-		end = strchr(dev_name, ':');
-		if (end == NULL)
-			goto out_bad_devname;
-		len = end - dev_name;
-
-		/* kill possible hostname list: not supported */
-		comma = strchr(dev_name, ',');
-		if (comma != NULL && comma < end)
-			*comma = 0;
-	}
-
-	if (len > maxnamlen)
-		goto out_hostname;
-
-	/* N.B. caller will free nfs_server.hostname in all cases */
-	*hostname = kstrndup(dev_name, len, GFP_KERNEL);
-	if (*hostname == NULL)
-		goto out_nomem;
-	len = strlen(++end);
-	if (len > maxpathlen)
-		goto out_path;
-	*export_path = kstrndup(end, len, GFP_KERNEL);
-	if (!*export_path)
-		goto out_nomem;
-
-	dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
-	return 0;
-
-out_bad_devname:
-	dfprintk(MOUNT, "NFS: device name not in host:path format\n");
-	return -EINVAL;
-
-out_nomem:
-	dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
-	return -ENOMEM;
-
-out_hostname:
-	dfprintk(MOUNT, "NFS: server hostname too long\n");
-	return -ENAMETOOLONG;
-
-out_path:
-	dfprintk(MOUNT, "NFS: export pathname too long\n");
-	return -ENAMETOOLONG;
-}
-
-/*
- * Validate the NFS2/NFS3 mount data
- * - fills in the mount root filehandle
- *
- * For option strings, user space handles the following behaviors:
- *
- * + DNS: mapping server host name to IP address ("addr=" option)
- *
- * + failure mode: how to behave if a mount request can't be handled
- *   immediately ("fg/bg" option)
- *
- * + retry: how often to retry a mount request ("retry=" option)
- *
- * + breaking back: trying proto=udp after proto=tcp, v2 after v3,
- *   mountproto=tcp after mountproto=udp, and so on
- */
-static int nfs23_validate_mount_data(void *options,
-				     struct nfs_parsed_mount_data *args,
-				     struct nfs_fh *mntfh,
-				     const char *dev_name)
-{
-	struct nfs_mount_data *data = (struct nfs_mount_data *)options;
-	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
-	int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
-
-	if (data == NULL)
-		goto out_no_data;
-
-	args->version = NFS_DEFAULT_VERSION;
-	switch (data->version) {
-	case 1:
-		data->namlen = 0;
-	case 2:
-		data->bsize = 0;
-	case 3:
-		if (data->flags & NFS_MOUNT_VER3)
-			goto out_no_v3;
-		data->root.size = NFS2_FHSIZE;
-		memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
-		/* Turn off security negotiation */
-		extra_flags |= NFS_MOUNT_SECFLAVOUR;
-	case 4:
-		if (data->flags & NFS_MOUNT_SECFLAVOUR)
-			goto out_no_sec;
-	case 5:
-		memset(data->context, 0, sizeof(data->context));
-	case 6:
-		if (data->flags & NFS_MOUNT_VER3) {
-			if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
-				goto out_invalid_fh;
-			mntfh->size = data->root.size;
-			args->version = 3;
-		} else {
-			mntfh->size = NFS2_FHSIZE;
-			args->version = 2;
-		}
-
-
-		memcpy(mntfh->data, data->root.data, mntfh->size);
-		if (mntfh->size < sizeof(mntfh->data))
-			memset(mntfh->data + mntfh->size, 0,
-			       sizeof(mntfh->data) - mntfh->size);
-
-		/*
-		 * Translate to nfs_parsed_mount_data, which nfs_fill_super
-		 * can deal with.
-		 */
-		args->flags		= data->flags & NFS_MOUNT_FLAGMASK;
-		args->flags		|= extra_flags;
-		args->rsize		= data->rsize;
-		args->wsize		= data->wsize;
-		args->timeo		= data->timeo;
-		args->retrans		= data->retrans;
-		args->acregmin		= data->acregmin;
-		args->acregmax		= data->acregmax;
-		args->acdirmin		= data->acdirmin;
-		args->acdirmax		= data->acdirmax;
-		args->need_mount	= false;
-
-		memcpy(sap, &data->addr, sizeof(data->addr));
-		args->nfs_server.addrlen = sizeof(data->addr);
-		args->nfs_server.port = ntohs(data->addr.sin_port);
-		if (!nfs_verify_server_address(sap))
-			goto out_no_address;
-
-		if (!(data->flags & NFS_MOUNT_TCP))
-			args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
-		/* N.B. caller will free nfs_server.hostname in all cases */
-		args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
-		args->namlen		= data->namlen;
-		args->bsize		= data->bsize;
-
-		if (data->flags & NFS_MOUNT_SECFLAVOUR)
-			args->selected_flavor = data->pseudoflavor;
-		else
-			args->selected_flavor = RPC_AUTH_UNIX;
-		if (!args->nfs_server.hostname)
-			goto out_nomem;
-
-		if (!(data->flags & NFS_MOUNT_NONLM))
-			args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
-					 NFS_MOUNT_LOCAL_FCNTL);
-		else
-			args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
-					NFS_MOUNT_LOCAL_FCNTL);
-		/*
-		 * The legacy version 6 binary mount data from userspace has a
-		 * field used only to transport selinux information into the
-		 * the kernel.  To continue to support that functionality we
-		 * have a touch of selinux knowledge here in the NFS code. The
-		 * userspace code converted context=blah to just blah so we are
-		 * converting back to the full string selinux understands.
-		 */
-		if (data->context[0]){
-#ifdef CONFIG_SECURITY_SELINUX
-			int rc;
-			char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL);
-			if (!opts_str)
-				return -ENOMEM;
-			strcpy(opts_str, "context=");
-			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
-			strcat(opts_str, &data->context[0]);
-			rc = security_sb_parse_opts_str(opts_str, &args->lsm_opts);
-			kfree(opts_str);
-			if (rc)
-				return rc;
-#else
-			return -EINVAL;
-#endif
-		}
-
-		break;
-	default:
-		return NFS_TEXT_DATA;
-	}
-
-	return 0;
-
-out_no_data:
-	dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
-	return -EINVAL;
-
-out_no_v3:
-	dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n",
-		 data->version);
-	return -EINVAL;
-
-out_no_sec:
-	dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n");
-	return -EINVAL;
-
-out_nomem:
-	dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n");
-	return -ENOMEM;
-
-out_no_address:
-	dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
-	return -EINVAL;
-
-out_invalid_fh:
-	dfprintk(MOUNT, "NFS: invalid root filehandle\n");
-	return -EINVAL;
-}
-
-#if IS_ENABLED(CONFIG_NFS_V4)
-static int nfs_validate_mount_data(struct file_system_type *fs_type,
-				   void *options,
-				   struct nfs_parsed_mount_data *args,
-				   struct nfs_fh *mntfh,
-				   const char *dev_name)
-{
-	if (fs_type == &nfs_fs_type)
-		return nfs23_validate_mount_data(options, args, mntfh, dev_name);
-	return nfs4_validate_mount_data(options, args, dev_name);
-}
-#else
-static int nfs_validate_mount_data(struct file_system_type *fs_type,
-				   void *options,
-				   struct nfs_parsed_mount_data *args,
-				   struct nfs_fh *mntfh,
-				   const char *dev_name)
-{
-	return nfs23_validate_mount_data(options, args, mntfh, dev_name);
-}
-#endif
-
-static int nfs_validate_text_mount_data(void *options,
-					struct nfs_parsed_mount_data *args,
-					const char *dev_name)
-{
-	int port = 0;
-	int max_namelen = PAGE_SIZE;
-	int max_pathlen = NFS_MAXPATHLEN;
-	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
-
-	if (nfs_parse_mount_options((char *)options, args) == 0)
-		return -EINVAL;
-
-	if (!nfs_verify_server_address(sap))
-		goto out_no_address;
-
-	if (args->version == 4) {
-#if IS_ENABLED(CONFIG_NFS_V4)
-		port = NFS_PORT;
-		max_namelen = NFS4_MAXNAMLEN;
-		max_pathlen = NFS4_MAXPATHLEN;
-		nfs_validate_transport_protocol(args);
-		if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
-			goto out_invalid_transport_udp;
-		nfs4_validate_mount_flags(args);
-#else
-		goto out_v4_not_compiled;
-#endif /* CONFIG_NFS_V4 */
-	} else
-		nfs_set_mount_transport_protocol(args);
-
-	nfs_set_port(sap, &args->nfs_server.port, port);
-
-	return nfs_parse_devname(dev_name,
-				   &args->nfs_server.hostname,
-				   max_namelen,
-				   &args->nfs_server.export_path,
-				   max_pathlen);
-
-#if !IS_ENABLED(CONFIG_NFS_V4)
-out_v4_not_compiled:
-	dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
-	return -EPROTONOSUPPORT;
-#else
-out_invalid_transport_udp:
-	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
-	return -EINVAL;
-#endif /* !CONFIG_NFS_V4 */
-
-out_no_address:
-	dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
-	return -EINVAL;
-}
-
 #define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
 		| NFS_MOUNT_SECURE \
 		| NFS_MOUNT_TCP \
@@ -2725,113 +1441,6 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
 
 #if IS_ENABLED(CONFIG_NFS_V4)
 
-static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
-{
-	args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
-			 NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
-}
-
-/*
- * Validate NFSv4 mount options
- */
-static int nfs4_validate_mount_data(void *options,
-				    struct nfs_parsed_mount_data *args,
-				    const char *dev_name)
-{
-	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
-	struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
-	char *c;
-
-	if (data == NULL)
-		goto out_no_data;
-
-	args->version = 4;
-
-	switch (data->version) {
-	case 1:
-		if (data->host_addrlen > sizeof(args->nfs_server.address))
-			goto out_no_address;
-		if (data->host_addrlen == 0)
-			goto out_no_address;
-		args->nfs_server.addrlen = data->host_addrlen;
-		if (copy_from_user(sap, data->host_addr, data->host_addrlen))
-			return -EFAULT;
-		if (!nfs_verify_server_address(sap))
-			goto out_no_address;
-		args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
-
-		if (data->auth_flavourlen) {
-			rpc_authflavor_t pseudoflavor;
-			if (data->auth_flavourlen > 1)
-				goto out_inval_auth;
-			if (copy_from_user(&pseudoflavor,
-					   data->auth_flavours,
-					   sizeof(pseudoflavor)))
-				return -EFAULT;
-			args->selected_flavor = pseudoflavor;
-		} else
-			args->selected_flavor = RPC_AUTH_UNIX;
-
-		c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
-		if (IS_ERR(c))
-			return PTR_ERR(c);
-		args->nfs_server.hostname = c;
-
-		c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
-		if (IS_ERR(c))
-			return PTR_ERR(c);
-		args->nfs_server.export_path = c;
-		dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
-
-		c = strndup_user(data->client_addr.data, 16);
-		if (IS_ERR(c))
-			return PTR_ERR(c);
-		args->client_address = c;
-
-		/*
-		 * Translate to nfs_parsed_mount_data, which nfs4_fill_super
-		 * can deal with.
-		 */
-
-		args->flags	= data->flags & NFS4_MOUNT_FLAGMASK;
-		args->rsize	= data->rsize;
-		args->wsize	= data->wsize;
-		args->timeo	= data->timeo;
-		args->retrans	= data->retrans;
-		args->acregmin	= data->acregmin;
-		args->acregmax	= data->acregmax;
-		args->acdirmin	= data->acdirmin;
-		args->acdirmax	= data->acdirmax;
-		args->nfs_server.protocol = data->proto;
-		nfs_validate_transport_protocol(args);
-		if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
-			goto out_invalid_transport_udp;
-
-		break;
-	default:
-		return NFS_TEXT_DATA;
-	}
-
-	return 0;
-
-out_no_data:
-	dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
-	return -EINVAL;
-
-out_inval_auth:
-	dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n",
-		 data->auth_flavourlen);
-	return -EINVAL;
-
-out_no_address:
-	dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
-	return -EINVAL;
-
-out_invalid_transport_udp:
-	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
-	return -EINVAL;
-}
-
 /*
  * NFS v4 module parameters need to stay in the
  * NFS client for backwards compatibility

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 18/27] NFS: Constify mount argument match tables [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (16 preceding siblings ...)
  2017-06-14 15:17 ` [PATCH 17/27] NFS: Move mount parameterisation bits into their own file " David Howells
@ 2017-06-14 15:18 ` David Howells
  2017-06-14 15:18 ` [PATCH 19/27] NFS: Rename struct nfs_parsed_mount_data to struct nfs_fs_context " David Howells
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:18 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

The mount argument match tables should never be altered so constify them.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/nfs/fs_context.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 3e2fe57b9b07..a41f034aafb2 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -197,7 +197,7 @@ enum {
 	Opt_lookupcache_err
 };
 
-static match_table_t nfs_lookupcache_tokens = {
+static const match_table_t nfs_lookupcache_tokens = {
 	{ Opt_lookupcache_all, "all" },
 	{ Opt_lookupcache_positive, "pos" },
 	{ Opt_lookupcache_positive, "positive" },
@@ -213,7 +213,7 @@ enum {
 	Opt_local_lock_err
 };
 
-static match_table_t nfs_local_lock_tokens = {
+static const match_table_t nfs_local_lock_tokens = {
 	{ Opt_local_lock_all, "all" },
 	{ Opt_local_lock_flock, "flock" },
 	{ Opt_local_lock_posix, "posix" },
@@ -229,7 +229,7 @@ enum {
 	Opt_vers_err
 };
 
-static match_table_t nfs_vers_tokens = {
+static const match_table_t nfs_vers_tokens = {
 	{ Opt_vers_2, "2" },
 	{ Opt_vers_3, "3" },
 	{ Opt_vers_4, "4" },

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 19/27] NFS: Rename struct nfs_parsed_mount_data to struct nfs_fs_context [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (17 preceding siblings ...)
  2017-06-14 15:18 ` [PATCH 18/27] NFS: Constify mount argument match tables " David Howells
@ 2017-06-14 15:18 ` David Howells
  2017-06-14 15:18 ` [PATCH 20/27] NFS: Split nfs_parse_mount_options() " David Howells
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:18 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Rename struct nfs_parsed_mount_data to struct nfs_fs_context and rename
pointers to it to "ctx".  At some point this will acquire an fs_context
struct as the first member.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/nfs/client.c     |   64 ++++----
 fs/nfs/fs_context.c |  433 +++++++++++++++++++++++++--------------------------
 fs/nfs/internal.h   |   14 +-
 fs/nfs/nfs4client.c |   58 +++----
 fs/nfs/nfs4super.c  |   10 +
 fs/nfs/super.c      |  184 +++++++++++-----------
 6 files changed, 381 insertions(+), 382 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index ee5ddbd36088..d25dfa15f2ec 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -635,25 +635,25 @@ EXPORT_SYMBOL_GPL(nfs_init_client);
  * Create a version 2 or 3 client
  */
 static int nfs_init_server(struct nfs_server *server,
-			   const struct nfs_parsed_mount_data *data,
+			   const struct nfs_fs_context *cfg,
 			   struct nfs_subversion *nfs_mod)
 {
 	struct rpc_timeout timeparms;
 	struct nfs_client_initdata cl_init = {
-		.hostname = data->nfs_server.hostname,
-		.addr = (const struct sockaddr *)&data->nfs_server.address,
-		.addrlen = data->nfs_server.addrlen,
+		.hostname = cfg->nfs_server.hostname,
+		.addr = (const struct sockaddr *)&cfg->nfs_server.address,
+		.addrlen = cfg->nfs_server.addrlen,
 		.nfs_mod = nfs_mod,
-		.proto = data->nfs_server.protocol,
-		.net = data->net,
+		.proto = cfg->nfs_server.protocol,
+		.net = cfg->net,
 		.timeparms = &timeparms,
 	};
 	struct nfs_client *clp;
 	int error;
 
-	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
-			data->timeo, data->retrans);
-	if (data->flags & NFS_MOUNT_NORESVPORT)
+	nfs_init_timeout_values(&timeparms, cfg->nfs_server.protocol,
+				cfg->timeo, cfg->retrans);
+	if (cfg->flags & NFS_MOUNT_NORESVPORT)
 		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
 
 	/* Allocate or find a client reference we can use */
@@ -664,46 +664,46 @@ static int nfs_init_server(struct nfs_server *server,
 	server->nfs_client = clp;
 
 	/* Initialise the client representation from the mount data */
-	server->flags = data->flags;
-	server->options = data->options;
+	server->flags = cfg->flags;
+	server->options = cfg->options;
 	server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
 		NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
 		NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
 
-	if (data->rsize)
-		server->rsize = nfs_block_size(data->rsize, NULL);
-	if (data->wsize)
-		server->wsize = nfs_block_size(data->wsize, NULL);
+	if (cfg->rsize)
+		server->rsize = nfs_block_size(cfg->rsize, NULL);
+	if (cfg->wsize)
+		server->wsize = nfs_block_size(cfg->wsize, NULL);
 
-	server->acregmin = data->acregmin * HZ;
-	server->acregmax = data->acregmax * HZ;
-	server->acdirmin = data->acdirmin * HZ;
-	server->acdirmax = data->acdirmax * HZ;
+	server->acregmin = cfg->acregmin * HZ;
+	server->acregmax = cfg->acregmax * HZ;
+	server->acdirmin = cfg->acdirmin * HZ;
+	server->acdirmax = cfg->acdirmax * HZ;
 
 	/* Start lockd here, before we might error out */
 	error = nfs_start_lockd(server);
 	if (error < 0)
 		goto error;
 
-	server->port = data->nfs_server.port;
-	server->auth_info = data->auth_info;
+	server->port = cfg->nfs_server.port;
+	server->auth_info = cfg->auth_info;
 
 	error = nfs_init_server_rpcclient(server, &timeparms,
-					  data->selected_flavor);
+					  cfg->selected_flavor);
 	if (error < 0)
 		goto error;
 
 	/* Preserve the values of mount_server-related mount options */
-	if (data->mount_server.addrlen) {
-		memcpy(&server->mountd_address, &data->mount_server.address,
-			data->mount_server.addrlen);
-		server->mountd_addrlen = data->mount_server.addrlen;
+	if (cfg->mount_server.addrlen) {
+		memcpy(&server->mountd_address, &cfg->mount_server.address,
+			cfg->mount_server.addrlen);
+		server->mountd_addrlen = cfg->mount_server.addrlen;
 	}
-	server->mountd_version = data->mount_server.version;
-	server->mountd_port = data->mount_server.port;
-	server->mountd_protocol = data->mount_server.protocol;
+	server->mountd_version = cfg->mount_server.version;
+	server->mountd_port = cfg->mount_server.port;
+	server->mountd_protocol = cfg->mount_server.protocol;
 
-	server->namelen  = data->namlen;
+	server->namelen  = cfg->namlen;
 	return 0;
 
 error:
@@ -938,7 +938,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
 		goto error;
 
 	/* Get a client representation */
-	error = nfs_init_server(server, mount_info->parsed, nfs_mod);
+	error = nfs_init_server(server, mount_info->ctx, nfs_mod);
 	if (error < 0)
 		goto error;
 
@@ -949,7 +949,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
 	if (server->nfs_client->rpc_ops->version == 3) {
 		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
 			server->namelen = NFS3_MAXNAMLEN;
-		if (!(mount_info->parsed->flags & NFS_MOUNT_NORDIRPLUS))
+		if (!(mount_info->ctx->flags & NFS_MOUNT_NORDIRPLUS))
 			server->caps |= NFS_CAP_READDIRPLUS;
 	} else {
 		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index a41f034aafb2..91e412e68183 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -240,40 +240,40 @@ static const match_table_t nfs_vers_tokens = {
 	{ Opt_vers_err, NULL }
 };
 
-struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
+struct nfs_fs_context *nfs_alloc_parsed_mount_data(void)
 {
-	struct nfs_parsed_mount_data *data;
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (data) {
-		data->timeo		= NFS_UNSPEC_TIMEO;
-		data->retrans		= NFS_UNSPEC_RETRANS;
-		data->acregmin		= NFS_DEF_ACREGMIN;
-		data->acregmax		= NFS_DEF_ACREGMAX;
-		data->acdirmin		= NFS_DEF_ACDIRMIN;
-		data->acdirmax		= NFS_DEF_ACDIRMAX;
-		data->mount_server.port	= NFS_UNSPEC_PORT;
-		data->nfs_server.port	= NFS_UNSPEC_PORT;
-		data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-		data->selected_flavor	= RPC_AUTH_MAXFLAVOR;
-		data->minorversion	= 0;
-		data->need_mount	= true;
-		data->net		= current->nsproxy->net_ns;
-		security_init_mnt_opts(&data->lsm_opts);
+	struct nfs_fs_context *ctx;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (ctx) {
+		ctx->timeo		= NFS_UNSPEC_TIMEO;
+		ctx->retrans		= NFS_UNSPEC_RETRANS;
+		ctx->acregmin		= NFS_DEF_ACREGMIN;
+		ctx->acregmax		= NFS_DEF_ACREGMAX;
+		ctx->acdirmin		= NFS_DEF_ACDIRMIN;
+		ctx->acdirmax		= NFS_DEF_ACDIRMAX;
+		ctx->mount_server.port	= NFS_UNSPEC_PORT;
+		ctx->nfs_server.port	= NFS_UNSPEC_PORT;
+		ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+		ctx->selected_flavor	= RPC_AUTH_MAXFLAVOR;
+		ctx->minorversion	= 0;
+		ctx->need_mount	= true;
+		ctx->net		= current->nsproxy->net_ns;
+		security_init_mnt_opts(&ctx->lsm_opts);
 	}
-	return data;
+	return ctx;
 }
 
-void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
+void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx)
 {
-	if (data) {
-		kfree(data->client_address);
-		kfree(data->mount_server.hostname);
-		kfree(data->nfs_server.export_path);
-		kfree(data->nfs_server.hostname);
-		kfree(data->fscache_uniq);
-		security_free_mnt_opts(&data->lsm_opts);
-		kfree(data);
+	if (ctx) {
+		kfree(ctx->client_address);
+		kfree(ctx->mount_server.hostname);
+		kfree(ctx->nfs_server.export_path);
+		kfree(ctx->nfs_server.hostname);
+		kfree(ctx->fscache_uniq);
+		security_free_mnt_opts(&ctx->lsm_opts);
+		kfree(ctx);
 	}
 }
 
@@ -304,15 +304,15 @@ static int nfs_verify_server_address(struct sockaddr *addr)
  * Sanity check the NFS transport protocol.
  *
  */
-static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
+static void nfs_validate_transport_protocol(struct nfs_fs_context *ctx)
 {
-	switch (mnt->nfs_server.protocol) {
+	switch (ctx->nfs_server.protocol) {
 	case XPRT_TRANSPORT_UDP:
 	case XPRT_TRANSPORT_TCP:
 	case XPRT_TRANSPORT_RDMA:
 		break;
 	default:
-		mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+		ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
 	}
 }
 
@@ -320,20 +320,20 @@ static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
  * For text based NFSv2/v3 mounts, the mount protocol transport default
  * settings should depend upon the specified NFS transport.
  */
-static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
+static void nfs_set_mount_transport_protocol(struct nfs_fs_context *ctx)
 {
-	nfs_validate_transport_protocol(mnt);
+	nfs_validate_transport_protocol(ctx);
 
-	if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP ||
-	    mnt->mount_server.protocol == XPRT_TRANSPORT_TCP)
+	if (ctx->mount_server.protocol == XPRT_TRANSPORT_UDP ||
+	    ctx->mount_server.protocol == XPRT_TRANSPORT_TCP)
 			return;
-	switch (mnt->nfs_server.protocol) {
+	switch (ctx->nfs_server.protocol) {
 	case XPRT_TRANSPORT_UDP:
-		mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+		ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
 		break;
 	case XPRT_TRANSPORT_TCP:
 	case XPRT_TRANSPORT_RDMA:
-		mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
+		ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
 	}
 }
 
@@ -365,8 +365,7 @@ static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
 /*
  * Parse the value of the 'sec=' option.
  */
-static int nfs_parse_security_flavors(char *value,
-				      struct nfs_parsed_mount_data *mnt)
+static int nfs_parse_security_flavors(char *value, struct nfs_fs_context *ctx)
 {
 	substring_t args[MAX_OPT_ARGS];
 	rpc_authflavor_t pseudoflavor;
@@ -415,7 +414,7 @@ static int nfs_parse_security_flavors(char *value,
 			return 0;
 		}
 
-		if (!nfs_auth_info_add(&mnt->auth_info, pseudoflavor))
+		if (!nfs_auth_info_add(&ctx->auth_info, pseudoflavor))
 			return 0;
 	}
 
@@ -423,36 +422,36 @@ static int nfs_parse_security_flavors(char *value,
 }
 
 static int nfs_parse_version_string(char *string,
-		struct nfs_parsed_mount_data *mnt,
+		struct nfs_fs_context *ctx,
 		substring_t *args)
 {
-	mnt->flags &= ~NFS_MOUNT_VER3;
+	ctx->flags &= ~NFS_MOUNT_VER3;
 	switch (match_token(string, nfs_vers_tokens, args)) {
 	case Opt_vers_2:
-		mnt->version = 2;
+		ctx->version = 2;
 		break;
 	case Opt_vers_3:
-		mnt->flags |= NFS_MOUNT_VER3;
-		mnt->version = 3;
+		ctx->flags |= NFS_MOUNT_VER3;
+		ctx->version = 3;
 		break;
 	case Opt_vers_4:
 		/* Backward compatibility option. In future,
 		 * the mount program should always supply
 		 * a NFSv4 minor version number.
 		 */
-		mnt->version = 4;
+		ctx->version = 4;
 		break;
 	case Opt_vers_4_0:
-		mnt->version = 4;
-		mnt->minorversion = 0;
+		ctx->version = 4;
+		ctx->minorversion = 0;
 		break;
 	case Opt_vers_4_1:
-		mnt->version = 4;
-		mnt->minorversion = 1;
+		ctx->version = 4;
+		ctx->minorversion = 1;
 		break;
 	case Opt_vers_4_2:
-		mnt->version = 4;
-		mnt->minorversion = 2;
+		ctx->version = 4;
+		ctx->minorversion = 2;
 		break;
 	default:
 		return 0;
@@ -500,7 +499,7 @@ static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
  * skipped as they are encountered.  If there were no errors, return 1;
  * otherwise return 0 (zero).
  */
-int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
+int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 {
 	char *p, *string, *secdata;
 	int rc, sloppy = 0, invalid_option = 0;
@@ -521,7 +520,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 	if (rc)
 		goto out_security_failure;
 
-	rc = security_sb_parse_opts_str(secdata, &mnt->lsm_opts);
+	rc = security_sb_parse_opts_str(secdata, &ctx->lsm_opts);
 	if (rc)
 		goto out_security_failure;
 
@@ -544,91 +543,91 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 		 * boolean options:  foo/nofoo
 		 */
 		case Opt_soft:
-			mnt->flags |= NFS_MOUNT_SOFT;
+			ctx->flags |= NFS_MOUNT_SOFT;
 			break;
 		case Opt_hard:
-			mnt->flags &= ~NFS_MOUNT_SOFT;
+			ctx->flags &= ~NFS_MOUNT_SOFT;
 			break;
 		case Opt_posix:
-			mnt->flags |= NFS_MOUNT_POSIX;
+			ctx->flags |= NFS_MOUNT_POSIX;
 			break;
 		case Opt_noposix:
-			mnt->flags &= ~NFS_MOUNT_POSIX;
+			ctx->flags &= ~NFS_MOUNT_POSIX;
 			break;
 		case Opt_cto:
-			mnt->flags &= ~NFS_MOUNT_NOCTO;
+			ctx->flags &= ~NFS_MOUNT_NOCTO;
 			break;
 		case Opt_nocto:
-			mnt->flags |= NFS_MOUNT_NOCTO;
+			ctx->flags |= NFS_MOUNT_NOCTO;
 			break;
 		case Opt_ac:
-			mnt->flags &= ~NFS_MOUNT_NOAC;
+			ctx->flags &= ~NFS_MOUNT_NOAC;
 			break;
 		case Opt_noac:
-			mnt->flags |= NFS_MOUNT_NOAC;
+			ctx->flags |= NFS_MOUNT_NOAC;
 			break;
 		case Opt_lock:
-			mnt->flags &= ~NFS_MOUNT_NONLM;
-			mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+			ctx->flags &= ~NFS_MOUNT_NONLM;
+			ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
 					NFS_MOUNT_LOCAL_FCNTL);
 			break;
 		case Opt_nolock:
-			mnt->flags |= NFS_MOUNT_NONLM;
-			mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+			ctx->flags |= NFS_MOUNT_NONLM;
+			ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
 				       NFS_MOUNT_LOCAL_FCNTL);
 			break;
 		case Opt_udp:
-			mnt->flags &= ~NFS_MOUNT_TCP;
-			mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+			ctx->flags &= ~NFS_MOUNT_TCP;
+			ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
 			break;
 		case Opt_tcp:
-			mnt->flags |= NFS_MOUNT_TCP;
-			mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+			ctx->flags |= NFS_MOUNT_TCP;
+			ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
 			break;
 		case Opt_rdma:
-			mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
-			mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+			ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */
+			ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
 			xprt_load_transport(p);
 			break;
 		case Opt_acl:
-			mnt->flags &= ~NFS_MOUNT_NOACL;
+			ctx->flags &= ~NFS_MOUNT_NOACL;
 			break;
 		case Opt_noacl:
-			mnt->flags |= NFS_MOUNT_NOACL;
+			ctx->flags |= NFS_MOUNT_NOACL;
 			break;
 		case Opt_rdirplus:
-			mnt->flags &= ~NFS_MOUNT_NORDIRPLUS;
+			ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
 			break;
 		case Opt_nordirplus:
-			mnt->flags |= NFS_MOUNT_NORDIRPLUS;
+			ctx->flags |= NFS_MOUNT_NORDIRPLUS;
 			break;
 		case Opt_sharecache:
-			mnt->flags &= ~NFS_MOUNT_UNSHARED;
+			ctx->flags &= ~NFS_MOUNT_UNSHARED;
 			break;
 		case Opt_nosharecache:
-			mnt->flags |= NFS_MOUNT_UNSHARED;
+			ctx->flags |= NFS_MOUNT_UNSHARED;
 			break;
 		case Opt_resvport:
-			mnt->flags &= ~NFS_MOUNT_NORESVPORT;
+			ctx->flags &= ~NFS_MOUNT_NORESVPORT;
 			break;
 		case Opt_noresvport:
-			mnt->flags |= NFS_MOUNT_NORESVPORT;
+			ctx->flags |= NFS_MOUNT_NORESVPORT;
 			break;
 		case Opt_fscache:
-			mnt->options |= NFS_OPTION_FSCACHE;
-			kfree(mnt->fscache_uniq);
-			mnt->fscache_uniq = NULL;
+			ctx->options |= NFS_OPTION_FSCACHE;
+			kfree(ctx->fscache_uniq);
+			ctx->fscache_uniq = NULL;
 			break;
 		case Opt_nofscache:
-			mnt->options &= ~NFS_OPTION_FSCACHE;
-			kfree(mnt->fscache_uniq);
-			mnt->fscache_uniq = NULL;
+			ctx->options &= ~NFS_OPTION_FSCACHE;
+			kfree(ctx->fscache_uniq);
+			ctx->fscache_uniq = NULL;
 			break;
 		case Opt_migration:
-			mnt->options |= NFS_OPTION_MIGRATION;
+			ctx->options |= NFS_OPTION_MIGRATION;
 			break;
 		case Opt_nomigration:
-			mnt->options &= NFS_OPTION_MIGRATION;
+			ctx->options &= NFS_OPTION_MIGRATION;
 			break;
 
 		/*
@@ -638,83 +637,83 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 			if (nfs_get_option_ul(args, &option) ||
 			    option > USHRT_MAX)
 				goto out_invalid_value;
-			mnt->nfs_server.port = option;
+			ctx->nfs_server.port = option;
 			break;
 		case Opt_rsize:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
-			mnt->rsize = option;
+			ctx->rsize = option;
 			break;
 		case Opt_wsize:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
-			mnt->wsize = option;
+			ctx->wsize = option;
 			break;
 		case Opt_bsize:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
-			mnt->bsize = option;
+			ctx->bsize = option;
 			break;
 		case Opt_timeo:
 			if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
 				goto out_invalid_value;
-			mnt->timeo = option;
+			ctx->timeo = option;
 			break;
 		case Opt_retrans:
 			if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
 				goto out_invalid_value;
-			mnt->retrans = option;
+			ctx->retrans = option;
 			break;
 		case Opt_acregmin:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
-			mnt->acregmin = option;
+			ctx->acregmin = option;
 			break;
 		case Opt_acregmax:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
-			mnt->acregmax = option;
+			ctx->acregmax = option;
 			break;
 		case Opt_acdirmin:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
-			mnt->acdirmin = option;
+			ctx->acdirmin = option;
 			break;
 		case Opt_acdirmax:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
-			mnt->acdirmax = option;
+			ctx->acdirmax = option;
 			break;
 		case Opt_actimeo:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
-			mnt->acregmin = mnt->acregmax =
-			mnt->acdirmin = mnt->acdirmax = option;
+			ctx->acregmin = ctx->acregmax =
+			ctx->acdirmin = ctx->acdirmax = option;
 			break;
 		case Opt_namelen:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
-			mnt->namlen = option;
+			ctx->namlen = option;
 			break;
 		case Opt_mountport:
 			if (nfs_get_option_ul(args, &option) ||
 			    option > USHRT_MAX)
 				goto out_invalid_value;
-			mnt->mount_server.port = option;
+			ctx->mount_server.port = option;
 			break;
 		case Opt_mountvers:
 			if (nfs_get_option_ul(args, &option) ||
 			    option < NFS_MNT_VERSION ||
 			    option > NFS_MNT3_VERSION)
 				goto out_invalid_value;
-			mnt->mount_server.version = option;
+			ctx->mount_server.version = option;
 			break;
 		case Opt_minorversion:
 			if (nfs_get_option_ul(args, &option))
 				goto out_invalid_value;
 			if (option > NFS4_MAX_MINOR_VERSION)
 				goto out_invalid_value;
-			mnt->minorversion = option;
+			ctx->minorversion = option;
 			break;
 
 		/*
@@ -724,7 +723,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 			string = match_strdup(args);
 			if (string == NULL)
 				goto out_nomem;
-			rc = nfs_parse_version_string(string, mnt, args);
+			rc = nfs_parse_version_string(string, ctx, args);
 			kfree(string);
 			if (!rc)
 				goto out_invalid_value;
@@ -733,7 +732,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 			string = match_strdup(args);
 			if (string == NULL)
 				goto out_nomem;
-			rc = nfs_parse_security_flavors(string, mnt);
+			rc = nfs_parse_security_flavors(string, ctx);
 			kfree(string);
 			if (!rc) {
 				dfprintk(MOUNT, "NFS:   unrecognized "
@@ -753,21 +752,21 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 			case Opt_xprt_udp6:
 				protofamily = AF_INET6;
 			case Opt_xprt_udp:
-				mnt->flags &= ~NFS_MOUNT_TCP;
-				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+				ctx->flags &= ~NFS_MOUNT_TCP;
+				ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
 				break;
 			case Opt_xprt_tcp6:
 				protofamily = AF_INET6;
 			case Opt_xprt_tcp:
-				mnt->flags |= NFS_MOUNT_TCP;
-				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+				ctx->flags |= NFS_MOUNT_TCP;
+				ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
 				break;
 			case Opt_xprt_rdma6:
 				protofamily = AF_INET6;
 			case Opt_xprt_rdma:
 				/* vector side protocols to TCP */
-				mnt->flags |= NFS_MOUNT_TCP;
-				mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+				ctx->flags |= NFS_MOUNT_TCP;
+				ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
 				xprt_load_transport(string);
 				break;
 			default:
@@ -791,12 +790,12 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 			case Opt_xprt_udp6:
 				mountfamily = AF_INET6;
 			case Opt_xprt_udp:
-				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+				ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
 				break;
 			case Opt_xprt_tcp6:
 				mountfamily = AF_INET6;
 			case Opt_xprt_tcp:
-				mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
+				ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
 				break;
 			case Opt_xprt_rdma: /* not used for side protocols */
 			default:
@@ -809,35 +808,35 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 			string = match_strdup(args);
 			if (string == NULL)
 				goto out_nomem;
-			mnt->nfs_server.addrlen =
-				rpc_pton(mnt->net, string, strlen(string),
+			ctx->nfs_server.addrlen =
+				rpc_pton(ctx->net, string, strlen(string),
 					(struct sockaddr *)
-					&mnt->nfs_server.address,
-					sizeof(mnt->nfs_server.address));
+					&ctx->nfs_server.address,
+					sizeof(ctx->nfs_server.address));
 			kfree(string);
-			if (mnt->nfs_server.addrlen == 0)
+			if (ctx->nfs_server.addrlen == 0)
 				goto out_invalid_address;
 			break;
 		case Opt_clientaddr:
-			if (nfs_get_option_str(args, &mnt->client_address))
+			if (nfs_get_option_str(args, &ctx->client_address))
 				goto out_nomem;
 			break;
 		case Opt_mounthost:
 			if (nfs_get_option_str(args,
-					       &mnt->mount_server.hostname))
+					       &ctx->mount_server.hostname))
 				goto out_nomem;
 			break;
 		case Opt_mountaddr:
 			string = match_strdup(args);
 			if (string == NULL)
 				goto out_nomem;
-			mnt->mount_server.addrlen =
-				rpc_pton(mnt->net, string, strlen(string),
+			ctx->mount_server.addrlen =
+				rpc_pton(ctx->net, string, strlen(string),
 					(struct sockaddr *)
-					&mnt->mount_server.address,
-					sizeof(mnt->mount_server.address));
+					&ctx->mount_server.address,
+					sizeof(ctx->mount_server.address));
 			kfree(string);
-			if (mnt->mount_server.addrlen == 0)
+			if (ctx->mount_server.addrlen == 0)
 				goto out_invalid_address;
 			break;
 		case Opt_lookupcache:
@@ -849,14 +848,14 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 			kfree(string);
 			switch (token) {
 				case Opt_lookupcache_all:
-					mnt->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
+					ctx->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
 					break;
 				case Opt_lookupcache_positive:
-					mnt->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
-					mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
+					ctx->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
+					ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
 					break;
 				case Opt_lookupcache_none:
-					mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
+					ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
 					break;
 				default:
 					dfprintk(MOUNT, "NFS:   invalid "
@@ -865,9 +864,9 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 			};
 			break;
 		case Opt_fscache_uniq:
-			if (nfs_get_option_str(args, &mnt->fscache_uniq))
+			if (nfs_get_option_str(args, &ctx->fscache_uniq))
 				goto out_nomem;
-			mnt->options |= NFS_OPTION_FSCACHE;
+			ctx->options |= NFS_OPTION_FSCACHE;
 			break;
 		case Opt_local_lock:
 			string = match_strdup(args);
@@ -878,17 +877,17 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 			kfree(string);
 			switch (token) {
 			case Opt_local_lock_all:
-				mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+				ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
 					       NFS_MOUNT_LOCAL_FCNTL);
 				break;
 			case Opt_local_lock_flock:
-				mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
+				ctx->flags |= NFS_MOUNT_LOCAL_FLOCK;
 				break;
 			case Opt_local_lock_posix:
-				mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
+				ctx->flags |= NFS_MOUNT_LOCAL_FCNTL;
 				break;
 			case Opt_local_lock_none:
-				mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+				ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
 						NFS_MOUNT_LOCAL_FCNTL);
 				break;
 			default:
@@ -921,11 +920,11 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 	if (!sloppy && invalid_option)
 		return 0;
 
-	if (mnt->minorversion && mnt->version != 4)
+	if (ctx->minorversion && ctx->version != 4)
 		goto out_minorversion_mismatch;
 
-	if (mnt->options & NFS_OPTION_MIGRATION &&
-	    (mnt->version != 4 || mnt->minorversion != 0))
+	if (ctx->options & NFS_OPTION_MIGRATION &&
+	    (ctx->version != 4 || ctx->minorversion != 0))
 		goto out_migration_misuse;
 
 	/*
@@ -933,15 +932,15 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 	 * families in the addr=/mountaddr= options.
 	 */
 	if (protofamily != AF_UNSPEC &&
-	    protofamily != mnt->nfs_server.address.ss_family)
+	    protofamily != ctx->nfs_server.address.ss_family)
 		goto out_proto_mismatch;
 
 	if (mountfamily != AF_UNSPEC) {
-		if (mnt->mount_server.addrlen) {
-			if (mountfamily != mnt->mount_server.address.ss_family)
+		if (ctx->mount_server.addrlen) {
+			if (mountfamily != ctx->mount_server.address.ss_family)
 				goto out_mountproto_mismatch;
 		} else {
-			if (mountfamily != mnt->nfs_server.address.ss_family)
+			if (mountfamily != ctx->nfs_server.address.ss_family)
 				goto out_mountproto_mismatch;
 		}
 	}
@@ -963,7 +962,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 	return 0;
 out_minorversion_mismatch:
 	printk(KERN_INFO "NFS: mount option vers=%u does not support "
-			 "minorversion=%u\n", mnt->version, mnt->minorversion);
+			 "minorversion=%u\n", ctx->version, ctx->minorversion);
 	return 0;
 out_migration_misuse:
 	printk(KERN_INFO
@@ -1067,18 +1066,18 @@ static int nfs_parse_devname(const char *dev_name,
  *   mountproto=tcp after mountproto=udp, and so on
  */
 static int nfs23_validate_mount_data(void *options,
-				     struct nfs_parsed_mount_data *args,
+				     struct nfs_fs_context *ctx,
 				     struct nfs_fh *mntfh,
 				     const char *dev_name)
 {
 	struct nfs_mount_data *data = (struct nfs_mount_data *)options;
-	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
 	int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
 
 	if (data == NULL)
 		goto out_no_data;
 
-	args->version = NFS_DEFAULT_VERSION;
+	ctx->version = NFS_DEFAULT_VERSION;
 	switch (data->version) {
 	case 1:
 		data->namlen = 0;
@@ -1101,10 +1100,10 @@ static int nfs23_validate_mount_data(void *options,
 			if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
 				goto out_invalid_fh;
 			mntfh->size = data->root.size;
-			args->version = 3;
+			ctx->version = 3;
 		} else {
 			mntfh->size = NFS2_FHSIZE;
-			args->version = 2;
+			ctx->version = 2;
 		}
 
 
@@ -1114,46 +1113,46 @@ static int nfs23_validate_mount_data(void *options,
 			       sizeof(mntfh->data) - mntfh->size);
 
 		/*
-		 * Translate to nfs_parsed_mount_data, which nfs_fill_super
+		 * Translate to nfs_fs_context, which nfs_fill_super
 		 * can deal with.
 		 */
-		args->flags		= data->flags & NFS_MOUNT_FLAGMASK;
-		args->flags		|= extra_flags;
-		args->rsize		= data->rsize;
-		args->wsize		= data->wsize;
-		args->timeo		= data->timeo;
-		args->retrans		= data->retrans;
-		args->acregmin		= data->acregmin;
-		args->acregmax		= data->acregmax;
-		args->acdirmin		= data->acdirmin;
-		args->acdirmax		= data->acdirmax;
-		args->need_mount	= false;
+		ctx->flags		= data->flags & NFS_MOUNT_FLAGMASK;
+		ctx->flags		|= extra_flags;
+		ctx->rsize		= data->rsize;
+		ctx->wsize		= data->wsize;
+		ctx->timeo		= data->timeo;
+		ctx->retrans		= data->retrans;
+		ctx->acregmin		= data->acregmin;
+		ctx->acregmax		= data->acregmax;
+		ctx->acdirmin		= data->acdirmin;
+		ctx->acdirmax		= data->acdirmax;
+		ctx->need_mount	= false;
 
 		memcpy(sap, &data->addr, sizeof(data->addr));
-		args->nfs_server.addrlen = sizeof(data->addr);
-		args->nfs_server.port = ntohs(data->addr.sin_port);
+		ctx->nfs_server.addrlen = sizeof(data->addr);
+		ctx->nfs_server.port = ntohs(data->addr.sin_port);
 		if (!nfs_verify_server_address(sap))
 			goto out_no_address;
 
 		if (!(data->flags & NFS_MOUNT_TCP))
-			args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+			ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
 		/* N.B. caller will free nfs_server.hostname in all cases */
-		args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
-		args->namlen		= data->namlen;
-		args->bsize		= data->bsize;
+		ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
+		ctx->namlen		= data->namlen;
+		ctx->bsize		= data->bsize;
 
 		if (data->flags & NFS_MOUNT_SECFLAVOUR)
-			args->selected_flavor = data->pseudoflavor;
+			ctx->selected_flavor = data->pseudoflavor;
 		else
-			args->selected_flavor = RPC_AUTH_UNIX;
-		if (!args->nfs_server.hostname)
+			ctx->selected_flavor = RPC_AUTH_UNIX;
+		if (!ctx->nfs_server.hostname)
 			goto out_nomem;
 
 		if (!(data->flags & NFS_MOUNT_NONLM))
-			args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
+			ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
 					 NFS_MOUNT_LOCAL_FCNTL);
 		else
-			args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
+			ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK|
 					NFS_MOUNT_LOCAL_FCNTL);
 		/*
 		 * The legacy version 6 binary mount data from userspace has a
@@ -1172,7 +1171,7 @@ static int nfs23_validate_mount_data(void *options,
 			strcpy(opts_str, "context=");
 			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
 			strcat(opts_str, &data->context[0]);
-			rc = security_sb_parse_opts_str(opts_str, &args->lsm_opts);
+			rc = security_sb_parse_opts_str(opts_str, &ctx->lsm_opts);
 			kfree(opts_str);
 			if (rc)
 				return rc;
@@ -1216,9 +1215,9 @@ static int nfs23_validate_mount_data(void *options,
 
 #if IS_ENABLED(CONFIG_NFS_V4)
 
-static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
+static void nfs4_validate_mount_flags(struct nfs_fs_context *ctx)
 {
-	args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
+	ctx->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
 			 NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
 }
 
@@ -1226,30 +1225,30 @@ static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
  * Validate NFSv4 mount options
  */
 static int nfs4_validate_mount_data(void *options,
-				    struct nfs_parsed_mount_data *args,
+				    struct nfs_fs_context *ctx,
 				    const char *dev_name)
 {
-	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
 	struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
 	char *c;
 
 	if (data == NULL)
 		goto out_no_data;
 
-	args->version = 4;
+	ctx->version = 4;
 
 	switch (data->version) {
 	case 1:
-		if (data->host_addrlen > sizeof(args->nfs_server.address))
+		if (data->host_addrlen > sizeof(ctx->nfs_server.address))
 			goto out_no_address;
 		if (data->host_addrlen == 0)
 			goto out_no_address;
-		args->nfs_server.addrlen = data->host_addrlen;
+		ctx->nfs_server.addrlen = data->host_addrlen;
 		if (copy_from_user(sap, data->host_addr, data->host_addrlen))
 			return -EFAULT;
 		if (!nfs_verify_server_address(sap))
 			goto out_no_address;
-		args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
+		ctx->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
 
 		if (data->auth_flavourlen) {
 			rpc_authflavor_t pseudoflavor;
@@ -1259,43 +1258,43 @@ static int nfs4_validate_mount_data(void *options,
 					   data->auth_flavours,
 					   sizeof(pseudoflavor)))
 				return -EFAULT;
-			args->selected_flavor = pseudoflavor;
+			ctx->selected_flavor = pseudoflavor;
 		} else
-			args->selected_flavor = RPC_AUTH_UNIX;
+			ctx->selected_flavor = RPC_AUTH_UNIX;
 
 		c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
 		if (IS_ERR(c))
 			return PTR_ERR(c);
-		args->nfs_server.hostname = c;
+		ctx->nfs_server.hostname = c;
 
 		c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
 		if (IS_ERR(c))
 			return PTR_ERR(c);
-		args->nfs_server.export_path = c;
+		ctx->nfs_server.export_path = c;
 		dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
 
 		c = strndup_user(data->client_addr.data, 16);
 		if (IS_ERR(c))
 			return PTR_ERR(c);
-		args->client_address = c;
+		ctx->client_address = c;
 
 		/*
-		 * Translate to nfs_parsed_mount_data, which nfs4_fill_super
+		 * Translate to nfs_fs_context, which nfs4_fill_super
 		 * can deal with.
 		 */
 
-		args->flags	= data->flags & NFS4_MOUNT_FLAGMASK;
-		args->rsize	= data->rsize;
-		args->wsize	= data->wsize;
-		args->timeo	= data->timeo;
-		args->retrans	= data->retrans;
-		args->acregmin	= data->acregmin;
-		args->acregmax	= data->acregmax;
-		args->acdirmin	= data->acdirmin;
-		args->acdirmax	= data->acdirmax;
-		args->nfs_server.protocol = data->proto;
-		nfs_validate_transport_protocol(args);
-		if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+		ctx->flags	= data->flags & NFS4_MOUNT_FLAGMASK;
+		ctx->rsize	= data->rsize;
+		ctx->wsize	= data->wsize;
+		ctx->timeo	= data->timeo;
+		ctx->retrans	= data->retrans;
+		ctx->acregmin	= data->acregmin;
+		ctx->acregmax	= data->acregmax;
+		ctx->acdirmin	= data->acdirmin;
+		ctx->acdirmax	= data->acdirmax;
+		ctx->nfs_server.protocol = data->proto;
+		nfs_validate_transport_protocol(ctx);
+		if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
 			goto out_invalid_transport_udp;
 
 		break;
@@ -1325,61 +1324,61 @@ static int nfs4_validate_mount_data(void *options,
 
 int nfs_validate_mount_data(struct file_system_type *fs_type,
 			    void *options,
-			    struct nfs_parsed_mount_data *args,
+			    struct nfs_fs_context *ctx,
 			    struct nfs_fh *mntfh,
 			    const char *dev_name)
 {
 	if (fs_type == &nfs_fs_type)
-		return nfs23_validate_mount_data(options, args, mntfh, dev_name);
-	return nfs4_validate_mount_data(options, args, dev_name);
+		return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
+	return nfs4_validate_mount_data(options, ctx, dev_name);
 }
 #else
 int nfs_validate_mount_data(struct file_system_type *fs_type,
 			    void *options,
-			    struct nfs_parsed_mount_data *args,
+			    struct nfs_fs_context *ctx,
 			    struct nfs_fh *mntfh,
 			    const char *dev_name)
 {
-	return nfs23_validate_mount_data(options, args, mntfh, dev_name);
+	return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
 }
 #endif
 
 int nfs_validate_text_mount_data(void *options,
-				 struct nfs_parsed_mount_data *args,
+				 struct nfs_fs_context *ctx,
 				 const char *dev_name)
 {
 	int port = 0;
 	int max_namelen = PAGE_SIZE;
 	int max_pathlen = NFS_MAXPATHLEN;
-	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
 
-	if (nfs_parse_mount_options((char *)options, args) == 0)
+	if (nfs_parse_mount_options((char *)options, ctx) == 0)
 		return -EINVAL;
 
 	if (!nfs_verify_server_address(sap))
 		goto out_no_address;
 
-	if (args->version == 4) {
+	if (ctx->version == 4) {
 #if IS_ENABLED(CONFIG_NFS_V4)
 		port = NFS_PORT;
 		max_namelen = NFS4_MAXNAMLEN;
 		max_pathlen = NFS4_MAXPATHLEN;
-		nfs_validate_transport_protocol(args);
-		if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+		nfs_validate_transport_protocol(ctx);
+		if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
 			goto out_invalid_transport_udp;
-		nfs4_validate_mount_flags(args);
+		nfs4_validate_mount_flags(ctx);
 #else
 		goto out_v4_not_compiled;
 #endif /* CONFIG_NFS_V4 */
 	} else
-		nfs_set_mount_transport_protocol(args);
+		nfs_set_mount_transport_protocol(ctx);
 
-	nfs_set_port(sap, &args->nfs_server.port, port);
+	nfs_set_port(sap, &ctx->nfs_server.port, port);
 
 	return nfs_parse_devname(dev_name,
-				   &args->nfs_server.hostname,
+				   &ctx->nfs_server.hostname,
 				   max_namelen,
-				   &args->nfs_server.export_path,
+				   &ctx->nfs_server.export_path,
 				   max_pathlen);
 
 #if !IS_ENABLED(CONFIG_NFS_V4)
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index cc9753366b88..990e0d4d59fa 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -85,7 +85,7 @@ struct nfs_client_initdata {
 /*
  * In-kernel mount arguments
  */
-struct nfs_parsed_mount_data {
+struct nfs_fs_context {
 	int			flags;
 	unsigned int		rsize, wsize;
 	unsigned int		timeo, retrans;
@@ -142,7 +142,7 @@ struct nfs_mount_request {
 struct nfs_mount_info {
 	void (*fill_super)(struct super_block *, struct nfs_mount_info *);
 	int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *);
-	struct nfs_parsed_mount_data *parsed;
+	struct nfs_fs_context *ctx;
 	struct nfs_clone_mount *cloned;
 	struct nfs_fh *mntfh;
 };
@@ -234,16 +234,16 @@ struct nfs_pageio_descriptor;
 /* mount.c */
 #define NFS_TEXT_DATA		1
 
-extern struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void);
-extern void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data);
-extern int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt);
+extern struct nfs_fs_context *nfs_alloc_parsed_mount_data(void);
+extern void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx);
+extern int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx);
 extern int nfs_validate_mount_data(struct file_system_type *fs_type,
 				   void *options,
-				   struct nfs_parsed_mount_data *args,
+				   struct nfs_fs_context *ctx,
 				   struct nfs_fh *mntfh,
 				   const char *dev_name);
 extern int nfs_validate_text_mount_data(void *options,
-					struct nfs_parsed_mount_data *args,
+					struct nfs_fs_context *ctx,
 					const char *dev_name);
 
 /* pagelist.c */
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 66776f022111..0b5e1ecfa8f8 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1009,60 +1009,60 @@ static int nfs4_server_common_setup(struct nfs_server *server,
  * Create a version 4 volume record
  */
 static int nfs4_init_server(struct nfs_server *server,
-		struct nfs_parsed_mount_data *data)
+			    struct nfs_fs_context *ctx)
 {
 	struct rpc_timeout timeparms;
 	int error;
 
-	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
-			data->timeo, data->retrans);
+	nfs_init_timeout_values(&timeparms, ctx->nfs_server.protocol,
+				ctx->timeo, ctx->retrans);
 
 	/* Initialise the client representation from the mount data */
-	server->flags = data->flags;
-	server->options = data->options;
-	server->auth_info = data->auth_info;
+	server->flags = ctx->flags;
+	server->options = ctx->options;
+	server->auth_info = ctx->auth_info;
 
 	/* Use the first specified auth flavor. If this flavor isn't
 	 * allowed by the server, use the SECINFO path to try the
 	 * other specified flavors */
-	if (data->auth_info.flavor_len >= 1)
-		data->selected_flavor = data->auth_info.flavors[0];
+	if (ctx->auth_info.flavor_len >= 1)
+		ctx->selected_flavor = ctx->auth_info.flavors[0];
 	else
-		data->selected_flavor = RPC_AUTH_UNIX;
+		ctx->selected_flavor = RPC_AUTH_UNIX;
 
 	/* Get a client record */
 	error = nfs4_set_client(server,
-			data->nfs_server.hostname,
-			(const struct sockaddr *)&data->nfs_server.address,
-			data->nfs_server.addrlen,
-			data->client_address,
-			data->nfs_server.protocol,
+			ctx->nfs_server.hostname,
+			(const struct sockaddr *)&ctx->nfs_server.address,
+			ctx->nfs_server.addrlen,
+			ctx->client_address,
+			ctx->nfs_server.protocol,
 			&timeparms,
-			data->minorversion,
-			data->net);
+			ctx->minorversion,
+			ctx->net);
 	if (error < 0)
 		return error;
 
-	if (data->rsize)
-		server->rsize = nfs_block_size(data->rsize, NULL);
-	if (data->wsize)
-		server->wsize = nfs_block_size(data->wsize, NULL);
+	if (ctx->rsize)
+		server->rsize = nfs_block_size(ctx->rsize, NULL);
+	if (ctx->wsize)
+		server->wsize = nfs_block_size(ctx->wsize, NULL);
 
-	server->acregmin = data->acregmin * HZ;
-	server->acregmax = data->acregmax * HZ;
-	server->acdirmin = data->acdirmin * HZ;
-	server->acdirmax = data->acdirmax * HZ;
-	server->port     = data->nfs_server.port;
+	server->acregmin = ctx->acregmin * HZ;
+	server->acregmax = ctx->acregmax * HZ;
+	server->acdirmin = ctx->acdirmin * HZ;
+	server->acdirmax = ctx->acdirmax * HZ;
+	server->port     = ctx->nfs_server.port;
 
 	return nfs_init_server_rpcclient(server, &timeparms,
-					 data->selected_flavor);
+					 ctx->selected_flavor);
 }
 
 /*
  * Create a version 4 volume record
  * - keyed on server and FSID
  */
-/*struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
+/*struct nfs_server *nfs4_create_server(const struct nfs_fs_context *data,
 				      struct nfs_fh *mntfh)*/
 struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
 				      struct nfs_subversion *nfs_mod)
@@ -1075,10 +1075,10 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
 	if (!server)
 		return ERR_PTR(-ENOMEM);
 
-	auth_probe = mount_info->parsed->auth_info.flavor_len < 1;
+	auth_probe = mount_info->ctx->auth_info.flavor_len < 1;
 
 	/* set up the general RPC client */
-	error = nfs4_init_server(server, mount_info->parsed);
+	error = nfs4_init_server(server, mount_info->ctx);
 	if (error < 0)
 		goto error;
 
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 6fb7cb6b3f4b..70111f222a25 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -241,15 +241,15 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 	char *export_path;
 	struct vfsmount *root_mnt;
 	struct dentry *res;
-	struct nfs_parsed_mount_data *data = mount_info->parsed;
+	struct nfs_fs_context *ctx = mount_info->ctx;
 
 	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
-	export_path = data->nfs_server.export_path;
-	data->nfs_server.export_path = "/";
+	export_path = ctx->nfs_server.export_path;
+	ctx->nfs_server.export_path = "/";
 	root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
-			data->nfs_server.hostname);
-	data->nfs_server.export_path = export_path;
+			ctx->nfs_server.hostname);
+	ctx->nfs_server.export_path = export_path;
 
 	res = nfs_follow_remote_path(root_mnt, export_path);
 
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index e2d1e1baf3e8..0eb56748f651 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -710,11 +710,11 @@ bool nfs_auth_info_match(const struct nfs_auth_info *auth_info,
 EXPORT_SYMBOL_GPL(nfs_auth_info_match);
 
 /*
- * Ensure that a specified authtype in args->auth_info is supported by
- * the server. Returns 0 and sets args->selected_flavor if it's ok, and
+ * Ensure that a specified authtype in cfg->auth_info is supported by
+ * the server. Returns 0 and sets cfg->selected_flavor if it's ok, and
  * -EACCES if not.
  */
-static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
+static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
 			rpc_authflavor_t *server_authlist, unsigned int count)
 {
 	rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
@@ -732,7 +732,7 @@ static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
 	for (i = 0; i < count; i++) {
 		flavor = server_authlist[i];
 
-		if (nfs_auth_info_match(&args->auth_info, flavor))
+		if (nfs_auth_info_match(&cfg->auth_info, flavor))
 			goto out;
 
 		if (flavor == RPC_AUTH_NULL)
@@ -749,8 +749,8 @@ static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
 	return -EACCES;
 
 out:
-	args->selected_flavor = flavor;
-	dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->selected_flavor);
+	cfg->selected_flavor = flavor;
+	dfprintk(MOUNT, "NFS: using auth flavor %u\n", cfg->selected_flavor);
 	return 0;
 }
 
@@ -758,50 +758,50 @@ static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
  * Use the remote server's MOUNT service to request the NFS file handle
  * corresponding to the provided path.
  */
-static int nfs_request_mount(struct nfs_parsed_mount_data *args,
+static int nfs_request_mount(struct nfs_fs_context *cfg,
 			     struct nfs_fh *root_fh,
 			     rpc_authflavor_t *server_authlist,
 			     unsigned int *server_authlist_len)
 {
 	struct nfs_mount_request request = {
 		.sap		= (struct sockaddr *)
-						&args->mount_server.address,
-		.dirpath	= args->nfs_server.export_path,
-		.protocol	= args->mount_server.protocol,
+						&cfg->mount_server.address,
+		.dirpath	= cfg->nfs_server.export_path,
+		.protocol	= cfg->mount_server.protocol,
 		.fh		= root_fh,
-		.noresvport	= args->flags & NFS_MOUNT_NORESVPORT,
+		.noresvport	= cfg->flags & NFS_MOUNT_NORESVPORT,
 		.auth_flav_len	= server_authlist_len,
 		.auth_flavs	= server_authlist,
-		.net		= args->net,
+		.net		= cfg->net,
 	};
 	int status;
 
-	if (args->mount_server.version == 0) {
-		switch (args->version) {
+	if (cfg->mount_server.version == 0) {
+		switch (cfg->version) {
 			default:
-				args->mount_server.version = NFS_MNT3_VERSION;
+				cfg->mount_server.version = NFS_MNT3_VERSION;
 				break;
 			case 2:
-				args->mount_server.version = NFS_MNT_VERSION;
+				cfg->mount_server.version = NFS_MNT_VERSION;
 		}
 	}
-	request.version = args->mount_server.version;
+	request.version = cfg->mount_server.version;
 
-	if (args->mount_server.hostname)
-		request.hostname = args->mount_server.hostname;
+	if (cfg->mount_server.hostname)
+		request.hostname = cfg->mount_server.hostname;
 	else
-		request.hostname = args->nfs_server.hostname;
+		request.hostname = cfg->nfs_server.hostname;
 
 	/*
 	 * Construct the mount server's address.
 	 */
-	if (args->mount_server.address.ss_family == AF_UNSPEC) {
-		memcpy(request.sap, &args->nfs_server.address,
-		       args->nfs_server.addrlen);
-		args->mount_server.addrlen = args->nfs_server.addrlen;
+	if (cfg->mount_server.address.ss_family == AF_UNSPEC) {
+		memcpy(request.sap, &cfg->nfs_server.address,
+		       cfg->nfs_server.addrlen);
+		cfg->mount_server.addrlen = cfg->nfs_server.addrlen;
 	}
-	request.salen = args->mount_server.addrlen;
-	nfs_set_port(request.sap, &args->mount_server.port, 0);
+	request.salen = cfg->mount_server.addrlen;
+	nfs_set_port(request.sap, &cfg->mount_server.port, 0);
 
 	/*
 	 * Now ask the mount server to map our export path
@@ -825,11 +825,11 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 	bool tried_auth_unix = false;
 	bool auth_null_in_list = false;
 	struct nfs_server *server = ERR_PTR(-EACCES);
-	struct nfs_parsed_mount_data *args = mount_info->parsed;
+	struct nfs_fs_context *ctx = mount_info->ctx;
 	rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS];
 	unsigned int authlist_len = ARRAY_SIZE(authlist);
 
-	status = nfs_request_mount(args, mount_info->mntfh, authlist,
+	status = nfs_request_mount(ctx, mount_info->mntfh, authlist,
 					&authlist_len);
 	if (status)
 		return ERR_PTR(status);
@@ -838,10 +838,10 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 	 * Was a sec= authflavor specified in the options? First, verify
 	 * whether the server supports it, and then just try to use it if so.
 	 */
-	if (args->auth_info.flavor_len > 0) {
-		status = nfs_verify_authflavors(args, authlist, authlist_len);
+	if (ctx->auth_info.flavor_len > 0) {
+		status = nfs_verify_authflavors(ctx, authlist, authlist_len);
 		dfprintk(MOUNT, "NFS: using auth flavor %u\n",
-			 args->selected_flavor);
+			 ctx->selected_flavor);
 		if (status)
 			return ERR_PTR(status);
 		return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
@@ -870,7 +870,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 			/* Fallthrough */
 		}
 		dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor);
-		args->selected_flavor = flavor;
+		ctx->selected_flavor = flavor;
 		server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
 		if (!IS_ERR(server))
 			return server;
@@ -886,7 +886,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 
 	/* Last chance! Try AUTH_UNIX */
 	dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX);
-	args->selected_flavor = RPC_AUTH_UNIX;
+	ctx->selected_flavor = RPC_AUTH_UNIX;
 	return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
 }
 
@@ -896,7 +896,7 @@ struct dentry *nfs_try_mount(int flags, const char *dev_name,
 {
 	struct nfs_server *server;
 
-	if (mount_info->parsed->need_mount)
+	if (mount_info->ctx->need_mount)
 		server = nfs_try_mount_request(mount_info, nfs_mod);
 	else
 		server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
@@ -923,23 +923,23 @@ EXPORT_SYMBOL_GPL(nfs_try_mount);
 
 static int
 nfs_compare_remount_data(struct nfs_server *nfss,
-			 struct nfs_parsed_mount_data *data)
+			 struct nfs_fs_context *ctx)
 {
-	if ((data->flags ^ nfss->flags) & NFS_REMOUNT_CMP_FLAGMASK ||
-	    data->rsize != nfss->rsize ||
-	    data->wsize != nfss->wsize ||
-	    data->version != nfss->nfs_client->rpc_ops->version ||
-	    data->minorversion != nfss->nfs_client->cl_minorversion ||
-	    data->retrans != nfss->client->cl_timeout->to_retries ||
-	    !nfs_auth_info_match(&data->auth_info, nfss->client->cl_auth->au_flavor) ||
-	    data->acregmin != nfss->acregmin / HZ ||
-	    data->acregmax != nfss->acregmax / HZ ||
-	    data->acdirmin != nfss->acdirmin / HZ ||
-	    data->acdirmax != nfss->acdirmax / HZ ||
-	    data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) ||
-	    data->nfs_server.port != nfss->port ||
-	    data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen ||
-	    !rpc_cmp_addr((struct sockaddr *)&data->nfs_server.address,
+	if ((ctx->flags ^ nfss->flags) & NFS_REMOUNT_CMP_FLAGMASK ||
+	    ctx->rsize != nfss->rsize ||
+	    ctx->wsize != nfss->wsize ||
+	    ctx->version != nfss->nfs_client->rpc_ops->version ||
+	    ctx->minorversion != nfss->nfs_client->cl_minorversion ||
+	    ctx->retrans != nfss->client->cl_timeout->to_retries ||
+	    !nfs_auth_info_match(&ctx->auth_info, nfss->client->cl_auth->au_flavor) ||
+	    ctx->acregmin != nfss->acregmin / HZ ||
+	    ctx->acregmax != nfss->acregmax / HZ ||
+	    ctx->acdirmin != nfss->acdirmin / HZ ||
+	    ctx->acdirmax != nfss->acdirmax / HZ ||
+	    ctx->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) ||
+	    ctx->nfs_server.port != nfss->port ||
+	    ctx->nfs_server.addrlen != nfss->nfs_client->cl_addrlen ||
+	    !rpc_cmp_addr((struct sockaddr *)&ctx->nfs_server.address,
 			  (struct sockaddr *)&nfss->nfs_client->cl_addr))
 		return -EINVAL;
 
@@ -951,7 +951,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 {
 	int error;
 	struct nfs_server *nfss = sb->s_fs_info;
-	struct nfs_parsed_mount_data *data;
+	struct nfs_fs_context *ctx;
 	struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data;
 	struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data;
 	u32 nfsvers = nfss->nfs_client->rpc_ops->version;
@@ -969,32 +969,32 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 					   options->version <= 6))))
 		return 0;
 
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (data == NULL)
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (ctx == NULL)
 		return -ENOMEM;
 
 	/* fill out struct with values from existing mount */
-	data->flags = nfss->flags;
-	data->rsize = nfss->rsize;
-	data->wsize = nfss->wsize;
-	data->retrans = nfss->client->cl_timeout->to_retries;
-	data->selected_flavor = nfss->client->cl_auth->au_flavor;
-	data->acregmin = nfss->acregmin / HZ;
-	data->acregmax = nfss->acregmax / HZ;
-	data->acdirmin = nfss->acdirmin / HZ;
-	data->acdirmax = nfss->acdirmax / HZ;
-	data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
-	data->nfs_server.port = nfss->port;
-	data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
-	data->version = nfsvers;
-	data->minorversion = nfss->nfs_client->cl_minorversion;
-	data->net = current->nsproxy->net_ns;
-	memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr,
-		data->nfs_server.addrlen);
+	ctx->flags = nfss->flags;
+	ctx->rsize = nfss->rsize;
+	ctx->wsize = nfss->wsize;
+	ctx->retrans = nfss->client->cl_timeout->to_retries;
+	ctx->selected_flavor = nfss->client->cl_auth->au_flavor;
+	ctx->acregmin = nfss->acregmin / HZ;
+	ctx->acregmax = nfss->acregmax / HZ;
+	ctx->acdirmin = nfss->acdirmin / HZ;
+	ctx->acdirmax = nfss->acdirmax / HZ;
+	ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
+	ctx->nfs_server.port = nfss->port;
+	ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
+	ctx->version = nfsvers;
+	ctx->minorversion = nfss->nfs_client->cl_minorversion;
+	ctx->net = current->nsproxy->net_ns;
+	memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr,
+		ctx->nfs_server.addrlen);
 
 	/* overwrite those values with any that were specified */
 	error = -EINVAL;
-	if (!nfs_parse_mount_options((char *)options, data))
+	if (!nfs_parse_mount_options((char *)options, ctx))
 		goto out;
 
 	/*
@@ -1003,13 +1003,13 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 	 * will clear SB_SYNCHRONOUS if -o sync wasn't specified in the
 	 * remount options, so we have to explicitly reset it.
 	 */
-	if (data->flags & NFS_MOUNT_NOAC)
+	if (ctx->flags & NFS_MOUNT_NOAC)
 		*flags |= SB_SYNCHRONOUS;
 
 	/* compare new mount options with old ones */
-	error = nfs_compare_remount_data(nfss, data);
+	error = nfs_compare_remount_data(nfss, ctx);
 out:
-	kfree(data);
+	kfree(ctx);
 	return error;
 }
 EXPORT_SYMBOL_GPL(nfs_remount);
@@ -1039,15 +1039,15 @@ static void nfs_initialise_sb(struct super_block *sb)
  */
 void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
 {
-	struct nfs_parsed_mount_data *data = mount_info->parsed;
+	struct nfs_fs_context *ctx = mount_info->ctx;
 	struct nfs_server *server = NFS_SB(sb);
 
 	sb->s_blocksize_bits = 0;
 	sb->s_blocksize = 0;
 	sb->s_xattr = server->nfs_client->cl_nfs_mod->xattr;
 	sb->s_op = server->nfs_client->cl_nfs_mod->sops;
-	if (data && data->bsize)
-		sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
+	if (ctx && ctx->bsize)
+		sb->s_blocksize = nfs_block_size(ctx->bsize, &sb->s_blocksize_bits);
 
 	if (server->nfs_client->rpc_ops->version != 2) {
 		/* The VFS shouldn't apply the umask to mode bits. We will do
@@ -1199,7 +1199,7 @@ static int nfs_compare_super(struct super_block *sb, void *data)
 
 #ifdef CONFIG_NFS_FSCACHE
 static void nfs_get_cache_cookie(struct super_block *sb,
-				 struct nfs_parsed_mount_data *parsed,
+				 struct nfs_fs_context *ctx,
 				 struct nfs_clone_mount *cloned)
 {
 	struct nfs_server *nfss = NFS_SB(sb);
@@ -1209,12 +1209,12 @@ static void nfs_get_cache_cookie(struct super_block *sb,
 	nfss->fscache_key = NULL;
 	nfss->fscache = NULL;
 
-	if (parsed) {
-		if (!(parsed->options & NFS_OPTION_FSCACHE))
+	if (ctx) {
+		if (!(ctx->options & NFS_OPTION_FSCACHE))
 			return;
-		if (parsed->fscache_uniq) {
-			uniq = parsed->fscache_uniq;
-			ulen = strlen(parsed->fscache_uniq);
+		if (ctx->fscache_uniq) {
+			uniq = ctx->fscache_uniq;
+			ulen = strlen(ctx->fscache_uniq);
 		}
 	} else if (cloned) {
 		struct nfs_server *mnt_s = NFS_SB(cloned->sb);
@@ -1231,7 +1231,7 @@ static void nfs_get_cache_cookie(struct super_block *sb,
 }
 #else
 static void nfs_get_cache_cookie(struct super_block *sb,
-				 struct nfs_parsed_mount_data *parsed,
+				 struct nfs_fs_context *parsed,
 				 struct nfs_clone_mount *cloned)
 {
 }
@@ -1245,7 +1245,7 @@ int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
 	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
 		kflags |= SECURITY_LSM_NATIVE_LABELS;
 
-	error = security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts,
+	error = security_sb_set_mnt_opts(s, &mount_info->ctx->lsm_opts,
 						kflags, &kflags_out);
 	if (error)
 		goto err;
@@ -1317,7 +1317,7 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
 	if (!s->s_root) {
 		/* initial superblock/root creation */
 		mount_info->fill_super(s, mount_info);
-		nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned);
+		nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned);
 	}
 
 	mntroot = nfs_get_root(s, mount_info->mntfh, dev_name);
@@ -1357,21 +1357,21 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
 	struct nfs_subversion *nfs_mod;
 	int error;
 
-	mount_info.parsed = nfs_alloc_parsed_mount_data();
+	mount_info.ctx = nfs_alloc_parsed_mount_data();
 	mount_info.mntfh = nfs_alloc_fhandle();
-	if (mount_info.parsed == NULL || mount_info.mntfh == NULL)
+	if (mount_info.ctx == NULL || mount_info.mntfh == NULL)
 		goto out;
 
 	/* Validate the mount data */
-	error = nfs_validate_mount_data(fs_type, raw_data, mount_info.parsed, mount_info.mntfh, dev_name);
+	error = nfs_validate_mount_data(fs_type, raw_data, mount_info.ctx, mount_info.mntfh, dev_name);
 	if (error == NFS_TEXT_DATA)
-		error = nfs_validate_text_mount_data(raw_data, mount_info.parsed, dev_name);
+		error = nfs_validate_text_mount_data(raw_data, mount_info.ctx, dev_name);
 	if (error < 0) {
 		mntroot = ERR_PTR(error);
 		goto out;
 	}
 
-	nfs_mod = get_nfs_version(mount_info.parsed->version);
+	nfs_mod = get_nfs_version(mount_info.ctx->version);
 	if (IS_ERR(nfs_mod)) {
 		mntroot = ERR_CAST(nfs_mod);
 		goto out;
@@ -1381,7 +1381,7 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
 
 	put_nfs_version(nfs_mod);
 out:
-	nfs_free_parsed_mount_data(mount_info.parsed);
+	nfs_free_parsed_mount_data(mount_info.ctx);
 	nfs_free_fhandle(mount_info.mntfh);
 	return mntroot;
 }

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 20/27] NFS: Split nfs_parse_mount_options() [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (18 preceding siblings ...)
  2017-06-14 15:18 ` [PATCH 19/27] NFS: Rename struct nfs_parsed_mount_data to struct nfs_fs_context " David Howells
@ 2017-06-14 15:18 ` David Howells
  2017-06-14 15:18 ` [PATCH 21/27] NFS: Deindent nfs_fs_context_parse_option() " David Howells
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:18 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Split nfs_parse_mount_options() to move the prologue, list-splitting and
epilogue into one function and the per-option processing into another.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/nfs/fs_context.c |  143 +++++++++++++++++++++++++++++----------------------
 fs/nfs/internal.h   |    3 +
 2 files changed, 83 insertions(+), 63 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 91e412e68183..e3e431e3a1fc 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -494,46 +494,18 @@ static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
 }
 
 /*
- * Error-check and convert a string of mount options from user space into
- * a data structure.  The whole mount string is processed; bad options are
- * skipped as they are encountered.  If there were no errors, return 1;
- * otherwise return 0 (zero).
+ * Parse a single mount option in "key[=val]" form.
  */
-int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
+static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 {
-	char *p, *string, *secdata;
-	int rc, sloppy = 0, invalid_option = 0;
-	unsigned short protofamily = AF_UNSPEC;
-	unsigned short mountfamily = AF_UNSPEC;
-
-	if (!raw) {
-		dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
-		return 1;
-	}
-	dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
-
-	secdata = alloc_secdata();
-	if (!secdata)
-		goto out_nomem;
-
-	rc = security_sb_copy_data(raw, secdata);
-	if (rc)
-		goto out_security_failure;
-
-	rc = security_sb_parse_opts_str(secdata, &ctx->lsm_opts);
-	if (rc)
-		goto out_security_failure;
-
-	free_secdata(secdata);
+	char *string;
+	int rc;
 
-	while ((p = strsep(&raw, ",")) != NULL) {
+	{
 		substring_t args[MAX_OPT_ARGS];
 		unsigned long option;
 		int token;
 
-		if (!*p)
-			continue;
-
 		dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
 
 		token = match_token(p, nfs_mount_option_tokens, args);
@@ -737,7 +709,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 			if (!rc) {
 				dfprintk(MOUNT, "NFS:   unrecognized "
 						"security flavor\n");
-				return 0;
+				return -EINVAL;
 			}
 			break;
 		case Opt_proto:
@@ -747,22 +719,22 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 			token = match_token(string,
 					    nfs_xprt_protocol_tokens, args);
 
-			protofamily = AF_INET;
+			ctx->protofamily = AF_INET;
 			switch (token) {
 			case Opt_xprt_udp6:
-				protofamily = AF_INET6;
+				ctx->protofamily = AF_INET6;
 			case Opt_xprt_udp:
 				ctx->flags &= ~NFS_MOUNT_TCP;
 				ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
 				break;
 			case Opt_xprt_tcp6:
-				protofamily = AF_INET6;
+				ctx->protofamily = AF_INET6;
 			case Opt_xprt_tcp:
 				ctx->flags |= NFS_MOUNT_TCP;
 				ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
 				break;
 			case Opt_xprt_rdma6:
-				protofamily = AF_INET6;
+				ctx->protofamily = AF_INET6;
 			case Opt_xprt_rdma:
 				/* vector side protocols to TCP */
 				ctx->flags |= NFS_MOUNT_TCP;
@@ -773,7 +745,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 				dfprintk(MOUNT, "NFS:   unrecognized "
 						"transport protocol\n");
 				kfree(string);
-				return 0;
+				return -EINVAL;
 			}
 			kfree(string);
 			break;
@@ -785,15 +757,15 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 					    nfs_xprt_protocol_tokens, args);
 			kfree(string);
 
-			mountfamily = AF_INET;
+			ctx->mountfamily = AF_INET;
 			switch (token) {
 			case Opt_xprt_udp6:
-				mountfamily = AF_INET6;
+				ctx->mountfamily = AF_INET6;
 			case Opt_xprt_udp:
 				ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
 				break;
 			case Opt_xprt_tcp6:
-				mountfamily = AF_INET6;
+				ctx->mountfamily = AF_INET6;
 			case Opt_xprt_tcp:
 				ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
 				break;
@@ -801,7 +773,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 			default:
 				dfprintk(MOUNT, "NFS:   unrecognized "
 						"transport protocol\n");
-				return 0;
+				return -EINVAL;
 			}
 			break;
 		case Opt_addr:
@@ -860,7 +832,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 				default:
 					dfprintk(MOUNT, "NFS:   invalid "
 							"lookupcache argument\n");
-					return 0;
+					return -EINVAL;
 			};
 			break;
 		case Opt_fscache_uniq:
@@ -893,7 +865,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 			default:
 				dfprintk(MOUNT, "NFS:	invalid	"
 						"local_lock argument\n");
-				return 0;
+				return -EINVAL;
 			};
 			break;
 
@@ -901,7 +873,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 		 * Special options
 		 */
 		case Opt_sloppy:
-			sloppy = 1;
+			ctx->sloppy = 1;
 			dfprintk(MOUNT, "NFS:   relaxing parsing rules\n");
 			break;
 		case Opt_userspace:
@@ -911,12 +883,63 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 			break;
 
 		default:
-			invalid_option = 1;
 			dfprintk(MOUNT, "NFS:   unrecognized mount option "
 					"'%s'\n", p);
+			return -EINVAL;
 		}
 	}
 
+	return 0;
+
+out_invalid_address:
+	printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
+	return -EINVAL;
+out_invalid_value:
+	printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
+	return -EINVAL;
+out_nomem:
+	printk(KERN_INFO "NFS: not enough memory to parse option\n");
+	return -ENOMEM;
+}
+
+/*
+ * Error-check and convert a string of mount options from user space into
+ * a data structure.  The whole mount string is processed; bad options are
+ * skipped as they are encountered.  If there were no errors, return 1;
+ * otherwise return 0 (zero).
+ */
+int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
+{
+	char *p, *secdata;
+	int rc, sloppy = 0, invalid_option = 0;
+
+	if (!raw) {
+		dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
+		return 1;
+	}
+	dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
+
+	secdata = alloc_secdata();
+	if (!secdata)
+		goto out_nomem;
+
+	rc = security_sb_copy_data(raw, secdata);
+	if (rc)
+		goto out_security_failure;
+
+	rc = security_sb_parse_opts_str(secdata, &ctx->lsm_opts);
+	if (rc)
+		goto out_security_failure;
+
+	free_secdata(secdata);
+
+	while ((p = strsep(&raw, ",")) != NULL) {
+		if (!*p)
+			continue;
+		if (nfs_fs_context_parse_option(ctx, p) < 0)
+			invalid_option = true;
+	}
+
 	if (!sloppy && invalid_option)
 		return 0;
 
@@ -931,22 +954,26 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 	 * verify that any proto=/mountproto= options match the address
 	 * families in the addr=/mountaddr= options.
 	 */
-	if (protofamily != AF_UNSPEC &&
-	    protofamily != ctx->nfs_server.address.ss_family)
+	if (ctx->protofamily != AF_UNSPEC &&
+	    ctx->protofamily != ctx->nfs_server.address.ss_family)
 		goto out_proto_mismatch;
 
-	if (mountfamily != AF_UNSPEC) {
+	if (ctx->mountfamily != AF_UNSPEC) {
 		if (ctx->mount_server.addrlen) {
-			if (mountfamily != ctx->mount_server.address.ss_family)
+			if (ctx->mountfamily != ctx->mount_server.address.ss_family)
 				goto out_mountproto_mismatch;
 		} else {
-			if (mountfamily != ctx->nfs_server.address.ss_family)
+			if (ctx->mountfamily != ctx->nfs_server.address.ss_family)
 				goto out_mountproto_mismatch;
 		}
 	}
 
 	return 1;
 
+out_minorversion_mismatch:
+	printk(KERN_INFO "NFS: mount option vers=%u does not support "
+			 "minorversion=%u\n", ctx->version, ctx->minorversion);
+	return 0;
 out_mountproto_mismatch:
 	printk(KERN_INFO "NFS: mount server address does not match mountproto= "
 			 "option\n");
@@ -954,20 +981,10 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 out_proto_mismatch:
 	printk(KERN_INFO "NFS: server address does not match proto= option\n");
 	return 0;
-out_invalid_address:
-	printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
-	return 0;
-out_invalid_value:
-	printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
-	return 0;
-out_minorversion_mismatch:
-	printk(KERN_INFO "NFS: mount option vers=%u does not support "
-			 "minorversion=%u\n", ctx->version, ctx->minorversion);
-	return 0;
 out_migration_misuse:
 	printk(KERN_INFO
 		"NFS: 'migration' not supported for this NFS version\n");
-	return 0;
+	return -EINVAL;
 out_nomem:
 	printk(KERN_INFO "NFS: not enough memory to parse option\n");
 	return 0;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 990e0d4d59fa..fab0fca9e0ef 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -100,7 +100,10 @@ struct nfs_fs_context {
 	unsigned int		version;
 	unsigned int		minorversion;
 	char			*fscache_uniq;
+	unsigned short		protofamily;
+	unsigned short		mountfamily;
 	bool			need_mount;
+	bool			sloppy;
 
 	struct {
 		struct sockaddr_storage	address;

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 21/27] NFS: Deindent nfs_fs_context_parse_option() [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (19 preceding siblings ...)
  2017-06-14 15:18 ` [PATCH 20/27] NFS: Split nfs_parse_mount_options() " David Howells
@ 2017-06-14 15:18 ` David Howells
  2017-06-14 15:18 ` [PATCH 22/27] NFS: Add a small buffer in nfs_fs_context to avoid string dup " David Howells
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:18 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Deindent nfs_fs_context_parse_option().

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/nfs/fs_context.c |  706 +++++++++++++++++++++++++--------------------------
 1 file changed, 351 insertions(+), 355 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index e3e431e3a1fc..a2ff9c30ff5a 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -498,395 +498,391 @@ static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
  */
 static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 {
+	substring_t args[MAX_OPT_ARGS];
+	unsigned long option;
 	char *string;
-	int rc;
-
-	{
-		substring_t args[MAX_OPT_ARGS];
-		unsigned long option;
-		int token;
+	int rc, token;
 
-		dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
+	dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
 
-		token = match_token(p, nfs_mount_option_tokens, args);
-		switch (token) {
+	token = match_token(p, nfs_mount_option_tokens, args);
+	switch (token) {
 
 		/*
 		 * boolean options:  foo/nofoo
 		 */
-		case Opt_soft:
-			ctx->flags |= NFS_MOUNT_SOFT;
-			break;
-		case Opt_hard:
-			ctx->flags &= ~NFS_MOUNT_SOFT;
-			break;
-		case Opt_posix:
-			ctx->flags |= NFS_MOUNT_POSIX;
-			break;
-		case Opt_noposix:
-			ctx->flags &= ~NFS_MOUNT_POSIX;
-			break;
-		case Opt_cto:
-			ctx->flags &= ~NFS_MOUNT_NOCTO;
-			break;
-		case Opt_nocto:
-			ctx->flags |= NFS_MOUNT_NOCTO;
-			break;
-		case Opt_ac:
-			ctx->flags &= ~NFS_MOUNT_NOAC;
-			break;
-		case Opt_noac:
-			ctx->flags |= NFS_MOUNT_NOAC;
-			break;
-		case Opt_lock:
-			ctx->flags &= ~NFS_MOUNT_NONLM;
-			ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
-					NFS_MOUNT_LOCAL_FCNTL);
-			break;
-		case Opt_nolock:
-			ctx->flags |= NFS_MOUNT_NONLM;
-			ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
-				       NFS_MOUNT_LOCAL_FCNTL);
-			break;
-		case Opt_udp:
-			ctx->flags &= ~NFS_MOUNT_TCP;
-			ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
-			break;
-		case Opt_tcp:
-			ctx->flags |= NFS_MOUNT_TCP;
-			ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-			break;
-		case Opt_rdma:
-			ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */
-			ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
-			xprt_load_transport(p);
-			break;
-		case Opt_acl:
-			ctx->flags &= ~NFS_MOUNT_NOACL;
-			break;
-		case Opt_noacl:
-			ctx->flags |= NFS_MOUNT_NOACL;
-			break;
-		case Opt_rdirplus:
-			ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
-			break;
-		case Opt_nordirplus:
-			ctx->flags |= NFS_MOUNT_NORDIRPLUS;
-			break;
-		case Opt_sharecache:
-			ctx->flags &= ~NFS_MOUNT_UNSHARED;
-			break;
-		case Opt_nosharecache:
-			ctx->flags |= NFS_MOUNT_UNSHARED;
-			break;
-		case Opt_resvport:
-			ctx->flags &= ~NFS_MOUNT_NORESVPORT;
-			break;
-		case Opt_noresvport:
-			ctx->flags |= NFS_MOUNT_NORESVPORT;
-			break;
-		case Opt_fscache:
-			ctx->options |= NFS_OPTION_FSCACHE;
-			kfree(ctx->fscache_uniq);
-			ctx->fscache_uniq = NULL;
-			break;
-		case Opt_nofscache:
-			ctx->options &= ~NFS_OPTION_FSCACHE;
-			kfree(ctx->fscache_uniq);
-			ctx->fscache_uniq = NULL;
-			break;
-		case Opt_migration:
-			ctx->options |= NFS_OPTION_MIGRATION;
-			break;
-		case Opt_nomigration:
-			ctx->options &= NFS_OPTION_MIGRATION;
-			break;
+	case Opt_soft:
+		ctx->flags |= NFS_MOUNT_SOFT;
+		break;
+	case Opt_hard:
+		ctx->flags &= ~NFS_MOUNT_SOFT;
+		break;
+	case Opt_posix:
+		ctx->flags |= NFS_MOUNT_POSIX;
+		break;
+	case Opt_noposix:
+		ctx->flags &= ~NFS_MOUNT_POSIX;
+		break;
+	case Opt_cto:
+		ctx->flags &= ~NFS_MOUNT_NOCTO;
+		break;
+	case Opt_nocto:
+		ctx->flags |= NFS_MOUNT_NOCTO;
+		break;
+	case Opt_ac:
+		ctx->flags &= ~NFS_MOUNT_NOAC;
+		break;
+	case Opt_noac:
+		ctx->flags |= NFS_MOUNT_NOAC;
+		break;
+	case Opt_lock:
+		ctx->flags &= ~NFS_MOUNT_NONLM;
+		ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+				NFS_MOUNT_LOCAL_FCNTL);
+		break;
+	case Opt_nolock:
+		ctx->flags |= NFS_MOUNT_NONLM;
+		ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+			       NFS_MOUNT_LOCAL_FCNTL);
+		break;
+	case Opt_udp:
+		ctx->flags &= ~NFS_MOUNT_TCP;
+		ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+		break;
+	case Opt_tcp:
+		ctx->flags |= NFS_MOUNT_TCP;
+		ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+		break;
+	case Opt_rdma:
+		ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */
+		ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+		xprt_load_transport(p);
+		break;
+	case Opt_acl:
+		ctx->flags &= ~NFS_MOUNT_NOACL;
+		break;
+	case Opt_noacl:
+		ctx->flags |= NFS_MOUNT_NOACL;
+		break;
+	case Opt_rdirplus:
+		ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
+		break;
+	case Opt_nordirplus:
+		ctx->flags |= NFS_MOUNT_NORDIRPLUS;
+		break;
+	case Opt_sharecache:
+		ctx->flags &= ~NFS_MOUNT_UNSHARED;
+		break;
+	case Opt_nosharecache:
+		ctx->flags |= NFS_MOUNT_UNSHARED;
+		break;
+	case Opt_resvport:
+		ctx->flags &= ~NFS_MOUNT_NORESVPORT;
+		break;
+	case Opt_noresvport:
+		ctx->flags |= NFS_MOUNT_NORESVPORT;
+		break;
+	case Opt_fscache:
+		ctx->options |= NFS_OPTION_FSCACHE;
+		kfree(ctx->fscache_uniq);
+		ctx->fscache_uniq = NULL;
+		break;
+	case Opt_nofscache:
+		ctx->options &= ~NFS_OPTION_FSCACHE;
+		kfree(ctx->fscache_uniq);
+		ctx->fscache_uniq = NULL;
+		break;
+	case Opt_migration:
+		ctx->options |= NFS_OPTION_MIGRATION;
+		break;
+	case Opt_nomigration:
+		ctx->options &= NFS_OPTION_MIGRATION;
+		break;
 
 		/*
 		 * options that take numeric values
 		 */
-		case Opt_port:
-			if (nfs_get_option_ul(args, &option) ||
-			    option > USHRT_MAX)
-				goto out_invalid_value;
-			ctx->nfs_server.port = option;
-			break;
-		case Opt_rsize:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			ctx->rsize = option;
-			break;
-		case Opt_wsize:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			ctx->wsize = option;
-			break;
-		case Opt_bsize:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			ctx->bsize = option;
-			break;
-		case Opt_timeo:
-			if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
-				goto out_invalid_value;
-			ctx->timeo = option;
-			break;
-		case Opt_retrans:
-			if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
-				goto out_invalid_value;
-			ctx->retrans = option;
-			break;
-		case Opt_acregmin:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			ctx->acregmin = option;
-			break;
-		case Opt_acregmax:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			ctx->acregmax = option;
-			break;
-		case Opt_acdirmin:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			ctx->acdirmin = option;
-			break;
-		case Opt_acdirmax:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			ctx->acdirmax = option;
-			break;
-		case Opt_actimeo:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			ctx->acregmin = ctx->acregmax =
+	case Opt_port:
+		if (nfs_get_option_ul(args, &option) ||
+		    option > USHRT_MAX)
+			goto out_invalid_value;
+		ctx->nfs_server.port = option;
+		break;
+	case Opt_rsize:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		ctx->rsize = option;
+		break;
+	case Opt_wsize:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		ctx->wsize = option;
+		break;
+	case Opt_bsize:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		ctx->bsize = option;
+		break;
+	case Opt_timeo:
+		if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
+			goto out_invalid_value;
+		ctx->timeo = option;
+		break;
+	case Opt_retrans:
+		if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
+			goto out_invalid_value;
+		ctx->retrans = option;
+		break;
+	case Opt_acregmin:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		ctx->acregmin = option;
+		break;
+	case Opt_acregmax:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		ctx->acregmax = option;
+		break;
+	case Opt_acdirmin:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		ctx->acdirmin = option;
+		break;
+	case Opt_acdirmax:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		ctx->acdirmax = option;
+		break;
+	case Opt_actimeo:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		ctx->acregmin = ctx->acregmax =
 			ctx->acdirmin = ctx->acdirmax = option;
-			break;
-		case Opt_namelen:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			ctx->namlen = option;
-			break;
-		case Opt_mountport:
-			if (nfs_get_option_ul(args, &option) ||
-			    option > USHRT_MAX)
-				goto out_invalid_value;
-			ctx->mount_server.port = option;
-			break;
-		case Opt_mountvers:
-			if (nfs_get_option_ul(args, &option) ||
-			    option < NFS_MNT_VERSION ||
-			    option > NFS_MNT3_VERSION)
-				goto out_invalid_value;
-			ctx->mount_server.version = option;
-			break;
-		case Opt_minorversion:
-			if (nfs_get_option_ul(args, &option))
-				goto out_invalid_value;
-			if (option > NFS4_MAX_MINOR_VERSION)
-				goto out_invalid_value;
-			ctx->minorversion = option;
-			break;
+		break;
+	case Opt_namelen:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		ctx->namlen = option;
+		break;
+	case Opt_mountport:
+		if (nfs_get_option_ul(args, &option) ||
+		    option > USHRT_MAX)
+			goto out_invalid_value;
+		ctx->mount_server.port = option;
+		break;
+	case Opt_mountvers:
+		if (nfs_get_option_ul(args, &option) ||
+		    option < NFS_MNT_VERSION ||
+		    option > NFS_MNT3_VERSION)
+			goto out_invalid_value;
+		ctx->mount_server.version = option;
+		break;
+	case Opt_minorversion:
+		if (nfs_get_option_ul(args, &option))
+			goto out_invalid_value;
+		if (option > NFS4_MAX_MINOR_VERSION)
+			goto out_invalid_value;
+		ctx->minorversion = option;
+		break;
 
 		/*
 		 * options that take text values
 		 */
-		case Opt_nfsvers:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			rc = nfs_parse_version_string(string, ctx, args);
-			kfree(string);
-			if (!rc)
-				goto out_invalid_value;
+	case Opt_nfsvers:
+		string = match_strdup(args);
+		if (string == NULL)
+			goto out_nomem;
+		rc = nfs_parse_version_string(string, ctx, args);
+		kfree(string);
+		if (!rc)
+			goto out_invalid_value;
+		break;
+	case Opt_sec:
+		string = match_strdup(args);
+		if (string == NULL)
+			goto out_nomem;
+		rc = nfs_parse_security_flavors(string, ctx);
+		kfree(string);
+		if (!rc) {
+			dfprintk(MOUNT, "NFS:   unrecognized "
+				 "security flavor\n");
+			return -EINVAL;
+		}
+		break;
+	case Opt_proto:
+		string = match_strdup(args);
+		if (string == NULL)
+			goto out_nomem;
+		token = match_token(string,
+				    nfs_xprt_protocol_tokens, args);
+
+		ctx->protofamily = AF_INET;
+		switch (token) {
+		case Opt_xprt_udp6:
+			ctx->protofamily = AF_INET6;
+		case Opt_xprt_udp:
+			ctx->flags &= ~NFS_MOUNT_TCP;
+			ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
 			break;
-		case Opt_sec:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			rc = nfs_parse_security_flavors(string, ctx);
-			kfree(string);
-			if (!rc) {
-				dfprintk(MOUNT, "NFS:   unrecognized "
-						"security flavor\n");
-				return -EINVAL;
-			}
+		case Opt_xprt_tcp6:
+			ctx->protofamily = AF_INET6;
+		case Opt_xprt_tcp:
+			ctx->flags |= NFS_MOUNT_TCP;
+			ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
 			break;
-		case Opt_proto:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			token = match_token(string,
-					    nfs_xprt_protocol_tokens, args);
-
-			ctx->protofamily = AF_INET;
-			switch (token) {
-			case Opt_xprt_udp6:
-				ctx->protofamily = AF_INET6;
-			case Opt_xprt_udp:
-				ctx->flags &= ~NFS_MOUNT_TCP;
-				ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
-				break;
-			case Opt_xprt_tcp6:
-				ctx->protofamily = AF_INET6;
-			case Opt_xprt_tcp:
-				ctx->flags |= NFS_MOUNT_TCP;
-				ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-				break;
-			case Opt_xprt_rdma6:
-				ctx->protofamily = AF_INET6;
-			case Opt_xprt_rdma:
-				/* vector side protocols to TCP */
-				ctx->flags |= NFS_MOUNT_TCP;
-				ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
-				xprt_load_transport(string);
-				break;
-			default:
-				dfprintk(MOUNT, "NFS:   unrecognized "
-						"transport protocol\n");
-				kfree(string);
-				return -EINVAL;
-			}
-			kfree(string);
+		case Opt_xprt_rdma6:
+			ctx->protofamily = AF_INET6;
+		case Opt_xprt_rdma:
+			/* vector side protocols to TCP */
+			ctx->flags |= NFS_MOUNT_TCP;
+			ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+			xprt_load_transport(string);
 			break;
-		case Opt_mountproto:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			token = match_token(string,
-					    nfs_xprt_protocol_tokens, args);
+		default:
+			dfprintk(MOUNT, "NFS:   unrecognized "
+				 "transport protocol\n");
 			kfree(string);
+			return -EINVAL;
+		}
+		kfree(string);
+		break;
+	case Opt_mountproto:
+		string = match_strdup(args);
+		if (string == NULL)
+			goto out_nomem;
+		token = match_token(string,
+				    nfs_xprt_protocol_tokens, args);
+		kfree(string);
 
-			ctx->mountfamily = AF_INET;
-			switch (token) {
-			case Opt_xprt_udp6:
-				ctx->mountfamily = AF_INET6;
-			case Opt_xprt_udp:
-				ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
-				break;
-			case Opt_xprt_tcp6:
-				ctx->mountfamily = AF_INET6;
-			case Opt_xprt_tcp:
-				ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
-				break;
-			case Opt_xprt_rdma: /* not used for side protocols */
-			default:
-				dfprintk(MOUNT, "NFS:   unrecognized "
-						"transport protocol\n");
-				return -EINVAL;
-			}
+		ctx->mountfamily = AF_INET;
+		switch (token) {
+		case Opt_xprt_udp6:
+			ctx->mountfamily = AF_INET6;
+		case Opt_xprt_udp:
+			ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
 			break;
-		case Opt_addr:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			ctx->nfs_server.addrlen =
-				rpc_pton(ctx->net, string, strlen(string),
-					(struct sockaddr *)
-					&ctx->nfs_server.address,
-					sizeof(ctx->nfs_server.address));
-			kfree(string);
-			if (ctx->nfs_server.addrlen == 0)
-				goto out_invalid_address;
+		case Opt_xprt_tcp6:
+			ctx->mountfamily = AF_INET6;
+		case Opt_xprt_tcp:
+			ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
 			break;
-		case Opt_clientaddr:
-			if (nfs_get_option_str(args, &ctx->client_address))
-				goto out_nomem;
+		case Opt_xprt_rdma: /* not used for side protocols */
+		default:
+			dfprintk(MOUNT, "NFS:   unrecognized "
+				 "transport protocol\n");
+			return -EINVAL;
+		}
+		break;
+	case Opt_addr:
+		string = match_strdup(args);
+		if (string == NULL)
+			goto out_nomem;
+		ctx->nfs_server.addrlen =
+			rpc_pton(ctx->net, string, strlen(string),
+				 (struct sockaddr *)
+				 &ctx->nfs_server.address,
+				 sizeof(ctx->nfs_server.address));
+		kfree(string);
+		if (ctx->nfs_server.addrlen == 0)
+			goto out_invalid_address;
+		break;
+	case Opt_clientaddr:
+		if (nfs_get_option_str(args, &ctx->client_address))
+			goto out_nomem;
+		break;
+	case Opt_mounthost:
+		if (nfs_get_option_str(args,
+				       &ctx->mount_server.hostname))
+			goto out_nomem;
+		break;
+	case Opt_mountaddr:
+		string = match_strdup(args);
+		if (string == NULL)
+			goto out_nomem;
+		ctx->mount_server.addrlen =
+			rpc_pton(ctx->net, string, strlen(string),
+				 (struct sockaddr *)
+				 &ctx->mount_server.address,
+				 sizeof(ctx->mount_server.address));
+		kfree(string);
+		if (ctx->mount_server.addrlen == 0)
+			goto out_invalid_address;
+		break;
+	case Opt_lookupcache:
+		string = match_strdup(args);
+		if (string == NULL)
+			goto out_nomem;
+		token = match_token(string,
+				    nfs_lookupcache_tokens, args);
+		kfree(string);
+		switch (token) {
+		case Opt_lookupcache_all:
+			ctx->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
 			break;
-		case Opt_mounthost:
-			if (nfs_get_option_str(args,
-					       &ctx->mount_server.hostname))
-				goto out_nomem;
+		case Opt_lookupcache_positive:
+			ctx->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
+			ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
 			break;
-		case Opt_mountaddr:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			ctx->mount_server.addrlen =
-				rpc_pton(ctx->net, string, strlen(string),
-					(struct sockaddr *)
-					&ctx->mount_server.address,
-					sizeof(ctx->mount_server.address));
-			kfree(string);
-			if (ctx->mount_server.addrlen == 0)
-				goto out_invalid_address;
+		case Opt_lookupcache_none:
+			ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
 			break;
-		case Opt_lookupcache:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			token = match_token(string,
-					nfs_lookupcache_tokens, args);
-			kfree(string);
-			switch (token) {
-				case Opt_lookupcache_all:
-					ctx->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
-					break;
-				case Opt_lookupcache_positive:
-					ctx->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
-					ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
-					break;
-				case Opt_lookupcache_none:
-					ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
-					break;
-				default:
-					dfprintk(MOUNT, "NFS:   invalid "
-							"lookupcache argument\n");
-					return -EINVAL;
-			};
+		default:
+			dfprintk(MOUNT, "NFS:   invalid "
+				 "lookupcache argument\n");
+			return -EINVAL;
+		};
+		break;
+	case Opt_fscache_uniq:
+		if (nfs_get_option_str(args, &ctx->fscache_uniq))
+			goto out_nomem;
+		ctx->options |= NFS_OPTION_FSCACHE;
+		break;
+	case Opt_local_lock:
+		string = match_strdup(args);
+		if (string == NULL)
+			goto out_nomem;
+		token = match_token(string, nfs_local_lock_tokens,
+				    args);
+		kfree(string);
+		switch (token) {
+		case Opt_local_lock_all:
+			ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+				       NFS_MOUNT_LOCAL_FCNTL);
 			break;
-		case Opt_fscache_uniq:
-			if (nfs_get_option_str(args, &ctx->fscache_uniq))
-				goto out_nomem;
-			ctx->options |= NFS_OPTION_FSCACHE;
+		case Opt_local_lock_flock:
+			ctx->flags |= NFS_MOUNT_LOCAL_FLOCK;
 			break;
-		case Opt_local_lock:
-			string = match_strdup(args);
-			if (string == NULL)
-				goto out_nomem;
-			token = match_token(string, nfs_local_lock_tokens,
-					args);
-			kfree(string);
-			switch (token) {
-			case Opt_local_lock_all:
-				ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
-					       NFS_MOUNT_LOCAL_FCNTL);
-				break;
-			case Opt_local_lock_flock:
-				ctx->flags |= NFS_MOUNT_LOCAL_FLOCK;
-				break;
-			case Opt_local_lock_posix:
-				ctx->flags |= NFS_MOUNT_LOCAL_FCNTL;
-				break;
-			case Opt_local_lock_none:
-				ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
-						NFS_MOUNT_LOCAL_FCNTL);
-				break;
-			default:
-				dfprintk(MOUNT, "NFS:	invalid	"
-						"local_lock argument\n");
-				return -EINVAL;
-			};
+		case Opt_local_lock_posix:
+			ctx->flags |= NFS_MOUNT_LOCAL_FCNTL;
 			break;
+		case Opt_local_lock_none:
+			ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+					NFS_MOUNT_LOCAL_FCNTL);
+			break;
+		default:
+			dfprintk(MOUNT, "NFS:	invalid	"
+				 "local_lock argument\n");
+			return -EINVAL;
+		};
+		break;
 
 		/*
 		 * Special options
 		 */
-		case Opt_sloppy:
-			ctx->sloppy = 1;
-			dfprintk(MOUNT, "NFS:   relaxing parsing rules\n");
-			break;
-		case Opt_userspace:
-		case Opt_deprecated:
-			dfprintk(MOUNT, "NFS:   ignoring mount option "
-					"'%s'\n", p);
-			break;
+	case Opt_sloppy:
+		ctx->sloppy = 1;
+		dfprintk(MOUNT, "NFS:   relaxing parsing rules\n");
+		break;
+	case Opt_userspace:
+	case Opt_deprecated:
+		dfprintk(MOUNT, "NFS:   ignoring mount option "
+			 "'%s'\n", p);
+		break;
 
-		default:
-			dfprintk(MOUNT, "NFS:   unrecognized mount option "
-					"'%s'\n", p);
-			return -EINVAL;
-		}
+	default:
+		dfprintk(MOUNT, "NFS:   unrecognized mount option "
+			 "'%s'\n", p);
+		return -EINVAL;
 	}
 
 	return 0;

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 22/27] NFS: Add a small buffer in nfs_fs_context to avoid string dup [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (20 preceding siblings ...)
  2017-06-14 15:18 ` [PATCH 21/27] NFS: Deindent nfs_fs_context_parse_option() " David Howells
@ 2017-06-14 15:18 ` David Howells
  2017-06-14 15:18 ` [PATCH 23/27] NFS: Do some tidying of the parsing code " David Howells
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:18 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Add a small buffer in nfs_fs_context to avoid string duplication when
parsing numbers.  Also make the parsing function wrapper place the parsed
integer directly in the appropriate nfs_fs_context struct member.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/nfs/fs_context.c |   83 ++++++++++++++++++---------------------------------
 fs/nfs/internal.h   |    2 +
 2 files changed, 32 insertions(+), 53 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index a2ff9c30ff5a..763a09b64971 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -466,27 +466,22 @@ static int nfs_get_option_str(substring_t args[], char **option)
 	return !*option;
 }
 
-static int nfs_get_option_ul(substring_t args[], unsigned long *option)
+static int nfs_get_option_ui(struct nfs_fs_context *ctx,
+			     substring_t args[], unsigned int *option)
 {
-	int rc;
-	char *string;
-
-	string = match_strdup(args);
-	if (string == NULL)
-		return -ENOMEM;
-	rc = kstrtoul(string, 10, option);
-	kfree(string);
-
-	return rc;
+	match_strlcpy(ctx->buf, args, sizeof(ctx->buf));
+	return kstrtouint(ctx->buf, 10, option);
 }
 
-static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
-		unsigned long l_bound, unsigned long u_bound)
+static int nfs_get_option_ui_bound(struct nfs_fs_context *ctx,
+				   substring_t args[], unsigned int *option,
+				   unsigned int l_bound, unsigned u_bound)
 {
 	int ret;
 
-	ret = nfs_get_option_ul(args, option);
-	if (ret != 0)
+	match_strlcpy(ctx->buf, args, sizeof(ctx->buf));
+	ret = kstrtouint(ctx->buf, 10, option);
+	if (ret < 0)
 		return ret;
 	if (*option < l_bound || *option > u_bound)
 		return -ERANGE;
@@ -499,7 +494,6 @@ static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
 static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 {
 	substring_t args[MAX_OPT_ARGS];
-	unsigned long option;
 	char *string;
 	int rc, token;
 
@@ -507,7 +501,6 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 
 	token = match_token(p, nfs_mount_option_tokens, args);
 	switch (token) {
-
 		/*
 		 * boolean options:  foo/nofoo
 		 */
@@ -603,86 +596,70 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		 * options that take numeric values
 		 */
 	case Opt_port:
-		if (nfs_get_option_ul(args, &option) ||
-		    option > USHRT_MAX)
+		if (nfs_get_option_ui_bound(ctx, args, &ctx->nfs_server.port,
+					    0, USHRT_MAX))
 			goto out_invalid_value;
-		ctx->nfs_server.port = option;
 		break;
 	case Opt_rsize:
-		if (nfs_get_option_ul(args, &option))
+		if (nfs_get_option_ui(ctx, args, &ctx->rsize))
 			goto out_invalid_value;
-		ctx->rsize = option;
 		break;
 	case Opt_wsize:
-		if (nfs_get_option_ul(args, &option))
+		if (nfs_get_option_ui(ctx, args, &ctx->wsize))
 			goto out_invalid_value;
-		ctx->wsize = option;
 		break;
 	case Opt_bsize:
-		if (nfs_get_option_ul(args, &option))
+		if (nfs_get_option_ui(ctx, args, &ctx->bsize))
 			goto out_invalid_value;
-		ctx->bsize = option;
 		break;
 	case Opt_timeo:
-		if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
+		if (nfs_get_option_ui_bound(ctx, args, &ctx->timeo, 1, INT_MAX))
 			goto out_invalid_value;
-		ctx->timeo = option;
 		break;
 	case Opt_retrans:
-		if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
+		if (nfs_get_option_ui_bound(ctx, args, &ctx->retrans, 0, INT_MAX))
 			goto out_invalid_value;
-		ctx->retrans = option;
 		break;
 	case Opt_acregmin:
-		if (nfs_get_option_ul(args, &option))
+		if (nfs_get_option_ui(ctx, args, &ctx->acregmin))
 			goto out_invalid_value;
-		ctx->acregmin = option;
 		break;
 	case Opt_acregmax:
-		if (nfs_get_option_ul(args, &option))
+		if (nfs_get_option_ui(ctx, args, &ctx->acregmax))
 			goto out_invalid_value;
-		ctx->acregmax = option;
 		break;
 	case Opt_acdirmin:
-		if (nfs_get_option_ul(args, &option))
+		if (nfs_get_option_ui(ctx, args, &ctx->acdirmin))
 			goto out_invalid_value;
-		ctx->acdirmin = option;
 		break;
 	case Opt_acdirmax:
-		if (nfs_get_option_ul(args, &option))
+		if (nfs_get_option_ui(ctx, args, &ctx->acdirmax))
 			goto out_invalid_value;
-		ctx->acdirmax = option;
 		break;
 	case Opt_actimeo:
-		if (nfs_get_option_ul(args, &option))
+		if (nfs_get_option_ui(ctx, args, &ctx->acdirmax))
 			goto out_invalid_value;
 		ctx->acregmin = ctx->acregmax =
-			ctx->acdirmin = ctx->acdirmax = option;
+			ctx->acdirmin = ctx->acdirmax;
 		break;
 	case Opt_namelen:
-		if (nfs_get_option_ul(args, &option))
+		if (nfs_get_option_ui(ctx, args, &ctx->namlen))
 			goto out_invalid_value;
-		ctx->namlen = option;
 		break;
 	case Opt_mountport:
-		if (nfs_get_option_ul(args, &option) ||
-		    option > USHRT_MAX)
+		if (nfs_get_option_ui_bound(ctx, args, &ctx->mount_server.port,
+					    0, USHRT_MAX))
 			goto out_invalid_value;
-		ctx->mount_server.port = option;
 		break;
 	case Opt_mountvers:
-		if (nfs_get_option_ul(args, &option) ||
-		    option < NFS_MNT_VERSION ||
-		    option > NFS_MNT3_VERSION)
+		if (nfs_get_option_ui_bound(ctx, args, &ctx->mount_server.version,
+					    NFS_MNT_VERSION, NFS_MNT3_VERSION))
 			goto out_invalid_value;
-		ctx->mount_server.version = option;
 		break;
 	case Opt_minorversion:
-		if (nfs_get_option_ul(args, &option))
-			goto out_invalid_value;
-		if (option > NFS4_MAX_MINOR_VERSION)
+		if (nfs_get_option_ui_bound(ctx, args, &ctx->minorversion,
+					    0, NFS4_MAX_MINOR_VERSION))
 			goto out_invalid_value;
-		ctx->minorversion = option;
 		break;
 
 		/*
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index fab0fca9e0ef..1c5404d846cc 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -125,6 +125,8 @@ struct nfs_fs_context {
 
 	struct security_mnt_opts lsm_opts;
 	struct net		*net;
+
+	char			buf[32];	/* Parse buffer */
 };
 
 /* mount_clnt.c */

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 23/27] NFS: Do some tidying of the parsing code [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (21 preceding siblings ...)
  2017-06-14 15:18 ` [PATCH 22/27] NFS: Add a small buffer in nfs_fs_context to avoid string dup " David Howells
@ 2017-06-14 15:18 ` David Howells
  2017-06-14 15:18 ` [PATCH 24/27] NFS: Add fs_context support. " David Howells
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:18 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Do some tidying of the parsing code, including:

 (*) Returning 0/error rather than true/false.

 (*) Putting the nfs_fs_context pointer first in some arg lists.

 (*) Unwrap some lines that will now fit on one line.

 (*) Provide unioned sockaddr/sockaddr_storage fields to avoid casts.

 (*) nfs_parse_devname() can paste its return values directly into the
     nfs_fs_context struct as that's where the caller puts them.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/nfs/fs_context.c |  128 ++++++++++++++++++++++-----------------------------
 fs/nfs/internal.h   |   16 ++++--
 fs/nfs/super.c      |    2 -
 3 files changed, 67 insertions(+), 79 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 763a09b64971..24becb82540f 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -341,8 +341,9 @@ static void nfs_set_mount_transport_protocol(struct nfs_fs_context *ctx)
  * Add 'flavor' to 'auth_info' if not already present.
  * Returns true if 'flavor' ends up in the list, false otherwise
  */
-static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
-			      rpc_authflavor_t flavor)
+static int nfs_auth_info_add(struct nfs_fs_context *ctx,
+			     struct nfs_auth_info *auth_info,
+			     rpc_authflavor_t flavor)
 {
 	unsigned int i;
 	unsigned int max_flavor_len = ARRAY_SIZE(auth_info->flavors);
@@ -350,26 +351,27 @@ static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
 	/* make sure this flavor isn't already in the list */
 	for (i = 0; i < auth_info->flavor_len; i++) {
 		if (flavor == auth_info->flavors[i])
-			return true;
+			return 0;
 	}
 
 	if (auth_info->flavor_len + 1 >= max_flavor_len) {
 		dfprintk(MOUNT, "NFS: too many sec= flavors\n");
-		return false;
+		return -EINVAL;
 	}
 
 	auth_info->flavors[auth_info->flavor_len++] = flavor;
-	return true;
+	return 0;
 }
 
 /*
  * Parse the value of the 'sec=' option.
  */
-static int nfs_parse_security_flavors(char *value, struct nfs_fs_context *ctx)
+static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value)
 {
 	substring_t args[MAX_OPT_ARGS];
 	rpc_authflavor_t pseudoflavor;
 	char *p;
+	int ret;
 
 	dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
 
@@ -411,19 +413,20 @@ static int nfs_parse_security_flavors(char *value, struct nfs_fs_context *ctx)
 		default:
 			dfprintk(MOUNT,
 				 "NFS: sec= option '%s' not recognized\n", p);
-			return 0;
+			return -EINVAL;
 		}
 
-		if (!nfs_auth_info_add(&ctx->auth_info, pseudoflavor))
-			return 0;
+		ret = nfs_auth_info_add(ctx, &ctx->auth_info, pseudoflavor);
+		if (ret < 0)
+			return ret;
 	}
 
-	return 1;
+	return 0;
 }
 
-static int nfs_parse_version_string(char *string,
-		struct nfs_fs_context *ctx,
-		substring_t *args)
+static int nfs_parse_version_string(struct nfs_fs_context *ctx,
+				    char *string,
+				    substring_t *args)
 {
 	ctx->flags &= ~NFS_MOUNT_VER3;
 	switch (match_token(string, nfs_vers_tokens, args)) {
@@ -454,9 +457,10 @@ static int nfs_parse_version_string(char *string,
 		ctx->minorversion = 2;
 		break;
 	default:
-		return 0;
+		dfprintk(MOUNT, "NFS:   Unsupported NFS version\n");
+		return -EINVAL;
 	}
-	return 1;
+	return 0;
 }
 
 static int nfs_get_option_str(substring_t args[], char **option)
@@ -495,7 +499,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 {
 	substring_t args[MAX_OPT_ARGS];
 	char *string;
-	int rc, token;
+	int ret, token;
 
 	dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
 
@@ -530,13 +534,11 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		break;
 	case Opt_lock:
 		ctx->flags &= ~NFS_MOUNT_NONLM;
-		ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
-				NFS_MOUNT_LOCAL_FCNTL);
+		ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
 		break;
 	case Opt_nolock:
 		ctx->flags |= NFS_MOUNT_NONLM;
-		ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
-			       NFS_MOUNT_LOCAL_FCNTL);
+		ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
 		break;
 	case Opt_udp:
 		ctx->flags &= ~NFS_MOUNT_TCP;
@@ -669,29 +671,25 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		string = match_strdup(args);
 		if (string == NULL)
 			goto out_nomem;
-		rc = nfs_parse_version_string(string, ctx, args);
+		ret = nfs_parse_version_string(ctx, string, args);
 		kfree(string);
-		if (!rc)
-			goto out_invalid_value;
+		if (ret < 0)
+			return ret;
 		break;
 	case Opt_sec:
 		string = match_strdup(args);
 		if (string == NULL)
 			goto out_nomem;
-		rc = nfs_parse_security_flavors(string, ctx);
+		ret = nfs_parse_security_flavors(ctx, string);
 		kfree(string);
-		if (!rc) {
-			dfprintk(MOUNT, "NFS:   unrecognized "
-				 "security flavor\n");
-			return -EINVAL;
-		}
+		if (ret < 0)
+			return ret;
 		break;
 	case Opt_proto:
 		string = match_strdup(args);
 		if (string == NULL)
 			goto out_nomem;
-		token = match_token(string,
-				    nfs_xprt_protocol_tokens, args);
+		token = match_token(string, nfs_xprt_protocol_tokens, args);
 
 		ctx->protofamily = AF_INET;
 		switch (token) {
@@ -716,9 +714,8 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			xprt_load_transport(string);
 			break;
 		default:
-			dfprintk(MOUNT, "NFS:   unrecognized "
-				 "transport protocol\n");
 			kfree(string);
+			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
 			return -EINVAL;
 		}
 		kfree(string);
@@ -727,8 +724,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		string = match_strdup(args);
 		if (string == NULL)
 			goto out_nomem;
-		token = match_token(string,
-				    nfs_xprt_protocol_tokens, args);
+		token = match_token(string, nfs_xprt_protocol_tokens, args);
 		kfree(string);
 
 		ctx->mountfamily = AF_INET;
@@ -745,8 +741,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			break;
 		case Opt_xprt_rdma: /* not used for side protocols */
 		default:
-			dfprintk(MOUNT, "NFS:   unrecognized "
-				 "transport protocol\n");
+			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
 			return -EINVAL;
 		}
 		break;
@@ -756,9 +751,8 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			goto out_nomem;
 		ctx->nfs_server.addrlen =
 			rpc_pton(ctx->net, string, strlen(string),
-				 (struct sockaddr *)
 				 &ctx->nfs_server.address,
-				 sizeof(ctx->nfs_server.address));
+				 sizeof(ctx->nfs_server._address));
 		kfree(string);
 		if (ctx->nfs_server.addrlen == 0)
 			goto out_invalid_address;
@@ -768,8 +762,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			goto out_nomem;
 		break;
 	case Opt_mounthost:
-		if (nfs_get_option_str(args,
-				       &ctx->mount_server.hostname))
+		if (nfs_get_option_str(args, &ctx->mount_server.hostname))
 			goto out_nomem;
 		break;
 	case Opt_mountaddr:
@@ -778,9 +771,8 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			goto out_nomem;
 		ctx->mount_server.addrlen =
 			rpc_pton(ctx->net, string, strlen(string),
-				 (struct sockaddr *)
 				 &ctx->mount_server.address,
-				 sizeof(ctx->mount_server.address));
+				 sizeof(ctx->mount_server._address));
 		kfree(string);
 		if (ctx->mount_server.addrlen == 0)
 			goto out_invalid_address;
@@ -789,8 +781,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		string = match_strdup(args);
 		if (string == NULL)
 			goto out_nomem;
-		token = match_token(string,
-				    nfs_lookupcache_tokens, args);
+		token = match_token(string, nfs_lookupcache_tokens, args);
 		kfree(string);
 		switch (token) {
 		case Opt_lookupcache_all:
@@ -804,10 +795,9 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
 			break;
 		default:
-			dfprintk(MOUNT, "NFS:   invalid "
-				 "lookupcache argument\n");
+			dfprintk(MOUNT, "NFS:   invalid lookupcache argument\n");
 			return -EINVAL;
-		};
+		}
 		break;
 	case Opt_fscache_uniq:
 		if (nfs_get_option_str(args, &ctx->fscache_uniq))
@@ -818,8 +808,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		string = match_strdup(args);
 		if (string == NULL)
 			goto out_nomem;
-		token = match_token(string, nfs_local_lock_tokens,
-				    args);
+		token = match_token(string, nfs_local_lock_tokens, args);
 		kfree(string);
 		switch (token) {
 		case Opt_local_lock_all:
@@ -837,8 +826,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 					NFS_MOUNT_LOCAL_FCNTL);
 			break;
 		default:
-			dfprintk(MOUNT, "NFS:	invalid	"
-				 "local_lock argument\n");
+			dfprintk(MOUNT, "NFS:	invalid	local_lock argument\n");
 			return -EINVAL;
 		};
 		break;
@@ -852,13 +840,11 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		break;
 	case Opt_userspace:
 	case Opt_deprecated:
-		dfprintk(MOUNT, "NFS:   ignoring mount option "
-			 "'%s'\n", p);
+		dfprintk(MOUNT, "NFS:   ignoring mount option '%s'\n", p);
 		break;
 
 	default:
-		dfprintk(MOUNT, "NFS:   unrecognized mount option "
-			 "'%s'\n", p);
+		dfprintk(MOUNT, "NFS:   unrecognized mount option '%s'\n", p);
 		return -EINVAL;
 	}
 
@@ -928,15 +914,15 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 	 * families in the addr=/mountaddr= options.
 	 */
 	if (ctx->protofamily != AF_UNSPEC &&
-	    ctx->protofamily != ctx->nfs_server.address.ss_family)
+	    ctx->protofamily != ctx->nfs_server.address.sa_family)
 		goto out_proto_mismatch;
 
 	if (ctx->mountfamily != AF_UNSPEC) {
 		if (ctx->mount_server.addrlen) {
-			if (ctx->mountfamily != ctx->mount_server.address.ss_family)
+			if (ctx->mountfamily != ctx->mount_server.address.sa_family)
 				goto out_mountproto_mismatch;
 		} else {
-			if (ctx->mountfamily != ctx->nfs_server.address.ss_family)
+			if (ctx->mountfamily != ctx->nfs_server.address.sa_family)
 				goto out_mountproto_mismatch;
 		}
 	}
@@ -976,9 +962,9 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
  *
  * Note: caller frees hostname and export path, even on error.
  */
-static int nfs_parse_devname(const char *dev_name,
-			     char **hostname, size_t maxnamlen,
-			     char **export_path, size_t maxpathlen)
+static int nfs_parse_devname(struct nfs_fs_context *ctx,
+			     const char *dev_name,
+			     size_t maxnamlen, size_t maxpathlen)
 {
 	size_t len;
 	char *end;
@@ -1009,17 +995,17 @@ static int nfs_parse_devname(const char *dev_name,
 		goto out_hostname;
 
 	/* N.B. caller will free nfs_server.hostname in all cases */
-	*hostname = kstrndup(dev_name, len, GFP_KERNEL);
-	if (*hostname == NULL)
+	ctx->nfs_server.hostname = kmemdup_nul(dev_name, len, GFP_KERNEL);
+	if (!ctx->nfs_server.hostname)
 		goto out_nomem;
 	len = strlen(++end);
 	if (len > maxpathlen)
 		goto out_path;
-	*export_path = kstrndup(end, len, GFP_KERNEL);
-	if (!*export_path)
+	ctx->nfs_server.export_path = kmemdup_nul(end, len, GFP_KERNEL);
+	if (!ctx->nfs_server.export_path)
 		goto out_nomem;
 
-	dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
+	dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", ctx->nfs_server.export_path);
 	return 0;
 
 out_bad_devname:
@@ -1040,7 +1026,7 @@ static int nfs_parse_devname(const char *dev_name,
 }
 
 /*
- * Validate the NFS2/NFS3 mount data
+ * Parse monolithic NFS2/NFS3 mount data
  * - fills in the mount root filehandle
  *
  * For option strings, user space handles the following behaviors:
@@ -1365,11 +1351,7 @@ int nfs_validate_text_mount_data(void *options,
 
 	nfs_set_port(sap, &ctx->nfs_server.port, port);
 
-	return nfs_parse_devname(dev_name,
-				   &ctx->nfs_server.hostname,
-				   max_namelen,
-				   &ctx->nfs_server.export_path,
-				   max_pathlen);
+	return nfs_parse_devname(ctx, dev_name, max_namelen, max_pathlen);
 
 #if !IS_ENABLED(CONFIG_NFS_V4)
 out_v4_not_compiled:
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 1c5404d846cc..fa568407cda8 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -86,11 +86,11 @@ struct nfs_client_initdata {
  * In-kernel mount arguments
  */
 struct nfs_fs_context {
-	int			flags;
+	unsigned int		flags;		/* NFS{,4}_MOUNT_* flags */
 	unsigned int		rsize, wsize;
 	unsigned int		timeo, retrans;
-	unsigned int		acregmin, acregmax,
-				acdirmin, acdirmax;
+	unsigned int		acregmin, acregmax;
+	unsigned int		acdirmin, acdirmax;
 	unsigned int		namlen;
 	unsigned int		options;
 	unsigned int		bsize;
@@ -106,7 +106,10 @@ struct nfs_fs_context {
 	bool			sloppy;
 
 	struct {
-		struct sockaddr_storage	address;
+		union {
+			struct sockaddr	address;
+			struct sockaddr_storage	_address;
+		};
 		size_t			addrlen;
 		char			*hostname;
 		u32			version;
@@ -115,7 +118,10 @@ struct nfs_fs_context {
 	} mount_server;
 
 	struct {
-		struct sockaddr_storage	address;
+		union {
+			struct sockaddr	address;
+			struct sockaddr_storage	_address;
+		};
 		size_t			addrlen;
 		char			*hostname;
 		char			*export_path;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 0eb56748f651..c13f0ff42df9 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -795,7 +795,7 @@ static int nfs_request_mount(struct nfs_fs_context *cfg,
 	/*
 	 * Construct the mount server's address.
 	 */
-	if (cfg->mount_server.address.ss_family == AF_UNSPEC) {
+	if (cfg->mount_server.address.sa_family == AF_UNSPEC) {
 		memcpy(request.sap, &cfg->nfs_server.address,
 		       cfg->nfs_server.addrlen);
 		cfg->mount_server.addrlen = cfg->nfs_server.addrlen;

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 24/27] NFS: Add fs_context support. [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (22 preceding siblings ...)
  2017-06-14 15:18 ` [PATCH 23/27] NFS: Do some tidying of the parsing code " David Howells
@ 2017-06-14 15:18 ` David Howells
  2017-06-15 15:28   ` Anna Schumaker
  2017-06-14 15:19 ` [PATCH 25/27] ipc: Convert mqueue fs to fs_context " David Howells
                   ` (3 subsequent siblings)
  27 siblings, 1 reply; 53+ messages in thread
From: David Howells @ 2017-06-14 15:18 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Add filesystem context support to NFS, parsing the options in advance and
attaching the information to struct nfs_fs_context.  The highlights are:

 (*) Merge nfs_mount_info and nfs_clone_mount into nfs_fs_context.  This
     structure represents NFS's superblock config.

 (*) Make use of the VFS's parsing support to split comma-separated lists.

 (*) Pin the NFS protocol module in the nfs_fs_context.

 (*) Attach supplementary error information to fs_context.  This has the
     downside that these strings must be static and can't be formatted.

 (*) Remove the auxiliary file_system_type structs since the information
     necessary can be conveyed in the nfs_fs_context struct instead.

 (*) Root mounts are made by duplicating the config for the requested mount
     so as to have the same parameters.  Submounts pick up their parameters
     from the parent superblock.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/nfs/client.c         |   74 +++--
 fs/nfs/fs_context.c     |  652 ++++++++++++++++++++++++++++-------------------
 fs/nfs/getroot.c        |   72 +++--
 fs/nfs/internal.h       |  104 +++----
 fs/nfs/namespace.c      |   76 ++++-
 fs/nfs/nfs3_fs.h        |    2 
 fs/nfs/nfs3client.c     |    6 
 fs/nfs/nfs3proc.c       |    2 
 fs/nfs/nfs4_fs.h        |    4 
 fs/nfs/nfs4client.c     |   44 ++-
 fs/nfs/nfs4namespace.c  |  208 +++++++++------
 fs/nfs/nfs4proc.c       |    3 
 fs/nfs/nfs4super.c      |  220 ++++++++--------
 fs/nfs/proc.c           |    2 
 fs/nfs/super.c          |  381 ++++++++-------------------
 include/linux/nfs_xdr.h |    7 -
 16 files changed, 940 insertions(+), 917 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index d25dfa15f2ec..8c9b610ca952 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -635,25 +635,24 @@ EXPORT_SYMBOL_GPL(nfs_init_client);
  * Create a version 2 or 3 client
  */
 static int nfs_init_server(struct nfs_server *server,
-			   const struct nfs_fs_context *cfg,
-			   struct nfs_subversion *nfs_mod)
+			   const struct nfs_fs_context *ctx)
 {
 	struct rpc_timeout timeparms;
 	struct nfs_client_initdata cl_init = {
-		.hostname = cfg->nfs_server.hostname,
-		.addr = (const struct sockaddr *)&cfg->nfs_server.address,
-		.addrlen = cfg->nfs_server.addrlen,
-		.nfs_mod = nfs_mod,
-		.proto = cfg->nfs_server.protocol,
-		.net = cfg->net,
+		.hostname = ctx->nfs_server.hostname,
+		.addr = (const struct sockaddr *)&ctx->nfs_server.address,
+		.addrlen = ctx->nfs_server.addrlen,
+		.nfs_mod = ctx->nfs_mod,
+		.proto = ctx->nfs_server.protocol,
+		.net = ctx->fc.net_ns,
 		.timeparms = &timeparms,
 	};
 	struct nfs_client *clp;
 	int error;
 
-	nfs_init_timeout_values(&timeparms, cfg->nfs_server.protocol,
-				cfg->timeo, cfg->retrans);
-	if (cfg->flags & NFS_MOUNT_NORESVPORT)
+	nfs_init_timeout_values(&timeparms, ctx->nfs_server.protocol,
+				ctx->timeo, ctx->retrans);
+	if (ctx->flags & NFS_MOUNT_NORESVPORT)
 		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
 
 	/* Allocate or find a client reference we can use */
@@ -664,46 +663,46 @@ static int nfs_init_server(struct nfs_server *server,
 	server->nfs_client = clp;
 
 	/* Initialise the client representation from the mount data */
-	server->flags = cfg->flags;
-	server->options = cfg->options;
+	server->flags = ctx->flags;
+	server->options = ctx->options;
 	server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
 		NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
 		NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
 
-	if (cfg->rsize)
-		server->rsize = nfs_block_size(cfg->rsize, NULL);
-	if (cfg->wsize)
-		server->wsize = nfs_block_size(cfg->wsize, NULL);
+	if (ctx->rsize)
+		server->rsize = nfs_block_size(ctx->rsize, NULL);
+	if (ctx->wsize)
+		server->wsize = nfs_block_size(ctx->wsize, NULL);
 
-	server->acregmin = cfg->acregmin * HZ;
-	server->acregmax = cfg->acregmax * HZ;
-	server->acdirmin = cfg->acdirmin * HZ;
-	server->acdirmax = cfg->acdirmax * HZ;
+	server->acregmin = ctx->acregmin * HZ;
+	server->acregmax = ctx->acregmax * HZ;
+	server->acdirmin = ctx->acdirmin * HZ;
+	server->acdirmax = ctx->acdirmax * HZ;
 
 	/* Start lockd here, before we might error out */
 	error = nfs_start_lockd(server);
 	if (error < 0)
 		goto error;
 
-	server->port = cfg->nfs_server.port;
-	server->auth_info = cfg->auth_info;
+	server->port = ctx->nfs_server.port;
+	server->auth_info = ctx->auth_info;
 
 	error = nfs_init_server_rpcclient(server, &timeparms,
-					  cfg->selected_flavor);
+					  ctx->selected_flavor);
 	if (error < 0)
 		goto error;
 
 	/* Preserve the values of mount_server-related mount options */
-	if (cfg->mount_server.addrlen) {
-		memcpy(&server->mountd_address, &cfg->mount_server.address,
-			cfg->mount_server.addrlen);
-		server->mountd_addrlen = cfg->mount_server.addrlen;
+	if (ctx->mount_server.addrlen) {
+		memcpy(&server->mountd_address, &ctx->mount_server.address,
+			ctx->mount_server.addrlen);
+		server->mountd_addrlen = ctx->mount_server.addrlen;
 	}
-	server->mountd_version = cfg->mount_server.version;
-	server->mountd_port = cfg->mount_server.port;
-	server->mountd_protocol = cfg->mount_server.protocol;
+	server->mountd_version = ctx->mount_server.version;
+	server->mountd_port = ctx->mount_server.port;
+	server->mountd_protocol = ctx->mount_server.protocol;
 
-	server->namelen  = cfg->namlen;
+	server->namelen  = ctx->namlen;
 	return 0;
 
 error:
@@ -921,8 +920,7 @@ EXPORT_SYMBOL_GPL(nfs_free_server);
  * Create a version 2 or 3 volume record
  * - keyed on server and FSID
  */
-struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
-				     struct nfs_subversion *nfs_mod)
+struct nfs_server *nfs_create_server(struct nfs_fs_context *ctx)
 {
 	struct nfs_server *server;
 	struct nfs_fattr *fattr;
@@ -938,18 +936,18 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
 		goto error;
 
 	/* Get a client representation */
-	error = nfs_init_server(server, mount_info->ctx, nfs_mod);
+	error = nfs_init_server(server, ctx);
 	if (error < 0)
 		goto error;
 
 	/* Probe the root fh to retrieve its FSID */
-	error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
+	error = nfs_probe_fsinfo(server, ctx->mntfh, fattr);
 	if (error < 0)
 		goto error;
 	if (server->nfs_client->rpc_ops->version == 3) {
 		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
 			server->namelen = NFS3_MAXNAMLEN;
-		if (!(mount_info->ctx->flags & NFS_MOUNT_NORDIRPLUS))
+		if (!(ctx->flags & NFS_MOUNT_NORDIRPLUS))
 			server->caps |= NFS_CAP_READDIRPLUS;
 	} else {
 		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
@@ -957,7 +955,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
 	}
 
 	if (!(fattr->valid & NFS_ATTR_FATTR)) {
-		error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL);
+		error = ctx->nfs_mod->rpc_ops->getattr(server, ctx->mntfh, fattr, NULL);
 		if (error < 0) {
 			dprintk("nfs_create_server: getattr error = %d\n", -error);
 			goto error;
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 24becb82540f..e8e88aaa5164 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -240,42 +240,8 @@ static const match_table_t nfs_vers_tokens = {
 	{ Opt_vers_err, NULL }
 };
 
-struct nfs_fs_context *nfs_alloc_parsed_mount_data(void)
-{
-	struct nfs_fs_context *ctx;
-
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-	if (ctx) {
-		ctx->timeo		= NFS_UNSPEC_TIMEO;
-		ctx->retrans		= NFS_UNSPEC_RETRANS;
-		ctx->acregmin		= NFS_DEF_ACREGMIN;
-		ctx->acregmax		= NFS_DEF_ACREGMAX;
-		ctx->acdirmin		= NFS_DEF_ACDIRMIN;
-		ctx->acdirmax		= NFS_DEF_ACDIRMAX;
-		ctx->mount_server.port	= NFS_UNSPEC_PORT;
-		ctx->nfs_server.port	= NFS_UNSPEC_PORT;
-		ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-		ctx->selected_flavor	= RPC_AUTH_MAXFLAVOR;
-		ctx->minorversion	= 0;
-		ctx->need_mount	= true;
-		ctx->net		= current->nsproxy->net_ns;
-		security_init_mnt_opts(&ctx->lsm_opts);
-	}
-	return ctx;
-}
-
-void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx)
-{
-	if (ctx) {
-		kfree(ctx->client_address);
-		kfree(ctx->mount_server.hostname);
-		kfree(ctx->nfs_server.export_path);
-		kfree(ctx->nfs_server.hostname);
-		kfree(ctx->fscache_uniq);
-		security_free_mnt_opts(&ctx->lsm_opts);
-		kfree(ctx);
-	}
-}
+const char nfs_slash[] = "/";
+EXPORT_SYMBOL_GPL(nfs_slash);
 
 /*
  * Sanity-check a server address provided by the mount command.
@@ -354,10 +320,8 @@ static int nfs_auth_info_add(struct nfs_fs_context *ctx,
 			return 0;
 	}
 
-	if (auth_info->flavor_len + 1 >= max_flavor_len) {
-		dfprintk(MOUNT, "NFS: too many sec= flavors\n");
-		return -EINVAL;
-	}
+	if (auth_info->flavor_len + 1 >= max_flavor_len)
+		return invalf("NFS: too many sec= flavors");
 
 	auth_info->flavors[auth_info->flavor_len++] = flavor;
 	return 0;
@@ -411,9 +375,7 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value)
 			pseudoflavor = RPC_AUTH_GSS_SPKMP;
 			break;
 		default:
-			dfprintk(MOUNT,
-				 "NFS: sec= option '%s' not recognized\n", p);
-			return -EINVAL;
+			return invalf("NFS: sec=%s option not recognized", p);
 		}
 
 		ret = nfs_auth_info_add(ctx, &ctx->auth_info, pseudoflavor);
@@ -457,8 +419,7 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx,
 		ctx->minorversion = 2;
 		break;
 	default:
-		dfprintk(MOUNT, "NFS:   Unsupported NFS version\n");
-		return -EINVAL;
+		return invalf("NFS: Unsupported NFS version");
 	}
 	return 0;
 }
@@ -495,8 +456,9 @@ static int nfs_get_option_ui_bound(struct nfs_fs_context *ctx,
 /*
  * Parse a single mount option in "key[=val]" form.
  */
-static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
+static int nfs_fs_context_parse_option(struct fs_context *fc, char *p)
 {
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
 	substring_t args[MAX_OPT_ARGS];
 	char *string;
 	int ret, token;
@@ -715,8 +677,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			break;
 		default:
 			kfree(string);
-			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
-			return -EINVAL;
+			return invalf("NFS: Unrecognized transport protocol");
 		}
 		kfree(string);
 		break;
@@ -741,8 +702,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			break;
 		case Opt_xprt_rdma: /* not used for side protocols */
 		default:
-			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
-			return -EINVAL;
+			return invalf("NFS: Unrecognized transport protocol");
 		}
 		break;
 	case Opt_addr:
@@ -750,7 +710,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		if (string == NULL)
 			goto out_nomem;
 		ctx->nfs_server.addrlen =
-			rpc_pton(ctx->net, string, strlen(string),
+			rpc_pton(fc->net_ns, string, strlen(string),
 				 &ctx->nfs_server.address,
 				 sizeof(ctx->nfs_server._address));
 		kfree(string);
@@ -770,7 +730,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		if (string == NULL)
 			goto out_nomem;
 		ctx->mount_server.addrlen =
-			rpc_pton(ctx->net, string, strlen(string),
+			rpc_pton(fc->net_ns, string, strlen(string),
 				 &ctx->mount_server.address,
 				 sizeof(ctx->mount_server._address));
 		kfree(string);
@@ -795,8 +755,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
 			break;
 		default:
-			dfprintk(MOUNT, "NFS:   invalid lookupcache argument\n");
-			return -EINVAL;
+			return invalf("NFS: Invalid lookupcache argument");
 		}
 		break;
 	case Opt_fscache_uniq:
@@ -826,16 +785,15 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 					NFS_MOUNT_LOCAL_FCNTL);
 			break;
 		default:
-			dfprintk(MOUNT, "NFS:	invalid	local_lock argument\n");
-			return -EINVAL;
-		};
+			return invalf("NFS: invalid local_lock argument");
+		}
 		break;
 
 		/*
 		 * Special options
 		 */
 	case Opt_sloppy:
-		ctx->sloppy = 1;
+		fc->sloppy = 1;
 		dfprintk(MOUNT, "NFS:   relaxing parsing rules\n");
 		break;
 	case Opt_userspace:
@@ -845,116 +803,24 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 
 	default:
 		dfprintk(MOUNT, "NFS:   unrecognized mount option '%s'\n", p);
-		return -EINVAL;
+		if (!fc->sloppy)
+			return invalf("NFS: Unrecognized mount option '%s'", p);
+		break;
 	}
 
 	return 0;
 
-out_invalid_address:
-	printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
-	return -EINVAL;
-out_invalid_value:
-	printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
-	return -EINVAL;
 out_nomem:
 	printk(KERN_INFO "NFS: not enough memory to parse option\n");
 	return -ENOMEM;
+out_invalid_value:
+	return invalf("NFS: Bad mount option value specified");
+out_invalid_address:
+	return invalf("NFS: Bad IP address specified");
 }
 
 /*
- * Error-check and convert a string of mount options from user space into
- * a data structure.  The whole mount string is processed; bad options are
- * skipped as they are encountered.  If there were no errors, return 1;
- * otherwise return 0 (zero).
- */
-int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
-{
-	char *p, *secdata;
-	int rc, sloppy = 0, invalid_option = 0;
-
-	if (!raw) {
-		dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
-		return 1;
-	}
-	dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
-
-	secdata = alloc_secdata();
-	if (!secdata)
-		goto out_nomem;
-
-	rc = security_sb_copy_data(raw, secdata);
-	if (rc)
-		goto out_security_failure;
-
-	rc = security_sb_parse_opts_str(secdata, &ctx->lsm_opts);
-	if (rc)
-		goto out_security_failure;
-
-	free_secdata(secdata);
-
-	while ((p = strsep(&raw, ",")) != NULL) {
-		if (!*p)
-			continue;
-		if (nfs_fs_context_parse_option(ctx, p) < 0)
-			invalid_option = true;
-	}
-
-	if (!sloppy && invalid_option)
-		return 0;
-
-	if (ctx->minorversion && ctx->version != 4)
-		goto out_minorversion_mismatch;
-
-	if (ctx->options & NFS_OPTION_MIGRATION &&
-	    (ctx->version != 4 || ctx->minorversion != 0))
-		goto out_migration_misuse;
-
-	/*
-	 * verify that any proto=/mountproto= options match the address
-	 * families in the addr=/mountaddr= options.
-	 */
-	if (ctx->protofamily != AF_UNSPEC &&
-	    ctx->protofamily != ctx->nfs_server.address.sa_family)
-		goto out_proto_mismatch;
-
-	if (ctx->mountfamily != AF_UNSPEC) {
-		if (ctx->mount_server.addrlen) {
-			if (ctx->mountfamily != ctx->mount_server.address.sa_family)
-				goto out_mountproto_mismatch;
-		} else {
-			if (ctx->mountfamily != ctx->nfs_server.address.sa_family)
-				goto out_mountproto_mismatch;
-		}
-	}
-
-	return 1;
-
-out_minorversion_mismatch:
-	printk(KERN_INFO "NFS: mount option vers=%u does not support "
-			 "minorversion=%u\n", ctx->version, ctx->minorversion);
-	return 0;
-out_mountproto_mismatch:
-	printk(KERN_INFO "NFS: mount server address does not match mountproto= "
-			 "option\n");
-	return 0;
-out_proto_mismatch:
-	printk(KERN_INFO "NFS: server address does not match proto= option\n");
-	return 0;
-out_migration_misuse:
-	printk(KERN_INFO
-		"NFS: 'migration' not supported for this NFS version\n");
-	return -EINVAL;
-out_nomem:
-	printk(KERN_INFO "NFS: not enough memory to parse option\n");
-	return 0;
-out_security_failure:
-	free_secdata(secdata);
-	printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
-	return 0;
-}
-
-/*
- * Split "dev_name" into "hostname:export_path".
+ * Split sc->device into "hostname:export_path".
  *
  * The leftmost colon demarks the split between the server's hostname
  * and the export path.  If the hostname starts with a left square
@@ -963,9 +829,9 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
  * Note: caller frees hostname and export path, even on error.
  */
 static int nfs_parse_devname(struct nfs_fs_context *ctx,
-			     const char *dev_name,
 			     size_t maxnamlen, size_t maxpathlen)
 {
+	char *dev_name = ctx->fc.device;
 	size_t len;
 	char *end;
 
@@ -1009,19 +875,15 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
 	return 0;
 
 out_bad_devname:
-	dfprintk(MOUNT, "NFS: device name not in host:path format\n");
-	return -EINVAL;
-
+	return invalf("NFS: device name not in host:path format");
 out_nomem:
-	dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
+	errorf("NFS: not enough memory to parse device name");
 	return -ENOMEM;
-
 out_hostname:
-	dfprintk(MOUNT, "NFS: server hostname too long\n");
+	errorf("NFS: server hostname too long");
 	return -ENAMETOOLONG;
-
 out_path:
-	dfprintk(MOUNT, "NFS: export pathname too long\n");
+	errorf("NFS: export pathname too long");
 	return -ENAMETOOLONG;
 }
 
@@ -1041,14 +903,14 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
  * + breaking back: trying proto=udp after proto=tcp, v2 after v3,
  *   mountproto=tcp after mountproto=udp, and so on
  */
-static int nfs23_validate_mount_data(void *options,
-				     struct nfs_fs_context *ctx,
-				     struct nfs_fh *mntfh,
-				     const char *dev_name)
+static int nfs23_monolithic_mount_data(struct fs_context *fc,
+				       struct nfs_mount_data *data)
 {
-	struct nfs_mount_data *data = (struct nfs_mount_data *)options;
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
+	struct nfs_fh *mntfh = ctx->mntfh;
 	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
 	int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
+	int ret;
 
 	if (data == NULL)
 		goto out_no_data;
@@ -1114,6 +976,9 @@ static int nfs23_validate_mount_data(void *options,
 			ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
 		/* N.B. caller will free nfs_server.hostname in all cases */
 		ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
+		if (!ctx->nfs_server.hostname)
+			goto out_nomem;
+
 		ctx->namlen		= data->namlen;
 		ctx->bsize		= data->bsize;
 
@@ -1121,8 +986,6 @@ static int nfs23_validate_mount_data(void *options,
 			ctx->selected_flavor = data->pseudoflavor;
 		else
 			ctx->selected_flavor = RPC_AUTH_UNIX;
-		if (!ctx->nfs_server.hostname)
-			goto out_nomem;
 
 		if (!(data->flags & NFS_MOUNT_NONLM))
 			ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
@@ -1130,6 +993,7 @@ static int nfs23_validate_mount_data(void *options,
 		else
 			ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK|
 					NFS_MOUNT_LOCAL_FCNTL);
+
 		/*
 		 * The legacy version 6 binary mount data from userspace has a
 		 * field used only to transport selinux information into the
@@ -1140,17 +1004,16 @@ static int nfs23_validate_mount_data(void *options,
 		 */
 		if (data->context[0]){
 #ifdef CONFIG_SECURITY_SELINUX
-			int rc;
 			char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL);
 			if (!opts_str)
 				return -ENOMEM;
 			strcpy(opts_str, "context=");
 			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
 			strcat(opts_str, &data->context[0]);
-			rc = security_sb_parse_opts_str(opts_str, &ctx->lsm_opts);
+			ret = vfs_parse_mount_option(fc, opts_str);
 			kfree(opts_str);
-			if (rc)
-				return rc;
+			if (ret)
+				return ret;
 #else
 			return -EINVAL;
 #endif
@@ -1158,54 +1021,44 @@ static int nfs23_validate_mount_data(void *options,
 
 		break;
 	default:
-		return NFS_TEXT_DATA;
+		return generic_monolithic_mount_data(fc, data);
 	}
 
+	ctx->skip_remount_option_check = true;
 	return 0;
 
 out_no_data:
-	dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
-	return -EINVAL;
+	if (fc->sb_flags & MS_REMOUNT) {
+		ctx->skip_remount_option_check = true;
+		return 0;
+	}
+	return invalf("NFS: mount program didn't pass any mount data");
 
 out_no_v3:
-	dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n",
-		 data->version);
-	return -EINVAL;
+	return invalf("NFS: nfs_mount_data version does not support v3");
 
 out_no_sec:
-	dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n");
-	return -EINVAL;
+	return invalf("NFS: nfs_mount_data version supports only AUTH_SYS");
 
 out_nomem:
-	dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n");
+	dfprintk(MOUNT, "NFS: not enough memory to handle mount options");
 	return -ENOMEM;
 
 out_no_address:
-	dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
-	return -EINVAL;
+	return invalf("NFS: mount program didn't pass remote address");
 
 out_invalid_fh:
-	dfprintk(MOUNT, "NFS: invalid root filehandle\n");
-	return -EINVAL;
-}
-
-#if IS_ENABLED(CONFIG_NFS_V4)
-
-static void nfs4_validate_mount_flags(struct nfs_fs_context *ctx)
-{
-	ctx->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
-			 NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
+	return invalf("NFS: invalid root filehandle");
 }
 
 /*
  * Validate NFSv4 mount options
  */
-static int nfs4_validate_mount_data(void *options,
-				    struct nfs_fs_context *ctx,
-				    const char *dev_name)
+static int nfs4_monolithic_mount_data(struct fs_context *fc,
+				      struct nfs4_mount_data *data)
 {
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
 	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
-	struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
 	char *c;
 
 	if (data == NULL)
@@ -1255,7 +1108,7 @@ static int nfs4_validate_mount_data(void *options,
 		ctx->client_address = c;
 
 		/*
-		 * Translate to nfs_fs_context, which nfs4_fill_super
+		 * Translate to nfs_fs_context, which nfs_fill_super
 		 * can deal with.
 		 */
 
@@ -1275,95 +1128,372 @@ static int nfs4_validate_mount_data(void *options,
 
 		break;
 	default:
-		return NFS_TEXT_DATA;
+		return generic_monolithic_mount_data(fc, data);
 	}
 
+	ctx->skip_remount_option_check = true;
 	return 0;
 
 out_no_data:
-	dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
-	return -EINVAL;
+	if (fc->sb_flags & MS_REMOUNT) {
+		ctx->skip_remount_option_check = true;
+		return 0;
+	}
+	return invalf("NFS4: mount program didn't pass any mount data");
 
 out_inval_auth:
-	dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n",
-		 data->auth_flavourlen);
-	return -EINVAL;
+	return invalf("NFS4: Invalid number of RPC auth flavours %d",
+		      data->auth_flavourlen);
 
 out_no_address:
-	dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
-	return -EINVAL;
+	return invalf("NFS4: mount program didn't pass remote address");
 
 out_invalid_transport_udp:
-	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
-	return -EINVAL;
+	return invalf("NFSv4: Unsupported transport protocol udp");
 }
 
-int nfs_validate_mount_data(struct file_system_type *fs_type,
-			    void *options,
-			    struct nfs_fs_context *ctx,
-			    struct nfs_fh *mntfh,
-			    const char *dev_name)
-{
-	if (fs_type == &nfs_fs_type)
-		return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
-	return nfs4_validate_mount_data(options, ctx, dev_name);
-}
-#else
-int nfs_validate_mount_data(struct file_system_type *fs_type,
-			    void *options,
-			    struct nfs_fs_context *ctx,
-			    struct nfs_fh *mntfh,
-			    const char *dev_name)
+/*
+ * Parse a monolithic block of data from sys_mount().
+ */
+static int nfs_monolithic_mount_data(struct fs_context *fc, void *data)
 {
-	return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
-}
+	if (fc->fs_type == &nfs_fs_type)
+		return nfs23_monolithic_mount_data(fc, data);
+
+#if IS_ENABLED(CONFIG_NFS_V4)
+	if (fc->fs_type == &nfs4_fs_type)
+		return nfs4_monolithic_mount_data(fc, data);
 #endif
 
-int nfs_validate_text_mount_data(void *options,
-				 struct nfs_fs_context *ctx,
-				 const char *dev_name)
+	return invalf("NFS: Unsupported monolithic data version");
+}
+
+/*
+ * Validate the preparsed information in the config.
+ */
+static int nfs_fs_context_validate(struct fs_context *fc)
 {
-	int port = 0;
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
+	struct nfs_subversion *nfs_mod;
+	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
 	int max_namelen = PAGE_SIZE;
 	int max_pathlen = NFS_MAXPATHLEN;
-	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
+	int port = 0;
+	int ret;
 
-	if (nfs_parse_mount_options((char *)options, ctx) == 0)
-		return -EINVAL;
+	if (ctx->fc.purpose == FS_CONTEXT_FOR_REMOUNT)
+		return 0;
+
+	if (!ctx->fc.device)
+		goto out_no_device_name;
+
+	/* Check for sanity first. */
+	if (ctx->minorversion && ctx->version != 4)
+		goto out_minorversion_mismatch;
+
+	if (ctx->options & NFS_OPTION_MIGRATION &&
+	    (ctx->version != 4 || ctx->minorversion != 0))
+		goto out_migration_misuse;
+
+	/* Verify that any proto=/mountproto= options match the address
+	 * families in the addr=/mountaddr= options.
+	 */
+	if (ctx->protofamily != AF_UNSPEC &&
+	    ctx->protofamily != ctx->nfs_server.address.sa_family)
+		goto out_proto_mismatch;
+
+	if (ctx->mountfamily != AF_UNSPEC) {
+		if (ctx->mount_server.addrlen) {
+			if (ctx->mountfamily != ctx->mount_server.address.sa_family)
+				goto out_mountproto_mismatch;
+		} else {
+			if (ctx->mountfamily != ctx->nfs_server.address.sa_family)
+				goto out_mountproto_mismatch;
+		}
+	}
 
 	if (!nfs_verify_server_address(sap))
 		goto out_no_address;
 
 	if (ctx->version == 4) {
-#if IS_ENABLED(CONFIG_NFS_V4)
-		port = NFS_PORT;
-		max_namelen = NFS4_MAXNAMLEN;
-		max_pathlen = NFS4_MAXPATHLEN;
-		nfs_validate_transport_protocol(ctx);
-		if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
-			goto out_invalid_transport_udp;
-		nfs4_validate_mount_flags(ctx);
-#else
-		goto out_v4_not_compiled;
-#endif /* CONFIG_NFS_V4 */
-	} else
+		if (IS_ENABLED(CONFIG_NFS_V4)) {
+			port = NFS_PORT;
+			max_namelen = NFS4_MAXNAMLEN;
+			max_pathlen = NFS4_MAXPATHLEN;
+			nfs_validate_transport_protocol(ctx);
+			if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+				goto out_invalid_transport_udp;
+			ctx->flags &= ~(NFS_MOUNT_NONLM | NFS_MOUNT_NOACL |
+					 NFS_MOUNT_VER3 | NFS_MOUNT_LOCAL_FLOCK |
+					 NFS_MOUNT_LOCAL_FCNTL);
+		} else {
+			goto out_v4_not_compiled;
+		}
+	} else {
 		nfs_set_mount_transport_protocol(ctx);
+	}
 
 	nfs_set_port(sap, &ctx->nfs_server.port, port);
 
-	return nfs_parse_devname(ctx, dev_name, max_namelen, max_pathlen);
+	ret = nfs_parse_devname(ctx, max_namelen, max_pathlen);
+	if (ret < 0)
+		return ret;
 
-#if !IS_ENABLED(CONFIG_NFS_V4)
+	/* Load the NFS protocol module if we haven't done so yet */
+	if (!ctx->nfs_mod) {
+		nfs_mod = get_nfs_version(ctx->version);
+		if (IS_ERR(nfs_mod)) {
+			ret = PTR_ERR(nfs_mod);
+			goto out_version_unavailable;
+		}
+		ctx->nfs_mod = nfs_mod;
+	}
+	return 0;
+
+out_no_device_name:
+	return invalf("NFS: Device name not specified");
 out_v4_not_compiled:
-	dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
+	errorf("NFS: NFSv4 is not compiled into kernel");
 	return -EPROTONOSUPPORT;
-#else
 out_invalid_transport_udp:
-	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
-	return -EINVAL;
-#endif /* !CONFIG_NFS_V4 */
-
+	return invalf("NFSv4: Unsupported transport protocol udp");
 out_no_address:
-	dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
-	return -EINVAL;
+	return invalf("NFS: mount program didn't pass remote address");
+out_mountproto_mismatch:
+	return invalf("NFS: Mount server address does not match mountproto= option");
+out_proto_mismatch:
+	return invalf("NFS: Server address does not match proto= option");
+out_minorversion_mismatch:
+	return invalf("NFS: Mount option vers=%u does not support minorversion=%u",
+		      ctx->version, ctx->minorversion);
+out_migration_misuse:
+	return invalf("NFS: 'Migration' not supported for this NFS version");
+out_version_unavailable:
+	errorf("NFS: Version unavailable");
+	return ret;
+}
+
+/*
+ * Use the preparsed information in the config to effect a mount.
+ */
+static int nfs_get_ordinary_tree(struct nfs_fs_context *ctx)
+{
+	ctx->set_security = nfs_set_sb_security;
+
+	return ctx->nfs_mod->rpc_ops->try_get_tree(ctx);
 }
+
+/*
+ * Clone an NFS2/3/4 server record on xdev traversal (FSID-change)
+ */
+static int nfs_get_xdev_tree(struct nfs_fs_context *ctx)
+{
+	struct nfs_server *server;
+	int ret;
+
+	dprintk("--> nfs_xdev_mount()\n");
+
+	ctx->set_security = nfs_clone_sb_security;
+
+	/* create a new volume representation */
+	server = ctx->nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb),
+						     ctx->mntfh,
+						     ctx->clone_data.fattr,
+						     ctx->selected_flavor);
+
+	if (IS_ERR(server))
+		ret = PTR_ERR(server);
+	else
+		ret = nfs_get_tree_common(server, ctx);
+
+	dprintk("<-- nfs_get_xdev_tree() = %d\n", ret);
+	return ret;
+}
+
+/*
+ * Create an NFS superblock by the appropriate method.
+ */
+static int nfs_get_tree(struct fs_context *fc)
+{
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
+	int ret;
+
+	if (!ctx->nfs_mod) {
+		pr_warn("Missing nfs_mod\n");
+		return -EINVAL;
+	}
+	if (!ctx->nfs_mod->rpc_ops) {
+		pr_warn("Missing rpc_ops\n");
+		return -EINVAL;
+	}
+
+	if (ctx->nfs_mod->rpc_ops->get_tree) {
+		ret = ctx->nfs_mod->rpc_ops->get_tree(ctx);
+		if (ret != 1)
+			return ret;
+	}
+
+	switch (ctx->mount_type) {
+	case NFS_MOUNT_ORDINARY:
+		return nfs_get_ordinary_tree(ctx);
+
+	case NFS_MOUNT_CROSS_DEV:
+		return nfs_get_xdev_tree(ctx);
+
+	default:
+		errorf("NFS: Unknown mount type");
+		return -ENOTSUPP;
+	}
+}
+
+/*
+ * Handle duplication of a configuration.  The caller copied *src into *sc, but
+ * it can't deal with resource pointers in the filesystem context, so we have
+ * to do that.  We need to clear pointers, copy data or get extra refs as
+ * appropriate.
+ */
+static int nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src)
+{
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
+
+	__module_get(ctx->nfs_mod->owner);
+	ctx->client_address		= NULL;
+	ctx->mount_server.hostname	= NULL;
+	ctx->nfs_server.export_path	= NULL;
+	ctx->nfs_server.hostname	= NULL;
+	ctx->fscache_uniq		= NULL;
+
+	ctx->mntfh = nfs_alloc_fhandle();
+	if (!ctx->mntfh)
+		return -ENOMEM;
+	return 0;
+}
+
+static void nfs_fs_context_free(struct fs_context *fc)
+{
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
+
+	if (ctx->nfs_mod)
+		put_nfs_version(ctx->nfs_mod);
+	kfree(ctx->client_address);
+	kfree(ctx->mount_server.hostname);
+	if (ctx->nfs_server.export_path != nfs_slash)
+		kfree(ctx->nfs_server.export_path);
+	kfree(ctx->nfs_server.hostname);
+	kfree(ctx->fscache_uniq);
+	nfs_free_fhandle(ctx->mntfh);
+}
+
+static const struct fs_context_operations nfs_fs_context_ops = {
+	.free			= nfs_fs_context_free,
+	.dup			= nfs_fs_context_dup,
+	.parse_option		= nfs_fs_context_parse_option,
+	.monolithic_mount_data	= nfs_monolithic_mount_data,
+	.validate		= nfs_fs_context_validate,
+	.get_tree		= nfs_get_tree,
+};
+
+/*
+ * Initialise a configuration from an extant superblock for remounting.
+ */
+static int nfs_mount_init_from_sb(struct fs_context *fc,
+				  struct super_block *sb)
+{
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
+	struct nfs_server *nfss = sb->s_fs_info;
+	struct net *net = nfss->nfs_client->cl_net;
+
+	ctx->flags		= nfss->flags;
+	ctx->rsize		= nfss->rsize;
+	ctx->wsize		= nfss->wsize;
+	ctx->retrans		= nfss->client->cl_timeout->to_retries;
+	ctx->selected_flavor	= nfss->client->cl_auth->au_flavor;
+	ctx->acregmin		= nfss->acregmin / HZ;
+	ctx->acregmax		= nfss->acregmax / HZ;
+	ctx->acdirmin		= nfss->acdirmin / HZ;
+	ctx->acdirmax		= nfss->acdirmax / HZ;
+	ctx->timeo		= 10U * nfss->client->cl_timeout->to_initval / HZ;
+	ctx->nfs_server.port	= nfss->port;
+	ctx->nfs_server.addrlen	= nfss->nfs_client->cl_addrlen;
+	ctx->version		= nfss->nfs_client->rpc_ops->version;
+	ctx->minorversion	= nfss->nfs_client->cl_minorversion;
+
+	memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr,
+		ctx->nfs_server.addrlen);
+
+	if (ctx->fc.net_ns != net) {
+		put_net(ctx->fc.net_ns);
+		ctx->fc.net_ns = get_net(net);
+	}
+
+	ctx->nfs_mod = nfss->nfs_client->cl_nfs_mod;
+	if (!try_module_get(ctx->nfs_mod->owner)) {
+		ctx->nfs_mod = NULL;
+		errorf("NFS: Protocol module not available");
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+/*
+ * Prepare superblock configuration.  We use the namespaces attached to the
+ * context.  This may be the current process's namespaces, or it may be a
+ * container's namespaces.
+ */
+static int nfs_init_fs_context(struct fs_context *fc, struct super_block *src_sb)
+{
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
+
+	ctx->mntfh = nfs_alloc_fhandle();
+	if (!ctx->mntfh)
+		return -ENOMEM;
+
+	ctx->fc.ops		= &nfs_fs_context_ops;
+	ctx->mount_type		= NFS_MOUNT_ORDINARY;
+	ctx->protofamily	= AF_UNSPEC;
+	ctx->mountfamily	= AF_UNSPEC;
+	ctx->mount_server.port	= NFS_UNSPEC_PORT;
+
+	if (!src_sb) {
+		ctx->timeo		= NFS_UNSPEC_TIMEO;
+		ctx->retrans		= NFS_UNSPEC_RETRANS;
+		ctx->acregmin		= NFS_DEF_ACREGMIN;
+		ctx->acregmax		= NFS_DEF_ACREGMAX;
+		ctx->acdirmin		= NFS_DEF_ACDIRMIN;
+		ctx->acdirmax		= NFS_DEF_ACDIRMAX;
+		ctx->nfs_server.port	= NFS_UNSPEC_PORT;
+		ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+		ctx->selected_flavor	= RPC_AUTH_MAXFLAVOR;
+		ctx->minorversion	= 0;
+		ctx->need_mount		= true;
+		return 0;
+	}
+
+	return nfs_mount_init_from_sb(fc, src_sb);
+}
+
+struct file_system_type nfs_fs_type = {
+	.owner			= THIS_MODULE,
+	.name			= "nfs",
+	.init_fs_context	= nfs_init_fs_context,
+	.fs_context_size	= sizeof(struct nfs_fs_context),
+	.kill_sb		= nfs_kill_super,
+	.fs_flags		= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
+};
+MODULE_ALIAS_FS("nfs");
+EXPORT_SYMBOL_GPL(nfs_fs_type);
+
+#if IS_ENABLED(CONFIG_NFS_V4)
+struct file_system_type nfs4_fs_type = {
+	.owner			= THIS_MODULE,
+	.name			= "nfs4",
+	.fs_context_size	= sizeof(struct nfs_fs_context),
+	.init_fs_context	= nfs_init_fs_context,
+	.kill_sb		= nfs_kill_super,
+	.fs_flags		= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
+};
+MODULE_ALIAS_FS("nfs4");
+MODULE_ALIAS("nfs4");
+EXPORT_SYMBOL_GPL(nfs4_fs_type);
+#endif /* CONFIG_NFS_V4 */
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 391dafaf9182..4a5ee38117b5 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -68,66 +68,70 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
 /*
  * get an NFS2/NFS3 root dentry from the root filehandle
  */
-struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
-			    const char *devname)
+int nfs_get_root(struct super_block *s, struct nfs_fs_context *ctx)
 {
-	struct nfs_server *server = NFS_SB(sb);
+	struct nfs_server *server = NFS_SB(s);
 	struct nfs_fsinfo fsinfo;
-	struct dentry *ret;
+	struct dentry *root;
 	struct inode *inode;
-	void *name = kstrdup(devname, GFP_KERNEL);
-	int error;
+	char *name;
+	int error = -ENOMEM;
 
+	name = kstrdup(ctx->fc.device, GFP_KERNEL);
 	if (!name)
-		return ERR_PTR(-ENOMEM);
+		goto out;
 
 	/* get the actual root for this mount */
 	fsinfo.fattr = nfs_alloc_fattr();
-	if (fsinfo.fattr == NULL) {
-		kfree(name);
-		return ERR_PTR(-ENOMEM);
-	}
+	if (fsinfo.fattr == NULL)
+		goto out_name;
 
-	error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
+	error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
 	if (error < 0) {
 		dprintk("nfs_get_root: getattr error = %d\n", -error);
-		ret = ERR_PTR(error);
-		goto out;
+		errorf("NFS: Couldn't getattr on root");
+		goto out_fattr;
 	}
 
-	inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL);
+	inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr, NULL);
 	if (IS_ERR(inode)) {
 		dprintk("nfs_get_root: get root inode failed\n");
-		ret = ERR_CAST(inode);
-		goto out;
+		error = PTR_ERR(inode);
+		errorf("NFS: Couldn't get root inode");
+		goto out_fattr;
 	}
 
-	error = nfs_superblock_set_dummy_root(sb, inode);
-	if (error != 0) {
-		ret = ERR_PTR(error);
-		goto out;
-	}
+	error = nfs_superblock_set_dummy_root(s, inode);
+	if (error != 0)
+		goto out_fattr;
 
 	/* root dentries normally start off anonymous and get spliced in later
 	 * if the dentry tree reaches them; however if the dentry already
 	 * exists, we'll pick it up at this point and use it as the root
 	 */
-	ret = d_obtain_root(inode);
-	if (IS_ERR(ret)) {
+	root = d_obtain_root(inode);
+	if (IS_ERR(root)) {
 		dprintk("nfs_get_root: get root dentry failed\n");
-		goto out;
+		error = PTR_ERR(root);
+		errorf("NFS: Couldn't get root dentry");
+		goto out_fattr;
 	}
 
-	security_d_instantiate(ret, inode);
-	spin_lock(&ret->d_lock);
-	if (IS_ROOT(ret) && !ret->d_fsdata &&
-	    !(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
-		ret->d_fsdata = name;
+	security_d_instantiate(root, inode);
+	spin_lock(&root->d_lock);
+	if (IS_ROOT(root) && !root->d_fsdata &&
+	    !(root->d_flags & DCACHE_NFSFS_RENAMED)) {
+		root->d_fsdata = name;
 		name = NULL;
 	}
-	spin_unlock(&ret->d_lock);
-out:
-	kfree(name);
+	spin_unlock(&root->d_lock);
+	ctx->fc.root = root;
+	error = 0;
+
+out_fattr:
 	nfs_free_fattr(fsinfo.fattr);
-	return ret;
+out_name:
+	kfree(name);
+out:
+	return error;
 }
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index fa568407cda8..ef7193479cda 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -3,7 +3,7 @@
  */
 
 #include "nfs4_fs.h"
-#include <linux/mount.h>
+#include <linux/fs_context.h>
 #include <linux/security.h>
 #include <linux/crc32.h>
 #include <linux/sunrpc/addr.h>
@@ -36,18 +36,6 @@ static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr)
 	return 1;
 }
 
-struct nfs_clone_mount {
-	const struct super_block *sb;
-	const struct dentry *dentry;
-	struct nfs_fh *fh;
-	struct nfs_fattr *fattr;
-	char *hostname;
-	char *mnt_path;
-	struct sockaddr *addr;
-	size_t addrlen;
-	rpc_authflavor_t authflavor;
-};
-
 /*
  * Note: RFC 1813 doesn't limit the number of auth flavors that
  * a server can return, so make something up.
@@ -82,10 +70,22 @@ struct nfs_client_initdata {
 	const struct rpc_timeout *timeparms;
 };
 
+enum nfs_mount_type {
+	NFS_MOUNT_ORDINARY,
+	NFS_MOUNT_CROSS_DEV,
+	NFS4_MOUNT_REMOTE,
+	NFS4_MOUNT_REFERRAL,
+	NFS4_MOUNT_REMOTE_REFERRAL,
+};
+
 /*
  * In-kernel mount arguments
  */
 struct nfs_fs_context {
+	struct fs_context	fc;
+	enum nfs_mount_type	mount_type : 8;
+	bool			skip_remount_option_check;
+	bool			need_mount;
 	unsigned int		flags;		/* NFS{,4}_MOUNT_* flags */
 	unsigned int		rsize, wsize;
 	unsigned int		timeo, retrans;
@@ -102,8 +102,6 @@ struct nfs_fs_context {
 	char			*fscache_uniq;
 	unsigned short		protofamily;
 	unsigned short		mountfamily;
-	bool			need_mount;
-	bool			sloppy;
 
 	struct {
 		union {
@@ -127,10 +125,22 @@ struct nfs_fs_context {
 		char			*export_path;
 		int			port;
 		unsigned short		protocol;
+		unsigned short		export_path_len;
 	} nfs_server;
 
-	struct security_mnt_opts lsm_opts;
-	struct net		*net;
+	struct nfs_fh		*mntfh;
+	struct nfs_subversion	*nfs_mod;
+	struct nfs_server	*server;
+
+	int (*set_security)(struct super_block *, struct nfs_fs_context *);
+
+	/* Information for a cloned mount. */
+	struct nfs_clone_mount {
+		struct super_block	*sb;
+		struct dentry		*dentry;
+		struct nfs_fattr	*fattr;
+		bool			cloned;
+	} clone_data;
 
 	char			buf[32];	/* Parse buffer */
 };
@@ -150,14 +160,6 @@ struct nfs_mount_request {
 	struct net		*net;
 };
 
-struct nfs_mount_info {
-	void (*fill_super)(struct super_block *, struct nfs_mount_info *);
-	int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *);
-	struct nfs_fs_context *ctx;
-	struct nfs_clone_mount *cloned;
-	struct nfs_fh *mntfh;
-};
-
 extern int nfs_mount(struct nfs_mount_request *info);
 extern void nfs_umount(const struct nfs_mount_request *info);
 
@@ -183,13 +185,9 @@ extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
 extern struct nfs_client *
 nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
 				struct nfs4_sessionid *, u32);
-extern struct nfs_server *nfs_create_server(struct nfs_mount_info *,
-					struct nfs_subversion *);
-extern struct nfs_server *nfs4_create_server(
-					struct nfs_mount_info *,
-					struct nfs_subversion *);
-extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
-						      struct nfs_fh *);
+extern struct nfs_server *nfs_create_server(struct nfs_fs_context *);
+extern struct nfs_server *nfs4_create_server(struct nfs_fs_context *);
+extern struct nfs_server *nfs4_create_referral_server(struct nfs_fs_context *);
 extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
 					struct sockaddr *sap, size_t salen,
 					struct net *net);
@@ -243,19 +241,7 @@ extern struct svc_version nfs4_callback_version4;
 struct nfs_pageio_descriptor;
 
 /* mount.c */
-#define NFS_TEXT_DATA		1
-
-extern struct nfs_fs_context *nfs_alloc_parsed_mount_data(void);
-extern void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx);
-extern int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx);
-extern int nfs_validate_mount_data(struct file_system_type *fs_type,
-				   void *options,
-				   struct nfs_fs_context *ctx,
-				   struct nfs_fh *mntfh,
-				   const char *dev_name);
-extern int nfs_validate_text_mount_data(void *options,
-					struct nfs_fs_context *ctx,
-					const char *dev_name);
+extern const char nfs_slash[];
 
 /* pagelist.c */
 extern int __init nfs_init_nfspagecache(void);
@@ -418,23 +404,12 @@ extern int nfs_wait_atomic_killable(atomic_t *p);
 /* super.c */
 extern const struct super_operations nfs_sops;
 extern struct file_system_type nfs_fs_type;
-extern struct file_system_type nfs_xdev_fs_type;
-#if IS_ENABLED(CONFIG_NFS_V4)
-extern struct file_system_type nfs4_xdev_fs_type;
-extern struct file_system_type nfs4_referral_fs_type;
-#endif
 bool nfs_auth_info_match(const struct nfs_auth_info *, rpc_authflavor_t);
-struct dentry *nfs_try_mount(int, const char *, struct nfs_mount_info *,
-			struct nfs_subversion *);
-int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
-int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
-struct dentry *nfs_fs_mount_common(struct nfs_server *, int, const char *,
-				   struct nfs_mount_info *, struct nfs_subversion *);
-struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *);
-struct dentry * nfs_xdev_mount_common(struct file_system_type *, int,
-		const char *, struct nfs_mount_info *);
+int nfs_try_get_tree(struct nfs_fs_context *);
+int nfs_set_sb_security(struct super_block *, struct nfs_fs_context *);
+int nfs_clone_sb_security(struct super_block *, struct nfs_fs_context *);
+int nfs_get_tree_common(struct nfs_server *, struct nfs_fs_context *);
 void nfs_kill_super(struct super_block *);
-void nfs_fill_super(struct super_block *, struct nfs_mount_info *);
 
 extern struct rpc_stat nfs_rpcstat;
 
@@ -467,12 +442,9 @@ struct vfsmount *nfs_do_submount(struct dentry *, struct nfs_fh *,
 				 struct nfs_fattr *, rpc_authflavor_t);
 
 /* getroot.c */
-extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *,
-				   const char *);
+extern int nfs_get_root(struct super_block *s, struct nfs_fs_context *cfg);
 #if IS_ENABLED(CONFIG_NFS_V4)
-extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *,
-				    const char *);
-
+extern int nfs4_get_root(struct super_block *s, struct nfs_fs_context *cfg);
 extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool);
 #endif
 
@@ -491,7 +463,7 @@ int  nfs_show_options(struct seq_file *, struct dentry *);
 int  nfs_show_devname(struct seq_file *, struct dentry *);
 int  nfs_show_path(struct seq_file *, struct dentry *);
 int  nfs_show_stats(struct seq_file *, struct dentry *);
-int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
+int nfs_remount(struct super_block *sb, struct fs_context *fc);
 
 /* write.c */
 extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index e5686be67be8..f80062d626f9 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -18,6 +18,7 @@
 #include <linux/vfs.h>
 #include <linux/sunrpc/gss_api.h>
 #include "internal.h"
+#include "nfs.h"
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
 
@@ -209,16 +210,6 @@ void nfs_release_automount_timer(void)
 		cancel_delayed_work(&nfs_automount_task);
 }
 
-/*
- * Clone a mountpoint of the appropriate type
- */
-static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
-					   const char *devname,
-					   struct nfs_clone_mount *mountdata)
-{
-	return vfs_submount(mountdata->dentry, &nfs_xdev_fs_type, devname, mountdata);
-}
-
 /**
  * nfs_do_submount - set up mountpoint when crossing a filesystem boundary
  * @dentry - parent directory
@@ -230,27 +221,58 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
 struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
 				 struct nfs_fattr *fattr, rpc_authflavor_t authflavor)
 {
-	struct nfs_clone_mount mountdata = {
-		.sb = dentry->d_sb,
-		.dentry = dentry,
-		.fh = fh,
-		.fattr = fattr,
-		.authflavor = authflavor,
-	};
+	struct nfs_fs_context *ctx;
+	struct fs_context *fc;
 	struct vfsmount *mnt;
-	char *page = (char *) __get_free_page(GFP_USER);
-	char *devname;
+	char *buffer, *p;
+	int ret;
+
+	/* Open a new filesystem context, transferring parameters from the
+	 * parent superblock, including the network namespace.
+	 */
+	fc = vfs_new_fs_context(&nfs_fs_type, dentry->d_sb, 0,
+				FS_CONTEXT_FOR_SUBMOUNT);
+	if (IS_ERR(fc))
+		return ERR_CAST(fc);
+	ctx = container_of(fc, struct nfs_fs_context, fc);
+
+	mnt = ERR_PTR(-ENOMEM);
+	buffer = kmalloc(4096, GFP_USER);
+	if (!buffer)
+		goto err_fc;
+
+	ctx->mount_type		= NFS_MOUNT_CROSS_DEV;
+	ctx->selected_flavor	= authflavor;
+	ctx->clone_data.sb	= dentry->d_sb;
+	ctx->clone_data.dentry	= dentry;
+	ctx->clone_data.fattr	= fattr;
+	ctx->clone_data.cloned	= true;
+
+	nfs_copy_fh(ctx->mntfh, fh);
+
+	p = nfs_devname(dentry, buffer, 4096);
+	if (IS_ERR(p)) {
+		errorf("NFS: Couldn't determine submount pathname");
+		mnt = ERR_CAST(p);
+		goto err_buffer;
+	}
+
+	ctx->fc.device = kmemdup(p, buffer + 4096 - p, GFP_KERNEL);
+	kfree(buffer);
+	if (!ctx->fc.device)
+		goto err_fc;
 
-	if (page == NULL)
-		return ERR_PTR(-ENOMEM);
+	ret = vfs_get_tree(fc);
+	if (ret < 0)
+		goto err_fc;
 
-	devname = nfs_devname(dentry, page, PAGE_SIZE);
-	if (IS_ERR(devname))
-		mnt = ERR_CAST(devname);
-	else
-		mnt = nfs_do_clone_mount(NFS_SB(dentry->d_sb), devname, &mountdata);
+	mnt = vfs_kern_mount_fc(&ctx->fc);
+	goto err_fc;
 
-	free_page((unsigned long)page);
+err_buffer:
+	kfree(buffer);
+err_fc:
+	put_fs_context(fc);
 	return mnt;
 }
 EXPORT_SYMBOL_GPL(nfs_do_submount);
diff --git a/fs/nfs/nfs3_fs.h b/fs/nfs/nfs3_fs.h
index e134d6548ab7..2094bb1f022e 100644
--- a/fs/nfs/nfs3_fs.h
+++ b/fs/nfs/nfs3_fs.h
@@ -26,7 +26,7 @@ static inline int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
 #endif /* CONFIG_NFS_V3_ACL */
 
 /* nfs3client.c */
-struct nfs_server *nfs3_create_server(struct nfs_mount_info *, struct nfs_subversion *);
+struct nfs_server *nfs3_create_server(struct nfs_fs_context *);
 struct nfs_server *nfs3_clone_server(struct nfs_server *, struct nfs_fh *,
 				     struct nfs_fattr *, rpc_authflavor_t);
 
diff --git a/fs/nfs/nfs3client.c b/fs/nfs/nfs3client.c
index 7879f2a0fcfd..3b99d4985c4c 100644
--- a/fs/nfs/nfs3client.c
+++ b/fs/nfs/nfs3client.c
@@ -45,10 +45,10 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server)
 }
 #endif
 
-struct nfs_server *nfs3_create_server(struct nfs_mount_info *mount_info,
-				      struct nfs_subversion *nfs_mod)
+struct nfs_server *nfs3_create_server(struct nfs_fs_context *ctx)
 {
-	struct nfs_server *server = nfs_create_server(mount_info, nfs_mod);
+	struct nfs_server *server = nfs_create_server(ctx);
+
 	/* Create a client RPC handle for the NFS v3 ACL management interface */
 	if (!IS_ERR(server))
 		nfs_init_server_aclclient(server);
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 0c07b567118d..96e315916a34 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -975,7 +975,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
 	.nlmclnt_ops	= &nlmclnt_fl_close_lock_ops,
 	.getroot	= nfs3_proc_get_root,
 	.submount	= nfs_submount,
-	.try_mount	= nfs_try_mount,
+	.try_get_tree	= nfs_try_get_tree,
 	.getattr	= nfs3_proc_getattr,
 	.setattr	= nfs3_proc_setattr,
 	.lookup		= nfs3_proc_lookup,
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index af285cc27ccf..c5882668dc8a 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -467,7 +467,6 @@ extern const nfs4_stateid zero_stateid;
 /* nfs4super.c */
 struct nfs_mount_info;
 extern struct nfs_subversion nfs_v4;
-struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *, struct nfs_subversion *);
 extern bool nfs4_disable_idmapping;
 extern unsigned short max_session_slots;
 extern unsigned short max_session_cb_slots;
@@ -477,6 +476,9 @@ extern bool recover_lost_locks;
 #define NFS4_CLIENT_ID_UNIQ_LEN		(64)
 extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN];
 
+extern int nfs4_try_get_tree(struct nfs_fs_context *);
+extern int nfs4_get_tree(struct nfs_fs_context *);
+
 /* nfs4sysctl.c */
 #ifdef CONFIG_SYSCTL
 int nfs4_register_sysctl(void);
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 0b5e1ecfa8f8..431eae161383 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1032,14 +1032,14 @@ static int nfs4_init_server(struct nfs_server *server,
 
 	/* Get a client record */
 	error = nfs4_set_client(server,
-			ctx->nfs_server.hostname,
-			(const struct sockaddr *)&ctx->nfs_server.address,
-			ctx->nfs_server.addrlen,
-			ctx->client_address,
-			ctx->nfs_server.protocol,
-			&timeparms,
-			ctx->minorversion,
-			ctx->net);
+				ctx->nfs_server.hostname,
+				&ctx->nfs_server.address,
+				ctx->nfs_server.addrlen,
+				ctx->client_address,
+				ctx->nfs_server.protocol,
+				&timeparms,
+				ctx->minorversion,
+				ctx->fc.net_ns);
 	if (error < 0)
 		return error;
 
@@ -1062,10 +1062,7 @@ static int nfs4_init_server(struct nfs_server *server,
  * Create a version 4 volume record
  * - keyed on server and FSID
  */
-/*struct nfs_server *nfs4_create_server(const struct nfs_fs_context *data,
-				      struct nfs_fh *mntfh)*/
-struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
-				      struct nfs_subversion *nfs_mod)
+struct nfs_server *nfs4_create_server(struct nfs_fs_context *ctx)
 {
 	struct nfs_server *server;
 	bool auth_probe;
@@ -1075,14 +1072,14 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
 	if (!server)
 		return ERR_PTR(-ENOMEM);
 
-	auth_probe = mount_info->ctx->auth_info.flavor_len < 1;
+	auth_probe = ctx->auth_info.flavor_len < 1;
 
 	/* set up the general RPC client */
-	error = nfs4_init_server(server, mount_info->ctx);
+	error = nfs4_init_server(server, ctx);
 	if (error < 0)
 		goto error;
 
-	error = nfs4_server_common_setup(server, mount_info->mntfh, auth_probe);
+	error = nfs4_server_common_setup(server, ctx->mntfh, auth_probe);
 	if (error < 0)
 		goto error;
 
@@ -1096,8 +1093,7 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
 /*
  * Create an NFS4 referral server record
  */
-struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
-					       struct nfs_fh *mntfh)
+struct nfs_server *nfs4_create_referral_server(struct nfs_fs_context *ctx)
 {
 	struct nfs_client *parent_client;
 	struct nfs_server *server, *parent_server;
@@ -1108,7 +1104,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
 	if (!server)
 		return ERR_PTR(-ENOMEM);
 
-	parent_server = NFS_SB(data->sb);
+	parent_server = NFS_SB(ctx->clone_data.sb);
 	parent_client = parent_server->nfs_client;
 
 	/* Initialise the client representation from the parent server */
@@ -1116,9 +1112,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
 
 	/* Get a client representation.
 	 * Note: NFSv4 always uses TCP, */
-	error = nfs4_set_client(server, data->hostname,
-				data->addr,
-				data->addrlen,
+	error = nfs4_set_client(server,
+				ctx->nfs_server.hostname,
+				&ctx->nfs_server.address,
+				ctx->nfs_server.addrlen,
 				parent_client->cl_ipaddr,
 				rpc_protocol(parent_server->client),
 				parent_server->client->cl_timeout,
@@ -1127,13 +1124,14 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
 	if (error < 0)
 		goto error;
 
-	error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
+	error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout,
+					  ctx->selected_flavor);
 	if (error < 0)
 		goto error;
 
 	auth_probe = parent_server->auth_info.flavor_len < 1;
 
-	error = nfs4_server_common_setup(server, mntfh, auth_probe);
+	error = nfs4_server_common_setup(server, ctx->mntfh, auth_probe);
 	if (error < 0)
 		goto error;
 
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 7d531da1bae3..07466ae971cc 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -7,6 +7,7 @@
  * NFSv4 namespace
  */
 
+#include <linux/module.h>
 #include <linux/dcache.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
@@ -20,37 +21,64 @@
 #include <linux/inet.h>
 #include "internal.h"
 #include "nfs4_fs.h"
+#include "nfs.h"
 #include "dns_resolve.h"
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
 
 /*
+ * Work out the length that an NFSv4 path would render to as a standard posix
+ * path, with a leading slash but no terminating slash.
+ */
+static ssize_t nfs4_pathname_len(const struct nfs4_pathname *pathname)
+{
+	ssize_t len;
+	int i;
+
+	for (i = 0; i < pathname->ncomponents; i++) {
+		const struct nfs4_string *component = &pathname->components[i];
+
+		if (component->len > NAME_MAX)
+			goto too_long;
+		len += 1 + component->len; /* Adding "/foo" */
+		if (len > PATH_MAX)
+			goto too_long;
+	}
+	return len;
+
+too_long:
+	return -ENAMETOOLONG;
+}
+
+/*
  * Convert the NFSv4 pathname components into a standard posix path.
- *
- * Note that the resulting string will be placed at the end of the buffer
  */
-static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
-					 char *buffer, ssize_t buflen)
+static char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
+				  unsigned short *_len)
 {
-	char *end = buffer + buflen;
-	int n;
+	ssize_t len;
+	char *buf, *p;
+	int i;
 
-	*--end = '\0';
-	buflen--;
-
-	n = pathname->ncomponents;
-	while (--n >= 0) {
-		const struct nfs4_string *component = &pathname->components[n];
-		buflen -= component->len + 1;
-		if (buflen < 0)
-			goto Elong;
-		end -= component->len;
-		memcpy(end, component->data, component->len);
-		*--end = '/';
+	len = nfs4_pathname_len(pathname);
+	if (len < 0)
+		return ERR_PTR(len);
+	*_len = len;
+
+	p = buf = kmalloc(len + 1, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < pathname->ncomponents; i++) {
+		const struct nfs4_string *component = &pathname->components[i];
+
+		*p++ = '/';
+		memcpy(p, component->data, component->len);
+		p += component->len;
 	}
-	return end;
-Elong:
-	return ERR_PTR(-ENAMETOOLONG);
+
+	*p = 0;
+	return buf;
 }
 
 /*
@@ -99,21 +127,25 @@ static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
  */
 static int nfs4_validate_fspath(struct dentry *dentry,
 				const struct nfs4_fs_locations *locations,
-				char *page, char *page2)
+				struct nfs_fs_context *ctx)
 {
-	const char *path, *fs_path;
+	const char *path;
+	char *buf;
+	int n;
 
-	path = nfs4_path(dentry, page, PAGE_SIZE);
-	if (IS_ERR(path))
+	buf = kmalloc(4096, GFP_KERNEL);
+	path = nfs4_path(dentry, buf, 4096);
+	if (IS_ERR(path)) {
+		kfree(buf);
 		return PTR_ERR(path);
+	}
 
-	fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
-	if (IS_ERR(fs_path))
-		return PTR_ERR(fs_path);
-
-	if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
+	n = strncmp(path, ctx->nfs_server.export_path,
+		    ctx->nfs_server.export_path_len);
+	kfree(buf);
+	if (n != 0) {
 		dprintk("%s: path %s does not begin with fsroot %s\n",
-			__func__, path, fs_path);
+			__func__, path, ctx->nfs_server.export_path);
 		return -ENOENT;
 	}
 
@@ -234,56 +266,66 @@ nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode,
 	return new;
 }
 
-static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
-				     char *page, char *page2,
+static struct vfsmount *try_location(struct dentry *dentry,
+				     struct nfs_fs_context *ctx,
 				     const struct nfs4_fs_location *location)
 {
-	const size_t addr_bufsize = sizeof(struct sockaddr_storage);
-	struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client);
+	struct net *net = rpc_net_ns(NFS_SB(dentry->d_sb)->client);
 	struct vfsmount *mnt = ERR_PTR(-ENOENT);
-	char *mnt_path;
-	unsigned int maxbuflen;
-	unsigned int s;
+	unsigned int len, s;
+	char *p;
 
-	mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
-	if (IS_ERR(mnt_path))
-		return ERR_CAST(mnt_path);
-	mountdata->mnt_path = mnt_path;
-	maxbuflen = mnt_path - 1 - page2;
+	/* Allocate a buffer big enough to hold any of the hostnames plus a
+	 * terminating char and also a buffer big enough to hold the hostname
+	 * plus a colon plus the path.
+	 */
+	len = 0;
+	for (s = 0; s < location->nservers; s++) {
+		const struct nfs4_string *buf = &location->servers[s];
+		if (buf->len > len)
+			len = buf->len;
+	}
 
-	mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL);
-	if (mountdata->addr == NULL)
+	ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL);
+	if (!ctx->nfs_server.hostname)
 		return ERR_PTR(-ENOMEM);
 
+	ctx->fc.device = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1,
+				 GFP_KERNEL);
+	if (!ctx->fc.device)
+		return ERR_PTR(-ENOMEM);
+	
 	for (s = 0; s < location->nservers; s++) {
 		const struct nfs4_string *buf = &location->servers[s];
 
-		if (buf->len <= 0 || buf->len >= maxbuflen)
-			continue;
-
 		if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
 			continue;
 
-		mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
-				mountdata->addr, addr_bufsize, net);
-		if (mountdata->addrlen == 0)
+		ctx->nfs_server.addrlen =
+			nfs_parse_server_name(buf->data, buf->len,
+					      &ctx->nfs_server.address,
+					      sizeof(ctx->nfs_server._address),
+					      net);
+		if (ctx->nfs_server.addrlen == 0)
 			continue;
 
-		rpc_set_port(mountdata->addr, NFS_PORT);
+		rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
 
-		memcpy(page2, buf->data, buf->len);
-		page2[buf->len] = '\0';
-		mountdata->hostname = page2;
+		memcpy(ctx->nfs_server.hostname, buf->data, buf->len);
+		ctx->nfs_server.hostname[buf->len] = '\0';
 
-		snprintf(page, PAGE_SIZE, "%s:%s",
-				mountdata->hostname,
-				mountdata->mnt_path);
+		p = ctx->fc.device;
+		memcpy(p, buf->data, buf->len);
+		p += buf->len;
+		*p++ = ':';
+		memcpy(p, ctx->nfs_server.export_path, ctx->nfs_server.export_path_len);
+		p += ctx->nfs_server.export_path_len;
+		*p = 0;
 
-		mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata);
+		mnt = vfs_kern_mount_fc(&ctx->fc);
 		if (!IS_ERR(mnt))
 			break;
 	}
-	kfree(mountdata->addr);
 	return mnt;
 }
 
@@ -296,33 +338,43 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
 static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
 					    const struct nfs4_fs_locations *locations)
 {
-	struct vfsmount *mnt = ERR_PTR(-ENOENT);
-	struct nfs_clone_mount mountdata = {
-		.sb = dentry->d_sb,
-		.dentry = dentry,
-		.authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor,
-	};
-	char *page = NULL, *page2 = NULL;
+	struct nfs_fs_context *ctx;
+	struct fs_context *fc;
+	struct vfsmount *mnt;
+	char *export_path;
 	int loc, error;
 
 	if (locations == NULL || locations->nlocations <= 0)
 		goto out;
 
+	fc = vfs_new_fs_context(&nfs4_fs_type, dentry->d_sb, 0,
+			       FS_CONTEXT_FOR_SUBMOUNT);
+	if (IS_ERR(fc)) {
+		mnt = ERR_CAST(fc);
+		goto out;
+	}
+	ctx = container_of(fc, struct nfs_fs_context, fc);
+
 	dprintk("%s: referral at %pd2\n", __func__, dentry);
 
-	page = (char *) __get_free_page(GFP_USER);
-	if (!page)
-		goto out;
+	ctx->mount_type		= NFS4_MOUNT_REFERRAL;
+	ctx->clone_data.sb	= dentry->d_sb;
+	ctx->clone_data.dentry	= dentry;
+	ctx->clone_data.cloned	= true;
 
-	page2 = (char *) __get_free_page(GFP_USER);
-	if (!page2)
-		goto out;
+	export_path = nfs4_pathname_string(&locations->fs_path,
+					   &ctx->nfs_server.export_path_len);
+	if (IS_ERR(export_path)) {
+		mnt = ERR_CAST(export_path);
+		goto out_sc;
+	}
+	ctx->nfs_server.export_path = export_path;
 
 	/* Ensure fs path is a prefix of current dentry path */
-	error = nfs4_validate_fspath(dentry, locations, page, page2);
+	error = nfs4_validate_fspath(dentry, locations, ctx);
 	if (error < 0) {
 		mnt = ERR_PTR(error);
-		goto out;
+		goto out_sc;
 	}
 
 	for (loc = 0; loc < locations->nlocations; loc++) {
@@ -332,14 +384,14 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
 		    location->rootpath.ncomponents == 0)
 			continue;
 
-		mnt = try_location(&mountdata, page, page2, location);
+		mnt = try_location(ctx->clone_data.dentry, ctx, location);
 		if (!IS_ERR(mnt))
 			break;
 	}
 
+out_sc:
+	put_fs_context(fc);
 out:
-	free_page((unsigned long) page);
-	free_page((unsigned long) page2);
 	return mnt;
 }
 
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c08c46a3b8cd..ca792f799941 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -9307,8 +9307,9 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
 	.file_inode_ops	= &nfs4_file_inode_operations,
 	.file_ops	= &nfs4_file_operations,
 	.getroot	= nfs4_proc_get_root,
+	.get_tree	= nfs4_get_tree,
 	.submount	= nfs4_submount,
-	.try_mount	= nfs4_try_mount,
+	.try_get_tree	= nfs4_try_get_tree,
 	.getattr	= nfs4_proc_getattr,
 	.setattr	= nfs4_proc_setattr,
 	.lookup		= nfs4_proc_lookup,
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 70111f222a25..9f2eacfee42c 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -3,6 +3,7 @@
  */
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/mount.h>
 #include <linux/nfs4_mount.h>
 #include <linux/nfs_fs.h>
 #include "delegation.h"
@@ -17,36 +18,6 @@
 
 static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc);
 static void nfs4_evict_inode(struct inode *inode);
-static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *raw_data);
-static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *raw_data);
-static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *raw_data);
-
-static struct file_system_type nfs4_remote_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "nfs4",
-	.mount		= nfs4_remote_mount,
-	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
-
-static struct file_system_type nfs4_remote_referral_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "nfs4",
-	.mount		= nfs4_remote_referral_mount,
-	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
-
-struct file_system_type nfs4_referral_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "nfs4",
-	.mount		= nfs4_referral_mount,
-	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
 
 static const struct super_operations nfs4_sops = {
 	.alloc_inode	= nfs_alloc_inode,
@@ -60,16 +31,16 @@ static const struct super_operations nfs4_sops = {
 	.show_devname	= nfs_show_devname,
 	.show_path	= nfs_show_path,
 	.show_stats	= nfs_show_stats,
-	.remount_fs	= nfs_remount,
+	.remount_fs_fc	= nfs_remount,
 };
 
 struct nfs_subversion nfs_v4 = {
-	.owner = THIS_MODULE,
-	.nfs_fs   = &nfs4_fs_type,
-	.rpc_vers = &nfs_version4,
-	.rpc_ops  = &nfs_v4_clientops,
-	.sops     = &nfs4_sops,
-	.xattr    = nfs4_xattr_handlers,
+	.owner		= THIS_MODULE,
+	.nfs_fs		= &nfs4_fs_type,
+	.rpc_vers	= &nfs_version4,
+	.rpc_ops	= &nfs_v4_clientops,
+	.sops		= &nfs4_sops,
+	.xattr		= nfs4_xattr_handlers,
 };
 
 static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -103,47 +74,63 @@ static void nfs4_evict_inode(struct inode *inode)
 /*
  * Get the superblock for the NFS4 root partition
  */
-static struct dentry *
-nfs4_remote_mount(struct file_system_type *fs_type, int flags,
-		  const char *dev_name, void *info)
+static int nfs4_get_remote_tree(struct nfs_fs_context *ctx)
 {
-	struct nfs_mount_info *mount_info = info;
 	struct nfs_server *server;
-	struct dentry *mntroot = ERR_PTR(-ENOMEM);
 
-	mount_info->set_security = nfs_set_sb_security;
+	ctx->set_security = nfs_set_sb_security;
 
 	/* Get a volume representation */
-	server = nfs4_create_server(mount_info, &nfs_v4);
-	if (IS_ERR(server)) {
-		mntroot = ERR_CAST(server);
-		goto out;
-	}
-
-	mntroot = nfs_fs_mount_common(server, flags, dev_name, mount_info, &nfs_v4);
+	server = nfs4_create_server(ctx);
+	if (IS_ERR(server))
+		return PTR_ERR(server);
 
-out:
-	return mntroot;
+	return nfs_get_tree_common(server, ctx);
 }
 
-static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
-		int flags, void *data, const char *hostname)
+/*
+ * Create a mount for the root of the server.  We copy the mount context we
+ * have for the parameters and set its hostname, path and type.
+ */
+static struct vfsmount *nfs_do_root_mount(struct nfs_fs_context *ctx,
+					  const char *hostname,
+					  enum nfs_mount_type type)
 {
+	struct nfs_fs_context *root_ctx;
+	struct fs_context *root_fc;
 	struct vfsmount *root_mnt;
 	char *root_devname;
 	size_t len;
+	int ret;
+
+	root_fc = vfs_dup_fs_context(&ctx->fc);
+	if (IS_ERR(root_fc))
+		return ERR_CAST(root_fc);
+	root_ctx = container_of(root_fc, struct nfs_fs_context, fc);
+
+	root_ctx->mount_type = type;
+	root_ctx->nfs_server.export_path = (char *)nfs_slash;
 
 	len = strlen(hostname) + 5;
+	root_mnt = ERR_PTR(-ENOMEM);
 	root_devname = kmalloc(len, GFP_KERNEL);
 	if (root_devname == NULL)
-		return ERR_PTR(-ENOMEM);
+		goto out_fc;
+
 	/* Does hostname needs to be enclosed in brackets? */
 	if (strchr(hostname, ':'))
 		snprintf(root_devname, len, "[%s]:/", hostname);
 	else
 		snprintf(root_devname, len, "%s:/", hostname);
-	root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
-	kfree(root_devname);
+	root_ctx->fc.device = root_devname;
+
+	ret = vfs_get_tree(&root_ctx->fc);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	root_mnt = vfs_kern_mount_fc(&root_ctx->fc);
+out_fc:
+	put_fs_context(root_fc);
 	return root_mnt;
 }
 
@@ -234,89 +221,98 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
 	return dentry;
 }
 
-struct dentry *nfs4_try_mount(int flags, const char *dev_name,
-			      struct nfs_mount_info *mount_info,
-			      struct nfs_subversion *nfs_mod)
+int nfs4_try_get_tree(struct nfs_fs_context *ctx)
 {
-	char *export_path;
 	struct vfsmount *root_mnt;
-	struct dentry *res;
-	struct nfs_fs_context *ctx = mount_info->ctx;
+	struct dentry *root;
 
-	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
+	dfprintk(MOUNT, "--> nfs4_try_get_tree()\n");
 
-	export_path = ctx->nfs_server.export_path;
-	ctx->nfs_server.export_path = "/";
-	root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
-			ctx->nfs_server.hostname);
-	ctx->nfs_server.export_path = export_path;
-
-	res = nfs_follow_remote_path(root_mnt, export_path);
+	/* We create a mount for the server's root, walk to the requested
+	 * location and then create another mount for that.
+	 */
+	root_mnt = nfs_do_root_mount(ctx, ctx->nfs_server.hostname,
+				     NFS4_MOUNT_REMOTE);
+	if (IS_ERR(root_mnt))
+		return PTR_ERR(root_mnt);
+
+	root = nfs_follow_remote_path(root_mnt, ctx->nfs_server.export_path);
+	if (IS_ERR(root)) {
+		errorf("NFS4: Couldn't follow remote path");
+		dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld [error]\n",
+			 PTR_ERR(root));
+		return PTR_ERR(root);
+	}
 
-	dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n",
-		 PTR_ERR_OR_ZERO(res),
-		 IS_ERR(res) ? " [error]" : "");
-	return res;
+	ctx->fc.root = root;
+	dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n");
+	return 0;
 }
 
-static struct dentry *
-nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
-			   const char *dev_name, void *raw_data)
+static int nfs4_get_remote_referral_tree(struct nfs_fs_context *ctx)
 {
-	struct nfs_mount_info mount_info = {
-		.fill_super = nfs_fill_super,
-		.set_security = nfs_clone_sb_security,
-		.cloned = raw_data,
-	};
 	struct nfs_server *server;
-	struct dentry *mntroot = ERR_PTR(-ENOMEM);
 
-	dprintk("--> nfs4_referral_get_sb()\n");
+	dprintk("--> nfs4_get_remote_referral_tree()\n");
 
-	mount_info.mntfh = nfs_alloc_fhandle();
-	if (mount_info.cloned == NULL || mount_info.mntfh == NULL)
-		goto out;
+	ctx->set_security = nfs_clone_sb_security;
+
+	if (!ctx->clone_data.cloned)
+		return -EINVAL;
 
 	/* create a new volume representation */
-	server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh);
-	if (IS_ERR(server)) {
-		mntroot = ERR_CAST(server);
-		goto out;
-	}
+	server = nfs4_create_referral_server(ctx);
+	if (IS_ERR(server))
+		return PTR_ERR(server);
 
-	mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, &nfs_v4);
-out:
-	nfs_free_fhandle(mount_info.mntfh);
-	return mntroot;
+	return nfs_get_tree_common(server, ctx);
 }
 
 /*
  * Create an NFS4 server record on referral traversal
  */
-static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
-		int flags, const char *dev_name, void *raw_data)
+static int nfs4_get_referral_tree(struct nfs_fs_context *ctx)
 {
-	struct nfs_clone_mount *data = raw_data;
-	char *export_path;
 	struct vfsmount *root_mnt;
-	struct dentry *res;
+	struct dentry *root;
 
 	dprintk("--> nfs4_referral_mount()\n");
 
-	export_path = data->mnt_path;
-	data->mnt_path = "/";
+	root_mnt = nfs_do_root_mount(ctx, ctx->nfs_server.hostname,
+				     NFS4_MOUNT_REMOTE_REFERRAL);
 
-	root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
-			flags, data, data->hostname);
-	data->mnt_path = export_path;
+	root = nfs_follow_remote_path(root_mnt, ctx->nfs_server.export_path);
+	if (IS_ERR(root)) {
+		errorf("NFS4: Couldn't follow remote path");
+		dfprintk(MOUNT, "<-- nfs4_referral_mount() = %ld [error]\n",
+			 PTR_ERR(root));
+		return PTR_ERR(root);
+	}
 
-	res = nfs_follow_remote_path(root_mnt, export_path);
-	dprintk("<-- nfs4_referral_mount() = %d%s\n",
-		PTR_ERR_OR_ZERO(res),
-		IS_ERR(res) ? " [error]" : "");
-	return res;
+	ctx->fc.root = root;
+	dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n");
+	return 0;
 }
 
+/*
+ * Handle special NFS4 mount types.
+ */
+int nfs4_get_tree(struct nfs_fs_context *ctx)
+{
+	switch (ctx->mount_type) {
+	case NFS4_MOUNT_REMOTE:
+		return nfs4_get_remote_tree(ctx);
+
+	case NFS4_MOUNT_REFERRAL:
+		return nfs4_get_referral_tree(ctx);
+
+	case NFS4_MOUNT_REMOTE_REFERRAL:
+		return nfs4_get_remote_referral_tree(ctx);
+
+	default:
+		return 1;
+	}
+}
 
 static int __init init_nfs_v4(void)
 {
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 9872cf676a50..cd22b82e7bb8 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -705,7 +705,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
 	.file_ops	= &nfs_file_operations,
 	.getroot	= nfs_proc_get_root,
 	.submount	= nfs_submount,
-	.try_mount	= nfs_try_mount,
+	.try_get_tree	= nfs_try_get_tree,
 	.getattr	= nfs_proc_getattr,
 	.setattr	= nfs_proc_setattr,
 	.lookup		= nfs_proc_lookup,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index c13f0ff42df9..3ef689c08f48 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -69,27 +69,6 @@
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
 
-static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type,
-		int flags, const char *dev_name, void *raw_data);
-
-struct file_system_type nfs_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "nfs",
-	.mount		= nfs_fs_mount,
-	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
-MODULE_ALIAS_FS("nfs");
-EXPORT_SYMBOL_GPL(nfs_fs_type);
-
-struct file_system_type nfs_xdev_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "nfs",
-	.mount		= nfs_xdev_mount,
-	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
-
 const struct super_operations nfs_sops = {
 	.alloc_inode	= nfs_alloc_inode,
 	.destroy_inode	= nfs_destroy_inode,
@@ -102,22 +81,11 @@ const struct super_operations nfs_sops = {
 	.show_devname	= nfs_show_devname,
 	.show_path	= nfs_show_path,
 	.show_stats	= nfs_show_stats,
-	.remount_fs	= nfs_remount,
+	.remount_fs_fc	= nfs_remount,
 };
 EXPORT_SYMBOL_GPL(nfs_sops);
 
 #if IS_ENABLED(CONFIG_NFS_V4)
-struct file_system_type nfs4_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "nfs4",
-	.mount		= nfs_fs_mount,
-	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
-MODULE_ALIAS_FS("nfs4");
-MODULE_ALIAS("nfs4");
-EXPORT_SYMBOL_GPL(nfs4_fs_type);
-
 static int __init register_nfs4_fs(void)
 {
 	return register_filesystem(&nfs4_fs_type);
@@ -710,11 +678,11 @@ bool nfs_auth_info_match(const struct nfs_auth_info *auth_info,
 EXPORT_SYMBOL_GPL(nfs_auth_info_match);
 
 /*
- * Ensure that a specified authtype in cfg->auth_info is supported by
- * the server. Returns 0 and sets cfg->selected_flavor if it's ok, and
+ * Ensure that a specified authtype in ctx->auth_info is supported by
+ * the server. Returns 0 and sets ctx->selected_flavor if it's ok, and
  * -EACCES if not.
  */
-static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
+static int nfs_verify_authflavors(struct nfs_fs_context *ctx,
 			rpc_authflavor_t *server_authlist, unsigned int count)
 {
 	rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
@@ -732,7 +700,7 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
 	for (i = 0; i < count; i++) {
 		flavor = server_authlist[i];
 
-		if (nfs_auth_info_match(&cfg->auth_info, flavor))
+		if (nfs_auth_info_match(&ctx->auth_info, flavor))
 			goto out;
 
 		if (flavor == RPC_AUTH_NULL)
@@ -749,8 +717,8 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
 	return -EACCES;
 
 out:
-	cfg->selected_flavor = flavor;
-	dfprintk(MOUNT, "NFS: using auth flavor %u\n", cfg->selected_flavor);
+	ctx->selected_flavor = flavor;
+	dfprintk(MOUNT, "NFS: using auth flavor %u\n", ctx->selected_flavor);
 	return 0;
 }
 
@@ -758,50 +726,50 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
  * Use the remote server's MOUNT service to request the NFS file handle
  * corresponding to the provided path.
  */
-static int nfs_request_mount(struct nfs_fs_context *cfg,
+static int nfs_request_mount(struct nfs_fs_context *ctx,
 			     struct nfs_fh *root_fh,
 			     rpc_authflavor_t *server_authlist,
 			     unsigned int *server_authlist_len)
 {
 	struct nfs_mount_request request = {
 		.sap		= (struct sockaddr *)
-						&cfg->mount_server.address,
-		.dirpath	= cfg->nfs_server.export_path,
-		.protocol	= cfg->mount_server.protocol,
+						&ctx->mount_server.address,
+		.dirpath	= ctx->nfs_server.export_path,
+		.protocol	= ctx->mount_server.protocol,
 		.fh		= root_fh,
-		.noresvport	= cfg->flags & NFS_MOUNT_NORESVPORT,
+		.noresvport	= ctx->flags & NFS_MOUNT_NORESVPORT,
 		.auth_flav_len	= server_authlist_len,
 		.auth_flavs	= server_authlist,
-		.net		= cfg->net,
+		.net		= ctx->fc.net_ns,
 	};
 	int status;
 
-	if (cfg->mount_server.version == 0) {
-		switch (cfg->version) {
+	if (ctx->mount_server.version == 0) {
+		switch (ctx->version) {
 			default:
-				cfg->mount_server.version = NFS_MNT3_VERSION;
+				ctx->mount_server.version = NFS_MNT3_VERSION;
 				break;
 			case 2:
-				cfg->mount_server.version = NFS_MNT_VERSION;
+				ctx->mount_server.version = NFS_MNT_VERSION;
 		}
 	}
-	request.version = cfg->mount_server.version;
+	request.version = ctx->mount_server.version;
 
-	if (cfg->mount_server.hostname)
-		request.hostname = cfg->mount_server.hostname;
+	if (ctx->mount_server.hostname)
+		request.hostname = ctx->mount_server.hostname;
 	else
-		request.hostname = cfg->nfs_server.hostname;
+		request.hostname = ctx->nfs_server.hostname;
 
 	/*
 	 * Construct the mount server's address.
 	 */
-	if (cfg->mount_server.address.sa_family == AF_UNSPEC) {
-		memcpy(request.sap, &cfg->nfs_server.address,
-		       cfg->nfs_server.addrlen);
-		cfg->mount_server.addrlen = cfg->nfs_server.addrlen;
+	if (ctx->mount_server.address.sa_family == AF_UNSPEC) {
+		memcpy(request.sap, &ctx->nfs_server.address,
+		       ctx->nfs_server.addrlen);
+		ctx->mount_server.addrlen = ctx->nfs_server.addrlen;
 	}
-	request.salen = cfg->mount_server.addrlen;
-	nfs_set_port(request.sap, &cfg->mount_server.port, 0);
+	request.salen = ctx->mount_server.addrlen;
+	nfs_set_port(request.sap, &ctx->mount_server.port, 0);
 
 	/*
 	 * Now ask the mount server to map our export path
@@ -817,20 +785,17 @@ static int nfs_request_mount(struct nfs_fs_context *cfg,
 	return 0;
 }
 
-static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info,
-					struct nfs_subversion *nfs_mod)
+static struct nfs_server *nfs_try_mount_request(struct nfs_fs_context *ctx)
 {
 	int status;
 	unsigned int i;
 	bool tried_auth_unix = false;
 	bool auth_null_in_list = false;
 	struct nfs_server *server = ERR_PTR(-EACCES);
-	struct nfs_fs_context *ctx = mount_info->ctx;
 	rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS];
 	unsigned int authlist_len = ARRAY_SIZE(authlist);
 
-	status = nfs_request_mount(ctx, mount_info->mntfh, authlist,
-					&authlist_len);
+	status = nfs_request_mount(ctx, ctx->mntfh, authlist, &authlist_len);
 	if (status)
 		return ERR_PTR(status);
 
@@ -844,7 +809,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 			 ctx->selected_flavor);
 		if (status)
 			return ERR_PTR(status);
-		return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+		return ctx->nfs_mod->rpc_ops->create_server(ctx);
 	}
 
 	/*
@@ -871,7 +836,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 		}
 		dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor);
 		ctx->selected_flavor = flavor;
-		server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+		server = ctx->nfs_mod->rpc_ops->create_server(ctx);
 		if (!IS_ERR(server))
 			return server;
 	}
@@ -887,26 +852,27 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 	/* Last chance! Try AUTH_UNIX */
 	dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX);
 	ctx->selected_flavor = RPC_AUTH_UNIX;
-	return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+	return ctx->nfs_mod->rpc_ops->create_server(ctx);
 }
 
-struct dentry *nfs_try_mount(int flags, const char *dev_name,
-			     struct nfs_mount_info *mount_info,
-			     struct nfs_subversion *nfs_mod)
+int nfs_try_get_tree(struct nfs_fs_context *ctx)
 {
 	struct nfs_server *server;
 
-	if (mount_info->ctx->need_mount)
-		server = nfs_try_mount_request(mount_info, nfs_mod);
+	if (ctx->need_mount)
+		server = nfs_try_mount_request(ctx);
 	else
-		server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+		server = ctx->nfs_mod->rpc_ops->create_server(ctx);
 
-	if (IS_ERR(server))
-		return ERR_CAST(server);
+	if (IS_ERR(server)) {
+		errorf("NFS: Couldn't create server");
+		return PTR_ERR(server);
+	}
 
-	return nfs_fs_mount_common(server, flags, dev_name, mount_info, nfs_mod);
+	return nfs_get_tree_common(server, ctx);
 }
-EXPORT_SYMBOL_GPL(nfs_try_mount);
+EXPORT_SYMBOL_GPL(nfs_try_get_tree);
+
 
 #define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
 		| NFS_MOUNT_SECURE \
@@ -946,15 +912,11 @@ nfs_compare_remount_data(struct nfs_server *nfss,
 	return 0;
 }
 
-int
-nfs_remount(struct super_block *sb, int *flags, char *raw_data)
+int nfs_remount(struct super_block *sb, struct fs_context *fc)
 {
-	int error;
+	struct nfs_fs_context *ctx =
+		container_of(fc, struct nfs_fs_context, fc);
 	struct nfs_server *nfss = sb->s_fs_info;
-	struct nfs_fs_context *ctx;
-	struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data;
-	struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data;
-	u32 nfsvers = nfss->nfs_client->rpc_ops->version;
 
 	sync_filesystem(sb);
 
@@ -964,39 +926,9 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 	 * ones were explicitly specified. Fall back to legacy behavior and
 	 * just return success.
 	 */
-	if ((nfsvers == 4 && (!options4 || options4->version == 1)) ||
-	    (nfsvers <= 3 && (!options || (options->version >= 1 &&
-					   options->version <= 6))))
+	if (ctx->skip_remount_option_check)
 		return 0;
 
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-	if (ctx == NULL)
-		return -ENOMEM;
-
-	/* fill out struct with values from existing mount */
-	ctx->flags = nfss->flags;
-	ctx->rsize = nfss->rsize;
-	ctx->wsize = nfss->wsize;
-	ctx->retrans = nfss->client->cl_timeout->to_retries;
-	ctx->selected_flavor = nfss->client->cl_auth->au_flavor;
-	ctx->acregmin = nfss->acregmin / HZ;
-	ctx->acregmax = nfss->acregmax / HZ;
-	ctx->acdirmin = nfss->acdirmin / HZ;
-	ctx->acdirmax = nfss->acdirmax / HZ;
-	ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
-	ctx->nfs_server.port = nfss->port;
-	ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
-	ctx->version = nfsvers;
-	ctx->minorversion = nfss->nfs_client->cl_minorversion;
-	ctx->net = current->nsproxy->net_ns;
-	memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr,
-		ctx->nfs_server.addrlen);
-
-	/* overwrite those values with any that were specified */
-	error = -EINVAL;
-	if (!nfs_parse_mount_options((char *)options, ctx))
-		goto out;
-
 	/*
 	 * noac is a special case. It implies -o sync, but that's not
 	 * necessarily reflected in the mtab options. do_remount_sb
@@ -1004,13 +936,10 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 	 * remount options, so we have to explicitly reset it.
 	 */
 	if (ctx->flags & NFS_MOUNT_NOAC)
-		*flags |= SB_SYNCHRONOUS;
+		ctx->fc.sb_flags |= SB_SYNCHRONOUS;
 
 	/* compare new mount options with old ones */
-	error = nfs_compare_remount_data(nfss, ctx);
-out:
-	kfree(ctx);
-	return error;
+	return nfs_compare_remount_data(nfss, ctx);
 }
 EXPORT_SYMBOL_GPL(nfs_remount);
 
@@ -1037,9 +966,8 @@ static void nfs_initialise_sb(struct super_block *sb)
 /*
  * Finish setting up an NFS2/3 superblock
  */
-void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
+static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx)
 {
-	struct nfs_fs_context *ctx = mount_info->ctx;
 	struct nfs_server *server = NFS_SB(sb);
 
 	sb->s_blocksize_bits = 0;
@@ -1059,15 +987,13 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
 
  	nfs_initialise_sb(sb);
 }
-EXPORT_SYMBOL_GPL(nfs_fill_super);
 
 /*
  * Finish setting up a cloned NFS2/3/4 superblock
  */
-static void nfs_clone_super(struct super_block *sb,
-			    struct nfs_mount_info *mount_info)
+static void nfs_clone_super(struct super_block *sb, struct nfs_fs_context *ctx)
 {
-	const struct super_block *old_sb = mount_info->cloned->sb;
+	const struct super_block *old_sb = ctx->clone_data.sb;
 	struct nfs_server *server = NFS_SB(sb);
 
 	sb->s_blocksize_bits = old_sb->s_blocksize_bits;
@@ -1087,13 +1013,14 @@ static void nfs_clone_super(struct super_block *sb,
  	nfs_initialise_sb(sb);
 }
 
-static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
+static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b,
+				     const struct nfs_fs_context *ctx)
 {
 	const struct nfs_server *a = s->s_fs_info;
 	const struct rpc_clnt *clnt_a = a->client;
 	const struct rpc_clnt *clnt_b = b->client;
 
-	if ((s->s_flags & NFS_SB_MASK) != (flags & NFS_SB_MASK))
+	if ((s->s_flags & NFS_SB_MASK) != (ctx->fc.sb_flags & NFS_SB_MASK))
 		goto Ebusy;
 	if (a->nfs_client != b->nfs_client)
 		goto Ebusy;
@@ -1119,18 +1046,13 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n
 	return 0;
 }
 
-struct nfs_sb_mountdata {
-	struct nfs_server *server;
-	int mntflags;
-};
-
-static int nfs_set_super(struct super_block *s, void *data)
+static int nfs_set_super(struct super_block *s, struct fs_context *fc)
 {
-	struct nfs_sb_mountdata *sb_mntdata = data;
-	struct nfs_server *server = sb_mntdata->server;
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
+	struct nfs_server *server = ctx->server;
 	int ret;
 
-	s->s_flags = sb_mntdata->mntflags;
+	s->s_flags = ctx->fc.sb_flags;
 	s->s_fs_info = server;
 	s->s_d_op = server->nfs_client->rpc_ops->dentry_ops;
 	ret = set_anon_super(s, server);
@@ -1181,11 +1103,10 @@ static int nfs_compare_super_address(struct nfs_server *server1,
 	return 1;
 }
 
-static int nfs_compare_super(struct super_block *sb, void *data)
+static int nfs_compare_super(struct super_block *sb, struct fs_context *fc)
 {
-	struct nfs_sb_mountdata *sb_mntdata = data;
-	struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb);
-	int mntflags = sb_mntdata->mntflags;
+	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
+	struct nfs_server *server = ctx->server, *old = NFS_SB(sb);
 
 	if (!nfs_compare_super_address(old, server))
 		return 0;
@@ -1194,13 +1115,12 @@ static int nfs_compare_super(struct super_block *sb, void *data)
 		return 0;
 	if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
 		return 0;
-	return nfs_compare_mount_options(sb, server, mntflags);
+	return nfs_compare_mount_options(sb, server, ctx);
 }
 
 #ifdef CONFIG_NFS_FSCACHE
 static void nfs_get_cache_cookie(struct super_block *sb,
-				 struct nfs_fs_context *ctx,
-				 struct nfs_clone_mount *cloned)
+				 struct nfs_fs_context *ctx)
 {
 	struct nfs_server *nfss = NFS_SB(sb);
 	char *uniq = NULL;
@@ -1209,77 +1129,72 @@ static void nfs_get_cache_cookie(struct super_block *sb,
 	nfss->fscache_key = NULL;
 	nfss->fscache = NULL;
 
-	if (ctx) {
+	if (!ctx)
+		return;
+
+	if (ctx->clone_data.cloned) {
+		struct nfs_server *mnt_s = NFS_SB(ctx->clone_data.sb);
+		if (!(mnt_s->options & NFS_OPTION_FSCACHE))
+			return;
+		if (mnt_s->fscache_key) {
+			uniq = mnt_s->fscache_key->key.uniquifier;
+			ulen = mnt_s->fscache_key->key.uniq_len;
+		}
+	} else {
 		if (!(ctx->options & NFS_OPTION_FSCACHE))
 			return;
 		if (ctx->fscache_uniq) {
 			uniq = ctx->fscache_uniq;
 			ulen = strlen(ctx->fscache_uniq);
 		}
-	} else if (cloned) {
-		struct nfs_server *mnt_s = NFS_SB(cloned->sb);
-		if (!(mnt_s->options & NFS_OPTION_FSCACHE))
-			return;
-		if (mnt_s->fscache_key) {
-			uniq = mnt_s->fscache_key->key.uniquifier;
-			ulen = mnt_s->fscache_key->key.uniq_len;
-		};
-	} else
 		return;
+	}
 
 	nfs_fscache_get_super_cookie(sb, uniq, ulen);
 }
 #else
 static void nfs_get_cache_cookie(struct super_block *sb,
-				 struct nfs_fs_context *parsed,
-				 struct nfs_clone_mount *cloned)
+				 struct nfs_fs_context *ctx)
 {
 }
 #endif
 
-int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
-			struct nfs_mount_info *mount_info)
+int nfs_set_sb_security(struct super_block *sb, struct nfs_fs_context *ctx)
 {
 	int error;
 	unsigned long kflags = 0, kflags_out = 0;
-	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
+
+	if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL)
 		kflags |= SECURITY_LSM_NATIVE_LABELS;
 
-	error = security_sb_set_mnt_opts(s, &mount_info->ctx->lsm_opts,
-						kflags, &kflags_out);
+	error = security_sb_set_mnt_opts(sb, ctx->fc.security,
+					 kflags, &kflags_out);
 	if (error)
 		goto err;
 
-	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
-		!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
-		NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
+	if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL &&
+	    !(kflags_out & SECURITY_LSM_NATIVE_LABELS))
+		NFS_SB(sb)->caps &= ~NFS_CAP_SECURITY_LABEL;
 err:
 	return error;
 }
 EXPORT_SYMBOL_GPL(nfs_set_sb_security);
 
-int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
-			  struct nfs_mount_info *mount_info)
+int nfs_clone_sb_security(struct super_block *sb, struct nfs_fs_context *ctx)
 {
 	/* clone any lsm security options from the parent to the new sb */
-	if (d_inode(mntroot)->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops)
+	if (d_inode(ctx->fc.root)->i_op !=
+	    NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops)
 		return -ESTALE;
-	return security_sb_clone_mnt_opts(mount_info->cloned->sb, s);
+	return security_sb_clone_mnt_opts(ctx->clone_data.sb, sb);
 }
 EXPORT_SYMBOL_GPL(nfs_clone_sb_security);
 
-struct dentry *nfs_fs_mount_common(struct nfs_server *server,
-				   int flags, const char *dev_name,
-				   struct nfs_mount_info *mount_info,
-				   struct nfs_subversion *nfs_mod)
+int nfs_get_tree_common(struct nfs_server *server, struct nfs_fs_context *ctx)
 {
 	struct super_block *s;
 	struct dentry *mntroot = ERR_PTR(-ENOMEM);
-	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
-	struct nfs_sb_mountdata sb_mntdata = {
-		.mntflags = flags,
-		.server = server,
-	};
+	int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super;
 	int error;
 
 	if (server->flags & NFS_MOUNT_UNSHARED)
@@ -1287,16 +1202,19 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
 
 	/* -o noac implies -o sync */
 	if (server->flags & NFS_MOUNT_NOAC)
-		sb_mntdata.mntflags |= SB_SYNCHRONOUS;
+		ctx->fc.sb_flags |= SB_SYNCHRONOUS;
 
-	if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL)
-		if (mount_info->cloned->sb->s_flags & SB_SYNCHRONOUS)
-			sb_mntdata.mntflags |= SB_SYNCHRONOUS;
+	if (ctx->clone_data.cloned && ctx->clone_data.sb != NULL)
+		if (ctx->clone_data.sb->s_flags & SB_SYNCHRONOUS)
+			ctx->fc.sb_flags |= SB_SYNCHRONOUS;
 
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata);
+	ctx->server = server;
+	s = sget_fc(&ctx->fc, compare_super, nfs_set_super);
+	ctx->server = NULL;
 	if (IS_ERR(s)) {
-		mntroot = ERR_CAST(s);
+		error = PTR_ERR(s);
+		errorf("NFS: Couldn't get superblock");
 		goto out_err_nosb;
 	}
 
@@ -1316,22 +1234,28 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
 
 	if (!s->s_root) {
 		/* initial superblock/root creation */
-		mount_info->fill_super(s, mount_info);
-		nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned);
+		if (ctx->clone_data.sb)
+			nfs_clone_super(s, ctx);
+		else
+			nfs_fill_super(s, ctx);
+		nfs_get_cache_cookie(s, ctx);
 	}
 
-	mntroot = nfs_get_root(s, mount_info->mntfh, dev_name);
-	if (IS_ERR(mntroot))
+	error = nfs_get_root(s, ctx);
+	if (error < 0) {
+		errorf("NFS: Couldn't get root dentry");
 		goto error_splat_super;
+	}
 
-	error = mount_info->set_security(s, mntroot, mount_info);
+	error = ctx->set_security(s, ctx);
 	if (error)
 		goto error_splat_root;
 
 	s->s_flags |= SB_ACTIVE;
+	error = 0;
 
 out:
-	return mntroot;
+	return error;
 
 out_err_nosb:
 	nfs_free_server(server);
@@ -1339,53 +1263,11 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
 
 error_splat_root:
 	dput(mntroot);
-	mntroot = ERR_PTR(error);
 error_splat_super:
 	deactivate_locked_super(s);
 	goto out;
 }
-EXPORT_SYMBOL_GPL(nfs_fs_mount_common);
-
-struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *raw_data)
-{
-	struct nfs_mount_info mount_info = {
-		.fill_super = nfs_fill_super,
-		.set_security = nfs_set_sb_security,
-	};
-	struct dentry *mntroot = ERR_PTR(-ENOMEM);
-	struct nfs_subversion *nfs_mod;
-	int error;
-
-	mount_info.ctx = nfs_alloc_parsed_mount_data();
-	mount_info.mntfh = nfs_alloc_fhandle();
-	if (mount_info.ctx == NULL || mount_info.mntfh == NULL)
-		goto out;
-
-	/* Validate the mount data */
-	error = nfs_validate_mount_data(fs_type, raw_data, mount_info.ctx, mount_info.mntfh, dev_name);
-	if (error == NFS_TEXT_DATA)
-		error = nfs_validate_text_mount_data(raw_data, mount_info.ctx, dev_name);
-	if (error < 0) {
-		mntroot = ERR_PTR(error);
-		goto out;
-	}
-
-	nfs_mod = get_nfs_version(mount_info.ctx->version);
-	if (IS_ERR(nfs_mod)) {
-		mntroot = ERR_CAST(nfs_mod);
-		goto out;
-	}
-
-	mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info, nfs_mod);
-
-	put_nfs_version(nfs_mod);
-out:
-	nfs_free_parsed_mount_data(mount_info.ctx);
-	nfs_free_fhandle(mount_info.mntfh);
-	return mntroot;
-}
-EXPORT_SYMBOL_GPL(nfs_fs_mount);
+EXPORT_SYMBOL_GPL(nfs_get_tree_common);
 
 /*
  * Destroy an NFS2/3 superblock
@@ -1404,41 +1286,6 @@ void nfs_kill_super(struct super_block *s)
 }
 EXPORT_SYMBOL_GPL(nfs_kill_super);
 
-/*
- * Clone an NFS2/3/4 server record on xdev traversal (FSID-change)
- */
-static struct dentry *
-nfs_xdev_mount(struct file_system_type *fs_type, int flags,
-		const char *dev_name, void *raw_data)
-{
-	struct nfs_clone_mount *data = raw_data;
-	struct nfs_mount_info mount_info = {
-		.fill_super = nfs_clone_super,
-		.set_security = nfs_clone_sb_security,
-		.cloned = data,
-	};
-	struct nfs_server *server;
-	struct dentry *mntroot = ERR_PTR(-ENOMEM);
-	struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod;
-
-	dprintk("--> nfs_xdev_mount()\n");
-
-	mount_info.mntfh = mount_info.cloned->fh;
-
-	/* create a new volume representation */
-	server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor);
-
-	if (IS_ERR(server))
-		mntroot = ERR_CAST(server);
-	else
-		mntroot = nfs_fs_mount_common(server, flags,
-				dev_name, &mount_info, nfs_mod);
-
-	dprintk("<-- nfs_xdev_mount() = %ld\n",
-			IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L);
-	return mntroot;
-}
-
 #if IS_ENABLED(CONFIG_NFS_V4)
 
 /*
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index b28c83475ee8..71697103a887 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1542,6 +1542,7 @@ struct nfs_subversion;
 struct nfs_mount_info;
 struct nfs_client_initdata;
 struct nfs_pageio_descriptor;
+struct nfs_fs_context;
 
 /*
  * RPC procedure vector for NFSv2/NFSv3 demuxing
@@ -1556,10 +1557,10 @@ struct nfs_rpc_ops {
 
 	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fsinfo *);
+	int	(*get_tree)(struct nfs_fs_context *);
 	struct vfsmount *(*submount) (struct nfs_server *, struct dentry *,
 				      struct nfs_fh *, struct nfs_fattr *);
-	struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *,
-				     struct nfs_subversion *);
+	int	(*try_get_tree) (struct nfs_fs_context *);
 	int	(*getattr) (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fattr *, struct nfs4_label *);
 	int	(*setattr) (struct dentry *, struct nfs_fattr *,
@@ -1620,7 +1621,7 @@ struct nfs_rpc_ops {
 	struct nfs_client *(*init_client) (struct nfs_client *,
 				const struct nfs_client_initdata *);
 	void	(*free_client) (struct nfs_client *);
-	struct nfs_server *(*create_server)(struct nfs_mount_info *, struct nfs_subversion *);
+	struct nfs_server *(*create_server)(struct nfs_fs_context *);
 	struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
 					   struct nfs_fattr *, rpc_authflavor_t);
 };

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 25/27] ipc: Convert mqueue fs to fs_context [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (23 preceding siblings ...)
  2017-06-14 15:18 ` [PATCH 24/27] NFS: Add fs_context support. " David Howells
@ 2017-06-14 15:19 ` David Howells
  2017-06-15 10:07   ` Al Viro
  2017-06-15 14:47   ` David Howells
  2017-06-14 15:19 ` [PATCH 26/27] cpuset: Use " David Howells
                   ` (2 subsequent siblings)
  27 siblings, 2 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:19 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells,
	linux-security-module, linux-fsdevel

Convert the mqueue filesystem to use the filesystem context stuff.

Notes:

 (1) The relevant ipc namespace is selected in when the context is
     initialised (and it defaults to the current task's ipc namespace).
     The caller can override this before calling vfs_get_tree().

 (2) Rather than simply calling kern_mount_data(), mq_init_ns() creates a
     context, adjusts it and then does the rest of the mount procedure.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 ipc/mqueue.c |   90 ++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 68 insertions(+), 22 deletions(-)

diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 9e3a0aab4416..5a0594a79855 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -18,6 +18,7 @@
 #include <linux/pagemap.h>
 #include <linux/file.h>
 #include <linux/mount.h>
+#include <linux/fs_context.h>
 #include <linux/namei.h>
 #include <linux/sysctl.h>
 #include <linux/poll.h>
@@ -42,6 +43,11 @@
 #include <net/sock.h>
 #include "util.h"
 
+struct mqueue_fs_context {
+	struct fs_context	fc;
+	struct ipc_namespace	*ipc_ns;
+};
+
 #define MQUEUE_MAGIC	0x19800202
 #define DIRENT_SIZE	20
 #define FILENT_SIZE	80
@@ -90,6 +96,7 @@ struct mqueue_inode_info {
 static const struct inode_operations mqueue_dir_inode_operations;
 static const struct file_operations mqueue_file_operations;
 static const struct super_operations mqueue_super_ops;
+static const struct fs_context_operations mqueue_fs_context_ops;
 static void remove_notification(struct mqueue_inode_info *info);
 
 static struct kmem_cache *mqueue_inode_cachep;
@@ -305,7 +312,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
 	return ERR_PTR(ret);
 }
 
-static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
+static int mqueue_fill_super(struct super_block *sb, struct fs_context *fc)
 {
 	struct inode *inode;
 	struct ipc_namespace *ns = sb->s_fs_info;
@@ -326,18 +333,28 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
 	return 0;
 }
 
-static struct dentry *mqueue_mount(struct file_system_type *fs_type,
-			 int flags, const char *dev_name,
-			 void *data)
+static int mqueue_get_tree(struct fs_context *fc)
 {
-	struct ipc_namespace *ns;
-	if (flags & SB_KERNMOUNT) {
-		ns = data;
-		data = NULL;
-	} else {
-		ns = current->nsproxy->ipc_ns;
-	}
-	return mount_ns(fs_type, flags, data, ns, ns->user_ns, mqueue_fill_super);
+	struct mqueue_fs_context *ctx = container_of(fc, struct mqueue_fs_context, fc);
+
+	return mount_ns_fc(fc, mqueue_fill_super, ctx->ipc_ns);
+}
+
+static void mqueue_fs_context_free(struct fs_context *fc)
+{
+	struct mqueue_fs_context *ctx = container_of(fc, struct mqueue_fs_context, fc);
+
+	if (ctx->ipc_ns)
+		put_ipc_ns(ctx->ipc_ns);
+}
+
+static int mqueue_init_fs_context(struct fs_context *fc, struct super_block *src_sb)
+{
+	struct mqueue_fs_context *ctx = container_of(fc, struct mqueue_fs_context, fc);
+
+	ctx->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns);
+	ctx->fc.ops = &mqueue_fs_context_ops;
+	return 0;
 }
 
 static void init_once(void *foo)
@@ -1399,15 +1416,26 @@ static const struct super_operations mqueue_super_ops = {
 	.statfs = simple_statfs,
 };
 
+static const struct fs_context_operations mqueue_fs_context_ops = {
+	.free		= mqueue_fs_context_free,
+	.get_tree	= mqueue_get_tree,
+};
+
 static struct file_system_type mqueue_fs_type = {
-	.name = "mqueue",
-	.mount = mqueue_mount,
-	.kill_sb = kill_litter_super,
-	.fs_flags = FS_USERNS_MOUNT,
+	.name			= "mqueue",
+	.fs_context_size	= sizeof(struct mqueue_fs_context),
+	.init_fs_context	= mqueue_init_fs_context,
+	.kill_sb		= kill_litter_super,
+	.fs_flags		= FS_USERNS_MOUNT,
 };
 
 int mq_init_ns(struct ipc_namespace *ns)
 {
+	struct mqueue_fs_context *ctx;
+	struct fs_context *fc;
+	struct vfsmount *mnt;
+	int ret;
+
 	ns->mq_queues_count  = 0;
 	ns->mq_queues_max    = DFLT_QUEUESMAX;
 	ns->mq_msg_max       = DFLT_MSGMAX;
@@ -1415,13 +1443,31 @@ int mq_init_ns(struct ipc_namespace *ns)
 	ns->mq_msg_default   = DFLT_MSG;
 	ns->mq_msgsize_default  = DFLT_MSGSIZE;
 
-	ns->mq_mnt = kern_mount_data(&mqueue_fs_type, ns);
-	if (IS_ERR(ns->mq_mnt)) {
-		int err = PTR_ERR(ns->mq_mnt);
-		ns->mq_mnt = NULL;
-		return err;
+	fc = vfs_new_fs_context(&mqueue_fs_type, NULL, 0, FS_CONTEXT_FOR_NEW);
+	if (IS_ERR(fc))
+		return PTR_ERR(fc);
+
+	ctx = container_of(fc, struct mqueue_fs_context, fc);
+	if (ctx->ipc_ns != ns) {
+		put_ipc_ns(ctx->ipc_ns);
+		ctx->ipc_ns = get_ipc_ns(ns);
 	}
-	return 0;
+
+	ret = vfs_get_tree(fc);
+	if (ret < 0)
+		goto out_fc;
+
+	mnt = kern_mount_data_fc(fc);
+	if (IS_ERR(mnt)) {
+		ret = PTR_ERR(mnt);
+		goto out_fc;
+	}
+
+	ns->mq_mnt = mnt;
+	ret = 0;
+out_fc:
+	put_fs_context(fc);
+	return ret;
 }
 
 void mq_clear_sbinfo(struct ipc_namespace *ns)

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 26/27] cpuset: Use fs_context [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (24 preceding siblings ...)
  2017-06-14 15:19 ` [PATCH 25/27] ipc: Convert mqueue fs to fs_context " David Howells
@ 2017-06-14 15:19 ` David Howells
  2017-06-14 15:19 ` [PATCH 27/27] kernfs, sysfs, cgroup: Support " David Howells
  2017-06-14 22:31 ` [PATCH 27/27] ... and the intel_rdt driver David Howells
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:19 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, dhowells, linux-fsdevel,
	linux-security-module, Tejun Heo

Make the cpuset filesystem use the filesystem context.  This is potentially
tricky as the cpuset fs is almost an alias for the cgroup filesystem, but
with some special parameters.

This can, however, be handled by setting up an appropriate cgroup
filesystem and returning the root directory of that as the root dir of this
one.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Tejun Heo <tj@kernel.org>
---

 kernel/cgroup/cpuset.c |   58 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 45 insertions(+), 13 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index ae643412948a..c25914a4e41a 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -38,7 +38,7 @@
 #include <linux/mm.h>
 #include <linux/memory.h>
 #include <linux/export.h>
-#include <linux/mount.h>
+#include <linux/fs_context.h>
 #include <linux/namei.h>
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
@@ -303,25 +303,57 @@ static DECLARE_WAIT_QUEUE_HEAD(cpuset_attach_wq);
  * users. If someone tries to mount the "cpuset" filesystem, we
  * silently switch it to mount "cgroup" instead
  */
-static struct dentry *cpuset_mount(struct file_system_type *fs_type,
-			 int flags, const char *unused_dev_name, void *data)
+static int cpuset_get_tree(struct fs_context *fc)
 {
-	struct file_system_type *cgroup_fs = get_fs_type("cgroup");
-	struct dentry *ret = ERR_PTR(-ENODEV);
+	struct file_system_type *cgroup_fs;
+	struct fs_context *cg_fc;
+	int ret = -ENODEV;
+
+	cgroup_fs = get_fs_type("cgroup");
 	if (cgroup_fs) {
-		char mountopts[] =
-			"cpuset,noprefix,"
-			"release_agent=/sbin/cpuset_release_agent";
-		ret = cgroup_fs->mount(cgroup_fs, flags,
-					   unused_dev_name, mountopts);
-		put_filesystem(cgroup_fs);
+		ret = PTR_ERR(cgroup_fs);
+		goto out;
+	}
+
+	cg_fc = vfs_new_fs_context(cgroup_fs, NULL, 0, FS_CONTEXT_FOR_NEW);
+	put_filesystem(cgroup_fs);
+	if (IS_ERR(cg_fc)) {
+		ret = PTR_ERR(cg_fc);
+		goto out;
 	}
+
+	ret = generic_monolithic_mount_data(
+		fc, "cpuset,noprefix,release_agent=/sbin/cpuset_release_agent");
+	if (ret < 0)
+		goto out_fc;
+
+	ret = vfs_get_tree(cg_fc);
+	if (ret < 0)
+		goto out_fc;
+
+	fc->root = dget(cg_fc->root);
+	ret = 0;
+
+out_fc:
+	put_fs_context(cg_fc);
+out:
 	return ret;
 }
 
+static const struct fs_context_operations cpuset_fs_context_ops = {
+	.get_tree	= cpuset_get_tree,
+};
+
+static int cpuset_init_fs_context(struct fs_context *fc, struct super_block *src_sb)
+{
+	fc->ops = &cpuset_fs_context_ops;
+	return 0;
+}
+
 static struct file_system_type cpuset_fs_type = {
-	.name = "cpuset",
-	.mount = cpuset_mount,
+	.name			= "cpuset",
+	.fs_context_size	= sizeof(struct fs_context),
+	.init_fs_context	= cpuset_init_fs_context,
 };
 
 /*

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH 27/27] kernfs, sysfs, cgroup: Support fs_context [ver #5]
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (25 preceding siblings ...)
  2017-06-14 15:19 ` [PATCH 26/27] cpuset: Use " David Howells
@ 2017-06-14 15:19 ` David Howells
  2017-06-14 17:54   ` Tejun Heo
  2017-06-23 15:29   ` David Howells
  2017-06-14 22:31 ` [PATCH 27/27] ... and the intel_rdt driver David Howells
  27 siblings, 2 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 15:19 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: linux-nfs, jlayton, Greg Kroah-Hartman, linux-kernel, dhowells,
	linux-fsdevel, linux-security-module, Li Zefan, Johannes Weiner,
	Tejun Heo, cgroups

Make kernfs support superblock creation/mount/remount with fs_context.

This requires that sysfs and cgroup, which are built on kernfs, be made to
support fs_context also.

Notes:

 (1) A kernfs_fs_context struct is created to wrap fs_context and the
     kernfs mount parameters are moved in here (or are in fs_context).

 (2) kernfs_mount{,_ns}() are made into kernfs_get_tree().  The extra
     namespace tag parameter is passed in the context if desired

 (3) kernfs_free_fs_context() is provided as a destructor for the
     kernfs_fs_context struct, but for the moment it does nothing except
     get called in the right places.

 (4) sysfs doesn't wrap kernfs_fs_context since it has no parameters to
     pass, but possibly this should be done anyway in case someone wants to
     add a parameter in future.

 (5) A cgroup_fs_context struct is created to wrap kernfs_fs_context and
     the cgroup v1 and v2 mount parameters are all moved there.

 (6) cgroup1 parameter parsing error messages are now handled by invalf(),
     which allows userspace to collect them directly.

 (7) cgroup1 parameter cleanup is now done in the context destructor rather
     than in the mount/get_tree and remount functions.

Weirdies:

 (*) cgroup_do_get_tree() calls cset_cgroup_from_root() with locks held,
     but then uses the resulting pointer after dropping the locks.  I'm
     told this is okay and needs commenting.

 (*) The cgroup refcount web.  This really needs documenting.

 (*) cgroup2 only has one root?

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
cc: Tejun Heo <tj@kernel.org>
cc: Li Zefan <lizefan@huawei.com>
cc: Johannes Weiner <hannes@cmpxchg.org>
cc: cgroups@vger.kernel.org
---

 fs/kernfs/mount.c               |   88 ++++++------
 fs/sysfs/mount.c                |   59 +++++---
 include/linux/cgroup.h          |    3 
 include/linux/kernfs.h          |   37 +++--
 kernel/cgroup/cgroup-internal.h |   42 +++---
 kernel/cgroup/cgroup-v1.c       |  291 ++++++++++++++++++---------------------
 kernel/cgroup/cgroup.c          |  172 +++++++++++++++--------
 7 files changed, 383 insertions(+), 309 deletions(-)

diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index f1e0b15015b7..4391e68e9cac 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -21,13 +21,14 @@
 
 struct kmem_cache *kernfs_node_cache;
 
-static int kernfs_sop_remount_fs(struct super_block *sb, int *flags, char *data)
+static int kernfs_sop_remount_fs(struct super_block *sb, struct fs_context *fc)
 {
+	struct kernfs_fs_context *kfc = container_of(fc, struct kernfs_fs_context, fc);
 	struct kernfs_root *root = kernfs_info(sb)->root;
 	struct kernfs_syscall_ops *scops = root->syscall_ops;
 
 	if (scops && scops->remount_fs)
-		return scops->remount_fs(root, flags, data);
+		return scops->remount_fs(root, kfc);
 	return 0;
 }
 
@@ -59,7 +60,7 @@ const struct super_operations kernfs_sops = {
 	.drop_inode	= generic_delete_inode,
 	.evict_inode	= kernfs_evict_inode,
 
-	.remount_fs	= kernfs_sop_remount_fs,
+	.remount_fs_fc	= kernfs_sop_remount_fs,
 	.show_options	= kernfs_sop_show_options,
 	.show_path	= kernfs_sop_show_path,
 };
@@ -145,7 +146,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
 	} while (true);
 }
 
-static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
+static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *kfc)
 {
 	struct kernfs_super_info *info = kernfs_info(sb);
 	struct inode *inode;
@@ -156,7 +157,7 @@ static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
 	sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
 	sb->s_blocksize = PAGE_SIZE;
 	sb->s_blocksize_bits = PAGE_SHIFT;
-	sb->s_magic = magic;
+	sb->s_magic = kfc->magic;
 	sb->s_op = &kernfs_sops;
 	sb->s_xattr = kernfs_xattr_handlers;
 	sb->s_time_gran = 1;
@@ -183,20 +184,25 @@ static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
 	return 0;
 }
 
-static int kernfs_test_super(struct super_block *sb, void *data)
+static int kernfs_test_super(struct super_block *sb, struct fs_context *fc)
 {
+	struct kernfs_fs_context *kfc = container_of(fc, struct kernfs_fs_context, fc);
 	struct kernfs_super_info *sb_info = kernfs_info(sb);
-	struct kernfs_super_info *info = data;
+	struct kernfs_super_info *info = kfc->info;
 
 	return sb_info->root == info->root && sb_info->ns == info->ns;
 }
 
-static int kernfs_set_super(struct super_block *sb, void *data)
+static int kernfs_set_super(struct super_block *sb, struct fs_context *fc)
 {
+	struct kernfs_fs_context *kfc = container_of(fc, struct kernfs_fs_context, fc);
 	int error;
-	error = set_anon_super(sb, data);
-	if (!error)
-		sb->s_fs_info = data;
+
+	error = set_anon_super(sb, kfc->info);
+	if (!error) {
+		sb->s_fs_info = kfc->info;
+		kfc->info = NULL;
+	}
 	return error;
 }
 
@@ -214,24 +220,15 @@ const void *kernfs_super_ns(struct super_block *sb)
 }
 
 /**
- * kernfs_mount_ns - kernfs mount helper
- * @fs_type: file_system_type of the fs being mounted
- * @flags: mount flags specified for the mount
- * @root: kernfs_root of the hierarchy being mounted
- * @magic: file system specific magic number
- * @new_sb_created: tell the caller if we allocated a new superblock
- * @ns: optional namespace tag of the mount
- *
- * This is to be called from each kernfs user's file_system_type->mount()
- * implementation, which should pass through the specified @fs_type and
- * @flags, and specify the hierarchy and namespace tag to mount via @root
- * and @ns, respectively.
+ * kernfs_get_tree - kernfs filesystem access/retrieval helper
+ * @kfc: The filesystem context.
  *
- * The return value can be passed to the vfs layer verbatim.
+ * This is to be called from each kernfs user's fs_context->ops->get_tree()
+ * implementation, which should set the specified ->@fs_type and ->@flags, and
+ * specify the hierarchy and namespace tag to mount via ->@root and ->@ns,
+ * respectively.
  */
-struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
-				struct kernfs_root *root, unsigned long magic,
-				bool *new_sb_created, const void *ns)
+int kernfs_get_tree(struct kernfs_fs_context *kfc)
 {
 	struct super_block *sb;
 	struct kernfs_super_info *info;
@@ -239,37 +236,42 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
 
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
-		return ERR_PTR(-ENOMEM);
-
-	info->root = root;
-	info->ns = ns;
+		return -ENOMEM;
 
-	sb = sget_userns(fs_type, kernfs_test_super, kernfs_set_super, flags,
-			 &init_user_ns, info);
-	if (IS_ERR(sb) || sb->s_fs_info != info)
-		kfree(info);
+	info->root = kfc->root;
+	info->ns = kfc->ns_tag;
+
+	kfc->info = info;
+	sb = sget_fc(&kfc->fc, kernfs_test_super, kernfs_set_super);
+	if (kfc->info) {
+		kfree(kfc->info);
+		kfc->info = NULL;
+	} else {
+		kfc->ns_tag = NULL;
+		kfc->fc.degraded = true;
+	}
 	if (IS_ERR(sb))
-		return ERR_CAST(sb);
-
-	if (new_sb_created)
-		*new_sb_created = !sb->s_root;
+		return PTR_ERR(sb);
 
 	if (!sb->s_root) {
 		struct kernfs_super_info *info = kernfs_info(sb);
 
-		error = kernfs_fill_super(sb, magic);
+		kfc->new_sb_created = true;
+
+		error = kernfs_fill_super(sb, kfc);
 		if (error) {
 			deactivate_locked_super(sb);
-			return ERR_PTR(error);
+			return error;
 		}
 		sb->s_flags |= SB_ACTIVE;
 
 		mutex_lock(&kernfs_mutex);
-		list_add(&info->node, &root->supers);
+		list_add(&info->node, &info->root->supers);
 		mutex_unlock(&kernfs_mutex);
 	}
 
-	return dget(sb->s_root);
+	kfc->fc.root = dget(sb->s_root);
+	return 0;
 }
 
 /**
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index fb49510c5dcf..cfe900d43663 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -23,27 +23,45 @@
 static struct kernfs_root *sysfs_root;
 struct kernfs_node *sysfs_root_kn;
 
-static struct dentry *sysfs_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+static int sysfs_get_tree(struct fs_context *fc)
 {
-	struct dentry *root;
-	void *ns;
-	bool new_sb;
+	struct kernfs_fs_context *kfc = container_of(fc, struct kernfs_fs_context, fc);
+	int ret;
 
-	if (!(flags & SB_KERNMOUNT)) {
+	ret = kernfs_get_tree(kfc);
+	if (kfc->new_sb_created)
+		fc->root->d_sb->s_iflags |= SB_I_USERNS_VISIBLE;
+	return 0;
+}
+
+static void sysfs_fs_context_free(struct fs_context *fc)
+{
+	struct kernfs_fs_context *kfc = container_of(fc, struct kernfs_fs_context, fc);
+
+	if (kfc->ns_tag)
+		kobj_ns_drop(KOBJ_NS_TYPE_NET, kfc->ns_tag);
+	kernfs_free_fs_context(kfc);
+}
+
+static const struct fs_context_operations sysfs_fs_context_ops = {
+	.free		= sysfs_fs_context_free,
+	.get_tree	= sysfs_get_tree,
+};
+
+static int sysfs_init_fs_context(struct fs_context *fc, struct super_block *src_sb)
+{
+	struct kernfs_fs_context *kfc = container_of(fc, struct kernfs_fs_context, fc);
+
+	if (!(fc->sb_flags & SB_KERNMOUNT)) {
 		if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET))
-			return ERR_PTR(-EPERM);
+			return -EPERM;
 	}
 
-	ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
-	root = kernfs_mount_ns(fs_type, flags, sysfs_root,
-				SYSFS_MAGIC, &new_sb, ns);
-	if (IS_ERR(root) || !new_sb)
-		kobj_ns_drop(KOBJ_NS_TYPE_NET, ns);
-	else if (new_sb)
-		root->d_sb->s_iflags |= SB_I_USERNS_VISIBLE;
-
-	return root;
+	kfc->ns_tag = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
+	kfc->root = sysfs_root;
+	kfc->magic = SYSFS_MAGIC;
+	kfc->fc.ops = &sysfs_fs_context_ops;
+	return 0;
 }
 
 static void sysfs_kill_sb(struct super_block *sb)
@@ -55,10 +73,11 @@ static void sysfs_kill_sb(struct super_block *sb)
 }
 
 static struct file_system_type sysfs_fs_type = {
-	.name		= "sysfs",
-	.mount		= sysfs_mount,
-	.kill_sb	= sysfs_kill_sb,
-	.fs_flags	= FS_USERNS_MOUNT,
+	.name			= "sysfs",
+	.fs_context_size	= sizeof(struct kernfs_fs_context),
+	.init_fs_context	= sysfs_init_fs_context,
+	.kill_sb		= sysfs_kill_sb,
+	.fs_flags		= FS_USERNS_MOUNT,
 };
 
 int __init sysfs_init(void)
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 710a005c6b7a..d5b5d9ae373c 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -713,10 +713,11 @@ copy_cgroup_ns(unsigned long flags, struct user_namespace *user_ns,
 
 #endif /* !CONFIG_CGROUPS */
 
-static inline void get_cgroup_ns(struct cgroup_namespace *ns)
+static inline struct cgroup_namespace *get_cgroup_ns(struct cgroup_namespace *ns)
 {
 	if (ns)
 		refcount_inc(&ns->count);
+	return ns;
 }
 
 static inline void put_cgroup_ns(struct cgroup_namespace *ns)
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index a9b11b8d06f2..c137eef5b31f 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -16,6 +16,7 @@
 #include <linux/rbtree.h>
 #include <linux/atomic.h>
 #include <linux/wait.h>
+#include <linux/fs_context.h>
 
 struct file;
 struct dentry;
@@ -25,6 +26,7 @@ struct vm_area_struct;
 struct super_block;
 struct file_system_type;
 
+struct kernfs_fs_context;
 struct kernfs_open_node;
 struct kernfs_iattrs;
 
@@ -145,7 +147,7 @@ struct kernfs_node {
  * kernfs_node parameter.
  */
 struct kernfs_syscall_ops {
-	int (*remount_fs)(struct kernfs_root *root, int *flags, char *data);
+	int (*remount_fs)(struct kernfs_root *root, struct kernfs_fs_context *kfc);
 	int (*show_options)(struct seq_file *sf, struct kernfs_root *root);
 
 	int (*mkdir)(struct kernfs_node *parent, const char *name,
@@ -245,6 +247,20 @@ struct kernfs_ops {
 #endif
 };
 
+/*
+ * The kernfs superblock creation/mount parameter context.
+ */
+struct kernfs_fs_context {
+	struct fs_context	fc;
+	struct kernfs_root	*root;		/* Root of the hierarchy being mounted */
+	void			*ns_tag;	/* Namespace tag of the mount (or NULL) */
+	unsigned long		magic;		/* File system specific magic number */
+
+	/* The following are set/used by kernfs_mount() */
+	struct kernfs_super_info *info;		/* The new superblock info */
+	bool			new_sb_created;	/* Set to T if we allocated a new sb */
+};
+
 #ifdef CONFIG_KERNFS
 
 static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn)
@@ -328,9 +344,7 @@ int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr);
 void kernfs_notify(struct kernfs_node *kn);
 
 const void *kernfs_super_ns(struct super_block *sb);
-struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
-			       struct kernfs_root *root, unsigned long magic,
-			       bool *new_sb_created, const void *ns);
+int kernfs_get_tree(struct kernfs_fs_context *fc);
 void kernfs_kill_sb(struct super_block *sb);
 struct super_block *kernfs_pin_sb(struct kernfs_root *root, const void *ns);
 
@@ -430,11 +444,8 @@ static inline void kernfs_notify(struct kernfs_node *kn) { }
 static inline const void *kernfs_super_ns(struct super_block *sb)
 { return NULL; }
 
-static inline struct dentry *
-kernfs_mount_ns(struct file_system_type *fs_type, int flags,
-		struct kernfs_root *root, unsigned long magic,
-		bool *new_sb_created, const void *ns)
-{ return ERR_PTR(-ENOSYS); }
+static inline int kernfs_get_tree(struct kernfs_fs_context *fc)
+{ return -ENOSYS; }
 
 static inline void kernfs_kill_sb(struct super_block *sb) { }
 
@@ -511,13 +522,9 @@ static inline int kernfs_rename(struct kernfs_node *kn,
 	return kernfs_rename_ns(kn, new_parent, new_name, NULL);
 }
 
-static inline struct dentry *
-kernfs_mount(struct file_system_type *fs_type, int flags,
-		struct kernfs_root *root, unsigned long magic,
-		bool *new_sb_created)
+static inline void kernfs_free_fs_context(struct kernfs_fs_context *kfc)
 {
-	return kernfs_mount_ns(fs_type, flags, root,
-				magic, new_sb_created, NULL);
+	/* Note that we don't deal with kfc->ns_tag here. */
 }
 
 #endif	/* __LINUX_KERNFS_H */
diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h
index 00f4d6bf048f..a74e5f0d523a 100644
--- a/kernel/cgroup/cgroup-internal.h
+++ b/kernel/cgroup/cgroup-internal.h
@@ -8,6 +8,26 @@
 #include <linux/refcount.h>
 
 /*
+ * The cgroup filesystem superblock creation/mount context.
+ */
+struct cgroup_fs_context {
+	struct kernfs_fs_context kfc;
+	struct cgroup_root	*root;
+	struct cgroup_namespace	*ns;
+	u8		version;		/* cgroups version */
+
+	/* cgroup1 bits */
+	bool		cpuset_clone_children;
+	bool		none;			/* User explicitly requested empty subsystem */
+	bool		all_ss;			/* Seen 'all' option */
+	bool		one_ss;			/* Seen 'none' option */
+	u16		subsys_mask;		/* Selected subsystems */
+	unsigned int	flags;			/* CGRP_ROOT_* flags */
+	char		*name;			/* Hierarchy name */
+	char		*release_agent;		/* Path for release notifications */
+};
+
+/*
  * A cgroup can be associated with multiple css_sets as different tasks may
  * belong to different cgroups on different hierarchies.  In the other
  * direction, a css_set is naturally associated with multiple cgroups.
@@ -85,16 +105,6 @@ struct cgroup_mgctx {
 #define DEFINE_CGROUP_MGCTX(name)						\
 	struct cgroup_mgctx name = CGROUP_MGCTX_INIT(name)
 
-struct cgroup_sb_opts {
-	u16 subsys_mask;
-	unsigned int flags;
-	char *release_agent;
-	bool cpuset_clone_children;
-	char *name;
-	/* User explicitly requested empty subsystem */
-	bool none;
-};
-
 extern struct mutex cgroup_mutex;
 extern spinlock_t css_set_lock;
 extern struct cgroup_subsys *cgroup_subsys[];
@@ -163,12 +173,10 @@ int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen,
 			  struct cgroup_namespace *ns);
 
 void cgroup_free_root(struct cgroup_root *root);
-void init_cgroup_root(struct cgroup_root *root, struct cgroup_sb_opts *opts);
+void init_cgroup_root(struct cgroup_fs_context *ctx);
 int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask, int ref_flags);
 int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask);
-struct dentry *cgroup_do_mount(struct file_system_type *fs_type, int flags,
-			       struct cgroup_root *root, unsigned long magic,
-			       struct cgroup_namespace *ns);
+int cgroup_do_get_tree(struct cgroup_fs_context *ctx);
 
 bool cgroup_may_migrate_to(struct cgroup *dst_cgrp);
 void cgroup_migrate_finish(struct cgroup_mgctx *mgctx);
@@ -208,8 +216,8 @@ bool cgroup1_ssid_disabled(int ssid);
 void cgroup1_pidlist_destroy_all(struct cgroup *cgrp);
 void cgroup1_release_agent(struct work_struct *work);
 void cgroup1_check_for_release(struct cgroup *cgrp);
-struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
-			     void *data, unsigned long magic,
-			     struct cgroup_namespace *ns);
+int cgroup1_parse_option(struct cgroup_fs_context *ctx, char *p);
+int cgroup1_validate(struct cgroup_fs_context *ctx);
+int cgroup1_get_tree(struct cgroup_fs_context *ctx);
 
 #endif /* __CGROUP_INTERNAL_H */
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index 85d75152402d..050d4a0e8e5a 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -864,164 +864,160 @@ static int cgroup1_show_options(struct seq_file *seq, struct kernfs_root *kf_roo
 	return 0;
 }
 
-static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
+int cgroup1_parse_option(struct cgroup_fs_context *ctx, char *token)
 {
-	char *token, *o = data;
-	bool all_ss = false, one_ss = false;
-	u16 mask = U16_MAX;
 	struct cgroup_subsys *ss;
-	int nr_opts = 0;
 	int i;
 
-#ifdef CONFIG_CPUSETS
-	mask = ~((u16)1 << cpuset_cgrp_id);
-#endif
-
-	memset(opts, 0, sizeof(*opts));
-
-	while ((token = strsep(&o, ",")) != NULL) {
-		nr_opts++;
+	if (!strcmp(token, "none")) {
+		/* Explicitly have no subsystems */
+		ctx->none = true;
+		return 0;
+	}
+	if (!strcmp(token, "all")) {
+		/* Mutually exclusive option 'all' + subsystem name */
+		if (ctx->one_ss)
+			return invalf("cgroup1: all conflicts with subsys name");
+		ctx->all_ss = true;
+		return 0;
+	}
+	if (!strcmp(token, "noprefix")) {
+		ctx->flags |= CGRP_ROOT_NOPREFIX;
+		return 0;
+	}
+	if (!strcmp(token, "clone_children")) {
+		ctx->cpuset_clone_children = true;
+		return 0;
+	}
+	if (!strcmp(token, "xattr")) {
+		ctx->flags |= CGRP_ROOT_XATTR;
+		return 0;
+	}
+	if (!strncmp(token, "release_agent=", 14)) {
+		/* Specifying two release agents is forbidden */
+		if (ctx->release_agent)
+			return invalf("cgroup1: release_agent respecified");
+		ctx->release_agent =
+			kstrndup(token + 14, PATH_MAX - 1, GFP_KERNEL);
+		if (!ctx->release_agent)
+			return -ENOMEM;
+		return 0;
+	}
 
-		if (!*token)
-			return -EINVAL;
-		if (!strcmp(token, "none")) {
-			/* Explicitly have no subsystems */
-			opts->none = true;
-			continue;
-		}
-		if (!strcmp(token, "all")) {
-			/* Mutually exclusive option 'all' + subsystem name */
-			if (one_ss)
-				return -EINVAL;
-			all_ss = true;
-			continue;
-		}
-		if (!strcmp(token, "noprefix")) {
-			opts->flags |= CGRP_ROOT_NOPREFIX;
-			continue;
+	if (!strncmp(token, "name=", 5)) {
+		const char *name = token + 5;
+		/* Can't specify an empty name */
+		if (!strlen(name))
+			return invalf("cgroup1: Empty name");
+		/* Must match [\w.-]+ */
+		for (i = 0; i < strlen(name); i++) {
+			char c = name[i];
+			if (isalnum(c))
+				continue;
+			if ((c == '.') || (c == '-') || (c == '_'))
+				continue;
+			return invalf("cgroup1: Invalid name");
 		}
-		if (!strcmp(token, "clone_children")) {
-			opts->cpuset_clone_children = true;
+		/* Specifying two names is forbidden */
+		if (ctx->name)
+			return invalf("cgroup1: name respecified");
+		ctx->name = kstrndup(name,
+				     MAX_CGROUP_ROOT_NAMELEN - 1,
+				     GFP_KERNEL);
+		if (!ctx->name)
+			return -ENOMEM;
+
+		return 0;
+	}
+
+	for_each_subsys(ss, i) {
+		if (strcmp(token, ss->legacy_name))
 			continue;
-		}
-		if (!strcmp(token, "xattr")) {
-			opts->flags |= CGRP_ROOT_XATTR;
+		if (!cgroup_ssid_enabled(i))
 			continue;
-		}
-		if (!strncmp(token, "release_agent=", 14)) {
-			/* Specifying two release agents is forbidden */
-			if (opts->release_agent)
-				return -EINVAL;
-			opts->release_agent =
-				kstrndup(token + 14, PATH_MAX - 1, GFP_KERNEL);
-			if (!opts->release_agent)
-				return -ENOMEM;
+		if (cgroup1_ssid_disabled(i))
 			continue;
-		}
-		if (!strncmp(token, "name=", 5)) {
-			const char *name = token + 5;
-			/* Can't specify an empty name */
-			if (!strlen(name))
-				return -EINVAL;
-			/* Must match [\w.-]+ */
-			for (i = 0; i < strlen(name); i++) {
-				char c = name[i];
-				if (isalnum(c))
-					continue;
-				if ((c == '.') || (c == '-') || (c == '_'))
-					continue;
-				return -EINVAL;
-			}
-			/* Specifying two names is forbidden */
-			if (opts->name)
-				return -EINVAL;
-			opts->name = kstrndup(name,
-					      MAX_CGROUP_ROOT_NAMELEN - 1,
-					      GFP_KERNEL);
-			if (!opts->name)
-				return -ENOMEM;
 
-			continue;
-		}
+		/* Mutually exclusive option 'all' + subsystem name */
+		if (ctx->all_ss)
+			return invalf("cgroup1: subsys name conflicts with all");
+		ctx->subsys_mask |= (1 << i);
+		ctx->one_ss = true;
+		return 0;
+	}
 
-		for_each_subsys(ss, i) {
-			if (strcmp(token, ss->legacy_name))
-				continue;
-			if (!cgroup_ssid_enabled(i))
-				continue;
-			if (cgroup1_ssid_disabled(i))
-				continue;
+	if (i == CGROUP_SUBSYS_COUNT)
+		return -ENOENT;
+
+	return 0;
+}
 
-			/* Mutually exclusive option 'all' + subsystem name */
-			if (all_ss)
-				return -EINVAL;
-			opts->subsys_mask |= (1 << i);
-			one_ss = true;
+/*
+ * Validate the options that have been parsed.
+ */
+int cgroup1_validate(struct cgroup_fs_context *ctx)
+{
+	struct cgroup_subsys *ss;
+	u16 mask = U16_MAX;
+	int i;
 
-			break;
-		}
-		if (i == CGROUP_SUBSYS_COUNT)
-			return -ENOENT;
-	}
+#ifdef CONFIG_CPUSETS
+	mask = ~((u16)1 << cpuset_cgrp_id);
+#endif
 
 	/*
 	 * If the 'all' option was specified select all the subsystems,
 	 * otherwise if 'none', 'name=' and a subsystem name options were
 	 * not specified, let's default to 'all'
 	 */
-	if (all_ss || (!one_ss && !opts->none && !opts->name))
+	if (ctx->all_ss || (!ctx->one_ss && !ctx->none && !ctx->name))
 		for_each_subsys(ss, i)
 			if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i))
-				opts->subsys_mask |= (1 << i);
+				ctx->subsys_mask |= (1 << i);
 
 	/*
 	 * We either have to specify by name or by subsystems. (So all
 	 * empty hierarchies must have a name).
 	 */
-	if (!opts->subsys_mask && !opts->name)
-		return -EINVAL;
+	if (!ctx->subsys_mask && !ctx->name)
+		return invalf("cgroup1: Need name or subsystem set");
 
 	/*
 	 * Option noprefix was introduced just for backward compatibility
 	 * with the old cpuset, so we allow noprefix only if mounting just
 	 * the cpuset subsystem.
 	 */
-	if ((opts->flags & CGRP_ROOT_NOPREFIX) && (opts->subsys_mask & mask))
-		return -EINVAL;
+	if ((ctx->flags & CGRP_ROOT_NOPREFIX) && (ctx->subsys_mask & mask))
+		return invalf("cgroup1: noprefix used incorrectly");
 
 	/* Can't specify "none" and some subsystems */
-	if (opts->subsys_mask && opts->none)
-		return -EINVAL;
+	if (ctx->subsys_mask && ctx->none)
+		return invalf("cgroup1: none used incorrectly");
 
 	return 0;
 }
 
-static int cgroup1_remount(struct kernfs_root *kf_root, int *flags, char *data)
+static int cgroup1_remount(struct kernfs_root *kf_root, struct kernfs_fs_context *kfc)
 {
-	int ret = 0;
+	struct cgroup_fs_context *ctx = container_of(kfc, struct cgroup_fs_context, kfc);
 	struct cgroup_root *root = cgroup_root_from_kf(kf_root);
-	struct cgroup_sb_opts opts;
 	u16 added_mask, removed_mask;
+	int ret = 0;
 
 	cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp);
 
-	/* See what subsystems are wanted */
-	ret = parse_cgroupfs_options(data, &opts);
-	if (ret)
-		goto out_unlock;
-
-	if (opts.subsys_mask != root->subsys_mask || opts.release_agent)
+	if (ctx->subsys_mask != root->subsys_mask || ctx->release_agent)
 		pr_warn("option changes via remount are deprecated (pid=%d comm=%s)\n",
 			task_tgid_nr(current), current->comm);
 
-	added_mask = opts.subsys_mask & ~root->subsys_mask;
-	removed_mask = root->subsys_mask & ~opts.subsys_mask;
+	added_mask = ctx->subsys_mask & ~root->subsys_mask;
+	removed_mask = root->subsys_mask & ~ctx->subsys_mask;
 
 	/* Don't allow flags or name to change at remount */
-	if ((opts.flags ^ root->flags) ||
-	    (opts.name && strcmp(opts.name, root->name))) {
-		pr_err("option or name mismatch, new: 0x%x \"%s\", old: 0x%x \"%s\"\n",
-		       opts.flags, opts.name ?: "", root->flags, root->name);
+	if ((ctx->flags ^ root->flags) ||
+	    (ctx->name && strcmp(ctx->name, root->name))) {
+		invalf("option or name mismatch, new: 0x%x \"%s\", old: 0x%x \"%s\"",
+		       ctx->flags, ctx->name ?: "", root->flags, root->name);
 		ret = -EINVAL;
 		goto out_unlock;
 	}
@@ -1038,17 +1034,15 @@ static int cgroup1_remount(struct kernfs_root *kf_root, int *flags, char *data)
 
 	WARN_ON(rebind_subsystems(&cgrp_dfl_root, removed_mask));
 
-	if (opts.release_agent) {
+	if (ctx->release_agent) {
 		spin_lock(&release_agent_path_lock);
-		strcpy(root->release_agent_path, opts.release_agent);
+		strcpy(root->release_agent_path, ctx->release_agent);
 		spin_unlock(&release_agent_path_lock);
 	}
 
 	trace_cgroup_remount(root);
 
  out_unlock:
-	kfree(opts.release_agent);
-	kfree(opts.name);
 	mutex_unlock(&cgroup_mutex);
 	return ret;
 }
@@ -1062,25 +1056,19 @@ struct kernfs_syscall_ops cgroup1_kf_syscall_ops = {
 	.show_path		= cgroup_show_path,
 };
 
-struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
-			     void *data, unsigned long magic,
-			     struct cgroup_namespace *ns)
+/*
+ * Find or create a v1 cgroups superblock.
+ */
+int cgroup1_get_tree(struct cgroup_fs_context *ctx)
 {
 	struct super_block *pinned_sb = NULL;
-	struct cgroup_sb_opts opts;
 	struct cgroup_root *root;
 	struct cgroup_subsys *ss;
-	struct dentry *dentry;
 	int i, ret;
 	bool new_root = false;
 
 	cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp);
 
-	/* First find the desired set of subsystems */
-	ret = parse_cgroupfs_options(data, &opts);
-	if (ret)
-		goto out_unlock;
-
 	/*
 	 * Destruction of cgroup root is asynchronous, so subsystems may
 	 * still be dying after the previous unmount.  Let's drain the
@@ -1089,15 +1077,13 @@ struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
 	 * starting.  Testing ref liveliness is good enough.
 	 */
 	for_each_subsys(ss, i) {
-		if (!(opts.subsys_mask & (1 << i)) ||
+		if (!(ctx->subsys_mask & (1 << i)) ||
 		    ss->root == &cgrp_dfl_root)
 			continue;
 
 		if (!percpu_ref_tryget_live(&ss->root->cgrp.self.refcnt)) {
 			mutex_unlock(&cgroup_mutex);
-			msleep(10);
-			ret = restart_syscall();
-			goto out_free;
+			goto err_restart;
 		}
 		cgroup_put(&ss->root->cgrp);
 	}
@@ -1113,8 +1099,8 @@ struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
 		 * name matches but sybsys_mask doesn't, we should fail.
 		 * Remember whether name matched.
 		 */
-		if (opts.name) {
-			if (strcmp(opts.name, root->name))
+		if (ctx->name) {
+			if (strcmp(ctx->name, root->name))
 				continue;
 			name_match = true;
 		}
@@ -1123,15 +1109,15 @@ struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
 		 * If we asked for subsystems (or explicitly for no
 		 * subsystems) then they must match.
 		 */
-		if ((opts.subsys_mask || opts.none) &&
-		    (opts.subsys_mask != root->subsys_mask)) {
+		if ((ctx->subsys_mask || ctx->none) &&
+		    (ctx->subsys_mask != root->subsys_mask)) {
 			if (!name_match)
 				continue;
 			ret = -EBUSY;
-			goto out_unlock;
+			goto err_unlock;
 		}
 
-		if (root->flags ^ opts.flags)
+		if (root->flags ^ ctx->flags)
 			pr_warn("new mount options do not match the existing superblock, will be ignored\n");
 
 		/*
@@ -1152,9 +1138,7 @@ struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
 			mutex_unlock(&cgroup_mutex);
 			if (!IS_ERR_OR_NULL(pinned_sb))
 				deactivate_super(pinned_sb);
-			msleep(10);
-			ret = restart_syscall();
-			goto out_free;
+			goto err_restart;
 		}
 
 		ret = 0;
@@ -1166,41 +1150,35 @@ struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
 	 * specification is allowed for already existing hierarchies but we
 	 * can't create new one without subsys specification.
 	 */
-	if (!opts.subsys_mask && !opts.none) {
-		ret = -EINVAL;
-		goto out_unlock;
+	if (!ctx->subsys_mask && !ctx->none) {
+		ret = invalf("cgroup1: No subsys list or none specified");
+		goto err_unlock;
 	}
 
 	/* Hierarchies may only be created in the initial cgroup namespace. */
-	if (ns != &init_cgroup_ns) {
+	if (ctx->ns != &init_cgroup_ns) {
 		ret = -EPERM;
-		goto out_unlock;
+		goto err_unlock;
 	}
 
 	root = kzalloc(sizeof(*root), GFP_KERNEL);
 	if (!root) {
 		ret = -ENOMEM;
-		goto out_unlock;
+		goto err_unlock;
 	}
 	new_root = true;
+	ctx->root = root;
 
-	init_cgroup_root(root, &opts);
+	init_cgroup_root(ctx);
 
-	ret = cgroup_setup_root(root, opts.subsys_mask, PERCPU_REF_INIT_DEAD);
+	ret = cgroup_setup_root(root, ctx->subsys_mask, PERCPU_REF_INIT_DEAD);
 	if (ret)
 		cgroup_free_root(root);
 
 out_unlock:
 	mutex_unlock(&cgroup_mutex);
-out_free:
-	kfree(opts.release_agent);
-	kfree(opts.name);
-
-	if (ret)
-		return ERR_PTR(ret);
 
-	dentry = cgroup_do_mount(&cgroup_fs_type, flags, root,
-				 CGROUP_SUPER_MAGIC, ns);
+	ret = cgroup_do_get_tree(ctx);
 
 	/*
 	 * There's a race window after we release cgroup_mutex and before
@@ -1221,7 +1199,14 @@ struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
 	if (pinned_sb)
 		deactivate_super(pinned_sb);
 
-	return dentry;
+	return ret;
+
+err_restart:
+	msleep(10);
+	return restart_syscall();
+err_unlock:
+	mutex_unlock(&cgroup_mutex);
+	return ret;
 }
 
 static int __init cgroup1_wq_init(void)
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 8d4e85eae42c..4cbf8ef26577 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -1542,10 +1542,9 @@ int cgroup_show_path(struct seq_file *sf, struct kernfs_node *kf_node,
 	return len;
 }
 
-static int cgroup_remount(struct kernfs_root *kf_root, int *flags, char *data)
+static int cgroup_remount(struct kernfs_root *kf_root, struct kernfs_fs_context *kfc)
 {
-	pr_err("remount is not allowed\n");
-	return -EINVAL;
+	return invalf("cgroup2: Remount is not allowed");
 }
 
 /*
@@ -1626,8 +1625,9 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
 	INIT_WORK(&cgrp->release_agent_work, cgroup1_release_agent);
 }
 
-void init_cgroup_root(struct cgroup_root *root, struct cgroup_sb_opts *opts)
+void init_cgroup_root(struct cgroup_fs_context *ctx)
 {
+	struct cgroup_root *root = ctx->root;
 	struct cgroup *cgrp = &root->cgrp;
 
 	INIT_LIST_HEAD(&root->root_list);
@@ -1636,12 +1636,12 @@ void init_cgroup_root(struct cgroup_root *root, struct cgroup_sb_opts *opts)
 	init_cgroup_housekeeping(cgrp);
 	idr_init(&root->cgroup_idr);
 
-	root->flags = opts->flags;
-	if (opts->release_agent)
-		strcpy(root->release_agent_path, opts->release_agent);
-	if (opts->name)
-		strcpy(root->name, opts->name);
-	if (opts->cpuset_clone_children)
+	root->flags = ctx->flags;
+	if (ctx->release_agent)
+		strcpy(root->release_agent_path, ctx->release_agent);
+	if (ctx->name)
+		strcpy(root->name, ctx->name);
+	if (ctx->cpuset_clone_children)
 		set_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags);
 }
 
@@ -1742,56 +1742,49 @@ int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask, int ref_flags)
 	return ret;
 }
 
-struct dentry *cgroup_do_mount(struct file_system_type *fs_type, int flags,
-			       struct cgroup_root *root, unsigned long magic,
-			       struct cgroup_namespace *ns)
+int cgroup_do_get_tree(struct cgroup_fs_context *ctx)
 {
-	struct dentry *dentry;
-	bool new_sb;
+	int ret;
 
-	dentry = kernfs_mount(fs_type, flags, root->kf_root, magic, &new_sb);
+	ctx->kfc.root = ctx->root->kf_root;
+	
+	ret = kernfs_get_tree(&ctx->kfc);
+	if (ret < 0)
+		goto out_cgrp;
 
 	/*
 	 * In non-init cgroup namespace, instead of root cgroup's dentry,
 	 * we return the dentry corresponding to the cgroupns->root_cgrp.
 	 */
-	if (!IS_ERR(dentry) && ns != &init_cgroup_ns) {
+	if (ctx->ns != &init_cgroup_ns) {
 		struct dentry *nsdentry;
 		struct cgroup *cgrp;
 
 		mutex_lock(&cgroup_mutex);
 		spin_lock_irq(&css_set_lock);
 
-		cgrp = cset_cgroup_from_root(ns->root_cset, root);
+		cgrp = cset_cgroup_from_root(ctx->ns->root_cset, ctx->root);
 
 		spin_unlock_irq(&css_set_lock);
 		mutex_unlock(&cgroup_mutex);
 
-		nsdentry = kernfs_node_dentry(cgrp->kn, dentry->d_sb);
-		dput(dentry);
-		dentry = nsdentry;
+		nsdentry = kernfs_node_dentry(cgrp->kn, ctx->kfc.fc.root->d_sb);
+		dput(ctx->kfc.fc.root);
+		ctx->kfc.fc.root = nsdentry;
 	}
 
-	if (IS_ERR(dentry) || !new_sb)
-		cgroup_put(&root->cgrp);
+	ret = 0;
+	if (ctx->kfc.new_sb_created)
+		goto out_cgrp;
+	return 0;
 
-	return dentry;
+out_cgrp:
+	return ret;
 }
 
-static struct dentry *cgroup_mount(struct file_system_type *fs_type,
-			 int flags, const char *unused_dev_name,
-			 void *data)
+static int cgroup_get_tree(struct fs_context *fc)
 {
-	struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
-	struct dentry *dentry;
-
-	get_cgroup_ns(ns);
-
-	/* Check if the caller has permission to mount. */
-	if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) {
-		put_cgroup_ns(ns);
-		return ERR_PTR(-EPERM);
-	}
+	struct cgroup_fs_context *ctx = container_of(fc, struct cgroup_fs_context, kfc.fc);
 
 	/*
 	 * The first time anyone tries to mount a cgroup, enable the list
@@ -1800,24 +1793,80 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
 	if (!use_task_css_set_links)
 		cgroup_enable_task_cg_lists();
 
-	if (fs_type == &cgroup2_fs_type) {
-		if (data) {
-			pr_err("cgroup2: unknown option \"%s\"\n", (char *)data);
-			put_cgroup_ns(ns);
-			return ERR_PTR(-EINVAL);
-		}
+	switch (ctx->version) {
+	case 1:
+		return cgroup1_get_tree(ctx);
+
+	case 2:
 		cgrp_dfl_visible = true;
 		cgroup_get_live(&cgrp_dfl_root.cgrp);
 
-		dentry = cgroup_do_mount(&cgroup2_fs_type, flags, &cgrp_dfl_root,
-					 CGROUP2_SUPER_MAGIC, ns);
-	} else {
-		dentry = cgroup1_mount(&cgroup_fs_type, flags, data,
-				       CGROUP_SUPER_MAGIC, ns);
+		ctx->root = &cgrp_dfl_root;
+		return cgroup_do_get_tree(ctx);
+
+	default:
+		BUG();
 	}
+}
+
+static int cgroup_parse_option(struct fs_context *fc, char *p)
+{
+	struct cgroup_fs_context *ctx = container_of(fc, struct cgroup_fs_context, kfc.fc);
+
+	if (ctx->version == 1)
+		return cgroup1_parse_option(ctx, p);
+
+	return invalf("cgroup2: Options not supported");
+}
 
-	put_cgroup_ns(ns);
-	return dentry;
+static int cgroup_validate(struct fs_context *fc)
+{
+	struct cgroup_fs_context *ctx = container_of(fc, struct cgroup_fs_context, kfc.fc);
+
+	if (ctx->version)
+		return cgroup1_validate(ctx);
+	return 0;
+}
+
+/*
+ * Destroy a cgroup filesystem context.
+ */
+static void cgroup_fs_context_free(struct fs_context *fc)
+{
+	struct cgroup_fs_context *ctx = container_of(fc, struct cgroup_fs_context, kfc.fc);
+
+	kfree(ctx->name);
+	kfree(ctx->release_agent);
+	cgroup_put(&ctx->root->cgrp);
+	put_cgroup_ns(ctx->ns);
+	kernfs_free_fs_context(&ctx->kfc);
+}
+
+static const struct fs_context_operations cgroup_fs_context_ops = {
+	.free		= cgroup_fs_context_free,
+	.parse_option	= cgroup_parse_option,
+	.validate	= cgroup_validate,
+	.get_tree	= cgroup_get_tree,
+};
+
+/*
+ * Initialise the cgroup filesystem creation/reconfiguration context.  Notably,
+ * we select the namespace we're going to use.
+ */
+static int cgroup_init_fs_context(struct fs_context *fc, struct super_block *src_sb)
+{
+	struct cgroup_fs_context *ctx = container_of(fc, struct cgroup_fs_context, kfc.fc);
+	struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
+
+	/* Check if the caller has permission to mount. */
+	if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ctx->ns = get_cgroup_ns(ns);
+	ctx->version = (fc->fs_type == &cgroup2_fs_type) ? 2 : 1;
+	ctx->kfc.magic = (ctx->version == 2) ? CGROUP2_SUPER_MAGIC : CGROUP_SUPER_MAGIC;
+	ctx->kfc.fc.ops = &cgroup_fs_context_ops;
+	return 0;
 }
 
 static void cgroup_kill_sb(struct super_block *sb)
@@ -1842,17 +1891,19 @@ static void cgroup_kill_sb(struct super_block *sb)
 }
 
 struct file_system_type cgroup_fs_type = {
-	.name = "cgroup",
-	.mount = cgroup_mount,
-	.kill_sb = cgroup_kill_sb,
-	.fs_flags = FS_USERNS_MOUNT,
+	.name			= "cgroup",
+	.fs_context_size	= sizeof(struct cgroup_fs_context),
+	.init_fs_context	= cgroup_init_fs_context,
+	.kill_sb		= cgroup_kill_sb,
+	.fs_flags		= FS_USERNS_MOUNT,
 };
 
 static struct file_system_type cgroup2_fs_type = {
-	.name = "cgroup2",
-	.mount = cgroup_mount,
-	.kill_sb = cgroup_kill_sb,
-	.fs_flags = FS_USERNS_MOUNT,
+	.name			= "cgroup2",
+	.fs_context_size	= sizeof(struct cgroup_fs_context),
+	.init_fs_context	= cgroup_init_fs_context,
+	.kill_sb		= cgroup_kill_sb,
+	.fs_flags		= FS_USERNS_MOUNT,
 };
 
 int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen,
@@ -4460,11 +4511,12 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
  */
 int __init cgroup_init_early(void)
 {
-	static struct cgroup_sb_opts __initdata opts;
+	static struct cgroup_fs_context __initdata ctx;
 	struct cgroup_subsys *ss;
 	int i;
 
-	init_cgroup_root(&cgrp_dfl_root, &opts);
+	ctx.root = &cgrp_dfl_root;
+	init_cgroup_root(&ctx);
 	cgrp_dfl_root.cgrp.self.flags |= CSS_NO_REF;
 
 	RCU_INIT_POINTER(init_task.cgroups, &init_css_set);

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH 27/27] kernfs, sysfs, cgroup: Support fs_context [ver #5]
  2017-06-14 15:19 ` [PATCH 27/27] kernfs, sysfs, cgroup: Support " David Howells
@ 2017-06-14 17:54   ` Tejun Heo
  2017-06-23 15:29   ` David Howells
  1 sibling, 0 replies; 53+ messages in thread
From: Tejun Heo @ 2017-06-14 17:54 UTC (permalink / raw)
  To: David Howells
  Cc: mszeredi, viro, linux-nfs, jlayton, Greg Kroah-Hartman,
	linux-kernel, linux-fsdevel, linux-security-module, Li Zefan,
	Johannes Weiner, cgroups

Hello, David.

On Wed, Jun 14, 2017 at 04:19:19PM +0100, David Howells wrote:
> Make kernfs support superblock creation/mount/remount with fs_context.
> 
> This requires that sysfs and cgroup, which are built on kernfs, be made to
> support fs_context also.

Can you please include a brief rationale for doing this and include a
pointer to the fuller description on what's going on?

> Weirdies:
> 
>  (*) cgroup_do_get_tree() calls cset_cgroup_from_root() with locks held,
>      but then uses the resulting pointer after dropping the locks.  I'm
>      told this is okay and needs commenting.

Yeah, will add the comment.

>  (*) The cgroup refcount web.  This really needs documenting.

If you're talking about the mount refcnt part, yeah, it's confusing to
me too and we definitely need to document it better.

>  (*) cgroup2 only has one root?

Yeap.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-14 15:16 ` [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context " David Howells
@ 2017-06-14 18:02   ` Randy Dunlap
  2017-06-14 20:03   ` Casey Schaufler
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 53+ messages in thread
From: Randy Dunlap @ 2017-06-14 18:02 UTC (permalink / raw)
  To: David Howells, mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, linux-security-module, linux-fsdevel

On 06/14/17 08:16, David Howells wrote:
> Introduce a filesystem context concept to be used during superblock
> creation for mount and superblock reconfiguration for remount.  This is
> allocated at the beginning of the mount procedure and into it is placed:
> 
>  (1) Filesystem type.
> 
>  (2) Namespaces.
> 
>  (3) Device name.
> 
>  (4) Superblock flags (MS_*).
> 
>  (5) Security details.
> 
>  (6) Filesystem-specific data, as set by the mount options.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
> 
>  Documentation/filesystems/mounting.txt |  436 ++++++++++++++++++++++++++++++++
>  include/linux/fs_context.h             |   72 +++++
>  2 files changed, 508 insertions(+)
>  create mode 100644 Documentation/filesystems/mounting.txt
>  create mode 100644 include/linux/fs_context.h
> 
> diff --git a/Documentation/filesystems/mounting.txt b/Documentation/filesystems/mounting.txt
> new file mode 100644
> index 000000000000..315a5a4ff5cc
> --- /dev/null
> +++ b/Documentation/filesystems/mounting.txt
> @@ -0,0 +1,436 @@
> +			      ===================
> +			      FILESYSTEM MOUNTING
> +			      ===================
> +
> +CONTENTS
> +
> + (1) Overview.
> +
> + (2) The filesystem context.
> +
> + (3) The filesystem context operations.
> +
> + (4) Filesystem context security.
> +
> + (5) VFS filesystem context operations.
> +
> +
> +========
> +OVERVIEW
> +========
> +
> +The creation of new mounts is now to be done in a multistep process:
> +
> + (1) Create a filesystem context.
> +
> + (2) Parse the options and attach them to the context.  Options may be passed
> +     individually from userspace.
> +
> + (3) Validate and pre-process the context.
> +
> + (4) Get or create a superblock and mountable root.
> +
> + (5) Perform the mount.
> +
> + (6) Return an error message attached to the context.
> +
> + (7) Destroy the context.
> +
> +To support this, the file_system_type struct gains two new fields:
> +
> +	unsigned short fs_context_size;
> +
> +which indicates the total amount of space that should be allocated for context
> +data (see the Filesystem Context section), and:
> +
> +	int (*init_fs_context)(struct fs_context *fc, struct super_block *src_sb);
> +
> +which is invoked to set up the filesystem-specific parts of a filesystem
> +context, including the additional space.  The src_sb parameter is used to
> +convey the superblock from which the filesystem may draw extra information
> +(such as namespaces), for submount (FS_CONTEXT_FOR_SUBMOUNT) or remount

                       ;

> +(FS_CONTEXT_FOR_REMOUNT) purposes or it will be NULL.
> +
> +Note that security initialisation is done *after* the filesystem is called so
> +that the namespaces may be adjusted first.
> +
> +And the super_operations struct gains one:

                                         one field:

> +
> +	int (*remount_fs_fc) (struct super_block *, struct fs_context *);
> +
> +This shadows the ->remount_fs() operation and takes a prepared filesystem
> +context instead of the mount flags and data page.  It may modify the ms_flags
> +in the context for the caller to pick up.
> +
> +[NOTE] remount_fs_fc is intended as a replacement for remount_fs.
> +
> +
> +======================
> +THE FILESYSTEM CONTEXT
> +======================
> +
> +The creation and reconfiguration of a superblock is governed by a filesystem
> +context.  This is represented by the fs_context structure:
> +
> +	struct fs_context {
> +		const struct fs_context_operations *ops;
> +		struct file_system_type *fs;
> +		struct dentry		*root;
> +		struct user_namespace	*user_ns;
> +		struct net		*net_ns;
> +		const struct cred	*cred;
> +		char			*device;
> +		void			*security;
> +		unsigned int		sb_flags;
> +		bool			sloppy;
> +		bool			silent;
> +		bool			degraded;
> +		enum fs_context_purpose	purpose : 8;
> +	};
> +
> +When the VFS creates this, it allocates ->fs_context_size bytes (as specified
> +by the file_system_type object) to hold both the fs_context struct and any
> +extra data required by the filesystem.  The fs_context struct is placed at the
> +beginning of this space.  Any extra space beyond that is for use by the
> +filesystem.  The filesystem should wrap the struct in its own, e.g.:
> +
> +	struct nfs_fs_context {
> +		struct fs_context fc;
> +		...
> +	};
> +
> +placing the fs_context struct first.  container_of() can then be used.  The
> +file_system_type would be initialised thus:
> +
> +	struct file_system_type nfs = {
> +		...
> +		.fs_context_size	= sizeof(struct nfs_fs_context),
> +		.init_fs_context	= nfs_init_fs_context,
> +		...
> +	};
> +
> +The fs_context fields are as follows:
> +
> + (*) const struct fs_context_operations *ops
> +
> +     These are operations that can be done on a filesystem context (see
> +     below).  This must be set by the ->init_fs_context() file_system_type
> +     operation.
> +
> + (*) struct file_system_type *fs
> +
> +     A pointer to the file_system_type of the filesystem that is being
> +     constructed or reconfigured.  This retains a ref on the type owner.

s/ref/reference/

> +
> + (*) struct dentry *root
> +
> +     A pointer to the root of the mountable tree (and indirectly, the
> +     superblock thereof).  This is filled in by the ->get_tree() op.
> +
> + (*) struct user_namespace *user_ns
> + (*) struct net *net_ns
> +
> +     This is a subset of the namespaces in use by the invoking process.  This

	These are                                                           They

> +     retains a ref on each namespace.  The subscribed namespaces may be

	retain a reference

> +     replaced by the filesystem to reflect other sources, such as the parent
> +     mount superblock on an automount.
> +
> + (*) struct cred *cred
> +
> +     The mounter's credentials.  This retains a ref on the credentials.

s/ref/reference/

> +
> + (*) char *device
> +
> +     This is the device to be mounted.  It may be a block device
> +     (e.g. /dev/sda1) or something more exotic, such as the "host:/path" that
> +     NFS desires.
> +
> + (*) void *security
> +
> +     A place for the LSMs to hang their security data for the superblock.  The
> +     relevant security operations are described below.
> +
> + (*) unsigned int sb_flags
> +
> +     This holds the MS_* flags mount flags.
> +
> + (*) bool sloppy
> + (*) bool silent
> +
> +     These are set if the sloppy or silent mount options are given.
> +
> +     [NOTE] sloppy is probably unnecessary when userspace passes over one
> +     option at a time since the error can just be ignored if userspace deems it
> +     to be unimportant.
> +
> +     [NOTE] silent is probably redundant with ms_flags & MS_SILENT.
> +
> + (*) bool degraded
> +
> +     This is set if any preallocated resources in the context have been used
> +     up, thereby rendering it unreusable for the ->get_tree() op.
> +
> + (*) enum fs_context_purpose
> +
> +     This indicates the purpose for which the context is intended.  The
> +     available values are:
> +
> +	FS_CONTEXT_FOR_NEW	-- New mount
> +	FS_CONTEXT_FOR_SUBMOUNT	-- New automatic submount of extant mount
> +	FS_CONTEXT_FOR_REMOUNT	-- Change an existing mount
> +
> +The mount context is created by calling vfs_new_fs_context(), vfs_sb_reconfig()
> +or vfs_dup_fs_context() and is destroyed with put_fs_context().  Note that the
> +structure is not refcounted.
> +
> +VFS, security and filesystem mount options are set individually with
> +vfs_parse_mount_option().  Options provided by the old mount(2) system call as
> +a page of data can be parsed with generic_monolithic_mount_data().
> +
> +When mounting, the filesystem is allowed to take data from any of the pointers
> +and attach it to the superblock (or whatever), provided it clears the pointer
> +in the mount context.
> +
> +The filesystem is also allowed to allocate resources and pin them with the
> +mount context.  For instance, NFS might pin the appropriate protocol version
> +module.
> +
> +
> +=================================
> +THE FILESYSTEM CONTEXT OPERATIONS
> +=================================
> +
> +The filesystem context points to a table of operations:
> +
> +	struct fs_context_operations {
> +		void (*free)(struct fs_context *fc);
> +		int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
> +		int (*parse_option)(struct fs_context *fc, char *p);
> +		int (*monolithic_mount_data)(struct fs_context *fc, void *data);
> +		int (*validate)(struct fs_context *fc);
> +		int (*get_tree)(struct fs_context *fc);
> +	};
> +
> +These operations are invoked by the various stages of the mount procedure to
> +manage the filesystem context.  They are as follows:
> +
> + (*) void (*free)(struct fs_context *fc);
> +
> +     Called to clean up the filesystem-specific part of the filesystem context
> +     when the context is destroyed.  It should be aware that parts of the
> +     context may have been removed and NULL'd out by ->get_tree().
> +
> + (*) int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
> +
> +     Called when a filesystem context has been duplicated to get any refs or
> +     copy any non-referenced resources held in the filesystem-specific part of
> +     the filesystem context.  An error may be returned to indicate failure to
> +     do this.
> +
> +     [!] Note that even if this fails, put_fs_context() will be called
> +	 immediately thereafter, so ->dup() *must* make the
> +	 filesystem-specific part safe for ->free().
> +
> + (*) int (*parse_option)(struct fs_context *fc, char *p);
> +
> +     Called when an option is to be added to the filesystem context.  p points
> +     to the option string, likely in "key[=val]" format.  VFS-specific options
> +     will have been weeded out and fc->sb_flags updated in the context.
> +     Security options will also have been weeded out and fc->security updated.
> +
> +     If successful, 0 should be returned and a negative error code otherwise.
> +     If an ambiguous error (such as -EINVAL) is returned, sb_cfg_error() or
> +     sb_cfg_inval() should be used to provide a string that provides more
> +     information.
> +
> + (*) int (*monolithic_mount_data)(struct fs_context *fc, void *data);
> +
> +     Called when the mount(2) system call is invoked to pass the entire data
> +     page in one go.  If this is expected to be just a list of "key[=val]"
> +     items separated by commas, then this may be set to NULL.
> +
> +     The return value is as for ->parse_option().
> +
> +     If the filesystem (eg. NFS) needs to examine the data first and then finds
> +     it's the standard key-val list then it may pass it off to
> +     generic_monolithic_mount_data().
> +
> + (*) int (*validate)(struct fs_context *fc);
> +
> +     Called when all the options have been applied and the mount is about to
> +     take place.  It is should check for inconsistencies from mount options and
> +     it is also allowed to do preliminary resource acquisition.  For instance,
> +     the core NFS module could load the NFS protocol module here.
> +
> +     Note that if fc->mount_type == FS_CONTEXT_FOR_REMOUNT, some of the options
> +     necessary for a new mount may not be set.
> +
> +     The return value is as for ->parse_option().
> +
> + (*) int (*get_tree)(struct fs_context *fc);
> +
> +     Called to get or create the mountable root and superblock, using the
> +     information stored in the filesystem context (remounts go
> +     via a different vector).  It may detach any resources it desires from the
> +     filesystem context and transfer them to the superblock it
> +     creates.
> +
> +     On success it should set fc->root to the mountable root.
> +
> +     In the case of an error, it should return a negative error code and
> +     consider invoking sb_cfg_inval() or sb_cfg_error().
> +
> +
> +=========================================
> +FILESYSTEM CONTEXT SECURITY
> +========================================
> +
> +The filesystem context contains a security points that the LSMs

                                              point or pointer ?

> +can use for building up a security context for the superblock to be mounted.
> +There are a number of operations used by the new mount code for this purpose:


-- 
~Randy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-14 15:16 ` [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context " David Howells
  2017-06-14 18:02   ` Randy Dunlap
@ 2017-06-14 20:03   ` Casey Schaufler
  2017-06-14 20:42   ` David Howells
  2017-06-14 22:58   ` Updated docs David Howells
  3 siblings, 0 replies; 53+ messages in thread
From: Casey Schaufler @ 2017-06-14 20:03 UTC (permalink / raw)
  To: David Howells, mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, linux-security-module, linux-fsdevel

On 6/14/2017 8:16 AM, David Howells wrote:
> Introduce a filesystem context concept to be used during superblock
> creation for mount and superblock reconfiguration for remount.  This is
> allocated at the beginning of the mount procedure and into it is placed:
>
>  (1) Filesystem type.
>
>  (2) Namespaces.
>
>  (3) Device name.
>
>  (4) Superblock flags (MS_*).
>
>  (5) Security details.
>
>  (6) Filesystem-specific data, as set by the mount options.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>
>  Documentation/filesystems/mounting.txt |  436 ++++++++++++++++++++++++++++++++
>  include/linux/fs_context.h             |   72 +++++
>  2 files changed, 508 insertions(+)
>  create mode 100644 Documentation/filesystems/mounting.txt
>  create mode 100644 include/linux/fs_context.h
>
> diff --git a/Documentation/filesystems/mounting.txt b/Documentation/filesystems/mounting.txt
> new file mode 100644
> index 000000000000..315a5a4ff5cc
> --- /dev/null
> +++ b/Documentation/filesystems/mounting.txt
> @@ -0,0 +1,436 @@
> +			      ===================
> +			      FILESYSTEM MOUNTING
> +			      ===================
> +
> +CONTENTS
> +
> + (1) Overview.
> +
> + (2) The filesystem context.
> +
> + (3) The filesystem context operations.
> +
> + (4) Filesystem context security.
> +
> + (5) VFS filesystem context operations.
> +
> +
> +========
> +OVERVIEW
> +========
> +
> +The creation of new mounts is now to be done in a multistep process:
> +
> + (1) Create a filesystem context.
> +
> + (2) Parse the options and attach them to the context.  Options may be passed
> +     individually from userspace.
> +
> + (3) Validate and pre-process the context.
> +
> + (4) Get or create a superblock and mountable root.
> +
> + (5) Perform the mount.
> +
> + (6) Return an error message attached to the context.
> +
> + (7) Destroy the context.
> +
> +To support this, the file_system_type struct gains two new fields:
> +
> +	unsigned short fs_context_size;
> +
> +which indicates the total amount of space that should be allocated for context
> +data (see the Filesystem Context section), and:
> +
> +	int (*init_fs_context)(struct fs_context *fc, struct super_block *src_sb);
> +
> +which is invoked to set up the filesystem-specific parts of a filesystem
> +context, including the additional space.  The src_sb parameter is used to
> +convey the superblock from which the filesystem may draw extra information
> +(such as namespaces), for submount (FS_CONTEXT_FOR_SUBMOUNT) or remount
> +(FS_CONTEXT_FOR_REMOUNT) purposes or it will be NULL.
> +
> +Note that security initialisation is done *after* the filesystem is called so
> +that the namespaces may be adjusted first.
> +
> +And the super_operations struct gains one:
> +
> +	int (*remount_fs_fc) (struct super_block *, struct fs_context *);
> +
> +This shadows the ->remount_fs() operation and takes a prepared filesystem
> +context instead of the mount flags and data page.  It may modify the ms_flags
> +in the context for the caller to pick up.
> +
> +[NOTE] remount_fs_fc is intended as a replacement for remount_fs.
> +
> +
> +======================
> +THE FILESYSTEM CONTEXT
> +======================
> +
> +The creation and reconfiguration of a superblock is governed by a filesystem
> +context.  This is represented by the fs_context structure:
> +
> +	struct fs_context {
> +		const struct fs_context_operations *ops;
> +		struct file_system_type *fs;
> +		struct dentry		*root;
> +		struct user_namespace	*user_ns;
> +		struct net		*net_ns;
> +		const struct cred	*cred;
> +		char			*device;
> +		void			*security;
> +		unsigned int		sb_flags;
> +		bool			sloppy;
> +		bool			silent;
> +		bool			degraded;
> +		enum fs_context_purpose	purpose : 8;
> +	};

Could you namespace the fields of this structure?
e.g. fs_cred, fs_security
It makes it so much easier to determine which ->cred
you're looking at.

> +
> +When the VFS creates this, it allocates ->fs_context_size bytes (as specified
> +by the file_system_type object) to hold both the fs_context struct and any
> +extra data required by the filesystem.  The fs_context struct is placed at the
> +beginning of this space.  Any extra space beyond that is for use by the
> +filesystem.  The filesystem should wrap the struct in its own, e.g.:
> +
> +	struct nfs_fs_context {
> +		struct fs_context fc;
> +		...
> +	};
> +
> +placing the fs_context struct first.  container_of() can then be used.  The
> +file_system_type would be initialised thus:
> +
> +	struct file_system_type nfs = {
> +		...
> +		.fs_context_size	= sizeof(struct nfs_fs_context),
> +		.init_fs_context	= nfs_init_fs_context,
> +		...
> +	};
> +
> +The fs_context fields are as follows:
> +
> + (*) const struct fs_context_operations *ops
> +
> +     These are operations that can be done on a filesystem context (see
> +     below).  This must be set by the ->init_fs_context() file_system_type
> +     operation.
> +
> + (*) struct file_system_type *fs
> +
> +     A pointer to the file_system_type of the filesystem that is being
> +     constructed or reconfigured.  This retains a ref on the type owner.
> +
> + (*) struct dentry *root
> +
> +     A pointer to the root of the mountable tree (and indirectly, the
> +     superblock thereof).  This is filled in by the ->get_tree() op.
> +
> + (*) struct user_namespace *user_ns
> + (*) struct net *net_ns
> +
> +     This is a subset of the namespaces in use by the invoking process.  This
> +     retains a ref on each namespace.  The subscribed namespaces may be
> +     replaced by the filesystem to reflect other sources, such as the parent
> +     mount superblock on an automount.
> +
> + (*) struct cred *cred
> +
> +     The mounter's credentials.  This retains a ref on the credentials.
> +
> + (*) char *device
> +
> +     This is the device to be mounted.  It may be a block device
> +     (e.g. /dev/sda1) or something more exotic, such as the "host:/path" that
> +     NFS desires.
> +
> + (*) void *security
> +
> +     A place for the LSMs to hang their security data for the superblock.  The
> +     relevant security operations are described below.
> +
> + (*) unsigned int sb_flags
> +
> +     This holds the MS_* flags mount flags.
> +
> + (*) bool sloppy
> + (*) bool silent
> +
> +     These are set if the sloppy or silent mount options are given.
> +
> +     [NOTE] sloppy is probably unnecessary when userspace passes over one
> +     option at a time since the error can just be ignored if userspace deems it
> +     to be unimportant.
> +
> +     [NOTE] silent is probably redundant with ms_flags & MS_SILENT.
> +
> + (*) bool degraded
> +
> +     This is set if any preallocated resources in the context have been used
> +     up, thereby rendering it unreusable for the ->get_tree() op.
> +
> + (*) enum fs_context_purpose
> +
> +     This indicates the purpose for which the context is intended.  The
> +     available values are:
> +
> +	FS_CONTEXT_FOR_NEW	-- New mount
> +	FS_CONTEXT_FOR_SUBMOUNT	-- New automatic submount of extant mount
> +	FS_CONTEXT_FOR_REMOUNT	-- Change an existing mount
> +
> +The mount context is created by calling vfs_new_fs_context(), vfs_sb_reconfig()
> +or vfs_dup_fs_context() and is destroyed with put_fs_context().  Note that the
> +structure is not refcounted.
> +
> +VFS, security and filesystem mount options are set individually with
> +vfs_parse_mount_option().  Options provided by the old mount(2) system call as
> +a page of data can be parsed with generic_monolithic_mount_data().
> +
> +When mounting, the filesystem is allowed to take data from any of the pointers
> +and attach it to the superblock (or whatever), provided it clears the pointer
> +in the mount context.
> +
> +The filesystem is also allowed to allocate resources and pin them with the
> +mount context.  For instance, NFS might pin the appropriate protocol version
> +module.
> +
> +
> +=================================
> +THE FILESYSTEM CONTEXT OPERATIONS
> +=================================
> +
> +The filesystem context points to a table of operations:
> +
> +	struct fs_context_operations {
> +		void (*free)(struct fs_context *fc);
> +		int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
> +		int (*parse_option)(struct fs_context *fc, char *p);
> +		int (*monolithic_mount_data)(struct fs_context *fc, void *data);
> +		int (*validate)(struct fs_context *fc);
> +		int (*get_tree)(struct fs_context *fc);
> +	};
> +
> +These operations are invoked by the various stages of the mount procedure to
> +manage the filesystem context.  They are as follows:
> +
> + (*) void (*free)(struct fs_context *fc);
> +
> +     Called to clean up the filesystem-specific part of the filesystem context
> +     when the context is destroyed.  It should be aware that parts of the
> +     context may have been removed and NULL'd out by ->get_tree().
> +
> + (*) int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
> +
> +     Called when a filesystem context has been duplicated to get any refs or
> +     copy any non-referenced resources held in the filesystem-specific part of
> +     the filesystem context.  An error may be returned to indicate failure to
> +     do this.
> +
> +     [!] Note that even if this fails, put_fs_context() will be called
> +	 immediately thereafter, so ->dup() *must* make the
> +	 filesystem-specific part safe for ->free().
> +
> + (*) int (*parse_option)(struct fs_context *fc, char *p);
> +
> +     Called when an option is to be added to the filesystem context.  p points
> +     to the option string, likely in "key[=val]" format.  VFS-specific options
> +     will have been weeded out and fc->sb_flags updated in the context.
> +     Security options will also have been weeded out and fc->security updated.
> +
> +     If successful, 0 should be returned and a negative error code otherwise.
> +     If an ambiguous error (such as -EINVAL) is returned, sb_cfg_error() or
> +     sb_cfg_inval() should be used to provide a string that provides more
> +     information.
> +
> + (*) int (*monolithic_mount_data)(struct fs_context *fc, void *data);
> +
> +     Called when the mount(2) system call is invoked to pass the entire data
> +     page in one go.  If this is expected to be just a list of "key[=val]"
> +     items separated by commas, then this may be set to NULL.
> +
> +     The return value is as for ->parse_option().
> +
> +     If the filesystem (eg. NFS) needs to examine the data first and then finds
> +     it's the standard key-val list then it may pass it off to
> +     generic_monolithic_mount_data().
> +
> + (*) int (*validate)(struct fs_context *fc);
> +
> +     Called when all the options have been applied and the mount is about to
> +     take place.  It is should check for inconsistencies from mount options and
> +     it is also allowed to do preliminary resource acquisition.  For instance,
> +     the core NFS module could load the NFS protocol module here.
> +
> +     Note that if fc->mount_type == FS_CONTEXT_FOR_REMOUNT, some of the options
> +     necessary for a new mount may not be set.
> +
> +     The return value is as for ->parse_option().
> +
> + (*) int (*get_tree)(struct fs_context *fc);
> +
> +     Called to get or create the mountable root and superblock, using the
> +     information stored in the filesystem context (remounts go
> +     via a different vector).  It may detach any resources it desires from the
> +     filesystem context and transfer them to the superblock it
> +     creates.
> +
> +     On success it should set fc->root to the mountable root.
> +
> +     In the case of an error, it should return a negative error code and
> +     consider invoking sb_cfg_inval() or sb_cfg_error().
> +
> +
> +=========================================
> +FILESYSTEM CONTEXT SECURITY
> +========================================
> +
> +The filesystem context contains a security points that the LSMs
> +can use for building up a security context for the superblock to be mounted.
> +There are a number of operations used by the new mount code for this purpose:
> +
> + (*) int security_fs_context_alloc(struct fs_context *fc,
> +				  struct super_block *src_sb);
> +
> +     Called to initialise fc->security (which is preset to NULL) and allocate
> +     any resources needed.  It should return 0 on success and a negative error
> +     code on failure.
> +
> +     src_sb is non-NULL in the case of a remount (FS_CONTEXT_FOR_REMOUNT) in
> +     which case it indicates the superblock to be remounted or in the case of a
> +     submount (FS_CONTEXT_FOR_SUBMOUNT) in which case it indicates the parent
> +     superblock.
> +
> + (*) int security_fs_context_dup(struct fs_context *fc,
> +				struct fs_context *src_mc);
> +
> +     Called to initialise fc->security (which is preset to NULL) and allocate
> +     any resources needed.  The original filesystem context is
> +     pointed to by src_mc and may be used for reference.  It should return 0 on
> +     success and a negative error code on failure.
> +
> + (*) void security_fs_context_free(struct fs_context *fc);
> +
> +     Called to clean up anything attached to fc->security.  Note that the
> +     contents may have been transferred to a superblock and the pointer NULL'd
> +     out during mount.
> +
> + (*) int security_fs_context_parse_option(struct fs_context *fc, char *opt);
> +
> +     Called for each mount option.  The mount options are in "key[=val]" form.
> +     An active LSM may reject one with an error, pass one over and return 0 or
> +     consume one and return 1.  If consumed, the option isn't passed on to the
> +     filesystem.
> +
> +     If it returns an error, more information can be returned with
> +     sb_cfg_inval() or sb_cfg_error().
> +
> + (*) int security_sb_get_tree(struct fs_context *fc);
> +
> +     Called during the mount procedure to verify that the specified superblock
> +     is allowed to be mounted and to transfer the security data there.
> +
> +     On success, it should return 0; otherwise it should return an error and
> +     perhaps call invalf() or errorf() to indicate the problem.  It should not
> +     return -ENOMEM as this should be taken care of in advance.
> +
> +     [NOTE] Should I add a security_fs_context_validate() operation so that the
> +     LSM has the opportunity to allocate stuff and check the options as a
> +     whole?
> +
> +
> +=================================
> +VFS FILESYSTEM CONTEXT OPERATIONS
> +=================================
> +
> +There are four operations for creating a filesystem context and
> +one for destroying a context:
> +
> + (*) struct fs_context *__vfs_new_fs_context(struct file_system_type *fs_type,
> +					     struct super_block *src_sb;
> +					     unsigned int ms_flags);
> +
> +     Create a filesystem context given a filesystem type pointer.
> +     This allocates the filesystem context, sets the flags,
> +     initialises the security and calls fs_type->init_fs_context() to initialise
> +     the filesystem context.
> +
> +     src_sb can be NULL or it may indicate a superblock that is going to be
> +     remounted (FS_CONTEXT_FOR_REMOUNT) or a superblock that is the parent of a
> +     submount (FS_CONTEXT_FOR_SUBMOUNT).  This superblock is provided as a
> +     source of namespace information.
> +
> + (*) struct fs_context *vfs_sb_reconfig(struct vfsmount *mnt,
> +					unsigned int ms_flags);
> +
> +     Create a filesystem context from the same filesystem as an
> +     extant mount and initialise the mount parameters from the superblock
> +     underlying that mount.  This is for use by remount.
> +
> + (*) struct fs_context *vfs_new_fs_context(const char *fs_name);
> +
> +     Create a filesystem context given a filesystem name.  It is assumed that
> +     the mount flags will be passed in as text options or set directly later.
> +     This is intended to be called from sys_mount() or sys_fsopen().  This
> +     copies current's namespaces to the context.
> +
> + (*) struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc);
> +
> +     Duplicate a filesystem context, copying any options noted and duplicating
> +     or additionally referencing any resources held therein.  This is
> +     available for use where a filesystem has to get a mount within a mount,
> +     such as NFS4 does by internally mounting the root of the target server
> +     and then doing a private pathwalk to the target directory.
> +
> + (*) void put_fs_context(struct fs_context *fc);
> +
> +     Destroy a filesystem context, releasing any resources it holds.  This
> +     calls the ->free() operation.  This is intended to be called by anyone
> +     who created a filesystem context.
> +
> +     [!] filesystem contexts are not refcounted, so this causes unconditional
> +	 destruction.
> +
> +In all the above operations, apart from the put op, the return is a mount
> +context pointer or a negative error code.  No error string is saved as the
> +error string is only guaranteed as long as the file_system_type is pinned (and
> +thus the module).
> +
> +In the remaining operations, if an error occurs, a negative error code is
> +returned and, if not obvious, fc->error_msg may have been set to point to a
> +useful string.  This string should not be freed.
> +
> + (*) int vfs_get_tree(struct fs_context *fc);
> +
> +     Get or create the mountable root and superblock, using the parameters in
> +     the filesystem context to select/configure the superblock.  This invokes
> +     the ->validate() op and then the ->get_tree() op.
> +
> +     [NOTE] ->validate() can probably be rolled into ->get_tree() and
> +     ->remount_fs_fc().
> +
> + (*) struct vfsmount *vfs_kern_mount_fc(struct fs_context *fc);
> +
> +     Create a mount given the parameters in the specified filesystem context.
> +
> + (*) struct vfsmount *vfs_submount_fc(const struct dentry *mountpoint,
> +				      struct fs_context *fc);
> +
> +     Create a mount given a filesystem context and set MS_SUBMOUNT on it.  A
> +     wrapper around vfs_kern_mount_fc().  This is intended to be called from
> +     filesystems that have automount points (NFS, AFS, ...).
> +
> + (*) int vfs_parse_mount_option(struct fs_context *fc, char *data);
> +
> +     Supply a single mount option to the filesystem context.  The mount option
> +     should likely be in a "key[=val]" string form.  The option is first
> +     checked to see if it corresponds to a standard mount flag (in which case
> +     it is used to mark an MS_xxx flag and consumed) or a security option (in
> +     which case the LSM consumes it) before it is passed on to the filesystem.
> +
> + (*) int generic_monolithic_mount_data(struct fs_context *fc, void *data);
> +
> +     Parse a sys_mount() data page, assuming the form to be a text list
> +     consisting of key[=val] options separated by commas.  Each item in the
> +     list is passed to vfs_mount_option().  This is the default when the
> +     ->monolithic_mount_data() operation is NULL.
> diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h
> new file mode 100644
> index 000000000000..429c40be2c9e
> --- /dev/null
> +++ b/include/linux/fs_context.h
> @@ -0,0 +1,72 @@
> +/* Filesystem superblock creation and reconfiguration context.
> + *
> + * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
> + * Written by David Howells (dhowells@redhat.com)
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public Licence
> + * as published by the Free Software Foundation; either version
> + * 2 of the Licence, or (at your option) any later version.
> + */
> +
> +#ifndef _LINUX_FS_CONTEXT_H
> +#define _LINUX_FS_CONTEXT_H
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +
> +struct cred;
> +struct dentry;
> +struct file_operations;
> +struct file_system_type;
> +struct mnt_namespace;
> +struct net;
> +struct pid_namespace;
> +struct super_block;
> +struct user_namespace;
> +struct vfsmount;
> +
> +enum fs_context_purpose {
> +	FS_CONTEXT_FOR_NEW,	/* New superblock for direct mount */
> +	FS_CONTEXT_FOR_SUBMOUNT,	/* New superblock for automatic submount */
> +	FS_CONTEXT_FOR_REMOUNT,	/* Superblock reconfiguration for remount */
> +};
> +
> +/*
> + * Filesystem context as allocated and constructed by the ->init_fs_context()
> + * file_system_type operation.  The size of the object allocated is specified
> + * in struct file_system_type::fs_context_size and this must include sufficient
> + * space for the fs_context struct.
> + *
> + * Superblock creation fills in ->root whereas reconfiguration begins with this
> + * already set.
> + *
> + * See Documentation/filesystems/mounting.txt
> + */
> +struct fs_context {
> +	const struct fs_context_operations *ops;
> +	struct file_system_type	*fs_type;
> +	struct dentry		*root;		/* The root and superblock */
> +	struct user_namespace	*user_ns;	/* The user namespace for this mount */
> +	struct net		*net_ns;	/* The network namespace for this mount */
> +	const struct cred	*cred;		/* The mounter's credentials */
> +	char			*device;	/* The device name or mount target */
> +	char			*subtype;	/* The subtype to set on the superblock */
> +	void			*security;	/* The LSM context */
> +	unsigned int		sb_flags;	/* The superblock flags (MS_*) */
> +	bool			sloppy;		/* Unrecognised options are okay */
> +	bool			silent;
> +	bool			degraded;	/* True if the context can't be reused */
> +	enum fs_context_purpose	purpose : 8;
> +};
> +
> +struct fs_context_operations {
> +	void (*free)(struct fs_context *fc);
> +	int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
> +	int (*parse_option)(struct fs_context *fc, char *p);
> +	int (*monolithic_mount_data)(struct fs_context *fc, void *data);
> +	int (*validate)(struct fs_context *fc);
> +	int (*get_tree)(struct fs_context *fc);
> +};
> +
> +#endif /* _LINUX_FS_CONTEXT_H */
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-14 15:16 ` [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context " David Howells
  2017-06-14 18:02   ` Randy Dunlap
  2017-06-14 20:03   ` Casey Schaufler
@ 2017-06-14 20:42   ` David Howells
  2017-06-14 20:53     ` Casey Schaufler
  2017-06-14 22:58   ` Updated docs David Howells
  3 siblings, 1 reply; 53+ messages in thread
From: David Howells @ 2017-06-14 20:42 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: dhowells, mszeredi, viro, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

Casey Schaufler <casey@schaufler-ca.com> wrote:

> Could you namespace the fields of this structure?
> e.g. fs_cred, fs_security

Linus objects to that practice.

David

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-14 20:42   ` David Howells
@ 2017-06-14 20:53     ` Casey Schaufler
  2017-06-17  9:57       ` Theodore Ts'o
  2017-06-17 14:18       ` David Howells
  0 siblings, 2 replies; 53+ messages in thread
From: Casey Schaufler @ 2017-06-14 20:53 UTC (permalink / raw)
  To: David Howells
  Cc: mszeredi, viro, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

On 6/14/2017 1:42 PM, David Howells wrote:
> Casey Schaufler <casey@schaufler-ca.com> wrote:
>
>> Could you namespace the fields of this structure?
>> e.g. fs_cred, fs_security
> Linus objects to that practice.

Sigh. Never mind. Thank you.

>
> David
>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 27/27] ... and the intel_rdt driver
  2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
                   ` (26 preceding siblings ...)
  2017-06-14 15:19 ` [PATCH 27/27] kernfs, sysfs, cgroup: Support " David Howells
@ 2017-06-14 22:31 ` David Howells
  27 siblings, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-14 22:31 UTC (permalink / raw)
  To: mszeredi, viro
  Cc: dhowells, linux-nfs, jlayton, Greg Kroah-Hartman, linux-kernel,
	linux-fsdevel, linux-security-module, Li Zefan, Johannes Weiner,
	Tejun Heo, cgroups, fenghua.yu

This also needs the attached addition to fix the intel_rdt driver.

David
---
diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
index f5af0cc7eb0d..d026701894fd 100644
--- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
+++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
@@ -35,6 +35,11 @@
 #include <asm/intel_rdt.h>
 #include <asm/intel_rdt_common.h>
 
+struct rdt_fs_context {
+	struct kernfs_fs_context kfc;
+	bool	enable_cdp;
+};
+
 DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
 struct kernfs_root *rdt_root;
 struct rdtgroup rdtgroup_default;
@@ -743,22 +748,6 @@ static void cdp_disable(void)
 	}
 }
 
-static int parse_rdtgroupfs_options(char *data)
-{
-	char *token, *o = data;
-	int ret = 0;
-
-	while ((token = strsep(&o, ",")) != NULL) {
-		if (!*token)
-			return -EINVAL;
-
-		if (!strcmp(token, "cdp"))
-			ret = cdp_enable();
-	}
-
-	return ret;
-}
-
 /*
  * We don't allow rdtgroup directories to be created anywhere
  * except the root directory. Thus when looking for the rdtgroup
@@ -823,11 +812,9 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn)
 	}
 }
 
-static struct dentry *rdt_mount(struct file_system_type *fs_type,
-				int flags, const char *unused_dev_name,
-				void *data)
+static int rdt_get_tree(struct fs_context *fc)
 {
-	struct dentry *dentry;
+	struct rdt_fs_context *ctx = container_of(fc, struct rdt_fs_context, kfc.fc);
 	int ret;
 
 	mutex_lock(&rdtgroup_mutex);
@@ -835,27 +822,25 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
 	 * resctrl file system can only be mounted once.
 	 */
 	if (static_branch_unlikely(&rdt_enable_key)) {
-		dentry = ERR_PTR(-EBUSY);
+		errorf("intel_rdt: Can only mount once");
+		ret = -EBUSY;
 		goto out;
 	}
 
-	ret = parse_rdtgroupfs_options(data);
-	if (ret) {
-		dentry = ERR_PTR(ret);
-		goto out_cdp;
+	if (ctx->enable_cdp) {
+		ret = cdp_enable();
+		if (ret < 0)
+			goto out_cdp;
 	}
 
 	closid_init();
 
 	ret = rdtgroup_create_info_dir(rdtgroup_default.kn);
-	if (ret) {
-		dentry = ERR_PTR(ret);
+	if (ret < 0)
 		goto out_cdp;
-	}
 
-	dentry = kernfs_mount(fs_type, flags, rdt_root,
-			      RDTGROUP_SUPER_MAGIC, NULL);
-	if (IS_ERR(dentry))
+	ret = kernfs_get_tree(&ctx->kfc);
+	if (ret < 0)
 		goto out_cdp;
 
 	static_branch_enable(&rdt_enable_key);
@@ -865,8 +850,42 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
 	cdp_disable();
 out:
 	mutex_unlock(&rdtgroup_mutex);
+	return ret;
+}
+
+static int rdt_parse_option(struct fs_context *fc, char *p)
+{
+	struct rdt_fs_context *ctx = container_of(fc, struct rdt_fs_context, kfc.fc);
 
-	return dentry;
+	if (strcmp(p, "cdp") == 0) {
+		ctx->enable_cdp = true;
+		return 0;
+	}
+
+	return invalf("intel_rdt: Unknown option");
+}
+
+static void rdt_fs_context_free(struct fs_context *fc)
+{
+	struct rdt_fs_context *ctx = container_of(fc, struct rdt_fs_context, kfc.fc);
+
+	kernfs_free_fs_context(&ctx->kfc);
+}
+
+static const struct fs_context_operations rdt_fs_context_ops = {
+	.free		= rdt_fs_context_free,
+	.parse_option	= rdt_parse_option,
+	.get_tree	= rdt_get_tree,
+};
+
+static int rdt_init_fs_context(struct fs_context *fc, struct super_block *src_sb)
+{
+	struct rdt_fs_context *ctx = container_of(fc, struct rdt_fs_context, kfc.fc);
+
+	ctx->kfc.root = rdt_root;
+	ctx->kfc.magic = RDTGROUP_SUPER_MAGIC;
+	ctx->kfc.fc.ops = &rdt_fs_context_ops;
+	return 0;
 }
 
 static int reset_all_ctrls(struct rdt_resource *r)
@@ -994,9 +1013,10 @@ static void rdt_kill_sb(struct super_block *sb)
 }
 
 static struct file_system_type rdt_fs_type = {
-	.name    = "resctrl",
-	.mount   = rdt_mount,
-	.kill_sb = rdt_kill_sb,
+	.name			= "resctrl",
+	.fs_context_size	= sizeof(struct rdt_fs_context),
+	.init_fs_context	= rdt_init_fs_context,
+	.kill_sb		= rdt_kill_sb,
 };
 
 static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Updated docs
  2017-06-14 15:16 ` [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context " David Howells
                     ` (2 preceding siblings ...)
  2017-06-14 20:42   ` David Howells
@ 2017-06-14 22:58   ` David Howells
  2017-06-15  1:53     ` Randy Dunlap
  3 siblings, 1 reply; 53+ messages in thread
From: David Howells @ 2017-06-14 22:58 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: dhowells, mszeredi, viro, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

Randy Dunlap <rdunlap@infradead.org> wrote:

> > +which is invoked to set up the filesystem-specific parts of a filesystem
> > +context, including the additional space.  The src_sb parameter is used to
> > +convey the superblock from which the filesystem may draw extra information
> > +(such as namespaces), for submount (FS_CONTEXT_FOR_SUBMOUNT) or remount
> 
>                        ;

Actually, this should rather be something like:

    which is invoked to set up the filesystem-specific parts of a filesystem
    context, including the additional space.  The src_sb parameter is used to
    convey the superblock from which the filesystem may draw extra information
    (such as namespaces) for submount (FS_CONTEXT_FOR_SUBMOUNT) or remount
    (FS_CONTEXT_FOR_REMOUNT) purposes - otherwise it will be NULL.

I forgot to thoroughly update the docs, so here they are.

David
---
			      ===================
			      FILESYSTEM MOUNTING
			      ===================

CONTENTS

 (1) Overview.

 (2) The filesystem context.

 (3) The filesystem context operations.

 (4) Filesystem context security.

 (5) VFS filesystem context operations.


========
OVERVIEW
========

The creation of new mounts is now to be done in a multistep process:

 (1) Create a filesystem context.

 (2) Parse the options and attach them to the context.  Options may be passed
     individually from userspace.

 (3) Validate and pre-process the context.

 (4) Get or create a superblock and mountable root.

 (5) Perform the mount.

 (6) Return an error message attached to the context.

 (7) Destroy the context.

To support this, the file_system_type struct gains two new fields:

	unsigned short fs_context_size;

which indicates the total amount of space that should be allocated for context
data (see the Filesystem Context section), and:

	int (*init_fs_context)(struct fs_context *fc, struct super_block *src_sb);

which is invoked to set up the filesystem-specific parts of a filesystem
context, including the additional space.  The src_sb parameter is used to
convey the superblock from which the filesystem may draw extra information
(such as namespaces) for submount (FS_CONTEXT_FOR_SUBMOUNT) or remount
(FS_CONTEXT_FOR_REMOUNT) purposes - otherwise it will be NULL.

Note that security initialisation is done *after* the filesystem is called so
that the namespaces may be adjusted first.

And the super_operations struct gains one field:

	int (*remount_fs_fc) (struct super_block *, struct fs_context *);

This shadows the ->remount_fs() operation and takes a prepared filesystem
context instead of the mount flags and data page.  It may modify the sb_flags
in the context for the caller to pick up.

[NOTE] remount_fs_fc is intended as a replacement for remount_fs.


======================
THE FILESYSTEM CONTEXT
======================

The creation and reconfiguration of a superblock is governed by a filesystem
context.  This is represented by the fs_context structure:

	struct fs_context {
		const struct fs_context_operations *ops;
		struct file_system_type *fs;
		struct dentry		*root;
		struct user_namespace	*user_ns;
		struct net		*net_ns;
		const struct cred	*cred;
		char			*device;
		char			*subtype;
		void			*security;
		unsigned int		sb_flags;
		bool			sloppy;
		bool			silent;
		bool			degraded;
		enum fs_context_purpose	purpose : 8;
	};

When the VFS creates this, it allocates ->fs_context_size bytes (as specified
by the file_system_type object) to hold both the fs_context struct and any
extra data required by the filesystem.  The fs_context struct is placed at the
beginning of this space.  Any extra space beyond that is for use by the
filesystem.  The filesystem should wrap the struct in its own, e.g.:

	struct nfs_fs_context {
		struct fs_context fc;
		...
	};

placing the fs_context struct first.  container_of() can then be used.  The
file_system_type would be initialised thus:

	struct file_system_type nfs = {
		...
		.fs_context_size	= sizeof(struct nfs_fs_context),
		.init_fs_context	= nfs_init_fs_context,
		...
	};

The fs_context fields are as follows:

 (*) const struct fs_context_operations *ops

     These are operations that can be done on a filesystem context (see
     below).  This must be set by the ->init_fs_context() file_system_type
     operation.

 (*) struct file_system_type *fs

     A pointer to the file_system_type of the filesystem that is being
     constructed or reconfigured.  This retains a reference on the type owner.

 (*) struct dentry *root

     A pointer to the root of the mountable tree (and indirectly, the
     superblock thereof).  This is filled in by the ->get_tree() op.

 (*) struct user_namespace *user_ns
 (*) struct net *net_ns

     There are a subset of the namespaces in use by the invoking process.  They
     retain references on each namespace.  The subscribed namespaces may be
     replaced by the filesystem to reflect other sources, such as the parent
     mount superblock on an automount.

 (*) struct cred *cred

     The mounter's credentials.  This retains a reference on the credentials.

 (*) char *device

     This is the device to be mounted.  It may be a block device
     (e.g. /dev/sda1) or something more exotic, such as the "host:/path" that
     NFS desires.

 (*) char *subtype

     This is a string to be added to the type displayed in /proc/mounts to
     qualify it (used by FUSE).  This is available for the filesystem to set if
     desired.

 (*) void *security

     A place for the LSMs to hang their security data for the superblock.  The
     relevant security operations are described below.

 (*) unsigned int sb_flags

     This holds the SB_* flags to be set in super_block::s_flags.

 (*) bool sloppy
 (*) bool silent

     These are set if the sloppy or silent mount options are given.

     [NOTE] sloppy is probably unnecessary when userspace passes over one
     option at a time since the error can just be ignored if userspace deems it
     to be unimportant.

     [NOTE] silent is probably redundant with sb_flags & SB_SILENT.

 (*) bool degraded

     This is set if any preallocated resources in the context have been used
     up, thereby rendering it unreusable for the ->get_tree() op.

 (*) enum fs_context_purpose

     This indicates the purpose for which the context is intended.  The
     available values are:

	FS_CONTEXT_FOR_NEW	-- New mount
	FS_CONTEXT_FOR_SUBMOUNT	-- New automatic submount of extant mount
	FS_CONTEXT_FOR_REMOUNT	-- Change an existing mount

The mount context is created by calling vfs_new_fs_context(), vfs_sb_reconfig()
or vfs_dup_fs_context() and is destroyed with put_fs_context().  Note that the
structure is not refcounted.

VFS, security and filesystem mount options are set individually with
vfs_parse_mount_option().  Options provided by the old mount(2) system call as
a page of data can be parsed with generic_monolithic_mount_data().

When mounting, the filesystem is allowed to take data from any of the pointers
and attach it to the superblock (or whatever), provided it clears the pointer
in the mount context.

The filesystem is also allowed to allocate resources and pin them with the
mount context.  For instance, NFS might pin the appropriate protocol version
module.


=================================
THE FILESYSTEM CONTEXT OPERATIONS
=================================

The filesystem context points to a table of operations:

	struct fs_context_operations {
		void (*free)(struct fs_context *fc);
		int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
		int (*parse_option)(struct fs_context *fc, char *p);
		int (*monolithic_mount_data)(struct fs_context *fc, void *data);
		int (*validate)(struct fs_context *fc);
		int (*get_tree)(struct fs_context *fc);
	};

These operations are invoked by the various stages of the mount procedure to
manage the filesystem context.  They are as follows:

 (*) void (*free)(struct fs_context *fc);

     Called to clean up the filesystem-specific part of the filesystem context
     when the context is destroyed.  It should be aware that parts of the
     context may have been removed and NULL'd out by ->get_tree().

 (*) int (*dup)(struct fs_context *fc, struct fs_context *src_fc);

     Called when a filesystem context has been duplicated to get any refs or
     copy any non-referenced resources held in the filesystem-specific part of
     the filesystem context.  An error may be returned to indicate failure to
     do this.

     [!] Note that even if this fails, put_fs_context() will be called
	 immediately thereafter, so ->dup() *must* make the
	 filesystem-specific part safe for ->free().

 (*) int (*parse_option)(struct fs_context *fc, char *p);

     Called when an option is to be added to the filesystem context.  p points
     to the option string, likely in "key[=val]" format.  VFS-specific options
     will have been weeded out and fc->sb_flags updated in the context.
     Security options will also have been weeded out and fc->security updated.

     If successful, 0 should be returned and a negative error code otherwise.
     If an ambiguous error (such as -EINVAL) is returned, sb_cfg_error() or
     sb_cfg_inval() should be used to provide a string that provides more
     information.

 (*) int (*monolithic_mount_data)(struct fs_context *fc, void *data);

     Called when the mount(2) system call is invoked to pass the entire data
     page in one go.  If this is expected to be just a list of "key[=val]"
     items separated by commas, then this may be set to NULL.

     The return value is as for ->parse_option().

     If the filesystem (eg. NFS) needs to examine the data first and then finds
     it's the standard key-val list then it may pass it off to
     generic_monolithic_mount_data().

 (*) int (*validate)(struct fs_context *fc);

     Called when all the options have been applied and the mount is about to
     take place.  It is should check for inconsistencies from mount options and
     it is also allowed to do preliminary resource acquisition.  For instance,
     the core NFS module could load the NFS protocol module here.

     Note that if fc->purpose == FS_CONTEXT_FOR_REMOUNT, some of the options
     necessary for a new mount may not be set.

     The return value is as for ->parse_option().

 (*) int (*get_tree)(struct fs_context *fc);

     Called to get or create the mountable root and superblock, using the
     information stored in the filesystem context (remounts go
     via a different vector).  It may detach any resources it desires from the
     filesystem context and transfer them to the superblock it
     creates.

     On success it should set fc->root to the mountable root.

     In the case of an error, it should return a negative error code and
     consider invoking sb_cfg_inval() or sb_cfg_error().


===========================
FILESYSTEM CONTEXT SECURITY
===========================

The filesystem context contains a security pointer that the LSMs can use for
building up a security context for the superblock to be mounted.  There are a
number of operations used by the new mount code for this purpose:

 (*) int security_fs_context_alloc(struct fs_context *fc,
				   struct super_block *src_sb);

     Called to initialise fc->security (which is preset to NULL) and allocate
     any resources needed.  It should return 0 on success and a negative error
     code on failure.

     src_sb is non-NULL in the case of a remount (FS_CONTEXT_FOR_REMOUNT) in
     which case it indicates the superblock to be remounted or in the case of a
     submount (FS_CONTEXT_FOR_SUBMOUNT) in which case it indicates the parent
     superblock.

 (*) int security_fs_context_dup(struct fs_context *fc,
				 struct fs_context *src_fc);

     Called to initialise fc->security (which is preset to NULL) and allocate
     any resources needed.  The original filesystem context is pointed to by
     src_fc and may be used for reference.  It should return 0 on success and a
     negative error code on failure.

 (*) void security_fs_context_free(struct fs_context *fc);

     Called to clean up anything attached to fc->security.  Note that the
     contents may have been transferred to a superblock and the pointer NULL'd
     out during mount.

 (*) int security_fs_context_parse_option(struct fs_context *fc, char *opt);

     Called for each mount option.  The mount options are in "key[=val]" form.
     An active LSM may reject one with an error, pass one over and return 0 or
     consume one and return 1.  If consumed, the option isn't passed on to the
     filesystem.

     If it returns an error, more information can be returned with
     invalf() or errorf().

 (*) int security_sb_get_tree(struct fs_context *fc);

     Called during the mount procedure to verify that the specified superblock
     is allowed to be mounted and to transfer the security data there.

     On success, it should return 0; otherwise it should return an error and
     perhaps call invalf() or errorf() to indicate the problem.  It should not
     return -ENOMEM as this should be taken care of in advance.

     [NOTE] Should I add a security_fs_context_validate() operation so that the
     LSM has the opportunity to allocate stuff and check the options as a
     whole?

 (*) int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint)

     Called during the mount procedure to verify that the root dentry attached
     to the context is permitted to be attached to the specified mountpoint.
     It should return 0 on success and a negative error code on failure.


=================================
VFS FILESYSTEM CONTEXT OPERATIONS
=================================

There are four operations for creating a filesystem context and
one for destroying a context:

 (*) struct fs_context *vfs_new_fs_context(struct file_system_type *fs_type,
					   struct super_block *src_sb;
					   unsigned int sb_flags);

     Create a filesystem context for a given filesystem type.  This allocates
     the filesystem context, sets the flags, initialises the security and calls
     fs_type->init_fs_context() to initialise the filesystem context.

     src_sb can be NULL or it may indicate a superblock that is going to be
     remounted (FS_CONTEXT_FOR_REMOUNT) or a superblock that is the parent of a
     submount (FS_CONTEXT_FOR_SUBMOUNT).  This superblock is provided as a
     source of namespace information.

 (*) struct fs_context *vfs_sb_reconfig(struct vfsmount *mnt,
					unsigned int sb_flags);

     Create a filesystem context from the same filesystem as an extant mount
     and initialise the mount parameters from the superblock underlying that
     mount.  This is for use by remount.

 (*) struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc);

     Duplicate a filesystem context, copying any options noted and duplicating
     or additionally referencing any resources held therein.  This is available
     for use where a filesystem has to get a mount within a mount, such as NFS4
     does by internally mounting the root of the target server and then doing a
     private pathwalk to the target directory.

 (*) void put_fs_context(struct fs_context *fc);

     Destroy a filesystem context, releasing any resources it holds.  This
     calls the ->free() operation.  This is intended to be called by anyone who
     created a filesystem context.

     [!] filesystem contexts are not refcounted, so this causes unconditional
	 destruction.

In all the above operations, apart from the put op, the return is a mount
context pointer or a negative error code.

In the remaining operations, if an error occurs, a negative error code is
returned and, if not obvious, invalf() or errorf() may have been invoked to set
a supplementary error message.

 (*) int vfs_get_tree(struct fs_context *fc);

     Get or create the mountable root and superblock, using the parameters in
     the filesystem context to select/configure the superblock.  This invokes
     the ->validate() op and then the ->get_tree() op.

     [NOTE] ->validate() could perhaps be rolled into ->get_tree() and
     ->remount_fs_fc().

 (*) struct vfsmount *vfs_kern_mount_fc(struct fs_context *fc);

     Create a mount given the parameters in the specified filesystem context.

 (*) int vfs_parse_mount_option(struct fs_context *fc, char *data);

     Supply a single mount option to the filesystem context.  The mount option
     should likely be in a "key[=val]" string form.  The option is first
     checked to see if it corresponds to a standard mount flag (in which case
     it is used to set an MS_xxx flag and consumed) or a security option (in
     which case the LSM consumes it) before it is passed on to the filesystem.

 (*) int generic_monolithic_mount_data(struct fs_context *fc, void *data);

     Parse a sys_mount() data page, assuming the form to be a text list
     consisting of key[=val] options separated by commas.  Each item in the
     list is passed to vfs_mount_option().  This is the default when the
     ->monolithic_mount_data() operation is NULL.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: Updated docs
  2017-06-14 22:58   ` Updated docs David Howells
@ 2017-06-15  1:53     ` Randy Dunlap
  0 siblings, 0 replies; 53+ messages in thread
From: Randy Dunlap @ 2017-06-15  1:53 UTC (permalink / raw)
  To: David Howells
  Cc: mszeredi, viro, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

Thanks for the update.  I have 2 more things for you to consider.

a.  In multiple places, there is something like "return 0 when no error
and return a negative error code otherwise."

I would say "or return a negative error code otherwise."

b. (below)

> ===========================
> FILESYSTEM CONTEXT SECURITY
> ===========================
> 
> The filesystem context contains a security pointer that the LSMs can use for
> building up a security context for the superblock to be mounted.  There are a
> number of operations used by the new mount code for this purpose:
> 
>  (*) int security_fs_context_alloc(struct fs_context *fc,
> 				   struct super_block *src_sb);
> 
>      Called to initialise fc->security (which is preset to NULL) and allocate
>      any resources needed.  It should return 0 on success and a negative error
>      code on failure.
> 
>      src_sb is non-NULL in the case of a remount (FS_CONTEXT_FOR_REMOUNT) in
>      which case it indicates the superblock to be remounted or in the case of a
>      submount (FS_CONTEXT_FOR_SUBMOUNT) in which case it indicates the parent
>      superblock.
> 

-ETOOMANYCASES

Maybe:
	For a remount (FS_CONTEXT_FOR_REMOUNT), src_sb is non-NULL and indicates
	the superblock to be remounted.  For a submount (FS_CONTEXT_FOR_SUBMOUNT),
	src_sb is also non-NULL and represents the parent superblock.


cheers.

-- 
~Randy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 03/27] VFS: Make get_mnt_ns() return the namespace [ver #5]
  2017-06-14 15:15 ` [PATCH 03/27] VFS: Make get_mnt_ns() return the namespace " David Howells
@ 2017-06-15  9:09   ` Al Viro
  0 siblings, 0 replies; 53+ messages in thread
From: Al Viro @ 2017-06-15  9:09 UTC (permalink / raw)
  To: David Howells
  Cc: mszeredi, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

On Wed, Jun 14, 2017 at 04:15:42PM +0100, David Howells wrote:
> Make get_mnt_ns() return the namespace it got a ref on for consistency with
> other namespace ref getting functions.

Is there any point in doing that?  I mean, it's not used in your patchset anymore
and existing callers are a mixed bag...

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags [ver #5]
  2017-06-14 15:16 ` [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags " David Howells
@ 2017-06-15  9:39   ` Al Viro
  2017-06-16  9:06     ` Christoph Hellwig
  2017-06-16 14:53     ` David Howells
  0 siblings, 2 replies; 53+ messages in thread
From: Al Viro @ 2017-06-15  9:39 UTC (permalink / raw)
  To: David Howells
  Cc: mszeredi, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

On Wed, Jun 14, 2017 at 04:16:22PM +0100, David Howells wrote:

> diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
> index d2fb9c8ed205..e831c115daf9 100644
> --- a/drivers/base/devtmpfs.c
> +++ b/drivers/base/devtmpfs.c
> @@ -355,7 +355,7 @@ int devtmpfs_mount(const char *mntdir)
>  	if (!thread)
>  		return 0;
>  
> -	err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL);
> +	err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", SB_SILENT, NULL);
>  	if (err)
>  		printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
>  	else
> @@ -381,7 +381,7 @@ static int devtmpfsd(void *p)
>  	*err = sys_unshare(CLONE_NEWNS);
>  	if (*err)
>  		goto out;
> -	*err = sys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options);
> +	*err = sys_mount("devtmpfs", "/", "devtmpfs", SB_SILENT, options);

Er...  These really should be MS_SILENT.

> @@ -311,14 +311,14 @@ static void get_dpms_capabilities(unsigned char flags,
>  				  struct fb_monspecs *specs)
>  {
>  	specs->dpms = 0;
> -	if (flags & DPMS_ACTIVE_OFF)
> -		specs->dpms |= FB_DPMS_ACTIVE_OFF;
> +	if (flags & DPSB_ACTIVE_OFF)
> +		specs->dpms |= FB_DPSB_ACTIVE_OFF;

... the hell?

> -	if (sb->s_flags & MS_RDONLY)
> +	if (sb->s_flags & SB_RDONLY)

TBH, it looks like something along the lines of sb_rdonly(sb) for the above would
make more sense.

>  static int flags_to_propagation_type(int flags)
>  {
> -	int type = flags & ~(MS_REC | MS_SILENT);
> +	int type = flags & ~(MS_REC | SB_SILENT);

Huh?

> -	flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
> -		   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
> -		   MS_STRICTATIME | MS_NOREMOTELOCK | MS_SUBMOUNT);
> +	flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | SB_ACTIVE | SB_BORN |
> +		   MS_NOATIME | MS_NODIRATIME | MS_RELATIME| SB_KERNMOUNT |
> +		   MS_STRICTATIME | SB_NOREMOTELOCK | SB_SUBMOUNT);

This is complete bullshit.  _IF_ you want to separate these sets, do that
consistently.  Mixing MS_... with SB_... in a mask is obviously wrong.
Sure, you can use the fact that such-and-such SB_ flag is the same value
as MS_... one; worth a BUILD_BUG_ON() somewhere to enforce that.  However,
please separate the places where you have mount(2) flags argument from
those where you have a set of SB_... bits.

In this case you certainly have MS_... bunch.  What's more, I would rather
do it as "we look only at..." instead of "we ignore the following..." - and
probably do it in do_...() functions instead.  Note that they already
have parsing and validation of their own...

> diff --git a/tools/testing/selftests/mount/unprivileged-remount-test.c b/tools/testing/selftests/mount/unprivileged-remount-test.c
> index 517785052f1c..65489157f8d7 100644
> --- a/tools/testing/selftests/mount/unprivileged-remount-test.c
> +++ b/tools/testing/selftests/mount/unprivileged-remount-test.c
> @@ -129,7 +129,7 @@ static int read_mnt_flags(const char *path)
>  	}
>  	mnt_flags = 0;
>  	if (stat.f_flag & ST_RDONLY)
> -		mnt_flags |= MS_RDONLY;
> +		mnt_flags |= SB_RDONLY;
>  	if (stat.f_flag & ST_NOSUID)
>  		mnt_flags |= MS_NOSUID;
>  	if (stat.f_flag & ST_NODEV)
> @@ -143,7 +143,7 @@ static int read_mnt_flags(const char *path)
>  	if (stat.f_flag & ST_RELATIME)
>  		mnt_flags |= MS_RELATIME;
>  	if (stat.f_flag & ST_SYNCHRONOUS)
> -		mnt_flags |= MS_SYNCHRONOUS;
> +		mnt_flags |= SB_SYNCHRONOUS;
>  	if (stat.f_flag & ST_MANDLOCK)
>  		mnt_flags |= ST_MANDLOCK;

Really?  That's userland code, isn't it?

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 25/27] ipc: Convert mqueue fs to fs_context [ver #5]
  2017-06-14 15:19 ` [PATCH 25/27] ipc: Convert mqueue fs to fs_context " David Howells
@ 2017-06-15 10:07   ` Al Viro
  2017-06-15 14:47   ` David Howells
  1 sibling, 0 replies; 53+ messages in thread
From: Al Viro @ 2017-06-15 10:07 UTC (permalink / raw)
  To: David Howells
  Cc: mszeredi, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

On Wed, Jun 14, 2017 at 04:19:03PM +0100, David Howells wrote:
> Convert the mqueue filesystem to use the filesystem context stuff.
> 
> Notes:
> 
>  (1) The relevant ipc namespace is selected in when the context is
>      initialised (and it defaults to the current task's ipc namespace).
>      The caller can override this before calling vfs_get_tree().
> 
>  (2) Rather than simply calling kern_mount_data(), mq_init_ns() creates a
>      context, adjusts it and then does the rest of the mount procedure.

> +	fc = vfs_new_fs_context(&mqueue_fs_type, NULL, 0, FS_CONTEXT_FOR_NEW);
> +	if (IS_ERR(fc))
> +		return PTR_ERR(fc);
> +
> +	ctx = container_of(fc, struct mqueue_fs_context, fc);

Ugh...

> +	if (ctx->ipc_ns != ns) {

How could they possibly be equal?  You are setting that ns up here, right?  How
could it be in any process' nsproxy?

> +		put_ipc_ns(ctx->ipc_ns);
> +		ctx->ipc_ns = get_ipc_ns(ns);

> +	mnt = kern_mount_data_fc(fc);
> +	if (IS_ERR(mnt)) {
> +		ret = PTR_ERR(mnt);
> +		goto out_fc;
> +	}
> +
> +	ns->mq_mnt = mnt;
> +	ret = 0;
> +out_fc:
> +	put_fs_context(fc);

Am I right assuming that it's an attempt to cope with "one process starts
setting the things up, passes descriptor to another and buggers off; the
recepient mounts the damn thing and needs something to hold your reference"?

Ugh, again...  Is there any reason for dynamic allocation of that thing in
this particular case?  AFAICS, these contortions are all due to going through
vfs_new_fs_context()/put_fs_context().  And it's not as if they had been
refcounted...

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 16/27] proc: Add fs_context support to procfs [ver #5]
  2017-06-14 15:17 ` [PATCH 16/27] proc: Add fs_context support to procfs " David Howells
@ 2017-06-15 10:14   ` Al Viro
  0 siblings, 0 replies; 53+ messages in thread
From: Al Viro @ 2017-06-15 10:14 UTC (permalink / raw)
  To: David Howells
  Cc: mszeredi, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

On Wed, Jun 14, 2017 at 04:17:43PM +0100, David Howells wrote:

>  int pid_ns_prepare_proc(struct pid_namespace *ns)
>  {
> +	struct proc_fs_context *ctx;
> +	struct fs_context *fc;
>  	struct vfsmount *mnt;
> +	int ret;
> +
> +	fc = vfs_new_fs_context(&proc_fs_type, NULL, 0, FS_CONTEXT_FOR_NEW);
> +	if (IS_ERR(fc))
> +		return PTR_ERR(fc);
> +
> +	ctx = container_of(fc, struct proc_fs_context, fc);
> +	if (ctx->pid_ns != ns) {
> +		put_pid_ns(ctx->pid_ns);
> +		get_pid_ns(ns);
> +		ctx->pid_ns = ns;
> +	}
> +
> +	ret = vfs_get_tree(fc);
> +	if (ret < 0) {
> +		put_fs_context(fc);
> +		return ret;
> +	}
>  
> -	mnt = kern_mount_data(&proc_fs_type, ns);
> +	mnt = kern_mount_data_fc(fc);
> +	put_fs_context(fc);

Same as with ipc; do you need to go through dynamic allocation,
container_of, patching it up, etc.?

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 25/27] ipc: Convert mqueue fs to fs_context [ver #5]
  2017-06-14 15:19 ` [PATCH 25/27] ipc: Convert mqueue fs to fs_context " David Howells
  2017-06-15 10:07   ` Al Viro
@ 2017-06-15 14:47   ` David Howells
  1 sibling, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-15 14:47 UTC (permalink / raw)
  To: Al Viro
  Cc: dhowells, mszeredi, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

Al Viro <viro@ZenIV.linux.org.uk> wrote:

> > +	if (ctx->ipc_ns != ns) {
> 
> How could they possibly be equal?  You are setting that ns up here, right?
> How could it be in any process' nsproxy?

Fair point.

> Ugh, again...  Is there any reason for dynamic allocation of that thing in
> this particular case?  AFAICS, these contortions are all due to going through
> vfs_new_fs_context()/put_fs_context().  And it's not as if they had been
> refcounted...

I can statically initialise it as below, but whilst I don't need to call
vfs_new_fs_context() and put_fs_context(), I do have to call the security
hooks (Smack makes no distinction for internal filesystems) to set up the
security context and clean it up, and I do have to have the error handling for
in case kern_mount_data_fc() fails.

So it actually makes both the source and the object file bigger.  Now, I could
hide some of this inside a pair of inline functions, but it doesn't help that
much.

What might be better is to provide a function that wraps the vfs_get_tree()
and kern_mount_data_fc() calls and the cleanup.

David
---
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index f2e1d1d69961..a18a5f6763f9 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1431,8 +1431,15 @@ static struct file_system_type mqueue_fs_type = {
 
 int mq_init_ns(struct ipc_namespace *ns)
 {
-	struct mqueue_fs_context *ctx;
-	struct fs_context *fc;
+	struct mqueue_fs_context ctx = {
+		.fc.ops		= &mqueue_fs_context_ops,
+		.fc.fs_type	= &mqueue_fs_type,
+		.fc.cred	= current_cred(),
+		.fc.user_ns	= current_user_ns(),
+		.fc.purpose	= FS_CONTEXT_FOR_NEW,
+		.ipc_ns		= ns,
+	};
+	struct super_block *sb;
 	struct vfsmount *mnt;
 	int ret;
 
@@ -1443,29 +1450,32 @@ int mq_init_ns(struct ipc_namespace *ns)
 	ns->mq_msg_default   = DFLT_MSG;
 	ns->mq_msgsize_default  = DFLT_MSGSIZE;
 
-	fc = vfs_new_fs_context(&mqueue_fs_type, NULL, 0, FS_CONTEXT_FOR_NEW);
-	if (IS_ERR(fc))
-		return PTR_ERR(fc);
-
-	ctx = container_of(fc, struct mqueue_fs_context, fc);
-	put_ipc_ns(ctx->ipc_ns);
-	ctx->ipc_ns = get_ipc_ns(ns);
+	ret = security_fs_context_alloc(&ctx.fc, NULL);
+	if (ret < 0)
+		return ret;
 
-	ret = vfs_get_tree(fc);
+	ret = vfs_get_tree(&ctx.fc);
 	if (ret < 0)
 		goto out_fc;
 
-	mnt = kern_mount_data_fc(fc);
+	mnt = kern_mount_data_fc(&ctx.fc);
 	if (IS_ERR(mnt)) {
 		ret = PTR_ERR(mnt);
-		goto out_fc;
+		goto out_root;
 	}
 
 	ns->mq_mnt = mnt;
 	ret = 0;
 out_fc:
-	put_fs_context(fc);
+	security_fs_context_free(&ctx.fc);
 	return ret;
+
+out_root:
+	sb = ctx.fc.root->d_sb;
+	dput(ctx.fc.root);
+	ctx.fc.root = NULL;
+	deactivate_super(sb);
+	goto out_fc;
 }
 
 void mq_clear_sbinfo(struct ipc_namespace *ns)

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH 24/27] NFS: Add fs_context support. [ver #5]
  2017-06-14 15:18 ` [PATCH 24/27] NFS: Add fs_context support. " David Howells
@ 2017-06-15 15:28   ` Anna Schumaker
  0 siblings, 0 replies; 53+ messages in thread
From: Anna Schumaker @ 2017-06-15 15:28 UTC (permalink / raw)
  To: David Howells, mszeredi, viro
  Cc: linux-nfs, jlayton, linux-kernel, linux-security-module, linux-fsdevel

Hi David,

Several comments below:

On 06/14/2017 11:18 AM, David Howells wrote:
> Add filesystem context support to NFS, parsing the options in advance and
> attaching the information to struct nfs_fs_context.  The highlights are:
> 
>  (*) Merge nfs_mount_info and nfs_clone_mount into nfs_fs_context.  This
>      structure represents NFS's superblock config.
> 
>  (*) Make use of the VFS's parsing support to split comma-separated lists.
> 
>  (*) Pin the NFS protocol module in the nfs_fs_context.
> 
>  (*) Attach supplementary error information to fs_context.  This has the
>      downside that these strings must be static and can't be formatted.
> 
>  (*) Remove the auxiliary file_system_type structs since the information
>      necessary can be conveyed in the nfs_fs_context struct instead.
> 
>  (*) Root mounts are made by duplicating the config for the requested mount
>      so as to have the same parameters.  Submounts pick up their parameters
>      from the parent superblock.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
> 
>  fs/nfs/client.c         |   74 +++--
>  fs/nfs/fs_context.c     |  652 ++++++++++++++++++++++++++++-------------------
>  fs/nfs/getroot.c        |   72 +++--
>  fs/nfs/internal.h       |  104 +++----
>  fs/nfs/namespace.c      |   76 ++++-
>  fs/nfs/nfs3_fs.h        |    2 
>  fs/nfs/nfs3client.c     |    6 
>  fs/nfs/nfs3proc.c       |    2 
>  fs/nfs/nfs4_fs.h        |    4 
>  fs/nfs/nfs4client.c     |   44 ++-
>  fs/nfs/nfs4namespace.c  |  208 +++++++++------
>  fs/nfs/nfs4proc.c       |    3 
>  fs/nfs/nfs4super.c      |  220 ++++++++--------
>  fs/nfs/proc.c           |    2 
>  fs/nfs/super.c          |  381 ++++++++-------------------
>  include/linux/nfs_xdr.h |    7 -
>  16 files changed, 940 insertions(+), 917 deletions(-)
> 
> diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> index d25dfa15f2ec..8c9b610ca952 100644
> --- a/fs/nfs/client.c
> +++ b/fs/nfs/client.c
> @@ -635,25 +635,24 @@ EXPORT_SYMBOL_GPL(nfs_init_client);
>   * Create a version 2 or 3 client
>   */
>  static int nfs_init_server(struct nfs_server *server,
> -			   const struct nfs_fs_context *cfg,
> -			   struct nfs_subversion *nfs_mod)
> +			   const struct nfs_fs_context *ctx)
>  {
>  	struct rpc_timeout timeparms;
>  	struct nfs_client_initdata cl_init = {
> -		.hostname = cfg->nfs_server.hostname,
> -		.addr = (const struct sockaddr *)&cfg->nfs_server.address,
> -		.addrlen = cfg->nfs_server.addrlen,
> -		.nfs_mod = nfs_mod,
> -		.proto = cfg->nfs_server.protocol,
> -		.net = cfg->net,
> +		.hostname = ctx->nfs_server.hostname,
> +		.addr = (const struct sockaddr *)&ctx->nfs_server.address,
> +		.addrlen = ctx->nfs_server.addrlen,
> +		.nfs_mod = ctx->nfs_mod,
> +		.proto = ctx->nfs_server.protocol,
> +		.net = ctx->fc.net_ns,
>  		.timeparms = &timeparms,
>  	};
>  	struct nfs_client *clp;
>  	int error;
>  
> -	nfs_init_timeout_values(&timeparms, cfg->nfs_server.protocol,
> -				cfg->timeo, cfg->retrans);
> -	if (cfg->flags & NFS_MOUNT_NORESVPORT)
> +	nfs_init_timeout_values(&timeparms, ctx->nfs_server.protocol,
> +				ctx->timeo, ctx->retrans);
> +	if (ctx->flags & NFS_MOUNT_NORESVPORT)
>  		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
>  
>  	/* Allocate or find a client reference we can use */
> @@ -664,46 +663,46 @@ static int nfs_init_server(struct nfs_server *server,
>  	server->nfs_client = clp;
>  
>  	/* Initialise the client representation from the mount data */
> -	server->flags = cfg->flags;
> -	server->options = cfg->options;
> +	server->flags = ctx->flags;
> +	server->options = ctx->options;
>  	server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
>  		NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
>  		NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
>  
> -	if (cfg->rsize)
> -		server->rsize = nfs_block_size(cfg->rsize, NULL);
> -	if (cfg->wsize)
> -		server->wsize = nfs_block_size(cfg->wsize, NULL);
> +	if (ctx->rsize)
> +		server->rsize = nfs_block_size(ctx->rsize, NULL);
> +	if (ctx->wsize)
> +		server->wsize = nfs_block_size(ctx->wsize, NULL);
>  
> -	server->acregmin = cfg->acregmin * HZ;
> -	server->acregmax = cfg->acregmax * HZ;
> -	server->acdirmin = cfg->acdirmin * HZ;
> -	server->acdirmax = cfg->acdirmax * HZ;
> +	server->acregmin = ctx->acregmin * HZ;
> +	server->acregmax = ctx->acregmax * HZ;
> +	server->acdirmin = ctx->acdirmin * HZ;
> +	server->acdirmax = ctx->acdirmax * HZ;
>  
>  	/* Start lockd here, before we might error out */
>  	error = nfs_start_lockd(server);
>  	if (error < 0)
>  		goto error;
>  
> -	server->port = cfg->nfs_server.port;
> -	server->auth_info = cfg->auth_info;
> +	server->port = ctx->nfs_server.port;
> +	server->auth_info = ctx->auth_info;
>  
>  	error = nfs_init_server_rpcclient(server, &timeparms,
> -					  cfg->selected_flavor);
> +					  ctx->selected_flavor);
>  	if (error < 0)
>  		goto error;
>  
>  	/* Preserve the values of mount_server-related mount options */
> -	if (cfg->mount_server.addrlen) {
> -		memcpy(&server->mountd_address, &cfg->mount_server.address,
> -			cfg->mount_server.addrlen);
> -		server->mountd_addrlen = cfg->mount_server.addrlen;
> +	if (ctx->mount_server.addrlen) {
> +		memcpy(&server->mountd_address, &ctx->mount_server.address,
> +			ctx->mount_server.addrlen);
> +		server->mountd_addrlen = ctx->mount_server.addrlen;
>  	}
> -	server->mountd_version = cfg->mount_server.version;
> -	server->mountd_port = cfg->mount_server.port;
> -	server->mountd_protocol = cfg->mount_server.protocol;
> +	server->mountd_version = ctx->mount_server.version;
> +	server->mountd_port = ctx->mount_server.port;
> +	server->mountd_protocol = ctx->mount_server.protocol;
>  
> -	server->namelen  = cfg->namlen;
> +	server->namelen  = ctx->namlen;
>  	return 0;
>  
>  error:
> @@ -921,8 +920,7 @@ EXPORT_SYMBOL_GPL(nfs_free_server);
>   * Create a version 2 or 3 volume record
>   * - keyed on server and FSID
>   */
> -struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
> -				     struct nfs_subversion *nfs_mod)
> +struct nfs_server *nfs_create_server(struct nfs_fs_context *ctx)
>  {
>  	struct nfs_server *server;
>  	struct nfs_fattr *fattr;
> @@ -938,18 +936,18 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
>  		goto error;
>  
>  	/* Get a client representation */
> -	error = nfs_init_server(server, mount_info->ctx, nfs_mod);
> +	error = nfs_init_server(server, ctx);
>  	if (error < 0)
>  		goto error;
>  
>  	/* Probe the root fh to retrieve its FSID */
> -	error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
> +	error = nfs_probe_fsinfo(server, ctx->mntfh, fattr);
>  	if (error < 0)
>  		goto error;
>  	if (server->nfs_client->rpc_ops->version == 3) {
>  		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
>  			server->namelen = NFS3_MAXNAMLEN;
> -		if (!(mount_info->ctx->flags & NFS_MOUNT_NORDIRPLUS))
> +		if (!(ctx->flags & NFS_MOUNT_NORDIRPLUS))
>  			server->caps |= NFS_CAP_READDIRPLUS;
>  	} else {
>  		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
> @@ -957,7 +955,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
>  	}
>  
>  	if (!(fattr->valid & NFS_ATTR_FATTR)) {
> -		error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL);
> +		error = ctx->nfs_mod->rpc_ops->getattr(server, ctx->mntfh, fattr, NULL);
>  		if (error < 0) {
>  			dprintk("nfs_create_server: getattr error = %d\n", -error);
>  			goto error;
> diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
> index 24becb82540f..e8e88aaa5164 100644
> --- a/fs/nfs/fs_context.c
> +++ b/fs/nfs/fs_context.c
> @@ -240,42 +240,8 @@ static const match_table_t nfs_vers_tokens = {
>  	{ Opt_vers_err, NULL }
>  };
>  
> -struct nfs_fs_context *nfs_alloc_parsed_mount_data(void)
> -{
> -	struct nfs_fs_context *ctx;
> -
> -	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> -	if (ctx) {
> -		ctx->timeo		= NFS_UNSPEC_TIMEO;
> -		ctx->retrans		= NFS_UNSPEC_RETRANS;
> -		ctx->acregmin		= NFS_DEF_ACREGMIN;
> -		ctx->acregmax		= NFS_DEF_ACREGMAX;
> -		ctx->acdirmin		= NFS_DEF_ACDIRMIN;
> -		ctx->acdirmax		= NFS_DEF_ACDIRMAX;
> -		ctx->mount_server.port	= NFS_UNSPEC_PORT;
> -		ctx->nfs_server.port	= NFS_UNSPEC_PORT;
> -		ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
> -		ctx->selected_flavor	= RPC_AUTH_MAXFLAVOR;
> -		ctx->minorversion	= 0;
> -		ctx->need_mount	= true;
> -		ctx->net		= current->nsproxy->net_ns;
> -		security_init_mnt_opts(&ctx->lsm_opts);
> -	}
> -	return ctx;
> -}
> -
> -void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx)
> -{
> -	if (ctx) {
> -		kfree(ctx->client_address);
> -		kfree(ctx->mount_server.hostname);
> -		kfree(ctx->nfs_server.export_path);
> -		kfree(ctx->nfs_server.hostname);
> -		kfree(ctx->fscache_uniq);
> -		security_free_mnt_opts(&ctx->lsm_opts);
> -		kfree(ctx);
> -	}
> -}
> +const char nfs_slash[] = "/";
> +EXPORT_SYMBOL_GPL(nfs_slash);
>  
>  /*
>   * Sanity-check a server address provided by the mount command.
> @@ -354,10 +320,8 @@ static int nfs_auth_info_add(struct nfs_fs_context *ctx,
>  			return 0;
>  	}
>  
> -	if (auth_info->flavor_len + 1 >= max_flavor_len) {
> -		dfprintk(MOUNT, "NFS: too many sec= flavors\n");
> -		return -EINVAL;
> -	}
> +	if (auth_info->flavor_len + 1 >= max_flavor_len)
> +		return invalf("NFS: too many sec= flavors");
>  
>  	auth_info->flavors[auth_info->flavor_len++] = flavor;
>  	return 0;
> @@ -411,9 +375,7 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value)
>  			pseudoflavor = RPC_AUTH_GSS_SPKMP;
>  			break;
>  		default:
> -			dfprintk(MOUNT,
> -				 "NFS: sec= option '%s' not recognized\n", p);
> -			return -EINVAL;
> +			return invalf("NFS: sec=%s option not recognized", p);
>  		}
>  
>  		ret = nfs_auth_info_add(ctx, &ctx->auth_info, pseudoflavor);
> @@ -457,8 +419,7 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx,
>  		ctx->minorversion = 2;
>  		break;
>  	default:
> -		dfprintk(MOUNT, "NFS:   Unsupported NFS version\n");
> -		return -EINVAL;
> +		return invalf("NFS: Unsupported NFS version");
>  	}
>  	return 0;
>  }
> @@ -495,8 +456,9 @@ static int nfs_get_option_ui_bound(struct nfs_fs_context *ctx,
>  /*
>   * Parse a single mount option in "key[=val]" form.
>   */
> -static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
> +static int nfs_fs_context_parse_option(struct fs_context *fc, char *p)
>  {
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
>  	substring_t args[MAX_OPT_ARGS];
>  	char *string;
>  	int ret, token;
> @@ -715,8 +677,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
>  			break;
>  		default:
>  			kfree(string);
> -			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
> -			return -EINVAL;
> +			return invalf("NFS: Unrecognized transport protocol");
>  		}
>  		kfree(string);
>  		break;
> @@ -741,8 +702,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
>  			break;
>  		case Opt_xprt_rdma: /* not used for side protocols */
>  		default:
> -			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
> -			return -EINVAL;
> +			return invalf("NFS: Unrecognized transport protocol");
>  		}
>  		break;
>  	case Opt_addr:
> @@ -750,7 +710,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
>  		if (string == NULL)
>  			goto out_nomem;
>  		ctx->nfs_server.addrlen =
> -			rpc_pton(ctx->net, string, strlen(string),
> +			rpc_pton(fc->net_ns, string, strlen(string),
>  				 &ctx->nfs_server.address,
>  				 sizeof(ctx->nfs_server._address));
>  		kfree(string);
> @@ -770,7 +730,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
>  		if (string == NULL)
>  			goto out_nomem;
>  		ctx->mount_server.addrlen =
> -			rpc_pton(ctx->net, string, strlen(string),
> +			rpc_pton(fc->net_ns, string, strlen(string),
>  				 &ctx->mount_server.address,
>  				 sizeof(ctx->mount_server._address));
>  		kfree(string);
> @@ -795,8 +755,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
>  			ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
>  			break;
>  		default:
> -			dfprintk(MOUNT, "NFS:   invalid lookupcache argument\n");
> -			return -EINVAL;
> +			return invalf("NFS: Invalid lookupcache argument");
>  		}
>  		break;
>  	case Opt_fscache_uniq:
> @@ -826,16 +785,15 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
>  					NFS_MOUNT_LOCAL_FCNTL);
>  			break;
>  		default:
> -			dfprintk(MOUNT, "NFS:	invalid	local_lock argument\n");
> -			return -EINVAL;
> -		};
> +			return invalf("NFS: invalid local_lock argument");
> +		}
>  		break;
>  
>  		/*
>  		 * Special options
>  		 */
>  	case Opt_sloppy:
> -		ctx->sloppy = 1;
> +		fc->sloppy = 1;
>  		dfprintk(MOUNT, "NFS:   relaxing parsing rules\n");
>  		break;
>  	case Opt_userspace:
> @@ -845,116 +803,24 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
>  
>  	default:
>  		dfprintk(MOUNT, "NFS:   unrecognized mount option '%s'\n", p);
> -		return -EINVAL;
> +		if (!fc->sloppy)
> +			return invalf("NFS: Unrecognized mount option '%s'", p);

Did you mean to remove the dfprintk() above with this change, too?  I wonder if the invalf() / errorf() changeover could go into its own patch to make it easier to catch any issues.

> +		break;
>  	}
>  
>  	return 0;
>  
> -out_invalid_address:
> -	printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
> -	return -EINVAL;
> -out_invalid_value:
> -	printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
> -	return -EINVAL;
>  out_nomem:
>  	printk(KERN_INFO "NFS: not enough memory to parse option\n");
>  	return -ENOMEM;
> +out_invalid_value:
> +	return invalf("NFS: Bad mount option value specified");
> +out_invalid_address:
> +	return invalf("NFS: Bad IP address specified");
>  }
>  
>  /*
> - * Error-check and convert a string of mount options from user space into
> - * a data structure.  The whole mount string is processed; bad options are
> - * skipped as they are encountered.  If there were no errors, return 1;
> - * otherwise return 0 (zero).
> - */
> -int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
> -{
> -	char *p, *secdata;
> -	int rc, sloppy = 0, invalid_option = 0;
> -
> -	if (!raw) {
> -		dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
> -		return 1;
> -	}
> -	dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
> -
> -	secdata = alloc_secdata();
> -	if (!secdata)
> -		goto out_nomem;
> -
> -	rc = security_sb_copy_data(raw, secdata);
> -	if (rc)
> -		goto out_security_failure;
> -
> -	rc = security_sb_parse_opts_str(secdata, &ctx->lsm_opts);
> -	if (rc)
> -		goto out_security_failure;
> -
> -	free_secdata(secdata);
> -
> -	while ((p = strsep(&raw, ",")) != NULL) {
> -		if (!*p)
> -			continue;
> -		if (nfs_fs_context_parse_option(ctx, p) < 0)
> -			invalid_option = true;
> -	}
> -
> -	if (!sloppy && invalid_option)
> -		return 0;
> -
> -	if (ctx->minorversion && ctx->version != 4)
> -		goto out_minorversion_mismatch;
> -
> -	if (ctx->options & NFS_OPTION_MIGRATION &&
> -	    (ctx->version != 4 || ctx->minorversion != 0))
> -		goto out_migration_misuse;
> -
> -	/*
> -	 * verify that any proto=/mountproto= options match the address
> -	 * families in the addr=/mountaddr= options.
> -	 */
> -	if (ctx->protofamily != AF_UNSPEC &&
> -	    ctx->protofamily != ctx->nfs_server.address.sa_family)
> -		goto out_proto_mismatch;
> -
> -	if (ctx->mountfamily != AF_UNSPEC) {
> -		if (ctx->mount_server.addrlen) {
> -			if (ctx->mountfamily != ctx->mount_server.address.sa_family)
> -				goto out_mountproto_mismatch;
> -		} else {
> -			if (ctx->mountfamily != ctx->nfs_server.address.sa_family)
> -				goto out_mountproto_mismatch;
> -		}
> -	}
> -
> -	return 1;
> -
> -out_minorversion_mismatch:
> -	printk(KERN_INFO "NFS: mount option vers=%u does not support "
> -			 "minorversion=%u\n", ctx->version, ctx->minorversion);
> -	return 0;
> -out_mountproto_mismatch:
> -	printk(KERN_INFO "NFS: mount server address does not match mountproto= "
> -			 "option\n");
> -	return 0;
> -out_proto_mismatch:
> -	printk(KERN_INFO "NFS: server address does not match proto= option\n");
> -	return 0;
> -out_migration_misuse:
> -	printk(KERN_INFO
> -		"NFS: 'migration' not supported for this NFS version\n");
> -	return -EINVAL;
> -out_nomem:
> -	printk(KERN_INFO "NFS: not enough memory to parse option\n");
> -	return 0;
> -out_security_failure:
> -	free_secdata(secdata);
> -	printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
> -	return 0;
> -}
> -
> -/*
> - * Split "dev_name" into "hostname:export_path".
> + * Split sc->device into "hostname:export_path".
>   *
>   * The leftmost colon demarks the split between the server's hostname
>   * and the export path.  If the hostname starts with a left square
> @@ -963,9 +829,9 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
>   * Note: caller frees hostname and export path, even on error.
>   */
>  static int nfs_parse_devname(struct nfs_fs_context *ctx,
> -			     const char *dev_name,
>  			     size_t maxnamlen, size_t maxpathlen)
>  {
> +	char *dev_name = ctx->fc.device;
>  	size_t len;
>  	char *end;
>  
> @@ -1009,19 +875,15 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
>  	return 0;
>  
>  out_bad_devname:
> -	dfprintk(MOUNT, "NFS: device name not in host:path format\n");
> -	return -EINVAL;
> -
> +	return invalf("NFS: device name not in host:path format");
>  out_nomem:
> -	dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
> +	errorf("NFS: not enough memory to parse device name");
>  	return -ENOMEM;
> -
>  out_hostname:
> -	dfprintk(MOUNT, "NFS: server hostname too long\n");
> +	errorf("NFS: server hostname too long");
>  	return -ENAMETOOLONG;
> -
>  out_path:
> -	dfprintk(MOUNT, "NFS: export pathname too long\n");
> +	errorf("NFS: export pathname too long");
>  	return -ENAMETOOLONG;
>  }
>  
> @@ -1041,14 +903,14 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
>   * + breaking back: trying proto=udp after proto=tcp, v2 after v3,
>   *   mountproto=tcp after mountproto=udp, and so on
>   */
> -static int nfs23_validate_mount_data(void *options,
> -				     struct nfs_fs_context *ctx,
> -				     struct nfs_fh *mntfh,
> -				     const char *dev_name)
> +static int nfs23_monolithic_mount_data(struct fs_context *fc,
> +				       struct nfs_mount_data *data)
>  {
> -	struct nfs_mount_data *data = (struct nfs_mount_data *)options;
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
> +	struct nfs_fh *mntfh = ctx->mntfh;
>  	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
>  	int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
> +	int ret;

If I set SECURITY_SELINUX=n and compile, I see this:

fs/nfs/fs_context.c:913:6: error: unused variable 'ret' [-Werror=unused-variable]
  int ret;  

>  
>  	if (data == NULL)
>  		goto out_no_data;
> @@ -1114,6 +976,9 @@ static int nfs23_validate_mount_data(void *options,
>  			ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
>  		/* N.B. caller will free nfs_server.hostname in all cases */
>  		ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
> +		if (!ctx->nfs_server.hostname)
> +			goto out_nomem;
> +
>  		ctx->namlen		= data->namlen;
>  		ctx->bsize		= data->bsize;
>  
> @@ -1121,8 +986,6 @@ static int nfs23_validate_mount_data(void *options,
>  			ctx->selected_flavor = data->pseudoflavor;
>  		else
>  			ctx->selected_flavor = RPC_AUTH_UNIX;
> -		if (!ctx->nfs_server.hostname)
> -			goto out_nomem;
>  
>  		if (!(data->flags & NFS_MOUNT_NONLM))
>  			ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
> @@ -1130,6 +993,7 @@ static int nfs23_validate_mount_data(void *options,
>  		else
>  			ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK|
>  					NFS_MOUNT_LOCAL_FCNTL);
> +
>  		/*
>  		 * The legacy version 6 binary mount data from userspace has a
>  		 * field used only to transport selinux information into the
> @@ -1140,17 +1004,16 @@ static int nfs23_validate_mount_data(void *options,
>  		 */
>  		if (data->context[0]){
>  #ifdef CONFIG_SECURITY_SELINUX
> -			int rc;

Keeping rc here would fix the problem I just mentioned

>  			char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL);
>  			if (!opts_str)
>  				return -ENOMEM;
>  			strcpy(opts_str, "context=");
>  			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
>  			strcat(opts_str, &data->context[0]);
> -			rc = security_sb_parse_opts_str(opts_str, &ctx->lsm_opts);
> +			ret = vfs_parse_mount_option(fc, opts_str);
>  			kfree(opts_str);
> -			if (rc)
> -				return rc;
> +			if (ret)
> +				return ret;
>  #else
>  			return -EINVAL;
>  #endif
> @@ -1158,54 +1021,44 @@ static int nfs23_validate_mount_data(void *options,
>  
>  		break;
>  	default:
> -		return NFS_TEXT_DATA;
> +		return generic_monolithic_mount_data(fc, data);
>  	}
>  
> +	ctx->skip_remount_option_check = true;
>  	return 0;
>  
>  out_no_data:
> -	dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
> -	return -EINVAL;
> +	if (fc->sb_flags & MS_REMOUNT) {
> +		ctx->skip_remount_option_check = true;
> +		return 0;
> +	}
> +	return invalf("NFS: mount program didn't pass any mount data");
>  
>  out_no_v3:
> -	dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n",
> -		 data->version);
> -	return -EINVAL;
> +	return invalf("NFS: nfs_mount_data version does not support v3");
>  
>  out_no_sec:
> -	dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n");
> -	return -EINVAL;
> +	return invalf("NFS: nfs_mount_data version supports only AUTH_SYS");
>  
>  out_nomem:
> -	dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n");
> +	dfprintk(MOUNT, "NFS: not enough memory to handle mount options");
>  	return -ENOMEM;
>  
>  out_no_address:
> -	dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
> -	return -EINVAL;
> +	return invalf("NFS: mount program didn't pass remote address");
>  
>  out_invalid_fh:
> -	dfprintk(MOUNT, "NFS: invalid root filehandle\n");
> -	return -EINVAL;
> -}
> -
> -#if IS_ENABLED(CONFIG_NFS_V4)

I think the "IS_ENABLED(CONFIG_NFS_V4)" check needs to stay here, otherwise gcc wtill complain that nfs4_monolithic_mount_data() is defined but not used

> -
> -static void nfs4_validate_mount_flags(struct nfs_fs_context *ctx)
> -{
> -	ctx->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
> -			 NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
> +	return invalf("NFS: invalid root filehandle");
>  }
>  
>  /*
>   * Validate NFSv4 mount options
>   */
> -static int nfs4_validate_mount_data(void *options,
> -				    struct nfs_fs_context *ctx,
> -				    const char *dev_name)
> +static int nfs4_monolithic_mount_data(struct fs_context *fc,
> +				      struct nfs4_mount_data *data)
>  {
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
>  	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
> -	struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
>  	char *c;
>  
>  	if (data == NULL)
> @@ -1255,7 +1108,7 @@ static int nfs4_validate_mount_data(void *options,
>  		ctx->client_address = c;
>  
>  		/*
> -		 * Translate to nfs_fs_context, which nfs4_fill_super
> +		 * Translate to nfs_fs_context, which nfs_fill_super
>  		 * can deal with.
>  		 */
>  
> @@ -1275,95 +1128,372 @@ static int nfs4_validate_mount_data(void *options,
>  
>  		break;
>  	default:
> -		return NFS_TEXT_DATA;
> +		return generic_monolithic_mount_data(fc, data);
>  	}
>  
> +	ctx->skip_remount_option_check = true;
>  	return 0;
>  
>  out_no_data:
> -	dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
> -	return -EINVAL;
> +	if (fc->sb_flags & MS_REMOUNT) {
> +		ctx->skip_remount_option_check = true;
> +		return 0;
> +	}
> +	return invalf("NFS4: mount program didn't pass any mount data");
>  
>  out_inval_auth:
> -	dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n",
> -		 data->auth_flavourlen);
> -	return -EINVAL;
> +	return invalf("NFS4: Invalid number of RPC auth flavours %d",
> +		      data->auth_flavourlen);
>  
>  out_no_address:
> -	dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
> -	return -EINVAL;
> +	return invalf("NFS4: mount program didn't pass remote address");
>  
>  out_invalid_transport_udp:
> -	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
> -	return -EINVAL;
> +	return invalf("NFSv4: Unsupported transport protocol udp");
>  }
>  
> -int nfs_validate_mount_data(struct file_system_type *fs_type,
> -			    void *options,
> -			    struct nfs_fs_context *ctx,
> -			    struct nfs_fh *mntfh,
> -			    const char *dev_name)
> -{
> -	if (fs_type == &nfs_fs_type)
> -		return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
> -	return nfs4_validate_mount_data(options, ctx, dev_name);
> -}
> -#else
> -int nfs_validate_mount_data(struct file_system_type *fs_type,
> -			    void *options,
> -			    struct nfs_fs_context *ctx,
> -			    struct nfs_fh *mntfh,
> -			    const char *dev_name)
> +/*
> + * Parse a monolithic block of data from sys_mount().
> + */
> +static int nfs_monolithic_mount_data(struct fs_context *fc, void *data)
>  {
> -	return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
> -}
> +	if (fc->fs_type == &nfs_fs_type)
> +		return nfs23_monolithic_mount_data(fc, data);
> +
> +#if IS_ENABLED(CONFIG_NFS_V4)
> +	if (fc->fs_type == &nfs4_fs_type)
> +		return nfs4_monolithic_mount_data(fc, data);
>  #endif
>  
> -int nfs_validate_text_mount_data(void *options,
> -				 struct nfs_fs_context *ctx,
> -				 const char *dev_name)
> +	return invalf("NFS: Unsupported monolithic data version");
> +}
> +
> +/*
> + * Validate the preparsed information in the config.
> + */
> +static int nfs_fs_context_validate(struct fs_context *fc)
>  {
> -	int port = 0;
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
> +	struct nfs_subversion *nfs_mod;
> +	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
>  	int max_namelen = PAGE_SIZE;
>  	int max_pathlen = NFS_MAXPATHLEN;
> -	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
> +	int port = 0;
> +	int ret;
>  
> -	if (nfs_parse_mount_options((char *)options, ctx) == 0)
> -		return -EINVAL;
> +	if (ctx->fc.purpose == FS_CONTEXT_FOR_REMOUNT)
> +		return 0;
> +
> +	if (!ctx->fc.device)
> +		goto out_no_device_name;
> +
> +	/* Check for sanity first. */
> +	if (ctx->minorversion && ctx->version != 4)
> +		goto out_minorversion_mismatch;
> +
> +	if (ctx->options & NFS_OPTION_MIGRATION &&
> +	    (ctx->version != 4 || ctx->minorversion != 0))
> +		goto out_migration_misuse;
> +
> +	/* Verify that any proto=/mountproto= options match the address
> +	 * families in the addr=/mountaddr= options.
> +	 */
> +	if (ctx->protofamily != AF_UNSPEC &&
> +	    ctx->protofamily != ctx->nfs_server.address.sa_family)
> +		goto out_proto_mismatch;
> +
> +	if (ctx->mountfamily != AF_UNSPEC) {
> +		if (ctx->mount_server.addrlen) {
> +			if (ctx->mountfamily != ctx->mount_server.address.sa_family)
> +				goto out_mountproto_mismatch;
> +		} else {
> +			if (ctx->mountfamily != ctx->nfs_server.address.sa_family)
> +				goto out_mountproto_mismatch;
> +		}
> +	}
>  
>  	if (!nfs_verify_server_address(sap))
>  		goto out_no_address;
>  
>  	if (ctx->version == 4) {
> -#if IS_ENABLED(CONFIG_NFS_V4)
> -		port = NFS_PORT;
> -		max_namelen = NFS4_MAXNAMLEN;
> -		max_pathlen = NFS4_MAXPATHLEN;
> -		nfs_validate_transport_protocol(ctx);
> -		if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
> -			goto out_invalid_transport_udp;
> -		nfs4_validate_mount_flags(ctx);
> -#else
> -		goto out_v4_not_compiled;
> -#endif /* CONFIG_NFS_V4 */
> -	} else
> +		if (IS_ENABLED(CONFIG_NFS_V4)) {
> +			port = NFS_PORT;
> +			max_namelen = NFS4_MAXNAMLEN;
> +			max_pathlen = NFS4_MAXPATHLEN;
> +			nfs_validate_transport_protocol(ctx);
> +			if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
> +				goto out_invalid_transport_udp;
> +			ctx->flags &= ~(NFS_MOUNT_NONLM | NFS_MOUNT_NOACL |
> +					 NFS_MOUNT_VER3 | NFS_MOUNT_LOCAL_FLOCK |
> +					 NFS_MOUNT_LOCAL_FCNTL);
> +		} else {
> +			goto out_v4_not_compiled;
> +		}
> +	} else {
>  		nfs_set_mount_transport_protocol(ctx);
> +	}
>  
>  	nfs_set_port(sap, &ctx->nfs_server.port, port);
>  
> -	return nfs_parse_devname(ctx, dev_name, max_namelen, max_pathlen);
> +	ret = nfs_parse_devname(ctx, max_namelen, max_pathlen);
> +	if (ret < 0)
> +		return ret;
>  
> -#if !IS_ENABLED(CONFIG_NFS_V4)
> +	/* Load the NFS protocol module if we haven't done so yet */
> +	if (!ctx->nfs_mod) {
> +		nfs_mod = get_nfs_version(ctx->version);
> +		if (IS_ERR(nfs_mod)) {
> +			ret = PTR_ERR(nfs_mod);
> +			goto out_version_unavailable;
> +		}
> +		ctx->nfs_mod = nfs_mod;
> +	}
> +	return 0;
> +
> +out_no_device_name:
> +	return invalf("NFS: Device name not specified");
>  out_v4_not_compiled:
> -	dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
> +	errorf("NFS: NFSv4 is not compiled into kernel");
>  	return -EPROTONOSUPPORT;
> -#else
>  out_invalid_transport_udp:
> -	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
> -	return -EINVAL;
> -#endif /* !CONFIG_NFS_V4 */
> -
> +	return invalf("NFSv4: Unsupported transport protocol udp");
>  out_no_address:
> -	dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
> -	return -EINVAL;
> +	return invalf("NFS: mount program didn't pass remote address");
> +out_mountproto_mismatch:
> +	return invalf("NFS: Mount server address does not match mountproto= option");
> +out_proto_mismatch:
> +	return invalf("NFS: Server address does not match proto= option");
> +out_minorversion_mismatch:
> +	return invalf("NFS: Mount option vers=%u does not support minorversion=%u",
> +		      ctx->version, ctx->minorversion);
> +out_migration_misuse:
> +	return invalf("NFS: 'Migration' not supported for this NFS version");
> +out_version_unavailable:
> +	errorf("NFS: Version unavailable");
> +	return ret;
> +}
> +
> +/*
> + * Use the preparsed information in the config to effect a mount.
> + */
> +static int nfs_get_ordinary_tree(struct nfs_fs_context *ctx)
> +{
> +	ctx->set_security = nfs_set_sb_security;
> +
> +	return ctx->nfs_mod->rpc_ops->try_get_tree(ctx);
>  }
> +
> +/*
> + * Clone an NFS2/3/4 server record on xdev traversal (FSID-change)
> + */
> +static int nfs_get_xdev_tree(struct nfs_fs_context *ctx)
> +{
> +	struct nfs_server *server;
> +	int ret;
> +
> +	dprintk("--> nfs_xdev_mount()\n");

I think the dprintk()s in this function are just going to add noise.  Can you do the patch without them?

Thanks,
Anna

> +
> +	ctx->set_security = nfs_clone_sb_security;
> +
> +	/* create a new volume representation */
> +	server = ctx->nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb),
> +						     ctx->mntfh,
> +						     ctx->clone_data.fattr,
> +						     ctx->selected_flavor);
> +
> +	if (IS_ERR(server))
> +		ret = PTR_ERR(server);
> +	else
> +		ret = nfs_get_tree_common(server, ctx);
> +
> +	dprintk("<-- nfs_get_xdev_tree() = %d\n", ret);
> +	return ret;
> +}
> +
> +/*
> + * Create an NFS superblock by the appropriate method.
> + */
> +static int nfs_get_tree(struct fs_context *fc)
> +{
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
> +	int ret;
> +
> +	if (!ctx->nfs_mod) {
> +		pr_warn("Missing nfs_mod\n");
> +		return -EINVAL;
> +	}
> +	if (!ctx->nfs_mod->rpc_ops) {
> +		pr_warn("Missing rpc_ops\n");
> +		return -EINVAL;
> +	}
> +
> +	if (ctx->nfs_mod->rpc_ops->get_tree) {
> +		ret = ctx->nfs_mod->rpc_ops->get_tree(ctx);
> +		if (ret != 1)
> +			return ret;
> +	}
> +
> +	switch (ctx->mount_type) {
> +	case NFS_MOUNT_ORDINARY:
> +		return nfs_get_ordinary_tree(ctx);
> +
> +	case NFS_MOUNT_CROSS_DEV:
> +		return nfs_get_xdev_tree(ctx);
> +
> +	default:
> +		errorf("NFS: Unknown mount type");
> +		return -ENOTSUPP;
> +	}
> +}
> +
> +/*
> + * Handle duplication of a configuration.  The caller copied *src into *sc, but
> + * it can't deal with resource pointers in the filesystem context, so we have
> + * to do that.  We need to clear pointers, copy data or get extra refs as
> + * appropriate.
> + */
> +static int nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src)
> +{
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
> +
> +	__module_get(ctx->nfs_mod->owner);
> +	ctx->client_address		= NULL;
> +	ctx->mount_server.hostname	= NULL;
> +	ctx->nfs_server.export_path	= NULL;
> +	ctx->nfs_server.hostname	= NULL;
> +	ctx->fscache_uniq		= NULL;
> +
> +	ctx->mntfh = nfs_alloc_fhandle();
> +	if (!ctx->mntfh)
> +		return -ENOMEM;
> +	return 0;
> +}
> +
> +static void nfs_fs_context_free(struct fs_context *fc)
> +{
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
> +
> +	if (ctx->nfs_mod)
> +		put_nfs_version(ctx->nfs_mod);
> +	kfree(ctx->client_address);
> +	kfree(ctx->mount_server.hostname);
> +	if (ctx->nfs_server.export_path != nfs_slash)
> +		kfree(ctx->nfs_server.export_path);
> +	kfree(ctx->nfs_server.hostname);
> +	kfree(ctx->fscache_uniq);
> +	nfs_free_fhandle(ctx->mntfh);
> +}
> +
> +static const struct fs_context_operations nfs_fs_context_ops = {
> +	.free			= nfs_fs_context_free,
> +	.dup			= nfs_fs_context_dup,
> +	.parse_option		= nfs_fs_context_parse_option,
> +	.monolithic_mount_data	= nfs_monolithic_mount_data,
> +	.validate		= nfs_fs_context_validate,
> +	.get_tree		= nfs_get_tree,
> +};
> +
> +/*
> + * Initialise a configuration from an extant superblock for remounting.
> + */
> +static int nfs_mount_init_from_sb(struct fs_context *fc,
> +				  struct super_block *sb)
> +{
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
> +	struct nfs_server *nfss = sb->s_fs_info;
> +	struct net *net = nfss->nfs_client->cl_net;
> +
> +	ctx->flags		= nfss->flags;
> +	ctx->rsize		= nfss->rsize;
> +	ctx->wsize		= nfss->wsize;
> +	ctx->retrans		= nfss->client->cl_timeout->to_retries;
> +	ctx->selected_flavor	= nfss->client->cl_auth->au_flavor;
> +	ctx->acregmin		= nfss->acregmin / HZ;
> +	ctx->acregmax		= nfss->acregmax / HZ;
> +	ctx->acdirmin		= nfss->acdirmin / HZ;
> +	ctx->acdirmax		= nfss->acdirmax / HZ;
> +	ctx->timeo		= 10U * nfss->client->cl_timeout->to_initval / HZ;
> +	ctx->nfs_server.port	= nfss->port;
> +	ctx->nfs_server.addrlen	= nfss->nfs_client->cl_addrlen;
> +	ctx->version		= nfss->nfs_client->rpc_ops->version;
> +	ctx->minorversion	= nfss->nfs_client->cl_minorversion;
> +
> +	memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr,
> +		ctx->nfs_server.addrlen);
> +
> +	if (ctx->fc.net_ns != net) {
> +		put_net(ctx->fc.net_ns);
> +		ctx->fc.net_ns = get_net(net);
> +	}
> +
> +	ctx->nfs_mod = nfss->nfs_client->cl_nfs_mod;
> +	if (!try_module_get(ctx->nfs_mod->owner)) {
> +		ctx->nfs_mod = NULL;
> +		errorf("NFS: Protocol module not available");
> +		return -ENOENT;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Prepare superblock configuration.  We use the namespaces attached to the
> + * context.  This may be the current process's namespaces, or it may be a
> + * container's namespaces.
> + */
> +static int nfs_init_fs_context(struct fs_context *fc, struct super_block *src_sb)
> +{
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
> +
> +	ctx->mntfh = nfs_alloc_fhandle();
> +	if (!ctx->mntfh)
> +		return -ENOMEM;
> +
> +	ctx->fc.ops		= &nfs_fs_context_ops;
> +	ctx->mount_type		= NFS_MOUNT_ORDINARY;
> +	ctx->protofamily	= AF_UNSPEC;
> +	ctx->mountfamily	= AF_UNSPEC;
> +	ctx->mount_server.port	= NFS_UNSPEC_PORT;
> +
> +	if (!src_sb) {
> +		ctx->timeo		= NFS_UNSPEC_TIMEO;
> +		ctx->retrans		= NFS_UNSPEC_RETRANS;
> +		ctx->acregmin		= NFS_DEF_ACREGMIN;
> +		ctx->acregmax		= NFS_DEF_ACREGMAX;
> +		ctx->acdirmin		= NFS_DEF_ACDIRMIN;
> +		ctx->acdirmax		= NFS_DEF_ACDIRMAX;
> +		ctx->nfs_server.port	= NFS_UNSPEC_PORT;
> +		ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
> +		ctx->selected_flavor	= RPC_AUTH_MAXFLAVOR;
> +		ctx->minorversion	= 0;
> +		ctx->need_mount		= true;
> +		return 0;
> +	}
> +
> +	return nfs_mount_init_from_sb(fc, src_sb);
> +}
> +
> +struct file_system_type nfs_fs_type = {
> +	.owner			= THIS_MODULE,
> +	.name			= "nfs",
> +	.init_fs_context	= nfs_init_fs_context,
> +	.fs_context_size	= sizeof(struct nfs_fs_context),
> +	.kill_sb		= nfs_kill_super,
> +	.fs_flags		= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
> +};
> +MODULE_ALIAS_FS("nfs");
> +EXPORT_SYMBOL_GPL(nfs_fs_type);
> +
> +#if IS_ENABLED(CONFIG_NFS_V4)
> +struct file_system_type nfs4_fs_type = {
> +	.owner			= THIS_MODULE,
> +	.name			= "nfs4",
> +	.fs_context_size	= sizeof(struct nfs_fs_context),
> +	.init_fs_context	= nfs_init_fs_context,
> +	.kill_sb		= nfs_kill_super,
> +	.fs_flags		= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
> +};
> +MODULE_ALIAS_FS("nfs4");
> +MODULE_ALIAS("nfs4");
> +EXPORT_SYMBOL_GPL(nfs4_fs_type);
> +#endif /* CONFIG_NFS_V4 */
> diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
> index 391dafaf9182..4a5ee38117b5 100644
> --- a/fs/nfs/getroot.c
> +++ b/fs/nfs/getroot.c
> @@ -68,66 +68,70 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
>  /*
>   * get an NFS2/NFS3 root dentry from the root filehandle
>   */
> -struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
> -			    const char *devname)
> +int nfs_get_root(struct super_block *s, struct nfs_fs_context *ctx)
>  {
> -	struct nfs_server *server = NFS_SB(sb);
> +	struct nfs_server *server = NFS_SB(s);
>  	struct nfs_fsinfo fsinfo;
> -	struct dentry *ret;
> +	struct dentry *root;
>  	struct inode *inode;
> -	void *name = kstrdup(devname, GFP_KERNEL);
> -	int error;
> +	char *name;
> +	int error = -ENOMEM;
>  
> +	name = kstrdup(ctx->fc.device, GFP_KERNEL);
>  	if (!name)
> -		return ERR_PTR(-ENOMEM);
> +		goto out;
>  
>  	/* get the actual root for this mount */
>  	fsinfo.fattr = nfs_alloc_fattr();
> -	if (fsinfo.fattr == NULL) {
> -		kfree(name);
> -		return ERR_PTR(-ENOMEM);
> -	}
> +	if (fsinfo.fattr == NULL)
> +		goto out_name;
>  
> -	error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
> +	error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
>  	if (error < 0) {
>  		dprintk("nfs_get_root: getattr error = %d\n", -error);
> -		ret = ERR_PTR(error);
> -		goto out;
> +		errorf("NFS: Couldn't getattr on root");
> +		goto out_fattr;
>  	}
>  
> -	inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL);
> +	inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr, NULL);
>  	if (IS_ERR(inode)) {
>  		dprintk("nfs_get_root: get root inode failed\n");
> -		ret = ERR_CAST(inode);
> -		goto out;
> +		error = PTR_ERR(inode);
> +		errorf("NFS: Couldn't get root inode");
> +		goto out_fattr;
>  	}
>  
> -	error = nfs_superblock_set_dummy_root(sb, inode);
> -	if (error != 0) {
> -		ret = ERR_PTR(error);
> -		goto out;
> -	}
> +	error = nfs_superblock_set_dummy_root(s, inode);
> +	if (error != 0)
> +		goto out_fattr;
>  
>  	/* root dentries normally start off anonymous and get spliced in later
>  	 * if the dentry tree reaches them; however if the dentry already
>  	 * exists, we'll pick it up at this point and use it as the root
>  	 */
> -	ret = d_obtain_root(inode);
> -	if (IS_ERR(ret)) {
> +	root = d_obtain_root(inode);
> +	if (IS_ERR(root)) {
>  		dprintk("nfs_get_root: get root dentry failed\n");
> -		goto out;
> +		error = PTR_ERR(root);
> +		errorf("NFS: Couldn't get root dentry");
> +		goto out_fattr;
>  	}
>  
> -	security_d_instantiate(ret, inode);
> -	spin_lock(&ret->d_lock);
> -	if (IS_ROOT(ret) && !ret->d_fsdata &&
> -	    !(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
> -		ret->d_fsdata = name;
> +	security_d_instantiate(root, inode);
> +	spin_lock(&root->d_lock);
> +	if (IS_ROOT(root) && !root->d_fsdata &&
> +	    !(root->d_flags & DCACHE_NFSFS_RENAMED)) {
> +		root->d_fsdata = name;
>  		name = NULL;
>  	}
> -	spin_unlock(&ret->d_lock);
> -out:
> -	kfree(name);
> +	spin_unlock(&root->d_lock);
> +	ctx->fc.root = root;
> +	error = 0;
> +
> +out_fattr:
>  	nfs_free_fattr(fsinfo.fattr);
> -	return ret;
> +out_name:
> +	kfree(name);
> +out:
> +	return error;
>  }
> diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
> index fa568407cda8..ef7193479cda 100644
> --- a/fs/nfs/internal.h
> +++ b/fs/nfs/internal.h
> @@ -3,7 +3,7 @@
>   */
>  
>  #include "nfs4_fs.h"
> -#include <linux/mount.h>
> +#include <linux/fs_context.h>
>  #include <linux/security.h>
>  #include <linux/crc32.h>
>  #include <linux/sunrpc/addr.h>
> @@ -36,18 +36,6 @@ static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr)
>  	return 1;
>  }
>  
> -struct nfs_clone_mount {
> -	const struct super_block *sb;
> -	const struct dentry *dentry;
> -	struct nfs_fh *fh;
> -	struct nfs_fattr *fattr;
> -	char *hostname;
> -	char *mnt_path;
> -	struct sockaddr *addr;
> -	size_t addrlen;
> -	rpc_authflavor_t authflavor;
> -};
> -
>  /*
>   * Note: RFC 1813 doesn't limit the number of auth flavors that
>   * a server can return, so make something up.
> @@ -82,10 +70,22 @@ struct nfs_client_initdata {
>  	const struct rpc_timeout *timeparms;
>  };
>  
> +enum nfs_mount_type {
> +	NFS_MOUNT_ORDINARY,
> +	NFS_MOUNT_CROSS_DEV,
> +	NFS4_MOUNT_REMOTE,
> +	NFS4_MOUNT_REFERRAL,
> +	NFS4_MOUNT_REMOTE_REFERRAL,
> +};
> +
>  /*
>   * In-kernel mount arguments
>   */
>  struct nfs_fs_context {
> +	struct fs_context	fc;
> +	enum nfs_mount_type	mount_type : 8;
> +	bool			skip_remount_option_check;
> +	bool			need_mount;
>  	unsigned int		flags;		/* NFS{,4}_MOUNT_* flags */
>  	unsigned int		rsize, wsize;
>  	unsigned int		timeo, retrans;
> @@ -102,8 +102,6 @@ struct nfs_fs_context {
>  	char			*fscache_uniq;
>  	unsigned short		protofamily;
>  	unsigned short		mountfamily;
> -	bool			need_mount;
> -	bool			sloppy;
>  
>  	struct {
>  		union {
> @@ -127,10 +125,22 @@ struct nfs_fs_context {
>  		char			*export_path;
>  		int			port;
>  		unsigned short		protocol;
> +		unsigned short		export_path_len;
>  	} nfs_server;
>  
> -	struct security_mnt_opts lsm_opts;
> -	struct net		*net;
> +	struct nfs_fh		*mntfh;
> +	struct nfs_subversion	*nfs_mod;
> +	struct nfs_server	*server;
> +
> +	int (*set_security)(struct super_block *, struct nfs_fs_context *);
> +
> +	/* Information for a cloned mount. */
> +	struct nfs_clone_mount {
> +		struct super_block	*sb;
> +		struct dentry		*dentry;
> +		struct nfs_fattr	*fattr;
> +		bool			cloned;
> +	} clone_data;
>  
>  	char			buf[32];	/* Parse buffer */
>  };
> @@ -150,14 +160,6 @@ struct nfs_mount_request {
>  	struct net		*net;
>  };
>  
> -struct nfs_mount_info {
> -	void (*fill_super)(struct super_block *, struct nfs_mount_info *);
> -	int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *);
> -	struct nfs_fs_context *ctx;
> -	struct nfs_clone_mount *cloned;
> -	struct nfs_fh *mntfh;
> -};
> -
>  extern int nfs_mount(struct nfs_mount_request *info);
>  extern void nfs_umount(const struct nfs_mount_request *info);
>  
> @@ -183,13 +185,9 @@ extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
>  extern struct nfs_client *
>  nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
>  				struct nfs4_sessionid *, u32);
> -extern struct nfs_server *nfs_create_server(struct nfs_mount_info *,
> -					struct nfs_subversion *);
> -extern struct nfs_server *nfs4_create_server(
> -					struct nfs_mount_info *,
> -					struct nfs_subversion *);
> -extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
> -						      struct nfs_fh *);
> +extern struct nfs_server *nfs_create_server(struct nfs_fs_context *);
> +extern struct nfs_server *nfs4_create_server(struct nfs_fs_context *);
> +extern struct nfs_server *nfs4_create_referral_server(struct nfs_fs_context *);
>  extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
>  					struct sockaddr *sap, size_t salen,
>  					struct net *net);
> @@ -243,19 +241,7 @@ extern struct svc_version nfs4_callback_version4;
>  struct nfs_pageio_descriptor;
>  
>  /* mount.c */
> -#define NFS_TEXT_DATA		1
> -
> -extern struct nfs_fs_context *nfs_alloc_parsed_mount_data(void);
> -extern void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx);
> -extern int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx);
> -extern int nfs_validate_mount_data(struct file_system_type *fs_type,
> -				   void *options,
> -				   struct nfs_fs_context *ctx,
> -				   struct nfs_fh *mntfh,
> -				   const char *dev_name);
> -extern int nfs_validate_text_mount_data(void *options,
> -					struct nfs_fs_context *ctx,
> -					const char *dev_name);
> +extern const char nfs_slash[];
>  
>  /* pagelist.c */
>  extern int __init nfs_init_nfspagecache(void);
> @@ -418,23 +404,12 @@ extern int nfs_wait_atomic_killable(atomic_t *p);
>  /* super.c */
>  extern const struct super_operations nfs_sops;
>  extern struct file_system_type nfs_fs_type;
> -extern struct file_system_type nfs_xdev_fs_type;
> -#if IS_ENABLED(CONFIG_NFS_V4)
> -extern struct file_system_type nfs4_xdev_fs_type;
> -extern struct file_system_type nfs4_referral_fs_type;
> -#endif
>  bool nfs_auth_info_match(const struct nfs_auth_info *, rpc_authflavor_t);
> -struct dentry *nfs_try_mount(int, const char *, struct nfs_mount_info *,
> -			struct nfs_subversion *);
> -int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
> -int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
> -struct dentry *nfs_fs_mount_common(struct nfs_server *, int, const char *,
> -				   struct nfs_mount_info *, struct nfs_subversion *);
> -struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *);
> -struct dentry * nfs_xdev_mount_common(struct file_system_type *, int,
> -		const char *, struct nfs_mount_info *);
> +int nfs_try_get_tree(struct nfs_fs_context *);
> +int nfs_set_sb_security(struct super_block *, struct nfs_fs_context *);
> +int nfs_clone_sb_security(struct super_block *, struct nfs_fs_context *);
> +int nfs_get_tree_common(struct nfs_server *, struct nfs_fs_context *);
>  void nfs_kill_super(struct super_block *);
> -void nfs_fill_super(struct super_block *, struct nfs_mount_info *);
>  
>  extern struct rpc_stat nfs_rpcstat;
>  
> @@ -467,12 +442,9 @@ struct vfsmount *nfs_do_submount(struct dentry *, struct nfs_fh *,
>  				 struct nfs_fattr *, rpc_authflavor_t);
>  
>  /* getroot.c */
> -extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *,
> -				   const char *);
> +extern int nfs_get_root(struct super_block *s, struct nfs_fs_context *cfg);
>  #if IS_ENABLED(CONFIG_NFS_V4)
> -extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *,
> -				    const char *);
> -
> +extern int nfs4_get_root(struct super_block *s, struct nfs_fs_context *cfg);
>  extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool);
>  #endif
>  
> @@ -491,7 +463,7 @@ int  nfs_show_options(struct seq_file *, struct dentry *);
>  int  nfs_show_devname(struct seq_file *, struct dentry *);
>  int  nfs_show_path(struct seq_file *, struct dentry *);
>  int  nfs_show_stats(struct seq_file *, struct dentry *);
> -int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
> +int nfs_remount(struct super_block *sb, struct fs_context *fc);
>  
>  /* write.c */
>  extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
> diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
> index e5686be67be8..f80062d626f9 100644
> --- a/fs/nfs/namespace.c
> +++ b/fs/nfs/namespace.c
> @@ -18,6 +18,7 @@
>  #include <linux/vfs.h>
>  #include <linux/sunrpc/gss_api.h>
>  #include "internal.h"
> +#include "nfs.h"
>  
>  #define NFSDBG_FACILITY		NFSDBG_VFS
>  
> @@ -209,16 +210,6 @@ void nfs_release_automount_timer(void)
>  		cancel_delayed_work(&nfs_automount_task);
>  }
>  
> -/*
> - * Clone a mountpoint of the appropriate type
> - */
> -static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
> -					   const char *devname,
> -					   struct nfs_clone_mount *mountdata)
> -{
> -	return vfs_submount(mountdata->dentry, &nfs_xdev_fs_type, devname, mountdata);
> -}
> -
>  /**
>   * nfs_do_submount - set up mountpoint when crossing a filesystem boundary
>   * @dentry - parent directory
> @@ -230,27 +221,58 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
>  struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
>  				 struct nfs_fattr *fattr, rpc_authflavor_t authflavor)
>  {
> -	struct nfs_clone_mount mountdata = {
> -		.sb = dentry->d_sb,
> -		.dentry = dentry,
> -		.fh = fh,
> -		.fattr = fattr,
> -		.authflavor = authflavor,
> -	};
> +	struct nfs_fs_context *ctx;
> +	struct fs_context *fc;
>  	struct vfsmount *mnt;
> -	char *page = (char *) __get_free_page(GFP_USER);
> -	char *devname;
> +	char *buffer, *p;
> +	int ret;
> +
> +	/* Open a new filesystem context, transferring parameters from the
> +	 * parent superblock, including the network namespace.
> +	 */
> +	fc = vfs_new_fs_context(&nfs_fs_type, dentry->d_sb, 0,
> +				FS_CONTEXT_FOR_SUBMOUNT);
> +	if (IS_ERR(fc))
> +		return ERR_CAST(fc);
> +	ctx = container_of(fc, struct nfs_fs_context, fc);
> +
> +	mnt = ERR_PTR(-ENOMEM);
> +	buffer = kmalloc(4096, GFP_USER);
> +	if (!buffer)
> +		goto err_fc;
> +
> +	ctx->mount_type		= NFS_MOUNT_CROSS_DEV;
> +	ctx->selected_flavor	= authflavor;
> +	ctx->clone_data.sb	= dentry->d_sb;
> +	ctx->clone_data.dentry	= dentry;
> +	ctx->clone_data.fattr	= fattr;
> +	ctx->clone_data.cloned	= true;
> +
> +	nfs_copy_fh(ctx->mntfh, fh);
> +
> +	p = nfs_devname(dentry, buffer, 4096);
> +	if (IS_ERR(p)) {
> +		errorf("NFS: Couldn't determine submount pathname");
> +		mnt = ERR_CAST(p);
> +		goto err_buffer;
> +	}
> +
> +	ctx->fc.device = kmemdup(p, buffer + 4096 - p, GFP_KERNEL);
> +	kfree(buffer);
> +	if (!ctx->fc.device)
> +		goto err_fc;
>  
> -	if (page == NULL)
> -		return ERR_PTR(-ENOMEM);
> +	ret = vfs_get_tree(fc);
> +	if (ret < 0)
> +		goto err_fc;
>  
> -	devname = nfs_devname(dentry, page, PAGE_SIZE);
> -	if (IS_ERR(devname))
> -		mnt = ERR_CAST(devname);
> -	else
> -		mnt = nfs_do_clone_mount(NFS_SB(dentry->d_sb), devname, &mountdata);
> +	mnt = vfs_kern_mount_fc(&ctx->fc);
> +	goto err_fc;
>  
> -	free_page((unsigned long)page);
> +err_buffer:
> +	kfree(buffer);
> +err_fc:
> +	put_fs_context(fc);
>  	return mnt;
>  }
>  EXPORT_SYMBOL_GPL(nfs_do_submount);
> diff --git a/fs/nfs/nfs3_fs.h b/fs/nfs/nfs3_fs.h
> index e134d6548ab7..2094bb1f022e 100644
> --- a/fs/nfs/nfs3_fs.h
> +++ b/fs/nfs/nfs3_fs.h
> @@ -26,7 +26,7 @@ static inline int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
>  #endif /* CONFIG_NFS_V3_ACL */
>  
>  /* nfs3client.c */
> -struct nfs_server *nfs3_create_server(struct nfs_mount_info *, struct nfs_subversion *);
> +struct nfs_server *nfs3_create_server(struct nfs_fs_context *);
>  struct nfs_server *nfs3_clone_server(struct nfs_server *, struct nfs_fh *,
>  				     struct nfs_fattr *, rpc_authflavor_t);
>  
> diff --git a/fs/nfs/nfs3client.c b/fs/nfs/nfs3client.c
> index 7879f2a0fcfd..3b99d4985c4c 100644
> --- a/fs/nfs/nfs3client.c
> +++ b/fs/nfs/nfs3client.c
> @@ -45,10 +45,10 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server)
>  }
>  #endif
>  
> -struct nfs_server *nfs3_create_server(struct nfs_mount_info *mount_info,
> -				      struct nfs_subversion *nfs_mod)
> +struct nfs_server *nfs3_create_server(struct nfs_fs_context *ctx)
>  {
> -	struct nfs_server *server = nfs_create_server(mount_info, nfs_mod);
> +	struct nfs_server *server = nfs_create_server(ctx);
> +
>  	/* Create a client RPC handle for the NFS v3 ACL management interface */
>  	if (!IS_ERR(server))
>  		nfs_init_server_aclclient(server);
> diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
> index 0c07b567118d..96e315916a34 100644
> --- a/fs/nfs/nfs3proc.c
> +++ b/fs/nfs/nfs3proc.c
> @@ -975,7 +975,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
>  	.nlmclnt_ops	= &nlmclnt_fl_close_lock_ops,
>  	.getroot	= nfs3_proc_get_root,
>  	.submount	= nfs_submount,
> -	.try_mount	= nfs_try_mount,
> +	.try_get_tree	= nfs_try_get_tree,
>  	.getattr	= nfs3_proc_getattr,
>  	.setattr	= nfs3_proc_setattr,
>  	.lookup		= nfs3_proc_lookup,
> diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
> index af285cc27ccf..c5882668dc8a 100644
> --- a/fs/nfs/nfs4_fs.h
> +++ b/fs/nfs/nfs4_fs.h
> @@ -467,7 +467,6 @@ extern const nfs4_stateid zero_stateid;
>  /* nfs4super.c */
>  struct nfs_mount_info;
>  extern struct nfs_subversion nfs_v4;
> -struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *, struct nfs_subversion *);
>  extern bool nfs4_disable_idmapping;
>  extern unsigned short max_session_slots;
>  extern unsigned short max_session_cb_slots;
> @@ -477,6 +476,9 @@ extern bool recover_lost_locks;
>  #define NFS4_CLIENT_ID_UNIQ_LEN		(64)
>  extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN];
>  
> +extern int nfs4_try_get_tree(struct nfs_fs_context *);
> +extern int nfs4_get_tree(struct nfs_fs_context *);
> +
>  /* nfs4sysctl.c */
>  #ifdef CONFIG_SYSCTL
>  int nfs4_register_sysctl(void);
> diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
> index 0b5e1ecfa8f8..431eae161383 100644
> --- a/fs/nfs/nfs4client.c
> +++ b/fs/nfs/nfs4client.c
> @@ -1032,14 +1032,14 @@ static int nfs4_init_server(struct nfs_server *server,
>  
>  	/* Get a client record */
>  	error = nfs4_set_client(server,
> -			ctx->nfs_server.hostname,
> -			(const struct sockaddr *)&ctx->nfs_server.address,
> -			ctx->nfs_server.addrlen,
> -			ctx->client_address,
> -			ctx->nfs_server.protocol,
> -			&timeparms,
> -			ctx->minorversion,
> -			ctx->net);
> +				ctx->nfs_server.hostname,
> +				&ctx->nfs_server.address,
> +				ctx->nfs_server.addrlen,
> +				ctx->client_address,
> +				ctx->nfs_server.protocol,
> +				&timeparms,
> +				ctx->minorversion,
> +				ctx->fc.net_ns);
>  	if (error < 0)
>  		return error;
>  
> @@ -1062,10 +1062,7 @@ static int nfs4_init_server(struct nfs_server *server,
>   * Create a version 4 volume record
>   * - keyed on server and FSID
>   */
> -/*struct nfs_server *nfs4_create_server(const struct nfs_fs_context *data,
> -				      struct nfs_fh *mntfh)*/
> -struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
> -				      struct nfs_subversion *nfs_mod)
> +struct nfs_server *nfs4_create_server(struct nfs_fs_context *ctx)
>  {
>  	struct nfs_server *server;
>  	bool auth_probe;
> @@ -1075,14 +1072,14 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
>  	if (!server)
>  		return ERR_PTR(-ENOMEM);
>  
> -	auth_probe = mount_info->ctx->auth_info.flavor_len < 1;
> +	auth_probe = ctx->auth_info.flavor_len < 1;
>  
>  	/* set up the general RPC client */
> -	error = nfs4_init_server(server, mount_info->ctx);
> +	error = nfs4_init_server(server, ctx);
>  	if (error < 0)
>  		goto error;
>  
> -	error = nfs4_server_common_setup(server, mount_info->mntfh, auth_probe);
> +	error = nfs4_server_common_setup(server, ctx->mntfh, auth_probe);
>  	if (error < 0)
>  		goto error;
>  
> @@ -1096,8 +1093,7 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
>  /*
>   * Create an NFS4 referral server record
>   */
> -struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
> -					       struct nfs_fh *mntfh)
> +struct nfs_server *nfs4_create_referral_server(struct nfs_fs_context *ctx)
>  {
>  	struct nfs_client *parent_client;
>  	struct nfs_server *server, *parent_server;
> @@ -1108,7 +1104,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
>  	if (!server)
>  		return ERR_PTR(-ENOMEM);
>  
> -	parent_server = NFS_SB(data->sb);
> +	parent_server = NFS_SB(ctx->clone_data.sb);
>  	parent_client = parent_server->nfs_client;
>  
>  	/* Initialise the client representation from the parent server */
> @@ -1116,9 +1112,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
>  
>  	/* Get a client representation.
>  	 * Note: NFSv4 always uses TCP, */
> -	error = nfs4_set_client(server, data->hostname,
> -				data->addr,
> -				data->addrlen,
> +	error = nfs4_set_client(server,
> +				ctx->nfs_server.hostname,
> +				&ctx->nfs_server.address,
> +				ctx->nfs_server.addrlen,
>  				parent_client->cl_ipaddr,
>  				rpc_protocol(parent_server->client),
>  				parent_server->client->cl_timeout,
> @@ -1127,13 +1124,14 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
>  	if (error < 0)
>  		goto error;
>  
> -	error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
> +	error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout,
> +					  ctx->selected_flavor);
>  	if (error < 0)
>  		goto error;
>  
>  	auth_probe = parent_server->auth_info.flavor_len < 1;
>  
> -	error = nfs4_server_common_setup(server, mntfh, auth_probe);
> +	error = nfs4_server_common_setup(server, ctx->mntfh, auth_probe);
>  	if (error < 0)
>  		goto error;
>  
> diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
> index 7d531da1bae3..07466ae971cc 100644
> --- a/fs/nfs/nfs4namespace.c
> +++ b/fs/nfs/nfs4namespace.c
> @@ -7,6 +7,7 @@
>   * NFSv4 namespace
>   */
>  
> +#include <linux/module.h>
>  #include <linux/dcache.h>
>  #include <linux/mount.h>
>  #include <linux/namei.h>
> @@ -20,37 +21,64 @@
>  #include <linux/inet.h>
>  #include "internal.h"
>  #include "nfs4_fs.h"
> +#include "nfs.h"
>  #include "dns_resolve.h"
>  
>  #define NFSDBG_FACILITY		NFSDBG_VFS
>  
>  /*
> + * Work out the length that an NFSv4 path would render to as a standard posix
> + * path, with a leading slash but no terminating slash.
> + */
> +static ssize_t nfs4_pathname_len(const struct nfs4_pathname *pathname)
> +{
> +	ssize_t len;
> +	int i;
> +
> +	for (i = 0; i < pathname->ncomponents; i++) {
> +		const struct nfs4_string *component = &pathname->components[i];
> +
> +		if (component->len > NAME_MAX)
> +			goto too_long;
> +		len += 1 + component->len; /* Adding "/foo" */
> +		if (len > PATH_MAX)
> +			goto too_long;
> +	}
> +	return len;
> +
> +too_long:
> +	return -ENAMETOOLONG;
> +}
> +
> +/*
>   * Convert the NFSv4 pathname components into a standard posix path.
> - *
> - * Note that the resulting string will be placed at the end of the buffer
>   */
> -static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
> -					 char *buffer, ssize_t buflen)
> +static char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
> +				  unsigned short *_len)
>  {
> -	char *end = buffer + buflen;
> -	int n;
> +	ssize_t len;
> +	char *buf, *p;
> +	int i;
>  
> -	*--end = '\0';
> -	buflen--;
> -
> -	n = pathname->ncomponents;
> -	while (--n >= 0) {
> -		const struct nfs4_string *component = &pathname->components[n];
> -		buflen -= component->len + 1;
> -		if (buflen < 0)
> -			goto Elong;
> -		end -= component->len;
> -		memcpy(end, component->data, component->len);
> -		*--end = '/';
> +	len = nfs4_pathname_len(pathname);
> +	if (len < 0)
> +		return ERR_PTR(len);
> +	*_len = len;
> +
> +	p = buf = kmalloc(len + 1, GFP_KERNEL);
> +	if (!buf)
> +		return ERR_PTR(-ENOMEM);
> +
> +	for (i = 0; i < pathname->ncomponents; i++) {
> +		const struct nfs4_string *component = &pathname->components[i];
> +
> +		*p++ = '/';
> +		memcpy(p, component->data, component->len);
> +		p += component->len;
>  	}
> -	return end;
> -Elong:
> -	return ERR_PTR(-ENAMETOOLONG);
> +
> +	*p = 0;
> +	return buf;
>  }
>  
>  /*
> @@ -99,21 +127,25 @@ static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
>   */
>  static int nfs4_validate_fspath(struct dentry *dentry,
>  				const struct nfs4_fs_locations *locations,
> -				char *page, char *page2)
> +				struct nfs_fs_context *ctx)
>  {
> -	const char *path, *fs_path;
> +	const char *path;
> +	char *buf;
> +	int n;
>  
> -	path = nfs4_path(dentry, page, PAGE_SIZE);
> -	if (IS_ERR(path))
> +	buf = kmalloc(4096, GFP_KERNEL);
> +	path = nfs4_path(dentry, buf, 4096);
> +	if (IS_ERR(path)) {
> +		kfree(buf);
>  		return PTR_ERR(path);
> +	}
>  
> -	fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
> -	if (IS_ERR(fs_path))
> -		return PTR_ERR(fs_path);
> -
> -	if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
> +	n = strncmp(path, ctx->nfs_server.export_path,
> +		    ctx->nfs_server.export_path_len);
> +	kfree(buf);
> +	if (n != 0) {
>  		dprintk("%s: path %s does not begin with fsroot %s\n",
> -			__func__, path, fs_path);
> +			__func__, path, ctx->nfs_server.export_path);
>  		return -ENOENT;
>  	}
>  
> @@ -234,56 +266,66 @@ nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode,
>  	return new;
>  }
>  
> -static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
> -				     char *page, char *page2,
> +static struct vfsmount *try_location(struct dentry *dentry,
> +				     struct nfs_fs_context *ctx,
>  				     const struct nfs4_fs_location *location)
>  {
> -	const size_t addr_bufsize = sizeof(struct sockaddr_storage);
> -	struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client);
> +	struct net *net = rpc_net_ns(NFS_SB(dentry->d_sb)->client);
>  	struct vfsmount *mnt = ERR_PTR(-ENOENT);
> -	char *mnt_path;
> -	unsigned int maxbuflen;
> -	unsigned int s;
> +	unsigned int len, s;
> +	char *p;
>  
> -	mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
> -	if (IS_ERR(mnt_path))
> -		return ERR_CAST(mnt_path);
> -	mountdata->mnt_path = mnt_path;
> -	maxbuflen = mnt_path - 1 - page2;
> +	/* Allocate a buffer big enough to hold any of the hostnames plus a
> +	 * terminating char and also a buffer big enough to hold the hostname
> +	 * plus a colon plus the path.
> +	 */
> +	len = 0;
> +	for (s = 0; s < location->nservers; s++) {
> +		const struct nfs4_string *buf = &location->servers[s];
> +		if (buf->len > len)
> +			len = buf->len;
> +	}
>  
> -	mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL);
> -	if (mountdata->addr == NULL)
> +	ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL);
> +	if (!ctx->nfs_server.hostname)
>  		return ERR_PTR(-ENOMEM);
>  
> +	ctx->fc.device = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1,
> +				 GFP_KERNEL);
> +	if (!ctx->fc.device)
> +		return ERR_PTR(-ENOMEM);
> +	
>  	for (s = 0; s < location->nservers; s++) {
>  		const struct nfs4_string *buf = &location->servers[s];
>  
> -		if (buf->len <= 0 || buf->len >= maxbuflen)
> -			continue;
> -
>  		if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
>  			continue;
>  
> -		mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
> -				mountdata->addr, addr_bufsize, net);
> -		if (mountdata->addrlen == 0)
> +		ctx->nfs_server.addrlen =
> +			nfs_parse_server_name(buf->data, buf->len,
> +					      &ctx->nfs_server.address,
> +					      sizeof(ctx->nfs_server._address),
> +					      net);
> +		if (ctx->nfs_server.addrlen == 0)
>  			continue;
>  
> -		rpc_set_port(mountdata->addr, NFS_PORT);
> +		rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
>  
> -		memcpy(page2, buf->data, buf->len);
> -		page2[buf->len] = '\0';
> -		mountdata->hostname = page2;
> +		memcpy(ctx->nfs_server.hostname, buf->data, buf->len);
> +		ctx->nfs_server.hostname[buf->len] = '\0';
>  
> -		snprintf(page, PAGE_SIZE, "%s:%s",
> -				mountdata->hostname,
> -				mountdata->mnt_path);
> +		p = ctx->fc.device;
> +		memcpy(p, buf->data, buf->len);
> +		p += buf->len;
> +		*p++ = ':';
> +		memcpy(p, ctx->nfs_server.export_path, ctx->nfs_server.export_path_len);
> +		p += ctx->nfs_server.export_path_len;
> +		*p = 0;
>  
> -		mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata);
> +		mnt = vfs_kern_mount_fc(&ctx->fc);
>  		if (!IS_ERR(mnt))
>  			break;
>  	}
> -	kfree(mountdata->addr);
>  	return mnt;
>  }
>  
> @@ -296,33 +338,43 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
>  static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
>  					    const struct nfs4_fs_locations *locations)
>  {
> -	struct vfsmount *mnt = ERR_PTR(-ENOENT);
> -	struct nfs_clone_mount mountdata = {
> -		.sb = dentry->d_sb,
> -		.dentry = dentry,
> -		.authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor,
> -	};
> -	char *page = NULL, *page2 = NULL;
> +	struct nfs_fs_context *ctx;
> +	struct fs_context *fc;
> +	struct vfsmount *mnt;
> +	char *export_path;
>  	int loc, error;
>  
>  	if (locations == NULL || locations->nlocations <= 0)
>  		goto out;
>  
> +	fc = vfs_new_fs_context(&nfs4_fs_type, dentry->d_sb, 0,
> +			       FS_CONTEXT_FOR_SUBMOUNT);
> +	if (IS_ERR(fc)) {
> +		mnt = ERR_CAST(fc);
> +		goto out;
> +	}
> +	ctx = container_of(fc, struct nfs_fs_context, fc);
> +
>  	dprintk("%s: referral at %pd2\n", __func__, dentry);
>  
> -	page = (char *) __get_free_page(GFP_USER);
> -	if (!page)
> -		goto out;
> +	ctx->mount_type		= NFS4_MOUNT_REFERRAL;
> +	ctx->clone_data.sb	= dentry->d_sb;
> +	ctx->clone_data.dentry	= dentry;
> +	ctx->clone_data.cloned	= true;
>  
> -	page2 = (char *) __get_free_page(GFP_USER);
> -	if (!page2)
> -		goto out;
> +	export_path = nfs4_pathname_string(&locations->fs_path,
> +					   &ctx->nfs_server.export_path_len);
> +	if (IS_ERR(export_path)) {
> +		mnt = ERR_CAST(export_path);
> +		goto out_sc;
> +	}
> +	ctx->nfs_server.export_path = export_path;
>  
>  	/* Ensure fs path is a prefix of current dentry path */
> -	error = nfs4_validate_fspath(dentry, locations, page, page2);
> +	error = nfs4_validate_fspath(dentry, locations, ctx);
>  	if (error < 0) {
>  		mnt = ERR_PTR(error);
> -		goto out;
> +		goto out_sc;
>  	}
>  
>  	for (loc = 0; loc < locations->nlocations; loc++) {
> @@ -332,14 +384,14 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
>  		    location->rootpath.ncomponents == 0)
>  			continue;
>  
> -		mnt = try_location(&mountdata, page, page2, location);
> +		mnt = try_location(ctx->clone_data.dentry, ctx, location);
>  		if (!IS_ERR(mnt))
>  			break;
>  	}
>  
> +out_sc:
> +	put_fs_context(fc);
>  out:
> -	free_page((unsigned long) page);
> -	free_page((unsigned long) page2);
>  	return mnt;
>  }
>  
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index c08c46a3b8cd..ca792f799941 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -9307,8 +9307,9 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
>  	.file_inode_ops	= &nfs4_file_inode_operations,
>  	.file_ops	= &nfs4_file_operations,
>  	.getroot	= nfs4_proc_get_root,
> +	.get_tree	= nfs4_get_tree,
>  	.submount	= nfs4_submount,
> -	.try_mount	= nfs4_try_mount,
> +	.try_get_tree	= nfs4_try_get_tree,
>  	.getattr	= nfs4_proc_getattr,
>  	.setattr	= nfs4_proc_setattr,
>  	.lookup		= nfs4_proc_lookup,
> diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
> index 70111f222a25..9f2eacfee42c 100644
> --- a/fs/nfs/nfs4super.c
> +++ b/fs/nfs/nfs4super.c
> @@ -3,6 +3,7 @@
>   */
>  #include <linux/init.h>
>  #include <linux/module.h>
> +#include <linux/mount.h>
>  #include <linux/nfs4_mount.h>
>  #include <linux/nfs_fs.h>
>  #include "delegation.h"
> @@ -17,36 +18,6 @@
>  
>  static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc);
>  static void nfs4_evict_inode(struct inode *inode);
> -static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type,
> -	int flags, const char *dev_name, void *raw_data);
> -static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
> -	int flags, const char *dev_name, void *raw_data);
> -static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
> -	int flags, const char *dev_name, void *raw_data);
> -
> -static struct file_system_type nfs4_remote_fs_type = {
> -	.owner		= THIS_MODULE,
> -	.name		= "nfs4",
> -	.mount		= nfs4_remote_mount,
> -	.kill_sb	= nfs_kill_super,
> -	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
> -};
> -
> -static struct file_system_type nfs4_remote_referral_fs_type = {
> -	.owner		= THIS_MODULE,
> -	.name		= "nfs4",
> -	.mount		= nfs4_remote_referral_mount,
> -	.kill_sb	= nfs_kill_super,
> -	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
> -};
> -
> -struct file_system_type nfs4_referral_fs_type = {
> -	.owner		= THIS_MODULE,
> -	.name		= "nfs4",
> -	.mount		= nfs4_referral_mount,
> -	.kill_sb	= nfs_kill_super,
> -	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
> -};
>  
>  static const struct super_operations nfs4_sops = {
>  	.alloc_inode	= nfs_alloc_inode,
> @@ -60,16 +31,16 @@ static const struct super_operations nfs4_sops = {
>  	.show_devname	= nfs_show_devname,
>  	.show_path	= nfs_show_path,
>  	.show_stats	= nfs_show_stats,
> -	.remount_fs	= nfs_remount,
> +	.remount_fs_fc	= nfs_remount,
>  };
>  
>  struct nfs_subversion nfs_v4 = {
> -	.owner = THIS_MODULE,
> -	.nfs_fs   = &nfs4_fs_type,
> -	.rpc_vers = &nfs_version4,
> -	.rpc_ops  = &nfs_v4_clientops,
> -	.sops     = &nfs4_sops,
> -	.xattr    = nfs4_xattr_handlers,
> +	.owner		= THIS_MODULE,
> +	.nfs_fs		= &nfs4_fs_type,
> +	.rpc_vers	= &nfs_version4,
> +	.rpc_ops	= &nfs_v4_clientops,
> +	.sops		= &nfs4_sops,
> +	.xattr		= nfs4_xattr_handlers,
>  };
>  
>  static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc)
> @@ -103,47 +74,63 @@ static void nfs4_evict_inode(struct inode *inode)
>  /*
>   * Get the superblock for the NFS4 root partition
>   */
> -static struct dentry *
> -nfs4_remote_mount(struct file_system_type *fs_type, int flags,
> -		  const char *dev_name, void *info)
> +static int nfs4_get_remote_tree(struct nfs_fs_context *ctx)
>  {
> -	struct nfs_mount_info *mount_info = info;
>  	struct nfs_server *server;
> -	struct dentry *mntroot = ERR_PTR(-ENOMEM);
>  
> -	mount_info->set_security = nfs_set_sb_security;
> +	ctx->set_security = nfs_set_sb_security;
>  
>  	/* Get a volume representation */
> -	server = nfs4_create_server(mount_info, &nfs_v4);
> -	if (IS_ERR(server)) {
> -		mntroot = ERR_CAST(server);
> -		goto out;
> -	}
> -
> -	mntroot = nfs_fs_mount_common(server, flags, dev_name, mount_info, &nfs_v4);
> +	server = nfs4_create_server(ctx);
> +	if (IS_ERR(server))
> +		return PTR_ERR(server);
>  
> -out:
> -	return mntroot;
> +	return nfs_get_tree_common(server, ctx);
>  }
>  
> -static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
> -		int flags, void *data, const char *hostname)
> +/*
> + * Create a mount for the root of the server.  We copy the mount context we
> + * have for the parameters and set its hostname, path and type.
> + */
> +static struct vfsmount *nfs_do_root_mount(struct nfs_fs_context *ctx,
> +					  const char *hostname,
> +					  enum nfs_mount_type type)
>  {
> +	struct nfs_fs_context *root_ctx;
> +	struct fs_context *root_fc;
>  	struct vfsmount *root_mnt;
>  	char *root_devname;
>  	size_t len;
> +	int ret;
> +
> +	root_fc = vfs_dup_fs_context(&ctx->fc);
> +	if (IS_ERR(root_fc))
> +		return ERR_CAST(root_fc);
> +	root_ctx = container_of(root_fc, struct nfs_fs_context, fc);
> +
> +	root_ctx->mount_type = type;
> +	root_ctx->nfs_server.export_path = (char *)nfs_slash;
>  
>  	len = strlen(hostname) + 5;
> +	root_mnt = ERR_PTR(-ENOMEM);
>  	root_devname = kmalloc(len, GFP_KERNEL);
>  	if (root_devname == NULL)
> -		return ERR_PTR(-ENOMEM);
> +		goto out_fc;
> +
>  	/* Does hostname needs to be enclosed in brackets? */
>  	if (strchr(hostname, ':'))
>  		snprintf(root_devname, len, "[%s]:/", hostname);
>  	else
>  		snprintf(root_devname, len, "%s:/", hostname);
> -	root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
> -	kfree(root_devname);
> +	root_ctx->fc.device = root_devname;
> +
> +	ret = vfs_get_tree(&root_ctx->fc);
> +	if (ret < 0)
> +		return ERR_PTR(ret);
> +
> +	root_mnt = vfs_kern_mount_fc(&root_ctx->fc);
> +out_fc:
> +	put_fs_context(root_fc);
>  	return root_mnt;
>  }
>  
> @@ -234,89 +221,98 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
>  	return dentry;
>  }
>  
> -struct dentry *nfs4_try_mount(int flags, const char *dev_name,
> -			      struct nfs_mount_info *mount_info,
> -			      struct nfs_subversion *nfs_mod)
> +int nfs4_try_get_tree(struct nfs_fs_context *ctx)
>  {
> -	char *export_path;
>  	struct vfsmount *root_mnt;
> -	struct dentry *res;
> -	struct nfs_fs_context *ctx = mount_info->ctx;
> +	struct dentry *root;
>  
> -	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
> +	dfprintk(MOUNT, "--> nfs4_try_get_tree()\n");
>  
> -	export_path = ctx->nfs_server.export_path;
> -	ctx->nfs_server.export_path = "/";
> -	root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
> -			ctx->nfs_server.hostname);
> -	ctx->nfs_server.export_path = export_path;
> -
> -	res = nfs_follow_remote_path(root_mnt, export_path);
> +	/* We create a mount for the server's root, walk to the requested
> +	 * location and then create another mount for that.
> +	 */
> +	root_mnt = nfs_do_root_mount(ctx, ctx->nfs_server.hostname,
> +				     NFS4_MOUNT_REMOTE);
> +	if (IS_ERR(root_mnt))
> +		return PTR_ERR(root_mnt);
> +
> +	root = nfs_follow_remote_path(root_mnt, ctx->nfs_server.export_path);
> +	if (IS_ERR(root)) {
> +		errorf("NFS4: Couldn't follow remote path");
> +		dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld [error]\n",
> +			 PTR_ERR(root));
> +		return PTR_ERR(root);
> +	}
>  
> -	dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n",
> -		 PTR_ERR_OR_ZERO(res),
> -		 IS_ERR(res) ? " [error]" : "");
> -	return res;
> +	ctx->fc.root = root;
> +	dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n");
> +	return 0;
>  }
>  
> -static struct dentry *
> -nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
> -			   const char *dev_name, void *raw_data)
> +static int nfs4_get_remote_referral_tree(struct nfs_fs_context *ctx)
>  {
> -	struct nfs_mount_info mount_info = {
> -		.fill_super = nfs_fill_super,
> -		.set_security = nfs_clone_sb_security,
> -		.cloned = raw_data,
> -	};
>  	struct nfs_server *server;
> -	struct dentry *mntroot = ERR_PTR(-ENOMEM);
>  
> -	dprintk("--> nfs4_referral_get_sb()\n");
> +	dprintk("--> nfs4_get_remote_referral_tree()\n");
>  
> -	mount_info.mntfh = nfs_alloc_fhandle();
> -	if (mount_info.cloned == NULL || mount_info.mntfh == NULL)
> -		goto out;
> +	ctx->set_security = nfs_clone_sb_security;
> +
> +	if (!ctx->clone_data.cloned)
> +		return -EINVAL;
>  
>  	/* create a new volume representation */
> -	server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh);
> -	if (IS_ERR(server)) {
> -		mntroot = ERR_CAST(server);
> -		goto out;
> -	}
> +	server = nfs4_create_referral_server(ctx);
> +	if (IS_ERR(server))
> +		return PTR_ERR(server);
>  
> -	mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, &nfs_v4);
> -out:
> -	nfs_free_fhandle(mount_info.mntfh);
> -	return mntroot;
> +	return nfs_get_tree_common(server, ctx);
>  }
>  
>  /*
>   * Create an NFS4 server record on referral traversal
>   */
> -static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
> -		int flags, const char *dev_name, void *raw_data)
> +static int nfs4_get_referral_tree(struct nfs_fs_context *ctx)
>  {
> -	struct nfs_clone_mount *data = raw_data;
> -	char *export_path;
>  	struct vfsmount *root_mnt;
> -	struct dentry *res;
> +	struct dentry *root;
>  
>  	dprintk("--> nfs4_referral_mount()\n");
>  
> -	export_path = data->mnt_path;
> -	data->mnt_path = "/";
> +	root_mnt = nfs_do_root_mount(ctx, ctx->nfs_server.hostname,
> +				     NFS4_MOUNT_REMOTE_REFERRAL);
>  
> -	root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
> -			flags, data, data->hostname);
> -	data->mnt_path = export_path;
> +	root = nfs_follow_remote_path(root_mnt, ctx->nfs_server.export_path);
> +	if (IS_ERR(root)) {
> +		errorf("NFS4: Couldn't follow remote path");
> +		dfprintk(MOUNT, "<-- nfs4_referral_mount() = %ld [error]\n",
> +			 PTR_ERR(root));
> +		return PTR_ERR(root);
> +	}
>  
> -	res = nfs_follow_remote_path(root_mnt, export_path);
> -	dprintk("<-- nfs4_referral_mount() = %d%s\n",
> -		PTR_ERR_OR_ZERO(res),
> -		IS_ERR(res) ? " [error]" : "");
> -	return res;
> +	ctx->fc.root = root;
> +	dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n");
> +	return 0;
>  }
>  
> +/*
> + * Handle special NFS4 mount types.
> + */
> +int nfs4_get_tree(struct nfs_fs_context *ctx)
> +{
> +	switch (ctx->mount_type) {
> +	case NFS4_MOUNT_REMOTE:
> +		return nfs4_get_remote_tree(ctx);
> +
> +	case NFS4_MOUNT_REFERRAL:
> +		return nfs4_get_referral_tree(ctx);
> +
> +	case NFS4_MOUNT_REMOTE_REFERRAL:
> +		return nfs4_get_remote_referral_tree(ctx);
> +
> +	default:
> +		return 1;
> +	}
> +}
>  
>  static int __init init_nfs_v4(void)
>  {
> diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
> index 9872cf676a50..cd22b82e7bb8 100644
> --- a/fs/nfs/proc.c
> +++ b/fs/nfs/proc.c
> @@ -705,7 +705,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
>  	.file_ops	= &nfs_file_operations,
>  	.getroot	= nfs_proc_get_root,
>  	.submount	= nfs_submount,
> -	.try_mount	= nfs_try_mount,
> +	.try_get_tree	= nfs_try_get_tree,
>  	.getattr	= nfs_proc_getattr,
>  	.setattr	= nfs_proc_setattr,
>  	.lookup		= nfs_proc_lookup,
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index c13f0ff42df9..3ef689c08f48 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -69,27 +69,6 @@
>  
>  #define NFSDBG_FACILITY		NFSDBG_VFS
>  
> -static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type,
> -		int flags, const char *dev_name, void *raw_data);
> -
> -struct file_system_type nfs_fs_type = {
> -	.owner		= THIS_MODULE,
> -	.name		= "nfs",
> -	.mount		= nfs_fs_mount,
> -	.kill_sb	= nfs_kill_super,
> -	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
> -};
> -MODULE_ALIAS_FS("nfs");
> -EXPORT_SYMBOL_GPL(nfs_fs_type);
> -
> -struct file_system_type nfs_xdev_fs_type = {
> -	.owner		= THIS_MODULE,
> -	.name		= "nfs",
> -	.mount		= nfs_xdev_mount,
> -	.kill_sb	= nfs_kill_super,
> -	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
> -};
> -
>  const struct super_operations nfs_sops = {
>  	.alloc_inode	= nfs_alloc_inode,
>  	.destroy_inode	= nfs_destroy_inode,
> @@ -102,22 +81,11 @@ const struct super_operations nfs_sops = {
>  	.show_devname	= nfs_show_devname,
>  	.show_path	= nfs_show_path,
>  	.show_stats	= nfs_show_stats,
> -	.remount_fs	= nfs_remount,
> +	.remount_fs_fc	= nfs_remount,
>  };
>  EXPORT_SYMBOL_GPL(nfs_sops);
>  
>  #if IS_ENABLED(CONFIG_NFS_V4)
> -struct file_system_type nfs4_fs_type = {
> -	.owner		= THIS_MODULE,
> -	.name		= "nfs4",
> -	.mount		= nfs_fs_mount,
> -	.kill_sb	= nfs_kill_super,
> -	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
> -};
> -MODULE_ALIAS_FS("nfs4");
> -MODULE_ALIAS("nfs4");
> -EXPORT_SYMBOL_GPL(nfs4_fs_type);
> -
>  static int __init register_nfs4_fs(void)
>  {
>  	return register_filesystem(&nfs4_fs_type);
> @@ -710,11 +678,11 @@ bool nfs_auth_info_match(const struct nfs_auth_info *auth_info,
>  EXPORT_SYMBOL_GPL(nfs_auth_info_match);
>  
>  /*
> - * Ensure that a specified authtype in cfg->auth_info is supported by
> - * the server. Returns 0 and sets cfg->selected_flavor if it's ok, and
> + * Ensure that a specified authtype in ctx->auth_info is supported by
> + * the server. Returns 0 and sets ctx->selected_flavor if it's ok, and
>   * -EACCES if not.
>   */
> -static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
> +static int nfs_verify_authflavors(struct nfs_fs_context *ctx,
>  			rpc_authflavor_t *server_authlist, unsigned int count)
>  {
>  	rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
> @@ -732,7 +700,7 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
>  	for (i = 0; i < count; i++) {
>  		flavor = server_authlist[i];
>  
> -		if (nfs_auth_info_match(&cfg->auth_info, flavor))
> +		if (nfs_auth_info_match(&ctx->auth_info, flavor))
>  			goto out;
>  
>  		if (flavor == RPC_AUTH_NULL)
> @@ -749,8 +717,8 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
>  	return -EACCES;
>  
>  out:
> -	cfg->selected_flavor = flavor;
> -	dfprintk(MOUNT, "NFS: using auth flavor %u\n", cfg->selected_flavor);
> +	ctx->selected_flavor = flavor;
> +	dfprintk(MOUNT, "NFS: using auth flavor %u\n", ctx->selected_flavor);
>  	return 0;
>  }
>  
> @@ -758,50 +726,50 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
>   * Use the remote server's MOUNT service to request the NFS file handle
>   * corresponding to the provided path.
>   */
> -static int nfs_request_mount(struct nfs_fs_context *cfg,
> +static int nfs_request_mount(struct nfs_fs_context *ctx,
>  			     struct nfs_fh *root_fh,
>  			     rpc_authflavor_t *server_authlist,
>  			     unsigned int *server_authlist_len)
>  {
>  	struct nfs_mount_request request = {
>  		.sap		= (struct sockaddr *)
> -						&cfg->mount_server.address,
> -		.dirpath	= cfg->nfs_server.export_path,
> -		.protocol	= cfg->mount_server.protocol,
> +						&ctx->mount_server.address,
> +		.dirpath	= ctx->nfs_server.export_path,
> +		.protocol	= ctx->mount_server.protocol,
>  		.fh		= root_fh,
> -		.noresvport	= cfg->flags & NFS_MOUNT_NORESVPORT,
> +		.noresvport	= ctx->flags & NFS_MOUNT_NORESVPORT,
>  		.auth_flav_len	= server_authlist_len,
>  		.auth_flavs	= server_authlist,
> -		.net		= cfg->net,
> +		.net		= ctx->fc.net_ns,
>  	};
>  	int status;
>  
> -	if (cfg->mount_server.version == 0) {
> -		switch (cfg->version) {
> +	if (ctx->mount_server.version == 0) {
> +		switch (ctx->version) {
>  			default:
> -				cfg->mount_server.version = NFS_MNT3_VERSION;
> +				ctx->mount_server.version = NFS_MNT3_VERSION;
>  				break;
>  			case 2:
> -				cfg->mount_server.version = NFS_MNT_VERSION;
> +				ctx->mount_server.version = NFS_MNT_VERSION;
>  		}
>  	}
> -	request.version = cfg->mount_server.version;
> +	request.version = ctx->mount_server.version;
>  
> -	if (cfg->mount_server.hostname)
> -		request.hostname = cfg->mount_server.hostname;
> +	if (ctx->mount_server.hostname)
> +		request.hostname = ctx->mount_server.hostname;
>  	else
> -		request.hostname = cfg->nfs_server.hostname;
> +		request.hostname = ctx->nfs_server.hostname;
>  
>  	/*
>  	 * Construct the mount server's address.
>  	 */
> -	if (cfg->mount_server.address.sa_family == AF_UNSPEC) {
> -		memcpy(request.sap, &cfg->nfs_server.address,
> -		       cfg->nfs_server.addrlen);
> -		cfg->mount_server.addrlen = cfg->nfs_server.addrlen;
> +	if (ctx->mount_server.address.sa_family == AF_UNSPEC) {
> +		memcpy(request.sap, &ctx->nfs_server.address,
> +		       ctx->nfs_server.addrlen);
> +		ctx->mount_server.addrlen = ctx->nfs_server.addrlen;
>  	}
> -	request.salen = cfg->mount_server.addrlen;
> -	nfs_set_port(request.sap, &cfg->mount_server.port, 0);
> +	request.salen = ctx->mount_server.addrlen;
> +	nfs_set_port(request.sap, &ctx->mount_server.port, 0);
>  
>  	/*
>  	 * Now ask the mount server to map our export path
> @@ -817,20 +785,17 @@ static int nfs_request_mount(struct nfs_fs_context *cfg,
>  	return 0;
>  }
>  
> -static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info,
> -					struct nfs_subversion *nfs_mod)
> +static struct nfs_server *nfs_try_mount_request(struct nfs_fs_context *ctx)
>  {
>  	int status;
>  	unsigned int i;
>  	bool tried_auth_unix = false;
>  	bool auth_null_in_list = false;
>  	struct nfs_server *server = ERR_PTR(-EACCES);
> -	struct nfs_fs_context *ctx = mount_info->ctx;
>  	rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS];
>  	unsigned int authlist_len = ARRAY_SIZE(authlist);
>  
> -	status = nfs_request_mount(ctx, mount_info->mntfh, authlist,
> -					&authlist_len);
> +	status = nfs_request_mount(ctx, ctx->mntfh, authlist, &authlist_len);
>  	if (status)
>  		return ERR_PTR(status);
>  
> @@ -844,7 +809,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
>  			 ctx->selected_flavor);
>  		if (status)
>  			return ERR_PTR(status);
> -		return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
> +		return ctx->nfs_mod->rpc_ops->create_server(ctx);
>  	}
>  
>  	/*
> @@ -871,7 +836,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
>  		}
>  		dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor);
>  		ctx->selected_flavor = flavor;
> -		server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
> +		server = ctx->nfs_mod->rpc_ops->create_server(ctx);
>  		if (!IS_ERR(server))
>  			return server;
>  	}
> @@ -887,26 +852,27 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
>  	/* Last chance! Try AUTH_UNIX */
>  	dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX);
>  	ctx->selected_flavor = RPC_AUTH_UNIX;
> -	return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
> +	return ctx->nfs_mod->rpc_ops->create_server(ctx);
>  }
>  
> -struct dentry *nfs_try_mount(int flags, const char *dev_name,
> -			     struct nfs_mount_info *mount_info,
> -			     struct nfs_subversion *nfs_mod)
> +int nfs_try_get_tree(struct nfs_fs_context *ctx)
>  {
>  	struct nfs_server *server;
>  
> -	if (mount_info->ctx->need_mount)
> -		server = nfs_try_mount_request(mount_info, nfs_mod);
> +	if (ctx->need_mount)
> +		server = nfs_try_mount_request(ctx);
>  	else
> -		server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
> +		server = ctx->nfs_mod->rpc_ops->create_server(ctx);
>  
> -	if (IS_ERR(server))
> -		return ERR_CAST(server);
> +	if (IS_ERR(server)) {
> +		errorf("NFS: Couldn't create server");
> +		return PTR_ERR(server);
> +	}
>  
> -	return nfs_fs_mount_common(server, flags, dev_name, mount_info, nfs_mod);
> +	return nfs_get_tree_common(server, ctx);
>  }
> -EXPORT_SYMBOL_GPL(nfs_try_mount);
> +EXPORT_SYMBOL_GPL(nfs_try_get_tree);
> +
>  
>  #define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
>  		| NFS_MOUNT_SECURE \
> @@ -946,15 +912,11 @@ nfs_compare_remount_data(struct nfs_server *nfss,
>  	return 0;
>  }
>  
> -int
> -nfs_remount(struct super_block *sb, int *flags, char *raw_data)
> +int nfs_remount(struct super_block *sb, struct fs_context *fc)
>  {
> -	int error;
> +	struct nfs_fs_context *ctx =
> +		container_of(fc, struct nfs_fs_context, fc);
>  	struct nfs_server *nfss = sb->s_fs_info;
> -	struct nfs_fs_context *ctx;
> -	struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data;
> -	struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data;
> -	u32 nfsvers = nfss->nfs_client->rpc_ops->version;
>  
>  	sync_filesystem(sb);
>  
> @@ -964,39 +926,9 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
>  	 * ones were explicitly specified. Fall back to legacy behavior and
>  	 * just return success.
>  	 */
> -	if ((nfsvers == 4 && (!options4 || options4->version == 1)) ||
> -	    (nfsvers <= 3 && (!options || (options->version >= 1 &&
> -					   options->version <= 6))))
> +	if (ctx->skip_remount_option_check)
>  		return 0;
>  
> -	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> -	if (ctx == NULL)
> -		return -ENOMEM;
> -
> -	/* fill out struct with values from existing mount */
> -	ctx->flags = nfss->flags;
> -	ctx->rsize = nfss->rsize;
> -	ctx->wsize = nfss->wsize;
> -	ctx->retrans = nfss->client->cl_timeout->to_retries;
> -	ctx->selected_flavor = nfss->client->cl_auth->au_flavor;
> -	ctx->acregmin = nfss->acregmin / HZ;
> -	ctx->acregmax = nfss->acregmax / HZ;
> -	ctx->acdirmin = nfss->acdirmin / HZ;
> -	ctx->acdirmax = nfss->acdirmax / HZ;
> -	ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
> -	ctx->nfs_server.port = nfss->port;
> -	ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
> -	ctx->version = nfsvers;
> -	ctx->minorversion = nfss->nfs_client->cl_minorversion;
> -	ctx->net = current->nsproxy->net_ns;
> -	memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr,
> -		ctx->nfs_server.addrlen);
> -
> -	/* overwrite those values with any that were specified */
> -	error = -EINVAL;
> -	if (!nfs_parse_mount_options((char *)options, ctx))
> -		goto out;
> -
>  	/*
>  	 * noac is a special case. It implies -o sync, but that's not
>  	 * necessarily reflected in the mtab options. do_remount_sb
> @@ -1004,13 +936,10 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
>  	 * remount options, so we have to explicitly reset it.
>  	 */
>  	if (ctx->flags & NFS_MOUNT_NOAC)
> -		*flags |= SB_SYNCHRONOUS;
> +		ctx->fc.sb_flags |= SB_SYNCHRONOUS;
>  
>  	/* compare new mount options with old ones */
> -	error = nfs_compare_remount_data(nfss, ctx);
> -out:
> -	kfree(ctx);
> -	return error;
> +	return nfs_compare_remount_data(nfss, ctx);
>  }
>  EXPORT_SYMBOL_GPL(nfs_remount);
>  
> @@ -1037,9 +966,8 @@ static void nfs_initialise_sb(struct super_block *sb)
>  /*
>   * Finish setting up an NFS2/3 superblock
>   */
> -void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
> +static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx)
>  {
> -	struct nfs_fs_context *ctx = mount_info->ctx;
>  	struct nfs_server *server = NFS_SB(sb);
>  
>  	sb->s_blocksize_bits = 0;
> @@ -1059,15 +987,13 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
>  
>   	nfs_initialise_sb(sb);
>  }
> -EXPORT_SYMBOL_GPL(nfs_fill_super);
>  
>  /*
>   * Finish setting up a cloned NFS2/3/4 superblock
>   */
> -static void nfs_clone_super(struct super_block *sb,
> -			    struct nfs_mount_info *mount_info)
> +static void nfs_clone_super(struct super_block *sb, struct nfs_fs_context *ctx)
>  {
> -	const struct super_block *old_sb = mount_info->cloned->sb;
> +	const struct super_block *old_sb = ctx->clone_data.sb;
>  	struct nfs_server *server = NFS_SB(sb);
>  
>  	sb->s_blocksize_bits = old_sb->s_blocksize_bits;
> @@ -1087,13 +1013,14 @@ static void nfs_clone_super(struct super_block *sb,
>   	nfs_initialise_sb(sb);
>  }
>  
> -static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
> +static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b,
> +				     const struct nfs_fs_context *ctx)
>  {
>  	const struct nfs_server *a = s->s_fs_info;
>  	const struct rpc_clnt *clnt_a = a->client;
>  	const struct rpc_clnt *clnt_b = b->client;
>  
> -	if ((s->s_flags & NFS_SB_MASK) != (flags & NFS_SB_MASK))
> +	if ((s->s_flags & NFS_SB_MASK) != (ctx->fc.sb_flags & NFS_SB_MASK))
>  		goto Ebusy;
>  	if (a->nfs_client != b->nfs_client)
>  		goto Ebusy;
> @@ -1119,18 +1046,13 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n
>  	return 0;
>  }
>  
> -struct nfs_sb_mountdata {
> -	struct nfs_server *server;
> -	int mntflags;
> -};
> -
> -static int nfs_set_super(struct super_block *s, void *data)
> +static int nfs_set_super(struct super_block *s, struct fs_context *fc)
>  {
> -	struct nfs_sb_mountdata *sb_mntdata = data;
> -	struct nfs_server *server = sb_mntdata->server;
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
> +	struct nfs_server *server = ctx->server;
>  	int ret;
>  
> -	s->s_flags = sb_mntdata->mntflags;
> +	s->s_flags = ctx->fc.sb_flags;
>  	s->s_fs_info = server;
>  	s->s_d_op = server->nfs_client->rpc_ops->dentry_ops;
>  	ret = set_anon_super(s, server);
> @@ -1181,11 +1103,10 @@ static int nfs_compare_super_address(struct nfs_server *server1,
>  	return 1;
>  }
>  
> -static int nfs_compare_super(struct super_block *sb, void *data)
> +static int nfs_compare_super(struct super_block *sb, struct fs_context *fc)
>  {
> -	struct nfs_sb_mountdata *sb_mntdata = data;
> -	struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb);
> -	int mntflags = sb_mntdata->mntflags;
> +	struct nfs_fs_context *ctx = container_of(fc, struct nfs_fs_context, fc);
> +	struct nfs_server *server = ctx->server, *old = NFS_SB(sb);
>  
>  	if (!nfs_compare_super_address(old, server))
>  		return 0;
> @@ -1194,13 +1115,12 @@ static int nfs_compare_super(struct super_block *sb, void *data)
>  		return 0;
>  	if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
>  		return 0;
> -	return nfs_compare_mount_options(sb, server, mntflags);
> +	return nfs_compare_mount_options(sb, server, ctx);
>  }
>  
>  #ifdef CONFIG_NFS_FSCACHE
>  static void nfs_get_cache_cookie(struct super_block *sb,
> -				 struct nfs_fs_context *ctx,
> -				 struct nfs_clone_mount *cloned)
> +				 struct nfs_fs_context *ctx)
>  {
>  	struct nfs_server *nfss = NFS_SB(sb);
>  	char *uniq = NULL;
> @@ -1209,77 +1129,72 @@ static void nfs_get_cache_cookie(struct super_block *sb,
>  	nfss->fscache_key = NULL;
>  	nfss->fscache = NULL;
>  
> -	if (ctx) {
> +	if (!ctx)
> +		return;
> +
> +	if (ctx->clone_data.cloned) {
> +		struct nfs_server *mnt_s = NFS_SB(ctx->clone_data.sb);
> +		if (!(mnt_s->options & NFS_OPTION_FSCACHE))
> +			return;
> +		if (mnt_s->fscache_key) {
> +			uniq = mnt_s->fscache_key->key.uniquifier;
> +			ulen = mnt_s->fscache_key->key.uniq_len;
> +		}
> +	} else {
>  		if (!(ctx->options & NFS_OPTION_FSCACHE))
>  			return;
>  		if (ctx->fscache_uniq) {
>  			uniq = ctx->fscache_uniq;
>  			ulen = strlen(ctx->fscache_uniq);
>  		}
> -	} else if (cloned) {
> -		struct nfs_server *mnt_s = NFS_SB(cloned->sb);
> -		if (!(mnt_s->options & NFS_OPTION_FSCACHE))
> -			return;
> -		if (mnt_s->fscache_key) {
> -			uniq = mnt_s->fscache_key->key.uniquifier;
> -			ulen = mnt_s->fscache_key->key.uniq_len;
> -		};
> -	} else
>  		return;
> +	}
>  
>  	nfs_fscache_get_super_cookie(sb, uniq, ulen);
>  }
>  #else
>  static void nfs_get_cache_cookie(struct super_block *sb,
> -				 struct nfs_fs_context *parsed,
> -				 struct nfs_clone_mount *cloned)
> +				 struct nfs_fs_context *ctx)
>  {
>  }
>  #endif
>  
> -int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
> -			struct nfs_mount_info *mount_info)
> +int nfs_set_sb_security(struct super_block *sb, struct nfs_fs_context *ctx)
>  {
>  	int error;
>  	unsigned long kflags = 0, kflags_out = 0;
> -	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
> +
> +	if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL)
>  		kflags |= SECURITY_LSM_NATIVE_LABELS;
>  
> -	error = security_sb_set_mnt_opts(s, &mount_info->ctx->lsm_opts,
> -						kflags, &kflags_out);
> +	error = security_sb_set_mnt_opts(sb, ctx->fc.security,
> +					 kflags, &kflags_out);
>  	if (error)
>  		goto err;
>  
> -	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
> -		!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
> -		NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
> +	if (NFS_SB(sb)->caps & NFS_CAP_SECURITY_LABEL &&
> +	    !(kflags_out & SECURITY_LSM_NATIVE_LABELS))
> +		NFS_SB(sb)->caps &= ~NFS_CAP_SECURITY_LABEL;
>  err:
>  	return error;
>  }
>  EXPORT_SYMBOL_GPL(nfs_set_sb_security);
>  
> -int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
> -			  struct nfs_mount_info *mount_info)
> +int nfs_clone_sb_security(struct super_block *sb, struct nfs_fs_context *ctx)
>  {
>  	/* clone any lsm security options from the parent to the new sb */
> -	if (d_inode(mntroot)->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops)
> +	if (d_inode(ctx->fc.root)->i_op !=
> +	    NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops)
>  		return -ESTALE;
> -	return security_sb_clone_mnt_opts(mount_info->cloned->sb, s);
> +	return security_sb_clone_mnt_opts(ctx->clone_data.sb, sb);
>  }
>  EXPORT_SYMBOL_GPL(nfs_clone_sb_security);
>  
> -struct dentry *nfs_fs_mount_common(struct nfs_server *server,
> -				   int flags, const char *dev_name,
> -				   struct nfs_mount_info *mount_info,
> -				   struct nfs_subversion *nfs_mod)
> +int nfs_get_tree_common(struct nfs_server *server, struct nfs_fs_context *ctx)
>  {
>  	struct super_block *s;
>  	struct dentry *mntroot = ERR_PTR(-ENOMEM);
> -	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
> -	struct nfs_sb_mountdata sb_mntdata = {
> -		.mntflags = flags,
> -		.server = server,
> -	};
> +	int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super;
>  	int error;
>  
>  	if (server->flags & NFS_MOUNT_UNSHARED)
> @@ -1287,16 +1202,19 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
>  
>  	/* -o noac implies -o sync */
>  	if (server->flags & NFS_MOUNT_NOAC)
> -		sb_mntdata.mntflags |= SB_SYNCHRONOUS;
> +		ctx->fc.sb_flags |= SB_SYNCHRONOUS;
>  
> -	if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL)
> -		if (mount_info->cloned->sb->s_flags & SB_SYNCHRONOUS)
> -			sb_mntdata.mntflags |= SB_SYNCHRONOUS;
> +	if (ctx->clone_data.cloned && ctx->clone_data.sb != NULL)
> +		if (ctx->clone_data.sb->s_flags & SB_SYNCHRONOUS)
> +			ctx->fc.sb_flags |= SB_SYNCHRONOUS;
>  
>  	/* Get a superblock - note that we may end up sharing one that already exists */
> -	s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata);
> +	ctx->server = server;
> +	s = sget_fc(&ctx->fc, compare_super, nfs_set_super);
> +	ctx->server = NULL;
>  	if (IS_ERR(s)) {
> -		mntroot = ERR_CAST(s);
> +		error = PTR_ERR(s);
> +		errorf("NFS: Couldn't get superblock");
>  		goto out_err_nosb;
>  	}
>  
> @@ -1316,22 +1234,28 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
>  
>  	if (!s->s_root) {
>  		/* initial superblock/root creation */
> -		mount_info->fill_super(s, mount_info);
> -		nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned);
> +		if (ctx->clone_data.sb)
> +			nfs_clone_super(s, ctx);
> +		else
> +			nfs_fill_super(s, ctx);
> +		nfs_get_cache_cookie(s, ctx);
>  	}
>  
> -	mntroot = nfs_get_root(s, mount_info->mntfh, dev_name);
> -	if (IS_ERR(mntroot))
> +	error = nfs_get_root(s, ctx);
> +	if (error < 0) {
> +		errorf("NFS: Couldn't get root dentry");
>  		goto error_splat_super;
> +	}
>  
> -	error = mount_info->set_security(s, mntroot, mount_info);
> +	error = ctx->set_security(s, ctx);
>  	if (error)
>  		goto error_splat_root;
>  
>  	s->s_flags |= SB_ACTIVE;
> +	error = 0;
>  
>  out:
> -	return mntroot;
> +	return error;
>  
>  out_err_nosb:
>  	nfs_free_server(server);
> @@ -1339,53 +1263,11 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
>  
>  error_splat_root:
>  	dput(mntroot);
> -	mntroot = ERR_PTR(error);
>  error_splat_super:
>  	deactivate_locked_super(s);
>  	goto out;
>  }
> -EXPORT_SYMBOL_GPL(nfs_fs_mount_common);
> -
> -struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
> -	int flags, const char *dev_name, void *raw_data)
> -{
> -	struct nfs_mount_info mount_info = {
> -		.fill_super = nfs_fill_super,
> -		.set_security = nfs_set_sb_security,
> -	};
> -	struct dentry *mntroot = ERR_PTR(-ENOMEM);
> -	struct nfs_subversion *nfs_mod;
> -	int error;
> -
> -	mount_info.ctx = nfs_alloc_parsed_mount_data();
> -	mount_info.mntfh = nfs_alloc_fhandle();
> -	if (mount_info.ctx == NULL || mount_info.mntfh == NULL)
> -		goto out;
> -
> -	/* Validate the mount data */
> -	error = nfs_validate_mount_data(fs_type, raw_data, mount_info.ctx, mount_info.mntfh, dev_name);
> -	if (error == NFS_TEXT_DATA)
> -		error = nfs_validate_text_mount_data(raw_data, mount_info.ctx, dev_name);
> -	if (error < 0) {
> -		mntroot = ERR_PTR(error);
> -		goto out;
> -	}
> -
> -	nfs_mod = get_nfs_version(mount_info.ctx->version);
> -	if (IS_ERR(nfs_mod)) {
> -		mntroot = ERR_CAST(nfs_mod);
> -		goto out;
> -	}
> -
> -	mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info, nfs_mod);
> -
> -	put_nfs_version(nfs_mod);
> -out:
> -	nfs_free_parsed_mount_data(mount_info.ctx);
> -	nfs_free_fhandle(mount_info.mntfh);
> -	return mntroot;
> -}
> -EXPORT_SYMBOL_GPL(nfs_fs_mount);
> +EXPORT_SYMBOL_GPL(nfs_get_tree_common);
>  
>  /*
>   * Destroy an NFS2/3 superblock
> @@ -1404,41 +1286,6 @@ void nfs_kill_super(struct super_block *s)
>  }
>  EXPORT_SYMBOL_GPL(nfs_kill_super);
>  
> -/*
> - * Clone an NFS2/3/4 server record on xdev traversal (FSID-change)
> - */
> -static struct dentry *
> -nfs_xdev_mount(struct file_system_type *fs_type, int flags,
> -		const char *dev_name, void *raw_data)
> -{
> -	struct nfs_clone_mount *data = raw_data;
> -	struct nfs_mount_info mount_info = {
> -		.fill_super = nfs_clone_super,
> -		.set_security = nfs_clone_sb_security,
> -		.cloned = data,
> -	};
> -	struct nfs_server *server;
> -	struct dentry *mntroot = ERR_PTR(-ENOMEM);
> -	struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod;
> -
> -	dprintk("--> nfs_xdev_mount()\n");
> -
> -	mount_info.mntfh = mount_info.cloned->fh;
> -
> -	/* create a new volume representation */
> -	server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor);
> -
> -	if (IS_ERR(server))
> -		mntroot = ERR_CAST(server);
> -	else
> -		mntroot = nfs_fs_mount_common(server, flags,
> -				dev_name, &mount_info, nfs_mod);
> -
> -	dprintk("<-- nfs_xdev_mount() = %ld\n",
> -			IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L);
> -	return mntroot;
> -}
> -
>  #if IS_ENABLED(CONFIG_NFS_V4)
>  
>  /*
> diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
> index b28c83475ee8..71697103a887 100644
> --- a/include/linux/nfs_xdr.h
> +++ b/include/linux/nfs_xdr.h
> @@ -1542,6 +1542,7 @@ struct nfs_subversion;
>  struct nfs_mount_info;
>  struct nfs_client_initdata;
>  struct nfs_pageio_descriptor;
> +struct nfs_fs_context;
>  
>  /*
>   * RPC procedure vector for NFSv2/NFSv3 demuxing
> @@ -1556,10 +1557,10 @@ struct nfs_rpc_ops {
>  
>  	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
>  			    struct nfs_fsinfo *);
> +	int	(*get_tree)(struct nfs_fs_context *);
>  	struct vfsmount *(*submount) (struct nfs_server *, struct dentry *,
>  				      struct nfs_fh *, struct nfs_fattr *);
> -	struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *,
> -				     struct nfs_subversion *);
> +	int	(*try_get_tree) (struct nfs_fs_context *);
>  	int	(*getattr) (struct nfs_server *, struct nfs_fh *,
>  			    struct nfs_fattr *, struct nfs4_label *);
>  	int	(*setattr) (struct dentry *, struct nfs_fattr *,
> @@ -1620,7 +1621,7 @@ struct nfs_rpc_ops {
>  	struct nfs_client *(*init_client) (struct nfs_client *,
>  				const struct nfs_client_initdata *);
>  	void	(*free_client) (struct nfs_client *);
> -	struct nfs_server *(*create_server)(struct nfs_mount_info *, struct nfs_subversion *);
> +	struct nfs_server *(*create_server)(struct nfs_fs_context *);
>  	struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
>  					   struct nfs_fattr *, rpc_authflavor_t);
>  };
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags [ver #5]
  2017-06-15  9:39   ` Al Viro
@ 2017-06-16  9:06     ` Christoph Hellwig
  2017-06-16 14:53     ` David Howells
  1 sibling, 0 replies; 53+ messages in thread
From: Christoph Hellwig @ 2017-06-16  9:06 UTC (permalink / raw)
  To: Al Viro
  Cc: David Howells, mszeredi, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

FYI, this patch didn't seem to make it through to the list, probably
because it was too large.

It might be good to just introduce the internal flags field first,
populate it with the translated flags, then switch users over to
it, and last but not least remove the old flags field and the MS_*
values that were only used internally.

Also if would be good to sort this out in a separate series without
all the mount context stuff.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags [ver #5]
  2017-06-15  9:39   ` Al Viro
  2017-06-16  9:06     ` Christoph Hellwig
@ 2017-06-16 14:53     ` David Howells
  2017-06-16 15:49       ` Christoph Hellwig
  2017-06-16 15:54       ` David Howells
  1 sibling, 2 replies; 53+ messages in thread
From: David Howells @ 2017-06-16 14:53 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: dhowells, Al Viro, mszeredi, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

Christoph Hellwig <hch@infradead.org> wrote:

> It might be good to just introduce the internal flags field first,

Internal flags field?  Did you mean Al's suggested sb_readonly() wrapper?

David

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags [ver #5]
  2017-06-16 14:53     ` David Howells
@ 2017-06-16 15:49       ` Christoph Hellwig
  2017-06-16 15:54       ` David Howells
  1 sibling, 0 replies; 53+ messages in thread
From: Christoph Hellwig @ 2017-06-16 15:49 UTC (permalink / raw)
  To: David Howells
  Cc: Christoph Hellwig, Al Viro, mszeredi, linux-nfs, jlayton,
	linux-kernel, linux-security-module, linux-fsdevel

On Fri, Jun 16, 2017 at 03:53:30PM +0100, David Howells wrote:
> Christoph Hellwig <hch@infradead.org> wrote:
> 
> > It might be good to just introduce the internal flags field first,
> 
> Internal flags field?  Did you mean Al's suggested sb_readonly() wrapper?

(1) Add a new SB field that is like s_flags but for the new flags,
(2) switch users over to the new field
(3) remove s_flags

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags [ver #5]
  2017-06-16 14:53     ` David Howells
  2017-06-16 15:49       ` Christoph Hellwig
@ 2017-06-16 15:54       ` David Howells
  1 sibling, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-16 15:54 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: dhowells, Al Viro, mszeredi, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

Christoph Hellwig <hch@infradead.org> wrote:

> (1) Add a new SB field that is like s_flags but for the new flags,

Do we really need to do that?  The SB_* flags are conumeric with the MS_*
flags they replace.

David

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-14 20:53     ` Casey Schaufler
@ 2017-06-17  9:57       ` Theodore Ts'o
  2017-06-17 14:18       ` David Howells
  1 sibling, 0 replies; 53+ messages in thread
From: Theodore Ts'o @ 2017-06-17  9:57 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: David Howells, mszeredi, viro, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel

On Wed, Jun 14, 2017 at 01:53:09PM -0700, Casey Schaufler wrote:
> On 6/14/2017 1:42 PM, David Howells wrote:
> > Casey Schaufler <casey@schaufler-ca.com> wrote:
> >
> >> Could you namespace the fields of this structure?
> >> e.g. fs_cred, fs_security
> > Linus objects to that practice.
> 
> Sigh. Never mind. Thank you.

I don't know that this is a hard and fast rule.  Struct bio uses a
"bi_" prefix (e.g., bi_error, bi_opf, bi_iter, etc.).

I find it's really helpful when I'm doing a "git grep" over the whole
tree; "git grep bi_flags" returns a much more specific and focused
results than "git grep flags".   :-)

						- Ted

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-14 20:53     ` Casey Schaufler
  2017-06-17  9:57       ` Theodore Ts'o
@ 2017-06-17 14:18       ` David Howells
  2017-06-17 14:56         ` Jeff Layton
  2017-06-19  7:47         ` David Howells
  1 sibling, 2 replies; 53+ messages in thread
From: David Howells @ 2017-06-17 14:18 UTC (permalink / raw)
  To: Theodore Ts'o
  Cc: dhowells, Casey Schaufler, mszeredi, viro, linux-nfs, jlayton,
	linux-kernel, linux-security-module, linux-fsdevel

Theodore Ts'o <tytso@mit.edu> wrote:

> I don't know that this is a hard and fast rule.  Struct bio uses a
> "bi_" prefix (e.g., bi_error, bi_opf, bi_iter, etc.).

Linus told me to stop doing it.

David

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-17 14:18       ` David Howells
@ 2017-06-17 14:56         ` Jeff Layton
  2017-06-17 15:11           ` Randy Dunlap
  2017-06-19  7:47         ` David Howells
  1 sibling, 1 reply; 53+ messages in thread
From: Jeff Layton @ 2017-06-17 14:56 UTC (permalink / raw)
  To: David Howells, Theodore Ts'o
  Cc: Casey Schaufler, mszeredi, viro, linux-nfs, linux-kernel,
	linux-security-module, linux-fsdevel

On Sat, 2017-06-17 at 15:18 +0100, David Howells wrote:
> Theodore Ts'o <tytso@mit.edu> wrote:
> 
> > I don't know that this is a hard and fast rule.  Struct bio uses a
> > "bi_" prefix (e.g., bi_error, bi_opf, bi_iter, etc.).
> 
> Linus told me to stop doing it.
> 
> David


That's a pity... I tend to like little prefixes on fields too. Trying to
find all occurrences of a symbol called "flags" in cscope is a losing
exercise.

Do you have a reference to the discussion so I can understand the
rationale there?

Thanks,
-- 
Jeff Layton <jlayton@redhat.com>

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-17 14:56         ` Jeff Layton
@ 2017-06-17 15:11           ` Randy Dunlap
  0 siblings, 0 replies; 53+ messages in thread
From: Randy Dunlap @ 2017-06-17 15:11 UTC (permalink / raw)
  To: Jeff Layton, David Howells, Theodore Ts'o
  Cc: Casey Schaufler, mszeredi, viro, linux-nfs, linux-kernel,
	linux-security-module, linux-fsdevel

On 06/17/2017 07:56 AM, Jeff Layton wrote:
> On Sat, 2017-06-17 at 15:18 +0100, David Howells wrote:
>> Theodore Ts'o <tytso@mit.edu> wrote:
>>
>>> I don't know that this is a hard and fast rule.  Struct bio uses a
>>> "bi_" prefix (e.g., bi_error, bi_opf, bi_iter, etc.).
>>
>> Linus told me to stop doing it.
>>
>> David
> 
> 
> That's a pity... I tend to like little prefixes on fields too. Trying to
> find all occurrences of a symbol called "flags" in cscope is a losing
> exercise.
> 
> Do you have a reference to the discussion so I can understand the
> rationale there?

Ack. This doesn't seem helpful.

He also objected to drivers with file names that begin with the parent
directory name, but we still have hundreds of those (see clk/, extcon/,
gpio/, hid/, i2c/, leds/ [then I stopped looking]).


-- 
~Randy

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context [ver #5]
  2017-06-17 14:18       ` David Howells
  2017-06-17 14:56         ` Jeff Layton
@ 2017-06-19  7:47         ` David Howells
  1 sibling, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-19  7:47 UTC (permalink / raw)
  To: Jeff Layton
  Cc: dhowells, Theodore Ts'o, Casey Schaufler, mszeredi, viro,
	linux-nfs, linux-kernel, linux-security-module, linux-fsdevel

Jeff Layton <jlayton@redhat.com> wrote:

> Do you have a reference to the discussion so I can understand the
> rationale there?

I'm afraid not - it was around 15-20 years ago, I think.  I seem to remember
the rationale being something like "because it's a stupid idea".

David

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 27/27] kernfs, sysfs, cgroup: Support fs_context [ver #5]
  2017-06-14 15:19 ` [PATCH 27/27] kernfs, sysfs, cgroup: Support " David Howells
  2017-06-14 17:54   ` Tejun Heo
@ 2017-06-23 15:29   ` David Howells
  1 sibling, 0 replies; 53+ messages in thread
From: David Howells @ 2017-06-23 15:29 UTC (permalink / raw)
  To: Tejun Heo
  Cc: dhowells, mszeredi, viro, linux-nfs, jlayton, Greg Kroah-Hartman,
	linux-kernel, linux-fsdevel, linux-security-module, Li Zefan,
	Johannes Weiner, cgroups

Tejun Heo <tj@kernel.org> wrote:

> > Make kernfs support superblock creation/mount/remount with fs_context.
> > 
> > This requires that sysfs and cgroup, which are built on kernfs, be made to
> > support fs_context also.
> 
> Can you please include a brief rationale for doing this and include a
> pointer to the fuller description on what's going on?

The overview is that I'm trying to create a method by which mount creation can
be better parameterised.  This includes:

 (1) Improved option passing from userspace.  We're limited to what we can
     cram into a single page and we have to pass all the options in one go.

     I was impressed by Miklós's idea that he presented at LSF/MM for opening
     an fd to the filesystem driver, passing the parameters individually by
     write() and then performing a mount from that, so I could permit:

     (a) Allow each individual option to exceed PAGE_SIZE in size.

     (b) Allow options to contain binary data as no characters need to be
     	 reserved for parsing tokens (NUL terminators, commas).

     (c) Allow feedback on individual options.

     (d) Allow the filesystem to ask for information, such as passwords.

     (e) Allow selection of a subtree of the "device" to actually use
     	 (ie. combine a bind mount with the mount).

 (2) Loading a context from an already mounted filesystem, thereby providing a
     better way of doing:

     (a) Bind mounts

     (b) Filesystem reconfiguration.

     (c) Parameter propagation to automounts/submounts.

 (3) Up-front parameter parsing and resource allocation.  This allows
     parameters to be parsed validated and resources to be allocated before we
     begin the super_block initialisation/creation/loading/whatever process,
     allowing us to get some error handling out of the way earlier.

     Ext4 has an interesting issue here: it will load the parameters from
     disk, then overlay them with the parameters given to sys_mount() as it
     parses them - but this will leave you with a half-set-up superblock if a
     parse error occurs.  I *think* the new-mount branch just discards the
     superblock in that case, but in the case of remount, only *some* of the
     changes will be applied - which is bad.

 (4) Better handling of namespaces - the fs_context gives us somewhere to
     anchor namespaces and potentially configure these before mounting.
     Certainly, it would give somewhere to pass namespace information to a
     submount.

     This would potentially make it possible to mount directly into someone
     else's namespaces for container handing.


I'd also like to make it possible to return better error messages from the
kernel as a lot of different things can go wrong during a mount and we only
have a small integer to convey this - plus dmesg, which might be inaccessible
and may mixed up with other things.

Originally, I implemented the supplementary error message handling as hanging
off the fs_context struct, but that got tricky with NFS because NFS4 creates a
mount for the root on a server and then invokes pathwalk to the intended path
from within the ->mount() function.

This pathwalk is expected to trip one or more automount points as changes in
FSID are detected - but they have no access to the parent fs_context struct in
which to supplement any error that is incurred.

So I've moved this to task_struct and provided a couple of prctls to manage it
- this also has the added bonus of making it more widely available and also
making it potentially useful to determine what happened in the case of an
automount failure.  However, Al would prefer me to move it back to the
fs_struct as it's too generic otherwise.

David

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH 06/27] Provide supplementary error message facility [ver #5]
  2017-06-14 15:16 ` [PATCH 06/27] Provide supplementary error message facility " David Howells
@ 2017-08-18  3:09   ` Kim Phillips
  0 siblings, 0 replies; 53+ messages in thread
From: Kim Phillips @ 2017-08-18  3:09 UTC (permalink / raw)
  To: David Howells
  Cc: mszeredi, viro, linux-nfs, jlayton, linux-kernel,
	linux-security-module, linux-fsdevel, perf group, Will Deacon,
	Mark Rutland, Arnaldo Carvalho de Melo

On Wed, 14 Jun 2017 16:16:11 +0100
David Howells <dhowells@redhat.com> wrote:

> Provide a way for the kernel to pass supplementary error messages to
> userspace.  This will make it easier for userspace, particularly in
> containers to find out what went wrong during mounts and automounts, but is
> also made available to any other syscalls that want to use it.

Hi all, I see patches 1-5 have already made it to Linus' master branch,
but I can't determine the status of this particular patch.

Assuming it's still under consideration, I'd like to attest to the
significantly higher level of user experience improvement it can give
perf users (see RFC below):  Am I taking the right approach here by
assuming this new error message facility is indeed eligible for upstream
acceptance sometime soon?

Thanks,

Kim

>From da34ddaf1aa8c731f645c268a1caf17029caca8c Mon Sep 17 00:00:00 2001
From: Kim Phillips <kim.phillips@arm.com>
Date: Wed, 16 Aug 2017 17:56:40 -0500
Subject: [RFC] perf tool & spe driver: shot at prctl errmsging

Example session: Lines beginning with "spe-pmu@" are new and
specify what the PMU driver found wrong to the user in a much
more precise manner:

$ ./perf record -e arm_spe_0// -C 0-3 true
Error:
spe-pmu@0: no sample period, or less than minimum (256)
PMU Hardware doesn't support sampling/overflow-interrupts.
$ ./perf record -e arm_spe_0// -C 0-3 -c 1024 true
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.022 MB perf.data ]
$ ./perf record -e arm_spe_0// -C 0-4 -c 1024 true
Error:
spe-pmu@0: not supported on CPU 4. Supported CPU list: 0-3
The arm_spe_0// event is not supported.
$ ./perf record -e arm_spe_0/pa_enable=1/ -C 0-3 -c 1024 true
Error:
spe-pmu@0: physical address and/or context ID capture limited to privileged users
$ sudo ./perf record -e arm_spe_0/pa_enable=1/ -C 0-3 -c 1024 true
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.071 MB perf.data ]
$

Signed-off-by: Kim Phillips <kim.phillips@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
---
- patch available and rebased on top of linux-will.git/perf/spe's latest, here:
	http://www.linux-arm.org/git?p=linux-kp.git;a=shortlog;h=refs/heads/spe-prctl
  or
	git://linux-arm.org/linux-kp.git  # spe-prctl branch

 drivers/perf/arm_spe_pmu.c | 46 ++++++++++++++++++++++++++++++++++++++--------
 tools/perf/perf.c          | 12 ++++++++++++
 tools/perf/util/evsel.c    | 14 +++++++++-----
 3 files changed, 59 insertions(+), 13 deletions(-)

diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
index fef0a4834879..cb4db7dac929 100644
--- a/drivers/perf/arm_spe_pmu.c
+++ b/drivers/perf/arm_spe_pmu.c
@@ -23,11 +23,13 @@
 #define DRVNAME				PMUNAME "_pmu"
 #define pr_fmt(fmt)			DRVNAME ": " fmt
 
+#include <linux/cpumask.h>
 #include <linux/cpuhotplug.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
+#include <linux/device.h>
 #include <linux/of_device.h>
 #include <linux/perf_event.h>
 #include <linux/platform_device.h>
@@ -660,20 +662,30 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
 	u64 reg;
 	struct perf_event_attr *attr = &event->attr;
 	struct arm_spe_pmu *spe_pmu = to_spe_pmu(event->pmu);
+	const struct device *dev = &spe_pmu->pdev->dev;
+	const char *devname = dev_name(dev);
 
 	/* This is, of course, deeply driver-specific */
 	if (attr->type != event->pmu->type)
 		return -ENOENT;
 
 	if (event->cpu >= 0 &&
-	    !cpumask_test_cpu(event->cpu, &spe_pmu->supported_cpus))
+	    !cpumask_test_cpu(event->cpu, &spe_pmu->supported_cpus)) {
+		errorf("%s: not supported on CPU %d. Supported CPU list: %*pbl\n",
+		       devname, event->cpu, cpumask_pr_args(&spe_pmu->supported_cpus));
 		return -ENOENT;
+	}
 
-	if (arm_spe_event_to_pmsevfr(event) & PMSEVFR_EL1_RES0)
+	if (arm_spe_event_to_pmsevfr(event) & PMSEVFR_EL1_RES0) {
+		errorf("%s: unsupported Sampling Event Filter (PMSEVFR) value\n",
+		       devname);
 		return -EOPNOTSUPP;
+	}
 
-	if (attr->exclude_idle)
+	if (attr->exclude_idle) {
+		errorf("%s: Cannot exclude profiling when idle\n", devname);
 		return -EOPNOTSUPP;
+	}
 
 	/*
 	 * Feedback-directed frequency throttling doesn't work when we
@@ -682,26 +694,44 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
 	 * count to reflect that. Instead, force the user to specify a
 	 * sample period instead.
 	 */
-	if (attr->freq)
+	if (attr->freq) {
+		errorf("%s: sample period must be specified\n", devname);
 		return -EINVAL;
+	}
+
+	if (!event->hw.sample_period ||
+	    event->hw.sample_period < spe_pmu->min_period) {
+		errorf("%s: no sample period, or less than minimum (%d)\n",
+		       devname, spe_pmu->min_period);
+		return -EOPNOTSUPP;
+	}
 
 	reg = arm_spe_event_to_pmsfcr(event);
 	if ((reg & BIT(PMSFCR_EL1_FE_SHIFT)) &&
-	    !(spe_pmu->features & SPE_PMU_FEAT_FILT_EVT))
+	    !(spe_pmu->features & SPE_PMU_FEAT_FILT_EVT)) {
+		errorf("%s: unsupported filter (EVT)\n", devname);
 		return -EOPNOTSUPP;
+	}
 
 	if ((reg & BIT(PMSFCR_EL1_FT_SHIFT)) &&
-	    !(spe_pmu->features & SPE_PMU_FEAT_FILT_TYP))
+	    !(spe_pmu->features & SPE_PMU_FEAT_FILT_TYP)) {
+		errorf("%s: unsupported filter (TYP)\n", devname);
 		return -EOPNOTSUPP;
+	}
 
 	if ((reg & BIT(PMSFCR_EL1_FL_SHIFT)) &&
-	    !(spe_pmu->features & SPE_PMU_FEAT_FILT_LAT))
+	    !(spe_pmu->features & SPE_PMU_FEAT_FILT_LAT)) {
+		errorf("%s: unsupported filter (LAT)\n", devname);
 		return -EOPNOTSUPP;
+	}
 
 	reg = arm_spe_event_to_pmscr(event);
 	if (!capable(CAP_SYS_ADMIN) &&
-	    (reg & (BIT(PMSCR_EL1_PA_SHIFT) | BIT(PMSCR_EL1_CX_SHIFT))))
+	    (reg & (BIT(PMSCR_EL1_PA_SHIFT) | BIT(PMSCR_EL1_CX_SHIFT)))) {
+		errorf("%s: physical address and/or context ID capture limited to privileged users\n",
+		       devname);
 		return -EACCES;
+	}
 
 	return 0;
 }
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 628a5e412cb1..0d16dc5042ab 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -30,6 +30,13 @@
 #include <unistd.h>
 #include <linux/kernel.h>
 
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+
+#define PR_ERRMSG_ENABLE		48
+#define PR_ERRMSG_READ			49
+
 const char perf_usage_string[] =
 	"perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
 
@@ -431,6 +438,11 @@ int main(int argc, const char **argv)
 	char sbuf[STRERR_BUFSIZE];
 	int value;
 
+	if (prctl(PR_ERRMSG_ENABLE, 1) < 0) {
+		perror("prctl/en");
+		exit(1);
+	}
+
 	/* libsubcmd init */
 	exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
 	pager_init(PERF_PAGER_ENVIRONMENT);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d9899280a9ee..e997a361d1eb 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -21,6 +21,7 @@
 #include <sys/ioctl.h>
 #include <sys/resource.h>
 #include <sys/types.h>
+#include <sys/prctl.h>
 #include <dirent.h>
 #include "asm/bug.h"
 #include "callchain.h"
@@ -40,6 +41,9 @@
 
 #include "sane_ctype.h"
 
+#define PR_ERRMSG_ENABLE		48
+#define PR_ERRMSG_READ			49
+
 static struct {
 	bool sample_id_all;
 	bool exclude_guest;
@@ -2518,19 +2522,19 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
 			      int err, char *msg, size_t size)
 {
 	char sbuf[STRERR_BUFSIZE];
-	int printed = 0;
-	int n, perr;
+	int perr, printed = 0;
+	size_t n;
 
 	do {
 		errno = 0;
 		n = prctl(PR_ERRMSG_READ, sbuf, sizeof(sbuf));
 		perr = errno;
-		if (n > 0) {
-			printed = scnprintf(msg, n + 1, "%s\n", sbuf);
+		if (n > 0 && n < size) {
+			sbuf[n] = 0;
+			printed = scnprintf(msg, size, "%s", sbuf);
 			size -= printed;
 			msg += printed;
 		}
-		
 	} while (perr == 0);
 
 	switch (err) {
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2017-08-18  3:09 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-14 15:15 [RFC][PATCH 00/27] VFS: Introduce filesystem context [ver #5] David Howells
2017-06-14 15:15 ` [PATCH 01/27] Provide a function to create a NUL-terminated string from unterminated data " David Howells
2017-06-14 15:15 ` [PATCH 02/27] VFS: Clean up whitespace in fs/namespace.c and fs/super.c " David Howells
2017-06-14 15:15 ` [PATCH 03/27] VFS: Make get_mnt_ns() return the namespace " David Howells
2017-06-15  9:09   ` Al Viro
2017-06-14 15:15 ` [PATCH 04/27] VFS: Make get_filesystem() return the affected filesystem " David Howells
2017-06-14 15:16 ` [PATCH 05/27] VFS: Provide empty name qstr " David Howells
2017-06-14 15:16 ` [PATCH 06/27] Provide supplementary error message facility " David Howells
2017-08-18  3:09   ` Kim Phillips
2017-06-14 15:16 ` [PATCH 07/27] VFS: Differentiate mount flags (MS_*) from internal superblock flags " David Howells
2017-06-15  9:39   ` Al Viro
2017-06-16  9:06     ` Christoph Hellwig
2017-06-16 14:53     ` David Howells
2017-06-16 15:49       ` Christoph Hellwig
2017-06-16 15:54       ` David Howells
2017-06-14 15:16 ` [PATCH 08/27] VFS: Introduce the structs and doc for a filesystem context " David Howells
2017-06-14 18:02   ` Randy Dunlap
2017-06-14 20:03   ` Casey Schaufler
2017-06-14 20:42   ` David Howells
2017-06-14 20:53     ` Casey Schaufler
2017-06-17  9:57       ` Theodore Ts'o
2017-06-17 14:18       ` David Howells
2017-06-17 14:56         ` Jeff Layton
2017-06-17 15:11           ` Randy Dunlap
2017-06-19  7:47         ` David Howells
2017-06-14 22:58   ` Updated docs David Howells
2017-06-15  1:53     ` Randy Dunlap
2017-06-14 15:16 ` [PATCH 09/27] VFS: Add LSM hooks for filesystem context [ver #5] David Howells
2017-06-14 15:16 ` [PATCH 10/27] VFS: Implement a filesystem superblock creation/configuration " David Howells
2017-06-14 15:17 ` [PATCH 11/27] VFS: Remove unused code after filesystem context changes " David Howells
2017-06-14 15:17 ` [PATCH 12/27] VFS: Implement fsopen() to prepare for a mount " David Howells
2017-06-14 15:17 ` [PATCH 13/27] VFS: Implement fsmount() to effect a pre-configured " David Howells
2017-06-14 15:17 ` [PATCH 14/27] VFS: Add a sample program for fsopen/fsmount " David Howells
2017-06-14 15:17 ` [PATCH 15/27] procfs: Move proc_fill_super() to fs/proc/root.c " David Howells
2017-06-14 15:17 ` [PATCH 16/27] proc: Add fs_context support to procfs " David Howells
2017-06-15 10:14   ` Al Viro
2017-06-14 15:17 ` [PATCH 17/27] NFS: Move mount parameterisation bits into their own file " David Howells
2017-06-14 15:18 ` [PATCH 18/27] NFS: Constify mount argument match tables " David Howells
2017-06-14 15:18 ` [PATCH 19/27] NFS: Rename struct nfs_parsed_mount_data to struct nfs_fs_context " David Howells
2017-06-14 15:18 ` [PATCH 20/27] NFS: Split nfs_parse_mount_options() " David Howells
2017-06-14 15:18 ` [PATCH 21/27] NFS: Deindent nfs_fs_context_parse_option() " David Howells
2017-06-14 15:18 ` [PATCH 22/27] NFS: Add a small buffer in nfs_fs_context to avoid string dup " David Howells
2017-06-14 15:18 ` [PATCH 23/27] NFS: Do some tidying of the parsing code " David Howells
2017-06-14 15:18 ` [PATCH 24/27] NFS: Add fs_context support. " David Howells
2017-06-15 15:28   ` Anna Schumaker
2017-06-14 15:19 ` [PATCH 25/27] ipc: Convert mqueue fs to fs_context " David Howells
2017-06-15 10:07   ` Al Viro
2017-06-15 14:47   ` David Howells
2017-06-14 15:19 ` [PATCH 26/27] cpuset: Use " David Howells
2017-06-14 15:19 ` [PATCH 27/27] kernfs, sysfs, cgroup: Support " David Howells
2017-06-14 17:54   ` Tejun Heo
2017-06-23 15:29   ` David Howells
2017-06-14 22:31 ` [PATCH 27/27] ... and the intel_rdt driver David Howells

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).