#include <linux/nfs_xdr.h>
#include <linux/magic.h>
#include <linux/parser.h>
+#include <linux/nsproxy.h>
+#include <linux/rcupdate.h>
#include <asm/system.h>
#include <asm/uaccess.h>
Opt_cto, Opt_nocto,
Opt_ac, Opt_noac,
Opt_lock, Opt_nolock,
- Opt_v2, Opt_v3, Opt_v4,
Opt_udp, Opt_tcp, Opt_rdma,
Opt_acl, Opt_noacl,
Opt_rdirplus, Opt_nordirplus,
Opt_namelen,
Opt_mountport,
Opt_mountvers,
- Opt_nfsvers,
Opt_minorversion,
/* Mount options that take string arguments */
+ Opt_nfsvers,
Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
Opt_addr, Opt_mountaddr, Opt_clientaddr,
Opt_lookupcache,
{ Opt_noac, "noac" },
{ Opt_lock, "lock" },
{ Opt_nolock, "nolock" },
- { Opt_v2, "v2" },
- { Opt_v3, "v3" },
- { Opt_v4, "v4" },
{ Opt_udp, "udp" },
{ Opt_tcp, "tcp" },
{ Opt_rdma, "rdma" },
{ 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_minorversion, "minorversion=%s" },
{ Opt_sec, "sec=%s" },
{ Opt_proto, "proto=%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 }
};
{ Opt_local_lock_err, NULL }
};
+enum {
+ Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
+ Opt_vers_4_1,
+
+ Opt_vers_err
+};
+
+static match_table_t nfs_vers_tokens = {
+ { Opt_vers_2, "2" },
+ { Opt_vers_3, "3" },
+ { Opt_vers_4, "4" },
+ { Opt_vers_4_0, "4.0" },
+ { Opt_vers_4_1, "4.1" },
+
+ { Opt_vers_err, NULL }
+};
static void nfs_umount_begin(struct super_block *);
static int nfs_statfs(struct dentry *, struct kstatfs *);
struct nfs_client *clp = nfss->nfs_client;
seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
- seq_printf(m, ",minorversion=%u", clp->cl_minorversion);
}
#else
static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
}
#endif
+static void nfs_show_nfs_version(struct seq_file *m,
+ unsigned int version,
+ unsigned int minorversion)
+{
+ seq_printf(m, ",vers=%u", version);
+ if (version == 4)
+ seq_printf(m, ".%u", minorversion);
+}
+
/*
* Describe the mount options in force on this server representation
*/
u32 version = clp->rpc_ops->version;
int local_flock, local_fcntl;
- seq_printf(m, ",vers=%u", version);
+ nfs_show_nfs_version(m, version, clp->cl_minorversion);
seq_printf(m, ",rsize=%u", nfss->rsize);
seq_printf(m, ",wsize=%u", nfss->wsize);
if (nfss->bsize != 0)
else
seq_puts(m, nfs_infop->nostr);
}
+ rcu_read_lock();
seq_printf(m, ",proto=%s",
rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
+ rcu_read_unlock();
if (version == 4) {
if (nfss->port != NFS_PORT)
seq_printf(m, ",port=%u", nfss->port);
nfs_show_mount_options(m, nfss, 0);
+ rcu_read_lock();
seq_printf(m, ",addr=%s",
rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient,
RPC_DISPLAY_ADDR));
+ rcu_read_unlock();
return 0;
}
seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
+ if (nfss->nfs_client && nfss->nfs_client->impl_id) {
+ struct nfs41_impl_id *impl_id = nfss->nfs_client->impl_id;
+ seq_printf(m, "\n\timpl_id:\tname='%s',domain='%s',"
+ "date='%llu,%u'",
+ impl_id->name, impl_id->domain,
+ impl_id->date.seconds, impl_id->date.nseconds);
+ }
+
seq_printf(m, "\n\tcaps:\t");
seq_printf(m, "caps=0x%x", nfss->caps);
seq_printf(m, ",wtmult=%u", nfss->wtmult);
data->auth_flavor_len = 1;
data->version = version;
data->minorversion = 0;
+ data->net = current->nsproxy->net_ns;
+ security_init_mnt_opts(&data->lsm_opts);
}
return data;
}
+static void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
+{
+ if (data) {
+ kfree(data->client_address);
+ kfree(data->mount_server.hostname);
+ kfree(data->nfs_server.export_path);
+ kfree(data->nfs_server.hostname);
+ kfree(data->fscache_uniq);
+ security_free_mnt_opts(&data->lsm_opts);
+ kfree(data);
+ }
+}
+
/*
* Sanity-check a server address provided by the mount command.
*
return 1;
}
+static int nfs_parse_version_string(char *string,
+ struct nfs_parsed_mount_data *mnt,
+ substring_t *args)
+{
+ mnt->flags &= ~NFS_MOUNT_VER3;
+ switch (match_token(string, nfs_vers_tokens, args)) {
+ case Opt_vers_2:
+ mnt->version = 2;
+ break;
+ case Opt_vers_3:
+ mnt->flags |= NFS_MOUNT_VER3;
+ mnt->version = 3;
+ break;
+ case Opt_vers_4:
+ /* Backward compatibility option. In future,
+ * the mount program should always supply
+ * a NFSv4 minor version number.
+ */
+ mnt->version = 4;
+ break;
+ case Opt_vers_4_0:
+ mnt->version = 4;
+ mnt->minorversion = 0;
+ break;
+ case Opt_vers_4_1:
+ mnt->version = 4;
+ mnt->minorversion = 1;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
static int nfs_get_option_str(substring_t args[], char **option)
{
kfree(*option);
mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
NFS_MOUNT_LOCAL_FCNTL);
break;
- case Opt_v2:
- mnt->flags &= ~NFS_MOUNT_VER3;
- mnt->version = 2;
- break;
- case Opt_v3:
- mnt->flags |= NFS_MOUNT_VER3;
- mnt->version = 3;
- break;
- case Opt_v4:
- mnt->flags &= ~NFS_MOUNT_VER3;
- mnt->version = 4;
- break;
case Opt_udp:
mnt->flags &= ~NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
goto out_invalid_value;
mnt->mount_server.version = option;
break;
- case Opt_nfsvers:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- switch (option) {
- case NFS2_VERSION:
- mnt->flags &= ~NFS_MOUNT_VER3;
- mnt->version = 2;
- break;
- case NFS3_VERSION:
- mnt->flags |= NFS_MOUNT_VER3;
- mnt->version = 3;
- break;
- case NFS4_VERSION:
- mnt->flags &= ~NFS_MOUNT_VER3;
- mnt->version = 4;
- break;
- default:
- goto out_invalid_value;
- }
- break;
case Opt_minorversion:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
/*
* options that take text values
*/
+ case Opt_nfsvers:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ rc = nfs_parse_version_string(string, mnt, args);
+ kfree(string);
+ if (!rc)
+ goto out_invalid_value;
+ break;
case Opt_sec:
string = match_strdup(args);
if (string == NULL)
if (string == NULL)
goto out_nomem;
mnt->nfs_server.addrlen =
- rpc_pton(string, strlen(string),
+ rpc_pton(mnt->net, string, strlen(string),
(struct sockaddr *)
&mnt->nfs_server.address,
sizeof(mnt->nfs_server.address));
if (string == NULL)
goto out_nomem;
mnt->mount_server.addrlen =
- rpc_pton(string, strlen(string),
+ rpc_pton(mnt->net, string, strlen(string),
(struct sockaddr *)
&mnt->mount_server.address,
sizeof(mnt->mount_server.address));
if (!sloppy && invalid_option)
return 0;
+ if (mnt->minorversion && mnt->version != 4)
+ goto out_minorversion_mismatch;
+
/*
* verify that any proto=/mountproto= options match the address
* familiies in the addr=/mountaddr= options.
out_invalid_value:
printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
return 0;
+out_minorversion_mismatch:
+ printk(KERN_INFO "NFS: mount option vers=%u does not support "
+ "minorversion=%u\n", mnt->version, mnt->minorversion);
+ return 0;
out_nomem:
printk(KERN_INFO "NFS: not enough memory to parse option\n");
return 0;
.noresvport = args->flags & NFS_MOUNT_NORESVPORT,
.auth_flav_len = &server_authlist_len,
.auth_flavs = server_authlist,
+ .net = args->net,
};
int status;
data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
mntfh = nfs_alloc_fhandle();
if (data == NULL || mntfh == NULL)
- goto out_free_fh;
-
- security_init_mnt_opts(&data->lsm_opts);
+ goto out;
/* Validate the mount data */
error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name);
#ifdef CONFIG_NFS_V4
if (data->version == 4) {
mntroot = nfs4_try_mount(flags, dev_name, data);
- kfree(data->client_address);
- kfree(data->nfs_server.export_path);
goto out;
}
#endif /* CONFIG_NFS_V4 */
s->s_flags |= MS_ACTIVE;
out:
- kfree(data->nfs_server.hostname);
- kfree(data->mount_server.hostname);
- kfree(data->fscache_uniq);
- security_free_mnt_opts(&data->lsm_opts);
-out_free_fh:
+ nfs_free_parsed_mount_data(data);
nfs_free_fhandle(mntfh);
- kfree(data);
return mntroot;
out_err_nosb:
return -EINVAL;
}
- if (args->client_address == NULL) {
- dfprintk(MOUNT,
- "NFS4: mount program didn't pass callback address\n");
- return -EINVAL;
- }
-
return nfs_parse_devname(dev_name,
&args->nfs_server.hostname,
NFS4_MAXNAMLEN,
mntfh = nfs_alloc_fhandle();
if (data == NULL || mntfh == NULL)
- goto out_free_fh;
-
- security_init_mnt_opts(&data->lsm_opts);
+ goto out;
/* Get a volume representation */
server = nfs4_create_server(data, mntfh);
if (!s->s_root) {
/* initial superblock/root creation */
nfs4_fill_super(s);
- nfs_fscache_get_super_cookie(
- s, data ? data->fscache_uniq : NULL, NULL);
+ nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL);
}
mntroot = nfs4_get_root(s, mntfh, dev_name);
s->s_flags |= MS_ACTIVE;
- security_free_mnt_opts(&data->lsm_opts);
nfs_free_fhandle(mntfh);
return mntroot;
out:
- security_free_mnt_opts(&data->lsm_opts);
-out_free_fh:
nfs_free_fhandle(mntfh);
return ERR_PTR(error);
data = nfs_alloc_parsed_mount_data(4);
if (data == NULL)
- goto out_free_data;
+ goto out;
/* Validate the mount data */
error = nfs4_validate_mount_data(raw_data, data, dev_name);
error = PTR_ERR(res);
out:
- kfree(data->client_address);
- kfree(data->nfs_server.export_path);
- kfree(data->nfs_server.hostname);
- kfree(data->fscache_uniq);
-out_free_data:
- kfree(data);
+ nfs_free_parsed_mount_data(data);
dprintk("<-- nfs4_mount() = %d%s\n", error,
error != 0 ? " [error]" : "");
return res;