Commit e38bb238 authored by Scott Mayhew's avatar Scott Mayhew Committed by Anna Schumaker

NFS: Convert mount option parsing to use functionality from fs_parser.h

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: default avatarScott Mayhew <smayhew@redhat.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 38465f5d
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/fs.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_fs.h>
#include <linux/nfs_mount.h> #include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h> #include <linux/nfs4_mount.h>
...@@ -28,218 +29,215 @@ ...@@ -28,218 +29,215 @@
#define NFS_MAX_CONNECTIONS 16 #define NFS_MAX_CONNECTIONS 16
enum { enum nfs_param {
/* Mount options that take no arguments */ Opt_ac,
Opt_soft, Opt_softerr, Opt_hard, Opt_acdirmax,
Opt_posix, Opt_noposix, Opt_acdirmin,
Opt_cto, Opt_nocto, Opt_acl,
Opt_ac, Opt_noac, Opt_acregmax,
Opt_lock, Opt_nolock, Opt_acregmin,
Opt_udp, Opt_tcp, Opt_rdma,
Opt_acl, Opt_noacl,
Opt_rdirplus, Opt_nordirplus,
Opt_sharecache, Opt_nosharecache,
Opt_resvport, Opt_noresvport,
Opt_fscache, Opt_nofscache,
Opt_migration, Opt_nomigration,
/* Mount options that take integer arguments */
Opt_port,
Opt_rsize, Opt_wsize, Opt_bsize,
Opt_timeo, Opt_retrans,
Opt_acregmin, Opt_acregmax,
Opt_acdirmin, Opt_acdirmax,
Opt_actimeo, Opt_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_mountport,
Opt_mountproto,
Opt_mountvers, Opt_mountvers,
Opt_minorversion, Opt_namelen,
/* Mount options that take string arguments */
Opt_nfsvers,
Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
Opt_addr, Opt_mountaddr, Opt_clientaddr,
Opt_nconnect, Opt_nconnect,
Opt_lookupcache, Opt_port,
Opt_fscache_uniq, Opt_posix,
Opt_local_lock, Opt_proto,
Opt_rdirplus,
/* Special mount options */ Opt_rdma,
Opt_userspace, Opt_deprecated, Opt_sloppy, Opt_resvport,
Opt_retrans,
Opt_err 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 = { static const struct fs_parameter_spec nfs_param_specs[] = {
{ Opt_userspace, "bg" }, fsparam_flag_no("ac", Opt_ac),
{ Opt_userspace, "fg" }, fsparam_u32 ("acdirmax", Opt_acdirmax),
{ Opt_userspace, "retry=%s" }, fsparam_u32 ("acdirmin", Opt_acdirmin),
fsparam_flag_no("acl", Opt_acl),
{ Opt_sloppy, "sloppy" }, fsparam_u32 ("acregmax", Opt_acregmax),
fsparam_u32 ("acregmin", Opt_acregmin),
{ Opt_soft, "soft" }, fsparam_u32 ("actimeo", Opt_actimeo),
{ Opt_softerr, "softerr" }, fsparam_string("addr", Opt_addr),
{ Opt_hard, "hard" }, fsparam_flag ("bg", Opt_bg),
{ Opt_deprecated, "intr" }, fsparam_u32 ("bsize", Opt_bsize),
{ Opt_deprecated, "nointr" }, fsparam_string("clientaddr", Opt_clientaddr),
{ Opt_posix, "posix" }, fsparam_flag_no("cto", Opt_cto),
{ Opt_noposix, "noposix" }, fsparam_flag ("fg", Opt_fg),
{ Opt_cto, "cto" }, __fsparam(fs_param_is_string, "fsc", Opt_fscache,
{ Opt_nocto, "nocto" }, fs_param_neg_with_no|fs_param_v_optional),
{ Opt_ac, "ac" }, fsparam_flag ("hard", Opt_hard),
{ Opt_noac, "noac" }, __fsparam(fs_param_is_flag, "intr", Opt_intr,
{ Opt_lock, "lock" }, fs_param_neg_with_no|fs_param_deprecated),
{ Opt_nolock, "nolock" }, fsparam_enum ("local_lock", Opt_local_lock),
{ Opt_udp, "udp" }, fsparam_flag_no("lock", Opt_lock),
{ Opt_tcp, "tcp" }, fsparam_enum ("lookupcache", Opt_lookupcache),
{ Opt_rdma, "rdma" }, fsparam_flag_no("migration", Opt_migration),
{ Opt_acl, "acl" }, fsparam_u32 ("minorversion", Opt_minorversion),
{ Opt_noacl, "noacl" }, fsparam_string("mountaddr", Opt_mountaddr),
{ Opt_rdirplus, "rdirplus" }, fsparam_string("mounthost", Opt_mounthost),
{ Opt_nordirplus, "nordirplus" }, fsparam_u32 ("mountport", Opt_mountport),
{ Opt_sharecache, "sharecache" }, fsparam_string("mountproto", Opt_mountproto),
{ Opt_nosharecache, "nosharecache" }, fsparam_u32 ("mountvers", Opt_mountvers),
{ Opt_resvport, "resvport" }, fsparam_u32 ("namlen", Opt_namelen),
{ Opt_noresvport, "noresvport" }, fsparam_u32 ("nconnect", Opt_nconnect),
{ Opt_fscache, "fsc" }, fsparam_string("nfsvers", Opt_vers),
{ Opt_nofscache, "nofsc" }, fsparam_u32 ("port", Opt_port),
{ Opt_migration, "migration" }, fsparam_flag_no("posix", Opt_posix),
{ Opt_nomigration, "nomigration" }, fsparam_string("proto", Opt_proto),
fsparam_flag_no("rdirplus", Opt_rdirplus),
{ Opt_port, "port=%s" }, fsparam_flag ("rdma", Opt_rdma),
{ Opt_rsize, "rsize=%s" }, fsparam_flag_no("resvport", Opt_resvport),
{ Opt_wsize, "wsize=%s" }, fsparam_u32 ("retrans", Opt_retrans),
{ Opt_bsize, "bsize=%s" }, fsparam_string("retry", Opt_retry),
{ Opt_timeo, "timeo=%s" }, fsparam_u32 ("rsize", Opt_rsize),
{ Opt_retrans, "retrans=%s" }, fsparam_string("sec", Opt_sec),
{ Opt_acregmin, "acregmin=%s" }, fsparam_flag_no("sharecache", Opt_sharecache),
{ Opt_acregmax, "acregmax=%s" }, fsparam_flag ("sloppy", Opt_sloppy),
{ Opt_acdirmin, "acdirmin=%s" }, fsparam_flag ("soft", Opt_soft),
{ Opt_acdirmax, "acdirmax=%s" }, fsparam_flag ("softerr", Opt_softerr),
{ Opt_actimeo, "actimeo=%s" }, fsparam_string("source", Opt_source),
{ Opt_namelen, "namlen=%s" }, fsparam_flag ("tcp", Opt_tcp),
{ Opt_mountport, "mountport=%s" }, fsparam_u32 ("timeo", Opt_timeo),
{ Opt_mountvers, "mountvers=%s" }, fsparam_flag ("udp", Opt_udp),
{ Opt_minorversion, "minorversion=%s" }, fsparam_flag ("v2", Opt_v),
fsparam_flag ("v3", Opt_v),
{ Opt_nfsvers, "nfsvers=%s" }, fsparam_flag ("v4", Opt_v),
{ Opt_nfsvers, "vers=%s" }, fsparam_flag ("v4.0", Opt_v),
fsparam_flag ("v4.1", Opt_v),
{ Opt_sec, "sec=%s" }, fsparam_flag ("v4.2", Opt_v),
{ Opt_proto, "proto=%s" }, fsparam_string("vers", Opt_vers),
{ Opt_mountproto, "mountproto=%s" }, fsparam_u32 ("wsize", Opt_wsize),
{ Opt_addr, "addr=%s" }, {}
{ Opt_clientaddr, "clientaddr=%s" },
{ Opt_mounthost, "mounthost=%s" },
{ Opt_mountaddr, "mountaddr=%s" },
{ Opt_nconnect, "nconnect=%s" },
{ Opt_lookupcache, "lookupcache=%s" },
{ Opt_fscache_uniq, "fsc=%s" },
{ Opt_local_lock, "local_lock=%s" },
/* The following needs to be listed after all other options */
{ Opt_nfsvers, "v%s" },
{ Opt_err, NULL }
}; };
enum { enum {
Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma, Opt_local_lock_all,
Opt_xprt_rdma6, Opt_local_lock_flock,
Opt_local_lock_none,
Opt_xprt_err Opt_local_lock_posix,
};
static const match_table_t nfs_xprt_protocol_tokens = {
{ Opt_xprt_udp, "udp" },
{ Opt_xprt_udp6, "udp6" },
{ Opt_xprt_tcp, "tcp" },
{ Opt_xprt_tcp6, "tcp6" },
{ Opt_xprt_rdma, "rdma" },
{ Opt_xprt_rdma6, "rdma6" },
{ Opt_xprt_err, NULL }
}; };
enum { enum {
Opt_sec_none, Opt_sec_sys, Opt_lookupcache_all,
Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p, Opt_lookupcache_none,
Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp, Opt_lookupcache_positive,
Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp,
Opt_sec_err
}; };
static const match_table_t nfs_secflavor_tokens = { static const struct fs_parameter_enum nfs_param_enums[] = {
{ Opt_sec_none, "none" }, { Opt_local_lock, "all", Opt_local_lock_all },
{ Opt_sec_none, "null" }, { Opt_local_lock, "flock", Opt_local_lock_flock },
{ Opt_sec_sys, "sys" }, { Opt_local_lock, "none", Opt_local_lock_none },
{ Opt_local_lock, "posix", Opt_local_lock_posix },
{ Opt_sec_krb5, "krb5" }, { Opt_lookupcache, "all", Opt_lookupcache_all },
{ Opt_sec_krb5i, "krb5i" }, { Opt_lookupcache, "none", Opt_lookupcache_none },
{ Opt_sec_krb5p, "krb5p" }, { Opt_lookupcache, "pos", Opt_lookupcache_positive },
{ Opt_lookupcache, "positive", Opt_lookupcache_positive },
{ Opt_sec_lkey, "lkey" }, {}
{ Opt_sec_lkeyi, "lkeyi" }, };
{ Opt_sec_lkeyp, "lkeyp" },
{ Opt_sec_spkm, "spkm3" },
{ Opt_sec_spkmi, "spkm3i" },
{ Opt_sec_spkmp, "spkm3p" },
{ Opt_sec_err, NULL } static const struct fs_parameter_description nfs_fs_parameters = {
.name = "nfs",
.specs = nfs_param_specs,
.enums = nfs_param_enums,
}; };
enum { enum {
Opt_lookupcache_all, Opt_lookupcache_positive, Opt_vers_2,
Opt_lookupcache_none, Opt_vers_3,
Opt_vers_4,
Opt_lookupcache_err Opt_vers_4_0,
Opt_vers_4_1,
Opt_vers_4_2,
}; };
static const match_table_t nfs_lookupcache_tokens = { static const struct constant_table nfs_vers_tokens[] = {
{ Opt_lookupcache_all, "all" }, { "2", Opt_vers_2 },
{ Opt_lookupcache_positive, "pos" }, { "3", Opt_vers_3 },
{ Opt_lookupcache_positive, "positive" }, { "4", Opt_vers_4 },
{ Opt_lookupcache_none, "none" }, { "4.0", Opt_vers_4_0 },
{ "4.1", Opt_vers_4_1 },
{ Opt_lookupcache_err, NULL } { "4.2", Opt_vers_4_2 },
}; };
enum { enum {
Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix, Opt_xprt_rdma,
Opt_local_lock_none, Opt_xprt_rdma6,
Opt_xprt_tcp,
Opt_local_lock_err Opt_xprt_tcp6,
Opt_xprt_udp,
Opt_xprt_udp6,
nr__Opt_xprt
}; };
static const match_table_t nfs_local_lock_tokens = { static const struct constant_table nfs_xprt_protocol_tokens[nr__Opt_xprt] = {
{ Opt_local_lock_all, "all" }, { "rdma", Opt_xprt_rdma },
{ Opt_local_lock_flock, "flock" }, { "rdma6", Opt_xprt_rdma6 },
{ Opt_local_lock_posix, "posix" }, { "tcp", Opt_xprt_tcp },
{ Opt_local_lock_none, "none" }, { "tcp6", Opt_xprt_tcp6 },
{ "udp", Opt_xprt_udp },
{ Opt_local_lock_err, NULL } { "udp6", Opt_xprt_udp6 },
}; };
enum { enum {
Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0, Opt_sec_krb5,
Opt_vers_4_1, Opt_vers_4_2, Opt_sec_krb5i,
Opt_sec_krb5p,
Opt_vers_err 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 = { static const struct constant_table nfs_secflavor_tokens[] = {
{ Opt_vers_2, "2" }, { "krb5", Opt_sec_krb5 },
{ Opt_vers_3, "3" }, { "krb5i", Opt_sec_krb5i },
{ Opt_vers_4, "4" }, { "krb5p", Opt_sec_krb5p },
{ Opt_vers_4_0, "4.0" }, { "lkey", Opt_sec_lkey },
{ Opt_vers_4_1, "4.1" }, { "lkeyi", Opt_sec_lkeyi },
{ Opt_vers_4_2, "4.2" }, { "lkeyp", Opt_sec_lkeyp },
{ "none", Opt_sec_none },
{ Opt_vers_err, NULL } { "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) 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, ...@@ -368,17 +366,19 @@ static int nfs_auth_info_add(struct nfs_fs_context *ctx,
/* /*
* Parse the value of the 'sec=' option. * 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; rpc_authflavor_t pseudoflavor;
char *p; char *string = param->string, *p;
int ret; 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) { while ((p = strsep(&string, ":")) != NULL) {
switch (match_token(p, nfs_secflavor_tokens, args)) { if (!*p)
continue;
switch (lookup_constant(nfs_secflavor_tokens, p, -1)) {
case Opt_sec_none: case Opt_sec_none:
pseudoflavor = RPC_AUTH_NULL; pseudoflavor = RPC_AUTH_NULL;
break; break;
...@@ -427,11 +427,10 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value) ...@@ -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, static int nfs_parse_version_string(struct nfs_fs_context *ctx,
char *string, const char *string)
substring_t *args)
{ {
ctx->flags &= ~NFS_MOUNT_VER3; 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: case Opt_vers_2:
ctx->version = 2; ctx->version = 2;
break; break;
...@@ -465,64 +464,24 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx, ...@@ -465,64 +464,24 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx,
return 0; 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]; struct fs_parse_result result;
char *string; unsigned short protofamily, mountfamily;
int token, ret; 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 (opt) {
switch (token) {
/* /*
* boolean options: foo/nofoo * boolean options: foo/nofoo
*/ */
...@@ -538,30 +497,31 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) ...@@ -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); ctx->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
break; break;
case Opt_posix: case Opt_posix:
ctx->flags |= NFS_MOUNT_POSIX; if (result.negated)
break; ctx->flags &= ~NFS_MOUNT_POSIX;
case Opt_noposix: else
ctx->flags &= ~NFS_MOUNT_POSIX; ctx->flags |= NFS_MOUNT_POSIX;
break; break;
case Opt_cto: case Opt_cto:
ctx->flags &= ~NFS_MOUNT_NOCTO; if (result.negated)
break; ctx->flags |= NFS_MOUNT_NOCTO;
case Opt_nocto: else
ctx->flags |= NFS_MOUNT_NOCTO; ctx->flags &= ~NFS_MOUNT_NOCTO;
break; break;
case Opt_ac: case Opt_ac:
ctx->flags &= ~NFS_MOUNT_NOAC; if (result.negated)
break; ctx->flags |= NFS_MOUNT_NOAC;
case Opt_noac: else
ctx->flags |= NFS_MOUNT_NOAC; ctx->flags &= ~NFS_MOUNT_NOAC;
break; break;
case Opt_lock: case Opt_lock:
ctx->flags &= ~NFS_MOUNT_NONLM; if (result.negated) {
ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL); ctx->flags |= NFS_MOUNT_NONLM;
break; ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
case Opt_nolock: } else {
ctx->flags |= NFS_MOUNT_NONLM; ctx->flags &= ~NFS_MOUNT_NONLM;
ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL); ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
}
break; break;
case Opt_udp: case Opt_udp:
ctx->flags &= ~NFS_MOUNT_TCP; ctx->flags &= ~NFS_MOUNT_TCP;
...@@ -574,195 +534,177 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) ...@@ -574,195 +534,177 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
case Opt_rdma: case Opt_rdma:
ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */ ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */
ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA; ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
xprt_load_transport(p); xprt_load_transport(param->key);
break; break;
case Opt_acl: case Opt_acl:
ctx->flags &= ~NFS_MOUNT_NOACL; if (result.negated)
break; ctx->flags |= NFS_MOUNT_NOACL;
case Opt_noacl: else
ctx->flags |= NFS_MOUNT_NOACL; ctx->flags &= ~NFS_MOUNT_NOACL;
break; break;
case Opt_rdirplus: case Opt_rdirplus:
ctx->flags &= ~NFS_MOUNT_NORDIRPLUS; if (result.negated)
break; ctx->flags |= NFS_MOUNT_NORDIRPLUS;
case Opt_nordirplus: else
ctx->flags |= NFS_MOUNT_NORDIRPLUS; ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
break; break;
case Opt_sharecache: case Opt_sharecache:
ctx->flags &= ~NFS_MOUNT_UNSHARED; if (result.negated)
break; ctx->flags |= NFS_MOUNT_UNSHARED;
case Opt_nosharecache: else
ctx->flags |= NFS_MOUNT_UNSHARED; ctx->flags &= ~NFS_MOUNT_UNSHARED;
break; break;
case Opt_resvport: case Opt_resvport:
ctx->flags &= ~NFS_MOUNT_NORESVPORT; if (result.negated)
break; ctx->flags |= NFS_MOUNT_NORESVPORT;
case Opt_noresvport: else
ctx->flags |= NFS_MOUNT_NORESVPORT; ctx->flags &= ~NFS_MOUNT_NORESVPORT;
break; break;
case Opt_fscache: case Opt_fscache:
ctx->options |= NFS_OPTION_FSCACHE;
kfree(ctx->fscache_uniq); kfree(ctx->fscache_uniq);
ctx->fscache_uniq = NULL; ctx->fscache_uniq = param->string;
break; param->string = NULL;
case Opt_nofscache: if (result.negated)
ctx->options &= ~NFS_OPTION_FSCACHE; ctx->options &= ~NFS_OPTION_FSCACHE;
kfree(ctx->fscache_uniq); else
ctx->fscache_uniq = NULL; ctx->options |= NFS_OPTION_FSCACHE;
break; break;
case Opt_migration: case Opt_migration:
ctx->options |= NFS_OPTION_MIGRATION; if (result.negated)
break; ctx->options &= ~NFS_OPTION_MIGRATION;
case Opt_nomigration: else
ctx->options &= ~NFS_OPTION_MIGRATION; ctx->options |= NFS_OPTION_MIGRATION;
break; break;
/* /*
* options that take numeric values * options that take numeric values
*/ */
case Opt_port: case Opt_port:
if (nfs_get_option_ui_bound(ctx, args, &ctx->nfs_server.port, if (result.uint_32 > USHRT_MAX)
0, USHRT_MAX)) goto out_of_bounds;
goto out_invalid_value; ctx->nfs_server.port = result.uint_32;
break; break;
case Opt_rsize: case Opt_rsize:
if (nfs_get_option_ui(ctx, args, &ctx->rsize)) ctx->rsize = result.uint_32;
goto out_invalid_value;
break; break;
case Opt_wsize: case Opt_wsize:
if (nfs_get_option_ui(ctx, args, &ctx->wsize)) ctx->wsize = result.uint_32;
goto out_invalid_value;
break; break;
case Opt_bsize: case Opt_bsize:
if (nfs_get_option_ui(ctx, args, &ctx->bsize)) ctx->bsize = result.uint_32;
goto out_invalid_value;
break; break;
case Opt_timeo: case Opt_timeo:
if (nfs_get_option_ui_bound(ctx, args, &ctx->timeo, 1, INT_MAX)) if (result.uint_32 < 1 || result.uint_32 > INT_MAX)
goto out_invalid_value; goto out_of_bounds;
ctx->timeo = result.uint_32;
break; break;
case Opt_retrans: case Opt_retrans:
if (nfs_get_option_ui_bound(ctx, args, &ctx->retrans, 0, INT_MAX)) if (result.uint_32 > INT_MAX)
goto out_invalid_value; goto out_of_bounds;
ctx->retrans = result.uint_32;
break; break;
case Opt_acregmin: case Opt_acregmin:
if (nfs_get_option_ui(ctx, args, &ctx->acregmin)) ctx->acregmin = result.uint_32;
goto out_invalid_value;
break; break;
case Opt_acregmax: case Opt_acregmax:
if (nfs_get_option_ui(ctx, args, &ctx->acregmax)) ctx->acregmax = result.uint_32;
goto out_invalid_value;
break; break;
case Opt_acdirmin: case Opt_acdirmin:
if (nfs_get_option_ui(ctx, args, &ctx->acdirmin)) ctx->acdirmin = result.uint_32;
goto out_invalid_value;
break; break;
case Opt_acdirmax: case Opt_acdirmax:
if (nfs_get_option_ui(ctx, args, &ctx->acdirmax)) ctx->acdirmax = result.uint_32;
goto out_invalid_value;
break; break;
case Opt_actimeo: case Opt_actimeo:
if (nfs_get_option_ui(ctx, args, &ctx->acdirmax)) ctx->acregmin = result.uint_32;
goto out_invalid_value; ctx->acregmax = result.uint_32;
ctx->acregmin = ctx->acregmax = ctx->acdirmin = result.uint_32;
ctx->acdirmin = ctx->acdirmax; ctx->acdirmax = result.uint_32;
break; break;
case Opt_namelen: case Opt_namelen:
if (nfs_get_option_ui(ctx, args, &ctx->namlen)) ctx->namlen = result.uint_32;
goto out_invalid_value;
break; break;
case Opt_mountport: case Opt_mountport:
if (nfs_get_option_ui_bound(ctx, args, &ctx->mount_server.port, if (result.uint_32 > USHRT_MAX)
0, USHRT_MAX)) goto out_of_bounds;
goto out_invalid_value; ctx->mount_server.port = result.uint_32;
break; break;
case Opt_mountvers: case Opt_mountvers:
if (nfs_get_option_ui_bound(ctx, args, &ctx->mount_server.version, if (result.uint_32 < NFS_MNT_VERSION ||
NFS_MNT_VERSION, NFS_MNT3_VERSION)) result.uint_32 > NFS_MNT3_VERSION)
goto out_invalid_value; goto out_of_bounds;
ctx->mount_server.version = result.uint_32;
break; break;
case Opt_minorversion: case Opt_minorversion:
if (nfs_get_option_ui_bound(ctx, args, &ctx->minorversion, if (result.uint_32 > NFS4_MAX_MINOR_VERSION)
0, NFS4_MAX_MINOR_VERSION)) goto out_of_bounds;
goto out_invalid_value; ctx->minorversion = result.uint_32;
break; break;
/* /*
* options that take text values * options that take text values
*/ */
case Opt_nfsvers: case Opt_v:
string = match_strdup(args); ret = nfs_parse_version_string(ctx, param->key + 1);
if (string == NULL) if (ret < 0)
goto out_nomem; return ret;
ret = nfs_parse_version_string(ctx, string, args); break;
kfree(string); case Opt_vers:
ret = nfs_parse_version_string(ctx, param->string);
if (ret < 0) if (ret < 0)
return ret; return ret;
break; break;
case Opt_sec: case Opt_sec:
string = match_strdup(args); ret = nfs_parse_security_flavors(ctx, param);
if (string == NULL)
goto out_nomem;
ret = nfs_parse_security_flavors(ctx, string);
kfree(string);
if (ret < 0) if (ret < 0)
return ret; return ret;
break; 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; case Opt_proto:
switch (token) { protofamily = AF_INET;
switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
case Opt_xprt_udp6: case Opt_xprt_udp6:
ctx->protofamily = AF_INET6; protofamily = AF_INET6;
/* fall through */ /* fall through */
case Opt_xprt_udp: case Opt_xprt_udp:
ctx->flags &= ~NFS_MOUNT_TCP; ctx->flags &= ~NFS_MOUNT_TCP;
ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
break; break;
case Opt_xprt_tcp6: case Opt_xprt_tcp6:
ctx->protofamily = AF_INET6; protofamily = AF_INET6;
/* fall through */ /* fall through */
case Opt_xprt_tcp: case Opt_xprt_tcp:
ctx->flags |= NFS_MOUNT_TCP; ctx->flags |= NFS_MOUNT_TCP;
ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP; ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
break; break;
case Opt_xprt_rdma6: case Opt_xprt_rdma6:
ctx->protofamily = AF_INET6; protofamily = AF_INET6;
/* fall through */ /* fall through */
case Opt_xprt_rdma: case Opt_xprt_rdma:
/* vector side protocols to TCP */ /* vector side protocols to TCP */
ctx->flags |= NFS_MOUNT_TCP; ctx->flags |= NFS_MOUNT_TCP;
ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA; ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
xprt_load_transport(string); xprt_load_transport(param->string);
break; break;
default: default:
kfree(string);
dfprintk(MOUNT, "NFS: unrecognized transport protocol\n"); dfprintk(MOUNT, "NFS: unrecognized transport protocol\n");
return -EINVAL; return -EINVAL;
} }
kfree(string);
ctx->protofamily = protofamily;
break; 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; case Opt_mountproto:
switch (token) { mountfamily = AF_INET;
switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
case Opt_xprt_udp6: case Opt_xprt_udp6:
ctx->mountfamily = AF_INET6; mountfamily = AF_INET6;
/* fall through */ /* fall through */
case Opt_xprt_udp: case Opt_xprt_udp:
ctx->mount_server.protocol = XPRT_TRANSPORT_UDP; ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
break; break;
case Opt_xprt_tcp6: case Opt_xprt_tcp6:
ctx->mountfamily = AF_INET6; mountfamily = AF_INET6;
/* fall through */ /* fall through */
case Opt_xprt_tcp: case Opt_xprt_tcp:
ctx->mount_server.protocol = XPRT_TRANSPORT_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) ...@@ -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"); dfprintk(MOUNT, "NFS: unrecognized transport protocol\n");
return -EINVAL; return -EINVAL;
} }
ctx->mountfamily = mountfamily;
break; break;
case Opt_addr: case Opt_addr:
string = match_strdup(args); len = rpc_pton(ctx->net, param->string, param->size,
if (string == NULL) &ctx->nfs_server.address,
goto out_nomem; sizeof(ctx->nfs_server._address));
ctx->nfs_server.addrlen = if (len == 0)
rpc_pton(ctx->net, string, strlen(string),
&ctx->nfs_server.address,
sizeof(ctx->nfs_server._address));
kfree(string);
if (ctx->nfs_server.addrlen == 0)
goto out_invalid_address; goto out_invalid_address;
ctx->nfs_server.addrlen = len;
break; break;
case Opt_clientaddr: case Opt_clientaddr:
if (nfs_get_option_str(args, &ctx->client_address)) kfree(ctx->client_address);
goto out_nomem; ctx->client_address = param->string;
param->string = NULL;
break; break;
case Opt_mounthost: case Opt_mounthost:
if (nfs_get_option_str(args, &ctx->mount_server.hostname)) kfree(ctx->mount_server.hostname);
goto out_nomem; ctx->mount_server.hostname = param->string;
param->string = NULL;
break; break;
case Opt_mountaddr: case Opt_mountaddr:
string = match_strdup(args); len = rpc_pton(ctx->net, param->string, param->size,
if (string == NULL) &ctx->mount_server.address,
goto out_nomem; sizeof(ctx->mount_server._address));
ctx->mount_server.addrlen = if (len == 0)
rpc_pton(ctx->net, string, strlen(string),
&ctx->mount_server.address,
sizeof(ctx->mount_server._address));
kfree(string);
if (ctx->mount_server.addrlen == 0)
goto out_invalid_address; goto out_invalid_address;
ctx->mount_server.addrlen = len;
break; break;
case Opt_nconnect: case Opt_nconnect:
if (nfs_get_option_us_bound(ctx, args, &ctx->nfs_server.nconnect, if (result.uint_32 < 1 || result.uint_32 > NFS_MAX_CONNECTIONS)
1, NFS_MAX_CONNECTIONS)) goto out_of_bounds;
goto out_invalid_value; ctx->nfs_server.nconnect = result.uint_32;
break; break;
case Opt_lookupcache: case Opt_lookupcache:
string = match_strdup(args); switch (result.uint_32) {
if (string == NULL)
goto out_nomem;
token = match_token(string, nfs_lookupcache_tokens, args);
kfree(string);
switch (token) {
case Opt_lookupcache_all: case Opt_lookupcache_all:
ctx->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE); ctx->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
break; break;
...@@ -828,22 +761,11 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) ...@@ -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; ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
break; break;
default: default:
dfprintk(MOUNT, "NFS: invalid lookupcache argument\n"); goto out_invalid_value;
return -EINVAL;
} }
break; 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: case Opt_local_lock:
string = match_strdup(args); switch (result.uint_32) {
if (string == NULL)
goto out_nomem;
token = match_token(string, nfs_local_lock_tokens, args);
kfree(string);
switch (token) {
case Opt_local_lock_all: case Opt_local_lock_all:
ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
NFS_MOUNT_LOCAL_FCNTL); NFS_MOUNT_LOCAL_FCNTL);
...@@ -859,8 +781,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) ...@@ -859,8 +781,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
NFS_MOUNT_LOCAL_FCNTL); NFS_MOUNT_LOCAL_FCNTL);
break; break;
default: default:
dfprintk(MOUNT, "NFS: invalid local_lock argument\n"); goto out_invalid_value;
return -EINVAL;
} }
break; break;
...@@ -868,30 +789,50 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) ...@@ -868,30 +789,50 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
* Special options * Special options
*/ */
case Opt_sloppy: case Opt_sloppy:
ctx->sloppy = 1; ctx->sloppy = true;
dfprintk(MOUNT, "NFS: relaxing parsing rules\n"); dfprintk(MOUNT, "NFS: relaxing parsing rules\n");
break; 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; return 0;
out_invalid_address:
printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
return -EINVAL;
out_invalid_value: 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; return -EINVAL;
out_nomem: out_invalid_address:
printk(KERN_INFO "NFS: not enough memory to parse option\n"); printk(KERN_INFO "NFS: Bad IP address specified\n");
return -ENOMEM; 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;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment