Linux Security Modules development
 help / color / mirror / Atom feed
* [PATCH v6 24/27] NFS: Convert mount option parsing to use functionality from fs_parser.h
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 | 787 ++++++++++++++++++++------------------------
 1 file changed, 364 insertions(+), 423 deletions(-)

diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 44531443a92b..9a3162055d5d 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -11,7 +11,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>
@@ -28,218 +29,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)
@@ -368,17 +366,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;
@@ -427,11 +427,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;
@@ -465,64 +464,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", param->key);
 
-	dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'\n", p);
+	opt = fs_parse(NULL, &nfs_fs_parameters, param, &result);
+	if (opt < 0)
+		return ctx->sloppy ? 1 : opt;
 
-	token = match_token(p, nfs_mount_option_tokens, args);
-	switch (token) {
+	switch (opt) {
 		/*
 		 * boolean options:  foo/nofoo
 		 */
@@ -538,30 +497,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;
@@ -574,195 +534,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;
@@ -772,51 +714,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;
@@ -828,22 +761,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);
@@ -859,8 +781,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");
-			return -EINVAL;
+			goto out_invalid_value;
 		}
 		break;
 
@@ -868,30 +789,50 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
 		 * 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 related

* [PATCH v6 20/27] NFS: Deindent nfs_fs_context_parse_option()
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 a386825c3b0f..92a1e4bd9133 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -500,410 +500,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 related

* [PATCH v6 09/27] nfs: don't bother passing nfs_subversion to ->try_mount() and nfs_fs_mount_common()
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 9888e9c7abe2..4a0ba66bc3aa 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -393,12 +393,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 a7a73b1d1fec..5d539dce9cef 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -526,7 +526,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 6e5417027021..2b34d8e124cd 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 6189f768aa59..cb0ead628842 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);
 
@@ -2648,8 +2648,7 @@ static void nfs_set_readahead(struct backing_dev_info *bdi,
 }
 
 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);
@@ -2677,7 +2676,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;
@@ -2763,7 +2763,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:
@@ -2797,10 +2797,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 72d5695c1b47..3ee2ad642cbc 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1655,8 +1655,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 related

* [PATCH v6 07/27] nfs: lift setting mount_info from nfs_xdev_mount()
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 8f4900bd04f7..b193dd626c0a 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -34,8 +34,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;
@@ -405,6 +403,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 5e0e9d29f5c5..a76aeb0c2923 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
 
@@ -213,16 +214,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
@@ -234,13 +225,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;
@@ -248,12 +246,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 379c7b26051d..97dc544eb220 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2395,7 +2395,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;
@@ -2796,27 +2796,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 related

* [PATCH v6 03/27] nfs: lift setting mount_info from nfs4_remote{,_referral}_mount
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 e7f2fd1925b1..ac3e8928643d 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 related

* [PATCH v6 04/27] nfs: fold nfs4_remote_fs_type and nfs4_remote_referral_fs_type
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 ac3e8928643d..54dbb4561ccc 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 related

* [PATCH v6 19/27] NFS: Split nfs_parse_mount_options()
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 52aa2b8522f0..a386825c3b0f 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -496,36 +496,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);
@@ -734,7 +716,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:
@@ -744,24 +726,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 */
@@ -773,7 +755,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
 				dfprintk(MOUNT, "NFS:   unrecognized "
 						"transport protocol\n");
 				kfree(string);
-				return 0;
+				return -EINVAL;
 			}
 			kfree(string);
 			break;
@@ -785,16 +767,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;
@@ -803,7 +785,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:
@@ -867,7 +849,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:
@@ -900,7 +882,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;
 
@@ -908,7 +890,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:
@@ -918,12 +900,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;
 
@@ -938,22 +961,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");
@@ -961,23 +988,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 7131fa150d1b..d0abc7b65cd2 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -96,7 +96,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 related

* [PATCH v6 21/27] NFS: Add a small buffer in nfs_fs_context to avoid string dup
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 92a1e4bd9133..2921c5820c31 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -468,27 +468,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;
@@ -501,7 +512,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;
 
@@ -609,86 +619,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;
 
 		/*
@@ -820,9 +814,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 d0abc7b65cd2..5342f3e4d565 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -122,6 +122,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 related

* [PATCH v6 27/27] NFS: Attach supplementary error information to fs_context.
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 e472334b978d..429315c011ae 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -318,10 +318,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;
@@ -378,9 +376,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);
@@ -425,8 +421,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;
 }
@@ -451,10 +446,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;
@@ -664,8 +657,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;
@@ -688,8 +680,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;
@@ -774,13 +765,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;
 }
 
@@ -846,19 +835,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;
 }
 
@@ -1015,29 +1000,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)
@@ -1132,21 +1111,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
 
@@ -1164,8 +1139,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");
 }
 
 /*
@@ -1253,32 +1227,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 a1fd4c3ebc4e..c0257411e158 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -133,6 +133,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 d537350c1fb7..4fd22c0d730c 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -281,7 +281,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 7d5ed37633d8..1475f932d7da 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 ed0290d5ebf3..76e0198adcfa 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1205,7 +1205,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;
 	}
 
@@ -1234,7 +1234,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 related

* [PATCH v6 08/27] nfs: stash nfs_subversion reference into nfs_mount_info
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 b193dd626c0a..9888e9c7abe2 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -142,6 +142,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 a76aeb0c2923..a00936dd153b 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -236,8 +236,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);
@@ -246,8 +246,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 c489942b9069..6e5417027021 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 97dc544eb220..6189f768aa59 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2761,6 +2761,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 related

* [PATCH v6 06/27] nfs4: fold nfs_do_root_mount/nfs_follow_remote_path
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 8146edf4ce3a..c489942b9069 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 related

* [PATCH v6 05/27] nfs: don't bother setting/restoring export_path around do_nfs_root_mount()
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 54dbb4561ccc..8146edf4ce3a 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 related

* [PATCH v6 15/27] nfs: get rid of ->set_security()
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 65c8e353cb6b..a467e43fc682 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -137,7 +137,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;
@@ -391,8 +390,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 30331558bd8e..bfe607374feb 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -233,7 +233,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 5020a43b31c9..f1c2d294073a 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 bec6c341f72c..de00f89dbe6e 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2550,52 +2550,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 void nfs_set_readahead(struct backing_dev_info *bdi,
 			      unsigned long iomax_pages)
 {
@@ -2610,6 +2564,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,
@@ -2670,7 +2625,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;
 
@@ -2695,7 +2669,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 related

* [PATCH v6 10/27] nfs: merge xdev and remote file_system_type
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 4a0ba66bc3aa..e338558b7908 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -388,7 +388,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 a00936dd153b..e5f4f2d760af 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -257,7 +257,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 2b34d8e124cd..1358d8078737 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 cb0ead628842..60845dc864e7 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,
@@ -2791,11 +2792,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 related

* [PATCH v6 12/27] nfs: don't pass nfs_subversion to ->create_server()
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 02110a30a49e..a2049747adc4 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -951,10 +951,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 310f81a149b2..0bb0493785fc 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -170,11 +170,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 223904bc40a7..54727d3d3042 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 460d6251c405..538fd036b69d 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1112,8 +1112,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 1358d8078737..e5d8a76bd144 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 0bedac041272..6239c78d8f54 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 3ee2ad642cbc..17527f6e6360 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1722,7 +1722,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 related

* [PATCH v6 11/27] nfs: unexport nfs_fs_mount_common()
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 e338558b7908..310f81a149b2 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -396,10 +396,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 60845dc864e7..0bedac041272 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)
 {
@@ -2648,7 +2650,7 @@ static void nfs_set_readahead(struct backing_dev_info *bdi,
 	bdi->io_pages = iomax_pages;
 }
 
-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;
@@ -2730,7 +2732,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 related

* [PATCH v6 14/27] nfs_clone_sb_security(): simplify the check for server bogosity
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 2bcf0f8295e0..bec6c341f72c 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2578,7 +2578,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 related

* [PATCH v6 00/27] nfs: Mount API conversion
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module

Hi Anna, Trond,

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 5 separate patches, and the entire set
has been rebased on top of v5.5-rc1.

Changes since v5:
- fixed possible derefence of error pointer in nfs4_validate_fspath()
  reported by Dan Carpenter
- rebased on top of v5.5-rc1
Changes since v4:
- further split the original "NFS: Add fs_context support" patch (new
  patch is about 25% smaller than the v4 patch)
- fixed NFSv4 referral mounts (broken in the original patch)
- fixed leak of nfs_fattr when fs_context is freed
Changes since v3:
- changed license and copyright text in fs/nfs/fs_context.c
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
Chagnes since v1:
- split up patch 23 into 4 separate patches

-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 (4):
  NFS: rename nfs_fs_context pointer arg in a few functions
  NFS: Convert mount option parsing to use functionality from
    fs_parser.h
  NFS: Additional refactoring for fs_context conversion
  NFS: Attach supplementary error information to fs_context.

 fs/nfs/Makefile         |    2 +-
 fs/nfs/client.c         |   80 +-
 fs/nfs/fs_context.c     | 1424 +++++++++++++++++++++++++
 fs/nfs/fscache.c        |    2 +-
 fs/nfs/getroot.c        |   73 +-
 fs/nfs/internal.h       |  132 +--
 fs/nfs/namespace.c      |  146 ++-
 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/nfs4file.c       |    1 +
 fs/nfs/nfs4namespace.c  |  292 +++---
 fs/nfs/nfs4proc.c       |    2 +-
 fs/nfs/nfs4super.c      |  257 ++---
 fs/nfs/proc.c           |    2 +-
 fs/nfs/super.c          | 2217 +++++----------------------------------
 include/linux/nfs_xdr.h |    9 +-
 19 files changed, 2287 insertions(+), 2470 deletions(-)
 create mode 100644 fs/nfs/fs_context.c

-- 
2.17.2


^ permalink raw reply

* [PATCH v6 02/27] nfs: stash server into struct nfs_mount_info
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
  To: anna.schumaker, trond.myklebust
  Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
	linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>

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 24a65da58aa9..8f4900bd04f7 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -142,6 +142,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;
 };
 
@@ -397,7 +398,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 beeaed872e6c..e7f2fd1925b1 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 f074c3773f0e..379c7b26051d 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);
 
@@ -2649,20 +2647,21 @@ static void nfs_set_readahead(struct backing_dev_info *bdi,
 	bdi->io_pages = iomax_pages;
 }
 
-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);
 
@@ -2803,7 +2802,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;
 
@@ -2812,10 +2810,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 related

* Re: [RFC PATCH] selinux: ensure we cleanup the internal AVC counters on error in avc_insert()
From: Stephen Smalley @ 2019-12-10 13:44 UTC (permalink / raw)
  To: Paul Moore, selinux; +Cc: rsiddoji, linux-security-module
In-Reply-To: <157594281322.676903.11041338053333686450.stgit@chester>

On 12/9/19 8:53 PM, Paul Moore wrote:
> In AVC insert we don't call avc_node_kill() when avc_xperms_populate()
> fails, resulting in the avc->avc_cache.active_nodes counter having a
> false value.

incorrect value?

   This patch corrects this problem and does some cleanup
> in avc_insert() while we are there.

submitting-patches.rst recommends describing in imperative mood and 
avoiding the words "patch" in what will eventually just be a commit log, 
ala "Correct this problem and perform some cleanup..."

Should probably add a:

Fixes: fa1aa143ac4a ("selinux: extended permissions for ioctls")

Might be easier to back port if you split the cleanup from the fix, but 
your call of course.

> 
> Reported-by: rsiddoji@codeaurora.org
> Suggested-by: Stephen Smalley <sds@tycho.nsa.gov>
> Signed-off-by: Paul Moore <paul@paul-moore.com>

Acked-by: Stephen Smalley <sds@tycho.nsa.gov>

> ---
>   security/selinux/avc.c |   51 +++++++++++++++++++++++-------------------------
>   1 file changed, 24 insertions(+), 27 deletions(-)
> 
> diff --git a/security/selinux/avc.c b/security/selinux/avc.c
> index 23dc888ae305..6646300f7ccb 100644
> --- a/security/selinux/avc.c
> +++ b/security/selinux/avc.c
> @@ -617,40 +617,37 @@ static struct avc_node *avc_insert(struct selinux_avc *avc,
>   	struct avc_node *pos, *node = NULL;
>   	int hvalue;
>   	unsigned long flag;
> +	spinlock_t *lock;
> +	struct hlist_head *head;
>   
>   	if (avc_latest_notif_update(avc, avd->seqno, 1))
> -		goto out;
> +		return NULL;
>   
>   	node = avc_alloc_node(avc);
> -	if (node) {
> -		struct hlist_head *head;
> -		spinlock_t *lock;
> -		int rc = 0;
> -
> -		hvalue = avc_hash(ssid, tsid, tclass);
> -		avc_node_populate(node, ssid, tsid, tclass, avd);
> -		rc = avc_xperms_populate(node, xp_node);
> -		if (rc) {
> -			kmem_cache_free(avc_node_cachep, node);
> -			return NULL;
> -		}
> -		head = &avc->avc_cache.slots[hvalue];
> -		lock = &avc->avc_cache.slots_lock[hvalue];
> +	if (!node)
> +		return NULL;
>   
> -		spin_lock_irqsave(lock, flag);
> -		hlist_for_each_entry(pos, head, list) {
> -			if (pos->ae.ssid == ssid &&
> -			    pos->ae.tsid == tsid &&
> -			    pos->ae.tclass == tclass) {
> -				avc_node_replace(avc, node, pos);
> -				goto found;
> -			}
> +	avc_node_populate(node, ssid, tsid, tclass, avd);
> +	if (avc_xperms_populate(node, xp_node)) {
> +		avc_node_kill(avc, node);
> +		return NULL;
> +	}
> +
> +	hvalue = avc_hash(ssid, tsid, tclass);
> +	head = &avc->avc_cache.slots[hvalue];
> +	lock = &avc->avc_cache.slots_lock[hvalue];
> +	spin_lock_irqsave(lock, flag);
> +	hlist_for_each_entry(pos, head, list) {
> +		if (pos->ae.ssid == ssid &&
> +			pos->ae.tsid == tsid &&
> +			pos->ae.tclass == tclass) {
> +			avc_node_replace(avc, node, pos);
> +			goto found;
>   		}
> -		hlist_add_head_rcu(&node->list, head);
> -found:
> -		spin_unlock_irqrestore(lock, flag);
>   	}
> -out:
> +	hlist_add_head_rcu(&node->list, head);
> +found:
> +	spin_unlock_irqrestore(lock, flag);
>   	return node;
>   }
>   
> 


^ permalink raw reply

* Re: [RFC PATCH] security: add an interface to lookup the lockdown reason
From: Stephen Smalley @ 2019-12-10 14:59 UTC (permalink / raw)
  To: Paul Moore, selinux, linux-security-module; +Cc: linux-next, jamorris
In-Reply-To: <157594493094.748324.9234611948545428995.stgit@chester>

On 12/9/19 9:28 PM, Paul Moore wrote:
> With CONFIG_AUDIT enabled but CONFIG_SECURITY disabled we run into
> a problem where the lockdown reason table is missing.  This patch
> attempts to fix this by hiding the table behind a lookup function.

Shouldn't lsm_audit.c be conditional on both CONFIG_AUDIT and 
CONFIG_SECURITY?  When/why would we want it built without 
CONFIG_SECURITY enabled?

> 
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
>   include/linux/security.h |    7 +++++++
>   security/lsm_audit.c     |   12 +++++++++---
>   security/security.c      |    5 +++++
>   3 files changed, 21 insertions(+), 3 deletions(-)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 64b19f050343..295509a809d6 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -447,6 +447,8 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
>   int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
>   int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
>   int security_locked_down(enum lockdown_reason what);
> +const char *security_locked_reasonstr(enum lockdown_reason what);
> +
>   #else /* CONFIG_SECURITY */
>   
>   static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data)
> @@ -1274,6 +1276,11 @@ static inline int security_locked_down(enum lockdown_reason what)
>   {
>   	return 0;
>   }
> +
> +static inline const char *security_locked_reasonstr(enum lockdown_reason what)
> +{
> +	return NULL;
> +}
>   #endif	/* CONFIG_SECURITY */
>   
>   #ifdef CONFIG_SECURITY_NETWORK
> diff --git a/security/lsm_audit.c b/security/lsm_audit.c
> index 2d2bf49016f4..519ef6046638 100644
> --- a/security/lsm_audit.c
> +++ b/security/lsm_audit.c
> @@ -426,10 +426,16 @@ static void dump_common_audit_data(struct audit_buffer *ab,
>   				 a->u.ibendport->dev_name,
>   				 a->u.ibendport->port);
>   		break;
> -	case LSM_AUDIT_DATA_LOCKDOWN:
> -		audit_log_format(ab, " lockdown_reason=");
> -		audit_log_string(ab, lockdown_reasons[a->u.reason]);
> +	case LSM_AUDIT_DATA_LOCKDOWN: {
> +		const char *str = security_locked_reasonstr(a->u.reason);
> +
> +		if (str) {
> +			audit_log_format(ab, " lockdown_reason=");
> +			audit_log_string(ab, str);
> +		} else
> +			audit_log_format(ab, " lockdown_reason=?");
>   		break;
> +	}
>   	} /* switch (a->type) */
>   }
>   
> diff --git a/security/security.c b/security/security.c
> index 2b5473d92416..2f228fdbebf5 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2438,6 +2438,11 @@ int security_locked_down(enum lockdown_reason what)
>   }
>   EXPORT_SYMBOL(security_locked_down);
>   
> +const char *security_locked_reasonstr(enum lockdown_reason what)
> +{
> +	return lockdown_reasons[what];
> +}
> +
>   #ifdef CONFIG_PERF_EVENTS
>   int security_perf_event_open(struct perf_event_attr *attr, int type)
>   {
> 


^ permalink raw reply

* Re: [RFC PATCH] security: add an interface to lookup the lockdown reason
From: Paul Moore @ 2019-12-10 15:04 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: selinux, linux-security-module, linux-next, jamorris
In-Reply-To: <285edbb5-b08e-5bdc-f951-841fe1d77521@tycho.nsa.gov>

On Tue, Dec 10, 2019 at 9:59 AM Stephen Smalley <sds@tycho.nsa.gov> wrote:
> On 12/9/19 9:28 PM, Paul Moore wrote:
> > With CONFIG_AUDIT enabled but CONFIG_SECURITY disabled we run into
> > a problem where the lockdown reason table is missing.  This patch
> > attempts to fix this by hiding the table behind a lookup function.
>
> Shouldn't lsm_audit.c be conditional on both CONFIG_AUDIT and
> CONFIG_SECURITY?  When/why would we want it built without
> CONFIG_SECURITY enabled?

My first thought of a fix was just that, but I remembered that the
capabilities code is built regardless of the CONFIG_SECURITY setting
and I thought there might be some value in allowing for lsm_audit to
be used in commoncap (although in full disclosure commoncap doesn't
currently make use of lsm_audit).

-- 
paul moore
www.paul-moore.com

^ permalink raw reply

* Re: [RFC PATCH] security: add an interface to lookup the lockdown reason
From: Stephen Smalley @ 2019-12-10 15:45 UTC (permalink / raw)
  To: Paul Moore; +Cc: selinux, linux-security-module, linux-next, jamorris
In-Reply-To: <CAHC9VhS4ksmcqBMzwQDArgd9xn_cJ+nyEBrHJcYjoiMaFzCq-Q@mail.gmail.com>

On 12/10/19 10:04 AM, Paul Moore wrote:
> On Tue, Dec 10, 2019 at 9:59 AM Stephen Smalley <sds@tycho.nsa.gov> wrote:
>> On 12/9/19 9:28 PM, Paul Moore wrote:
>>> With CONFIG_AUDIT enabled but CONFIG_SECURITY disabled we run into
>>> a problem where the lockdown reason table is missing.  This patch
>>> attempts to fix this by hiding the table behind a lookup function.
>>
>> Shouldn't lsm_audit.c be conditional on both CONFIG_AUDIT and
>> CONFIG_SECURITY?  When/why would we want it built without
>> CONFIG_SECURITY enabled?
> 
> My first thought of a fix was just that, but I remembered that the
> capabilities code is built regardless of the CONFIG_SECURITY setting
> and I thought there might be some value in allowing for lsm_audit to
> be used in commoncap (although in full disclosure commoncap doesn't
> currently make use of lsm_audit).

Seems contrary to normal practice, i.e. if/when commoncap grows a 
dependency, it can be changed then.



^ permalink raw reply

* Re: [RFC PATCH] selinux: ensure we cleanup the internal AVC counters on error in avc_insert()
From: Paul Moore @ 2019-12-10 15:54 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: selinux, rsiddoji, linux-security-module
In-Reply-To: <f7e43b67-3f46-e480-f8b0-e86eff85293f@tycho.nsa.gov>

On Tue, Dec 10, 2019 at 8:44 AM Stephen Smalley <sds@tycho.nsa.gov> wrote:
> On 12/9/19 8:53 PM, Paul Moore wrote:
> > In AVC insert we don't call avc_node_kill() when avc_xperms_populate()
> > fails, resulting in the avc->avc_cache.active_nodes counter having a
> > false value.
>
> incorrect value?
>
>    This patch corrects this problem and does some cleanup
> > in avc_insert() while we are there.
>
> submitting-patches.rst recommends describing in imperative mood and
> avoiding the words "patch" in what will eventually just be a commit log,
> ala "Correct this problem and perform some cleanup..."

Well, you've made me feel better about my nit-picky comments on patches ;)

Are you okay with the following?

  selinux: ensure we cleanup the internal AVC counters on error in avc_insert()

  Fix avc_insert() to call avc_node_kill() if we've already allocated
  an AVC node and the code fails to insert the node in the cache.

> Should probably add a:
>
> Fixes: fa1aa143ac4a ("selinux: extended permissions for ioctls")
>
> Might be easier to back port if you split the cleanup from the fix, but
> your call of course.

I waffled on that last night when I wrote up the patch, and more
generally if this should go to -stable or -next (despite what is
claimed, adding a "Fixes:" tag means it gets picked up by -stable more
often than not in my experience).  At its worst, not fixing this bug
means we could end up effectively shrinking the AVC cache if xperms
are used *and* we happen to fail a memory allocation while adding a
new entry to the AVC; we don't cause an incorrect node to be cached,
we don't crash the system, we don't leak memory.  My thinking is that
this isn't a major concern, and not worth the risk to -stable, but if
anyone has any data that shows otherwise, please let me know.

I'll go ahead and add the "Fixes:" tag (technically this is the
*right* thing to do), but I'm going to stick with -next and leave the
cleanup as-is just to raise the bar a bit for the -stable backports
which I'm sure are going to happen.

-- 
paul moore
www.paul-moore.com

^ permalink raw reply

* Re: [RFC PATCH] security: add an interface to lookup the lockdown reason
From: Paul Moore @ 2019-12-10 15:58 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: selinux, linux-security-module, linux-next, jamorris
In-Reply-To: <a11bfefc-c010-36ca-2303-35dcd4e9aa41@tycho.nsa.gov>

On Tue, Dec 10, 2019 at 10:45 AM Stephen Smalley <sds@tycho.nsa.gov> wrote:
> On 12/10/19 10:04 AM, Paul Moore wrote:
> > On Tue, Dec 10, 2019 at 9:59 AM Stephen Smalley <sds@tycho.nsa.gov> wrote:
> >> On 12/9/19 9:28 PM, Paul Moore wrote:
> >>> With CONFIG_AUDIT enabled but CONFIG_SECURITY disabled we run into
> >>> a problem where the lockdown reason table is missing.  This patch
> >>> attempts to fix this by hiding the table behind a lookup function.
> >>
> >> Shouldn't lsm_audit.c be conditional on both CONFIG_AUDIT and
> >> CONFIG_SECURITY?  When/why would we want it built without
> >> CONFIG_SECURITY enabled?
> >
> > My first thought of a fix was just that, but I remembered that the
> > capabilities code is built regardless of the CONFIG_SECURITY setting
> > and I thought there might be some value in allowing for lsm_audit to
> > be used in commoncap (although in full disclosure commoncap doesn't
> > currently make use of lsm_audit).
>
> Seems contrary to normal practice, i.e. if/when commoncap grows a
> dependency, it can be changed then.

Okay, want to submit a tested patch?  I really would like to get this
fixed before today's linux-next run.

-- 
paul moore
www.paul-moore.com

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox