/* *SanitychecktheNFStransportprotocol.
*/ 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;
}
return0;
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");
}
/* *FortextbasedNFSv2/v3mounts,themountprotocoltransportdefault *settingsshoulddependuponthespecifiedNFStransport.
*/ 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;
}
}
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;
/* *booleanoptions: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;
/* *optionsthattakenumericvalues
*/ 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;
/* *optionsthattaketextvalues
*/ 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;
/* *Specialoptions
*/ case Opt_sloppy:
ctx->sloppy = true; break;
}
return0;
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");
}
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;
/* *forproto==XPRT_TRANSPORT_UDP,whichiswhatuses *to_exponential,implyingshift:limittheshiftvalue *toBITS_PER_LONG(majortimeoisunsignedlong)
*/ 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;
out_no_data: if (is_remount_fc(fc)) {
ctx->skip_reconfig_option_check = true; return0;
} 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");
/* Verify that any proto=/mountproto= options match the address *familiesintheaddr=/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;
} return0;
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;
}
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.