NFS: Invalid mount option values should always fail, even with "sloppy"

Ian Kent reports:

"I've noticed a couple of other regressions with the options vers
and proto option of mount.nfs(8).

The commands:

mount -t nfs -o vers=<invalid version> <server>:/<path> /<mountpoint>
mount -t nfs -o proto=<invalid proto> <server>:/<path> /<mountpoint>

both immediately fail.

But if the "-s" option is also used they both succeed with the
mount falling back to defaults (by the look of it).

In the past these failed even when the sloppy option was given, as
I think they should. I believe the sloppy option is meant to allow
the mount command to still function for mount options (for example
in shared autofs maps) that exist on other Unix implementations but
aren't present in the Linux mount.nfs(8). So, an invalid value
specified for a known mount option is different to an unknown mount
option and should fail appropriately."

See RH bugzilla 486266.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Chuck Lever 2009-06-17 18:02:13 -07:00 committed by Trond Myklebust
parent 065015e5ef
commit d23c45fd84

View file

@ -942,11 +942,6 @@ static int nfs_parse_security_flavors(char *value,
return 1; return 1;
} }
static void nfs_parse_invalid_value(const char *option)
{
dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option);
}
/* /*
* Error-check and convert a string of mount options from user space into * 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 * a data structure. The whole mount string is processed; bad options are
@ -957,7 +952,7 @@ static int nfs_parse_mount_options(char *raw,
struct nfs_parsed_mount_data *mnt) struct nfs_parsed_mount_data *mnt)
{ {
char *p, *string, *secdata; char *p, *string, *secdata;
int rc, sloppy = 0, errors = 0; int rc, sloppy = 0, invalid_option = 0;
if (!raw) { if (!raw) {
dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
@ -1091,113 +1086,82 @@ static int nfs_parse_mount_options(char *raw,
*/ */
case Opt_port: case Opt_port:
if (match_int(args, &option) || if (match_int(args, &option) ||
option < 0 || option > USHORT_MAX) { option < 0 || option > USHORT_MAX)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("port"); mnt->nfs_server.port = option;
} else
mnt->nfs_server.port = option;
break; break;
case Opt_rsize: case Opt_rsize:
if (match_int(args, &option) || option < 0) { if (match_int(args, &option) || option < 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("rsize"); mnt->rsize = option;
} else
mnt->rsize = option;
break; break;
case Opt_wsize: case Opt_wsize:
if (match_int(args, &option) || option < 0) { if (match_int(args, &option) || option < 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("wsize"); mnt->wsize = option;
} else
mnt->wsize = option;
break; break;
case Opt_bsize: case Opt_bsize:
if (match_int(args, &option) || option < 0) { if (match_int(args, &option) || option < 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("bsize"); mnt->bsize = option;
} else
mnt->bsize = option;
break; break;
case Opt_timeo: case Opt_timeo:
if (match_int(args, &option) || option <= 0) { if (match_int(args, &option) || option <= 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("timeo"); mnt->timeo = option;
} else
mnt->timeo = option;
break; break;
case Opt_retrans: case Opt_retrans:
if (match_int(args, &option) || option <= 0) { if (match_int(args, &option) || option <= 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("retrans"); mnt->retrans = option;
} else
mnt->retrans = option;
break; break;
case Opt_acregmin: case Opt_acregmin:
if (match_int(args, &option) || option < 0) { if (match_int(args, &option) || option < 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("acregmin"); mnt->acregmin = option;
} else
mnt->acregmin = option;
break; break;
case Opt_acregmax: case Opt_acregmax:
if (match_int(args, &option) || option < 0) { if (match_int(args, &option) || option < 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("acregmax"); mnt->acregmax = option;
} else
mnt->acregmax = option;
break; break;
case Opt_acdirmin: case Opt_acdirmin:
if (match_int(args, &option) || option < 0) { if (match_int(args, &option) || option < 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("acdirmin"); mnt->acdirmin = option;
} else
mnt->acdirmin = option;
break; break;
case Opt_acdirmax: case Opt_acdirmax:
if (match_int(args, &option) || option < 0) { if (match_int(args, &option) || option < 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("acdirmax"); mnt->acdirmax = option;
} else
mnt->acdirmax = option;
break; break;
case Opt_actimeo: case Opt_actimeo:
if (match_int(args, &option) || option < 0) { if (match_int(args, &option) || option < 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("actimeo"); mnt->acregmin = mnt->acregmax =
} else mnt->acdirmin = mnt->acdirmax = option;
mnt->acregmin = mnt->acregmax =
mnt->acdirmin = mnt->acdirmax = option;
break; break;
case Opt_namelen: case Opt_namelen:
if (match_int(args, &option) || option < 0) { if (match_int(args, &option) || option < 0)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("namlen"); mnt->namlen = option;
} else
mnt->namlen = option;
break; break;
case Opt_mountport: case Opt_mountport:
if (match_int(args, &option) || if (match_int(args, &option) ||
option < 0 || option > USHORT_MAX) { option < 0 || option > USHORT_MAX)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("mountport"); mnt->mount_server.port = option;
} else
mnt->mount_server.port = option;
break; break;
case Opt_mountvers: case Opt_mountvers:
if (match_int(args, &option) || if (match_int(args, &option) ||
option < NFS_MNT_VERSION || option < NFS_MNT_VERSION ||
option > NFS_MNT3_VERSION) { option > NFS_MNT3_VERSION)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("mountvers"); mnt->mount_server.version = option;
} else
mnt->mount_server.version = option;
break; break;
case Opt_nfsvers: case Opt_nfsvers:
if (match_int(args, &option)) { if (match_int(args, &option))
errors++; goto out_invalid_value;
nfs_parse_invalid_value("nfsvers");
break;
}
switch (option) { switch (option) {
case NFS2_VERSION: case NFS2_VERSION:
mnt->flags &= ~NFS_MOUNT_VER3; mnt->flags &= ~NFS_MOUNT_VER3;
@ -1206,8 +1170,7 @@ static int nfs_parse_mount_options(char *raw,
mnt->flags |= NFS_MOUNT_VER3; mnt->flags |= NFS_MOUNT_VER3;
break; break;
default: default:
errors++; goto out_invalid_value;
nfs_parse_invalid_value("nfsvers");
} }
break; break;
@ -1221,9 +1184,9 @@ static int nfs_parse_mount_options(char *raw,
rc = nfs_parse_security_flavors(string, mnt); rc = nfs_parse_security_flavors(string, mnt);
kfree(string); kfree(string);
if (!rc) { if (!rc) {
errors++;
dfprintk(MOUNT, "NFS: unrecognized " dfprintk(MOUNT, "NFS: unrecognized "
"security flavor\n"); "security flavor\n");
return 0;
} }
break; break;
case Opt_proto: case Opt_proto:
@ -1237,23 +1200,25 @@ static int nfs_parse_mount_options(char *raw,
case Opt_xprt_udp: case Opt_xprt_udp:
mnt->flags &= ~NFS_MOUNT_TCP; mnt->flags &= ~NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
kfree(string);
break; break;
case Opt_xprt_tcp: case Opt_xprt_tcp:
mnt->flags |= NFS_MOUNT_TCP; mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
kfree(string);
break; break;
case Opt_xprt_rdma: case Opt_xprt_rdma:
/* vector side protocols to TCP */ /* vector side protocols to TCP */
mnt->flags |= NFS_MOUNT_TCP; mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
xprt_load_transport(string); xprt_load_transport(string);
kfree(string);
break; break;
default: default:
errors++;
dfprintk(MOUNT, "NFS: unrecognized " dfprintk(MOUNT, "NFS: unrecognized "
"transport protocol\n"); "transport protocol\n");
return 0;
} }
kfree(string);
break; break;
case Opt_mountproto: case Opt_mountproto:
string = match_strdup(args); string = match_strdup(args);
@ -1272,9 +1237,9 @@ static int nfs_parse_mount_options(char *raw,
break; break;
case Opt_xprt_rdma: /* not used for side protocols */ case Opt_xprt_rdma: /* not used for side protocols */
default: default:
errors++;
dfprintk(MOUNT, "NFS: unrecognized " dfprintk(MOUNT, "NFS: unrecognized "
"transport protocol\n"); "transport protocol\n");
return 0;
} }
break; break;
case Opt_addr: case Opt_addr:
@ -1330,9 +1295,9 @@ static int nfs_parse_mount_options(char *raw,
mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
break; break;
default: default:
errors++;
dfprintk(MOUNT, "NFS: invalid " dfprintk(MOUNT, "NFS: invalid "
"lookupcache argument\n"); "lookupcache argument\n");
return 0;
}; };
break; break;
@ -1350,20 +1315,20 @@ static int nfs_parse_mount_options(char *raw,
break; break;
default: default:
errors++; invalid_option = 1;
dfprintk(MOUNT, "NFS: unrecognized mount option " dfprintk(MOUNT, "NFS: unrecognized mount option "
"'%s'\n", p); "'%s'\n", p);
} }
} }
if (errors > 0) { if (!sloppy && invalid_option)
dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", return 0;
errors, (errors == 1 ? "" : "s"));
if (!sloppy)
return 0;
}
return 1; return 1;
out_invalid_value:
printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p);
return 0;
out_nomem: out_nomem:
printk(KERN_INFO "NFS: not enough memory to parse option\n"); printk(KERN_INFO "NFS: not enough memory to parse option\n");
return 0; return 0;