162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/nfs_fs.h> 362306a36Sopenharmony_ci#include <linux/nfs_mount.h> 462306a36Sopenharmony_ci#include <linux/sunrpc/addr.h> 562306a36Sopenharmony_ci#include "internal.h" 662306a36Sopenharmony_ci#include "nfs3_fs.h" 762306a36Sopenharmony_ci#include "netns.h" 862306a36Sopenharmony_ci#include "sysfs.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#ifdef CONFIG_NFS_V3_ACL 1162306a36Sopenharmony_cistatic struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; 1262306a36Sopenharmony_cistatic const struct rpc_version *nfsacl_version[] = { 1362306a36Sopenharmony_ci [3] = &nfsacl_version3, 1462306a36Sopenharmony_ci}; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciconst struct rpc_program nfsacl_program = { 1762306a36Sopenharmony_ci .name = "nfsacl", 1862306a36Sopenharmony_ci .number = NFS_ACL_PROGRAM, 1962306a36Sopenharmony_ci .nrvers = ARRAY_SIZE(nfsacl_version), 2062306a36Sopenharmony_ci .version = nfsacl_version, 2162306a36Sopenharmony_ci .stats = &nfsacl_rpcstat, 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Initialise an NFSv3 ACL client connection 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_cistatic void nfs_init_server_aclclient(struct nfs_server *server) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci if (server->flags & NFS_MOUNT_NOACL) 3062306a36Sopenharmony_ci goto out_noacl; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3); 3362306a36Sopenharmony_ci if (IS_ERR(server->client_acl)) 3462306a36Sopenharmony_ci goto out_noacl; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci nfs_sysfs_link_rpc_client(server, server->client_acl, NULL); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* No errors! Assume that Sun nfsacls are supported */ 3962306a36Sopenharmony_ci server->caps |= NFS_CAP_ACLS; 4062306a36Sopenharmony_ci return; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciout_noacl: 4362306a36Sopenharmony_ci server->caps &= ~NFS_CAP_ACLS; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci#else 4662306a36Sopenharmony_cistatic inline void nfs_init_server_aclclient(struct nfs_server *server) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci server->flags &= ~NFS_MOUNT_NOACL; 4962306a36Sopenharmony_ci server->caps &= ~NFS_CAP_ACLS; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci#endif 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct nfs_server *nfs3_create_server(struct fs_context *fc) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct nfs_server *server = nfs_create_server(fc); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* Create a client RPC handle for the NFS v3 ACL management interface */ 5862306a36Sopenharmony_ci if (!IS_ERR(server)) 5962306a36Sopenharmony_ci nfs_init_server_aclclient(server); 6062306a36Sopenharmony_ci return server; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct nfs_server *nfs3_clone_server(struct nfs_server *source, 6462306a36Sopenharmony_ci struct nfs_fh *fh, 6562306a36Sopenharmony_ci struct nfs_fattr *fattr, 6662306a36Sopenharmony_ci rpc_authflavor_t flavor) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct nfs_server *server = nfs_clone_server(source, fh, fattr, flavor); 6962306a36Sopenharmony_ci if (!IS_ERR(server) && !IS_ERR(source->client_acl)) 7062306a36Sopenharmony_ci nfs_init_server_aclclient(server); 7162306a36Sopenharmony_ci return server; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * Set up a pNFS Data Server client over NFSv3. 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * Return any existing nfs_client that matches server address,port,version 7862306a36Sopenharmony_ci * and minorversion. 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * For a new nfs_client, use a soft mount (default), a low retrans and a 8162306a36Sopenharmony_ci * low timeout interval so that if a connection is lost, we retry through 8262306a36Sopenharmony_ci * the MDS. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_cistruct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv, 8562306a36Sopenharmony_ci const struct sockaddr_storage *ds_addr, int ds_addrlen, 8662306a36Sopenharmony_ci int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct rpc_timeout ds_timeout; 8962306a36Sopenharmony_ci unsigned long connect_timeout = ds_timeo * (ds_retrans + 1) * HZ / 10; 9062306a36Sopenharmony_ci struct nfs_client *mds_clp = mds_srv->nfs_client; 9162306a36Sopenharmony_ci struct nfs_client_initdata cl_init = { 9262306a36Sopenharmony_ci .addr = ds_addr, 9362306a36Sopenharmony_ci .addrlen = ds_addrlen, 9462306a36Sopenharmony_ci .nodename = mds_clp->cl_rpcclient->cl_nodename, 9562306a36Sopenharmony_ci .ip_addr = mds_clp->cl_ipaddr, 9662306a36Sopenharmony_ci .nfs_mod = &nfs_v3, 9762306a36Sopenharmony_ci .proto = ds_proto, 9862306a36Sopenharmony_ci .net = mds_clp->cl_net, 9962306a36Sopenharmony_ci .timeparms = &ds_timeout, 10062306a36Sopenharmony_ci .cred = mds_srv->cred, 10162306a36Sopenharmony_ci .xprtsec = mds_clp->cl_xprtsec, 10262306a36Sopenharmony_ci .connect_timeout = connect_timeout, 10362306a36Sopenharmony_ci .reconnect_timeout = connect_timeout, 10462306a36Sopenharmony_ci }; 10562306a36Sopenharmony_ci struct nfs_client *clp; 10662306a36Sopenharmony_ci char buf[INET6_ADDRSTRLEN + 1]; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* fake a hostname because lockd wants it */ 10962306a36Sopenharmony_ci if (rpc_ntop((struct sockaddr *)ds_addr, buf, sizeof(buf)) <= 0) 11062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 11162306a36Sopenharmony_ci cl_init.hostname = buf; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci switch (ds_proto) { 11462306a36Sopenharmony_ci case XPRT_TRANSPORT_TCP: 11562306a36Sopenharmony_ci case XPRT_TRANSPORT_TCP_TLS: 11662306a36Sopenharmony_ci if (mds_clp->cl_nconnect > 1) 11762306a36Sopenharmony_ci cl_init.nconnect = mds_clp->cl_nconnect; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (mds_srv->flags & NFS_MOUNT_NORESVPORT) 12162306a36Sopenharmony_ci __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci __set_bit(NFS_CS_DS, &cl_init.init_flags); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Use the MDS nfs_client cl_ipaddr. */ 12662306a36Sopenharmony_ci nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans); 12762306a36Sopenharmony_ci clp = nfs_get_client(&cl_init); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return clp; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs3_set_ds_client); 132