// SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/nfs/fs_context.c * * Copyright (C) 1992 Rick Sladkey * Conversion to new mount api Copyright (C) David Howells * * NFS mount handling. * * Split from fs/nfs/super.c by David Howells <dhowells@redhat.com>
*/
/* * Sanity-check a server address provided by the mount command. * * Address family must be initialized, and address must not be * the ANY address for that family.
*/ staticint nfs_verify_server_address(struct sockaddr_storage *addr)
{ switch (addr->ss_family) { case AF_INET: { struct sockaddr_in *sa = (struct sockaddr_in *)addr; return sa->sin_addr.s_addr != htonl(INADDR_ANY);
} case AF_INET6: { struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr; return !ipv6_addr_any(sa);
}
}
/* * Sanity check the NFS transport protocol.
*/ staticint nfs_validate_transport_protocol(struct fs_context *fc, struct nfs_fs_context *ctx)
{ switch (ctx->nfs_server.protocol) { case XPRT_TRANSPORT_UDP: if (nfs_server_transport_udp_invalid(ctx)) goto out_invalid_transport_udp; break; case XPRT_TRANSPORT_TCP: case XPRT_TRANSPORT_RDMA: break; default:
ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
}
if (ctx->xprtsec.policy != RPC_XPRTSEC_NONE) switch (ctx->nfs_server.protocol) { case XPRT_TRANSPORT_TCP:
ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP_TLS; break; default: goto out_invalid_xprtsec_policy;
}
return 0;
out_invalid_transport_udp: return nfs_invalf(fc, "NFS: Unsupported transport protocol udp");
out_invalid_xprtsec_policy: return nfs_invalf(fc, "NFS: Transport does not support xprtsec");
}
/* * For text based NFSv2/v3 mounts, the mount protocol transport default * settings should depend upon the specified NFS transport.
*/ staticvoid nfs_set_mount_transport_protocol(struct nfs_fs_context *ctx)
{ if (ctx->mount_server.protocol == XPRT_TRANSPORT_UDP ||
ctx->mount_server.protocol == XPRT_TRANSPORT_TCP) return; switch (ctx->nfs_server.protocol) { case XPRT_TRANSPORT_UDP:
ctx->mount_server.protocol = XPRT_TRANSPORT_UDP; break; case XPRT_TRANSPORT_TCP: case XPRT_TRANSPORT_RDMA:
ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
}
}
/* * Add 'flavor' to 'auth_info' if not already present. * Returns true if 'flavor' ends up in the list, false otherwise
*/ staticint nfs_auth_info_add(struct fs_context *fc, struct nfs_auth_info *auth_info,
rpc_authflavor_t flavor)
{ unsignedint i; unsignedint max_flavor_len = ARRAY_SIZE(auth_info->flavors);
/* make sure this flavor isn't already in the list */ for (i = 0; i < auth_info->flavor_len; i++) { if (flavor == auth_info->flavors[i]) return 0;
}
if (auth_info->flavor_len + 1 >= max_flavor_len) return nfs_invalf(fc, "NFS: too many sec= flavors");
switch (opt) { case Opt_source: if (fc->source) return nfs_invalf(fc, "NFS: Multiple sources not supported");
fc->source = param->string;
param->string = NULL; break;
/* * 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 | NFS_MOUNT_SOFTREVAL;
ctx->flags &= ~NFS_MOUNT_SOFT; break; case Opt_hard:
ctx->flags &= ~(NFS_MOUNT_SOFT |
NFS_MOUNT_SOFTERR |
NFS_MOUNT_SOFTREVAL); break; case Opt_softreval: if (result.negated)
ctx->flags &= ~NFS_MOUNT_SOFTREVAL; else
ctx->flags |= NFS_MOUNT_SOFTREVAL; break; case Opt_posix: if (result.negated)
ctx->flags &= ~NFS_MOUNT_POSIX; else
ctx->flags |= NFS_MOUNT_POSIX; break; case Opt_cto: if (result.negated)
ctx->flags |= NFS_MOUNT_NOCTO; else
ctx->flags &= ~NFS_MOUNT_NOCTO; break; case Opt_trunkdiscovery: if (result.negated)
ctx->flags &= ~NFS_MOUNT_TRUNK_DISCOVERY; else
ctx->flags |= NFS_MOUNT_TRUNK_DISCOVERY; break; case Opt_alignwrite: if (result.negated)
ctx->flags |= NFS_MOUNT_NO_ALIGNWRITE; else
ctx->flags &= ~NFS_MOUNT_NO_ALIGNWRITE; break; case Opt_ac: if (result.negated)
ctx->flags |= NFS_MOUNT_NOAC; else
ctx->flags &= ~NFS_MOUNT_NOAC; break; case Opt_lock: if (result.negated) {
ctx->lock_status = NFS_LOCK_NOLOCK;
ctx->flags |= NFS_MOUNT_NONLM;
ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
} else {
ctx->lock_status = NFS_LOCK_LOCK;
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: case Opt_rdma:
ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */
ret = xprt_find_transport_ident(param->key); if (ret < 0) goto out_bad_transport;
ctx->nfs_server.protocol = ret; break; case Opt_acl: if (result.negated)
ctx->flags |= NFS_MOUNT_NOACL; else
ctx->flags &= ~NFS_MOUNT_NOACL; break; case Opt_rdirplus: if (result.negated) {
ctx->flags &= ~NFS_MOUNT_FORCE_RDIRPLUS;
ctx->flags |= NFS_MOUNT_NORDIRPLUS;
} elseif (!param->string) {
ctx->flags &= ~(NFS_MOUNT_NORDIRPLUS | NFS_MOUNT_FORCE_RDIRPLUS);
} else { switch (lookup_constant(nfs_rdirplus_tokens, param->string, -1)) { case Opt_rdirplus_none:
ctx->flags &= ~NFS_MOUNT_FORCE_RDIRPLUS;
ctx->flags |= NFS_MOUNT_NORDIRPLUS; break; case Opt_rdirplus_force:
ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
ctx->flags |= NFS_MOUNT_FORCE_RDIRPLUS; break; default: goto out_invalid_value;
}
} break; case Opt_sharecache: if (result.negated)
ctx->flags |= NFS_MOUNT_UNSHARED; else
ctx->flags &= ~NFS_MOUNT_UNSHARED; break; case Opt_resvport: if (result.negated)
ctx->flags |= NFS_MOUNT_NORESVPORT; else
ctx->flags &= ~NFS_MOUNT_NORESVPORT; break; case Opt_fscache_flag: if (result.negated)
ctx->options &= ~NFS_OPTION_FSCACHE; else
ctx->options |= NFS_OPTION_FSCACHE;
kfree(ctx->fscache_uniq);
ctx->fscache_uniq = NULL; break; case Opt_fscache:
trace_nfs_mount_assign(param->key, param->string);
ctx->options |= NFS_OPTION_FSCACHE;
kfree(ctx->fscache_uniq);
ctx->fscache_uniq = param->string;
param->string = NULL; break; case Opt_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 (result.uint_32 > USHRT_MAX) goto out_of_bounds;
ctx->nfs_server.port = result.uint_32; break; case Opt_rsize:
ctx->rsize = result.uint_32; break; case Opt_wsize:
ctx->wsize = result.uint_32; break; case Opt_bsize:
ctx->bsize = result.uint_32; break; case Opt_timeo: if (result.uint_32 < 1 || result.uint_32 > INT_MAX) goto out_of_bounds;
ctx->timeo = result.uint_32; break; case Opt_retrans: if (result.uint_32 > INT_MAX) goto out_of_bounds;
ctx->retrans = result.uint_32; break; case Opt_acregmin:
ctx->acregmin = result.uint_32; break; case Opt_acregmax:
ctx->acregmax = result.uint_32; break; case Opt_acdirmin:
ctx->acdirmin = result.uint_32; break; case Opt_acdirmax:
ctx->acdirmax = result.uint_32; break; case Opt_actimeo:
ctx->acregmin = result.uint_32;
ctx->acregmax = result.uint_32;
ctx->acdirmin = result.uint_32;
ctx->acdirmax = result.uint_32; break; case Opt_namelen:
ctx->namlen = result.uint_32; break; case Opt_mountport: if (result.uint_32 > USHRT_MAX) goto out_of_bounds;
ctx->mount_server.port = result.uint_32; break; case Opt_mountvers: 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 (result.uint_32 > NFS4_MAX_MINOR_VERSION) goto out_of_bounds;
ctx->minorversion = result.uint_32; break;
/* * options that take text values
*/ case Opt_v:
ret = nfs_parse_version_string(fc, param->key + 1); if (ret < 0) return ret; break; case Opt_vers: if (!param->string) goto out_invalid_value;
trace_nfs_mount_assign(param->key, param->string);
ret = nfs_parse_version_string(fc, param->string); if (ret < 0) return ret; break; case Opt_sec:
ret = nfs_parse_security_flavors(fc, param); if (ret < 0) return ret; break; case Opt_xprtsec:
ret = nfs_parse_xprtsec_policy(fc, param); if (ret < 0) return ret; break; case Opt_cert_serial:
ret = nfs_tls_key_verify(result.int_32); if (ret < 0) return ret;
ctx->xprtsec.cert_serial = result.int_32; break; case Opt_privkey_serial:
ret = nfs_tls_key_verify(result.int_32); if (ret < 0) return ret;
ctx->xprtsec.privkey_serial = result.int_32; break;
case Opt_proto: if (!param->string) goto out_invalid_value;
trace_nfs_mount_assign(param->key, param->string);
protofamily = AF_INET; switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) { case Opt_xprt_udp6:
protofamily = AF_INET6;
fallthrough; case Opt_xprt_udp:
ctx->flags &= ~NFS_MOUNT_TCP;
ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; break; case Opt_xprt_tcp6:
protofamily = AF_INET6;
fallthrough; case Opt_xprt_tcp:
ctx->flags |= NFS_MOUNT_TCP;
ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP; break; case Opt_xprt_rdma6:
protofamily = AF_INET6;
fallthrough; case Opt_xprt_rdma: /* vector side protocols to TCP */
ctx->flags |= NFS_MOUNT_TCP;
ret = xprt_find_transport_ident(param->string); if (ret < 0) goto out_bad_transport;
ctx->nfs_server.protocol = ret; break; default: goto out_bad_transport;
}
ctx->protofamily = protofamily; break;
case Opt_mountproto: if (!param->string) goto out_invalid_value;
trace_nfs_mount_assign(param->key, param->string);
mountfamily = AF_INET; switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) { case Opt_xprt_udp6:
mountfamily = AF_INET6;
fallthrough; case Opt_xprt_udp:
ctx->mount_server.protocol = XPRT_TRANSPORT_UDP; break; case Opt_xprt_tcp6:
mountfamily = AF_INET6;
fallthrough; case Opt_xprt_tcp:
ctx->mount_server.protocol = XPRT_TRANSPORT_TCP; break; case Opt_xprt_rdma: /* not used for side protocols */ default: goto out_bad_transport;
}
ctx->mountfamily = mountfamily; break;
case Opt_addr:
trace_nfs_mount_assign(param->key, param->string);
len = rpc_pton(fc->net_ns, 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:
trace_nfs_mount_assign(param->key, param->string);
kfree(ctx->client_address);
ctx->client_address = param->string;
param->string = NULL; break; case Opt_mounthost:
trace_nfs_mount_assign(param->key, param->string);
kfree(ctx->mount_server.hostname);
ctx->mount_server.hostname = param->string;
param->string = NULL; break; case Opt_mountaddr:
trace_nfs_mount_assign(param->key, param->string);
len = rpc_pton(fc->net_ns, 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:
trace_nfs_mount_assign(param->key, param->string); 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_max_connect:
trace_nfs_mount_assign(param->key, param->string); if (result.uint_32 < 1 || result.uint_32 > NFS_MAX_TRANSPORTS) goto out_of_bounds;
ctx->nfs_server.max_connect = result.uint_32; break; case Opt_fatal_neterrors:
trace_nfs_mount_assign(param->key, param->string); switch (result.uint_32) { case Opt_fatal_neterrors_default: if (fc->net_ns != &init_net)
ctx->flags |= NFS_MOUNT_NETUNREACH_FATAL; else
ctx->flags &= ~NFS_MOUNT_NETUNREACH_FATAL; break; case Opt_fatal_neterrors_enetunreach:
ctx->flags |= NFS_MOUNT_NETUNREACH_FATAL; break; case Opt_fatal_neterrors_none:
ctx->flags &= ~NFS_MOUNT_NETUNREACH_FATAL; break; default: goto out_invalid_value;
} break; case Opt_lookupcache:
trace_nfs_mount_assign(param->key, param->string); switch (result.uint_32) { 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: goto out_invalid_value;
} break; case Opt_local_lock:
trace_nfs_mount_assign(param->key, param->string); switch (result.uint_32) { 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: goto out_invalid_value;
} break; case Opt_write:
trace_nfs_mount_assign(param->key, param->string); switch (result.uint_32) { case Opt_write_lazy:
ctx->flags &=
~(NFS_MOUNT_WRITE_EAGER | NFS_MOUNT_WRITE_WAIT); break; case Opt_write_eager:
ctx->flags |= NFS_MOUNT_WRITE_EAGER;
ctx->flags &= ~NFS_MOUNT_WRITE_WAIT; break; case Opt_write_wait:
ctx->flags |=
NFS_MOUNT_WRITE_EAGER | NFS_MOUNT_WRITE_WAIT; break; default: goto out_invalid_value;
} break;
/* * Special options
*/ case Opt_sloppy:
ctx->sloppy = true; break;
}
return 0;
out_invalid_value: return nfs_invalf(fc, "NFS: Bad mount option value specified");
out_invalid_address: return nfs_invalf(fc, "NFS: Bad IP address specified");
out_of_bounds: return nfs_invalf(fc, "NFS: Value for '%s' out of range", param->key);
out_bad_transport: return nfs_invalf(fc, "NFS: Unrecognized transport protocol");
}
/* * Split fc->source into "hostname:export_path". * * The leftmost colon demarks the split between the server's hostname * and the export path. If the hostname starts with a left square * bracket, then it may contain colons. * * Note: caller frees hostname and export path, even on error.
*/ staticint nfs_parse_source(struct fs_context *fc,
size_t maxnamlen, size_t maxpathlen)
{ struct nfs_fs_context *ctx = nfs_fc2context(fc); constchar *dev_name = fc->source;
size_t len; constchar *end;
if (unlikely(!dev_name || !*dev_name)) return -EINVAL;
/* Is the host name protected with square brakcets? */ if (*dev_name == '[') {
end = strchr(++dev_name, ']'); if (end == NULL || end[1] != ':') goto out_bad_devname;
len = end - dev_name;
end++;
} else { constchar *comma;
end = strchr(dev_name, ':'); if (end == NULL) goto out_bad_devname;
len = end - dev_name;
/* kill possible hostname list: not supported */
comma = memchr(dev_name, ',', len); if (comma)
len = comma - dev_name;
}
if (len > maxnamlen) goto out_hostname;
kfree(ctx->nfs_server.hostname);
/* N.B. caller will free nfs_server.hostname in all cases */
ctx->nfs_server.hostname = kmemdup_nul(dev_name, len, GFP_KERNEL); if (!ctx->nfs_server.hostname) goto out_nomem;
len = strlen(++end); if (len > maxpathlen) goto out_path;
ctx->nfs_server.export_path = kmemdup_nul(end, len, GFP_KERNEL); if (!ctx->nfs_server.export_path) goto out_nomem;
/* * Parse monolithic NFS2/NFS3 mount data * - fills in the mount root filehandle * * For option strings, user space handles the following behaviors: * * + DNS: mapping server host name to IP address ("addr=" option) * * + failure mode: how to behave if a mount request can't be handled * immediately ("fg/bg" option) * * + retry: how often to retry a mount request ("retry=" option) * * + breaking back: trying proto=udp after proto=tcp, v2 after v3, * mountproto=tcp after mountproto=udp, and so on
*/ staticint nfs23_parse_monolithic(struct fs_context *fc, struct nfs_mount_data *data)
{ struct nfs_fs_context *ctx = nfs_fc2context(fc); struct nfs_fh *mntfh = ctx->mntfh; struct sockaddr_storage *sap = &ctx->nfs_server._address; int extra_flags = NFS_MOUNT_LEGACY_INTERFACE; int ret;
if (data == NULL) goto out_no_data;
ctx->version = NFS_DEFAULT_VERSION; switch (data->version) { case 1:
data->namlen = 0;
fallthrough; case 2:
data->bsize = 0;
fallthrough; case 3: if (data->flags & NFS_MOUNT_VER3) goto out_no_v3;
data->root.size = NFS2_FHSIZE;
memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); /* Turn off security negotiation */
extra_flags |= NFS_MOUNT_SECFLAVOUR;
fallthrough; case 4: if (data->flags & NFS_MOUNT_SECFLAVOUR) goto out_no_sec;
fallthrough; case 5:
memset(data->context, 0, sizeof(data->context));
fallthrough; case 6: if (data->flags & NFS_MOUNT_VER3) { if (data->root.size > NFS3_FHSIZE || data->root.size == 0) goto out_invalid_fh;
mntfh->size = data->root.size;
ctx->version = 3;
} else {
mntfh->size = NFS2_FHSIZE;
ctx->version = 2;
}
/* * for proto == XPRT_TRANSPORT_UDP, which is what uses * to_exponential, implying shift: limit the shift value * to BITS_PER_LONG (majortimeo is unsigned long)
*/ if (!(data->flags & NFS_MOUNT_TCP)) /* this will be UDP */ if (data->retrans >= 64) /* shift value is too large */ goto out_invalid_data;
if (sap->ss_family != AF_INET ||
!nfs_verify_server_address(sap)) goto out_no_address;
if (!(data->flags & NFS_MOUNT_TCP))
ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; /* N.B. caller will free nfs_server.hostname in all cases */
ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); if (!ctx->nfs_server.hostname) goto out_nomem;
/* * The legacy version 6 binary mount data from userspace has a * field used only to transport selinux information into the * kernel. To continue to support that functionality we * have a touch of selinux knowledge here in the NFS code. The * userspace code converted context=blah to just blah so we are * converting back to the full string selinux understands.
*/ if (data->context[0]){ #ifdef CONFIG_SECURITY_SELINUX int ret;
data->context[NFS_MAX_CONTEXT_LEN] = '\0';
ret = vfs_parse_fs_string(fc, "context",
data->context, strlen(data->context)); if (ret < 0) return ret; #else return -EINVAL; #endif
}
break; default: goto generic;
}
ret = nfs_validate_transport_protocol(fc, ctx); if (ret) return ret;
out_no_data: if (is_remount_fc(fc)) {
ctx->skip_reconfig_option_check = true; return 0;
} return nfs_invalf(fc, "NFS: mount program didn't pass any mount data");
out_no_v3: return nfs_invalf(fc, "NFS: nfs_mount_data version does not support v3");
out_no_sec: return nfs_invalf(fc, "NFS: nfs_mount_data version supports only AUTH_SYS");
out_nomem: return -ENOMEM;
out_no_address: return nfs_invalf(fc, "NFS: mount program didn't pass remote address");
out_inval_auth: return nfs_invalf(fc, "NFS4: Invalid number of RPC auth flavours %d",
data->auth_flavourlen);
out_no_address: return nfs_invalf(fc, "NFS4: mount program didn't pass remote address");
} #endif
/* * Parse a monolithic block of data from sys_mount().
*/ staticint nfs_fs_context_parse_monolithic(struct fs_context *fc, void *data)
{ if (fc->fs_type == &nfs_fs_type) return nfs23_parse_monolithic(fc, data);
#if IS_ENABLED(CONFIG_NFS_V4) if (fc->fs_type == &nfs4_fs_type) return nfs4_parse_monolithic(fc, data); #endif
return nfs_invalf(fc, "NFS: Unsupported monolithic data version");
}
/* * Validate the preparsed information in the config.
*/ staticint nfs_fs_context_validate(struct fs_context *fc)
{ struct nfs_fs_context *ctx = nfs_fc2context(fc); struct nfs_subversion *nfs_mod; struct sockaddr_storage *sap = &ctx->nfs_server._address; int max_namelen = PAGE_SIZE; int max_pathlen = NFS_MAXPATHLEN; int port = 0; int ret;
if (!fc->source) goto out_no_device_name;
/* Check for sanity first. */ if (ctx->minorversion && ctx->version != 4) goto out_minorversion_mismatch;
/* Verify that any proto=/mountproto= options match the address * families in the addr=/mountaddr= options.
*/ if (ctx->protofamily != AF_UNSPEC &&
ctx->protofamily != ctx->nfs_server.address.sa_family) goto out_proto_mismatch;
if (ctx->mountfamily != AF_UNSPEC) { if (ctx->mount_server.addrlen) { if (ctx->mountfamily != ctx->mount_server.address.sa_family) goto out_mountproto_mismatch;
} else { if (ctx->mountfamily != ctx->nfs_server.address.sa_family) goto out_mountproto_mismatch;
}
}
if (!nfs_verify_server_address(sap)) goto out_no_address;
ret = nfs_validate_transport_protocol(fc, ctx); if (ret) return ret;
if (ctx->version == 4) { if (IS_ENABLED(CONFIG_NFS_V4)) { if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
port = NFS_RDMA_PORT; else
port = NFS_PORT;
max_namelen = NFS4_MAXNAMLEN;
max_pathlen = NFS4_MAXPATHLEN;
ctx->flags &= ~(NFS_MOUNT_NONLM | NFS_MOUNT_NOACL |
NFS_MOUNT_VER3 | NFS_MOUNT_LOCAL_FLOCK |
NFS_MOUNT_LOCAL_FCNTL);
} else { goto out_v4_not_compiled;
}
} else {
nfs_set_mount_transport_protocol(ctx); if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
port = NFS_RDMA_PORT;
}
nfs_set_port(sap, &ctx->nfs_server.port, port);
ret = nfs_parse_source(fc, max_namelen, max_pathlen); if (ret < 0) return ret;
/* Load the NFS protocol module if we haven't done so yet */ if (!ctx->nfs_mod) {
nfs_mod = find_nfs_version(ctx->version); if (IS_ERR(nfs_mod)) {
ret = PTR_ERR(nfs_mod); goto out_version_unavailable;
}
ctx->nfs_mod = nfs_mod;
}
/* Ensure the filesystem context has the correct fs_type */ if (fc->fs_type != ctx->nfs_mod->nfs_fs) {
module_put(fc->fs_type->owner);
__module_get(ctx->nfs_mod->nfs_fs->owner);
fc->fs_type = ctx->nfs_mod->nfs_fs;
} return 0;
out_no_device_name: return nfs_invalf(fc, "NFS: Device name not specified");
out_v4_not_compiled:
nfs_errorf(fc, "NFS: NFSv4 is not compiled into kernel"); return -EPROTONOSUPPORT;
out_no_address: return nfs_invalf(fc, "NFS: mount program didn't pass remote address");
out_mountproto_mismatch: return nfs_invalf(fc, "NFS: Mount server address does not match mountproto= option");
out_proto_mismatch: return nfs_invalf(fc, "NFS: Server address does not match proto= option");
out_minorversion_mismatch: return nfs_invalf(fc, "NFS: Mount option vers=%u does not support minorversion=%u",
ctx->version, ctx->minorversion);
out_migration_misuse: return nfs_invalf(fc, "NFS: 'Migration' not supported for this NFS version");
out_version_unavailable:
nfs_errorf(fc, "NFS: Version unavailable"); return ret;
}
/* * Create an NFS superblock by the appropriate method.
*/ staticint nfs_get_tree(struct fs_context *fc)
{ struct nfs_fs_context *ctx = nfs_fc2context(fc); int err = nfs_fs_context_validate(fc);
if (err) return err; if (!ctx->internal) return ctx->nfs_mod->rpc_ops->try_get_tree(fc); else return nfs_get_tree_common(fc);
}
/* * Handle duplication of a configuration. The caller copied *src into *sc, but * it can't deal with resource pointers in the filesystem context, so we have * to do that. We need to clear pointers, copy data or get extra refs as * appropriate.
*/ staticint nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
{ struct nfs_fs_context *src = nfs_fc2context(src_fc), *ctx;
ctx = kmemdup(src, sizeof(struct nfs_fs_context), GFP_KERNEL); if (!ctx) return -ENOMEM;
/* * Prepare superblock configuration. We use the namespaces attached to the * context. This may be the current process's namespaces, or it may be a * container's namespaces.
*/ staticint nfs_init_fs_context(struct fs_context *fc)
{ struct nfs_fs_context *ctx;
ctx = kzalloc(sizeof(struct nfs_fs_context), GFP_KERNEL); if (unlikely(!ctx)) return -ENOMEM;
ctx->mntfh = nfs_alloc_fhandle(); if (unlikely(!ctx->mntfh)) {
kfree(ctx); return -ENOMEM;
}
if (fc->root) { /* reconfigure, start with the current config */ struct nfs_server *nfss = fc->root->d_sb->s_fs_info; struct net *net = nfss->nfs_client->cl_net;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.