LKML Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v3 00/26] nfs: Mount API conversion
@ 2019-09-11 16:15 Scott Mayhew
  2019-09-11 16:15 ` [PATCH v3 01/26] saner calling conventions for nfs_fs_mount_common() Scott Mayhew
                   ` (25 more replies)
  0 siblings, 26 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:15 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

Hi Anna,

Here's a set of patches that converts NFS to use the mount API.  Note that
there are a lot of preliminary patches, some from David and some from Al.
The final patch (the one that does the actual conversion) from the David's
initial posting has been split into 4 separate patches, and the entire set
has been rebased on top of v5.3-rc6.

Changes since v2:
- fixed the conversion of the nconnect= option
- added '#if IS_ENABLED(CONFIG_NFS_V4)' around nfs4_parse_monolithic()
  to avoid unused-function warning when compiling with v4 disabled

-Scott

Al Viro (15):
  saner calling conventions for nfs_fs_mount_common()
  nfs: stash server into struct nfs_mount_info
  nfs: lift setting mount_info from nfs4_remote{,_referral}_mount
  nfs: fold nfs4_remote_fs_type and nfs4_remote_referral_fs_type
  nfs: don't bother setting/restoring export_path around
    do_nfs_root_mount()
  nfs4: fold nfs_do_root_mount/nfs_follow_remote_path
  nfs: lift setting mount_info from nfs_xdev_mount()
  nfs: stash nfs_subversion reference into nfs_mount_info
  nfs: don't bother passing nfs_subversion to ->try_mount() and
    nfs_fs_mount_common()
  nfs: merge xdev and remote file_system_type
  nfs: unexport nfs_fs_mount_common()
  nfs: don't pass nfs_subversion to ->create_server()
  nfs: get rid of mount_info ->fill_super()
  nfs_clone_sb_security(): simplify the check for server bogosity
  nfs: get rid of ->set_security()

David Howells (8):
  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.

Scott Mayhew (3):
  NFS: rename nfs_fs_context pointer arg in a few functions
  NFS: Convert mount option parsing to use functionality from
    fs_parser.h
  NFS: Attach supplementary error information to fs_context.

 fs/nfs/Makefile         |    2 +-
 fs/nfs/client.c         |   80 +-
 fs/nfs/fs_context.c     | 1425 ++++++++++++++++++++++++++++
 fs/nfs/fscache.c        |    2 +-
 fs/nfs/getroot.c        |   73 +-
 fs/nfs/internal.h       |  132 +--
 fs/nfs/namespace.c      |  144 +--
 fs/nfs/nfs3_fs.h        |    2 +-
 fs/nfs/nfs3client.c     |    6 +-
 fs/nfs/nfs3proc.c       |    2 +-
 fs/nfs/nfs4_fs.h        |    9 +-
 fs/nfs/nfs4client.c     |   99 +-
 fs/nfs/nfs4namespace.c  |  285 +++---
 fs/nfs/nfs4proc.c       |    2 +-
 fs/nfs/nfs4super.c      |  257 ++---
 fs/nfs/proc.c           |    2 +-
 fs/nfs/super.c          | 1962 ++++-----------------------------------
 include/linux/nfs_xdr.h |    9 +-
 18 files changed, 2156 insertions(+), 2337 deletions(-)
 create mode 100644 fs/nfs/fs_context.c

-- 
2.17.2


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

* [PATCH v3 01/26] saner calling conventions for nfs_fs_mount_common()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
@ 2019-09-11 16:15 ` Scott Mayhew
  2019-09-11 16:15 ` [PATCH v3 02/26] nfs: stash server into struct nfs_mount_info Scott Mayhew
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:15 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

Allow it to take ERR_PTR() for server and return ERR_CAST() of it in
such case.  All callers used to open-code that...

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/nfs4super.c | 16 +---------------
 fs/nfs/super.c     | 11 ++++-------
 2 files changed, 5 insertions(+), 22 deletions(-)

diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 04c57066a11a..baece9857bcf 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -110,21 +110,12 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
 {
 	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;
 
 	/* 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);
-
-out:
-	return mntroot;
+	return nfs_fs_mount_common(server, flags, dev_name, mount_info, &nfs_v4);
 }
 
 static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
@@ -280,11 +271,6 @@ nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
 
 	/* 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;
-	}
-
 	mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, &nfs_v4);
 out:
 	nfs_free_fhandle(mount_info.mntfh);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 703f595dce90..467d7a636f0b 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1903,9 +1903,6 @@ struct dentry *nfs_try_mount(int flags, const char *dev_name,
 	else
 		server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
 
-	if (IS_ERR(server))
-		return ERR_CAST(server);
-
 	return nfs_fs_mount_common(server, flags, dev_name, mount_info, nfs_mod);
 }
 EXPORT_SYMBOL_GPL(nfs_try_mount);
@@ -2641,6 +2638,9 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
 	};
 	int error;
 
+	if (IS_ERR(server))
+		return ERR_CAST(server);
+
 	if (server->flags & NFS_MOUNT_UNSHARED)
 		compare_super = NULL;
 
@@ -2789,10 +2789,7 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
 	/* 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,
+	mntroot = nfs_fs_mount_common(server, flags,
 				dev_name, &mount_info, nfs_mod);
 
 	dprintk("<-- nfs_xdev_mount() = %ld\n",
-- 
2.17.2


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

* [PATCH v3 02/26] nfs: stash server into struct nfs_mount_info
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
  2019-09-11 16:15 ` [PATCH v3 01/26] saner calling conventions for nfs_fs_mount_common() Scott Mayhew
@ 2019-09-11 16:15 ` Scott Mayhew
  2019-09-11 16:15 ` [PATCH v3 03/26] nfs: lift setting mount_info from nfs4_remote{,_referral}_mount Scott Mayhew
                   ` (23 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:15 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/internal.h  |  3 ++-
 fs/nfs/nfs4super.c | 10 ++++------
 fs/nfs/super.c     | 19 ++++++++-----------
 3 files changed, 14 insertions(+), 18 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index a2346a2f8361..c132e683e1c9 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -150,6 +150,7 @@ struct nfs_mount_info {
 	int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *);
 	struct nfs_parsed_mount_data *parsed;
 	struct nfs_clone_mount *cloned;
+	struct nfs_server *server;
 	struct nfs_fh *mntfh;
 };
 
@@ -405,7 +406,7 @@ 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 dentry *nfs_fs_mount_common(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,
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index baece9857bcf..4591d6618efa 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -109,13 +109,12 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
 		  const char *dev_name, void *info)
 {
 	struct nfs_mount_info *mount_info = info;
-	struct nfs_server *server;
 
 	mount_info->set_security = nfs_set_sb_security;
 
 	/* Get a volume representation */
-	server = nfs4_create_server(mount_info, &nfs_v4);
-	return nfs_fs_mount_common(server, flags, dev_name, mount_info, &nfs_v4);
+	mount_info->server = nfs4_create_server(mount_info, &nfs_v4);
+	return nfs_fs_mount_common(flags, dev_name, mount_info, &nfs_v4);
 }
 
 static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
@@ -260,7 +259,6 @@ nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
 		.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");
@@ -270,8 +268,8 @@ nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
 		goto out;
 
 	/* create a new volume representation */
-	server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh);
-	mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, &nfs_v4);
+	mount_info.server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh);
+	mntroot = nfs_fs_mount_common(flags, dev_name, &mount_info, &nfs_v4);
 out:
 	nfs_free_fhandle(mount_info.mntfh);
 	return mntroot;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 467d7a636f0b..10544ef8de57 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1896,14 +1896,12 @@ struct dentry *nfs_try_mount(int flags, const char *dev_name,
 			     struct nfs_mount_info *mount_info,
 			     struct nfs_subversion *nfs_mod)
 {
-	struct nfs_server *server;
-
 	if (mount_info->parsed->need_mount)
-		server = nfs_try_mount_request(mount_info, nfs_mod);
+		mount_info->server = nfs_try_mount_request(mount_info, nfs_mod);
 	else
-		server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+		mount_info->server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
 
-	return nfs_fs_mount_common(server, flags, dev_name, mount_info, nfs_mod);
+	return nfs_fs_mount_common(flags, dev_name, mount_info, nfs_mod);
 }
 EXPORT_SYMBOL_GPL(nfs_try_mount);
 
@@ -2624,20 +2622,21 @@ int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
 }
 EXPORT_SYMBOL_GPL(nfs_clone_sb_security);
 
-struct dentry *nfs_fs_mount_common(struct nfs_server *server,
-				   int flags, const char *dev_name,
+struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 				   struct nfs_mount_info *mount_info,
 				   struct nfs_subversion *nfs_mod)
 {
 	struct super_block *s;
 	struct dentry *mntroot = ERR_PTR(-ENOMEM);
 	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
+	struct nfs_server *server = mount_info->server;
 	struct nfs_sb_mountdata sb_mntdata = {
 		.mntflags = flags,
 		.server = server,
 	};
 	int error;
 
+	mount_info->server = NULL;
 	if (IS_ERR(server))
 		return ERR_CAST(server);
 
@@ -2778,7 +2777,6 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
 		.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;
 
@@ -2787,10 +2785,9 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
 	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);
+	mount_info.server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor);
 
-	mntroot = nfs_fs_mount_common(server, flags,
-				dev_name, &mount_info, nfs_mod);
+	mntroot = nfs_fs_mount_common(flags, dev_name, &mount_info, nfs_mod);
 
 	dprintk("<-- nfs_xdev_mount() = %ld\n",
 			IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L);
-- 
2.17.2


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

* [PATCH v3 03/26] nfs: lift setting mount_info from nfs4_remote{,_referral}_mount
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
  2019-09-11 16:15 ` [PATCH v3 01/26] saner calling conventions for nfs_fs_mount_common() Scott Mayhew
  2019-09-11 16:15 ` [PATCH v3 02/26] nfs: stash server into struct nfs_mount_info Scott Mayhew
@ 2019-09-11 16:15 ` Scott Mayhew
  2019-09-11 16:15 ` [PATCH v3 04/26] nfs: fold nfs4_remote_fs_type and nfs4_remote_referral_fs_type Scott Mayhew
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:15 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

Do that (fhandle allocation, setting struct server up) in
nfs4_referral_mount() and nfs4_try_mount() resp. and pass the
server and pointer to mount_info into nfs_do_root_mount() so that
nfs4_remote_referral_mount()/nfs_remote_mount() could be merged.

Since we are moving stuff from ->mount() instances to the points
prior to vfs_kern_mount() that would trigger those, we need to
make sure that do_nfs_root_mount() will do the corresponding
cleanup itself if it doesn't trigger those ->mount() instances.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/nfs4super.c | 67 ++++++++++++++++++++++++----------------------
 1 file changed, 35 insertions(+), 32 deletions(-)

diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 4591d6618efa..773c347df3ab 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -108,32 +108,37 @@ static struct dentry *
 nfs4_remote_mount(struct file_system_type *fs_type, int flags,
 		  const char *dev_name, void *info)
 {
-	struct nfs_mount_info *mount_info = info;
-
-	mount_info->set_security = nfs_set_sb_security;
-
-	/* Get a volume representation */
-	mount_info->server = nfs4_create_server(mount_info, &nfs_v4);
-	return nfs_fs_mount_common(flags, dev_name, mount_info, &nfs_v4);
+	return nfs_fs_mount_common(flags, dev_name, info, &nfs_v4);
 }
 
 static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
-		int flags, void *data, const char *hostname)
+					  struct nfs_server *server, int flags,
+					  struct nfs_mount_info *info,
+					  const char *hostname)
 {
 	struct vfsmount *root_mnt;
 	char *root_devname;
 	size_t len;
 
+	if (IS_ERR(server))
+		return ERR_CAST(server);
+
 	len = strlen(hostname) + 5;
 	root_devname = kmalloc(len, GFP_KERNEL);
-	if (root_devname == NULL)
+	if (root_devname == NULL) {
+		nfs_free_server(server);
 		return ERR_PTR(-ENOMEM);
+	}
 	/* 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);
+	info->server = server;
+	root_mnt = vfs_kern_mount(fs_type, flags, root_devname, info);
+	if (info->server)
+		nfs_free_server(info->server);
+	info->server = NULL;
 	kfree(root_devname);
 	return root_mnt;
 }
@@ -234,11 +239,15 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 	struct dentry *res;
 	struct nfs_parsed_mount_data *data = mount_info->parsed;
 
+	mount_info->set_security = nfs_set_sb_security;
+
 	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
 	export_path = data->nfs_server.export_path;
 	data->nfs_server.export_path = "/";
-	root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
+	root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type,
+			nfs4_create_server(mount_info, &nfs_v4),
+			flags, mount_info,
 			data->nfs_server.hostname);
 	data->nfs_server.export_path = export_path;
 
@@ -254,25 +263,7 @@ static struct dentry *
 nfs4_remote_referral_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_clone_sb_security,
-		.cloned = raw_data,
-	};
-	struct dentry *mntroot = ERR_PTR(-ENOMEM);
-
-	dprintk("--> nfs4_referral_get_sb()\n");
-
-	mount_info.mntfh = nfs_alloc_fhandle();
-	if (mount_info.cloned == NULL || mount_info.mntfh == NULL)
-		goto out;
-
-	/* create a new volume representation */
-	mount_info.server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh);
-	mntroot = nfs_fs_mount_common(flags, dev_name, &mount_info, &nfs_v4);
-out:
-	nfs_free_fhandle(mount_info.mntfh);
-	return mntroot;
+	return nfs_fs_mount_common(flags, dev_name, raw_data, &nfs_v4);
 }
 
 /*
@@ -282,23 +273,35 @@ static struct dentry *nfs4_referral_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_fill_super,
+		.set_security = nfs_clone_sb_security,
+		.cloned = data,
+	};
 	char *export_path;
 	struct vfsmount *root_mnt;
 	struct dentry *res;
 
 	dprintk("--> nfs4_referral_mount()\n");
 
+	mount_info.mntfh = nfs_alloc_fhandle();
+	if (!mount_info.mntfh)
+		return ERR_PTR(-ENOMEM);
+
 	export_path = data->mnt_path;
 	data->mnt_path = "/";
-
 	root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
-			flags, data, data->hostname);
+			nfs4_create_referral_server(mount_info.cloned,
+						    mount_info.mntfh),
+			flags, &mount_info, data->hostname);
 	data->mnt_path = export_path;
 
 	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]" : "");
+
+	nfs_free_fhandle(mount_info.mntfh);
 	return res;
 }
 
-- 
2.17.2


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

* [PATCH v3 04/26] nfs: fold nfs4_remote_fs_type and nfs4_remote_referral_fs_type
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (2 preceding siblings ...)
  2019-09-11 16:15 ` [PATCH v3 03/26] nfs: lift setting mount_info from nfs4_remote{,_referral}_mount Scott Mayhew
@ 2019-09-11 16:15 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 05/26] nfs: don't bother setting/restoring export_path around do_nfs_root_mount() Scott Mayhew
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:15 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

They are identical now.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/nfs4super.c | 26 ++++----------------------
 1 file changed, 4 insertions(+), 22 deletions(-)

diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 773c347df3ab..d0237d8ffa2b 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -22,8 +22,6 @@ 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,
@@ -33,14 +31,6 @@ static struct file_system_type nfs4_remote_fs_type = {
 	.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",
@@ -111,8 +101,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
 	return nfs_fs_mount_common(flags, dev_name, info, &nfs_v4);
 }
 
-static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
-					  struct nfs_server *server, int flags,
+static struct vfsmount *nfs_do_root_mount(struct nfs_server *server, int flags,
 					  struct nfs_mount_info *info,
 					  const char *hostname)
 {
@@ -135,7 +124,7 @@ static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
 	else
 		snprintf(root_devname, len, "%s:/", hostname);
 	info->server = server;
-	root_mnt = vfs_kern_mount(fs_type, flags, root_devname, info);
+	root_mnt = vfs_kern_mount(&nfs4_remote_fs_type, flags, root_devname, info);
 	if (info->server)
 		nfs_free_server(info->server);
 	info->server = NULL;
@@ -245,7 +234,7 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 
 	export_path = data->nfs_server.export_path;
 	data->nfs_server.export_path = "/";
-	root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type,
+	root_mnt = nfs_do_root_mount(
 			nfs4_create_server(mount_info, &nfs_v4),
 			flags, mount_info,
 			data->nfs_server.hostname);
@@ -259,13 +248,6 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 	return res;
 }
 
-static struct dentry *
-nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
-			   const char *dev_name, void *raw_data)
-{
-	return nfs_fs_mount_common(flags, dev_name, raw_data, &nfs_v4);
-}
-
 /*
  * Create an NFS4 server record on referral traversal
  */
@@ -290,7 +272,7 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
 
 	export_path = data->mnt_path;
 	data->mnt_path = "/";
-	root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
+	root_mnt = nfs_do_root_mount(
 			nfs4_create_referral_server(mount_info.cloned,
 						    mount_info.mntfh),
 			flags, &mount_info, data->hostname);
-- 
2.17.2


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

* [PATCH v3 05/26] nfs: don't bother setting/restoring export_path around do_nfs_root_mount()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (3 preceding siblings ...)
  2019-09-11 16:15 ` [PATCH v3 04/26] nfs: fold nfs4_remote_fs_type and nfs4_remote_referral_fs_type Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 06/26] nfs4: fold nfs_do_root_mount/nfs_follow_remote_path Scott Mayhew
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

nothing in it will be looking at that thing anyway

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/nfs4super.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index d0237d8ffa2b..a0b66f98f6ba 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -233,12 +233,10 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
 	export_path = data->nfs_server.export_path;
-	data->nfs_server.export_path = "/";
 	root_mnt = nfs_do_root_mount(
 			nfs4_create_server(mount_info, &nfs_v4),
 			flags, mount_info,
 			data->nfs_server.hostname);
-	data->nfs_server.export_path = export_path;
 
 	res = nfs_follow_remote_path(root_mnt, export_path);
 
@@ -271,12 +269,10 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
 		return ERR_PTR(-ENOMEM);
 
 	export_path = data->mnt_path;
-	data->mnt_path = "/";
 	root_mnt = nfs_do_root_mount(
 			nfs4_create_referral_server(mount_info.cloned,
 						    mount_info.mntfh),
 			flags, &mount_info, data->hostname);
-	data->mnt_path = export_path;
 
 	res = nfs_follow_remote_path(root_mnt, export_path);
 	dprintk("<-- nfs4_referral_mount() = %d%s\n",
-- 
2.17.2


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

* [PATCH v3 06/26] nfs4: fold nfs_do_root_mount/nfs_follow_remote_path
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (4 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 05/26] nfs: don't bother setting/restoring export_path around do_nfs_root_mount() Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 07/26] nfs: lift setting mount_info from nfs_xdev_mount() Scott Mayhew
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/nfs4super.c | 88 +++++++++++++++++++---------------------------
 1 file changed, 37 insertions(+), 51 deletions(-)

diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index a0b66f98f6ba..91ba1b6741dc 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -101,37 +101,6 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
 	return nfs_fs_mount_common(flags, dev_name, info, &nfs_v4);
 }
 
-static struct vfsmount *nfs_do_root_mount(struct nfs_server *server, int flags,
-					  struct nfs_mount_info *info,
-					  const char *hostname)
-{
-	struct vfsmount *root_mnt;
-	char *root_devname;
-	size_t len;
-
-	if (IS_ERR(server))
-		return ERR_CAST(server);
-
-	len = strlen(hostname) + 5;
-	root_devname = kmalloc(len, GFP_KERNEL);
-	if (root_devname == NULL) {
-		nfs_free_server(server);
-		return ERR_PTR(-ENOMEM);
-	}
-	/* Does hostname needs to be enclosed in brackets? */
-	if (strchr(hostname, ':'))
-		snprintf(root_devname, len, "[%s]:/", hostname);
-	else
-		snprintf(root_devname, len, "%s:/", hostname);
-	info->server = server;
-	root_mnt = vfs_kern_mount(&nfs4_remote_fs_type, flags, root_devname, info);
-	if (info->server)
-		nfs_free_server(info->server);
-	info->server = NULL;
-	kfree(root_devname);
-	return root_mnt;
-}
-
 struct nfs_referral_count {
 	struct list_head list;
 	const struct task_struct *task;
@@ -198,11 +167,38 @@ static void nfs_referral_loop_unprotect(void)
 	kfree(p);
 }
 
-static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
-		const char *export_path)
+static struct dentry *do_nfs4_mount(struct nfs_server *server, int flags,
+				    struct nfs_mount_info *info,
+				    const char *hostname,
+				    const char *export_path)
 {
+	struct vfsmount *root_mnt;
 	struct dentry *dentry;
+	char *root_devname;
 	int err;
+	size_t len;
+
+	if (IS_ERR(server))
+		return ERR_CAST(server);
+
+	len = strlen(hostname) + 5;
+	root_devname = kmalloc(len, GFP_KERNEL);
+	if (root_devname == NULL) {
+		nfs_free_server(server);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* Does hostname needs to be enclosed in brackets? */
+	if (strchr(hostname, ':'))
+		snprintf(root_devname, len, "[%s]:/", hostname);
+	else
+		snprintf(root_devname, len, "%s:/", hostname);
+	info->server = server;
+	root_mnt = vfs_kern_mount(&nfs4_remote_fs_type, flags, root_devname, info);
+	if (info->server)
+		nfs_free_server(info->server);
+	info->server = NULL;
+	kfree(root_devname);
 
 	if (IS_ERR(root_mnt))
 		return ERR_CAST(root_mnt);
@@ -223,22 +219,17 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 			      struct nfs_mount_info *mount_info,
 			      struct nfs_subversion *nfs_mod)
 {
-	char *export_path;
-	struct vfsmount *root_mnt;
-	struct dentry *res;
 	struct nfs_parsed_mount_data *data = mount_info->parsed;
+	struct dentry *res;
 
 	mount_info->set_security = nfs_set_sb_security;
 
 	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
-	export_path = data->nfs_server.export_path;
-	root_mnt = nfs_do_root_mount(
-			nfs4_create_server(mount_info, &nfs_v4),
-			flags, mount_info,
-			data->nfs_server.hostname);
-
-	res = nfs_follow_remote_path(root_mnt, export_path);
+	res = do_nfs4_mount(nfs4_create_server(mount_info, &nfs_v4),
+			    flags, mount_info,
+			    data->nfs_server.hostname,
+			    data->nfs_server.export_path);
 
 	dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n",
 		 PTR_ERR_OR_ZERO(res),
@@ -258,8 +249,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
 		.set_security = nfs_clone_sb_security,
 		.cloned = data,
 	};
-	char *export_path;
-	struct vfsmount *root_mnt;
 	struct dentry *res;
 
 	dprintk("--> nfs4_referral_mount()\n");
@@ -268,13 +257,10 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
 	if (!mount_info.mntfh)
 		return ERR_PTR(-ENOMEM);
 
-	export_path = data->mnt_path;
-	root_mnt = nfs_do_root_mount(
-			nfs4_create_referral_server(mount_info.cloned,
-						    mount_info.mntfh),
-			flags, &mount_info, data->hostname);
+	res = do_nfs4_mount(nfs4_create_referral_server(mount_info.cloned,
+							mount_info.mntfh),
+			    flags, &mount_info, data->hostname, data->mnt_path);
 
-	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]" : "");
-- 
2.17.2


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

* [PATCH v3 07/26] nfs: lift setting mount_info from nfs_xdev_mount()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (5 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 06/26] nfs4: fold nfs_do_root_mount/nfs_follow_remote_path Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 08/26] nfs: stash nfs_subversion reference into nfs_mount_info Scott Mayhew
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

Do it in nfs_do_submount() instead.  As a side benefit, nfs_clone_data
doesn't need ->fh and ->fattr anymore.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/internal.h  |  3 +--
 fs/nfs/namespace.c | 35 +++++++++++++++++++++--------------
 fs/nfs/super.c     | 25 ++++---------------------
 3 files changed, 26 insertions(+), 37 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index c132e683e1c9..eeb54b45875c 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -42,8 +42,6 @@ static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr)
 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;
@@ -413,6 +411,7 @@ struct dentry * nfs_xdev_mount_common(struct file_system_type *, int,
 		const char *, struct nfs_mount_info *);
 void nfs_kill_super(struct super_block *);
 void nfs_fill_super(struct super_block *, struct nfs_mount_info *);
+void nfs_clone_super(struct super_block *, struct nfs_mount_info *);
 
 extern struct rpc_stat nfs_rpcstat;
 
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 9287eb666322..7c78e6956639 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -19,6 +19,7 @@
 #include <linux/vfs.h>
 #include <linux/sunrpc/gss_api.h>
 #include "internal.h"
+#include "nfs.h"
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
 
@@ -210,16 +211,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
@@ -231,13 +222,20 @@ 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 super_block *sb = dentry->d_sb;
 	struct nfs_clone_mount mountdata = {
-		.sb = dentry->d_sb,
+		.sb = sb,
 		.dentry = dentry,
-		.fh = fh,
-		.fattr = fattr,
 		.authflavor = authflavor,
 	};
+	struct nfs_mount_info mount_info = {
+		.fill_super = nfs_clone_super,
+		.set_security = nfs_clone_sb_security,
+		.cloned = &mountdata,
+		.mntfh = fh,
+	};
+	struct nfs_subversion *nfs_mod = NFS_SB(sb)->nfs_client->cl_nfs_mod;
+	struct nfs_server *server;
 	struct vfsmount *mnt;
 	char *page = (char *) __get_free_page(GFP_USER);
 	char *devname;
@@ -245,12 +243,21 @@ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
 	if (page == NULL)
 		return ERR_PTR(-ENOMEM);
 
+	server = nfs_mod->rpc_ops->clone_server(NFS_SB(sb), fh,
+						fattr, authflavor);
+	if (IS_ERR(server))
+		return ERR_CAST(server);
+
+	mount_info.server = server;
+
 	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_submount(dentry, &nfs_xdev_fs_type, devname, &mount_info);
 
+	if (mount_info.server)
+		nfs_free_server(mount_info.server);
 	free_page((unsigned long)page);
 	return mnt;
 }
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 10544ef8de57..7fc354207347 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2386,7 +2386,7 @@ EXPORT_SYMBOL_GPL(nfs_fill_super);
 /*
  * Finish setting up a cloned NFS2/3/4 superblock
  */
-static void nfs_clone_super(struct super_block *sb,
+void nfs_clone_super(struct super_block *sb,
 			    struct nfs_mount_info *mount_info)
 {
 	const struct super_block *old_sb = mount_info->cloned->sb;
@@ -2771,27 +2771,10 @@ 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 dentry *mntroot = ERR_PTR(-ENOMEM);
-	struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod;
-
-	dprintk("--> nfs_xdev_mount()\n");
+	struct nfs_mount_info *info = raw_data;
+	struct nfs_subversion *nfs_mod = NFS_SB(info->cloned->sb)->nfs_client->cl_nfs_mod;
 
-	mount_info.mntfh = mount_info.cloned->fh;
-
-	/* create a new volume representation */
-	mount_info.server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor);
-
-	mntroot = nfs_fs_mount_common(flags, dev_name, &mount_info, nfs_mod);
-
-	dprintk("<-- nfs_xdev_mount() = %ld\n",
-			IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L);
-	return mntroot;
+	return nfs_fs_mount_common(flags, dev_name, info, nfs_mod);
 }
 
 #if IS_ENABLED(CONFIG_NFS_V4)
-- 
2.17.2


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

* [PATCH v3 08/26] nfs: stash nfs_subversion reference into nfs_mount_info
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (6 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 07/26] nfs: lift setting mount_info from nfs_xdev_mount() Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 09/26] nfs: don't bother passing nfs_subversion to ->try_mount() and nfs_fs_mount_common() Scott Mayhew
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

That will allow to get rid of passing those references around in
quite a few places.  Moreover, that will allow to merge xdev and
remote file_system_type.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/internal.h  | 1 +
 fs/nfs/namespace.c | 6 +++---
 fs/nfs/nfs4super.c | 1 +
 fs/nfs/super.c     | 1 +
 4 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index eeb54b45875c..0c42cf685d4b 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -150,6 +150,7 @@ struct nfs_mount_info {
 	struct nfs_clone_mount *cloned;
 	struct nfs_server *server;
 	struct nfs_fh *mntfh;
+	struct nfs_subversion *nfs_mod;
 };
 
 extern int nfs_mount(struct nfs_mount_request *info);
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 7c78e6956639..0d0587ed7d94 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -233,8 +233,8 @@ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
 		.set_security = nfs_clone_sb_security,
 		.cloned = &mountdata,
 		.mntfh = fh,
+		.nfs_mod = NFS_SB(sb)->nfs_client->cl_nfs_mod,
 	};
-	struct nfs_subversion *nfs_mod = NFS_SB(sb)->nfs_client->cl_nfs_mod;
 	struct nfs_server *server;
 	struct vfsmount *mnt;
 	char *page = (char *) __get_free_page(GFP_USER);
@@ -243,8 +243,8 @@ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
 	if (page == NULL)
 		return ERR_PTR(-ENOMEM);
 
-	server = nfs_mod->rpc_ops->clone_server(NFS_SB(sb), fh,
-						fattr, authflavor);
+	server = mount_info.nfs_mod->rpc_ops->clone_server(NFS_SB(sb), fh,
+							   fattr, authflavor);
 	if (IS_ERR(server))
 		return ERR_CAST(server);
 
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 91ba1b6741dc..88d83cab8e9b 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -248,6 +248,7 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
 		.fill_super = nfs_fill_super,
 		.set_security = nfs_clone_sb_security,
 		.cloned = data,
+		.nfs_mod = &nfs_v4,
 	};
 	struct dentry *res;
 
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 7fc354207347..2a6b4e4b0a2d 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2736,6 +2736,7 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
 		mntroot = ERR_CAST(nfs_mod);
 		goto out;
 	}
+	mount_info.nfs_mod = nfs_mod;
 
 	mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info, nfs_mod);
 
-- 
2.17.2


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

* [PATCH v3 09/26] nfs: don't bother passing nfs_subversion to ->try_mount() and nfs_fs_mount_common()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (7 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 08/26] nfs: stash nfs_subversion reference into nfs_mount_info Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 10/26] nfs: merge xdev and remote file_system_type Scott Mayhew
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/internal.h       |  6 ++----
 fs/nfs/nfs4_fs.h        |  2 +-
 fs/nfs/nfs4super.c      |  5 ++---
 fs/nfs/super.c          | 19 ++++++++-----------
 include/linux/nfs_xdr.h |  3 +--
 5 files changed, 14 insertions(+), 21 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 0c42cf685d4b..3334d0f3ecf9 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -401,12 +401,10 @@ extern struct file_system_type nfs_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 *);
+struct dentry *nfs_try_mount(int, const char *, struct nfs_mount_info *);
 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(int, const char *,
-				   struct nfs_mount_info *, struct nfs_subversion *);
+struct dentry *nfs_fs_mount_common(int, const char *, struct nfs_mount_info *);
 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 *);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 3564da1ba8a1..67ecd7bb512f 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -517,7 +517,7 @@ extern const nfs4_stateid invalid_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 *);
+struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *);
 extern bool nfs4_disable_idmapping;
 extern unsigned short max_session_slots;
 extern unsigned short max_session_cb_slots;
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 88d83cab8e9b..83bca2ea566c 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -98,7 +98,7 @@ static struct dentry *
 nfs4_remote_mount(struct file_system_type *fs_type, int flags,
 		  const char *dev_name, void *info)
 {
-	return nfs_fs_mount_common(flags, dev_name, info, &nfs_v4);
+	return nfs_fs_mount_common(flags, dev_name, info);
 }
 
 struct nfs_referral_count {
@@ -216,8 +216,7 @@ static struct dentry *do_nfs4_mount(struct nfs_server *server, int flags,
 }
 
 struct dentry *nfs4_try_mount(int flags, const char *dev_name,
-			      struct nfs_mount_info *mount_info,
-			      struct nfs_subversion *nfs_mod)
+			      struct nfs_mount_info *mount_info)
 {
 	struct nfs_parsed_mount_data *data = mount_info->parsed;
 	struct dentry *res;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 2a6b4e4b0a2d..ca6295945880 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1893,15 +1893,15 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 }
 
 struct dentry *nfs_try_mount(int flags, const char *dev_name,
-			     struct nfs_mount_info *mount_info,
-			     struct nfs_subversion *nfs_mod)
+			     struct nfs_mount_info *mount_info)
 {
+	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
 	if (mount_info->parsed->need_mount)
 		mount_info->server = nfs_try_mount_request(mount_info, nfs_mod);
 	else
 		mount_info->server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
 
-	return nfs_fs_mount_common(flags, dev_name, mount_info, nfs_mod);
+	return nfs_fs_mount_common(flags, dev_name, mount_info);
 }
 EXPORT_SYMBOL_GPL(nfs_try_mount);
 
@@ -2623,8 +2623,7 @@ int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
 EXPORT_SYMBOL_GPL(nfs_clone_sb_security);
 
 struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
-				   struct nfs_mount_info *mount_info,
-				   struct nfs_subversion *nfs_mod)
+				   struct nfs_mount_info *mount_info)
 {
 	struct super_block *s;
 	struct dentry *mntroot = ERR_PTR(-ENOMEM);
@@ -2652,7 +2651,8 @@ struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 			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);
+	s = sget(mount_info->nfs_mod->nfs_fs, compare_super, nfs_set_super,
+		 flags, &sb_mntdata);
 	if (IS_ERR(s)) {
 		mntroot = ERR_CAST(s);
 		goto out_err_nosb;
@@ -2738,7 +2738,7 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
 	}
 	mount_info.nfs_mod = nfs_mod;
 
-	mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info, nfs_mod);
+	mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info);
 
 	put_nfs_version(nfs_mod);
 out:
@@ -2772,10 +2772,7 @@ static struct dentry *
 nfs_xdev_mount(struct file_system_type *fs_type, int flags,
 		const char *dev_name, void *raw_data)
 {
-	struct nfs_mount_info *info = raw_data;
-	struct nfs_subversion *nfs_mod = NFS_SB(info->cloned->sb)->nfs_client->cl_nfs_mod;
-
-	return nfs_fs_mount_common(flags, dev_name, info, nfs_mod);
+	return nfs_fs_mount_common(flags, dev_name, raw_data);
 }
 
 #if IS_ENABLED(CONFIG_NFS_V4)
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 9b8324ec08f3..4fdf4a523185 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1638,8 +1638,7 @@ struct nfs_rpc_ops {
 			    struct nfs_fsinfo *);
 	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 *);
+	struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *);
 	int	(*getattr) (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fattr *, struct nfs4_label *,
 			    struct inode *);
-- 
2.17.2


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

* [PATCH v3 10/26] nfs: merge xdev and remote file_system_type
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (8 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 09/26] nfs: don't bother passing nfs_subversion to ->try_mount() and nfs_fs_mount_common() Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 11/26] nfs: unexport nfs_fs_mount_common() Scott Mayhew
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

they are identical now...

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/internal.h  |  2 +-
 fs/nfs/namespace.c |  2 +-
 fs/nfs/nfs4super.c | 22 +---------------------
 fs/nfs/super.c     | 14 ++++++++------
 4 files changed, 11 insertions(+), 29 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 3334d0f3ecf9..ac3478827a83 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -396,7 +396,7 @@ extern int nfs_wait_atomic_killable(atomic_t *p, unsigned int mode);
 /* 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;
+extern struct file_system_type nfs_prepared_fs_type;
 #if IS_ENABLED(CONFIG_NFS_V4)
 extern struct file_system_type nfs4_referral_fs_type;
 #endif
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 0d0587ed7d94..970f92a860ed 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -254,7 +254,7 @@ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
 	if (IS_ERR(devname))
 		mnt = ERR_CAST(devname);
 	else
-		mnt = vfs_submount(dentry, &nfs_xdev_fs_type, devname, &mount_info);
+		mnt = vfs_submount(dentry, &nfs_prepared_fs_type, devname, &mount_info);
 
 	if (mount_info.server)
 		nfs_free_server(mount_info.server);
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 83bca2ea566c..5bca30f704e4 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -18,19 +18,9 @@
 
 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 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,
-};
-
 struct file_system_type nfs4_referral_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "nfs4",
@@ -91,16 +81,6 @@ static void nfs4_evict_inode(struct inode *inode)
 	nfs_clear_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)
-{
-	return nfs_fs_mount_common(flags, dev_name, info);
-}
-
 struct nfs_referral_count {
 	struct list_head list;
 	const struct task_struct *task;
@@ -194,7 +174,7 @@ static struct dentry *do_nfs4_mount(struct nfs_server *server, int flags,
 	else
 		snprintf(root_devname, len, "%s:/", hostname);
 	info->server = server;
-	root_mnt = vfs_kern_mount(&nfs4_remote_fs_type, flags, root_devname, info);
+	root_mnt = vfs_kern_mount(&nfs_prepared_fs_type, flags, root_devname, info);
 	if (info->server)
 		nfs_free_server(info->server);
 	info->server = NULL;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index ca6295945880..d80992d2b6fe 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -293,7 +293,7 @@ static match_table_t nfs_vers_tokens = {
 	{ Opt_vers_err, NULL }
 };
 
-static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type,
+static struct dentry *nfs_prepared_mount(struct file_system_type *fs_type,
 		int flags, const char *dev_name, void *raw_data);
 
 struct file_system_type nfs_fs_type = {
@@ -306,13 +306,14 @@ struct file_system_type nfs_fs_type = {
 MODULE_ALIAS_FS("nfs");
 EXPORT_SYMBOL_GPL(nfs_fs_type);
 
-struct file_system_type nfs_xdev_fs_type = {
+struct file_system_type nfs_prepared_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "nfs",
-	.mount		= nfs_xdev_mount,
+	.mount		= nfs_prepared_mount,
 	.kill_sb	= nfs_kill_super,
 	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
 };
+EXPORT_SYMBOL_GPL(nfs_prepared_fs_type);
 
 const struct super_operations nfs_sops = {
 	.alloc_inode	= nfs_alloc_inode,
@@ -2766,11 +2767,12 @@ 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)
+ * Internal use only: mount_info is already set up by caller.
+ * Used for mountpoint crossings and for nfs4 root.
  */
 static struct dentry *
-nfs_xdev_mount(struct file_system_type *fs_type, int flags,
-		const char *dev_name, void *raw_data)
+nfs_prepared_mount(struct file_system_type *fs_type, int flags,
+		   const char *dev_name, void *raw_data)
 {
 	return nfs_fs_mount_common(flags, dev_name, raw_data);
 }
-- 
2.17.2


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

* [PATCH v3 11/26] nfs: unexport nfs_fs_mount_common()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (9 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 10/26] nfs: merge xdev and remote file_system_type Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 12/26] nfs: don't pass nfs_subversion to ->create_server() Scott Mayhew
                   ` (14 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

Make it static, even.  And remove a stale extern of (long-gone)
nfs_xdev_mount_common() from internal.h, while we are at it.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/internal.h | 3 ---
 fs/nfs/super.c    | 5 +++--
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index ac3478827a83..207d1574e246 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -404,10 +404,7 @@ 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 *);
 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(int, const char *, struct nfs_mount_info *);
 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 *);
 void nfs_kill_super(struct super_block *);
 void nfs_fill_super(struct super_block *, struct nfs_mount_info *);
 void nfs_clone_super(struct super_block *, struct nfs_mount_info *);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index d80992d2b6fe..c3ee83c17f07 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1893,6 +1893,8 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 	return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
 }
 
+static struct dentry *nfs_fs_mount_common(int, const char *, struct nfs_mount_info *);
+
 struct dentry *nfs_try_mount(int flags, const char *dev_name,
 			     struct nfs_mount_info *mount_info)
 {
@@ -2623,7 +2625,7 @@ int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
 }
 EXPORT_SYMBOL_GPL(nfs_clone_sb_security);
 
-struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
+static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 				   struct nfs_mount_info *mount_info)
 {
 	struct super_block *s;
@@ -2705,7 +2707,6 @@ struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 	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)
-- 
2.17.2


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

* [PATCH v3 12/26] nfs: don't pass nfs_subversion to ->create_server()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (10 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 11/26] nfs: unexport nfs_fs_mount_common() Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 13/26] nfs: get rid of mount_info ->fill_super() Scott Mayhew
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

pick it from mount_info

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/client.c         |  4 ++--
 fs/nfs/internal.h       |  7 ++-----
 fs/nfs/nfs3_fs.h        |  2 +-
 fs/nfs/nfs3client.c     |  5 ++---
 fs/nfs/nfs4client.c     |  3 +--
 fs/nfs/nfs4super.c      |  2 +-
 fs/nfs/super.c          | 14 +++++++-------
 include/linux/nfs_xdr.h |  2 +-
 8 files changed, 17 insertions(+), 22 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 30838304a0bf..130c065141b3 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -940,10 +940,10 @@ 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_mount_info *mount_info)
 {
 	struct nfs_server *server;
+	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
 	struct nfs_fattr *fattr;
 	int error;
 
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 207d1574e246..444d0fc2bcca 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -178,11 +178,8 @@ 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 *nfs_create_server(struct nfs_mount_info *);
+extern struct nfs_server *nfs4_create_server(struct nfs_mount_info *);
 extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
 						      struct nfs_fh *);
 extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
diff --git a/fs/nfs/nfs3_fs.h b/fs/nfs/nfs3_fs.h
index f82e11c4cb56..09602dc1889f 100644
--- a/fs/nfs/nfs3_fs.h
+++ b/fs/nfs/nfs3_fs.h
@@ -27,7 +27,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_mount_info *);
 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 148ceb74d27c..a340b5d0e1a3 100644
--- a/fs/nfs/nfs3client.c
+++ b/fs/nfs/nfs3client.c
@@ -46,10 +46,9 @@ 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_mount_info *mount_info)
 {
-	struct nfs_server *server = nfs_create_server(mount_info, nfs_mod);
+	struct nfs_server *server = nfs_create_server(mount_info);
 	/* 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/nfs4client.c b/fs/nfs/nfs4client.c
index da6204025a2d..16fba83b5c4b 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1109,8 +1109,7 @@ static int nfs4_init_server(struct nfs_server *server,
  */
 /*struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *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_mount_info *mount_info)
 {
 	struct nfs_server *server;
 	bool auth_probe;
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 5bca30f704e4..b6cf62125380 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -205,7 +205,7 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 
 	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
-	res = do_nfs4_mount(nfs4_create_server(mount_info, &nfs_v4),
+	res = do_nfs4_mount(nfs4_create_server(mount_info),
 			    flags, mount_info,
 			    data->nfs_server.hostname,
 			    data->nfs_server.export_path);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index c3ee83c17f07..157d340333c8 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1820,8 +1820,7 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args,
 	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_mount_info *mount_info)
 {
 	int status;
 	unsigned int i;
@@ -1831,6 +1830,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 	struct nfs_parsed_mount_data *args = mount_info->parsed;
 	rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS];
 	unsigned int authlist_len = ARRAY_SIZE(authlist);
+	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
 
 	status = nfs_request_mount(args, mount_info->mntfh, authlist,
 					&authlist_len);
@@ -1847,7 +1847,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 			 args->selected_flavor);
 		if (status)
 			return ERR_PTR(status);
-		return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+		return nfs_mod->rpc_ops->create_server(mount_info);
 	}
 
 	/*
@@ -1874,7 +1874,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);
 		args->selected_flavor = flavor;
-		server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+		server = nfs_mod->rpc_ops->create_server(mount_info);
 		if (!IS_ERR(server))
 			return server;
 	}
@@ -1890,7 +1890,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;
-	return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+	return nfs_mod->rpc_ops->create_server(mount_info);
 }
 
 static struct dentry *nfs_fs_mount_common(int, const char *, struct nfs_mount_info *);
@@ -1900,9 +1900,9 @@ struct dentry *nfs_try_mount(int flags, const char *dev_name,
 {
 	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
 	if (mount_info->parsed->need_mount)
-		mount_info->server = nfs_try_mount_request(mount_info, nfs_mod);
+		mount_info->server = nfs_try_mount_request(mount_info);
 	else
-		mount_info->server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+		mount_info->server = nfs_mod->rpc_ops->create_server(mount_info);
 
 	return nfs_fs_mount_common(flags, dev_name, mount_info);
 }
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 4fdf4a523185..82bdb91da2ae 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1705,7 +1705,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_mount_info *);
 	struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
 					   struct nfs_fattr *, rpc_authflavor_t);
 };
-- 
2.17.2


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

* [PATCH v3 13/26] nfs: get rid of mount_info ->fill_super()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (11 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 12/26] nfs: don't pass nfs_subversion to ->create_server() Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 14/26] nfs_clone_sb_security(): simplify the check for server bogosity Scott Mayhew
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

The only possible values are nfs_fill_super and nfs_clone_super.  The
latter is used only when crossing into a submount and it is almost
identical to the former; the only differences are
	* ->s_time_gran unconditionally set to 1 (even for v2 mounts).
Regression dating back to 2012, actually.
	* ->s_blocksize/->s_blocksize_bits set to that of parent.

Rather than messing with the method, stash ->s_blocksize_bits in
mount_info in submount case and after the (now unconditional)
call of nfs_fill_super() override ->s_blocksize/->s_blocksize_bits
if that has been set.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/internal.h  |  4 +--
 fs/nfs/namespace.c |  2 +-
 fs/nfs/nfs4super.c |  1 -
 fs/nfs/super.c     | 66 +++++++++++-----------------------------------
 4 files changed, 18 insertions(+), 55 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 444d0fc2bcca..fa737e37f7c9 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -144,7 +144,7 @@ struct nfs_mount_request {
 };
 
 struct nfs_mount_info {
-	void (*fill_super)(struct super_block *, struct nfs_mount_info *);
+	unsigned int inherited_bsize;
 	int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *);
 	struct nfs_parsed_mount_data *parsed;
 	struct nfs_clone_mount *cloned;
@@ -403,8 +403,6 @@ int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_
 int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
 struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *);
 void nfs_kill_super(struct super_block *);
-void nfs_fill_super(struct super_block *, struct nfs_mount_info *);
-void nfs_clone_super(struct super_block *, struct nfs_mount_info *);
 
 extern struct rpc_stat nfs_rpcstat;
 
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 970f92a860ed..7bc5b9b8f5ea 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -229,7 +229,7 @@ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
 		.authflavor = authflavor,
 	};
 	struct nfs_mount_info mount_info = {
-		.fill_super = nfs_clone_super,
+		.inherited_bsize = sb->s_blocksize_bits,
 		.set_security = nfs_clone_sb_security,
 		.cloned = &mountdata,
 		.mntfh = fh,
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index b6cf62125380..d387c3c3b600 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -224,7 +224,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
 {
 	struct nfs_clone_mount *data = raw_data;
 	struct nfs_mount_info mount_info = {
-		.fill_super = nfs_fill_super,
 		.set_security = nfs_clone_sb_security,
 		.cloned = data,
 		.nfs_mod = &nfs_v4,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 157d340333c8..89751ce21110 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2339,29 +2339,9 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 EXPORT_SYMBOL_GPL(nfs_remount);
 
 /*
- * Initialise the common bits of the superblock
+ * Finish setting up an NFS superblock
  */
-static void nfs_initialise_sb(struct super_block *sb)
-{
-	struct nfs_server *server = NFS_SB(sb);
-
-	sb->s_magic = NFS_SUPER_MAGIC;
-
-	/* We probably want something more informative here */
-	snprintf(sb->s_id, sizeof(sb->s_id),
-		 "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev));
-
-	if (sb->s_blocksize == 0)
-		sb->s_blocksize = nfs_block_bits(server->wsize,
-						 &sb->s_blocksize_bits);
-
-	nfs_super_set_maxbytes(sb, server->maxfilesize);
-}
-
-/*
- * 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_mount_info *mount_info)
 {
 	struct nfs_parsed_mount_data *data = mount_info->parsed;
 	struct nfs_server *server = NFS_SB(sb);
@@ -2382,35 +2362,17 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
 		sb->s_export_op = &nfs_export_ops;
 	}
 
- 	nfs_initialise_sb(sb);
-}
-EXPORT_SYMBOL_GPL(nfs_fill_super);
-
-/*
- * Finish setting up a cloned NFS2/3/4 superblock
- */
-void nfs_clone_super(struct super_block *sb,
-			    struct nfs_mount_info *mount_info)
-{
-	const struct super_block *old_sb = mount_info->cloned->sb;
-	struct nfs_server *server = NFS_SB(sb);
+	sb->s_magic = NFS_SUPER_MAGIC;
 
-	sb->s_blocksize_bits = old_sb->s_blocksize_bits;
-	sb->s_blocksize = old_sb->s_blocksize;
-	sb->s_maxbytes = old_sb->s_maxbytes;
-	sb->s_xattr = old_sb->s_xattr;
-	sb->s_op = old_sb->s_op;
-	sb->s_time_gran = 1;
-	sb->s_export_op = old_sb->s_export_op;
+	/* We probably want something more informative here */
+	snprintf(sb->s_id, sizeof(sb->s_id),
+		 "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev));
 
-	if (server->nfs_client->rpc_ops->version != 2) {
-		/* The VFS shouldn't apply the umask to mode bits. We will do
-		 * so ourselves when necessary.
-		 */
-		sb->s_flags |= SB_POSIXACL;
-	}
+	if (sb->s_blocksize == 0)
+		sb->s_blocksize = nfs_block_bits(server->wsize,
+						 &sb->s_blocksize_bits);
 
- 	nfs_initialise_sb(sb);
+	nfs_super_set_maxbytes(sb, server->maxfilesize);
 }
 
 static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
@@ -2676,8 +2638,13 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 	}
 
 	if (!s->s_root) {
+		unsigned bsize = mount_info->inherited_bsize;
 		/* initial superblock/root creation */
-		mount_info->fill_super(s, mount_info);
+		nfs_fill_super(s, mount_info);
+		if (bsize) {
+			s->s_blocksize_bits = bsize;
+			s->s_blocksize = 1U << bsize;
+		}
 		nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned);
 		if (!(server->flags & NFS_MOUNT_UNSHARED))
 			s->s_iflags |= SB_I_MULTIROOT;
@@ -2712,7 +2679,6 @@ 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);
-- 
2.17.2


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

* [PATCH v3 14/26] nfs_clone_sb_security(): simplify the check for server bogosity
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (12 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 13/26] nfs: get rid of mount_info ->fill_super() Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 15/26] nfs: get rid of ->set_security() Scott Mayhew
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

We used to check ->i_op for being nfs_dir_inode_operations.  With
separate inode_operations for v3 and v4 that became bogus, but
rather than going for protocol-dependent comparison we could've
just checked ->i_fop instead; _that_ is the same for all protocol
versions.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/super.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 89751ce21110..6f4983fc3937 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2569,7 +2569,7 @@ int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
 	unsigned long kflags = 0, kflags_out = 0;
 
 	/* 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(mntroot)->i_fop != &nfs_dir_operations)
 		return -ESTALE;
 
 	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
-- 
2.17.2


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

* [PATCH v3 15/26] nfs: get rid of ->set_security()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (13 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 14/26] nfs_clone_sb_security(): simplify the check for server bogosity Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 16/26] NFS: Move mount parameterisation bits into their own file Scott Mayhew
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: Al Viro <viro@zeniv.linux.org.uk>

it's always either nfs_set_sb_security() or nfs_clone_sb_security(),
the choice being controlled by mount_info->cloned != NULL.  No need
to add methods, especially when both instances live right next to
the caller and are never accessed anywhere else.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/internal.h  |  3 --
 fs/nfs/namespace.c |  1 -
 fs/nfs/nfs4super.c |  3 --
 fs/nfs/super.c     | 69 ++++++++++++++--------------------------------
 4 files changed, 21 insertions(+), 55 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index fa737e37f7c9..d512ec394559 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -145,7 +145,6 @@ struct nfs_mount_request {
 
 struct nfs_mount_info {
 	unsigned int inherited_bsize;
-	int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *);
 	struct nfs_parsed_mount_data *parsed;
 	struct nfs_clone_mount *cloned;
 	struct nfs_server *server;
@@ -399,8 +398,6 @@ 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 *);
-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(struct file_system_type *, int, const char *, void *);
 void nfs_kill_super(struct super_block *);
 
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 7bc5b9b8f5ea..72a99f9c7390 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -230,7 +230,6 @@ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
 	};
 	struct nfs_mount_info mount_info = {
 		.inherited_bsize = sb->s_blocksize_bits,
-		.set_security = nfs_clone_sb_security,
 		.cloned = &mountdata,
 		.mntfh = fh,
 		.nfs_mod = NFS_SB(sb)->nfs_client->cl_nfs_mod,
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index d387c3c3b600..38f2eec7e1ad 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -201,8 +201,6 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 	struct nfs_parsed_mount_data *data = mount_info->parsed;
 	struct dentry *res;
 
-	mount_info->set_security = nfs_set_sb_security;
-
 	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
 	res = do_nfs4_mount(nfs4_create_server(mount_info),
@@ -224,7 +222,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
 {
 	struct nfs_clone_mount *data = raw_data;
 	struct nfs_mount_info mount_info = {
-		.set_security = nfs_clone_sb_security,
 		.cloned = data,
 		.nfs_mod = &nfs_v4,
 	};
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 6f4983fc3937..d8702e57f7fc 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2541,52 +2541,6 @@ static void nfs_get_cache_cookie(struct super_block *sb,
 }
 #endif
 
-int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
-			struct nfs_mount_info *mount_info)
-{
-	int error;
-	unsigned long kflags = 0, kflags_out = 0;
-	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,
-						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;
-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 error;
-	unsigned long kflags = 0, kflags_out = 0;
-
-	/* clone any lsm security options from the parent to the new sb */
-	if (d_inode(mntroot)->i_fop != &nfs_dir_operations)
-		return -ESTALE;
-
-	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
-		kflags |= SECURITY_LSM_NATIVE_LABELS;
-
-	error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags,
-			&kflags_out);
-	if (error)
-		return error;
-
-	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
-		!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
-		NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nfs_clone_sb_security);
-
 static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 				   struct nfs_mount_info *mount_info)
 {
@@ -2594,6 +2548,7 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 	struct dentry *mntroot = ERR_PTR(-ENOMEM);
 	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
 	struct nfs_server *server = mount_info->server;
+	unsigned long kflags = 0, kflags_out = 0;
 	struct nfs_sb_mountdata sb_mntdata = {
 		.mntflags = flags,
 		.server = server,
@@ -2654,7 +2609,26 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 	if (IS_ERR(mntroot))
 		goto error_splat_super;
 
-	error = mount_info->set_security(s, mntroot, mount_info);
+
+	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
+		kflags |= SECURITY_LSM_NATIVE_LABELS;
+	if (mount_info->cloned) {
+		if (d_inode(mntroot)->i_fop != &nfs_dir_operations) {
+			error = -ESTALE;
+			goto error_splat_root;
+		}
+		/* clone any lsm security options from the parent to the new sb */
+		error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags,
+				&kflags_out);
+	} else {
+		error = security_sb_set_mnt_opts(s, mount_info->parsed->lsm_opts,
+							kflags, &kflags_out);
+	}
+	if (error)
+		goto error_splat_root;
+	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
+		!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
+		NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
 	if (error)
 		goto error_splat_root;
 
@@ -2679,7 +2653,6 @@ 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 = {
-		.set_security = nfs_set_sb_security,
 	};
 	struct dentry *mntroot = ERR_PTR(-ENOMEM);
 	struct nfs_subversion *nfs_mod;
-- 
2.17.2


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

* [PATCH v3 16/26] NFS: Move mount parameterisation bits into their own file
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (14 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 15/26] nfs: get rid of ->set_security() Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 18:24   ` Chuck Lever
  2019-09-11 16:16 ` [PATCH v3 17/26] NFS: Constify mount argument match tables Scott Mayhew
                   ` (9 subsequent siblings)
  25 siblings, 1 reply; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: David Howells <dhowells@redhat.com>

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>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/Makefile     |    2 +-
 fs/nfs/fs_context.c | 1418 +++++++++++++++++++++++++++++++++++++++++++
 fs/nfs/internal.h   |   29 +
 fs/nfs/super.c      | 1411 ------------------------------------------
 4 files changed, 1448 insertions(+), 1412 deletions(-)
 create mode 100644 fs/nfs/fs_context.c

diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 34cdeaecccf6..2433c3e03cfa 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -9,7 +9,7 @@ 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 \
-			   export.o sysfs.o
+			   export.o sysfs.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..82b312a5cdde
--- /dev/null
+++ b/fs/nfs/fs_context.c
@@ -0,0 +1,1418 @@
+/* NFS mount handling.
+ *
+ * Copyright (C) 2018 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
+
+#define NFS_MAX_CONNECTIONS 16
+
+enum {
+	/* Mount options that take no arguments */
+	Opt_soft, Opt_softerr, 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_nconnect,
+	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_softerr, "softerr" },
+	{ 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_nconnect, "nconnect=%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;
+		data->lsm_opts		= NULL;
+	}
+	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;
+	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);
+
+	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
+	if (rc)
+		goto out_security_failure;
+
+	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;
+			mnt->flags &= ~NFS_MOUNT_SOFTERR;
+			break;
+		case Opt_softerr:
+			mnt->flags |= NFS_MOUNT_SOFTERR;
+			mnt->flags &= ~NFS_MOUNT_SOFT;
+			break;
+		case Opt_hard:
+			mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
+			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;
+				/* fall through */
+			case Opt_xprt_udp:
+				mnt->flags &= ~NFS_MOUNT_TCP;
+				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+				break;
+			case Opt_xprt_tcp6:
+				protofamily = AF_INET6;
+				/* fall through */
+			case Opt_xprt_tcp:
+				mnt->flags |= NFS_MOUNT_TCP;
+				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+				break;
+			case Opt_xprt_rdma6:
+				protofamily = AF_INET6;
+				/* fall through */
+			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;
+				/* fall through */
+			case Opt_xprt_udp:
+				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+				break;
+			case Opt_xprt_tcp6:
+				mountfamily = AF_INET6;
+				/* fall through */
+			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_nconnect:
+			if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
+				goto out_invalid_value;
+			mnt->nfs_server.nconnect = option;
+			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:
+	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;
+
+	if (unlikely(!dev_name || !*dev_name)) {
+		dfprintk(MOUNT, "NFS: device name not specified\n");
+		return -EINVAL;
+	}
+
+	/* 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)
+			len = comma - dev_name;
+	}
+
+	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; /* fall through */
+	case 2:
+		data->bsize = 0; /* fall through */
+	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;
+		/* fall through */
+	case 4:
+		if (data->flags & NFS_MOUNT_SECFLAVOUR)
+			goto out_no_sec;
+		/* fall through */
+	case 5:
+		memset(data->context, 0, sizeof(data->context));
+		/* fall through */
+	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 (sap->sa_family != AF_INET ||
+		    !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;
+			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
+			rc = security_add_mnt_opt("context", data->context,
+					strlen(data->context), &args->lsm_opts);
+			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)
+		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+			port = NFS_RDMA_PORT;
+		else
+			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);
+		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+			port = NFS_RDMA_PORT;
+	}
+
+	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 d512ec394559..b66fd35993b3 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -7,6 +7,7 @@
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/crc32.h>
+#include <linux/sunrpc/addr.h>
 #include <linux/nfs_page.h>
 #include <linux/wait_bit.h>
 
@@ -232,6 +233,22 @@ extern const struct svc_version nfs4_callback_version1;
 extern const 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);
@@ -763,3 +780,15 @@ static inline bool nfs_error_is_fatal(int err)
 	}
 }
 
+/*
+ * 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 d8702e57f7fc..886220d2da4e 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -69,229 +69,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
-
-#define NFS_MAX_CONNECTIONS 16
-
-enum {
-	/* Mount options that take no arguments */
-	Opt_soft, Opt_softerr, 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_nconnect,
-	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_softerr, "softerr" },
-	{ 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_nconnect, "nconnect=%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_prepared_mount(struct file_system_type *fs_type,
 		int flags, const char *dev_name, void *raw_data);
@@ -332,10 +109,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",
@@ -932,141 +705,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;
-		data->lsm_opts		= NULL;
-	}
-	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.
@@ -1087,627 +725,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;
-	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);
-
-	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
-	if (rc)
-		goto out_security_failure;
-
-	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;
-			mnt->flags &= ~NFS_MOUNT_SOFTERR;
-			break;
-		case Opt_softerr:
-			mnt->flags |= NFS_MOUNT_SOFTERR;
-			mnt->flags &= ~NFS_MOUNT_SOFT;
-			break;
-		case Opt_hard:
-			mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
-			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;
-				/* fall through */
-			case Opt_xprt_udp:
-				mnt->flags &= ~NFS_MOUNT_TCP;
-				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
-				break;
-			case Opt_xprt_tcp6:
-				protofamily = AF_INET6;
-				/* fall through */
-			case Opt_xprt_tcp:
-				mnt->flags |= NFS_MOUNT_TCP;
-				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
-				break;
-			case Opt_xprt_rdma6:
-				protofamily = AF_INET6;
-				/* fall through */
-			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;
-				/* fall through */
-			case Opt_xprt_udp:
-				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
-				break;
-			case Opt_xprt_tcp6:
-				mountfamily = AF_INET6;
-				/* fall through */
-			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_nconnect:
-			if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
-				goto out_invalid_value;
-			mnt->nfs_server.nconnect = option;
-			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:
-	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
@@ -1908,327 +925,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;
-
-	if (unlikely(!dev_name || !*dev_name)) {
-		dfprintk(MOUNT, "NFS: device name not specified\n");
-		return -EINVAL;
-	}
-
-	/* 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)
-			len = comma - dev_name;
-	}
-
-	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; /* fall through */
-	case 2:
-		data->bsize = 0; /* fall through */
-	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;
-		/* fall through */
-	case 4:
-		if (data->flags & NFS_MOUNT_SECFLAVOUR)
-			goto out_no_sec;
-		/* fall through */
-	case 5:
-		memset(data->context, 0, sizeof(data->context));
-		/* fall through */
-	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 (sap->sa_family != AF_INET ||
-		    !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;
-			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
-			rc = security_add_mnt_opt("context", data->context,
-					strlen(data->context), &args->lsm_opts);
-			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)
-		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
-			port = NFS_RDMA_PORT;
-		else
-			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);
-		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
-			port = NFS_RDMA_PORT;
-	}
-
-	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 \
@@ -2719,113 +1415,6 @@ nfs_prepared_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
-- 
2.17.2


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

* [PATCH v3 17/26] NFS: Constify mount argument match tables
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (15 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 16/26] NFS: Move mount parameterisation bits into their own file Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 18/26] NFS: Rename struct nfs_parsed_mount_data to struct nfs_fs_context Scott Mayhew
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: David Howells <dhowells@redhat.com>

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

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 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 82b312a5cdde..967c684b26d2 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -203,7 +203,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" },
@@ -219,7 +219,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" },
@@ -235,7 +235,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" },
-- 
2.17.2


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

* [PATCH v3 18/26] NFS: Rename struct nfs_parsed_mount_data to struct nfs_fs_context
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (16 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 17/26] NFS: Constify mount argument match tables Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 19/26] NFS: Split nfs_parse_mount_options() Scott Mayhew
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: David Howells <dhowells@redhat.com>

Rename struct nfs_parsed_mount_data to struct nfs_fs_context and rename
pointers to it to "ctx".  At some point this will be pointed to by an
fs_context struct's fs_private pointer.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/client.c     |  66 +++----
 fs/nfs/fs_context.c | 446 ++++++++++++++++++++++----------------------
 fs/nfs/internal.h   |  14 +-
 fs/nfs/nfs4client.c |  60 +++---
 fs/nfs/nfs4super.c  |   6 +-
 fs/nfs/super.c      | 194 +++++++++----------
 6 files changed, 393 insertions(+), 393 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 130c065141b3..1afd796a3706 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -648,27 +648,27 @@ 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,
 		.cred = server->cred,
-		.nconnect = data->nfs_server.nconnect,
+		.nconnect = cfg->nfs_server.nconnect,
 	};
 	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 */
@@ -679,46 +679,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:
@@ -959,7 +959,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;
 
@@ -970,7 +970,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 967c684b26d2..5357430416d7 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -246,40 +246,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;
-		data->lsm_opts		= NULL;
+	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;
+		ctx->lsm_opts = NULL;
 	}
-	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);
 	}
 }
 
@@ -310,15 +310,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;
 	}
 }
 
@@ -326,20 +326,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;
 	}
 }
 
@@ -371,8 +371,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;
@@ -421,7 +420,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;
 	}
 
@@ -429,36 +428,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;
@@ -506,7 +505,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;
 	int rc, sloppy = 0, invalid_option = 0;
@@ -519,7 +518,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 	}
 	dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
 
-	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
+	rc = security_sb_eat_lsm_opts(raw, &ctx->lsm_opts);
 	if (rc)
 		goto out_security_failure;
 
@@ -540,96 +539,96 @@ 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;
-			mnt->flags &= ~NFS_MOUNT_SOFTERR;
+			ctx->flags |= NFS_MOUNT_SOFT;
+			ctx->flags &= ~NFS_MOUNT_SOFTERR;
 			break;
 		case Opt_softerr:
-			mnt->flags |= NFS_MOUNT_SOFTERR;
-			mnt->flags &= ~NFS_MOUNT_SOFT;
+			ctx->flags |= NFS_MOUNT_SOFTERR;
+			ctx->flags &= ~NFS_MOUNT_SOFT;
 			break;
 		case Opt_hard:
-			mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
+			ctx->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
 			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;
 
 		/*
@@ -639,83 +638,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;
 
 		/*
@@ -725,7 +724,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;
@@ -734,7 +733,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 "
@@ -755,23 +754,23 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 				protofamily = AF_INET6;
 				/* fall through */
 			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;
 				/* fall through */
 			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;
 				/* fall through */
 			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:
@@ -796,13 +795,13 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
 				mountfamily = AF_INET6;
 				/* fall through */
 			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;
 				/* fall through */
 			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:
@@ -815,41 +814,41 @@ 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_nconnect:
 			if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
 				goto out_invalid_value;
-			mnt->nfs_server.nconnect = option;
+			ctx->nfs_server.nconnect = option;
 			break;
 		case Opt_lookupcache:
 			string = match_strdup(args);
@@ -860,14 +859,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 "
@@ -876,9 +875,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);
@@ -889,17 +888,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:
@@ -932,11 +931,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;
 
 	/*
@@ -944,15 +943,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;
 		}
 	}
@@ -974,7 +973,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
@@ -1082,18 +1081,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; /* fall through */
@@ -1119,10 +1118,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;
 		}
 
 
@@ -1132,47 +1131,47 @@ 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 (sap->sa_family != AF_INET ||
 		    !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
@@ -1187,7 +1186,7 @@ static int nfs23_validate_mount_data(void *options,
 			int rc;
 			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
 			rc = security_add_mnt_opt("context", data->context,
-					strlen(data->context), &args->lsm_opts);
+					strlen(data->context), ctx->lsm_opts);
 			if (rc)
 				return rc;
 #else
@@ -1229,10 +1228,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);
 }
 
@@ -1240,30 +1238,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;
@@ -1273,43 +1271,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;
@@ -1339,67 +1337,67 @@ 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)
-		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+		if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
 			port = NFS_RDMA_PORT;
 		else
 			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);
-		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+		nfs_set_mount_transport_protocol(ctx);
+		if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
 			port = NFS_RDMA_PORT;
 	}
 
-	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 b66fd35993b3..632174d666a8 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -89,7 +89,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;
@@ -146,7 +146,7 @@ struct nfs_mount_request {
 
 struct nfs_mount_info {
 	unsigned int inherited_bsize;
-	struct nfs_parsed_mount_data *parsed;
+	struct nfs_fs_context *ctx;
 	struct nfs_clone_mount *cloned;
 	struct nfs_server *server;
 	struct nfs_fh *mntfh;
@@ -237,16 +237,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 16fba83b5c4b..2ee2281ce404 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1053,61 +1053,61 @@ 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->nfs_server.nconnect,
-			data->net);
+			ctx->minorversion,
+			ctx->nfs_server.nconnect,
+			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)
 {
@@ -1121,10 +1121,10 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info)
 
 	server->cred = get_cred(current_cred());
 
-	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 38f2eec7e1ad..ca9740137cfe 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -198,15 +198,15 @@ static struct dentry *do_nfs4_mount(struct nfs_server *server, int flags,
 struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 			      struct nfs_mount_info *mount_info)
 {
-	struct nfs_parsed_mount_data *data = mount_info->parsed;
+	struct nfs_fs_context *ctx = mount_info->ctx;
 	struct dentry *res;
 
 	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
 	res = do_nfs4_mount(nfs4_create_server(mount_info),
 			    flags, mount_info,
-			    data->nfs_server.hostname,
-			    data->nfs_server.export_path);
+			    ctx->nfs_server.hostname,
+			    ctx->nfs_server.export_path);
 
 	dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n",
 		 PTR_ERR_OR_ZERO(res),
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 886220d2da4e..abd99ed00e39 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -726,12 +726,13 @@ 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,
-			rpc_authflavor_t *server_authlist, unsigned int count)
+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;
 	bool found_auth_null = false;
@@ -752,7 +753,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)
@@ -760,7 +761,7 @@ static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
 	}
 
 	if (found_auth_null) {
-		flavor = args->auth_info.flavors[0];
+		flavor = cfg->auth_info.flavors[0];
 		goto out;
 	}
 
@@ -769,8 +770,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;
 }
 
@@ -778,50 +779,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
@@ -844,12 +845,12 @@ 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);
 	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
 
-	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);
@@ -858,10 +859,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);
@@ -890,7 +891,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);
 		if (!IS_ERR(server))
 			return server;
@@ -906,7 +907,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);
 }
 
@@ -916,7 +917,7 @@ struct dentry *nfs_try_mount(int flags, const char *dev_name,
 			     struct nfs_mount_info *mount_info)
 {
 	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
-	if (mount_info->parsed->need_mount)
+	if (mount_info->ctx->need_mount)
 		mount_info->server = nfs_try_mount_request(mount_info);
 	else
 		mount_info->server = nfs_mod->rpc_ops->create_server(mount_info);
@@ -940,24 +941,24 @@ 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->options & NFS_OPTION_FSCACHE) != (nfss->options & NFS_OPTION_FSCACHE) ||
-	    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->options & NFS_OPTION_FSCACHE) != (nfss->options & NFS_OPTION_FSCACHE) ||
+	    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;
 
@@ -969,7 +970,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;
@@ -987,32 +988,32 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 					   options->version <= 6))))
 		return 0;
 
-	data = nfs_alloc_parsed_mount_data();
-	if (data == NULL)
+	ctx = nfs_alloc_parsed_mount_data();
+	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;
 
 	/*
@@ -1021,15 +1022,15 @@ 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);
 	if (!error)
-		error = security_sb_remount(sb, data->lsm_opts);
+		error = security_sb_remount(sb, ctx->lsm_opts);
 out:
-	nfs_free_parsed_mount_data(data);
+	nfs_free_parsed_mount_data(ctx);
 	return error;
 }
 EXPORT_SYMBOL_GPL(nfs_remount);
@@ -1039,15 +1040,15 @@ EXPORT_SYMBOL_GPL(nfs_remount);
  */
 static 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 +1200,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 +1210,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 +1232,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)
 {
 }
@@ -1296,7 +1297,7 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 			s->s_blocksize_bits = bsize;
 			s->s_blocksize = 1U << bsize;
 		}
-		nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned);
+		nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned);
 		if (!(server->flags & NFS_MOUNT_UNSHARED))
 			s->s_iflags |= SB_I_MULTIROOT;
 	}
@@ -1317,7 +1318,7 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 		error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags,
 				&kflags_out);
 	} else {
-		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)
@@ -1354,21 +1355,22 @@ 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;
@@ -1379,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;
 }
-- 
2.17.2


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

* [PATCH v3 19/26] NFS: Split nfs_parse_mount_options()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (17 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 18/26] NFS: Rename struct nfs_parsed_mount_data to struct nfs_fs_context Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 20/26] NFS: Deindent nfs_fs_context_parse_option() Scott Mayhew
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: David Howells <dhowells@redhat.com>

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>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/fs_context.c | 126 ++++++++++++++++++++++++--------------------
 fs/nfs/internal.h   |   3 ++
 2 files changed, 73 insertions(+), 56 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 5357430416d7..227a85f652b5 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -500,36 +500,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;
-	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);
-
-	rc = security_sb_eat_lsm_opts(raw, &ctx->lsm_opts);
-	if (rc)
-		goto out_security_failure;
+	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);
@@ -738,7 +720,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:
@@ -748,24 +730,24 @@ 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;
 				/* fall through */
 			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;
 				/* fall through */
 			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;
 				/* fall through */
 			case Opt_xprt_rdma:
 				/* vector side protocols to TCP */
@@ -777,7 +759,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;
@@ -789,16 +771,16 @@ 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;
 				/* fall through */
 			case Opt_xprt_udp:
 				ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
 				break;
 			case Opt_xprt_tcp6:
-				mountfamily = AF_INET6;
+				ctx->mountfamily = AF_INET6;
 				/* fall through */
 			case Opt_xprt_tcp:
 				ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
@@ -807,7 +789,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:
@@ -871,7 +853,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:
@@ -904,7 +886,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;
 
@@ -912,7 +894,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:
@@ -922,12 +904,53 @@ 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;
+	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);
+
+	rc = security_sb_eat_lsm_opts(raw, &ctx->lsm_opts);
+	if (rc)
+		goto out_security_failure;
+
+	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;
 
@@ -942,22 +965,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");
@@ -965,23 +992,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;
-out_nomem:
-	printk(KERN_INFO "NFS: not enough memory to parse option\n");
-	return 0;
+	return -EINVAL;
 out_security_failure:
 	printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
 	return 0;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 632174d666a8..d084182f8e43 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -104,7 +104,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;
-- 
2.17.2


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

* [PATCH v3 20/26] NFS: Deindent nfs_fs_context_parse_option()
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (18 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 19/26] NFS: Split nfs_parse_mount_options() Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 21/26] NFS: Add a small buffer in nfs_fs_context to avoid string dup Scott Mayhew
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: David Howells <dhowells@redhat.com>

Deindent nfs_fs_context_parse_option().

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/fs_context.c | 739 ++++++++++++++++++++++----------------------
 1 file changed, 367 insertions(+), 372 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 227a85f652b5..29d50c052ddc 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -504,410 +504,405 @@ 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 token, rc;
 
-		dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
-
-		token = match_token(p, nfs_mount_option_tokens, args);
-		switch (token) {
+	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:
-			ctx->flags |= NFS_MOUNT_SOFT;
-			ctx->flags &= ~NFS_MOUNT_SOFTERR;
-			break;
-		case Opt_softerr:
-			ctx->flags |= NFS_MOUNT_SOFTERR;
-			ctx->flags &= ~NFS_MOUNT_SOFT;
-			break;
-		case Opt_hard:
-			ctx->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
-			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;
+		ctx->flags &= ~NFS_MOUNT_SOFTERR;
+		break;
+	case Opt_softerr:
+		ctx->flags |= NFS_MOUNT_SOFTERR;
+		ctx->flags &= ~NFS_MOUNT_SOFT;
+		break;
+	case Opt_hard:
+		ctx->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
+		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;
+			/* fall through */
+		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;
+			/* fall through */
+		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;
-				/* fall through */
-			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;
-				/* fall through */
-			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;
-				/* fall through */
-			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;
+			/* fall through */
+		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;
-				/* fall through */
-			case Opt_xprt_udp:
-				ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
-				break;
-			case Opt_xprt_tcp6:
-				ctx->mountfamily = AF_INET6;
-				/* fall through */
-			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;
-			}
-			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;
+		ctx->mountfamily = AF_INET;
+		switch (token) {
+		case Opt_xprt_udp6:
+			ctx->mountfamily = AF_INET6;
+			/* fall through */
+		case Opt_xprt_udp:
+			ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
+			break;
+		case Opt_xprt_tcp6:
+			ctx->mountfamily = AF_INET6;
+			/* fall through */
+		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;
+		}
+		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_nconnect:
+		if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
+			goto out_invalid_value;
+		ctx->nfs_server.nconnect = option;
+		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_nconnect:
-			if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
-				goto out_invalid_value;
-			ctx->nfs_server.nconnect = option;
+		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_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;
-			};
+		case Opt_local_lock_flock:
+			ctx->flags |= NFS_MOUNT_LOCAL_FLOCK;
 			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_posix:
+			ctx->flags |= NFS_MOUNT_LOCAL_FCNTL;
 			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_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;
-- 
2.17.2


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

* [PATCH v3 21/26] NFS: Add a small buffer in nfs_fs_context to avoid string dup
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (19 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 20/26] NFS: Deindent nfs_fs_context_parse_option() Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 22/26] NFS: Do some tidying of the parsing code Scott Mayhew
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: David Howells <dhowells@redhat.com>

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>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/fs_context.c | 98 +++++++++++++++++++++------------------------
 fs/nfs/internal.h   |  2 +
 2 files changed, 48 insertions(+), 52 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 29d50c052ddc..1ff60c0e073f 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -472,27 +472,38 @@ 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;
+	match_strlcpy(ctx->buf, args, sizeof(ctx->buf));
+	return kstrtouint(ctx->buf, 10, option);
+}
 
-	string = match_strdup(args);
-	if (string == NULL)
-		return -ENOMEM;
-	rc = kstrtoul(string, 10, option);
-	kfree(string);
+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;
 
-	return rc;
+	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;
+	return 0;
 }
 
-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_us_bound(struct nfs_fs_context *ctx,
+				   substring_t args[], unsigned short *option,
+				   unsigned short l_bound,
+				   unsigned short u_bound)
 {
 	int ret;
 
-	ret = nfs_get_option_ul(args, option);
-	if (ret != 0)
+	match_strlcpy(ctx->buf, args, sizeof(ctx->buf));
+	ret = kstrtou16(ctx->buf, 10, option);
+	if (ret < 0)
 		return ret;
 	if (*option < l_bound || *option > u_bound)
 		return -ERANGE;
@@ -505,7 +516,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 token, rc;
 
@@ -613,86 +623,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;
 
 		/*
@@ -824,9 +818,9 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			goto out_invalid_address;
 		break;
 	case Opt_nconnect:
-		if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
+		if (nfs_get_option_us_bound(ctx, args, &ctx->nfs_server.nconnect,
+					    1, NFS_MAX_CONNECTIONS))
 			goto out_invalid_value;
-		ctx->nfs_server.nconnect = option;
 		break;
 	case Opt_lookupcache:
 		string = match_strdup(args);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index d084182f8e43..11df0d1f9fd4 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -130,6 +130,8 @@ struct nfs_fs_context {
 
 	void			*lsm_opts;
 	struct net		*net;
+
+	char			buf[32];	/* Parse buffer */
 };
 
 /* mount_clnt.c */
-- 
2.17.2


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

* [PATCH v3 22/26] NFS: Do some tidying of the parsing code
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (20 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 21/26] NFS: Add a small buffer in nfs_fs_context to avoid string dup Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 23/26] NFS: rename nfs_fs_context pointer arg in a few functions Scott Mayhew
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: David Howells <dhowells@redhat.com>

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>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 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 1ff60c0e073f..02ed45ccdebf 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -347,8 +347,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);
@@ -356,26 +357,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);
 
@@ -417,19 +419,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)) {
@@ -460,9 +463,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)
@@ -517,7 +521,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 {
 	substring_t args[MAX_OPT_ARGS];
 	char *string;
-	int token, rc;
+	int token, ret;
 
 	dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
 
@@ -557,13 +561,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;
@@ -696,29 +698,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) {
@@ -746,9 +744,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);
@@ -757,8 +754,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;
@@ -777,8 +773,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;
@@ -788,9 +783,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;
@@ -800,8 +794,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:
@@ -810,9 +803,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;
@@ -826,8 +818,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:
@@ -841,10 +832,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))
@@ -855,8 +845,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:
@@ -874,8 +863,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;
@@ -889,13 +877,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;
 	}
 
@@ -955,15 +941,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;
 		}
 	}
@@ -999,9 +985,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;
@@ -1037,17 +1023,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:
@@ -1068,7 +1054,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:
@@ -1397,11 +1383,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 11df0d1f9fd4..caaf0af1bc7f 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -90,11 +90,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;
@@ -110,7 +110,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;
@@ -119,7 +122,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 abd99ed00e39..d44de53c17a6 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -816,7 +816,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;
-- 
2.17.2


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

* [PATCH v3 23/26] NFS: rename nfs_fs_context pointer arg in a few functions
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (21 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 22/26] NFS: Do some tidying of the parsing code Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 24/26] NFS: Convert mount option parsing to use functionality from fs_parser.h Scott Mayhew
                   ` (2 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

Split out from commit "NFS: Add fs_context support."

Rename cfg to ctx in nfs_init_server(), nfs_verify_authflavors(),
and nfs_request_mount().  No functional changes.

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 fs/nfs/client.c | 62 ++++++++++++++++++++++++-------------------------
 fs/nfs/super.c  | 54 +++++++++++++++++++++---------------------
 2 files changed, 58 insertions(+), 58 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 1afd796a3706..511d1d629786 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -648,27 +648,27 @@ 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,
+			   const struct nfs_fs_context *ctx,
 			   struct nfs_subversion *nfs_mod)
 {
 	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,
+		.hostname = ctx->nfs_server.hostname,
+		.addr = (const struct sockaddr *)&ctx->nfs_server.address,
+		.addrlen = ctx->nfs_server.addrlen,
 		.nfs_mod = nfs_mod,
-		.proto = cfg->nfs_server.protocol,
-		.net = cfg->net,
+		.proto = ctx->nfs_server.protocol,
+		.net = ctx->net,
 		.timeparms = &timeparms,
 		.cred = server->cred,
-		.nconnect = cfg->nfs_server.nconnect,
+		.nconnect = ctx->nfs_server.nconnect,
 	};
 	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 */
@@ -679,46 +679,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:
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index d44de53c17a6..9aa27093d8b6 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -726,11 +726,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)
 {
@@ -753,7 +753,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)
@@ -761,7 +761,7 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
 	}
 
 	if (found_auth_null) {
-		flavor = cfg->auth_info.flavors[0];
+		flavor = ctx->auth_info.flavors[0];
 		goto out;
 	}
 
@@ -770,8 +770,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;
 }
 
@@ -779,50 +779,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->net,
 	};
 	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
-- 
2.17.2


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

* [PATCH v3 24/26] NFS: Convert mount option parsing to use functionality from fs_parser.h
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (22 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 23/26] NFS: rename nfs_fs_context pointer arg in a few functions Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 25/26] NFS: Add fs_context support Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 26/26] NFS: Attach supplementary error information to fs_context Scott Mayhew
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

Split out from commit "NFS: Add fs_context support."

Convert existing mount option definitions to fs_parameter_enum's and
fs_parameter_spec's.  Parse mount options using fs_parse() and
lookup_constant().

Notes:

1) Fixed a typo in the udp6 definition in nfs_xprt_protocol_tokens
from the original commit.

2) fs_parse() expects an fs_context as the first arg so that any
errors can be logged to the fs_context.  We're passing NULL for the
fs_context (this will change in commit "NFS: Add fs_context support.")
which is okay as it will cause logfc() to do a printk() instead.

3) fs_parse() expects an fs_paramter as the third arg.  We're
building an fs_parameter manually in nfs_fs_context_parse_option(),
which will go away in commit "NFS: Add fs_context support.".

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 fs/nfs/fs_context.c | 789 ++++++++++++++++++++------------------------
 1 file changed, 365 insertions(+), 424 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 02ed45ccdebf..d65f5d7a488e 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -15,7 +15,8 @@
 
 #include <linux/module.h>
 #include <linux/fs.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/nfs4_mount.h>
@@ -32,218 +33,215 @@
 
 #define NFS_MAX_CONNECTIONS 16
 
-enum {
-	/* Mount options that take no arguments */
-	Opt_soft, Opt_softerr, 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,
+enum nfs_param {
+	Opt_ac,
+	Opt_acdirmax,
+	Opt_acdirmin,
+	Opt_acl,
+	Opt_acregmax,
+	Opt_acregmin,
 	Opt_actimeo,
-	Opt_namelen,
+	Opt_addr,
+	Opt_bg,
+	Opt_bsize,
+	Opt_clientaddr,
+	Opt_cto,
+	Opt_fg,
+	Opt_fscache,
+	Opt_hard,
+	Opt_intr,
+	Opt_local_lock,
+	Opt_lock,
+	Opt_lookupcache,
+	Opt_migration,
+	Opt_minorversion,
+	Opt_mountaddr,
+	Opt_mounthost,
 	Opt_mountport,
+	Opt_mountproto,
 	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_namelen,
 	Opt_nconnect,
-	Opt_lookupcache,
-	Opt_fscache_uniq,
-	Opt_local_lock,
-
-	/* Special mount options */
-	Opt_userspace, Opt_deprecated, Opt_sloppy,
-
-	Opt_err
+	Opt_port,
+	Opt_posix,
+	Opt_proto,
+	Opt_rdirplus,
+	Opt_rdma,
+	Opt_resvport,
+	Opt_retrans,
+	Opt_retry,
+	Opt_rsize,
+	Opt_sec,
+	Opt_sharecache,
+	Opt_sloppy,
+	Opt_soft,
+	Opt_softerr,
+	Opt_source,
+	Opt_tcp,
+	Opt_timeo,
+	Opt_udp,
+	Opt_v,
+	Opt_vers,
+	Opt_wsize,
 };
 
-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_softerr, "softerr" },
-	{ 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_nconnect, "nconnect=%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 }
+static const struct fs_parameter_spec nfs_param_specs[] = {
+	fsparam_flag_no("ac",		Opt_ac),
+	fsparam_u32   ("acdirmax",	Opt_acdirmax),
+	fsparam_u32   ("acdirmin",	Opt_acdirmin),
+	fsparam_flag_no("acl",		Opt_acl),
+	fsparam_u32   ("acregmax",	Opt_acregmax),
+	fsparam_u32   ("acregmin",	Opt_acregmin),
+	fsparam_u32   ("actimeo",	Opt_actimeo),
+	fsparam_string("addr",		Opt_addr),
+	fsparam_flag  ("bg",		Opt_bg),
+	fsparam_u32   ("bsize",		Opt_bsize),
+	fsparam_string("clientaddr",	Opt_clientaddr),
+	fsparam_flag_no("cto",		Opt_cto),
+	fsparam_flag  ("fg",		Opt_fg),
+	__fsparam(fs_param_is_string, "fsc",		Opt_fscache,
+		  fs_param_neg_with_no|fs_param_v_optional),
+	fsparam_flag  ("hard",		Opt_hard),
+	__fsparam(fs_param_is_flag, "intr",		Opt_intr,
+		  fs_param_neg_with_no|fs_param_deprecated),
+	fsparam_enum  ("local_lock",	Opt_local_lock),
+	fsparam_flag_no("lock",		Opt_lock),
+	fsparam_enum  ("lookupcache",	Opt_lookupcache),
+	fsparam_flag_no("migration",	Opt_migration),
+	fsparam_u32   ("minorversion",	Opt_minorversion),
+	fsparam_string("mountaddr",	Opt_mountaddr),
+	fsparam_string("mounthost",	Opt_mounthost),
+	fsparam_u32   ("mountport",	Opt_mountport),
+	fsparam_string("mountproto",	Opt_mountproto),
+	fsparam_u32   ("mountvers",	Opt_mountvers),
+	fsparam_u32   ("namlen",	Opt_namelen),
+	fsparam_u32   ("nconnect",	Opt_nconnect),
+	fsparam_string("nfsvers",	Opt_vers),
+	fsparam_u32   ("port",		Opt_port),
+	fsparam_flag_no("posix",	Opt_posix),
+	fsparam_string("proto",		Opt_proto),
+	fsparam_flag_no("rdirplus",	Opt_rdirplus),
+	fsparam_flag  ("rdma",		Opt_rdma),
+	fsparam_flag_no("resvport",	Opt_resvport),
+	fsparam_u32   ("retrans",	Opt_retrans),
+	fsparam_string("retry",		Opt_retry),
+	fsparam_u32   ("rsize",		Opt_rsize),
+	fsparam_string("sec",		Opt_sec),
+	fsparam_flag_no("sharecache",	Opt_sharecache),
+	fsparam_flag  ("sloppy",	Opt_sloppy),
+	fsparam_flag  ("soft",		Opt_soft),
+	fsparam_flag  ("softerr",	Opt_softerr),
+	fsparam_string("source",	Opt_source),
+	fsparam_flag  ("tcp",		Opt_tcp),
+	fsparam_u32   ("timeo",		Opt_timeo),
+	fsparam_flag  ("udp",		Opt_udp),
+	fsparam_flag  ("v2",		Opt_v),
+	fsparam_flag  ("v3",		Opt_v),
+	fsparam_flag  ("v4",		Opt_v),
+	fsparam_flag  ("v4.0",		Opt_v),
+	fsparam_flag  ("v4.1",		Opt_v),
+	fsparam_flag  ("v4.2",		Opt_v),
+	fsparam_string("vers",		Opt_vers),
+	fsparam_u32   ("wsize",		Opt_wsize),
+	{}
 };
 
 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 }
+	Opt_local_lock_all,
+	Opt_local_lock_flock,
+	Opt_local_lock_none,
+	Opt_local_lock_posix,
 };
 
 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
+	Opt_lookupcache_all,
+	Opt_lookupcache_none,
+	Opt_lookupcache_positive,
 };
 
-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" },
+static const struct fs_parameter_enum nfs_param_enums[] = {
+	{ Opt_local_lock,	"all",		Opt_local_lock_all },
+	{ Opt_local_lock,	"flock",	Opt_local_lock_flock },
+	{ Opt_local_lock,	"none",		Opt_local_lock_none },
+	{ Opt_local_lock,	"posix",	Opt_local_lock_posix },
+	{ Opt_lookupcache,	"all",		Opt_lookupcache_all },
+	{ Opt_lookupcache,	"none",		Opt_lookupcache_none },
+	{ Opt_lookupcache,	"pos",		Opt_lookupcache_positive },
+	{ Opt_lookupcache,	"positive",	Opt_lookupcache_positive },
+	{}
+};
 
-	{ Opt_sec_err, NULL }
+static const struct fs_parameter_description nfs_fs_parameters = {
+	.name		= "nfs",
+	.specs		= nfs_param_specs,
+	.enums		= nfs_param_enums,
 };
 
 enum {
-	Opt_lookupcache_all, Opt_lookupcache_positive,
-	Opt_lookupcache_none,
-
-	Opt_lookupcache_err
+	Opt_vers_2,
+	Opt_vers_3,
+	Opt_vers_4,
+	Opt_vers_4_0,
+	Opt_vers_4_1,
+	Opt_vers_4_2,
 };
 
-static const 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 }
+static const struct constant_table nfs_vers_tokens[] = {
+	{ "2",		Opt_vers_2 },
+	{ "3",		Opt_vers_3 },
+	{ "4",		Opt_vers_4 },
+	{ "4.0",	Opt_vers_4_0 },
+	{ "4.1",	Opt_vers_4_1 },
+	{ "4.2",	Opt_vers_4_2 },
 };
 
 enum {
-	Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
-	Opt_local_lock_none,
-
-	Opt_local_lock_err
+	Opt_xprt_rdma,
+	Opt_xprt_rdma6,
+	Opt_xprt_tcp,
+	Opt_xprt_tcp6,
+	Opt_xprt_udp,
+	Opt_xprt_udp6,
+	nr__Opt_xprt
 };
 
-static const 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 }
+static const struct constant_table nfs_xprt_protocol_tokens[nr__Opt_xprt] = {
+	{ "rdma",	Opt_xprt_rdma },
+	{ "rdma6",	Opt_xprt_rdma6 },
+	{ "tcp",	Opt_xprt_tcp },
+	{ "tcp6",	Opt_xprt_tcp6 },
+	{ "udp",	Opt_xprt_udp },
+	{ "udp6",	Opt_xprt_udp6 },
 };
 
 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
+	Opt_sec_krb5,
+	Opt_sec_krb5i,
+	Opt_sec_krb5p,
+	Opt_sec_lkey,
+	Opt_sec_lkeyi,
+	Opt_sec_lkeyp,
+	Opt_sec_none,
+	Opt_sec_spkm,
+	Opt_sec_spkmi,
+	Opt_sec_spkmp,
+	Opt_sec_sys,
+	nr__Opt_sec
 };
 
-static const 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 const struct constant_table nfs_secflavor_tokens[] = {
+	{ "krb5",	Opt_sec_krb5 },
+	{ "krb5i",	Opt_sec_krb5i },
+	{ "krb5p",	Opt_sec_krb5p },
+	{ "lkey",	Opt_sec_lkey },
+	{ "lkeyi",	Opt_sec_lkeyi },
+	{ "lkeyp",	Opt_sec_lkeyp },
+	{ "none",	Opt_sec_none },
+	{ "null",	Opt_sec_none },
+	{ "spkm3",	Opt_sec_spkm },
+	{ "spkm3i",	Opt_sec_spkmi },
+	{ "spkm3p",	Opt_sec_spkmp },
+	{ "sys",	Opt_sec_sys },
 };
 
 struct nfs_fs_context *nfs_alloc_parsed_mount_data(void)
@@ -372,17 +370,19 @@ static int nfs_auth_info_add(struct nfs_fs_context *ctx,
 /*
  * Parse the value of the 'sec=' option.
  */
-static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value)
+static int nfs_parse_security_flavors(struct nfs_fs_context *ctx,
+				      struct fs_parameter *param)
 {
-	substring_t args[MAX_OPT_ARGS];
 	rpc_authflavor_t pseudoflavor;
-	char *p;
+	char *string = param->string, *p;
 	int ret;
 
-	dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
+	dfprintk(MOUNT, "NFS: parsing %s=%s option\n", param->key, param->string);
 
-	while ((p = strsep(&value, ":")) != NULL) {
-		switch (match_token(p, nfs_secflavor_tokens, args)) {
+	while ((p = strsep(&string, ":")) != NULL) {
+		if (!*p)
+			continue;
+		switch (lookup_constant(nfs_secflavor_tokens, p, -1)) {
 		case Opt_sec_none:
 			pseudoflavor = RPC_AUTH_NULL;
 			break;
@@ -431,11 +431,10 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value)
 }
 
 static int nfs_parse_version_string(struct nfs_fs_context *ctx,
-				    char *string,
-				    substring_t *args)
+				    const char *string)
 {
 	ctx->flags &= ~NFS_MOUNT_VER3;
-	switch (match_token(string, nfs_vers_tokens, args)) {
+	switch (lookup_constant(nfs_vers_tokens, string, -1)) {
 	case Opt_vers_2:
 		ctx->version = 2;
 		break;
@@ -469,64 +468,24 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx,
 	return 0;
 }
 
-static int nfs_get_option_str(substring_t args[], char **option)
-{
-	kfree(*option);
-	*option = match_strdup(args);
-	return !*option;
-}
-
-static int nfs_get_option_ui(struct nfs_fs_context *ctx,
-			     substring_t args[], unsigned int *option)
-{
-	match_strlcpy(ctx->buf, args, sizeof(ctx->buf));
-	return kstrtouint(ctx->buf, 10, option);
-}
-
-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;
-
-	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;
-	return 0;
-}
-
-static int nfs_get_option_us_bound(struct nfs_fs_context *ctx,
-				   substring_t args[], unsigned short *option,
-				   unsigned short l_bound,
-				   unsigned short u_bound)
-{
-	int ret;
-
-	match_strlcpy(ctx->buf, args, sizeof(ctx->buf));
-	ret = kstrtou16(ctx->buf, 10, option);
-	if (ret < 0)
-		return ret;
-	if (*option < l_bound || *option > u_bound)
-		return -ERANGE;
-	return 0;
-}
-
 /*
- * Parse a single mount option in "key[=val]" form.
+ * Parse a single mount parameter.
  */
-static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
+static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx,
+				      struct fs_parameter *param)
 {
-	substring_t args[MAX_OPT_ARGS];
-	char *string;
-	int token, ret;
+	struct fs_parse_result result;
+	unsigned short protofamily, mountfamily;
+	unsigned int len;
+	int ret, opt;
 
-	dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
+	dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", param->key);
 
-	token = match_token(p, nfs_mount_option_tokens, args);
-	switch (token) {
+	opt = fs_parse(NULL, &nfs_fs_parameters, param, &result);
+	if (opt < 0)
+		return ctx->sloppy ? 1 : opt;
+
+	switch (opt) {
 		/*
 		 * boolean options:  foo/nofoo
 		 */
@@ -542,30 +501,31 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		ctx->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
 		break;
 	case Opt_posix:
-		ctx->flags |= NFS_MOUNT_POSIX;
-		break;
-	case Opt_noposix:
-		ctx->flags &= ~NFS_MOUNT_POSIX;
+		if (result.negated)
+			ctx->flags &= ~NFS_MOUNT_POSIX;
+		else
+			ctx->flags |= NFS_MOUNT_POSIX;
 		break;
 	case Opt_cto:
-		ctx->flags &= ~NFS_MOUNT_NOCTO;
-		break;
-	case Opt_nocto:
-		ctx->flags |= NFS_MOUNT_NOCTO;
+		if (result.negated)
+			ctx->flags |= NFS_MOUNT_NOCTO;
+		else
+			ctx->flags &= ~NFS_MOUNT_NOCTO;
 		break;
 	case Opt_ac:
-		ctx->flags &= ~NFS_MOUNT_NOAC;
-		break;
-	case Opt_noac:
-		ctx->flags |= NFS_MOUNT_NOAC;
+		if (result.negated)
+			ctx->flags |= NFS_MOUNT_NOAC;
+		else
+			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);
+		if (result.negated) {
+			ctx->flags |= NFS_MOUNT_NONLM;
+			ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
+		} else {
+			ctx->flags &= ~NFS_MOUNT_NONLM;
+			ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
+		}
 		break;
 	case Opt_udp:
 		ctx->flags &= ~NFS_MOUNT_TCP;
@@ -578,195 +538,177 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 	case Opt_rdma:
 		ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */
 		ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
-		xprt_load_transport(p);
+		xprt_load_transport(param->key);
 		break;
 	case Opt_acl:
-		ctx->flags &= ~NFS_MOUNT_NOACL;
-		break;
-	case Opt_noacl:
-		ctx->flags |= NFS_MOUNT_NOACL;
+		if (result.negated)
+			ctx->flags |= NFS_MOUNT_NOACL;
+		else
+			ctx->flags &= ~NFS_MOUNT_NOACL;
 		break;
 	case Opt_rdirplus:
-		ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
-		break;
-	case Opt_nordirplus:
-		ctx->flags |= NFS_MOUNT_NORDIRPLUS;
+		if (result.negated)
+			ctx->flags |= NFS_MOUNT_NORDIRPLUS;
+		else
+			ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
 		break;
 	case Opt_sharecache:
-		ctx->flags &= ~NFS_MOUNT_UNSHARED;
-		break;
-	case Opt_nosharecache:
-		ctx->flags |= NFS_MOUNT_UNSHARED;
+		if (result.negated)
+			ctx->flags |= NFS_MOUNT_UNSHARED;
+		else
+			ctx->flags &= ~NFS_MOUNT_UNSHARED;
 		break;
 	case Opt_resvport:
-		ctx->flags &= ~NFS_MOUNT_NORESVPORT;
-		break;
-	case Opt_noresvport:
-		ctx->flags |= NFS_MOUNT_NORESVPORT;
+		if (result.negated)
+			ctx->flags |= NFS_MOUNT_NORESVPORT;
+		else
+			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;
+		ctx->fscache_uniq = param->string;
+		param->string = NULL;
+		if (result.negated)
+			ctx->options &= ~NFS_OPTION_FSCACHE;
+		else
+			ctx->options |= NFS_OPTION_FSCACHE;
 		break;
 	case Opt_migration:
-		ctx->options |= NFS_OPTION_MIGRATION;
-		break;
-	case Opt_nomigration:
-		ctx->options &= ~NFS_OPTION_MIGRATION;
+		if (result.negated)
+			ctx->options &= ~NFS_OPTION_MIGRATION;
+		else
+			ctx->options |= NFS_OPTION_MIGRATION;
 		break;
 
 		/*
 		 * options that take numeric values
 		 */
 	case Opt_port:
-		if (nfs_get_option_ui_bound(ctx, args, &ctx->nfs_server.port,
-					    0, USHRT_MAX))
-			goto out_invalid_value;
+		if (result.uint_32 > USHRT_MAX)
+			goto out_of_bounds;
+		ctx->nfs_server.port = result.uint_32;
 		break;
 	case Opt_rsize:
-		if (nfs_get_option_ui(ctx, args, &ctx->rsize))
-			goto out_invalid_value;
+		ctx->rsize = result.uint_32;
 		break;
 	case Opt_wsize:
-		if (nfs_get_option_ui(ctx, args, &ctx->wsize))
-			goto out_invalid_value;
+		ctx->wsize = result.uint_32;
 		break;
 	case Opt_bsize:
-		if (nfs_get_option_ui(ctx, args, &ctx->bsize))
-			goto out_invalid_value;
+		ctx->bsize = result.uint_32;
 		break;
 	case Opt_timeo:
-		if (nfs_get_option_ui_bound(ctx, args, &ctx->timeo, 1, INT_MAX))
-			goto out_invalid_value;
+		if (result.uint_32 < 1 || result.uint_32 > INT_MAX)
+			goto out_of_bounds;
+		ctx->timeo = result.uint_32;
 		break;
 	case Opt_retrans:
-		if (nfs_get_option_ui_bound(ctx, args, &ctx->retrans, 0, INT_MAX))
-			goto out_invalid_value;
+		if (result.uint_32 > INT_MAX)
+			goto out_of_bounds;
+		ctx->retrans = result.uint_32;
 		break;
 	case Opt_acregmin:
-		if (nfs_get_option_ui(ctx, args, &ctx->acregmin))
-			goto out_invalid_value;
+		ctx->acregmin = result.uint_32;
 		break;
 	case Opt_acregmax:
-		if (nfs_get_option_ui(ctx, args, &ctx->acregmax))
-			goto out_invalid_value;
+		ctx->acregmax = result.uint_32;
 		break;
 	case Opt_acdirmin:
-		if (nfs_get_option_ui(ctx, args, &ctx->acdirmin))
-			goto out_invalid_value;
+		ctx->acdirmin = result.uint_32;
 		break;
 	case Opt_acdirmax:
-		if (nfs_get_option_ui(ctx, args, &ctx->acdirmax))
-			goto out_invalid_value;
+		ctx->acdirmax = result.uint_32;
 		break;
 	case Opt_actimeo:
-		if (nfs_get_option_ui(ctx, args, &ctx->acdirmax))
-			goto out_invalid_value;
-		ctx->acregmin = ctx->acregmax =
-			ctx->acdirmin = ctx->acdirmax;
+		ctx->acregmin = result.uint_32;
+		ctx->acregmax = result.uint_32;
+		ctx->acdirmin = result.uint_32;
+		ctx->acdirmax = result.uint_32;
 		break;
 	case Opt_namelen:
-		if (nfs_get_option_ui(ctx, args, &ctx->namlen))
-			goto out_invalid_value;
+		ctx->namlen = result.uint_32;
 		break;
 	case Opt_mountport:
-		if (nfs_get_option_ui_bound(ctx, args, &ctx->mount_server.port,
-					    0, USHRT_MAX))
-			goto out_invalid_value;
+		if (result.uint_32 > USHRT_MAX)
+			goto out_of_bounds;
+		ctx->mount_server.port = result.uint_32;
 		break;
 	case Opt_mountvers:
-		if (nfs_get_option_ui_bound(ctx, args, &ctx->mount_server.version,
-					    NFS_MNT_VERSION, NFS_MNT3_VERSION))
-			goto out_invalid_value;
+		if (result.uint_32 < NFS_MNT_VERSION ||
+		    result.uint_32 > NFS_MNT3_VERSION)
+			goto out_of_bounds;
+		ctx->mount_server.version = result.uint_32;
 		break;
 	case Opt_minorversion:
-		if (nfs_get_option_ui_bound(ctx, args, &ctx->minorversion,
-					    0, NFS4_MAX_MINOR_VERSION))
-			goto out_invalid_value;
+		if (result.uint_32 > NFS4_MAX_MINOR_VERSION)
+			goto out_of_bounds;
+		ctx->minorversion = result.uint_32;
 		break;
 
 		/*
 		 * options that take text values
 		 */
-	case Opt_nfsvers:
-		string = match_strdup(args);
-		if (string == NULL)
-			goto out_nomem;
-		ret = nfs_parse_version_string(ctx, string, args);
-		kfree(string);
+	case Opt_v:
+		ret = nfs_parse_version_string(ctx, param->key + 1);
+		if (ret < 0)
+			return ret;
+		break;
+	case Opt_vers:
+		ret = nfs_parse_version_string(ctx, param->string);
 		if (ret < 0)
 			return ret;
 		break;
 	case Opt_sec:
-		string = match_strdup(args);
-		if (string == NULL)
-			goto out_nomem;
-		ret = nfs_parse_security_flavors(ctx, string);
-		kfree(string);
+		ret = nfs_parse_security_flavors(ctx, param);
 		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);
 
-		ctx->protofamily = AF_INET;
-		switch (token) {
+	case Opt_proto:
+		protofamily = AF_INET;
+		switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
 		case Opt_xprt_udp6:
-			ctx->protofamily = AF_INET6;
+			protofamily = AF_INET6;
 			/* fall through */
 		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;
+			protofamily = AF_INET6;
 			/* fall through */
 		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;
+			protofamily = AF_INET6;
 			/* fall through */
 		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);
+			xprt_load_transport(param->string);
 			break;
 		default:
-			kfree(string);
 			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
 			return -EINVAL;
 		}
-		kfree(string);
+
+		ctx->protofamily = protofamily;
 		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_mountproto:
+		mountfamily = AF_INET;
+		switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
 		case Opt_xprt_udp6:
-			ctx->mountfamily = AF_INET6;
+			mountfamily = AF_INET6;
 			/* fall through */
 		case Opt_xprt_udp:
 			ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
 			break;
 		case Opt_xprt_tcp6:
-			ctx->mountfamily = AF_INET6;
+			mountfamily = AF_INET6;
 			/* fall through */
 		case Opt_xprt_tcp:
 			ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
@@ -776,51 +718,42 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
 			return -EINVAL;
 		}
+		ctx->mountfamily = mountfamily;
 		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),
-				 &ctx->nfs_server.address,
-				 sizeof(ctx->nfs_server._address));
-		kfree(string);
-		if (ctx->nfs_server.addrlen == 0)
+		len = rpc_pton(ctx->net, param->string, param->size,
+			       &ctx->nfs_server.address,
+			       sizeof(ctx->nfs_server._address));
+		if (len == 0)
 			goto out_invalid_address;
+		ctx->nfs_server.addrlen = len;
 		break;
 	case Opt_clientaddr:
-		if (nfs_get_option_str(args, &ctx->client_address))
-			goto out_nomem;
+		kfree(ctx->client_address);
+		ctx->client_address = param->string;
+		param->string = NULL;
 		break;
 	case Opt_mounthost:
-		if (nfs_get_option_str(args, &ctx->mount_server.hostname))
-			goto out_nomem;
+		kfree(ctx->mount_server.hostname);
+		ctx->mount_server.hostname = param->string;
+		param->string = NULL;
 		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),
-				 &ctx->mount_server.address,
-				 sizeof(ctx->mount_server._address));
-		kfree(string);
-		if (ctx->mount_server.addrlen == 0)
+		len = rpc_pton(ctx->net, param->string, param->size,
+			       &ctx->mount_server.address,
+			       sizeof(ctx->mount_server._address));
+		if (len == 0)
 			goto out_invalid_address;
+		ctx->mount_server.addrlen = len;
 		break;
 	case Opt_nconnect:
-		if (nfs_get_option_us_bound(ctx, args, &ctx->nfs_server.nconnect,
-					    1, NFS_MAX_CONNECTIONS))
-			goto out_invalid_value;
+		if (result.uint_32 < 1 || result.uint_32 > NFS_MAX_CONNECTIONS)
+			goto out_of_bounds;
+		ctx->nfs_server.nconnect = result.uint_32;
 		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) {
+		switch (result.uint_32) {
 		case Opt_lookupcache_all:
 			ctx->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
 			break;
@@ -832,22 +765,11 @@ 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;
+			goto out_invalid_value;
 		}
 		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) {
+		switch (result.uint_32) {
 		case Opt_local_lock_all:
 			ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
 				       NFS_MOUNT_LOCAL_FCNTL);
@@ -863,39 +785,58 @@ 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;
-		};
+			goto out_invalid_value;
+		}
 		break;
 
 		/*
 		 * Special options
 		 */
 	case Opt_sloppy:
-		ctx->sloppy = 1;
+		ctx->sloppy = true;
 		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;
 	}
 
 	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);
+	printk(KERN_INFO "NFS: Bad mount option value specified\n");
 	return -EINVAL;
-out_nomem:
-	printk(KERN_INFO "NFS: not enough memory to parse option\n");
-	return -ENOMEM;
+out_invalid_address:
+	printk(KERN_INFO "NFS: Bad IP address specified\n");
+	return -EINVAL;
+out_of_bounds:
+	printk(KERN_INFO "NFS: Value for '%s' out of range\n", param->key);
+	return -ERANGE;
+}
+
+/* cribbed from generic_parse_monolithic and vfs_parse_fs_string */
+static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
+{
+	int ret;
+	char *key = p, *value;
+	size_t v_size = 0;
+	struct fs_parameter param;
+
+	memset(&param, 0, sizeof(param));
+	value = strchr(key, '=');
+	if (value && value != key) {
+		*value++ = 0;
+		v_size = strlen(value);
+	}
+	param.key = key;
+	param.type = fs_value_is_flag;
+	param.size = v_size;
+	if (v_size > 0) {
+		param.type = fs_value_is_string;
+		param.string = kmemdup_nul(value, v_size, GFP_KERNEL);
+		if (!param.string)
+			return -ENOMEM;
+	}
+	ret = nfs_fs_context_parse_param(ctx, &param);
+	kfree(param.string);
+	return ret;
 }
 
 /*
-- 
2.17.2


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

* [PATCH v3 25/26] NFS: Add fs_context support.
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (23 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 24/26] NFS: Convert mount option parsing to use functionality from fs_parser.h Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  2019-09-11 16:16 ` [PATCH v3 26/26] NFS: Attach supplementary error information to fs_context Scott Mayhew
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

From: David Howells <dhowells@redhat.com>

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.

[AV -- retrans is u32, not string]
[SM -- Renamed cfg to ctx in a few functions in an earlier patch]
[SM -- Moved fs_context mount option parsing to an earlier patch]
[SM -- Moved fs_context error logging to a later patch]
[SM -- Fixed printks in nfs4_try_get_tree() and nfs4_get_referral_tree()]
[SM -- Added is_remount_fc() helper]

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 fs/nfs/client.c         |  22 +-
 fs/nfs/fs_context.c     | 578 ++++++++++++++++++++++++----------------
 fs/nfs/fscache.c        |   2 +-
 fs/nfs/getroot.c        |  70 ++---
 fs/nfs/internal.h       | 100 +++----
 fs/nfs/namespace.c      | 134 ++++++----
 fs/nfs/nfs3_fs.h        |   2 +-
 fs/nfs/nfs3client.c     |   5 +-
 fs/nfs/nfs3proc.c       |   2 +-
 fs/nfs/nfs4_fs.h        |   9 +-
 fs/nfs/nfs4client.c     |  62 ++---
 fs/nfs/nfs4namespace.c  | 285 +++++++++++---------
 fs/nfs/nfs4proc.c       |   2 +-
 fs/nfs/nfs4super.c      | 164 ++++++------
 fs/nfs/proc.c           |   2 +-
 fs/nfs/super.c          | 312 ++++++----------------
 include/linux/nfs_xdr.h |   8 +-
 17 files changed, 897 insertions(+), 862 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 511d1d629786..a26e7d1d74bc 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -648,17 +648,17 @@ 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 *ctx,
-			   struct nfs_subversion *nfs_mod)
+			   const struct fs_context *fc)
 {
+	const struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	struct rpc_timeout timeparms;
 	struct nfs_client_initdata cl_init = {
 		.hostname = ctx->nfs_server.hostname,
 		.addr = (const struct sockaddr *)&ctx->nfs_server.address,
 		.addrlen = ctx->nfs_server.addrlen,
-		.nfs_mod = nfs_mod,
+		.nfs_mod = ctx->nfs_mod,
 		.proto = ctx->nfs_server.protocol,
-		.net = ctx->net,
+		.net = fc->net_ns,
 		.timeparms = &timeparms,
 		.cred = server->cred,
 		.nconnect = ctx->nfs_server.nconnect,
@@ -940,10 +940,10 @@ 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_server *nfs_create_server(struct fs_context *fc)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	struct nfs_server *server;
-	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
 	struct nfs_fattr *fattr;
 	int error;
 
@@ -959,18 +959,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, fc);
 	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)
@@ -978,8 +978,8 @@ 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, NULL);
+		error = ctx->nfs_mod->rpc_ops->getattr(server, ctx->mntfh,
+						       fattr, NULL, 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 d65f5d7a488e..14c43d1c7da9 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -244,43 +244,6 @@ static const struct constant_table nfs_secflavor_tokens[] = {
 	{ "sys",	Opt_sec_sys },
 };
 
-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;
-		ctx->lsm_opts = NULL;
-	}
-	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);
-	}
-}
-
 /*
  * Sanity-check a server address provided by the mount command.
  *
@@ -345,7 +308,7 @@ 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 int nfs_auth_info_add(struct nfs_fs_context *ctx,
+static int nfs_auth_info_add(struct fs_context *fc,
 			     struct nfs_auth_info *auth_info,
 			     rpc_authflavor_t flavor)
 {
@@ -370,9 +333,10 @@ static int nfs_auth_info_add(struct nfs_fs_context *ctx,
 /*
  * Parse the value of the 'sec=' option.
  */
-static int nfs_parse_security_flavors(struct nfs_fs_context *ctx,
+static int nfs_parse_security_flavors(struct fs_context *fc,
 				      struct fs_parameter *param)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	rpc_authflavor_t pseudoflavor;
 	char *string = param->string, *p;
 	int ret;
@@ -422,7 +386,7 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx,
 			return -EINVAL;
 		}
 
-		ret = nfs_auth_info_add(ctx, &ctx->auth_info, pseudoflavor);
+		ret = nfs_auth_info_add(fc, &ctx->auth_info, pseudoflavor);
 		if (ret < 0)
 			return ret;
 	}
@@ -430,9 +394,11 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx,
 	return 0;
 }
 
-static int nfs_parse_version_string(struct nfs_fs_context *ctx,
+static int nfs_parse_version_string(struct fs_context *fc,
 				    const char *string)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+
 	ctx->flags &= ~NFS_MOUNT_VER3;
 	switch (lookup_constant(nfs_vers_tokens, string, -1)) {
 	case Opt_vers_2:
@@ -471,21 +437,31 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx,
 /*
  * Parse a single mount parameter.
  */
-static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx,
+static int nfs_fs_context_parse_param(struct fs_context *fc,
 				      struct fs_parameter *param)
 {
 	struct fs_parse_result result;
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	unsigned short protofamily, mountfamily;
 	unsigned int len;
 	int ret, opt;
 
 	dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", param->key);
 
-	opt = fs_parse(NULL, &nfs_fs_parameters, param, &result);
+	opt = fs_parse(fc, &nfs_fs_parameters, param, &result);
 	if (opt < 0)
 		return ctx->sloppy ? 1 : opt;
 
 	switch (opt) {
+	case Opt_source:
+		if (fc->source) {
+			dfprintk(MOUNT, "NFS: Multiple sources not supported\n");
+			return -EINVAL;
+		}
+		fc->source = param->string;
+		param->string = NULL;
+		break;
+
 		/*
 		 * boolean options:  foo/nofoo
 		 */
@@ -649,17 +625,17 @@ static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx,
 		 * options that take text values
 		 */
 	case Opt_v:
-		ret = nfs_parse_version_string(ctx, param->key + 1);
+		ret = nfs_parse_version_string(fc, param->key + 1);
 		if (ret < 0)
 			return ret;
 		break;
 	case Opt_vers:
-		ret = nfs_parse_version_string(ctx, param->string);
+		ret = nfs_parse_version_string(fc, param->string);
 		if (ret < 0)
 			return ret;
 		break;
 	case Opt_sec:
-		ret = nfs_parse_security_flavors(ctx, param);
+		ret = nfs_parse_security_flavors(fc, param);
 		if (ret < 0)
 			return ret;
 		break;
@@ -722,7 +698,7 @@ static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx,
 		break;
 
 	case Opt_addr:
-		len = rpc_pton(ctx->net, param->string, param->size,
+		len = rpc_pton(fc->net_ns, param->string, param->size,
 			       &ctx->nfs_server.address,
 			       sizeof(ctx->nfs_server._address));
 		if (len == 0)
@@ -740,7 +716,7 @@ static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx,
 		param->string = NULL;
 		break;
 	case Opt_mountaddr:
-		len = rpc_pton(ctx->net, param->string, param->size,
+		len = rpc_pton(fc->net_ns, param->string, param->size,
 			       &ctx->mount_server.address,
 			       sizeof(ctx->mount_server._address));
 		if (len == 0)
@@ -811,114 +787,8 @@ static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx,
 	return -ERANGE;
 }
 
-/* cribbed from generic_parse_monolithic and vfs_parse_fs_string */
-static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
-{
-	int ret;
-	char *key = p, *value;
-	size_t v_size = 0;
-	struct fs_parameter param;
-
-	memset(&param, 0, sizeof(param));
-	value = strchr(key, '=');
-	if (value && value != key) {
-		*value++ = 0;
-		v_size = strlen(value);
-	}
-	param.key = key;
-	param.type = fs_value_is_flag;
-	param.size = v_size;
-	if (v_size > 0) {
-		param.type = fs_value_is_string;
-		param.string = kmemdup_nul(value, v_size, GFP_KERNEL);
-		if (!param.string)
-			return -ENOMEM;
-	}
-	ret = nfs_fs_context_parse_param(ctx, &param);
-	kfree(param.string);
-	return ret;
-}
-
 /*
- * 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;
-	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);
-
-	rc = security_sb_eat_lsm_opts(raw, &ctx->lsm_opts);
-	if (rc)
-		goto out_security_failure;
-
-	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_security_failure:
-	printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
-	return 0;
-}
-
-/*
- * Split "dev_name" into "hostname:export_path".
+ * Split fc->source 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
@@ -926,12 +796,13 @@ 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)
+static int nfs_parse_source(struct fs_context *fc,
+			    size_t maxnamlen, size_t maxpathlen)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	const char *dev_name = fc->source;
 	size_t len;
-	char *end;
+	const char *end;
 
 	if (unlikely(!dev_name || !*dev_name)) {
 		dfprintk(MOUNT, "NFS: device name not specified\n");
@@ -947,7 +818,7 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
 		len = end - dev_name;
 		end++;
 	} else {
-		char *comma;
+		const char *comma;
 
 		end = strchr(dev_name, ':');
 		if (end == NULL)
@@ -955,8 +826,8 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
 		len = end - dev_name;
 
 		/* kill possible hostname list: not supported */
-		comma = strchr(dev_name, ',');
-		if (comma != NULL && comma < end)
+		comma = memchr(dev_name, ',', len);
+		if (comma)
 			len = comma - dev_name;
 	}
 
@@ -994,6 +865,11 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
 	return -ENAMETOOLONG;
 }
 
+static inline bool is_remount_fc(struct fs_context *fc)
+{
+	return fc->root != NULL;
+}
+
 /*
  * Parse monolithic NFS2/NFS3 mount data
  * - fills in the mount root filehandle
@@ -1010,12 +886,11 @@ 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_parse_monolithic(struct fs_context *fc,
+				  struct nfs_mount_data *data)
 {
-	struct nfs_mount_data *data = (struct nfs_mount_data *)options;
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	struct nfs_fh *mntfh = ctx->mntfh;
 	struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
 	int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
 
@@ -1087,6 +962,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;
 
@@ -1094,8 +972,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|
@@ -1103,6 +979,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
@@ -1113,12 +990,13 @@ static int nfs23_validate_mount_data(void *options,
 		 */
 		if (data->context[0]){
 #ifdef CONFIG_SECURITY_SELINUX
-			int rc;
+			int ret;
+
 			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
-			rc = security_add_mnt_opt("context", data->context,
-					strlen(data->context), ctx->lsm_opts);
-			if (rc)
-				return rc;
+			ret = vfs_parse_fs_string(fc, "context",
+						  data->context, strlen(data->context));
+			if (ret < 0)
+				return ret;
 #else
 			return -EINVAL;
 #endif
@@ -1126,12 +1004,20 @@ static int nfs23_validate_mount_data(void *options,
 
 		break;
 	default:
-		return NFS_TEXT_DATA;
+		goto generic;
 	}
 
+	ctx->skip_reconfig_option_check = true;
 	return 0;
 
+generic:
+	return generic_parse_monolithic(fc, data);
+
 out_no_data:
+	if (is_remount_fc(fc)) {
+		ctx->skip_reconfig_option_check = true;
+		return 0;
+	}
 	dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
 	return -EINVAL;
 
@@ -1158,21 +1044,14 @@ static int nfs23_validate_mount_data(void *options,
 }
 
 #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);
-}
-
 /*
  * Validate NFSv4 mount options
  */
-static int nfs4_validate_mount_data(void *options,
-				    struct nfs_fs_context *ctx,
-				    const char *dev_name)
+static int nfs4_parse_monolithic(struct fs_context *fc,
+				 struct nfs4_mount_data *data)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(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)
@@ -1222,7 +1101,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.
 		 */
 
@@ -1242,12 +1121,20 @@ static int nfs4_validate_mount_data(void *options,
 
 		break;
 	default:
-		return NFS_TEXT_DATA;
+		goto generic;
 	}
 
+	ctx->skip_reconfig_option_check = true;
 	return 0;
 
+generic:
+	return generic_parse_monolithic(fc, data);
+
 out_no_data:
+	if (is_remount_fc(fc)) {
+		ctx->skip_reconfig_option_check = true;
+		return 0;
+	}
 	dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
 	return -EINVAL;
 
@@ -1264,58 +1151,87 @@ static int nfs4_validate_mount_data(void *options,
 	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
 	return -EINVAL;
 }
+#endif
 
-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_fs_context_parse_monolithic(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_parse_monolithic(fc, data);
+
+#if IS_ENABLED(CONFIG_NFS_V4)
+	if (fc->fs_type == &nfs4_fs_type)
+		return nfs4_parse_monolithic(fc, data);
 #endif
 
-int nfs_validate_text_mount_data(void *options,
-				 struct nfs_fs_context *ctx,
-				 const char *dev_name)
+	dfprintk(MOUNT, "NFS: Unsupported monolithic data version\n");
+	return -EINVAL;
+}
+
+/*
+ * 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 = nfs_fc2context(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 (!fc->source)
+		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)
-		if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
-			port = NFS_RDMA_PORT;
-		else
-			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 */
+		if (IS_ENABLED(CONFIG_NFS_V4)) {
+			if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+				port = NFS_RDMA_PORT;
+			else
+				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);
 		if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
@@ -1324,19 +1240,219 @@ int nfs_validate_text_mount_data(void *options,
 
 	nfs_set_port(sap, &ctx->nfs_server.port, port);
 
-	return nfs_parse_devname(ctx, dev_name, max_namelen, max_pathlen);
+	ret = nfs_parse_source(fc, max_namelen, max_pathlen);
+	if (ret < 0)
+		return ret;
+
+	/* 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;
 
-#if !IS_ENABLED(CONFIG_NFS_V4)
+out_no_device_name:
+	dfprintk(MOUNT, "NFS: Device name not specified\n");
+	return -EINVAL;
 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;
+out_mountproto_mismatch:
+	dfprintk(MOUNT, "NFS: Mount server address does not match mountproto= option\n");
+	return -EINVAL;
+out_proto_mismatch:
+	dfprintk(MOUNT, "NFS: Server address does not match proto= option\n");
+	return -EINVAL;
+out_minorversion_mismatch:
+	dfprintk(MOUNT, "NFS: Mount option vers=%u does not support minorversion=%u\n",
+			  ctx->version, ctx->minorversion);
+	return -EINVAL;
+out_migration_misuse:
+	dfprintk(MOUNT, "NFS: 'Migration' not supported for this NFS version\n");
+	return -EINVAL;
+out_version_unavailable:
+	dfprintk(MOUNT, "NFS: Version unavailable\n");
+	return ret;
+}
+
+/*
+ * Create an NFS superblock by the appropriate method.
+ */
+static int nfs_get_tree(struct fs_context *fc)
+{
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	int err = nfs_fs_context_validate(fc);
+
+	if (err)
+		return err;
+	if (!ctx->internal)
+		return ctx->nfs_mod->rpc_ops->try_get_tree(fc);
+	else
+		return nfs_get_tree_common(fc);
+}
+
+/*
+ * 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_fc)
+{
+	struct nfs_fs_context *src = nfs_fc2context(src_fc), *ctx;
+
+	ctx = kmemdup(src, sizeof(struct nfs_fs_context), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->mntfh = nfs_alloc_fhandle();
+	if (!ctx->mntfh) {
+		kfree(ctx);
+		return -ENOMEM;
+	}
+	nfs_copy_fh(ctx->mntfh, src->mntfh);
+
+	__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;
+	fc->fs_private = ctx;
+	return 0;
+}
+
+static void nfs_fs_context_free(struct fs_context *fc)
+{
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+
+	if (ctx) {
+		if (ctx->server)
+			nfs_free_server(ctx->server);
+		if (ctx->nfs_mod)
+			put_nfs_version(ctx->nfs_mod);
+		kfree(ctx->client_address);
+		kfree(ctx->mount_server.hostname);
+		kfree(ctx->nfs_server.export_path);
+		kfree(ctx->nfs_server.hostname);
+		kfree(ctx->fscache_uniq);
+		nfs_free_fhandle(ctx->mntfh);
+		kfree(ctx);
+	}
+}
+
+static const struct fs_context_operations nfs_fs_context_ops = {
+	.free			= nfs_fs_context_free,
+	.dup			= nfs_fs_context_dup,
+	.parse_param		= nfs_fs_context_parse_param,
+	.parse_monolithic	= nfs_fs_context_parse_monolithic,
+	.get_tree		= nfs_get_tree,
+	.reconfigure		= nfs_reconfigure,
+};
+
+/*
+ * 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 nfs_fs_context *ctx;
+
+	ctx = kzalloc(sizeof(struct nfs_fs_context), GFP_KERNEL);
+	if (unlikely(!ctx))
+		return -ENOMEM;
+
+	ctx->mntfh = nfs_alloc_fhandle();
+	if (unlikely(!ctx->mntfh)) {
+		kfree(ctx);
+		return -ENOMEM;
+	}
+
+	ctx->protofamily	= AF_UNSPEC;
+	ctx->mountfamily	= AF_UNSPEC;
+	ctx->mount_server.port	= NFS_UNSPEC_PORT;
+
+	if (fc->root) {
+		/* reconfigure, start with the current config */
+		struct nfs_server *nfss = fc->root->d_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 (fc->net_ns != net) {
+			put_net(fc->net_ns);
+			fc->net_ns = get_net(net);
+		}
+
+		ctx->nfs_mod = nfss->nfs_client->cl_nfs_mod;
+		__module_get(ctx->nfs_mod->owner);
+	} else {
+		/* defaults */
+		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;
+	}
+	fc->fs_private = ctx;
+	fc->ops = &nfs_fs_context_ops;
+	return 0;
 }
+
+struct file_system_type nfs_fs_type = {
+	.owner			= THIS_MODULE,
+	.name			= "nfs",
+	.init_fs_context	= nfs_init_fs_context,
+	.parameters		= &nfs_fs_parameters,
+	.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",
+	.init_fs_context	= nfs_init_fs_context,
+	.parameters		= &nfs_fs_parameters,
+	.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/fscache.c b/fs/nfs/fscache.c
index 3800ab6f08fa..4a8df8c30a03 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -128,7 +128,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/getroot.c b/fs/nfs/getroot.c
index 878c4c5982d9..ab45496d23a6 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -64,66 +64,68 @@ 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 fs_context *fc)
 {
-	struct nfs_server *server = NFS_SB(sb);
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	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(fc->source, 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;
+		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);
+		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);
+		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);
+	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 caaf0af1bc7f..e0911815e153 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -4,18 +4,19 @@
  */
 
 #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>
 #include <linux/nfs_page.h>
 #include <linux/wait_bit.h>
 
-#define NFS_MS_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
+#define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
 
 extern const struct export_operations nfs_export_ops;
 
 struct nfs_string;
+struct nfs_pageio_descriptor;
 
 /* Maximum number of readahead requests
  * FIXME: this should really be a sysctl so that users may tune it to suit
@@ -40,16 +41,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;
-	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.
@@ -90,6 +81,10 @@ struct nfs_client_initdata {
  * In-kernel mount arguments
  */
 struct nfs_fs_context {
+	bool			internal;
+	bool			skip_reconfig_option_check;
+	bool			need_mount;
+	bool			sloppy;
 	unsigned int		flags;		/* NFS{,4}_MOUNT_* flags */
 	unsigned int		rsize, wsize;
 	unsigned int		timeo, retrans;
@@ -106,8 +101,6 @@ struct nfs_fs_context {
 	char			*fscache_uniq;
 	unsigned short		protofamily;
 	unsigned short		mountfamily;
-	bool			need_mount;
-	bool			sloppy;
 
 	struct {
 		union {
@@ -132,14 +125,27 @@ struct nfs_fs_context {
 		int			port;
 		unsigned short		protocol;
 		unsigned short		nconnect;
+		unsigned short		export_path_len;
 	} nfs_server;
 
-	void			*lsm_opts;
-	struct net		*net;
-
-	char			buf[32];	/* Parse buffer */
+	struct nfs_fh		*mntfh;
+	struct nfs_server	*server;
+	struct nfs_subversion	*nfs_mod;
+
+	/* Information for a cloned mount. */
+	struct nfs_clone_mount {
+		struct super_block	*sb;
+		struct dentry		*dentry;
+		struct nfs_fattr	*fattr;
+		unsigned int		inherited_bsize;
+	} clone_data;
 };
 
+static inline struct nfs_fs_context *nfs_fc2context(const struct fs_context *fc)
+{
+	return fc->fs_private;
+}
+
 /* mount_clnt.c */
 struct nfs_mount_request {
 	struct sockaddr		*sap;
@@ -155,15 +161,6 @@ struct nfs_mount_request {
 	struct net		*net;
 };
 
-struct nfs_mount_info {
-	unsigned int inherited_bsize;
-	struct nfs_fs_context *ctx;
-	struct nfs_clone_mount *cloned;
-	struct nfs_server *server;
-	struct nfs_fh *mntfh;
-	struct nfs_subversion *nfs_mod;
-};
-
 extern int nfs_mount(struct nfs_mount_request *info);
 extern void nfs_umount(const struct nfs_mount_request *info);
 
@@ -189,10 +186,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 *);
-extern struct nfs_server *nfs4_create_server(struct nfs_mount_info *);
-extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
-						      struct nfs_fh *);
+extern struct nfs_server *nfs_create_server(struct fs_context *);
+extern struct nfs_server *nfs4_create_server(struct fs_context *);
+extern struct nfs_server *nfs4_create_referral_server(struct fs_context *);
 extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
 					struct sockaddr *sap, size_t salen,
 					struct net *net);
@@ -243,22 +239,8 @@ static inline void nfs_fs_proc_exit(void)
 extern const struct svc_version nfs4_callback_version1;
 extern const 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);
+/* fs_context.c */
+extern struct file_system_type nfs_fs_type;
 
 /* pagelist.c */
 extern int __init nfs_init_nfspagecache(void);
@@ -419,14 +401,9 @@ extern int nfs_wait_atomic_killable(atomic_t *p, unsigned int mode);
 
 /* super.c */
 extern const struct super_operations nfs_sops;
-extern struct file_system_type nfs_fs_type;
-extern struct file_system_type nfs_prepared_fs_type;
-#if IS_ENABLED(CONFIG_NFS_V4)
-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 dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *);
+int nfs_try_get_tree(struct fs_context *);
+int nfs_get_tree_common(struct fs_context *);
 void nfs_kill_super(struct super_block *);
 
 extern struct rpc_stat nfs_rpcstat;
@@ -454,18 +431,13 @@ static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi)
 extern char *nfs_path(char **p, struct dentry *dentry,
 		      char *buffer, ssize_t buflen, unsigned flags);
 extern struct vfsmount *nfs_d_automount(struct path *path);
-struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *,
-			      struct nfs_fh *, struct nfs_fattr *);
-struct vfsmount *nfs_do_submount(struct dentry *, struct nfs_fh *,
-				 struct nfs_fattr *, rpc_authflavor_t);
+int nfs_submount(struct fs_context *, struct nfs_server *);
+int nfs_do_submount(struct fs_context *);
 
 /* 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 fs_context *fc);
 #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 fs_context *cfg);
 extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool);
 #endif
 
@@ -484,7 +456,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_reconfigure(struct fs_context *);
 
 /* 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 72a99f9c7390..3e566a632215 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -140,31 +140,62 @@ EXPORT_SYMBOL_GPL(nfs_path);
  */
 struct vfsmount *nfs_d_automount(struct path *path)
 {
-	struct vfsmount *mnt;
+	struct nfs_fs_context *ctx;
+	struct fs_context *fc;
+	struct vfsmount *mnt = ERR_PTR(-ENOMEM);
 	struct nfs_server *server = NFS_SERVER(d_inode(path->dentry));
-	struct nfs_fh *fh = NULL;
-	struct nfs_fattr *fattr = NULL;
+	struct nfs_client *client = server->nfs_client;
+	int ret;
 
 	if (IS_ROOT(path->dentry))
 		return ERR_PTR(-ESTALE);
 
-	mnt = ERR_PTR(-ENOMEM);
-	fh = nfs_alloc_fhandle();
-	fattr = nfs_alloc_fattr();
-	if (fh == NULL || fattr == NULL)
-		goto out;
+	/* Open a new filesystem context, transferring parameters from the
+	 * parent superblock, including the network namespace.
+	 */
+	fc = fs_context_for_submount(&nfs_fs_type, path->dentry);
+	if (IS_ERR(fc))
+		return ERR_CAST(fc);
 
-	mnt = server->nfs_client->rpc_ops->submount(server, path->dentry, fh, fattr);
+	ctx = nfs_fc2context(fc);
+	ctx->clone_data.dentry	= path->dentry;
+	ctx->clone_data.sb	= path->dentry->d_sb;
+	ctx->clone_data.fattr	= nfs_alloc_fattr();
+	if (!ctx->clone_data.fattr)
+		goto out_fc;
+
+	if (fc->net_ns != client->cl_net) {
+		put_net(fc->net_ns);
+		fc->net_ns = get_net(client->cl_net);
+	}
+
+	/* for submounts we want the same server; referrals will reassign */
+	memcpy(&ctx->nfs_server.address, &client->cl_addr, client->cl_addrlen);
+	ctx->nfs_server.addrlen	= client->cl_addrlen;
+	ctx->nfs_server.port	= server->port;
+
+	ctx->version		= client->rpc_ops->version;
+	ctx->minorversion	= client->cl_minorversion;
+	ctx->nfs_mod		= client->cl_nfs_mod;
+	__module_get(ctx->nfs_mod->owner);
+
+	ret = client->rpc_ops->submount(fc, server);
+	if (ret < 0) {
+		mnt = ERR_PTR(ret);
+		goto out_fc;
+	}
+
+	up_write(&fc->root->d_sb->s_umount);
+	mnt = vfs_create_mount(fc);
 	if (IS_ERR(mnt))
-		goto out;
+		goto out_fc;
 
 	mntget(mnt); /* prevent immediate expiration */
 	mnt_set_expiry(mnt, &nfs_automount_list);
 	schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
 
-out:
-	nfs_free_fattr(fattr);
-	nfs_free_fhandle(fh);
+out_fc:
+	put_fs_context(fc);
 	return mnt;
 }
 
@@ -219,61 +250,62 @@ void nfs_release_automount_timer(void)
  * @authflavor: security flavor to use when performing the mount
  *
  */
-struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
-				 struct nfs_fattr *fattr, rpc_authflavor_t authflavor)
+int nfs_do_submount(struct fs_context *fc)
 {
-	struct super_block *sb = dentry->d_sb;
-	struct nfs_clone_mount mountdata = {
-		.sb = sb,
-		.dentry = dentry,
-		.authflavor = authflavor,
-	};
-	struct nfs_mount_info mount_info = {
-		.inherited_bsize = sb->s_blocksize_bits,
-		.cloned = &mountdata,
-		.mntfh = fh,
-		.nfs_mod = NFS_SB(sb)->nfs_client->cl_nfs_mod,
-	};
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	struct dentry *dentry = ctx->clone_data.dentry;
 	struct nfs_server *server;
-	struct vfsmount *mnt;
-	char *page = (char *) __get_free_page(GFP_USER);
-	char *devname;
+	char *buffer, *p;
+	int ret;
 
-	if (page == NULL)
-		return ERR_PTR(-ENOMEM);
+	/* 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);
 
-	server = mount_info.nfs_mod->rpc_ops->clone_server(NFS_SB(sb), fh,
-							   fattr, authflavor);
 	if (IS_ERR(server))
-		return ERR_CAST(server);
+		return PTR_ERR(server);
 
-	mount_info.server = server;
+	ctx->server = server;
 
-	devname = nfs_devname(dentry, page, PAGE_SIZE);
-	if (IS_ERR(devname))
-		mnt = ERR_CAST(devname);
-	else
-		mnt = vfs_submount(dentry, &nfs_prepared_fs_type, devname, &mount_info);
+	buffer = kmalloc(4096, GFP_USER);
+	if (!buffer)
+		return -ENOMEM;
 
-	if (mount_info.server)
-		nfs_free_server(mount_info.server);
-	free_page((unsigned long)page);
-	return mnt;
+	ctx->internal		= true;
+	ctx->clone_data.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits;
+
+	p = nfs_devname(dentry, buffer, 4096);
+	if (IS_ERR(p)) {
+		dprintk("NFS: Couldn't determine submount pathname\n");
+		ret = PTR_ERR(p);
+	} else {
+		ret = vfs_parse_fs_string(fc, "source", p, buffer + 4096 - p);
+		if (!ret)
+			ret = vfs_get_tree(fc);
+	}
+	kfree(buffer);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(nfs_do_submount);
 
-struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
-			      struct nfs_fh *fh, struct nfs_fattr *fattr)
+int nfs_submount(struct fs_context *fc, struct nfs_server *server)
 {
-	int err;
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	struct dentry *dentry = ctx->clone_data.dentry;
 	struct dentry *parent = dget_parent(dentry);
+	int err;
 
 	/* Look it up again to get its attributes */
-	err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name, fh, fattr, NULL);
+	err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name,
+						  ctx->mntfh, ctx->clone_data.fattr,
+						  NULL);
 	dput(parent);
 	if (err != 0)
-		return ERR_PTR(err);
+		return err;
 
-	return nfs_do_submount(dentry, fh, fattr, server->client->cl_auth->au_flavor);
+	ctx->selected_flavor = server->client->cl_auth->au_flavor;
+	return nfs_do_submount(fc);
 }
 EXPORT_SYMBOL_GPL(nfs_submount);
diff --git a/fs/nfs/nfs3_fs.h b/fs/nfs/nfs3_fs.h
index 09602dc1889f..1b950b66b3bb 100644
--- a/fs/nfs/nfs3_fs.h
+++ b/fs/nfs/nfs3_fs.h
@@ -27,7 +27,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_server *nfs3_create_server(struct 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 a340b5d0e1a3..bfd9b5f03455 100644
--- a/fs/nfs/nfs3client.c
+++ b/fs/nfs/nfs3client.c
@@ -46,9 +46,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_server *nfs3_create_server(struct fs_context *fc)
 {
-	struct nfs_server *server = nfs_create_server(mount_info);
+	struct nfs_server *server = nfs_create_server(fc);
+
 	/* 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 a3ad2d46fd42..912a0b0c9bb9 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -963,7 +963,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 67ecd7bb512f..a6ee4de47774 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -268,14 +268,13 @@ extern const struct dentry_operations nfs4_dentry_operations;
 int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
 		    unsigned, umode_t);
 
-/* super.c */
+/* fs_context.c */
 extern struct file_system_type nfs4_fs_type;
 
 /* nfs4namespace.c */
 struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *,
 					 const struct qstr *);
-struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *,
-			       struct nfs_fh *, struct nfs_fattr *);
+int nfs4_submount(struct fs_context *, struct nfs_server *);
 int nfs4_replace_transport(struct nfs_server *server,
 				const struct nfs4_fs_locations *locations);
 
@@ -517,7 +516,6 @@ extern const nfs4_stateid invalid_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 *);
 extern bool nfs4_disable_idmapping;
 extern unsigned short max_session_slots;
 extern unsigned short max_session_cb_slots;
@@ -527,6 +525,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 fs_context *);
+extern int nfs4_get_referral_tree(struct 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 2ee2281ce404..be26fbe06863 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1052,9 +1052,9 @@ 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_fs_context *ctx)
+static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	struct rpc_timeout timeparms;
 	int error;
 
@@ -1076,15 +1076,15 @@ 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->nfs_server.nconnect,
-			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->nfs_server.nconnect,
+				fc->net_ns);
 	if (error < 0)
 		return error;
 
@@ -1107,10 +1107,9 @@ 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_server *nfs4_create_server(struct fs_context *fc)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	struct nfs_server *server;
 	bool auth_probe;
 	int error;
@@ -1121,14 +1120,14 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info)
 
 	server->cred = get_cred(current_cred());
 
-	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, fc);
 	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;
 
@@ -1142,9 +1141,9 @@ 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 fs_context *fc)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	struct nfs_client *parent_client;
 	struct nfs_server *server, *parent_server;
 	bool auth_probe;
@@ -1154,7 +1153,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;
 
 	server->cred = get_cred(parent_server->cred);
@@ -1164,10 +1163,11 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
 
 	/* Get a client representation */
 #if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
-	rpc_set_port(data->addr, NFS_RDMA_PORT);
-	error = nfs4_set_client(server, data->hostname,
-				data->addr,
-				data->addrlen,
+	rpc_set_port(&ctx->nfs_server.address, NFS_RDMA_PORT);
+	error = nfs4_set_client(server,
+				ctx->nfs_server.hostname,
+				&ctx->nfs_server.address,
+				ctx->nfs_server.addrlen,
 				parent_client->cl_ipaddr,
 				XPRT_TRANSPORT_RDMA,
 				parent_server->client->cl_timeout,
@@ -1178,10 +1178,11 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
 		goto init_server;
 #endif	/* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */
 
-	rpc_set_port(data->addr, NFS_PORT);
-	error = nfs4_set_client(server, data->hostname,
-				data->addr,
-				data->addrlen,
+	rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
+	error = nfs4_set_client(server,
+				ctx->nfs_server.hostname,
+				&ctx->nfs_server.address,
+				ctx->nfs_server.addrlen,
 				parent_client->cl_ipaddr,
 				XPRT_TRANSPORT_TCP,
 				parent_server->client->cl_timeout,
@@ -1194,13 +1195,14 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
 #if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
 init_server:
 #endif
-	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 2e460c33ae48..37999925040a 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -8,6 +8,7 @@
  * NFSv4 namespace
  */
 
+#include <linux/module.h>
 #include <linux/dcache.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
@@ -21,37 +22,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 = 0;
+	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;
+
+	len = nfs4_pathname_len(pathname);
+	if (len < 0)
+		return ERR_PTR(len);
+	*_len = len;
 
-	*--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 = '/';
+	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;
 }
 
 /*
@@ -100,21 +128,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;
 	}
 
@@ -236,55 +268,70 @@ 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,
-				     const struct nfs4_fs_location *location)
+static int try_location(struct fs_context *fc,
+			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 vfsmount *mnt = ERR_PTR(-ENOENT);
-	char *mnt_path;
-	unsigned int maxbuflen;
-	unsigned int s;
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	unsigned int len, s;
+	char *source, *p;
+	int ret = -ENOENT;
+
+	/* 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;
+	}
 
-	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;
+	kfree(ctx->nfs_server.hostname);
+	ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL);
+	if (!ctx->nfs_server.hostname)
+		return -ENOMEM;
 
-	mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL);
-	if (mountdata->addr == NULL)
-		return ERR_PTR(-ENOMEM);
+	source = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1,
+			 GFP_KERNEL);
+	if (!source)
+		return -ENOMEM;
 
+	kfree(fc->source);
+	fc->source = source;
 	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),
+					      fc->net_ns);
+		if (ctx->nfs_server.addrlen == 0)
 			continue;
 
-		memcpy(page2, buf->data, buf->len);
-		page2[buf->len] = '\0';
-		mountdata->hostname = page2;
+		rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
 
-		snprintf(page, PAGE_SIZE, "%s:%s",
-				mountdata->hostname,
-				mountdata->mnt_path);
+		memcpy(ctx->nfs_server.hostname, buf->data, buf->len);
+		ctx->nfs_server.hostname[buf->len] = '\0';
 
-		mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata);
-		if (!IS_ERR(mnt))
-			break;
+		p = source;
+		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;
+
+		ret = nfs4_get_referral_tree(fc);
+		if (ret == 0)
+			return 0;
 	}
-	kfree(mountdata->addr);
-	return mnt;
+
+	return ret;
 }
 
 /**
@@ -293,38 +340,31 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
  * @locations: array of NFSv4 server location information
  *
  */
-static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
-					    const struct nfs4_fs_locations *locations)
+static int nfs_follow_referral(struct fs_context *fc,
+			       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 = nfs_fc2context(fc);
+	char *export_path;
 	int loc, error;
 
 	if (locations == NULL || locations->nlocations <= 0)
-		goto out;
+		return -ENOENT;
 
-	dprintk("%s: referral at %pd2\n", __func__, dentry);
+	dprintk("%s: referral at %pd2\n", __func__, ctx->clone_data.dentry);
 
-	page = (char *) __get_free_page(GFP_USER);
-	if (!page)
-		goto out;
+	export_path = nfs4_pathname_string(&locations->fs_path,
+					   &ctx->nfs_server.export_path_len);
+	if (IS_ERR(export_path))
+		return PTR_ERR(export_path);
 
-	page2 = (char *) __get_free_page(GFP_USER);
-	if (!page2)
-		goto out;
+	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);
-	if (error < 0) {
-		mnt = ERR_PTR(error);
-		goto out;
-	}
+	error = nfs4_validate_fspath(ctx->clone_data.dentry, locations, ctx);
+	if (error < 0)
+		return error;
 
+	error = -ENOENT;
 	for (loc = 0; loc < locations->nlocations; loc++) {
 		const struct nfs4_fs_location *location = &locations->locations[loc];
 
@@ -332,15 +372,12 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
 		    location->rootpath.ncomponents == 0)
 			continue;
 
-		mnt = try_location(&mountdata, page, page2, location);
-		if (!IS_ERR(mnt))
-			break;
+		error = try_location(fc, location);
+		if (error == 0)
+			return 0;
 	}
 
-out:
-	free_page((unsigned long) page);
-	free_page((unsigned long) page2);
-	return mnt;
+	return error;
 }
 
 /*
@@ -348,71 +385,73 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
  * @dentry - dentry of referral
  *
  */
-static struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry)
+static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client)
 {
-	struct vfsmount *mnt = ERR_PTR(-ENOMEM);
-	struct dentry *parent;
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	struct dentry *dentry, *parent;
 	struct nfs4_fs_locations *fs_locations = NULL;
 	struct page *page;
-	int err;
+	int err = -ENOMEM;
 
 	/* BUG_ON(IS_ROOT(dentry)); */
 	page = alloc_page(GFP_KERNEL);
-	if (page == NULL)
-		return mnt;
+	if (!page)
+		return -ENOMEM;
 
 	fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
-	if (fs_locations == NULL)
+	if (!fs_locations)
 		goto out_free;
 
 	/* Get locations */
-	mnt = ERR_PTR(-ENOENT);
-
+	dentry = ctx->clone_data.dentry;
 	parent = dget_parent(dentry);
 	dprintk("%s: getting locations for %pd2\n",
 		__func__, dentry);
 
 	err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page);
 	dput(parent);
-	if (err != 0 ||
-	    fs_locations->nlocations <= 0 ||
+	if (err != 0)
+		goto out_free_2;
+
+	err = -ENOENT;
+	if (fs_locations->nlocations <= 0 ||
 	    fs_locations->fs_path.ncomponents <= 0)
-		goto out_free;
+		goto out_free_2;
 
-	mnt = nfs_follow_referral(dentry, fs_locations);
+	err = nfs_follow_referral(fc, fs_locations);
+out_free_2:
+	kfree(fs_locations);
 out_free:
 	__free_page(page);
-	kfree(fs_locations);
-	return mnt;
+	return err;
 }
 
-struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
-			       struct nfs_fh *fh, struct nfs_fattr *fattr)
+int nfs4_submount(struct fs_context *fc, struct nfs_server *server)
 {
-	rpc_authflavor_t flavor = server->client->cl_auth->au_flavor;
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	struct dentry *dentry = ctx->clone_data.dentry;
 	struct dentry *parent = dget_parent(dentry);
 	struct inode *dir = d_inode(parent);
 	const struct qstr *name = &dentry->d_name;
 	struct rpc_clnt *client;
-	struct vfsmount *mnt;
+	int ret;
 
 	/* Look it up again to get its attributes and sec flavor */
-	client = nfs4_proc_lookup_mountpoint(dir, name, fh, fattr);
+	client = nfs4_proc_lookup_mountpoint(dir, name, ctx->mntfh,
+					     ctx->clone_data.fattr);
 	dput(parent);
 	if (IS_ERR(client))
-		return ERR_CAST(client);
+		return PTR_ERR(client);
 
-	if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
-		mnt = nfs_do_refmount(client, dentry);
-		goto out;
+	if (ctx->clone_data.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
+		ret = nfs_do_refmount(fc, client);
+	} else {
+		ctx->selected_flavor = client->cl_auth->au_flavor;
+		ret = nfs_do_submount(fc);
 	}
 
-	if (client->cl_auth->au_flavor != flavor)
-		flavor = client->cl_auth->au_flavor;
-	mnt = nfs_do_submount(dentry, fh, fattr, flavor);
-out:
 	rpc_shutdown_client(client);
-	return mnt;
+	return ret;
 }
 
 /*
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1406858bae6c..2f31ece2f4a4 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -9895,7 +9895,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
 	.file_ops	= &nfs4_file_operations,
 	.getroot	= nfs4_proc_get_root,
 	.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 ca9740137cfe..3b27c5e3d781 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -4,6 +4,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"
@@ -18,16 +19,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_referral_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *raw_data);
-
-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,
@@ -41,16 +32,15 @@ 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,
 };
 
 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)
@@ -147,105 +137,123 @@ static void nfs_referral_loop_unprotect(void)
 	kfree(p);
 }
 
-static struct dentry *do_nfs4_mount(struct nfs_server *server, int flags,
-				    struct nfs_mount_info *info,
-				    const char *hostname,
-				    const char *export_path)
+static int do_nfs4_mount(struct nfs_server *server,
+			 struct fs_context *fc,
+			 const char *hostname,
+			 const char *export_path)
 {
+	struct nfs_fs_context *root_ctx;
+	struct fs_context *root_fc;
 	struct vfsmount *root_mnt;
 	struct dentry *dentry;
-	char *root_devname;
-	int err;
 	size_t len;
+	int ret;
+
+	struct fs_parameter param = {
+		.key	= "source",
+		.type	= fs_value_is_string,
+		.dirfd	= -1,
+	};
 
 	if (IS_ERR(server))
-		return ERR_CAST(server);
+		return PTR_ERR(server);
 
-	len = strlen(hostname) + 5;
-	root_devname = kmalloc(len, GFP_KERNEL);
-	if (root_devname == NULL) {
+	root_fc = vfs_dup_fs_context(fc);
+	if (IS_ERR(root_fc)) {
 		nfs_free_server(server);
-		return ERR_PTR(-ENOMEM);
+		return PTR_ERR(root_fc);
+	}
+	kfree(root_fc->source);
+	root_fc->source = NULL;
+
+	root_ctx = nfs_fc2context(root_fc);
+	root_ctx->internal = true;
+	root_ctx->server = server;
+	/* We leave export_path unset as it's not used to find the root. */
+
+	len = strlen(hostname) + 5;
+	param.string = kmalloc(len, GFP_KERNEL);
+	if (param.string == NULL) {
+		put_fs_context(root_fc);
+		return -ENOMEM;
 	}
 
 	/* Does hostname needs to be enclosed in brackets? */
 	if (strchr(hostname, ':'))
-		snprintf(root_devname, len, "[%s]:/", hostname);
+		param.size = snprintf(param.string, len, "[%s]:/", hostname);
 	else
-		snprintf(root_devname, len, "%s:/", hostname);
-	info->server = server;
-	root_mnt = vfs_kern_mount(&nfs_prepared_fs_type, flags, root_devname, info);
-	if (info->server)
-		nfs_free_server(info->server);
-	info->server = NULL;
-	kfree(root_devname);
+		param.size = snprintf(param.string, len, "%s:/", hostname);
+	ret = vfs_parse_fs_param(root_fc, &param);
+	kfree(param.string);
+	if (ret < 0) {
+		put_fs_context(root_fc);
+		return ret;
+	}
+	root_mnt = fc_mount(root_fc);
+	put_fs_context(root_fc);
 
 	if (IS_ERR(root_mnt))
-		return ERR_CAST(root_mnt);
+		return PTR_ERR(root_mnt);
 
-	err = nfs_referral_loop_protect();
-	if (err) {
+	ret = nfs_referral_loop_protect();
+	if (ret) {
 		mntput(root_mnt);
-		return ERR_PTR(err);
+		return ret;
 	}
 
 	dentry = mount_subtree(root_mnt, export_path);
 	nfs_referral_loop_unprotect();
 
-	return dentry;
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+
+	fc->root = dentry;
+	return 0;
 }
 
-struct dentry *nfs4_try_mount(int flags, const char *dev_name,
-			      struct nfs_mount_info *mount_info)
+int nfs4_try_get_tree(struct fs_context *fc)
 {
-	struct nfs_fs_context *ctx = mount_info->ctx;
-	struct dentry *res;
-
-	dfprintk(MOUNT, "--> nfs4_try_mount()\n");
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	int err;
 
-	res = do_nfs4_mount(nfs4_create_server(mount_info),
-			    flags, mount_info,
-			    ctx->nfs_server.hostname,
-			    ctx->nfs_server.export_path);
+	dfprintk(MOUNT, "--> nfs4_try_get_tree()\n");
 
-	dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n",
-		 PTR_ERR_OR_ZERO(res),
-		 IS_ERR(res) ? " [error]" : "");
-	return res;
+	/* We create a mount for the server's root, walk to the requested
+	 * location and then create another mount for that.
+	 */
+	err= do_nfs4_mount(nfs4_create_server(fc),
+			   fc, ctx->nfs_server.hostname,
+			   ctx->nfs_server.export_path);
+	if (err) {
+		dfprintk(MOUNT, "<-- nfs4_try_get_tree() = %d [error]\n", err);
+	} else {
+		dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n");
+	}
+	return err;
 }
 
 /*
  * 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)
+int nfs4_get_referral_tree(struct fs_context *fc)
 {
-	struct nfs_clone_mount *data = raw_data;
-	struct nfs_mount_info mount_info = {
-		.cloned = data,
-		.nfs_mod = &nfs_v4,
-	};
-	struct dentry *res;
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	int err;
 
 	dprintk("--> nfs4_referral_mount()\n");
 
-	mount_info.mntfh = nfs_alloc_fhandle();
-	if (!mount_info.mntfh)
-		return ERR_PTR(-ENOMEM);
-
-	res = do_nfs4_mount(nfs4_create_referral_server(mount_info.cloned,
-							mount_info.mntfh),
-			    flags, &mount_info, data->hostname, data->mnt_path);
-
-	dprintk("<-- nfs4_referral_mount() = %d%s\n",
-		PTR_ERR_OR_ZERO(res),
-		IS_ERR(res) ? " [error]" : "");
-
-	nfs_free_fhandle(mount_info.mntfh);
-	return res;
+	/* create a new volume representation */
+	err = do_nfs4_mount(nfs4_create_referral_server(fc),
+			    fc, ctx->nfs_server.hostname,
+			    ctx->nfs_server.export_path);
+	if (err) {
+		dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = %d [error]\n", err);
+	} else {
+		dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n");
+	}
+	return err;
 }
 
-
 static int __init init_nfs_v4(void)
 {
 	int err;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 5552fa8b6e12..03b175fd94b9 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -707,7 +707,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 9aa27093d8b6..60174a30a91a 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -70,28 +70,6 @@
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
 
-static struct dentry *nfs_prepared_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_prepared_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "nfs",
-	.mount		= nfs_prepared_mount,
-	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
-EXPORT_SYMBOL_GPL(nfs_prepared_fs_type);
-
 const struct super_operations nfs_sops = {
 	.alloc_inode	= nfs_alloc_inode,
 	.free_inode	= nfs_free_inode,
@@ -104,22 +82,10 @@ 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,
 };
 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);
@@ -779,11 +745,12 @@ static int nfs_verify_authflavors(struct nfs_fs_context *ctx,
  * 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 *ctx,
+static int nfs_request_mount(struct fs_context *fc,
 			     struct nfs_fh *root_fh,
 			     rpc_authflavor_t *server_authlist,
 			     unsigned int *server_authlist_len)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	struct nfs_mount_request request = {
 		.sap		= (struct sockaddr *)
 						&ctx->mount_server.address,
@@ -793,7 +760,7 @@ static int nfs_request_mount(struct nfs_fs_context *ctx,
 		.noresvport	= ctx->flags & NFS_MOUNT_NORESVPORT,
 		.auth_flav_len	= server_authlist_len,
 		.auth_flavs	= server_authlist,
-		.net		= ctx->net,
+		.net		= fc->net_ns,
 	};
 	int status;
 
@@ -838,20 +805,18 @@ static int nfs_request_mount(struct nfs_fs_context *ctx,
 	return 0;
 }
 
-static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info)
+static struct nfs_server *nfs_try_mount_request(struct fs_context *fc)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	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);
-	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
 
-	status = nfs_request_mount(ctx, mount_info->mntfh, authlist,
-					&authlist_len);
+	status = nfs_request_mount(fc, ctx->mntfh, authlist, &authlist_len);
 	if (status)
 		return ERR_PTR(status);
 
@@ -865,7 +830,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);
+		return ctx->nfs_mod->rpc_ops->create_server(fc);
 	}
 
 	/*
@@ -892,7 +857,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);
+		server = ctx->nfs_mod->rpc_ops->create_server(fc);
 		if (!IS_ERR(server))
 			return server;
 	}
@@ -908,23 +873,22 @@ 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);
+	return ctx->nfs_mod->rpc_ops->create_server(fc);
 }
 
-static struct dentry *nfs_fs_mount_common(int, const char *, struct nfs_mount_info *);
-
-struct dentry *nfs_try_mount(int flags, const char *dev_name,
-			     struct nfs_mount_info *mount_info)
+int nfs_try_get_tree(struct fs_context *fc)
 {
-	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
-	if (mount_info->ctx->need_mount)
-		mount_info->server = nfs_try_mount_request(mount_info);
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+
+	if (ctx->need_mount)
+		ctx->server = nfs_try_mount_request(fc);
 	else
-		mount_info->server = nfs_mod->rpc_ops->create_server(mount_info);
+		ctx->server = ctx->nfs_mod->rpc_ops->create_server(fc);
 
-	return nfs_fs_mount_common(flags, dev_name, mount_info);
+	return nfs_get_tree_common(fc);
 }
-EXPORT_SYMBOL_GPL(nfs_try_mount);
+EXPORT_SYMBOL_GPL(nfs_try_get_tree);
+
 
 #define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
 		| NFS_MOUNT_SECURE \
@@ -965,15 +929,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_reconfigure(struct fs_context *fc)
 {
-	int error;
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
+	struct super_block *sb = fc->root->d_sb;
 	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);
 
@@ -983,64 +943,30 @@ 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_reconfig_option_check)
 		return 0;
 
-	ctx = nfs_alloc_parsed_mount_data();
-	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
+	 * necessarily reflected in the mtab options. reconfigure_super
 	 * will clear SB_SYNCHRONOUS if -o sync wasn't specified in the
 	 * remount options, so we have to explicitly reset it.
 	 */
-	if (ctx->flags & NFS_MOUNT_NOAC)
-		*flags |= SB_SYNCHRONOUS;
+	if (ctx->flags & NFS_MOUNT_NOAC) {
+		fc->sb_flags |= SB_SYNCHRONOUS;
+		fc->sb_flags_mask |= SB_SYNCHRONOUS;
+	}
 
 	/* compare new mount options with old ones */
-	error = nfs_compare_remount_data(nfss, ctx);
-	if (!error)
-		error = security_sb_remount(sb, ctx->lsm_opts);
-out:
-	nfs_free_parsed_mount_data(ctx);
-	return error;
+	return nfs_compare_remount_data(nfss, ctx);
 }
-EXPORT_SYMBOL_GPL(nfs_remount);
+EXPORT_SYMBOL_GPL(nfs_reconfigure);
 
 /*
  * Finish setting up an NFS superblock
  */
-static 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;
@@ -1072,13 +998,14 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_
 	nfs_super_set_maxbytes(sb, server->maxfilesize);
 }
 
-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 fs_context *fc)
 {
 	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_MS_MASK) != (flags & NFS_MS_MASK))
+	if ((s->s_flags & NFS_SB_MASK) != (fc->sb_flags & NFS_SB_MASK))
 		goto Ebusy;
 	if (a->nfs_client != b->nfs_client)
 		goto Ebusy;
@@ -1103,19 +1030,11 @@ 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_server *server = fc->s_fs_info;
 	int ret;
 
-	s->s_flags = sb_mntdata->mntflags;
-	s->s_fs_info = server;
 	s->s_d_op = server->nfs_client->rpc_ops->dentry_ops;
 	ret = set_anon_super(s, server);
 	if (ret == 0)
@@ -1180,11 +1099,9 @@ static int nfs_compare_userns(const struct nfs_server *old,
 	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_server *server = fc->s_fs_info, *old = NFS_SB(sb);
 
 	if (!nfs_compare_super_address(old, server))
 		return 0;
@@ -1195,13 +1112,12 @@ static int nfs_compare_super(struct super_block *sb, void *data)
 		return 0;
 	if (!nfs_compare_userns(old, server))
 		return 0;
-	return nfs_compare_mount_options(sb, server, mntflags);
+	return nfs_compare_mount_options(sb, server, fc);
 }
 
 #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;
@@ -1210,68 +1126,70 @@ 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.sb) {
+		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
 
-static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
-				   struct nfs_mount_info *mount_info)
+int nfs_get_tree_common(struct fs_context *fc)
 {
+	struct nfs_fs_context *ctx = nfs_fc2context(fc);
 	struct super_block *s;
-	struct dentry *mntroot = ERR_PTR(-ENOMEM);
-	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
-	struct nfs_server *server = mount_info->server;
+	int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super;
+	struct nfs_server *server = ctx->server;
 	unsigned long kflags = 0, kflags_out = 0;
-	struct nfs_sb_mountdata sb_mntdata = {
-		.mntflags = flags,
-		.server = server,
-	};
 	int error;
 
-	mount_info->server = NULL;
+	ctx->server = NULL;
 	if (IS_ERR(server))
-		return ERR_CAST(server);
+		return PTR_ERR(server);
 
 	if (server->flags & NFS_MOUNT_UNSHARED)
 		compare_super = NULL;
 
 	/* -o noac implies -o sync */
 	if (server->flags & NFS_MOUNT_NOAC)
-		sb_mntdata.mntflags |= SB_SYNCHRONOUS;
+		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.sb)
+		if (ctx->clone_data.sb->s_flags & SB_SYNCHRONOUS)
+			fc->sb_flags |= SB_SYNCHRONOUS;
+
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		fc->lsm_flags |= SECURITY_LSM_NATIVE_LABELS;
 
 	/* Get a superblock - note that we may end up sharing one that already exists */
-	s = sget(mount_info->nfs_mod->nfs_fs, compare_super, nfs_set_super,
-		 flags, &sb_mntdata);
+	fc->s_fs_info = server;
+	s = sget_fc(fc, compare_super, nfs_set_super);
+	fc->s_fs_info = NULL;
 	if (IS_ERR(s)) {
-		mntroot = ERR_CAST(s);
+		error = PTR_ERR(s);
+		dfprintk(MOUNT, "NFS: Couldn't get superblock\n");
 		goto out_err_nosb;
 	}
 
@@ -1281,44 +1199,41 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 	} else {
 		error = super_setup_bdi_name(s, "%u:%u", MAJOR(server->s_dev),
 					     MINOR(server->s_dev));
-		if (error) {
-			mntroot = ERR_PTR(error);
+		if (error)
 			goto error_splat_super;
-		}
 		s->s_bdi->ra_pages = server->rpages * NFS_MAX_READAHEAD;
 		server->super = s;
 	}
 
 	if (!s->s_root) {
-		unsigned bsize = mount_info->inherited_bsize;
+		unsigned bsize = ctx->clone_data.inherited_bsize;
 		/* initial superblock/root creation */
-		nfs_fill_super(s, mount_info);
+		nfs_fill_super(s, ctx);
 		if (bsize) {
 			s->s_blocksize_bits = bsize;
 			s->s_blocksize = 1U << bsize;
 		}
-		nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned);
-		if (!(server->flags & NFS_MOUNT_UNSHARED))
-			s->s_iflags |= SB_I_MULTIROOT;
+		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, fc);
+	if (error < 0) {
+		dfprintk(MOUNT, "NFS: Couldn't get root dentry\n");
 		goto error_splat_super;
-
+	}
 
 	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
 		kflags |= SECURITY_LSM_NATIVE_LABELS;
-	if (mount_info->cloned) {
-		if (d_inode(mntroot)->i_fop != &nfs_dir_operations) {
+	if (ctx->clone_data.sb) {
+		if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
 			error = -ESTALE;
 			goto error_splat_root;
 		}
 		/* clone any lsm security options from the parent to the new sb */
-		error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags,
+		error = security_sb_clone_mnt_opts(ctx->clone_data.sb, s, kflags,
 				&kflags_out);
 	} else {
-		error = security_sb_set_mnt_opts(s, mount_info->ctx->lsm_opts,
+		error = security_sb_set_mnt_opts(s, fc->security,
 							kflags, &kflags_out);
 	}
 	if (error)
@@ -1326,67 +1241,25 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
 	if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
 		!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
 		NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
-	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);
 	goto out;
 
 error_splat_root:
-	dput(mntroot);
-	mntroot = ERR_PTR(error);
+	dput(fc->root);
+	fc->root = NULL;
 error_splat_super:
 	deactivate_locked_super(s);
 	goto out;
 }
 
-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 = {
-	};
-	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;
-	}
-	mount_info.nfs_mod = nfs_mod;
-
-	mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info);
-
-	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);
-
 /*
  * Destroy an NFS2/3 superblock
  */
@@ -1404,17 +1277,6 @@ void nfs_kill_super(struct super_block *s)
 }
 EXPORT_SYMBOL_GPL(nfs_kill_super);
 
-/*
- * Internal use only: mount_info is already set up by caller.
- * Used for mountpoint crossings and for nfs4 root.
- */
-static struct dentry *
-nfs_prepared_mount(struct file_system_type *fs_type, int flags,
-		   const char *dev_name, void *raw_data)
-{
-	return nfs_fs_mount_common(flags, dev_name, raw_data);
-}
-
 #if IS_ENABLED(CONFIG_NFS_V4)
 
 /*
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 82bdb91da2ae..ed9f215d03ea 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1622,6 +1622,7 @@ struct nfs_subversion;
 struct nfs_mount_info;
 struct nfs_client_initdata;
 struct nfs_pageio_descriptor;
+struct fs_context;
 
 /*
  * RPC procedure vector for NFSv2/NFSv3 demuxing
@@ -1636,9 +1637,8 @@ struct nfs_rpc_ops {
 
 	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fsinfo *);
-	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 *);
+	int	(*submount) (struct fs_context *, struct nfs_server *);
+	int	(*try_get_tree) (struct fs_context *);
 	int	(*getattr) (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fattr *, struct nfs4_label *,
 			    struct inode *);
@@ -1705,7 +1705,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_server *(*create_server)(struct fs_context *);
 	struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
 					   struct nfs_fattr *, rpc_authflavor_t);
 };
-- 
2.17.2


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

* [PATCH v3 26/26] NFS: Attach supplementary error information to fs_context.
  2019-09-11 16:15 [PATCH v3 00/26] nfs: Mount API conversion Scott Mayhew
                   ` (24 preceding siblings ...)
  2019-09-11 16:16 ` [PATCH v3 25/26] NFS: Add fs_context support Scott Mayhew
@ 2019-09-11 16:16 ` Scott Mayhew
  25 siblings, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-11 16:16 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel

Split out from commit "NFS: Add fs_context support."

Add wrappers nfs_errorf(), nfs_invalf(), and nfs_warnf() which log error
information to the fs_context.  Convert some printk's to use these new
wrappers instead.

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
 fs/nfs/fs_context.c | 105 +++++++++++++++-----------------------------
 fs/nfs/getroot.c    |   3 ++
 fs/nfs/internal.h   |   4 ++
 fs/nfs/namespace.c  |   2 +-
 fs/nfs/nfs4super.c  |   2 +
 fs/nfs/super.c      |   4 +-
 6 files changed, 48 insertions(+), 72 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 14c43d1c7da9..03044aaa8e17 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -321,10 +321,8 @@ static int nfs_auth_info_add(struct fs_context *fc,
 			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 nfs_invalf(fc, "NFS: too many sec= flavors");
 
 	auth_info->flavors[auth_info->flavor_len++] = flavor;
 	return 0;
@@ -381,9 +379,7 @@ static int nfs_parse_security_flavors(struct fs_context *fc,
 			pseudoflavor = RPC_AUTH_GSS_SPKMP;
 			break;
 		default:
-			dfprintk(MOUNT,
-				 "NFS: sec= option '%s' not recognized\n", p);
-			return -EINVAL;
+			return nfs_invalf(fc, "NFS: sec=%s option not recognized", p);
 		}
 
 		ret = nfs_auth_info_add(fc, &ctx->auth_info, pseudoflavor);
@@ -428,8 +424,7 @@ static int nfs_parse_version_string(struct fs_context *fc,
 		ctx->minorversion = 2;
 		break;
 	default:
-		dfprintk(MOUNT, "NFS:   Unsupported NFS version\n");
-		return -EINVAL;
+		return nfs_invalf(fc, "NFS: Unsupported NFS version");
 	}
 	return 0;
 }
@@ -454,10 +449,8 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
 
 	switch (opt) {
 	case Opt_source:
-		if (fc->source) {
-			dfprintk(MOUNT, "NFS: Multiple sources not supported\n");
-			return -EINVAL;
-		}
+		if (fc->source)
+			return nfs_invalf(fc, "NFS: Multiple sources not supported");
 		fc->source = param->string;
 		param->string = NULL;
 		break;
@@ -667,8 +660,7 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
 			xprt_load_transport(param->string);
 			break;
 		default:
-			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
-			return -EINVAL;
+			return nfs_invalf(fc, "NFS: Unrecognized transport protocol");
 		}
 
 		ctx->protofamily = protofamily;
@@ -691,8 +683,7 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
 			break;
 		case Opt_xprt_rdma: /* not used for side protocols */
 		default:
-			dfprintk(MOUNT, "NFS:   unrecognized transport protocol\n");
-			return -EINVAL;
+			return nfs_invalf(fc, "NFS: Unrecognized transport protocol");
 		}
 		ctx->mountfamily = mountfamily;
 		break;
@@ -777,13 +768,11 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
 	return 0;
 
 out_invalid_value:
-	printk(KERN_INFO "NFS: Bad mount option value specified\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFS: Bad mount option value specified");
 out_invalid_address:
-	printk(KERN_INFO "NFS: Bad IP address specified\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFS: Bad IP address specified");
 out_of_bounds:
-	printk(KERN_INFO "NFS: Value for '%s' out of range\n", param->key);
+	nfs_invalf(fc, "NFS: Value for '%s' out of range", param->key);
 	return -ERANGE;
 }
 
@@ -849,19 +838,15 @@ static int nfs_parse_source(struct fs_context *fc,
 	return 0;
 
 out_bad_devname:
-	dfprintk(MOUNT, "NFS: device name not in host:path format\n");
-	return -EINVAL;
-
+	return nfs_invalf(fc, "NFS: device name not in host:path format");
 out_nomem:
-	dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
+	nfs_errorf(fc, "NFS: not enough memory to parse device name");
 	return -ENOMEM;
-
 out_hostname:
-	dfprintk(MOUNT, "NFS: server hostname too long\n");
+	nfs_errorf(fc, "NFS: server hostname too long");
 	return -ENAMETOOLONG;
-
 out_path:
-	dfprintk(MOUNT, "NFS: export pathname too long\n");
+	nfs_errorf(fc, "NFS: export pathname too long");
 	return -ENAMETOOLONG;
 }
 
@@ -1018,29 +1003,23 @@ static int nfs23_parse_monolithic(struct fs_context *fc,
 		ctx->skip_reconfig_option_check = true;
 		return 0;
 	}
-	dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "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 nfs_invalf(fc, "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 nfs_invalf(fc, "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 nfs_invalf(fc, "NFS: mount program didn't pass remote address");
 
 out_invalid_fh:
-	dfprintk(MOUNT, "NFS: invalid root filehandle\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFS: invalid root filehandle");
 }
 
 #if IS_ENABLED(CONFIG_NFS_V4)
@@ -1135,21 +1114,17 @@ static int nfs4_parse_monolithic(struct fs_context *fc,
 		ctx->skip_reconfig_option_check = true;
 		return 0;
 	}
-	dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "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 nfs_invalf(fc, "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 nfs_invalf(fc, "NFS4: mount program didn't pass remote address");
 
 out_invalid_transport_udp:
-	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFSv4: Unsupported transport protocol udp");
 }
 #endif
 
@@ -1167,8 +1142,7 @@ static int nfs_fs_context_parse_monolithic(struct fs_context *fc,
 		return nfs4_parse_monolithic(fc, data);
 #endif
 
-	dfprintk(MOUNT, "NFS: Unsupported monolithic data version\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFS: Unsupported monolithic data version");
 }
 
 /*
@@ -1256,32 +1230,25 @@ static int nfs_fs_context_validate(struct fs_context *fc)
 	return 0;
 
 out_no_device_name:
-	dfprintk(MOUNT, "NFS: Device name not specified\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFS: Device name not specified");
 out_v4_not_compiled:
-	dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
+	nfs_errorf(fc, "NFS: NFSv4 is not compiled into kernel");
 	return -EPROTONOSUPPORT;
 out_invalid_transport_udp:
-	dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFSv4: Unsupported transport protocol udp");
 out_no_address:
-	dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFS: mount program didn't pass remote address");
 out_mountproto_mismatch:
-	dfprintk(MOUNT, "NFS: Mount server address does not match mountproto= option\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFS: Mount server address does not match mountproto= option");
 out_proto_mismatch:
-	dfprintk(MOUNT, "NFS: Server address does not match proto= option\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFS: Server address does not match proto= option");
 out_minorversion_mismatch:
-	dfprintk(MOUNT, "NFS: Mount option vers=%u does not support minorversion=%u\n",
+	return nfs_invalf(fc, "NFS: Mount option vers=%u does not support minorversion=%u",
 			  ctx->version, ctx->minorversion);
-	return -EINVAL;
 out_migration_misuse:
-	dfprintk(MOUNT, "NFS: 'Migration' not supported for this NFS version\n");
-	return -EINVAL;
+	return nfs_invalf(fc, "NFS: 'Migration' not supported for this NFS version");
 out_version_unavailable:
-	dfprintk(MOUNT, "NFS: Version unavailable\n");
+	nfs_errorf(fc, "NFS: Version unavailable");
 	return ret;
 }
 
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index ab45496d23a6..b012c2668a1f 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -86,6 +86,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
 	error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
 	if (error < 0) {
 		dprintk("nfs_get_root: getattr error = %d\n", -error);
+		nfs_errorf(fc, "NFS: Couldn't getattr on root");
 		goto out_fattr;
 	}
 
@@ -93,6 +94,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
 	if (IS_ERR(inode)) {
 		dprintk("nfs_get_root: get root inode failed\n");
 		error = PTR_ERR(inode);
+		nfs_errorf(fc, "NFS: Couldn't get root inode");
 		goto out_fattr;
 	}
 
@@ -108,6 +110,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
 	if (IS_ERR(root)) {
 		dprintk("nfs_get_root: get root dentry failed\n");
 		error = PTR_ERR(root);
+		nfs_errorf(fc, "NFS: Couldn't get root dentry");
 		goto out_fattr;
 	}
 
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index e0911815e153..e1f46034814f 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -141,6 +141,10 @@ struct nfs_fs_context {
 	} clone_data;
 };
 
+#define nfs_errorf(fc, fmt, ...) errorf(fc, fmt, ## __VA_ARGS__)
+#define nfs_invalf(fc, fmt, ...) invalf(fc, fmt, ## __VA_ARGS__)
+#define nfs_warnf(fc, fmt, ...) warnf(fc, fmt, ## __VA_ARGS__)
+
 static inline struct nfs_fs_context *nfs_fc2context(const struct fs_context *fc)
 {
 	return fc->fs_private;
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 3e566a632215..c1824bc6336b 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -278,7 +278,7 @@ int nfs_do_submount(struct fs_context *fc)
 
 	p = nfs_devname(dentry, buffer, 4096);
 	if (IS_ERR(p)) {
-		dprintk("NFS: Couldn't determine submount pathname\n");
+		nfs_errorf(fc, "NFS: Couldn't determine submount pathname");
 		ret = PTR_ERR(p);
 	} else {
 		ret = vfs_parse_fs_string(fc, "source", p, buffer + 4096 - p);
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 3b27c5e3d781..54e9c54bd08d 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -225,6 +225,7 @@ int nfs4_try_get_tree(struct fs_context *fc)
 			   fc, ctx->nfs_server.hostname,
 			   ctx->nfs_server.export_path);
 	if (err) {
+		nfs_errorf(fc, "NFS4: Couldn't follow remote path");
 		dfprintk(MOUNT, "<-- nfs4_try_get_tree() = %d [error]\n", err);
 	} else {
 		dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n");
@@ -247,6 +248,7 @@ int nfs4_get_referral_tree(struct fs_context *fc)
 			    fc, ctx->nfs_server.hostname,
 			    ctx->nfs_server.export_path);
 	if (err) {
+		nfs_errorf(fc, "NFS4: Couldn't follow remote path");
 		dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = %d [error]\n", err);
 	} else {
 		dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n");
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 60174a30a91a..2e363cc65688 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1189,7 +1189,7 @@ int nfs_get_tree_common(struct fs_context *fc)
 	fc->s_fs_info = NULL;
 	if (IS_ERR(s)) {
 		error = PTR_ERR(s);
-		dfprintk(MOUNT, "NFS: Couldn't get superblock\n");
+		nfs_errorf(fc, "NFS: Couldn't get superblock");
 		goto out_err_nosb;
 	}
 
@@ -1218,7 +1218,7 @@ int nfs_get_tree_common(struct fs_context *fc)
 
 	error = nfs_get_root(s, fc);
 	if (error < 0) {
-		dfprintk(MOUNT, "NFS: Couldn't get root dentry\n");
+		nfs_errorf(fc, "NFS: Couldn't get root dentry");
 		goto error_splat_super;
 	}
 
-- 
2.17.2


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

* Re: [PATCH v3 16/26] NFS: Move mount parameterisation bits into their own file
  2019-09-11 16:16 ` [PATCH v3 16/26] NFS: Move mount parameterisation bits into their own file Scott Mayhew
@ 2019-09-11 18:24   ` Chuck Lever
  2019-09-11 19:00     ` Trond Myklebust
  2019-09-12 17:35     ` Scott Mayhew
  0 siblings, 2 replies; 32+ messages in thread
From: Chuck Lever @ 2019-09-11 18:24 UTC (permalink / raw)
  To: Scott Mayhew
  Cc: Anna Schumaker, trond.myklebust, David Howells, Al Viro,
	Linux NFS Mailing List, linux-fsdevel, linux-kernel



> On Sep 11, 2019, at 12:16 PM, Scott Mayhew <smayhew@redhat.com> wrote:
> 
> From: David Howells <dhowells@redhat.com>
> 
> 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>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
> fs/nfs/Makefile     |    2 +-
> fs/nfs/fs_context.c | 1418 +++++++++++++++++++++++++++++++++++++++++++
> fs/nfs/internal.h   |   29 +
> fs/nfs/super.c      | 1411 ------------------------------------------
> 4 files changed, 1448 insertions(+), 1412 deletions(-)
> create mode 100644 fs/nfs/fs_context.c
> 
> diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
> index 34cdeaecccf6..2433c3e03cfa 100644
> --- a/fs/nfs/Makefile
> +++ b/fs/nfs/Makefile
> @@ -9,7 +9,7 @@ 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 \
> -			   export.o sysfs.o
> +			   export.o sysfs.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..82b312a5cdde
> --- /dev/null
> +++ b/fs/nfs/fs_context.c
> @@ -0,0 +1,1418 @@
> +/* NFS mount handling.
> + *
> + * Copyright (C) 2018 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.
> + */

New source files should have an SPDX tag instead of boilerplate.
I suggest:

// SPDX-License-Identifier: GPL-2.0-only


> +
> +#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
> +
> +#define NFS_MAX_CONNECTIONS 16
> +
> +enum {
> +	/* Mount options that take no arguments */
> +	Opt_soft, Opt_softerr, 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_nconnect,
> +	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_softerr, "softerr" },
> +	{ 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_nconnect, "nconnect=%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;
> +		data->lsm_opts		= NULL;
> +	}
> +	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;
> +	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);
> +
> +	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
> +	if (rc)
> +		goto out_security_failure;
> +
> +	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;
> +			mnt->flags &= ~NFS_MOUNT_SOFTERR;
> +			break;
> +		case Opt_softerr:
> +			mnt->flags |= NFS_MOUNT_SOFTERR;
> +			mnt->flags &= ~NFS_MOUNT_SOFT;
> +			break;
> +		case Opt_hard:
> +			mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
> +			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;
> +				/* fall through */
> +			case Opt_xprt_udp:
> +				mnt->flags &= ~NFS_MOUNT_TCP;
> +				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
> +				break;
> +			case Opt_xprt_tcp6:
> +				protofamily = AF_INET6;
> +				/* fall through */
> +			case Opt_xprt_tcp:
> +				mnt->flags |= NFS_MOUNT_TCP;
> +				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
> +				break;
> +			case Opt_xprt_rdma6:
> +				protofamily = AF_INET6;
> +				/* fall through */
> +			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;
> +				/* fall through */
> +			case Opt_xprt_udp:
> +				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
> +				break;
> +			case Opt_xprt_tcp6:
> +				mountfamily = AF_INET6;
> +				/* fall through */
> +			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_nconnect:
> +			if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
> +				goto out_invalid_value;
> +			mnt->nfs_server.nconnect = option;
> +			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:
> +	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;
> +
> +	if (unlikely(!dev_name || !*dev_name)) {
> +		dfprintk(MOUNT, "NFS: device name not specified\n");
> +		return -EINVAL;
> +	}
> +
> +	/* 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)
> +			len = comma - dev_name;
> +	}
> +
> +	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; /* fall through */
> +	case 2:
> +		data->bsize = 0; /* fall through */
> +	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;
> +		/* fall through */
> +	case 4:
> +		if (data->flags & NFS_MOUNT_SECFLAVOUR)
> +			goto out_no_sec;
> +		/* fall through */
> +	case 5:
> +		memset(data->context, 0, sizeof(data->context));
> +		/* fall through */
> +	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 (sap->sa_family != AF_INET ||
> +		    !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;
> +			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
> +			rc = security_add_mnt_opt("context", data->context,
> +					strlen(data->context), &args->lsm_opts);
> +			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)
> +		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> +			port = NFS_RDMA_PORT;
> +		else
> +			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);
> +		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> +			port = NFS_RDMA_PORT;
> +	}
> +
> +	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 d512ec394559..b66fd35993b3 100644
> --- a/fs/nfs/internal.h
> +++ b/fs/nfs/internal.h
> @@ -7,6 +7,7 @@
> #include <linux/mount.h>
> #include <linux/security.h>
> #include <linux/crc32.h>
> +#include <linux/sunrpc/addr.h>
> #include <linux/nfs_page.h>
> #include <linux/wait_bit.h>
> 
> @@ -232,6 +233,22 @@ extern const struct svc_version nfs4_callback_version1;
> extern const 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);
> @@ -763,3 +780,15 @@ static inline bool nfs_error_is_fatal(int err)
> 	}
> }
> 
> +/*
> + * 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 d8702e57f7fc..886220d2da4e 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -69,229 +69,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
> -
> -#define NFS_MAX_CONNECTIONS 16
> -
> -enum {
> -	/* Mount options that take no arguments */
> -	Opt_soft, Opt_softerr, 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_nconnect,
> -	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_softerr, "softerr" },
> -	{ 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_nconnect, "nconnect=%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_prepared_mount(struct file_system_type *fs_type,
> 		int flags, const char *dev_name, void *raw_data);
> @@ -332,10 +109,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",
> @@ -932,141 +705,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;
> -		data->lsm_opts		= NULL;
> -	}
> -	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.
> @@ -1087,627 +725,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;
> -	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);
> -
> -	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
> -	if (rc)
> -		goto out_security_failure;
> -
> -	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;
> -			mnt->flags &= ~NFS_MOUNT_SOFTERR;
> -			break;
> -		case Opt_softerr:
> -			mnt->flags |= NFS_MOUNT_SOFTERR;
> -			mnt->flags &= ~NFS_MOUNT_SOFT;
> -			break;
> -		case Opt_hard:
> -			mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
> -			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;
> -				/* fall through */
> -			case Opt_xprt_udp:
> -				mnt->flags &= ~NFS_MOUNT_TCP;
> -				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
> -				break;
> -			case Opt_xprt_tcp6:
> -				protofamily = AF_INET6;
> -				/* fall through */
> -			case Opt_xprt_tcp:
> -				mnt->flags |= NFS_MOUNT_TCP;
> -				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
> -				break;
> -			case Opt_xprt_rdma6:
> -				protofamily = AF_INET6;
> -				/* fall through */
> -			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;
> -				/* fall through */
> -			case Opt_xprt_udp:
> -				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
> -				break;
> -			case Opt_xprt_tcp6:
> -				mountfamily = AF_INET6;
> -				/* fall through */
> -			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_nconnect:
> -			if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
> -				goto out_invalid_value;
> -			mnt->nfs_server.nconnect = option;
> -			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:
> -	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
> @@ -1908,327 +925,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;
> -
> -	if (unlikely(!dev_name || !*dev_name)) {
> -		dfprintk(MOUNT, "NFS: device name not specified\n");
> -		return -EINVAL;
> -	}
> -
> -	/* 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)
> -			len = comma - dev_name;
> -	}
> -
> -	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; /* fall through */
> -	case 2:
> -		data->bsize = 0; /* fall through */
> -	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;
> -		/* fall through */
> -	case 4:
> -		if (data->flags & NFS_MOUNT_SECFLAVOUR)
> -			goto out_no_sec;
> -		/* fall through */
> -	case 5:
> -		memset(data->context, 0, sizeof(data->context));
> -		/* fall through */
> -	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 (sap->sa_family != AF_INET ||
> -		    !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;
> -			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
> -			rc = security_add_mnt_opt("context", data->context,
> -					strlen(data->context), &args->lsm_opts);
> -			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)
> -		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> -			port = NFS_RDMA_PORT;
> -		else
> -			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);
> -		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> -			port = NFS_RDMA_PORT;
> -	}
> -
> -	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 \
> @@ -2719,113 +1415,6 @@ nfs_prepared_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
> -- 
> 2.17.2
> 

--
Chuck Lever
chucklever@gmail.com




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

* Re: [PATCH v3 16/26] NFS: Move mount parameterisation bits into their own file
  2019-09-11 18:24   ` Chuck Lever
@ 2019-09-11 19:00     ` Trond Myklebust
  2019-09-12 17:36       ` Scott Mayhew
  2019-09-12 17:35     ` Scott Mayhew
  1 sibling, 1 reply; 32+ messages in thread
From: Trond Myklebust @ 2019-09-11 19:00 UTC (permalink / raw)
  To: chucklever, smayhew
  Cc: linux-nfs, linux-fsdevel, anna.schumaker, viro, dhowells, linux-kernel

On Wed, 2019-09-11 at 14:24 -0400, Chuck Lever wrote:
> > On Sep 11, 2019, at 12:16 PM, Scott Mayhew <smayhew@redhat.com>
> > wrote:
> > 
> > From: David Howells <dhowells@redhat.com>
> > 
> > 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>
> > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> > ---
> > fs/nfs/Makefile     |    2 +-
> > fs/nfs/fs_context.c | 1418
> > +++++++++++++++++++++++++++++++++++++++++++
> > fs/nfs/internal.h   |   29 +
> > fs/nfs/super.c      | 1411 ----------------------------------------
> > --
> > 4 files changed, 1448 insertions(+), 1412 deletions(-)
> > create mode 100644 fs/nfs/fs_context.c
> > 
> > diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
> > index 34cdeaecccf6..2433c3e03cfa 100644
> > --- a/fs/nfs/Makefile
> > +++ b/fs/nfs/Makefile
> > @@ -9,7 +9,7 @@ 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
> > \
> > -			   export.o sysfs.o
> > +			   export.o sysfs.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..82b312a5cdde
> > --- /dev/null
> > +++ b/fs/nfs/fs_context.c
> > @@ -0,0 +1,1418 @@
> > +/* NFS mount handling.
> > + *
> > + * Copyright (C) 2018 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.
> > + */
> 
> New source files should have an SPDX tag instead of boilerplate.
> I suggest:
> 
> // SPDX-License-Identifier: GPL-2.0-only
> 

Agreed. It is also quite a long stretch to claim authorship of the
entire file as implied above. Given that this is mostly a copy-paste
effort, then most of the actual copyrights belong to the people who've
contributed to super.c (and to inode.c before it). David is one of
those authors, but he is one of many.


> > +#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
> > +
> > +#define NFS_MAX_CONNECTIONS 16
> > +
> > +enum {
> > +	/* Mount options that take no arguments */
> > +	Opt_soft, Opt_softerr, 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_nconnect,
> > +	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_softerr, "softerr" },
> > +	{ 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_nconnect, "nconnect=%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;
> > +		data->lsm_opts		= NULL;
> > +	}
> > +	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;
> > +	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);
> > +
> > +	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
> > +	if (rc)
> > +		goto out_security_failure;
> > +
> > +	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;
> > +			mnt->flags &= ~NFS_MOUNT_SOFTERR;
> > +			break;
> > +		case Opt_softerr:
> > +			mnt->flags |= NFS_MOUNT_SOFTERR;
> > +			mnt->flags &= ~NFS_MOUNT_SOFT;
> > +			break;
> > +		case Opt_hard:
> > +			mnt->flags &=
> > ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
> > +			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;
> > +				/* fall through */
> > +			case Opt_xprt_udp:
> > +				mnt->flags &= ~NFS_MOUNT_TCP;
> > +				mnt->nfs_server.protocol =
> > XPRT_TRANSPORT_UDP;
> > +				break;
> > +			case Opt_xprt_tcp6:
> > +				protofamily = AF_INET6;
> > +				/* fall through */
> > +			case Opt_xprt_tcp:
> > +				mnt->flags |= NFS_MOUNT_TCP;
> > +				mnt->nfs_server.protocol =
> > XPRT_TRANSPORT_TCP;
> > +				break;
> > +			case Opt_xprt_rdma6:
> > +				protofamily = AF_INET6;
> > +				/* fall through */
> > +			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;
> > +				/* fall through */
> > +			case Opt_xprt_udp:
> > +				mnt->mount_server.protocol =
> > XPRT_TRANSPORT_UDP;
> > +				break;
> > +			case Opt_xprt_tcp6:
> > +				mountfamily = AF_INET6;
> > +				/* fall through */
> > +			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_nconnect:
> > +			if (nfs_get_option_ul_bound(args, &option, 1,
> > NFS_MAX_CONNECTIONS))
> > +				goto out_invalid_value;
> > +			mnt->nfs_server.nconnect = option;
> > +			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:
> > +	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;
> > +
> > +	if (unlikely(!dev_name || !*dev_name)) {
> > +		dfprintk(MOUNT, "NFS: device name not specified\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* 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)
> > +			len = comma - dev_name;
> > +	}
> > +
> > +	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; /* fall through */
> > +	case 2:
> > +		data->bsize = 0; /* fall through */
> > +	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;
> > +		/* fall through */
> > +	case 4:
> > +		if (data->flags & NFS_MOUNT_SECFLAVOUR)
> > +			goto out_no_sec;
> > +		/* fall through */
> > +	case 5:
> > +		memset(data->context, 0, sizeof(data->context));
> > +		/* fall through */
> > +	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 (sap->sa_family != AF_INET ||
> > +		    !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;
> > +			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
> > +			rc = security_add_mnt_opt("context", data-
> > >context,
> > +					strlen(data->context), &args-
> > >lsm_opts);
> > +			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)
> > +		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > +			port = NFS_RDMA_PORT;
> > +		else
> > +			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);
> > +		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > +			port = NFS_RDMA_PORT;
> > +	}
> > +
> > +	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 d512ec394559..b66fd35993b3 100644
> > --- a/fs/nfs/internal.h
> > +++ b/fs/nfs/internal.h
> > @@ -7,6 +7,7 @@
> > #include <linux/mount.h>
> > #include <linux/security.h>
> > #include <linux/crc32.h>
> > +#include <linux/sunrpc/addr.h>
> > #include <linux/nfs_page.h>
> > #include <linux/wait_bit.h>
> > 
> > @@ -232,6 +233,22 @@ extern const struct svc_version
> > nfs4_callback_version1;
> > extern const 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);
> > @@ -763,3 +780,15 @@ static inline bool nfs_error_is_fatal(int err)
> > 	}
> > }
> > 
> > +/*
> > + * 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 d8702e57f7fc..886220d2da4e 100644
> > --- a/fs/nfs/super.c
> > +++ b/fs/nfs/super.c
> > @@ -69,229 +69,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
> > -
> > -#define NFS_MAX_CONNECTIONS 16
> > -
> > -enum {
> > -	/* Mount options that take no arguments */
> > -	Opt_soft, Opt_softerr, 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_nconnect,
> > -	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_softerr, "softerr" },
> > -	{ 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_nconnect, "nconnect=%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_prepared_mount(struct file_system_type
> > *fs_type,
> > 		int flags, const char *dev_name, void *raw_data);
> > @@ -332,10 +109,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",
> > @@ -932,141 +705,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;
> > -		data->lsm_opts		= NULL;
> > -	}
> > -	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.
> > @@ -1087,627 +725,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;
> > -	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);
> > -
> > -	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
> > -	if (rc)
> > -		goto out_security_failure;
> > -
> > -	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;
> > -			mnt->flags &= ~NFS_MOUNT_SOFTERR;
> > -			break;
> > -		case Opt_softerr:
> > -			mnt->flags |= NFS_MOUNT_SOFTERR;
> > -			mnt->flags &= ~NFS_MOUNT_SOFT;
> > -			break;
> > -		case Opt_hard:
> > -			mnt->flags &=
> > ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
> > -			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;
> > -				/* fall through */
> > -			case Opt_xprt_udp:
> > -				mnt->flags &= ~NFS_MOUNT_TCP;
> > -				mnt->nfs_server.protocol =
> > XPRT_TRANSPORT_UDP;
> > -				break;
> > -			case Opt_xprt_tcp6:
> > -				protofamily = AF_INET6;
> > -				/* fall through */
> > -			case Opt_xprt_tcp:
> > -				mnt->flags |= NFS_MOUNT_TCP;
> > -				mnt->nfs_server.protocol =
> > XPRT_TRANSPORT_TCP;
> > -				break;
> > -			case Opt_xprt_rdma6:
> > -				protofamily = AF_INET6;
> > -				/* fall through */
> > -			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;
> > -				/* fall through */
> > -			case Opt_xprt_udp:
> > -				mnt->mount_server.protocol =
> > XPRT_TRANSPORT_UDP;
> > -				break;
> > -			case Opt_xprt_tcp6:
> > -				mountfamily = AF_INET6;
> > -				/* fall through */
> > -			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_nconnect:
> > -			if (nfs_get_option_ul_bound(args, &option, 1,
> > NFS_MAX_CONNECTIONS))
> > -				goto out_invalid_value;
> > -			mnt->nfs_server.nconnect = option;
> > -			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:
> > -	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
> > @@ -1908,327 +925,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;
> > -
> > -	if (unlikely(!dev_name || !*dev_name)) {
> > -		dfprintk(MOUNT, "NFS: device name not specified\n");
> > -		return -EINVAL;
> > -	}
> > -
> > -	/* 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)
> > -			len = comma - dev_name;
> > -	}
> > -
> > -	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; /* fall through */
> > -	case 2:
> > -		data->bsize = 0; /* fall through */
> > -	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;
> > -		/* fall through */
> > -	case 4:
> > -		if (data->flags & NFS_MOUNT_SECFLAVOUR)
> > -			goto out_no_sec;
> > -		/* fall through */
> > -	case 5:
> > -		memset(data->context, 0, sizeof(data->context));
> > -		/* fall through */
> > -	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 (sap->sa_family != AF_INET ||
> > -		    !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;
> > -			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
> > -			rc = security_add_mnt_opt("context", data-
> > >context,
> > -					strlen(data->context), &args-
> > >lsm_opts);
> > -			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)
> > -		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > -			port = NFS_RDMA_PORT;
> > -		else
> > -			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);
> > -		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > -			port = NFS_RDMA_PORT;
> > -	}
> > -
> > -	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 \
> > @@ -2719,113 +1415,6 @@ nfs_prepared_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
> > -- 
> > 2.17.2
> > 
> 
> --
> Chuck Lever
> chucklever@gmail.com
> 
> 
> 
-- 
Trond Myklebust
Linux NFS client maintainer, Hammerspace
trond.myklebust@hammerspace.com



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

* Re: [PATCH v3 16/26] NFS: Move mount parameterisation bits into their own file
  2019-09-11 18:24   ` Chuck Lever
  2019-09-11 19:00     ` Trond Myklebust
@ 2019-09-12 17:35     ` Scott Mayhew
  1 sibling, 0 replies; 32+ messages in thread
From: Scott Mayhew @ 2019-09-12 17:35 UTC (permalink / raw)
  To: Chuck Lever
  Cc: Anna Schumaker, trond.myklebust, David Howells, Al Viro,
	Linux NFS Mailing List, linux-fsdevel, linux-kernel

On Wed, 11 Sep 2019, Chuck Lever wrote:

> 
> 
> > On Sep 11, 2019, at 12:16 PM, Scott Mayhew <smayhew@redhat.com> wrote:
> > 
> > From: David Howells <dhowells@redhat.com>
> > 
> > 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>
> > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> > ---
> > fs/nfs/Makefile     |    2 +-
> > fs/nfs/fs_context.c | 1418 +++++++++++++++++++++++++++++++++++++++++++
> > fs/nfs/internal.h   |   29 +
> > fs/nfs/super.c      | 1411 ------------------------------------------
> > 4 files changed, 1448 insertions(+), 1412 deletions(-)
> > create mode 100644 fs/nfs/fs_context.c
> > 
> > diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
> > index 34cdeaecccf6..2433c3e03cfa 100644
> > --- a/fs/nfs/Makefile
> > +++ b/fs/nfs/Makefile
> > @@ -9,7 +9,7 @@ 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 \
> > -			   export.o sysfs.o
> > +			   export.o sysfs.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..82b312a5cdde
> > --- /dev/null
> > +++ b/fs/nfs/fs_context.c
> > @@ -0,0 +1,1418 @@
> > +/* NFS mount handling.
> > + *
> > + * Copyright (C) 2018 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.
> > + */
> 
> New source files should have an SPDX tag instead of boilerplate.
> I suggest:
> 
> // SPDX-License-Identifier: GPL-2.0-only
> 
Got it - thanks.

-Scott
> 
> > +
> > +#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
> > +
> > +#define NFS_MAX_CONNECTIONS 16
> > +
> > +enum {
> > +	/* Mount options that take no arguments */
> > +	Opt_soft, Opt_softerr, 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_nconnect,
> > +	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_softerr, "softerr" },
> > +	{ 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_nconnect, "nconnect=%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;
> > +		data->lsm_opts		= NULL;
> > +	}
> > +	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;
> > +	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);
> > +
> > +	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
> > +	if (rc)
> > +		goto out_security_failure;
> > +
> > +	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;
> > +			mnt->flags &= ~NFS_MOUNT_SOFTERR;
> > +			break;
> > +		case Opt_softerr:
> > +			mnt->flags |= NFS_MOUNT_SOFTERR;
> > +			mnt->flags &= ~NFS_MOUNT_SOFT;
> > +			break;
> > +		case Opt_hard:
> > +			mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
> > +			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;
> > +				/* fall through */
> > +			case Opt_xprt_udp:
> > +				mnt->flags &= ~NFS_MOUNT_TCP;
> > +				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
> > +				break;
> > +			case Opt_xprt_tcp6:
> > +				protofamily = AF_INET6;
> > +				/* fall through */
> > +			case Opt_xprt_tcp:
> > +				mnt->flags |= NFS_MOUNT_TCP;
> > +				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
> > +				break;
> > +			case Opt_xprt_rdma6:
> > +				protofamily = AF_INET6;
> > +				/* fall through */
> > +			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;
> > +				/* fall through */
> > +			case Opt_xprt_udp:
> > +				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
> > +				break;
> > +			case Opt_xprt_tcp6:
> > +				mountfamily = AF_INET6;
> > +				/* fall through */
> > +			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_nconnect:
> > +			if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
> > +				goto out_invalid_value;
> > +			mnt->nfs_server.nconnect = option;
> > +			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:
> > +	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;
> > +
> > +	if (unlikely(!dev_name || !*dev_name)) {
> > +		dfprintk(MOUNT, "NFS: device name not specified\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* 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)
> > +			len = comma - dev_name;
> > +	}
> > +
> > +	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; /* fall through */
> > +	case 2:
> > +		data->bsize = 0; /* fall through */
> > +	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;
> > +		/* fall through */
> > +	case 4:
> > +		if (data->flags & NFS_MOUNT_SECFLAVOUR)
> > +			goto out_no_sec;
> > +		/* fall through */
> > +	case 5:
> > +		memset(data->context, 0, sizeof(data->context));
> > +		/* fall through */
> > +	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 (sap->sa_family != AF_INET ||
> > +		    !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;
> > +			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
> > +			rc = security_add_mnt_opt("context", data->context,
> > +					strlen(data->context), &args->lsm_opts);
> > +			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)
> > +		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > +			port = NFS_RDMA_PORT;
> > +		else
> > +			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);
> > +		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > +			port = NFS_RDMA_PORT;
> > +	}
> > +
> > +	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 d512ec394559..b66fd35993b3 100644
> > --- a/fs/nfs/internal.h
> > +++ b/fs/nfs/internal.h
> > @@ -7,6 +7,7 @@
> > #include <linux/mount.h>
> > #include <linux/security.h>
> > #include <linux/crc32.h>
> > +#include <linux/sunrpc/addr.h>
> > #include <linux/nfs_page.h>
> > #include <linux/wait_bit.h>
> > 
> > @@ -232,6 +233,22 @@ extern const struct svc_version nfs4_callback_version1;
> > extern const 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);
> > @@ -763,3 +780,15 @@ static inline bool nfs_error_is_fatal(int err)
> > 	}
> > }
> > 
> > +/*
> > + * 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 d8702e57f7fc..886220d2da4e 100644
> > --- a/fs/nfs/super.c
> > +++ b/fs/nfs/super.c
> > @@ -69,229 +69,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
> > -
> > -#define NFS_MAX_CONNECTIONS 16
> > -
> > -enum {
> > -	/* Mount options that take no arguments */
> > -	Opt_soft, Opt_softerr, 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_nconnect,
> > -	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_softerr, "softerr" },
> > -	{ 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_nconnect, "nconnect=%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_prepared_mount(struct file_system_type *fs_type,
> > 		int flags, const char *dev_name, void *raw_data);
> > @@ -332,10 +109,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",
> > @@ -932,141 +705,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;
> > -		data->lsm_opts		= NULL;
> > -	}
> > -	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.
> > @@ -1087,627 +725,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;
> > -	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);
> > -
> > -	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
> > -	if (rc)
> > -		goto out_security_failure;
> > -
> > -	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;
> > -			mnt->flags &= ~NFS_MOUNT_SOFTERR;
> > -			break;
> > -		case Opt_softerr:
> > -			mnt->flags |= NFS_MOUNT_SOFTERR;
> > -			mnt->flags &= ~NFS_MOUNT_SOFT;
> > -			break;
> > -		case Opt_hard:
> > -			mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
> > -			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;
> > -				/* fall through */
> > -			case Opt_xprt_udp:
> > -				mnt->flags &= ~NFS_MOUNT_TCP;
> > -				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
> > -				break;
> > -			case Opt_xprt_tcp6:
> > -				protofamily = AF_INET6;
> > -				/* fall through */
> > -			case Opt_xprt_tcp:
> > -				mnt->flags |= NFS_MOUNT_TCP;
> > -				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
> > -				break;
> > -			case Opt_xprt_rdma6:
> > -				protofamily = AF_INET6;
> > -				/* fall through */
> > -			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;
> > -				/* fall through */
> > -			case Opt_xprt_udp:
> > -				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
> > -				break;
> > -			case Opt_xprt_tcp6:
> > -				mountfamily = AF_INET6;
> > -				/* fall through */
> > -			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_nconnect:
> > -			if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
> > -				goto out_invalid_value;
> > -			mnt->nfs_server.nconnect = option;
> > -			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:
> > -	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
> > @@ -1908,327 +925,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;
> > -
> > -	if (unlikely(!dev_name || !*dev_name)) {
> > -		dfprintk(MOUNT, "NFS: device name not specified\n");
> > -		return -EINVAL;
> > -	}
> > -
> > -	/* 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)
> > -			len = comma - dev_name;
> > -	}
> > -
> > -	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; /* fall through */
> > -	case 2:
> > -		data->bsize = 0; /* fall through */
> > -	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;
> > -		/* fall through */
> > -	case 4:
> > -		if (data->flags & NFS_MOUNT_SECFLAVOUR)
> > -			goto out_no_sec;
> > -		/* fall through */
> > -	case 5:
> > -		memset(data->context, 0, sizeof(data->context));
> > -		/* fall through */
> > -	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 (sap->sa_family != AF_INET ||
> > -		    !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;
> > -			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
> > -			rc = security_add_mnt_opt("context", data->context,
> > -					strlen(data->context), &args->lsm_opts);
> > -			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)
> > -		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > -			port = NFS_RDMA_PORT;
> > -		else
> > -			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);
> > -		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > -			port = NFS_RDMA_PORT;
> > -	}
> > -
> > -	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 \
> > @@ -2719,113 +1415,6 @@ nfs_prepared_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
> > -- 
> > 2.17.2
> > 
> 
> --
> Chuck Lever
> chucklever@gmail.com
> 
> 
> 

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

* Re: [PATCH v3 16/26] NFS: Move mount parameterisation bits into their own file
  2019-09-11 19:00     ` Trond Myklebust
@ 2019-09-12 17:36       ` Scott Mayhew
  2019-09-12 17:42         ` Trond Myklebust
  0 siblings, 1 reply; 32+ messages in thread
From: Scott Mayhew @ 2019-09-12 17:36 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: chucklever, linux-nfs, linux-fsdevel, anna.schumaker, viro,
	dhowells, linux-kernel

On Wed, 11 Sep 2019, Trond Myklebust wrote:

> On Wed, 2019-09-11 at 14:24 -0400, Chuck Lever wrote:
> > > On Sep 11, 2019, at 12:16 PM, Scott Mayhew <smayhew@redhat.com>
> > > wrote:
> > > 
> > > From: David Howells <dhowells@redhat.com>
> > > 
> > > 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>
> > > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> > > ---
> > > fs/nfs/Makefile     |    2 +-
> > > fs/nfs/fs_context.c | 1418
> > > +++++++++++++++++++++++++++++++++++++++++++
> > > fs/nfs/internal.h   |   29 +
> > > fs/nfs/super.c      | 1411 ----------------------------------------
> > > --
> > > 4 files changed, 1448 insertions(+), 1412 deletions(-)
> > > create mode 100644 fs/nfs/fs_context.c
> > > 
> > > diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
> > > index 34cdeaecccf6..2433c3e03cfa 100644
> > > --- a/fs/nfs/Makefile
> > > +++ b/fs/nfs/Makefile
> > > @@ -9,7 +9,7 @@ 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
> > > \
> > > -			   export.o sysfs.o
> > > +			   export.o sysfs.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..82b312a5cdde
> > > --- /dev/null
> > > +++ b/fs/nfs/fs_context.c
> > > @@ -0,0 +1,1418 @@
> > > +/* NFS mount handling.
> > > + *
> > > + * Copyright (C) 2018 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.
> > > + */
> > 
> > New source files should have an SPDX tag instead of boilerplate.
> > I suggest:
> > 
> > // SPDX-License-Identifier: GPL-2.0-only
> > 
> 
> Agreed. It is also quite a long stretch to claim authorship of the
> entire file as implied above. Given that this is mostly a copy-paste
> effort, then most of the actual copyrights belong to the people who've
> contributed to super.c (and to inode.c before it). David is one of
> those authors, but he is one of many.

Okay, how about:

// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/fs/nfs/fs_context.c
 *
 * Copyright (C) 1992 Rick Sladkey
 *
 * NFS mount handling.
 *
 * Split from fs/nfs/super.c by David Howells <dhowells@redhat.com>
 */

and have patch 25/26 add a line

 * Conversion to new mount api Copyright (C) David Howells

-Scott
> 
> 
> > > +#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
> > > +
> > > +#define NFS_MAX_CONNECTIONS 16
> > > +
> > > +enum {
> > > +	/* Mount options that take no arguments */
> > > +	Opt_soft, Opt_softerr, 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_nconnect,
> > > +	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_softerr, "softerr" },
> > > +	{ 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_nconnect, "nconnect=%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;
> > > +		data->lsm_opts		= NULL;
> > > +	}
> > > +	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;
> > > +	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);
> > > +
> > > +	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
> > > +	if (rc)
> > > +		goto out_security_failure;
> > > +
> > > +	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;
> > > +			mnt->flags &= ~NFS_MOUNT_SOFTERR;
> > > +			break;
> > > +		case Opt_softerr:
> > > +			mnt->flags |= NFS_MOUNT_SOFTERR;
> > > +			mnt->flags &= ~NFS_MOUNT_SOFT;
> > > +			break;
> > > +		case Opt_hard:
> > > +			mnt->flags &=
> > > ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
> > > +			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;
> > > +				/* fall through */
> > > +			case Opt_xprt_udp:
> > > +				mnt->flags &= ~NFS_MOUNT_TCP;
> > > +				mnt->nfs_server.protocol =
> > > XPRT_TRANSPORT_UDP;
> > > +				break;
> > > +			case Opt_xprt_tcp6:
> > > +				protofamily = AF_INET6;
> > > +				/* fall through */
> > > +			case Opt_xprt_tcp:
> > > +				mnt->flags |= NFS_MOUNT_TCP;
> > > +				mnt->nfs_server.protocol =
> > > XPRT_TRANSPORT_TCP;
> > > +				break;
> > > +			case Opt_xprt_rdma6:
> > > +				protofamily = AF_INET6;
> > > +				/* fall through */
> > > +			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;
> > > +				/* fall through */
> > > +			case Opt_xprt_udp:
> > > +				mnt->mount_server.protocol =
> > > XPRT_TRANSPORT_UDP;
> > > +				break;
> > > +			case Opt_xprt_tcp6:
> > > +				mountfamily = AF_INET6;
> > > +				/* fall through */
> > > +			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_nconnect:
> > > +			if (nfs_get_option_ul_bound(args, &option, 1,
> > > NFS_MAX_CONNECTIONS))
> > > +				goto out_invalid_value;
> > > +			mnt->nfs_server.nconnect = option;
> > > +			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:
> > > +	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;
> > > +
> > > +	if (unlikely(!dev_name || !*dev_name)) {
> > > +		dfprintk(MOUNT, "NFS: device name not specified\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	/* 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)
> > > +			len = comma - dev_name;
> > > +	}
> > > +
> > > +	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; /* fall through */
> > > +	case 2:
> > > +		data->bsize = 0; /* fall through */
> > > +	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;
> > > +		/* fall through */
> > > +	case 4:
> > > +		if (data->flags & NFS_MOUNT_SECFLAVOUR)
> > > +			goto out_no_sec;
> > > +		/* fall through */
> > > +	case 5:
> > > +		memset(data->context, 0, sizeof(data->context));
> > > +		/* fall through */
> > > +	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 (sap->sa_family != AF_INET ||
> > > +		    !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;
> > > +			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
> > > +			rc = security_add_mnt_opt("context", data-
> > > >context,
> > > +					strlen(data->context), &args-
> > > >lsm_opts);
> > > +			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)
> > > +		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > > +			port = NFS_RDMA_PORT;
> > > +		else
> > > +			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);
> > > +		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > > +			port = NFS_RDMA_PORT;
> > > +	}
> > > +
> > > +	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 d512ec394559..b66fd35993b3 100644
> > > --- a/fs/nfs/internal.h
> > > +++ b/fs/nfs/internal.h
> > > @@ -7,6 +7,7 @@
> > > #include <linux/mount.h>
> > > #include <linux/security.h>
> > > #include <linux/crc32.h>
> > > +#include <linux/sunrpc/addr.h>
> > > #include <linux/nfs_page.h>
> > > #include <linux/wait_bit.h>
> > > 
> > > @@ -232,6 +233,22 @@ extern const struct svc_version
> > > nfs4_callback_version1;
> > > extern const 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);
> > > @@ -763,3 +780,15 @@ static inline bool nfs_error_is_fatal(int err)
> > > 	}
> > > }
> > > 
> > > +/*
> > > + * 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 d8702e57f7fc..886220d2da4e 100644
> > > --- a/fs/nfs/super.c
> > > +++ b/fs/nfs/super.c
> > > @@ -69,229 +69,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
> > > -
> > > -#define NFS_MAX_CONNECTIONS 16
> > > -
> > > -enum {
> > > -	/* Mount options that take no arguments */
> > > -	Opt_soft, Opt_softerr, 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_nconnect,
> > > -	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_softerr, "softerr" },
> > > -	{ 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_nconnect, "nconnect=%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_prepared_mount(struct file_system_type
> > > *fs_type,
> > > 		int flags, const char *dev_name, void *raw_data);
> > > @@ -332,10 +109,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",
> > > @@ -932,141 +705,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;
> > > -		data->lsm_opts		= NULL;
> > > -	}
> > > -	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.
> > > @@ -1087,627 +725,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;
> > > -	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);
> > > -
> > > -	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
> > > -	if (rc)
> > > -		goto out_security_failure;
> > > -
> > > -	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;
> > > -			mnt->flags &= ~NFS_MOUNT_SOFTERR;
> > > -			break;
> > > -		case Opt_softerr:
> > > -			mnt->flags |= NFS_MOUNT_SOFTERR;
> > > -			mnt->flags &= ~NFS_MOUNT_SOFT;
> > > -			break;
> > > -		case Opt_hard:
> > > -			mnt->flags &=
> > > ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
> > > -			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;
> > > -				/* fall through */
> > > -			case Opt_xprt_udp:
> > > -				mnt->flags &= ~NFS_MOUNT_TCP;
> > > -				mnt->nfs_server.protocol =
> > > XPRT_TRANSPORT_UDP;
> > > -				break;
> > > -			case Opt_xprt_tcp6:
> > > -				protofamily = AF_INET6;
> > > -				/* fall through */
> > > -			case Opt_xprt_tcp:
> > > -				mnt->flags |= NFS_MOUNT_TCP;
> > > -				mnt->nfs_server.protocol =
> > > XPRT_TRANSPORT_TCP;
> > > -				break;
> > > -			case Opt_xprt_rdma6:
> > > -				protofamily = AF_INET6;
> > > -				/* fall through */
> > > -			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;
> > > -				/* fall through */
> > > -			case Opt_xprt_udp:
> > > -				mnt->mount_server.protocol =
> > > XPRT_TRANSPORT_UDP;
> > > -				break;
> > > -			case Opt_xprt_tcp6:
> > > -				mountfamily = AF_INET6;
> > > -				/* fall through */
> > > -			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_nconnect:
> > > -			if (nfs_get_option_ul_bound(args, &option, 1,
> > > NFS_MAX_CONNECTIONS))
> > > -				goto out_invalid_value;
> > > -			mnt->nfs_server.nconnect = option;
> > > -			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:
> > > -	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
> > > @@ -1908,327 +925,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;
> > > -
> > > -	if (unlikely(!dev_name || !*dev_name)) {
> > > -		dfprintk(MOUNT, "NFS: device name not specified\n");
> > > -		return -EINVAL;
> > > -	}
> > > -
> > > -	/* 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)
> > > -			len = comma - dev_name;
> > > -	}
> > > -
> > > -	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; /* fall through */
> > > -	case 2:
> > > -		data->bsize = 0; /* fall through */
> > > -	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;
> > > -		/* fall through */
> > > -	case 4:
> > > -		if (data->flags & NFS_MOUNT_SECFLAVOUR)
> > > -			goto out_no_sec;
> > > -		/* fall through */
> > > -	case 5:
> > > -		memset(data->context, 0, sizeof(data->context));
> > > -		/* fall through */
> > > -	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 (sap->sa_family != AF_INET ||
> > > -		    !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;
> > > -			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
> > > -			rc = security_add_mnt_opt("context", data-
> > > >context,
> > > -					strlen(data->context), &args-
> > > >lsm_opts);
> > > -			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)
> > > -		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > > -			port = NFS_RDMA_PORT;
> > > -		else
> > > -			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);
> > > -		if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
> > > -			port = NFS_RDMA_PORT;
> > > -	}
> > > -
> > > -	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 \
> > > @@ -2719,113 +1415,6 @@ nfs_prepared_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
> > > -- 
> > > 2.17.2
> > > 
> > 
> > --
> > Chuck Lever
> > chucklever@gmail.com
> > 
> > 
> > 
> -- 
> Trond Myklebust
> Linux NFS client maintainer, Hammerspace
> trond.myklebust@hammerspace.com
> 
> 

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

* Re: [PATCH v3 16/26] NFS: Move mount parameterisation bits into their own file
  2019-09-12 17:36       ` Scott Mayhew
@ 2019-09-12 17:42         ` Trond Myklebust
  0 siblings, 0 replies; 32+ messages in thread
From: Trond Myklebust @ 2019-09-12 17:42 UTC (permalink / raw)
  To: smayhew
  Cc: chucklever, linux-nfs, linux-fsdevel, anna.schumaker, viro,
	dhowells, linux-kernel

On Thu, 2019-09-12 at 13:36 -0400, Scott Mayhew wrote:
> On Wed, 11 Sep 2019, Trond Myklebust wrote:
> 
> > On Wed, 2019-09-11 at 14:24 -0400, Chuck Lever wrote:
> > > > On Sep 11, 2019, at 12:16 PM, Scott Mayhew <smayhew@redhat.com>
> > > > wrote:
> > > > 
> > > > From: David Howells <dhowells@redhat.com>
> > > > 
> > > > 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>
> > > > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> > > > ---
> > > > fs/nfs/Makefile     |    2 +-
> > > > fs/nfs/fs_context.c | 1418
> > > > +++++++++++++++++++++++++++++++++++++++++++
> > > > fs/nfs/internal.h   |   29 +
> > > > fs/nfs/super.c      | 1411 ------------------------------------
> > > > ----
> > > > --
> > > > 4 files changed, 1448 insertions(+), 1412 deletions(-)
> > > > create mode 100644 fs/nfs/fs_context.c
> > > > 
> > > > diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
> > > > index 34cdeaecccf6..2433c3e03cfa 100644
> > > > --- a/fs/nfs/Makefile
> > > > +++ b/fs/nfs/Makefile
> > > > @@ -9,7 +9,7 @@ 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
> > > > \
> > > > -			   export.o sysfs.o
> > > > +			   export.o sysfs.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..82b312a5cdde
> > > > --- /dev/null
> > > > +++ b/fs/nfs/fs_context.c
> > > > @@ -0,0 +1,1418 @@
> > > > +/* NFS mount handling.
> > > > + *
> > > > + * Copyright (C) 2018 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.
> > > > + */
> > > 
> > > New source files should have an SPDX tag instead of boilerplate.
> > > I suggest:
> > > 
> > > // SPDX-License-Identifier: GPL-2.0-only
> > > 
> > 
> > Agreed. It is also quite a long stretch to claim authorship of the
> > entire file as implied above. Given that this is mostly a copy-
> > paste
> > effort, then most of the actual copyrights belong to the people
> > who've
> > contributed to super.c (and to inode.c before it). David is one of
> > those authors, but he is one of many.
> 
> Okay, how about:
> 
> // SPDX-License-Identifier: GPL-2.0-only
> /*
>  * linux/fs/nfs/fs_context.c
>  *
>  * Copyright (C) 1992 Rick Sladkey
>  *
>  * NFS mount handling.
>  *
>  * Split from fs/nfs/super.c by David Howells <dhowells@redhat.com>
>  */
> 
> and have patch 25/26 add a line
> 
>  * Conversion to new mount api Copyright (C) David Howells

That looks more reasonable to me.

> 
> -Scott
> > 
> > > > +#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
> > > > +
> > > > +#define NFS_MAX_CONNECTIONS 16
> > > > +
> > > > +enum {
> > > > +	/* Mount options that take no arguments */
> > > > +	Opt_soft, Opt_softerr, 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_nconnect,
> > > > +	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_softerr, "softerr" },
> > > > +	{ 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_nconnect, "nconnect=%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;
> > > > +		data->lsm_opts		= NULL;
> > > > +	}
> > > > +	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;
&g