162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/nfs/fs_context.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1992 Rick Sladkey 662306a36Sopenharmony_ci * Conversion to new mount api Copyright (C) David Howells 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * NFS mount handling. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Split from fs/nfs/super.c by David Howells <dhowells@redhat.com> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/compat.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/fs.h> 1662306a36Sopenharmony_ci#include <linux/fs_context.h> 1762306a36Sopenharmony_ci#include <linux/fs_parser.h> 1862306a36Sopenharmony_ci#include <linux/nfs_fs.h> 1962306a36Sopenharmony_ci#include <linux/nfs_mount.h> 2062306a36Sopenharmony_ci#include <linux/nfs4_mount.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <net/handshake.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "nfs.h" 2562306a36Sopenharmony_ci#include "internal.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "nfstrace.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_MOUNT 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NFS_V3) 3262306a36Sopenharmony_ci#define NFS_DEFAULT_VERSION 3 3362306a36Sopenharmony_ci#else 3462306a36Sopenharmony_ci#define NFS_DEFAULT_VERSION 2 3562306a36Sopenharmony_ci#endif 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define NFS_MAX_CONNECTIONS 16 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cienum nfs_param { 4062306a36Sopenharmony_ci Opt_ac, 4162306a36Sopenharmony_ci Opt_acdirmax, 4262306a36Sopenharmony_ci Opt_acdirmin, 4362306a36Sopenharmony_ci Opt_acl, 4462306a36Sopenharmony_ci Opt_acregmax, 4562306a36Sopenharmony_ci Opt_acregmin, 4662306a36Sopenharmony_ci Opt_actimeo, 4762306a36Sopenharmony_ci Opt_addr, 4862306a36Sopenharmony_ci Opt_bg, 4962306a36Sopenharmony_ci Opt_bsize, 5062306a36Sopenharmony_ci Opt_clientaddr, 5162306a36Sopenharmony_ci Opt_cto, 5262306a36Sopenharmony_ci Opt_fg, 5362306a36Sopenharmony_ci Opt_fscache, 5462306a36Sopenharmony_ci Opt_fscache_flag, 5562306a36Sopenharmony_ci Opt_hard, 5662306a36Sopenharmony_ci Opt_intr, 5762306a36Sopenharmony_ci Opt_local_lock, 5862306a36Sopenharmony_ci Opt_lock, 5962306a36Sopenharmony_ci Opt_lookupcache, 6062306a36Sopenharmony_ci Opt_migration, 6162306a36Sopenharmony_ci Opt_minorversion, 6262306a36Sopenharmony_ci Opt_mountaddr, 6362306a36Sopenharmony_ci Opt_mounthost, 6462306a36Sopenharmony_ci Opt_mountport, 6562306a36Sopenharmony_ci Opt_mountproto, 6662306a36Sopenharmony_ci Opt_mountvers, 6762306a36Sopenharmony_ci Opt_namelen, 6862306a36Sopenharmony_ci Opt_nconnect, 6962306a36Sopenharmony_ci Opt_max_connect, 7062306a36Sopenharmony_ci Opt_port, 7162306a36Sopenharmony_ci Opt_posix, 7262306a36Sopenharmony_ci Opt_proto, 7362306a36Sopenharmony_ci Opt_rdirplus, 7462306a36Sopenharmony_ci Opt_rdma, 7562306a36Sopenharmony_ci Opt_resvport, 7662306a36Sopenharmony_ci Opt_retrans, 7762306a36Sopenharmony_ci Opt_retry, 7862306a36Sopenharmony_ci Opt_rsize, 7962306a36Sopenharmony_ci Opt_sec, 8062306a36Sopenharmony_ci Opt_sharecache, 8162306a36Sopenharmony_ci Opt_sloppy, 8262306a36Sopenharmony_ci Opt_soft, 8362306a36Sopenharmony_ci Opt_softerr, 8462306a36Sopenharmony_ci Opt_softreval, 8562306a36Sopenharmony_ci Opt_source, 8662306a36Sopenharmony_ci Opt_tcp, 8762306a36Sopenharmony_ci Opt_timeo, 8862306a36Sopenharmony_ci Opt_trunkdiscovery, 8962306a36Sopenharmony_ci Opt_udp, 9062306a36Sopenharmony_ci Opt_v, 9162306a36Sopenharmony_ci Opt_vers, 9262306a36Sopenharmony_ci Opt_wsize, 9362306a36Sopenharmony_ci Opt_write, 9462306a36Sopenharmony_ci Opt_xprtsec, 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cienum { 9862306a36Sopenharmony_ci Opt_local_lock_all, 9962306a36Sopenharmony_ci Opt_local_lock_flock, 10062306a36Sopenharmony_ci Opt_local_lock_none, 10162306a36Sopenharmony_ci Opt_local_lock_posix, 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic const struct constant_table nfs_param_enums_local_lock[] = { 10562306a36Sopenharmony_ci { "all", Opt_local_lock_all }, 10662306a36Sopenharmony_ci { "flock", Opt_local_lock_flock }, 10762306a36Sopenharmony_ci { "posix", Opt_local_lock_posix }, 10862306a36Sopenharmony_ci { "none", Opt_local_lock_none }, 10962306a36Sopenharmony_ci {} 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cienum { 11362306a36Sopenharmony_ci Opt_lookupcache_all, 11462306a36Sopenharmony_ci Opt_lookupcache_none, 11562306a36Sopenharmony_ci Opt_lookupcache_positive, 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic const struct constant_table nfs_param_enums_lookupcache[] = { 11962306a36Sopenharmony_ci { "all", Opt_lookupcache_all }, 12062306a36Sopenharmony_ci { "none", Opt_lookupcache_none }, 12162306a36Sopenharmony_ci { "pos", Opt_lookupcache_positive }, 12262306a36Sopenharmony_ci { "positive", Opt_lookupcache_positive }, 12362306a36Sopenharmony_ci {} 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cienum { 12762306a36Sopenharmony_ci Opt_write_lazy, 12862306a36Sopenharmony_ci Opt_write_eager, 12962306a36Sopenharmony_ci Opt_write_wait, 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic const struct constant_table nfs_param_enums_write[] = { 13362306a36Sopenharmony_ci { "lazy", Opt_write_lazy }, 13462306a36Sopenharmony_ci { "eager", Opt_write_eager }, 13562306a36Sopenharmony_ci { "wait", Opt_write_wait }, 13662306a36Sopenharmony_ci {} 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic const struct fs_parameter_spec nfs_fs_parameters[] = { 14062306a36Sopenharmony_ci fsparam_flag_no("ac", Opt_ac), 14162306a36Sopenharmony_ci fsparam_u32 ("acdirmax", Opt_acdirmax), 14262306a36Sopenharmony_ci fsparam_u32 ("acdirmin", Opt_acdirmin), 14362306a36Sopenharmony_ci fsparam_flag_no("acl", Opt_acl), 14462306a36Sopenharmony_ci fsparam_u32 ("acregmax", Opt_acregmax), 14562306a36Sopenharmony_ci fsparam_u32 ("acregmin", Opt_acregmin), 14662306a36Sopenharmony_ci fsparam_u32 ("actimeo", Opt_actimeo), 14762306a36Sopenharmony_ci fsparam_string("addr", Opt_addr), 14862306a36Sopenharmony_ci fsparam_flag ("bg", Opt_bg), 14962306a36Sopenharmony_ci fsparam_u32 ("bsize", Opt_bsize), 15062306a36Sopenharmony_ci fsparam_string("clientaddr", Opt_clientaddr), 15162306a36Sopenharmony_ci fsparam_flag_no("cto", Opt_cto), 15262306a36Sopenharmony_ci fsparam_flag ("fg", Opt_fg), 15362306a36Sopenharmony_ci fsparam_flag_no("fsc", Opt_fscache_flag), 15462306a36Sopenharmony_ci fsparam_string("fsc", Opt_fscache), 15562306a36Sopenharmony_ci fsparam_flag ("hard", Opt_hard), 15662306a36Sopenharmony_ci __fsparam(NULL, "intr", Opt_intr, 15762306a36Sopenharmony_ci fs_param_neg_with_no|fs_param_deprecated, NULL), 15862306a36Sopenharmony_ci fsparam_enum ("local_lock", Opt_local_lock, nfs_param_enums_local_lock), 15962306a36Sopenharmony_ci fsparam_flag_no("lock", Opt_lock), 16062306a36Sopenharmony_ci fsparam_enum ("lookupcache", Opt_lookupcache, nfs_param_enums_lookupcache), 16162306a36Sopenharmony_ci fsparam_flag_no("migration", Opt_migration), 16262306a36Sopenharmony_ci fsparam_u32 ("minorversion", Opt_minorversion), 16362306a36Sopenharmony_ci fsparam_string("mountaddr", Opt_mountaddr), 16462306a36Sopenharmony_ci fsparam_string("mounthost", Opt_mounthost), 16562306a36Sopenharmony_ci fsparam_u32 ("mountport", Opt_mountport), 16662306a36Sopenharmony_ci fsparam_string("mountproto", Opt_mountproto), 16762306a36Sopenharmony_ci fsparam_u32 ("mountvers", Opt_mountvers), 16862306a36Sopenharmony_ci fsparam_u32 ("namlen", Opt_namelen), 16962306a36Sopenharmony_ci fsparam_u32 ("nconnect", Opt_nconnect), 17062306a36Sopenharmony_ci fsparam_u32 ("max_connect", Opt_max_connect), 17162306a36Sopenharmony_ci fsparam_string("nfsvers", Opt_vers), 17262306a36Sopenharmony_ci fsparam_u32 ("port", Opt_port), 17362306a36Sopenharmony_ci fsparam_flag_no("posix", Opt_posix), 17462306a36Sopenharmony_ci fsparam_string("proto", Opt_proto), 17562306a36Sopenharmony_ci fsparam_flag_no("rdirplus", Opt_rdirplus), 17662306a36Sopenharmony_ci fsparam_flag ("rdma", Opt_rdma), 17762306a36Sopenharmony_ci fsparam_flag_no("resvport", Opt_resvport), 17862306a36Sopenharmony_ci fsparam_u32 ("retrans", Opt_retrans), 17962306a36Sopenharmony_ci fsparam_string("retry", Opt_retry), 18062306a36Sopenharmony_ci fsparam_u32 ("rsize", Opt_rsize), 18162306a36Sopenharmony_ci fsparam_string("sec", Opt_sec), 18262306a36Sopenharmony_ci fsparam_flag_no("sharecache", Opt_sharecache), 18362306a36Sopenharmony_ci fsparam_flag ("sloppy", Opt_sloppy), 18462306a36Sopenharmony_ci fsparam_flag ("soft", Opt_soft), 18562306a36Sopenharmony_ci fsparam_flag ("softerr", Opt_softerr), 18662306a36Sopenharmony_ci fsparam_flag ("softreval", Opt_softreval), 18762306a36Sopenharmony_ci fsparam_string("source", Opt_source), 18862306a36Sopenharmony_ci fsparam_flag ("tcp", Opt_tcp), 18962306a36Sopenharmony_ci fsparam_u32 ("timeo", Opt_timeo), 19062306a36Sopenharmony_ci fsparam_flag_no("trunkdiscovery", Opt_trunkdiscovery), 19162306a36Sopenharmony_ci fsparam_flag ("udp", Opt_udp), 19262306a36Sopenharmony_ci fsparam_flag ("v2", Opt_v), 19362306a36Sopenharmony_ci fsparam_flag ("v3", Opt_v), 19462306a36Sopenharmony_ci fsparam_flag ("v4", Opt_v), 19562306a36Sopenharmony_ci fsparam_flag ("v4.0", Opt_v), 19662306a36Sopenharmony_ci fsparam_flag ("v4.1", Opt_v), 19762306a36Sopenharmony_ci fsparam_flag ("v4.2", Opt_v), 19862306a36Sopenharmony_ci fsparam_string("vers", Opt_vers), 19962306a36Sopenharmony_ci fsparam_enum ("write", Opt_write, nfs_param_enums_write), 20062306a36Sopenharmony_ci fsparam_u32 ("wsize", Opt_wsize), 20162306a36Sopenharmony_ci fsparam_string("xprtsec", Opt_xprtsec), 20262306a36Sopenharmony_ci {} 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cienum { 20662306a36Sopenharmony_ci Opt_vers_2, 20762306a36Sopenharmony_ci Opt_vers_3, 20862306a36Sopenharmony_ci Opt_vers_4, 20962306a36Sopenharmony_ci Opt_vers_4_0, 21062306a36Sopenharmony_ci Opt_vers_4_1, 21162306a36Sopenharmony_ci Opt_vers_4_2, 21262306a36Sopenharmony_ci}; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic const struct constant_table nfs_vers_tokens[] = { 21562306a36Sopenharmony_ci { "2", Opt_vers_2 }, 21662306a36Sopenharmony_ci { "3", Opt_vers_3 }, 21762306a36Sopenharmony_ci { "4", Opt_vers_4 }, 21862306a36Sopenharmony_ci { "4.0", Opt_vers_4_0 }, 21962306a36Sopenharmony_ci { "4.1", Opt_vers_4_1 }, 22062306a36Sopenharmony_ci { "4.2", Opt_vers_4_2 }, 22162306a36Sopenharmony_ci {} 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cienum { 22562306a36Sopenharmony_ci Opt_xprt_rdma, 22662306a36Sopenharmony_ci Opt_xprt_rdma6, 22762306a36Sopenharmony_ci Opt_xprt_tcp, 22862306a36Sopenharmony_ci Opt_xprt_tcp6, 22962306a36Sopenharmony_ci Opt_xprt_udp, 23062306a36Sopenharmony_ci Opt_xprt_udp6, 23162306a36Sopenharmony_ci nr__Opt_xprt 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic const struct constant_table nfs_xprt_protocol_tokens[] = { 23562306a36Sopenharmony_ci { "rdma", Opt_xprt_rdma }, 23662306a36Sopenharmony_ci { "rdma6", Opt_xprt_rdma6 }, 23762306a36Sopenharmony_ci { "tcp", Opt_xprt_tcp }, 23862306a36Sopenharmony_ci { "tcp6", Opt_xprt_tcp6 }, 23962306a36Sopenharmony_ci { "udp", Opt_xprt_udp }, 24062306a36Sopenharmony_ci { "udp6", Opt_xprt_udp6 }, 24162306a36Sopenharmony_ci {} 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cienum { 24562306a36Sopenharmony_ci Opt_sec_krb5, 24662306a36Sopenharmony_ci Opt_sec_krb5i, 24762306a36Sopenharmony_ci Opt_sec_krb5p, 24862306a36Sopenharmony_ci Opt_sec_lkey, 24962306a36Sopenharmony_ci Opt_sec_lkeyi, 25062306a36Sopenharmony_ci Opt_sec_lkeyp, 25162306a36Sopenharmony_ci Opt_sec_none, 25262306a36Sopenharmony_ci Opt_sec_spkm, 25362306a36Sopenharmony_ci Opt_sec_spkmi, 25462306a36Sopenharmony_ci Opt_sec_spkmp, 25562306a36Sopenharmony_ci Opt_sec_sys, 25662306a36Sopenharmony_ci nr__Opt_sec 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic const struct constant_table nfs_secflavor_tokens[] = { 26062306a36Sopenharmony_ci { "krb5", Opt_sec_krb5 }, 26162306a36Sopenharmony_ci { "krb5i", Opt_sec_krb5i }, 26262306a36Sopenharmony_ci { "krb5p", Opt_sec_krb5p }, 26362306a36Sopenharmony_ci { "lkey", Opt_sec_lkey }, 26462306a36Sopenharmony_ci { "lkeyi", Opt_sec_lkeyi }, 26562306a36Sopenharmony_ci { "lkeyp", Opt_sec_lkeyp }, 26662306a36Sopenharmony_ci { "none", Opt_sec_none }, 26762306a36Sopenharmony_ci { "null", Opt_sec_none }, 26862306a36Sopenharmony_ci { "spkm3", Opt_sec_spkm }, 26962306a36Sopenharmony_ci { "spkm3i", Opt_sec_spkmi }, 27062306a36Sopenharmony_ci { "spkm3p", Opt_sec_spkmp }, 27162306a36Sopenharmony_ci { "sys", Opt_sec_sys }, 27262306a36Sopenharmony_ci {} 27362306a36Sopenharmony_ci}; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cienum { 27662306a36Sopenharmony_ci Opt_xprtsec_none, 27762306a36Sopenharmony_ci Opt_xprtsec_tls, 27862306a36Sopenharmony_ci Opt_xprtsec_mtls, 27962306a36Sopenharmony_ci nr__Opt_xprtsec 28062306a36Sopenharmony_ci}; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic const struct constant_table nfs_xprtsec_policies[] = { 28362306a36Sopenharmony_ci { "none", Opt_xprtsec_none }, 28462306a36Sopenharmony_ci { "tls", Opt_xprtsec_tls }, 28562306a36Sopenharmony_ci { "mtls", Opt_xprtsec_mtls }, 28662306a36Sopenharmony_ci {} 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* 29062306a36Sopenharmony_ci * Sanity-check a server address provided by the mount command. 29162306a36Sopenharmony_ci * 29262306a36Sopenharmony_ci * Address family must be initialized, and address must not be 29362306a36Sopenharmony_ci * the ANY address for that family. 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_cistatic int nfs_verify_server_address(struct sockaddr_storage *addr) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci switch (addr->ss_family) { 29862306a36Sopenharmony_ci case AF_INET: { 29962306a36Sopenharmony_ci struct sockaddr_in *sa = (struct sockaddr_in *)addr; 30062306a36Sopenharmony_ci return sa->sin_addr.s_addr != htonl(INADDR_ANY); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci case AF_INET6: { 30362306a36Sopenharmony_ci struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr; 30462306a36Sopenharmony_ci return !ipv6_addr_any(sa); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci#ifdef CONFIG_NFS_DISABLE_UDP_SUPPORT 31262306a36Sopenharmony_cistatic bool nfs_server_transport_udp_invalid(const struct nfs_fs_context *ctx) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci return true; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci#else 31762306a36Sopenharmony_cistatic bool nfs_server_transport_udp_invalid(const struct nfs_fs_context *ctx) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci if (ctx->version == 4) 32062306a36Sopenharmony_ci return true; 32162306a36Sopenharmony_ci return false; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci#endif 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/* 32662306a36Sopenharmony_ci * Sanity check the NFS transport protocol. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_cistatic int nfs_validate_transport_protocol(struct fs_context *fc, 32962306a36Sopenharmony_ci struct nfs_fs_context *ctx) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci switch (ctx->nfs_server.protocol) { 33262306a36Sopenharmony_ci case XPRT_TRANSPORT_UDP: 33362306a36Sopenharmony_ci if (nfs_server_transport_udp_invalid(ctx)) 33462306a36Sopenharmony_ci goto out_invalid_transport_udp; 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci case XPRT_TRANSPORT_TCP: 33762306a36Sopenharmony_ci case XPRT_TRANSPORT_RDMA: 33862306a36Sopenharmony_ci break; 33962306a36Sopenharmony_ci default: 34062306a36Sopenharmony_ci ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (ctx->xprtsec.policy != RPC_XPRTSEC_NONE) 34462306a36Sopenharmony_ci switch (ctx->nfs_server.protocol) { 34562306a36Sopenharmony_ci case XPRT_TRANSPORT_TCP: 34662306a36Sopenharmony_ci ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP_TLS; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci default: 34962306a36Sopenharmony_ci goto out_invalid_xprtsec_policy; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return 0; 35362306a36Sopenharmony_ciout_invalid_transport_udp: 35462306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Unsupported transport protocol udp"); 35562306a36Sopenharmony_ciout_invalid_xprtsec_policy: 35662306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Transport does not support xprtsec"); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci/* 36062306a36Sopenharmony_ci * For text based NFSv2/v3 mounts, the mount protocol transport default 36162306a36Sopenharmony_ci * settings should depend upon the specified NFS transport. 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_cistatic void nfs_set_mount_transport_protocol(struct nfs_fs_context *ctx) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci if (ctx->mount_server.protocol == XPRT_TRANSPORT_UDP || 36662306a36Sopenharmony_ci ctx->mount_server.protocol == XPRT_TRANSPORT_TCP) 36762306a36Sopenharmony_ci return; 36862306a36Sopenharmony_ci switch (ctx->nfs_server.protocol) { 36962306a36Sopenharmony_ci case XPRT_TRANSPORT_UDP: 37062306a36Sopenharmony_ci ctx->mount_server.protocol = XPRT_TRANSPORT_UDP; 37162306a36Sopenharmony_ci break; 37262306a36Sopenharmony_ci case XPRT_TRANSPORT_TCP: 37362306a36Sopenharmony_ci case XPRT_TRANSPORT_RDMA: 37462306a36Sopenharmony_ci ctx->mount_server.protocol = XPRT_TRANSPORT_TCP; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/* 37962306a36Sopenharmony_ci * Add 'flavor' to 'auth_info' if not already present. 38062306a36Sopenharmony_ci * Returns true if 'flavor' ends up in the list, false otherwise 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_cistatic int nfs_auth_info_add(struct fs_context *fc, 38362306a36Sopenharmony_ci struct nfs_auth_info *auth_info, 38462306a36Sopenharmony_ci rpc_authflavor_t flavor) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci unsigned int i; 38762306a36Sopenharmony_ci unsigned int max_flavor_len = ARRAY_SIZE(auth_info->flavors); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* make sure this flavor isn't already in the list */ 39062306a36Sopenharmony_ci for (i = 0; i < auth_info->flavor_len; i++) { 39162306a36Sopenharmony_ci if (flavor == auth_info->flavors[i]) 39262306a36Sopenharmony_ci return 0; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (auth_info->flavor_len + 1 >= max_flavor_len) 39662306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: too many sec= flavors"); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci auth_info->flavors[auth_info->flavor_len++] = flavor; 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/* 40362306a36Sopenharmony_ci * Parse the value of the 'sec=' option. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_cistatic int nfs_parse_security_flavors(struct fs_context *fc, 40662306a36Sopenharmony_ci struct fs_parameter *param) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 40962306a36Sopenharmony_ci rpc_authflavor_t pseudoflavor; 41062306a36Sopenharmony_ci char *string = param->string, *p; 41162306a36Sopenharmony_ci int ret; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, string); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci while ((p = strsep(&string, ":")) != NULL) { 41662306a36Sopenharmony_ci if (!*p) 41762306a36Sopenharmony_ci continue; 41862306a36Sopenharmony_ci switch (lookup_constant(nfs_secflavor_tokens, p, -1)) { 41962306a36Sopenharmony_ci case Opt_sec_none: 42062306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_NULL; 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci case Opt_sec_sys: 42362306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_UNIX; 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci case Opt_sec_krb5: 42662306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_GSS_KRB5; 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci case Opt_sec_krb5i: 42962306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_GSS_KRB5I; 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci case Opt_sec_krb5p: 43262306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_GSS_KRB5P; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case Opt_sec_lkey: 43562306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_GSS_LKEY; 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci case Opt_sec_lkeyi: 43862306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_GSS_LKEYI; 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci case Opt_sec_lkeyp: 44162306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_GSS_LKEYP; 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci case Opt_sec_spkm: 44462306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_GSS_SPKM; 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci case Opt_sec_spkmi: 44762306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_GSS_SPKMI; 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case Opt_sec_spkmp: 45062306a36Sopenharmony_ci pseudoflavor = RPC_AUTH_GSS_SPKMP; 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci default: 45362306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: sec=%s option not recognized", p); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci ret = nfs_auth_info_add(fc, &ctx->auth_info, pseudoflavor); 45762306a36Sopenharmony_ci if (ret < 0) 45862306a36Sopenharmony_ci return ret; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int nfs_parse_xprtsec_policy(struct fs_context *fc, 46562306a36Sopenharmony_ci struct fs_parameter *param) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci switch (lookup_constant(nfs_xprtsec_policies, param->string, -1)) { 47262306a36Sopenharmony_ci case Opt_xprtsec_none: 47362306a36Sopenharmony_ci ctx->xprtsec.policy = RPC_XPRTSEC_NONE; 47462306a36Sopenharmony_ci break; 47562306a36Sopenharmony_ci case Opt_xprtsec_tls: 47662306a36Sopenharmony_ci ctx->xprtsec.policy = RPC_XPRTSEC_TLS_ANON; 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci case Opt_xprtsec_mtls: 47962306a36Sopenharmony_ci ctx->xprtsec.policy = RPC_XPRTSEC_TLS_X509; 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci default: 48262306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Unrecognized transport security policy"); 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int nfs_parse_version_string(struct fs_context *fc, 48862306a36Sopenharmony_ci const char *string) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_VER3; 49362306a36Sopenharmony_ci switch (lookup_constant(nfs_vers_tokens, string, -1)) { 49462306a36Sopenharmony_ci case Opt_vers_2: 49562306a36Sopenharmony_ci ctx->version = 2; 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci case Opt_vers_3: 49862306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_VER3; 49962306a36Sopenharmony_ci ctx->version = 3; 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci case Opt_vers_4: 50262306a36Sopenharmony_ci /* Backward compatibility option. In future, 50362306a36Sopenharmony_ci * the mount program should always supply 50462306a36Sopenharmony_ci * a NFSv4 minor version number. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ci ctx->version = 4; 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci case Opt_vers_4_0: 50962306a36Sopenharmony_ci ctx->version = 4; 51062306a36Sopenharmony_ci ctx->minorversion = 0; 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci case Opt_vers_4_1: 51362306a36Sopenharmony_ci ctx->version = 4; 51462306a36Sopenharmony_ci ctx->minorversion = 1; 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci case Opt_vers_4_2: 51762306a36Sopenharmony_ci ctx->version = 4; 51862306a36Sopenharmony_ci ctx->minorversion = 2; 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci default: 52162306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Unsupported NFS version"); 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci/* 52762306a36Sopenharmony_ci * Parse a single mount parameter. 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_cistatic int nfs_fs_context_parse_param(struct fs_context *fc, 53062306a36Sopenharmony_ci struct fs_parameter *param) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct fs_parse_result result; 53362306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 53462306a36Sopenharmony_ci unsigned short protofamily, mountfamily; 53562306a36Sopenharmony_ci unsigned int len; 53662306a36Sopenharmony_ci int ret, opt; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci trace_nfs_mount_option(param); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci opt = fs_parse(fc, nfs_fs_parameters, param, &result); 54162306a36Sopenharmony_ci if (opt < 0) 54262306a36Sopenharmony_ci return (opt == -ENOPARAM && ctx->sloppy) ? 1 : opt; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (fc->security) 54562306a36Sopenharmony_ci ctx->has_sec_mnt_opts = 1; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci switch (opt) { 54862306a36Sopenharmony_ci case Opt_source: 54962306a36Sopenharmony_ci if (fc->source) 55062306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Multiple sources not supported"); 55162306a36Sopenharmony_ci fc->source = param->string; 55262306a36Sopenharmony_ci param->string = NULL; 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* 55662306a36Sopenharmony_ci * boolean options: foo/nofoo 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ci case Opt_soft: 55962306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_SOFT; 56062306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_SOFTERR; 56162306a36Sopenharmony_ci break; 56262306a36Sopenharmony_ci case Opt_softerr: 56362306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_SOFTERR | NFS_MOUNT_SOFTREVAL; 56462306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_SOFT; 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci case Opt_hard: 56762306a36Sopenharmony_ci ctx->flags &= ~(NFS_MOUNT_SOFT | 56862306a36Sopenharmony_ci NFS_MOUNT_SOFTERR | 56962306a36Sopenharmony_ci NFS_MOUNT_SOFTREVAL); 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci case Opt_softreval: 57262306a36Sopenharmony_ci if (result.negated) 57362306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_SOFTREVAL; 57462306a36Sopenharmony_ci else 57562306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_SOFTREVAL; 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci case Opt_posix: 57862306a36Sopenharmony_ci if (result.negated) 57962306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_POSIX; 58062306a36Sopenharmony_ci else 58162306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_POSIX; 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci case Opt_cto: 58462306a36Sopenharmony_ci if (result.negated) 58562306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_NOCTO; 58662306a36Sopenharmony_ci else 58762306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_NOCTO; 58862306a36Sopenharmony_ci break; 58962306a36Sopenharmony_ci case Opt_trunkdiscovery: 59062306a36Sopenharmony_ci if (result.negated) 59162306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_TRUNK_DISCOVERY; 59262306a36Sopenharmony_ci else 59362306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_TRUNK_DISCOVERY; 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci case Opt_ac: 59662306a36Sopenharmony_ci if (result.negated) 59762306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_NOAC; 59862306a36Sopenharmony_ci else 59962306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_NOAC; 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci case Opt_lock: 60262306a36Sopenharmony_ci if (result.negated) { 60362306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_NONLM; 60462306a36Sopenharmony_ci ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL); 60562306a36Sopenharmony_ci } else { 60662306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_NONLM; 60762306a36Sopenharmony_ci ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL); 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci case Opt_udp: 61162306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_TCP; 61262306a36Sopenharmony_ci ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci case Opt_tcp: 61562306a36Sopenharmony_ci case Opt_rdma: 61662306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */ 61762306a36Sopenharmony_ci ret = xprt_find_transport_ident(param->key); 61862306a36Sopenharmony_ci if (ret < 0) 61962306a36Sopenharmony_ci goto out_bad_transport; 62062306a36Sopenharmony_ci ctx->nfs_server.protocol = ret; 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci case Opt_acl: 62362306a36Sopenharmony_ci if (result.negated) 62462306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_NOACL; 62562306a36Sopenharmony_ci else 62662306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_NOACL; 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci case Opt_rdirplus: 62962306a36Sopenharmony_ci if (result.negated) 63062306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_NORDIRPLUS; 63162306a36Sopenharmony_ci else 63262306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_NORDIRPLUS; 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci case Opt_sharecache: 63562306a36Sopenharmony_ci if (result.negated) 63662306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_UNSHARED; 63762306a36Sopenharmony_ci else 63862306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_UNSHARED; 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci case Opt_resvport: 64162306a36Sopenharmony_ci if (result.negated) 64262306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_NORESVPORT; 64362306a36Sopenharmony_ci else 64462306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_NORESVPORT; 64562306a36Sopenharmony_ci break; 64662306a36Sopenharmony_ci case Opt_fscache_flag: 64762306a36Sopenharmony_ci if (result.negated) 64862306a36Sopenharmony_ci ctx->options &= ~NFS_OPTION_FSCACHE; 64962306a36Sopenharmony_ci else 65062306a36Sopenharmony_ci ctx->options |= NFS_OPTION_FSCACHE; 65162306a36Sopenharmony_ci kfree(ctx->fscache_uniq); 65262306a36Sopenharmony_ci ctx->fscache_uniq = NULL; 65362306a36Sopenharmony_ci break; 65462306a36Sopenharmony_ci case Opt_fscache: 65562306a36Sopenharmony_ci ctx->options |= NFS_OPTION_FSCACHE; 65662306a36Sopenharmony_ci kfree(ctx->fscache_uniq); 65762306a36Sopenharmony_ci ctx->fscache_uniq = param->string; 65862306a36Sopenharmony_ci param->string = NULL; 65962306a36Sopenharmony_ci break; 66062306a36Sopenharmony_ci case Opt_migration: 66162306a36Sopenharmony_ci if (result.negated) 66262306a36Sopenharmony_ci ctx->options &= ~NFS_OPTION_MIGRATION; 66362306a36Sopenharmony_ci else 66462306a36Sopenharmony_ci ctx->options |= NFS_OPTION_MIGRATION; 66562306a36Sopenharmony_ci break; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * options that take numeric values 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci case Opt_port: 67162306a36Sopenharmony_ci if (result.uint_32 > USHRT_MAX) 67262306a36Sopenharmony_ci goto out_of_bounds; 67362306a36Sopenharmony_ci ctx->nfs_server.port = result.uint_32; 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci case Opt_rsize: 67662306a36Sopenharmony_ci ctx->rsize = result.uint_32; 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci case Opt_wsize: 67962306a36Sopenharmony_ci ctx->wsize = result.uint_32; 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci case Opt_bsize: 68262306a36Sopenharmony_ci ctx->bsize = result.uint_32; 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci case Opt_timeo: 68562306a36Sopenharmony_ci if (result.uint_32 < 1 || result.uint_32 > INT_MAX) 68662306a36Sopenharmony_ci goto out_of_bounds; 68762306a36Sopenharmony_ci ctx->timeo = result.uint_32; 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci case Opt_retrans: 69062306a36Sopenharmony_ci if (result.uint_32 > INT_MAX) 69162306a36Sopenharmony_ci goto out_of_bounds; 69262306a36Sopenharmony_ci ctx->retrans = result.uint_32; 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci case Opt_acregmin: 69562306a36Sopenharmony_ci ctx->acregmin = result.uint_32; 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci case Opt_acregmax: 69862306a36Sopenharmony_ci ctx->acregmax = result.uint_32; 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci case Opt_acdirmin: 70162306a36Sopenharmony_ci ctx->acdirmin = result.uint_32; 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci case Opt_acdirmax: 70462306a36Sopenharmony_ci ctx->acdirmax = result.uint_32; 70562306a36Sopenharmony_ci break; 70662306a36Sopenharmony_ci case Opt_actimeo: 70762306a36Sopenharmony_ci ctx->acregmin = result.uint_32; 70862306a36Sopenharmony_ci ctx->acregmax = result.uint_32; 70962306a36Sopenharmony_ci ctx->acdirmin = result.uint_32; 71062306a36Sopenharmony_ci ctx->acdirmax = result.uint_32; 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci case Opt_namelen: 71362306a36Sopenharmony_ci ctx->namlen = result.uint_32; 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci case Opt_mountport: 71662306a36Sopenharmony_ci if (result.uint_32 > USHRT_MAX) 71762306a36Sopenharmony_ci goto out_of_bounds; 71862306a36Sopenharmony_ci ctx->mount_server.port = result.uint_32; 71962306a36Sopenharmony_ci break; 72062306a36Sopenharmony_ci case Opt_mountvers: 72162306a36Sopenharmony_ci if (result.uint_32 < NFS_MNT_VERSION || 72262306a36Sopenharmony_ci result.uint_32 > NFS_MNT3_VERSION) 72362306a36Sopenharmony_ci goto out_of_bounds; 72462306a36Sopenharmony_ci ctx->mount_server.version = result.uint_32; 72562306a36Sopenharmony_ci break; 72662306a36Sopenharmony_ci case Opt_minorversion: 72762306a36Sopenharmony_ci if (result.uint_32 > NFS4_MAX_MINOR_VERSION) 72862306a36Sopenharmony_ci goto out_of_bounds; 72962306a36Sopenharmony_ci ctx->minorversion = result.uint_32; 73062306a36Sopenharmony_ci break; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* 73362306a36Sopenharmony_ci * options that take text values 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ci case Opt_v: 73662306a36Sopenharmony_ci ret = nfs_parse_version_string(fc, param->key + 1); 73762306a36Sopenharmony_ci if (ret < 0) 73862306a36Sopenharmony_ci return ret; 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci case Opt_vers: 74162306a36Sopenharmony_ci if (!param->string) 74262306a36Sopenharmony_ci goto out_invalid_value; 74362306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 74462306a36Sopenharmony_ci ret = nfs_parse_version_string(fc, param->string); 74562306a36Sopenharmony_ci if (ret < 0) 74662306a36Sopenharmony_ci return ret; 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci case Opt_sec: 74962306a36Sopenharmony_ci ret = nfs_parse_security_flavors(fc, param); 75062306a36Sopenharmony_ci if (ret < 0) 75162306a36Sopenharmony_ci return ret; 75262306a36Sopenharmony_ci break; 75362306a36Sopenharmony_ci case Opt_xprtsec: 75462306a36Sopenharmony_ci ret = nfs_parse_xprtsec_policy(fc, param); 75562306a36Sopenharmony_ci if (ret < 0) 75662306a36Sopenharmony_ci return ret; 75762306a36Sopenharmony_ci break; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci case Opt_proto: 76062306a36Sopenharmony_ci if (!param->string) 76162306a36Sopenharmony_ci goto out_invalid_value; 76262306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 76362306a36Sopenharmony_ci protofamily = AF_INET; 76462306a36Sopenharmony_ci switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) { 76562306a36Sopenharmony_ci case Opt_xprt_udp6: 76662306a36Sopenharmony_ci protofamily = AF_INET6; 76762306a36Sopenharmony_ci fallthrough; 76862306a36Sopenharmony_ci case Opt_xprt_udp: 76962306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_TCP; 77062306a36Sopenharmony_ci ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci case Opt_xprt_tcp6: 77362306a36Sopenharmony_ci protofamily = AF_INET6; 77462306a36Sopenharmony_ci fallthrough; 77562306a36Sopenharmony_ci case Opt_xprt_tcp: 77662306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_TCP; 77762306a36Sopenharmony_ci ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci case Opt_xprt_rdma6: 78062306a36Sopenharmony_ci protofamily = AF_INET6; 78162306a36Sopenharmony_ci fallthrough; 78262306a36Sopenharmony_ci case Opt_xprt_rdma: 78362306a36Sopenharmony_ci /* vector side protocols to TCP */ 78462306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_TCP; 78562306a36Sopenharmony_ci ret = xprt_find_transport_ident(param->string); 78662306a36Sopenharmony_ci if (ret < 0) 78762306a36Sopenharmony_ci goto out_bad_transport; 78862306a36Sopenharmony_ci ctx->nfs_server.protocol = ret; 78962306a36Sopenharmony_ci break; 79062306a36Sopenharmony_ci default: 79162306a36Sopenharmony_ci goto out_bad_transport; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci ctx->protofamily = protofamily; 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci case Opt_mountproto: 79862306a36Sopenharmony_ci if (!param->string) 79962306a36Sopenharmony_ci goto out_invalid_value; 80062306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 80162306a36Sopenharmony_ci mountfamily = AF_INET; 80262306a36Sopenharmony_ci switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) { 80362306a36Sopenharmony_ci case Opt_xprt_udp6: 80462306a36Sopenharmony_ci mountfamily = AF_INET6; 80562306a36Sopenharmony_ci fallthrough; 80662306a36Sopenharmony_ci case Opt_xprt_udp: 80762306a36Sopenharmony_ci ctx->mount_server.protocol = XPRT_TRANSPORT_UDP; 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci case Opt_xprt_tcp6: 81062306a36Sopenharmony_ci mountfamily = AF_INET6; 81162306a36Sopenharmony_ci fallthrough; 81262306a36Sopenharmony_ci case Opt_xprt_tcp: 81362306a36Sopenharmony_ci ctx->mount_server.protocol = XPRT_TRANSPORT_TCP; 81462306a36Sopenharmony_ci break; 81562306a36Sopenharmony_ci case Opt_xprt_rdma: /* not used for side protocols */ 81662306a36Sopenharmony_ci default: 81762306a36Sopenharmony_ci goto out_bad_transport; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci ctx->mountfamily = mountfamily; 82062306a36Sopenharmony_ci break; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci case Opt_addr: 82362306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 82462306a36Sopenharmony_ci len = rpc_pton(fc->net_ns, param->string, param->size, 82562306a36Sopenharmony_ci &ctx->nfs_server.address, 82662306a36Sopenharmony_ci sizeof(ctx->nfs_server._address)); 82762306a36Sopenharmony_ci if (len == 0) 82862306a36Sopenharmony_ci goto out_invalid_address; 82962306a36Sopenharmony_ci ctx->nfs_server.addrlen = len; 83062306a36Sopenharmony_ci break; 83162306a36Sopenharmony_ci case Opt_clientaddr: 83262306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 83362306a36Sopenharmony_ci kfree(ctx->client_address); 83462306a36Sopenharmony_ci ctx->client_address = param->string; 83562306a36Sopenharmony_ci param->string = NULL; 83662306a36Sopenharmony_ci break; 83762306a36Sopenharmony_ci case Opt_mounthost: 83862306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 83962306a36Sopenharmony_ci kfree(ctx->mount_server.hostname); 84062306a36Sopenharmony_ci ctx->mount_server.hostname = param->string; 84162306a36Sopenharmony_ci param->string = NULL; 84262306a36Sopenharmony_ci break; 84362306a36Sopenharmony_ci case Opt_mountaddr: 84462306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 84562306a36Sopenharmony_ci len = rpc_pton(fc->net_ns, param->string, param->size, 84662306a36Sopenharmony_ci &ctx->mount_server.address, 84762306a36Sopenharmony_ci sizeof(ctx->mount_server._address)); 84862306a36Sopenharmony_ci if (len == 0) 84962306a36Sopenharmony_ci goto out_invalid_address; 85062306a36Sopenharmony_ci ctx->mount_server.addrlen = len; 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci case Opt_nconnect: 85362306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 85462306a36Sopenharmony_ci if (result.uint_32 < 1 || result.uint_32 > NFS_MAX_CONNECTIONS) 85562306a36Sopenharmony_ci goto out_of_bounds; 85662306a36Sopenharmony_ci ctx->nfs_server.nconnect = result.uint_32; 85762306a36Sopenharmony_ci break; 85862306a36Sopenharmony_ci case Opt_max_connect: 85962306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 86062306a36Sopenharmony_ci if (result.uint_32 < 1 || result.uint_32 > NFS_MAX_TRANSPORTS) 86162306a36Sopenharmony_ci goto out_of_bounds; 86262306a36Sopenharmony_ci ctx->nfs_server.max_connect = result.uint_32; 86362306a36Sopenharmony_ci break; 86462306a36Sopenharmony_ci case Opt_lookupcache: 86562306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 86662306a36Sopenharmony_ci switch (result.uint_32) { 86762306a36Sopenharmony_ci case Opt_lookupcache_all: 86862306a36Sopenharmony_ci ctx->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE); 86962306a36Sopenharmony_ci break; 87062306a36Sopenharmony_ci case Opt_lookupcache_positive: 87162306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE; 87262306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG; 87362306a36Sopenharmony_ci break; 87462306a36Sopenharmony_ci case Opt_lookupcache_none: 87562306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; 87662306a36Sopenharmony_ci break; 87762306a36Sopenharmony_ci default: 87862306a36Sopenharmony_ci goto out_invalid_value; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci break; 88162306a36Sopenharmony_ci case Opt_local_lock: 88262306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 88362306a36Sopenharmony_ci switch (result.uint_32) { 88462306a36Sopenharmony_ci case Opt_local_lock_all: 88562306a36Sopenharmony_ci ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | 88662306a36Sopenharmony_ci NFS_MOUNT_LOCAL_FCNTL); 88762306a36Sopenharmony_ci break; 88862306a36Sopenharmony_ci case Opt_local_lock_flock: 88962306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_LOCAL_FLOCK; 89062306a36Sopenharmony_ci break; 89162306a36Sopenharmony_ci case Opt_local_lock_posix: 89262306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_LOCAL_FCNTL; 89362306a36Sopenharmony_ci break; 89462306a36Sopenharmony_ci case Opt_local_lock_none: 89562306a36Sopenharmony_ci ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK | 89662306a36Sopenharmony_ci NFS_MOUNT_LOCAL_FCNTL); 89762306a36Sopenharmony_ci break; 89862306a36Sopenharmony_ci default: 89962306a36Sopenharmony_ci goto out_invalid_value; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci break; 90262306a36Sopenharmony_ci case Opt_write: 90362306a36Sopenharmony_ci trace_nfs_mount_assign(param->key, param->string); 90462306a36Sopenharmony_ci switch (result.uint_32) { 90562306a36Sopenharmony_ci case Opt_write_lazy: 90662306a36Sopenharmony_ci ctx->flags &= 90762306a36Sopenharmony_ci ~(NFS_MOUNT_WRITE_EAGER | NFS_MOUNT_WRITE_WAIT); 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci case Opt_write_eager: 91062306a36Sopenharmony_ci ctx->flags |= NFS_MOUNT_WRITE_EAGER; 91162306a36Sopenharmony_ci ctx->flags &= ~NFS_MOUNT_WRITE_WAIT; 91262306a36Sopenharmony_ci break; 91362306a36Sopenharmony_ci case Opt_write_wait: 91462306a36Sopenharmony_ci ctx->flags |= 91562306a36Sopenharmony_ci NFS_MOUNT_WRITE_EAGER | NFS_MOUNT_WRITE_WAIT; 91662306a36Sopenharmony_ci break; 91762306a36Sopenharmony_ci default: 91862306a36Sopenharmony_ci goto out_invalid_value; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci break; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* 92362306a36Sopenharmony_ci * Special options 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_ci case Opt_sloppy: 92662306a36Sopenharmony_ci ctx->sloppy = true; 92762306a36Sopenharmony_ci break; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci return 0; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ciout_invalid_value: 93362306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Bad mount option value specified"); 93462306a36Sopenharmony_ciout_invalid_address: 93562306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Bad IP address specified"); 93662306a36Sopenharmony_ciout_of_bounds: 93762306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Value for '%s' out of range", param->key); 93862306a36Sopenharmony_ciout_bad_transport: 93962306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Unrecognized transport protocol"); 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci/* 94362306a36Sopenharmony_ci * Split fc->source into "hostname:export_path". 94462306a36Sopenharmony_ci * 94562306a36Sopenharmony_ci * The leftmost colon demarks the split between the server's hostname 94662306a36Sopenharmony_ci * and the export path. If the hostname starts with a left square 94762306a36Sopenharmony_ci * bracket, then it may contain colons. 94862306a36Sopenharmony_ci * 94962306a36Sopenharmony_ci * Note: caller frees hostname and export path, even on error. 95062306a36Sopenharmony_ci */ 95162306a36Sopenharmony_cistatic int nfs_parse_source(struct fs_context *fc, 95262306a36Sopenharmony_ci size_t maxnamlen, size_t maxpathlen) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 95562306a36Sopenharmony_ci const char *dev_name = fc->source; 95662306a36Sopenharmony_ci size_t len; 95762306a36Sopenharmony_ci const char *end; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (unlikely(!dev_name || !*dev_name)) 96062306a36Sopenharmony_ci return -EINVAL; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* Is the host name protected with square brakcets? */ 96362306a36Sopenharmony_ci if (*dev_name == '[') { 96462306a36Sopenharmony_ci end = strchr(++dev_name, ']'); 96562306a36Sopenharmony_ci if (end == NULL || end[1] != ':') 96662306a36Sopenharmony_ci goto out_bad_devname; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci len = end - dev_name; 96962306a36Sopenharmony_ci end++; 97062306a36Sopenharmony_ci } else { 97162306a36Sopenharmony_ci const char *comma; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci end = strchr(dev_name, ':'); 97462306a36Sopenharmony_ci if (end == NULL) 97562306a36Sopenharmony_ci goto out_bad_devname; 97662306a36Sopenharmony_ci len = end - dev_name; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* kill possible hostname list: not supported */ 97962306a36Sopenharmony_ci comma = memchr(dev_name, ',', len); 98062306a36Sopenharmony_ci if (comma) 98162306a36Sopenharmony_ci len = comma - dev_name; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (len > maxnamlen) 98562306a36Sopenharmony_ci goto out_hostname; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci kfree(ctx->nfs_server.hostname); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci /* N.B. caller will free nfs_server.hostname in all cases */ 99062306a36Sopenharmony_ci ctx->nfs_server.hostname = kmemdup_nul(dev_name, len, GFP_KERNEL); 99162306a36Sopenharmony_ci if (!ctx->nfs_server.hostname) 99262306a36Sopenharmony_ci goto out_nomem; 99362306a36Sopenharmony_ci len = strlen(++end); 99462306a36Sopenharmony_ci if (len > maxpathlen) 99562306a36Sopenharmony_ci goto out_path; 99662306a36Sopenharmony_ci ctx->nfs_server.export_path = kmemdup_nul(end, len, GFP_KERNEL); 99762306a36Sopenharmony_ci if (!ctx->nfs_server.export_path) 99862306a36Sopenharmony_ci goto out_nomem; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci trace_nfs_mount_path(ctx->nfs_server.export_path); 100162306a36Sopenharmony_ci return 0; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ciout_bad_devname: 100462306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: device name not in host:path format"); 100562306a36Sopenharmony_ciout_nomem: 100662306a36Sopenharmony_ci nfs_errorf(fc, "NFS: not enough memory to parse device name"); 100762306a36Sopenharmony_ci return -ENOMEM; 100862306a36Sopenharmony_ciout_hostname: 100962306a36Sopenharmony_ci nfs_errorf(fc, "NFS: server hostname too long"); 101062306a36Sopenharmony_ci return -ENAMETOOLONG; 101162306a36Sopenharmony_ciout_path: 101262306a36Sopenharmony_ci nfs_errorf(fc, "NFS: export pathname too long"); 101362306a36Sopenharmony_ci return -ENAMETOOLONG; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic inline bool is_remount_fc(struct fs_context *fc) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci return fc->root != NULL; 101962306a36Sopenharmony_ci} 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci/* 102262306a36Sopenharmony_ci * Parse monolithic NFS2/NFS3 mount data 102362306a36Sopenharmony_ci * - fills in the mount root filehandle 102462306a36Sopenharmony_ci * 102562306a36Sopenharmony_ci * For option strings, user space handles the following behaviors: 102662306a36Sopenharmony_ci * 102762306a36Sopenharmony_ci * + DNS: mapping server host name to IP address ("addr=" option) 102862306a36Sopenharmony_ci * 102962306a36Sopenharmony_ci * + failure mode: how to behave if a mount request can't be handled 103062306a36Sopenharmony_ci * immediately ("fg/bg" option) 103162306a36Sopenharmony_ci * 103262306a36Sopenharmony_ci * + retry: how often to retry a mount request ("retry=" option) 103362306a36Sopenharmony_ci * 103462306a36Sopenharmony_ci * + breaking back: trying proto=udp after proto=tcp, v2 after v3, 103562306a36Sopenharmony_ci * mountproto=tcp after mountproto=udp, and so on 103662306a36Sopenharmony_ci */ 103762306a36Sopenharmony_cistatic int nfs23_parse_monolithic(struct fs_context *fc, 103862306a36Sopenharmony_ci struct nfs_mount_data *data) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 104162306a36Sopenharmony_ci struct nfs_fh *mntfh = ctx->mntfh; 104262306a36Sopenharmony_ci struct sockaddr_storage *sap = &ctx->nfs_server._address; 104362306a36Sopenharmony_ci int extra_flags = NFS_MOUNT_LEGACY_INTERFACE; 104462306a36Sopenharmony_ci int ret; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (data == NULL) 104762306a36Sopenharmony_ci goto out_no_data; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci ctx->version = NFS_DEFAULT_VERSION; 105062306a36Sopenharmony_ci switch (data->version) { 105162306a36Sopenharmony_ci case 1: 105262306a36Sopenharmony_ci data->namlen = 0; 105362306a36Sopenharmony_ci fallthrough; 105462306a36Sopenharmony_ci case 2: 105562306a36Sopenharmony_ci data->bsize = 0; 105662306a36Sopenharmony_ci fallthrough; 105762306a36Sopenharmony_ci case 3: 105862306a36Sopenharmony_ci if (data->flags & NFS_MOUNT_VER3) 105962306a36Sopenharmony_ci goto out_no_v3; 106062306a36Sopenharmony_ci data->root.size = NFS2_FHSIZE; 106162306a36Sopenharmony_ci memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); 106262306a36Sopenharmony_ci /* Turn off security negotiation */ 106362306a36Sopenharmony_ci extra_flags |= NFS_MOUNT_SECFLAVOUR; 106462306a36Sopenharmony_ci fallthrough; 106562306a36Sopenharmony_ci case 4: 106662306a36Sopenharmony_ci if (data->flags & NFS_MOUNT_SECFLAVOUR) 106762306a36Sopenharmony_ci goto out_no_sec; 106862306a36Sopenharmony_ci fallthrough; 106962306a36Sopenharmony_ci case 5: 107062306a36Sopenharmony_ci memset(data->context, 0, sizeof(data->context)); 107162306a36Sopenharmony_ci fallthrough; 107262306a36Sopenharmony_ci case 6: 107362306a36Sopenharmony_ci if (data->flags & NFS_MOUNT_VER3) { 107462306a36Sopenharmony_ci if (data->root.size > NFS3_FHSIZE || data->root.size == 0) 107562306a36Sopenharmony_ci goto out_invalid_fh; 107662306a36Sopenharmony_ci mntfh->size = data->root.size; 107762306a36Sopenharmony_ci ctx->version = 3; 107862306a36Sopenharmony_ci } else { 107962306a36Sopenharmony_ci mntfh->size = NFS2_FHSIZE; 108062306a36Sopenharmony_ci ctx->version = 2; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci memcpy(mntfh->data, data->root.data, mntfh->size); 108562306a36Sopenharmony_ci if (mntfh->size < sizeof(mntfh->data)) 108662306a36Sopenharmony_ci memset(mntfh->data + mntfh->size, 0, 108762306a36Sopenharmony_ci sizeof(mntfh->data) - mntfh->size); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci /* 109062306a36Sopenharmony_ci * for proto == XPRT_TRANSPORT_UDP, which is what uses 109162306a36Sopenharmony_ci * to_exponential, implying shift: limit the shift value 109262306a36Sopenharmony_ci * to BITS_PER_LONG (majortimeo is unsigned long) 109362306a36Sopenharmony_ci */ 109462306a36Sopenharmony_ci if (!(data->flags & NFS_MOUNT_TCP)) /* this will be UDP */ 109562306a36Sopenharmony_ci if (data->retrans >= 64) /* shift value is too large */ 109662306a36Sopenharmony_ci goto out_invalid_data; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /* 109962306a36Sopenharmony_ci * Translate to nfs_fs_context, which nfs_fill_super 110062306a36Sopenharmony_ci * can deal with. 110162306a36Sopenharmony_ci */ 110262306a36Sopenharmony_ci ctx->flags = data->flags & NFS_MOUNT_FLAGMASK; 110362306a36Sopenharmony_ci ctx->flags |= extra_flags; 110462306a36Sopenharmony_ci ctx->rsize = data->rsize; 110562306a36Sopenharmony_ci ctx->wsize = data->wsize; 110662306a36Sopenharmony_ci ctx->timeo = data->timeo; 110762306a36Sopenharmony_ci ctx->retrans = data->retrans; 110862306a36Sopenharmony_ci ctx->acregmin = data->acregmin; 110962306a36Sopenharmony_ci ctx->acregmax = data->acregmax; 111062306a36Sopenharmony_ci ctx->acdirmin = data->acdirmin; 111162306a36Sopenharmony_ci ctx->acdirmax = data->acdirmax; 111262306a36Sopenharmony_ci ctx->need_mount = false; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci memcpy(sap, &data->addr, sizeof(data->addr)); 111562306a36Sopenharmony_ci ctx->nfs_server.addrlen = sizeof(data->addr); 111662306a36Sopenharmony_ci ctx->nfs_server.port = ntohs(data->addr.sin_port); 111762306a36Sopenharmony_ci if (sap->ss_family != AF_INET || 111862306a36Sopenharmony_ci !nfs_verify_server_address(sap)) 111962306a36Sopenharmony_ci goto out_no_address; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (!(data->flags & NFS_MOUNT_TCP)) 112262306a36Sopenharmony_ci ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; 112362306a36Sopenharmony_ci /* N.B. caller will free nfs_server.hostname in all cases */ 112462306a36Sopenharmony_ci ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); 112562306a36Sopenharmony_ci if (!ctx->nfs_server.hostname) 112662306a36Sopenharmony_ci goto out_nomem; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci ctx->namlen = data->namlen; 112962306a36Sopenharmony_ci ctx->bsize = data->bsize; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (data->flags & NFS_MOUNT_SECFLAVOUR) 113262306a36Sopenharmony_ci ctx->selected_flavor = data->pseudoflavor; 113362306a36Sopenharmony_ci else 113462306a36Sopenharmony_ci ctx->selected_flavor = RPC_AUTH_UNIX; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if (!(data->flags & NFS_MOUNT_NONLM)) 113762306a36Sopenharmony_ci ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK| 113862306a36Sopenharmony_ci NFS_MOUNT_LOCAL_FCNTL); 113962306a36Sopenharmony_ci else 114062306a36Sopenharmony_ci ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK| 114162306a36Sopenharmony_ci NFS_MOUNT_LOCAL_FCNTL); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci /* 114462306a36Sopenharmony_ci * The legacy version 6 binary mount data from userspace has a 114562306a36Sopenharmony_ci * field used only to transport selinux information into the 114662306a36Sopenharmony_ci * kernel. To continue to support that functionality we 114762306a36Sopenharmony_ci * have a touch of selinux knowledge here in the NFS code. The 114862306a36Sopenharmony_ci * userspace code converted context=blah to just blah so we are 114962306a36Sopenharmony_ci * converting back to the full string selinux understands. 115062306a36Sopenharmony_ci */ 115162306a36Sopenharmony_ci if (data->context[0]){ 115262306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX 115362306a36Sopenharmony_ci int ret; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci data->context[NFS_MAX_CONTEXT_LEN] = '\0'; 115662306a36Sopenharmony_ci ret = vfs_parse_fs_string(fc, "context", 115762306a36Sopenharmony_ci data->context, strlen(data->context)); 115862306a36Sopenharmony_ci if (ret < 0) 115962306a36Sopenharmony_ci return ret; 116062306a36Sopenharmony_ci#else 116162306a36Sopenharmony_ci return -EINVAL; 116262306a36Sopenharmony_ci#endif 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci break; 116662306a36Sopenharmony_ci default: 116762306a36Sopenharmony_ci goto generic; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci ret = nfs_validate_transport_protocol(fc, ctx); 117162306a36Sopenharmony_ci if (ret) 117262306a36Sopenharmony_ci return ret; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci ctx->skip_reconfig_option_check = true; 117562306a36Sopenharmony_ci return 0; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_cigeneric: 117862306a36Sopenharmony_ci return generic_parse_monolithic(fc, data); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ciout_no_data: 118162306a36Sopenharmony_ci if (is_remount_fc(fc)) { 118262306a36Sopenharmony_ci ctx->skip_reconfig_option_check = true; 118362306a36Sopenharmony_ci return 0; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: mount program didn't pass any mount data"); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ciout_no_v3: 118862306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: nfs_mount_data version does not support v3"); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ciout_no_sec: 119162306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: nfs_mount_data version supports only AUTH_SYS"); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ciout_nomem: 119462306a36Sopenharmony_ci return -ENOMEM; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ciout_no_address: 119762306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: mount program didn't pass remote address"); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ciout_invalid_fh: 120062306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: invalid root filehandle"); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ciout_invalid_data: 120362306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: invalid binary mount data"); 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NFS_V4) 120762306a36Sopenharmony_cistruct compat_nfs_string { 120862306a36Sopenharmony_ci compat_uint_t len; 120962306a36Sopenharmony_ci compat_uptr_t data; 121062306a36Sopenharmony_ci}; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_cistatic inline void compat_nfs_string(struct nfs_string *dst, 121362306a36Sopenharmony_ci struct compat_nfs_string *src) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci dst->data = compat_ptr(src->data); 121662306a36Sopenharmony_ci dst->len = src->len; 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistruct compat_nfs4_mount_data_v1 { 122062306a36Sopenharmony_ci compat_int_t version; 122162306a36Sopenharmony_ci compat_int_t flags; 122262306a36Sopenharmony_ci compat_int_t rsize; 122362306a36Sopenharmony_ci compat_int_t wsize; 122462306a36Sopenharmony_ci compat_int_t timeo; 122562306a36Sopenharmony_ci compat_int_t retrans; 122662306a36Sopenharmony_ci compat_int_t acregmin; 122762306a36Sopenharmony_ci compat_int_t acregmax; 122862306a36Sopenharmony_ci compat_int_t acdirmin; 122962306a36Sopenharmony_ci compat_int_t acdirmax; 123062306a36Sopenharmony_ci struct compat_nfs_string client_addr; 123162306a36Sopenharmony_ci struct compat_nfs_string mnt_path; 123262306a36Sopenharmony_ci struct compat_nfs_string hostname; 123362306a36Sopenharmony_ci compat_uint_t host_addrlen; 123462306a36Sopenharmony_ci compat_uptr_t host_addr; 123562306a36Sopenharmony_ci compat_int_t proto; 123662306a36Sopenharmony_ci compat_int_t auth_flavourlen; 123762306a36Sopenharmony_ci compat_uptr_t auth_flavours; 123862306a36Sopenharmony_ci}; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_cistatic void nfs4_compat_mount_data_conv(struct nfs4_mount_data *data) 124162306a36Sopenharmony_ci{ 124262306a36Sopenharmony_ci struct compat_nfs4_mount_data_v1 *compat = 124362306a36Sopenharmony_ci (struct compat_nfs4_mount_data_v1 *)data; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* copy the fields backwards */ 124662306a36Sopenharmony_ci data->auth_flavours = compat_ptr(compat->auth_flavours); 124762306a36Sopenharmony_ci data->auth_flavourlen = compat->auth_flavourlen; 124862306a36Sopenharmony_ci data->proto = compat->proto; 124962306a36Sopenharmony_ci data->host_addr = compat_ptr(compat->host_addr); 125062306a36Sopenharmony_ci data->host_addrlen = compat->host_addrlen; 125162306a36Sopenharmony_ci compat_nfs_string(&data->hostname, &compat->hostname); 125262306a36Sopenharmony_ci compat_nfs_string(&data->mnt_path, &compat->mnt_path); 125362306a36Sopenharmony_ci compat_nfs_string(&data->client_addr, &compat->client_addr); 125462306a36Sopenharmony_ci data->acdirmax = compat->acdirmax; 125562306a36Sopenharmony_ci data->acdirmin = compat->acdirmin; 125662306a36Sopenharmony_ci data->acregmax = compat->acregmax; 125762306a36Sopenharmony_ci data->acregmin = compat->acregmin; 125862306a36Sopenharmony_ci data->retrans = compat->retrans; 125962306a36Sopenharmony_ci data->timeo = compat->timeo; 126062306a36Sopenharmony_ci data->wsize = compat->wsize; 126162306a36Sopenharmony_ci data->rsize = compat->rsize; 126262306a36Sopenharmony_ci data->flags = compat->flags; 126362306a36Sopenharmony_ci data->version = compat->version; 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci/* 126762306a36Sopenharmony_ci * Validate NFSv4 mount options 126862306a36Sopenharmony_ci */ 126962306a36Sopenharmony_cistatic int nfs4_parse_monolithic(struct fs_context *fc, 127062306a36Sopenharmony_ci struct nfs4_mount_data *data) 127162306a36Sopenharmony_ci{ 127262306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 127362306a36Sopenharmony_ci struct sockaddr_storage *sap = &ctx->nfs_server._address; 127462306a36Sopenharmony_ci int ret; 127562306a36Sopenharmony_ci char *c; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci if (!data) { 127862306a36Sopenharmony_ci if (is_remount_fc(fc)) 127962306a36Sopenharmony_ci goto done; 128062306a36Sopenharmony_ci return nfs_invalf(fc, 128162306a36Sopenharmony_ci "NFS4: mount program didn't pass any mount data"); 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci ctx->version = 4; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (data->version != 1) 128762306a36Sopenharmony_ci return generic_parse_monolithic(fc, data); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (in_compat_syscall()) 129062306a36Sopenharmony_ci nfs4_compat_mount_data_conv(data); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (data->host_addrlen > sizeof(ctx->nfs_server.address)) 129362306a36Sopenharmony_ci goto out_no_address; 129462306a36Sopenharmony_ci if (data->host_addrlen == 0) 129562306a36Sopenharmony_ci goto out_no_address; 129662306a36Sopenharmony_ci ctx->nfs_server.addrlen = data->host_addrlen; 129762306a36Sopenharmony_ci if (copy_from_user(sap, data->host_addr, data->host_addrlen)) 129862306a36Sopenharmony_ci return -EFAULT; 129962306a36Sopenharmony_ci if (!nfs_verify_server_address(sap)) 130062306a36Sopenharmony_ci goto out_no_address; 130162306a36Sopenharmony_ci ctx->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (data->auth_flavourlen) { 130462306a36Sopenharmony_ci rpc_authflavor_t pseudoflavor; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (data->auth_flavourlen > 1) 130762306a36Sopenharmony_ci goto out_inval_auth; 130862306a36Sopenharmony_ci if (copy_from_user(&pseudoflavor, data->auth_flavours, 130962306a36Sopenharmony_ci sizeof(pseudoflavor))) 131062306a36Sopenharmony_ci return -EFAULT; 131162306a36Sopenharmony_ci ctx->selected_flavor = pseudoflavor; 131262306a36Sopenharmony_ci } else { 131362306a36Sopenharmony_ci ctx->selected_flavor = RPC_AUTH_UNIX; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); 131762306a36Sopenharmony_ci if (IS_ERR(c)) 131862306a36Sopenharmony_ci return PTR_ERR(c); 131962306a36Sopenharmony_ci ctx->nfs_server.hostname = c; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN); 132262306a36Sopenharmony_ci if (IS_ERR(c)) 132362306a36Sopenharmony_ci return PTR_ERR(c); 132462306a36Sopenharmony_ci ctx->nfs_server.export_path = c; 132562306a36Sopenharmony_ci trace_nfs_mount_path(c); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci c = strndup_user(data->client_addr.data, 16); 132862306a36Sopenharmony_ci if (IS_ERR(c)) 132962306a36Sopenharmony_ci return PTR_ERR(c); 133062306a36Sopenharmony_ci ctx->client_address = c; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* 133362306a36Sopenharmony_ci * Translate to nfs_fs_context, which nfs_fill_super 133462306a36Sopenharmony_ci * can deal with. 133562306a36Sopenharmony_ci */ 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci ctx->flags = data->flags & NFS4_MOUNT_FLAGMASK; 133862306a36Sopenharmony_ci ctx->rsize = data->rsize; 133962306a36Sopenharmony_ci ctx->wsize = data->wsize; 134062306a36Sopenharmony_ci ctx->timeo = data->timeo; 134162306a36Sopenharmony_ci ctx->retrans = data->retrans; 134262306a36Sopenharmony_ci ctx->acregmin = data->acregmin; 134362306a36Sopenharmony_ci ctx->acregmax = data->acregmax; 134462306a36Sopenharmony_ci ctx->acdirmin = data->acdirmin; 134562306a36Sopenharmony_ci ctx->acdirmax = data->acdirmax; 134662306a36Sopenharmony_ci ctx->nfs_server.protocol = data->proto; 134762306a36Sopenharmony_ci ret = nfs_validate_transport_protocol(fc, ctx); 134862306a36Sopenharmony_ci if (ret) 134962306a36Sopenharmony_ci return ret; 135062306a36Sopenharmony_cidone: 135162306a36Sopenharmony_ci ctx->skip_reconfig_option_check = true; 135262306a36Sopenharmony_ci return 0; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ciout_inval_auth: 135562306a36Sopenharmony_ci return nfs_invalf(fc, "NFS4: Invalid number of RPC auth flavours %d", 135662306a36Sopenharmony_ci data->auth_flavourlen); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ciout_no_address: 135962306a36Sopenharmony_ci return nfs_invalf(fc, "NFS4: mount program didn't pass remote address"); 136062306a36Sopenharmony_ci} 136162306a36Sopenharmony_ci#endif 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci/* 136462306a36Sopenharmony_ci * Parse a monolithic block of data from sys_mount(). 136562306a36Sopenharmony_ci */ 136662306a36Sopenharmony_cistatic int nfs_fs_context_parse_monolithic(struct fs_context *fc, 136762306a36Sopenharmony_ci void *data) 136862306a36Sopenharmony_ci{ 136962306a36Sopenharmony_ci if (fc->fs_type == &nfs_fs_type) 137062306a36Sopenharmony_ci return nfs23_parse_monolithic(fc, data); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NFS_V4) 137362306a36Sopenharmony_ci if (fc->fs_type == &nfs4_fs_type) 137462306a36Sopenharmony_ci return nfs4_parse_monolithic(fc, data); 137562306a36Sopenharmony_ci#endif 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Unsupported monolithic data version"); 137862306a36Sopenharmony_ci} 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci/* 138162306a36Sopenharmony_ci * Validate the preparsed information in the config. 138262306a36Sopenharmony_ci */ 138362306a36Sopenharmony_cistatic int nfs_fs_context_validate(struct fs_context *fc) 138462306a36Sopenharmony_ci{ 138562306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 138662306a36Sopenharmony_ci struct nfs_subversion *nfs_mod; 138762306a36Sopenharmony_ci struct sockaddr_storage *sap = &ctx->nfs_server._address; 138862306a36Sopenharmony_ci int max_namelen = PAGE_SIZE; 138962306a36Sopenharmony_ci int max_pathlen = NFS_MAXPATHLEN; 139062306a36Sopenharmony_ci int port = 0; 139162306a36Sopenharmony_ci int ret; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (!fc->source) 139462306a36Sopenharmony_ci goto out_no_device_name; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci /* Check for sanity first. */ 139762306a36Sopenharmony_ci if (ctx->minorversion && ctx->version != 4) 139862306a36Sopenharmony_ci goto out_minorversion_mismatch; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (ctx->options & NFS_OPTION_MIGRATION && 140162306a36Sopenharmony_ci (ctx->version != 4 || ctx->minorversion != 0)) 140262306a36Sopenharmony_ci goto out_migration_misuse; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci /* Verify that any proto=/mountproto= options match the address 140562306a36Sopenharmony_ci * families in the addr=/mountaddr= options. 140662306a36Sopenharmony_ci */ 140762306a36Sopenharmony_ci if (ctx->protofamily != AF_UNSPEC && 140862306a36Sopenharmony_ci ctx->protofamily != ctx->nfs_server.address.sa_family) 140962306a36Sopenharmony_ci goto out_proto_mismatch; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if (ctx->mountfamily != AF_UNSPEC) { 141262306a36Sopenharmony_ci if (ctx->mount_server.addrlen) { 141362306a36Sopenharmony_ci if (ctx->mountfamily != ctx->mount_server.address.sa_family) 141462306a36Sopenharmony_ci goto out_mountproto_mismatch; 141562306a36Sopenharmony_ci } else { 141662306a36Sopenharmony_ci if (ctx->mountfamily != ctx->nfs_server.address.sa_family) 141762306a36Sopenharmony_ci goto out_mountproto_mismatch; 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (!nfs_verify_server_address(sap)) 142262306a36Sopenharmony_ci goto out_no_address; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci ret = nfs_validate_transport_protocol(fc, ctx); 142562306a36Sopenharmony_ci if (ret) 142662306a36Sopenharmony_ci return ret; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci if (ctx->version == 4) { 142962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_NFS_V4)) { 143062306a36Sopenharmony_ci if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA) 143162306a36Sopenharmony_ci port = NFS_RDMA_PORT; 143262306a36Sopenharmony_ci else 143362306a36Sopenharmony_ci port = NFS_PORT; 143462306a36Sopenharmony_ci max_namelen = NFS4_MAXNAMLEN; 143562306a36Sopenharmony_ci max_pathlen = NFS4_MAXPATHLEN; 143662306a36Sopenharmony_ci ctx->flags &= ~(NFS_MOUNT_NONLM | NFS_MOUNT_NOACL | 143762306a36Sopenharmony_ci NFS_MOUNT_VER3 | NFS_MOUNT_LOCAL_FLOCK | 143862306a36Sopenharmony_ci NFS_MOUNT_LOCAL_FCNTL); 143962306a36Sopenharmony_ci } else { 144062306a36Sopenharmony_ci goto out_v4_not_compiled; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci } else { 144362306a36Sopenharmony_ci nfs_set_mount_transport_protocol(ctx); 144462306a36Sopenharmony_ci if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA) 144562306a36Sopenharmony_ci port = NFS_RDMA_PORT; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci nfs_set_port(sap, &ctx->nfs_server.port, port); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci ret = nfs_parse_source(fc, max_namelen, max_pathlen); 145162306a36Sopenharmony_ci if (ret < 0) 145262306a36Sopenharmony_ci return ret; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci /* Load the NFS protocol module if we haven't done so yet */ 145562306a36Sopenharmony_ci if (!ctx->nfs_mod) { 145662306a36Sopenharmony_ci nfs_mod = get_nfs_version(ctx->version); 145762306a36Sopenharmony_ci if (IS_ERR(nfs_mod)) { 145862306a36Sopenharmony_ci ret = PTR_ERR(nfs_mod); 145962306a36Sopenharmony_ci goto out_version_unavailable; 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci ctx->nfs_mod = nfs_mod; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci /* Ensure the filesystem context has the correct fs_type */ 146562306a36Sopenharmony_ci if (fc->fs_type != ctx->nfs_mod->nfs_fs) { 146662306a36Sopenharmony_ci module_put(fc->fs_type->owner); 146762306a36Sopenharmony_ci __module_get(ctx->nfs_mod->nfs_fs->owner); 146862306a36Sopenharmony_ci fc->fs_type = ctx->nfs_mod->nfs_fs; 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci return 0; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ciout_no_device_name: 147362306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Device name not specified"); 147462306a36Sopenharmony_ciout_v4_not_compiled: 147562306a36Sopenharmony_ci nfs_errorf(fc, "NFS: NFSv4 is not compiled into kernel"); 147662306a36Sopenharmony_ci return -EPROTONOSUPPORT; 147762306a36Sopenharmony_ciout_no_address: 147862306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: mount program didn't pass remote address"); 147962306a36Sopenharmony_ciout_mountproto_mismatch: 148062306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Mount server address does not match mountproto= option"); 148162306a36Sopenharmony_ciout_proto_mismatch: 148262306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Server address does not match proto= option"); 148362306a36Sopenharmony_ciout_minorversion_mismatch: 148462306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: Mount option vers=%u does not support minorversion=%u", 148562306a36Sopenharmony_ci ctx->version, ctx->minorversion); 148662306a36Sopenharmony_ciout_migration_misuse: 148762306a36Sopenharmony_ci return nfs_invalf(fc, "NFS: 'Migration' not supported for this NFS version"); 148862306a36Sopenharmony_ciout_version_unavailable: 148962306a36Sopenharmony_ci nfs_errorf(fc, "NFS: Version unavailable"); 149062306a36Sopenharmony_ci return ret; 149162306a36Sopenharmony_ci} 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci/* 149462306a36Sopenharmony_ci * Create an NFS superblock by the appropriate method. 149562306a36Sopenharmony_ci */ 149662306a36Sopenharmony_cistatic int nfs_get_tree(struct fs_context *fc) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 149962306a36Sopenharmony_ci int err = nfs_fs_context_validate(fc); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (err) 150262306a36Sopenharmony_ci return err; 150362306a36Sopenharmony_ci if (!ctx->internal) 150462306a36Sopenharmony_ci return ctx->nfs_mod->rpc_ops->try_get_tree(fc); 150562306a36Sopenharmony_ci else 150662306a36Sopenharmony_ci return nfs_get_tree_common(fc); 150762306a36Sopenharmony_ci} 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci/* 151062306a36Sopenharmony_ci * Handle duplication of a configuration. The caller copied *src into *sc, but 151162306a36Sopenharmony_ci * it can't deal with resource pointers in the filesystem context, so we have 151262306a36Sopenharmony_ci * to do that. We need to clear pointers, copy data or get extra refs as 151362306a36Sopenharmony_ci * appropriate. 151462306a36Sopenharmony_ci */ 151562306a36Sopenharmony_cistatic int nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) 151662306a36Sopenharmony_ci{ 151762306a36Sopenharmony_ci struct nfs_fs_context *src = nfs_fc2context(src_fc), *ctx; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci ctx = kmemdup(src, sizeof(struct nfs_fs_context), GFP_KERNEL); 152062306a36Sopenharmony_ci if (!ctx) 152162306a36Sopenharmony_ci return -ENOMEM; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci ctx->mntfh = nfs_alloc_fhandle(); 152462306a36Sopenharmony_ci if (!ctx->mntfh) { 152562306a36Sopenharmony_ci kfree(ctx); 152662306a36Sopenharmony_ci return -ENOMEM; 152762306a36Sopenharmony_ci } 152862306a36Sopenharmony_ci nfs_copy_fh(ctx->mntfh, src->mntfh); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci __module_get(ctx->nfs_mod->owner); 153162306a36Sopenharmony_ci ctx->client_address = NULL; 153262306a36Sopenharmony_ci ctx->mount_server.hostname = NULL; 153362306a36Sopenharmony_ci ctx->nfs_server.export_path = NULL; 153462306a36Sopenharmony_ci ctx->nfs_server.hostname = NULL; 153562306a36Sopenharmony_ci ctx->fscache_uniq = NULL; 153662306a36Sopenharmony_ci ctx->clone_data.fattr = NULL; 153762306a36Sopenharmony_ci fc->fs_private = ctx; 153862306a36Sopenharmony_ci return 0; 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cistatic void nfs_fs_context_free(struct fs_context *fc) 154262306a36Sopenharmony_ci{ 154362306a36Sopenharmony_ci struct nfs_fs_context *ctx = nfs_fc2context(fc); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (ctx) { 154662306a36Sopenharmony_ci if (ctx->server) 154762306a36Sopenharmony_ci nfs_free_server(ctx->server); 154862306a36Sopenharmony_ci if (ctx->nfs_mod) 154962306a36Sopenharmony_ci put_nfs_version(ctx->nfs_mod); 155062306a36Sopenharmony_ci kfree(ctx->client_address); 155162306a36Sopenharmony_ci kfree(ctx->mount_server.hostname); 155262306a36Sopenharmony_ci kfree(ctx->nfs_server.export_path); 155362306a36Sopenharmony_ci kfree(ctx->nfs_server.hostname); 155462306a36Sopenharmony_ci kfree(ctx->fscache_uniq); 155562306a36Sopenharmony_ci nfs_free_fhandle(ctx->mntfh); 155662306a36Sopenharmony_ci nfs_free_fattr(ctx->clone_data.fattr); 155762306a36Sopenharmony_ci kfree(ctx); 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic const struct fs_context_operations nfs_fs_context_ops = { 156262306a36Sopenharmony_ci .free = nfs_fs_context_free, 156362306a36Sopenharmony_ci .dup = nfs_fs_context_dup, 156462306a36Sopenharmony_ci .parse_param = nfs_fs_context_parse_param, 156562306a36Sopenharmony_ci .parse_monolithic = nfs_fs_context_parse_monolithic, 156662306a36Sopenharmony_ci .get_tree = nfs_get_tree, 156762306a36Sopenharmony_ci .reconfigure = nfs_reconfigure, 156862306a36Sopenharmony_ci}; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci/* 157162306a36Sopenharmony_ci * Prepare superblock configuration. We use the namespaces attached to the 157262306a36Sopenharmony_ci * context. This may be the current process's namespaces, or it may be a 157362306a36Sopenharmony_ci * container's namespaces. 157462306a36Sopenharmony_ci */ 157562306a36Sopenharmony_cistatic int nfs_init_fs_context(struct fs_context *fc) 157662306a36Sopenharmony_ci{ 157762306a36Sopenharmony_ci struct nfs_fs_context *ctx; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci ctx = kzalloc(sizeof(struct nfs_fs_context), GFP_KERNEL); 158062306a36Sopenharmony_ci if (unlikely(!ctx)) 158162306a36Sopenharmony_ci return -ENOMEM; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci ctx->mntfh = nfs_alloc_fhandle(); 158462306a36Sopenharmony_ci if (unlikely(!ctx->mntfh)) { 158562306a36Sopenharmony_ci kfree(ctx); 158662306a36Sopenharmony_ci return -ENOMEM; 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci ctx->protofamily = AF_UNSPEC; 159062306a36Sopenharmony_ci ctx->mountfamily = AF_UNSPEC; 159162306a36Sopenharmony_ci ctx->mount_server.port = NFS_UNSPEC_PORT; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci if (fc->root) { 159462306a36Sopenharmony_ci /* reconfigure, start with the current config */ 159562306a36Sopenharmony_ci struct nfs_server *nfss = fc->root->d_sb->s_fs_info; 159662306a36Sopenharmony_ci struct net *net = nfss->nfs_client->cl_net; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci ctx->flags = nfss->flags; 159962306a36Sopenharmony_ci ctx->rsize = nfss->rsize; 160062306a36Sopenharmony_ci ctx->wsize = nfss->wsize; 160162306a36Sopenharmony_ci ctx->retrans = nfss->client->cl_timeout->to_retries; 160262306a36Sopenharmony_ci ctx->selected_flavor = nfss->client->cl_auth->au_flavor; 160362306a36Sopenharmony_ci ctx->acregmin = nfss->acregmin / HZ; 160462306a36Sopenharmony_ci ctx->acregmax = nfss->acregmax / HZ; 160562306a36Sopenharmony_ci ctx->acdirmin = nfss->acdirmin / HZ; 160662306a36Sopenharmony_ci ctx->acdirmax = nfss->acdirmax / HZ; 160762306a36Sopenharmony_ci ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; 160862306a36Sopenharmony_ci ctx->nfs_server.port = nfss->port; 160962306a36Sopenharmony_ci ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; 161062306a36Sopenharmony_ci ctx->version = nfss->nfs_client->rpc_ops->version; 161162306a36Sopenharmony_ci ctx->minorversion = nfss->nfs_client->cl_minorversion; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci memcpy(&ctx->nfs_server._address, &nfss->nfs_client->cl_addr, 161462306a36Sopenharmony_ci ctx->nfs_server.addrlen); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci if (fc->net_ns != net) { 161762306a36Sopenharmony_ci put_net(fc->net_ns); 161862306a36Sopenharmony_ci fc->net_ns = get_net(net); 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci ctx->nfs_mod = nfss->nfs_client->cl_nfs_mod; 162262306a36Sopenharmony_ci __module_get(ctx->nfs_mod->owner); 162362306a36Sopenharmony_ci } else { 162462306a36Sopenharmony_ci /* defaults */ 162562306a36Sopenharmony_ci ctx->timeo = NFS_UNSPEC_TIMEO; 162662306a36Sopenharmony_ci ctx->retrans = NFS_UNSPEC_RETRANS; 162762306a36Sopenharmony_ci ctx->acregmin = NFS_DEF_ACREGMIN; 162862306a36Sopenharmony_ci ctx->acregmax = NFS_DEF_ACREGMAX; 162962306a36Sopenharmony_ci ctx->acdirmin = NFS_DEF_ACDIRMIN; 163062306a36Sopenharmony_ci ctx->acdirmax = NFS_DEF_ACDIRMAX; 163162306a36Sopenharmony_ci ctx->nfs_server.port = NFS_UNSPEC_PORT; 163262306a36Sopenharmony_ci ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP; 163362306a36Sopenharmony_ci ctx->selected_flavor = RPC_AUTH_MAXFLAVOR; 163462306a36Sopenharmony_ci ctx->minorversion = 0; 163562306a36Sopenharmony_ci ctx->need_mount = true; 163662306a36Sopenharmony_ci ctx->xprtsec.policy = RPC_XPRTSEC_NONE; 163762306a36Sopenharmony_ci ctx->xprtsec.cert_serial = TLS_NO_CERT; 163862306a36Sopenharmony_ci ctx->xprtsec.privkey_serial = TLS_NO_PRIVKEY; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci fc->s_iflags |= SB_I_STABLE_WRITES; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci fc->fs_private = ctx; 164362306a36Sopenharmony_ci fc->ops = &nfs_fs_context_ops; 164462306a36Sopenharmony_ci return 0; 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_cistruct file_system_type nfs_fs_type = { 164862306a36Sopenharmony_ci .owner = THIS_MODULE, 164962306a36Sopenharmony_ci .name = "nfs", 165062306a36Sopenharmony_ci .init_fs_context = nfs_init_fs_context, 165162306a36Sopenharmony_ci .parameters = nfs_fs_parameters, 165262306a36Sopenharmony_ci .kill_sb = nfs_kill_super, 165362306a36Sopenharmony_ci .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, 165462306a36Sopenharmony_ci}; 165562306a36Sopenharmony_ciMODULE_ALIAS_FS("nfs"); 165662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_fs_type); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NFS_V4) 165962306a36Sopenharmony_cistruct file_system_type nfs4_fs_type = { 166062306a36Sopenharmony_ci .owner = THIS_MODULE, 166162306a36Sopenharmony_ci .name = "nfs4", 166262306a36Sopenharmony_ci .init_fs_context = nfs_init_fs_context, 166362306a36Sopenharmony_ci .parameters = nfs_fs_parameters, 166462306a36Sopenharmony_ci .kill_sb = nfs_kill_super, 166562306a36Sopenharmony_ci .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, 166662306a36Sopenharmony_ci}; 166762306a36Sopenharmony_ciMODULE_ALIAS_FS("nfs4"); 166862306a36Sopenharmony_ciMODULE_ALIAS("nfs4"); 166962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_fs_type); 167062306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4 */ 1671