Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * NFS server support for local clients to bypass network stack
  4 *
  5 * Copyright (C) 2014 Weston Andros Adamson <dros@primarydata.com>
  6 * Copyright (C) 2019 Trond Myklebust <trond.myklebust@hammerspace.com>
  7 * Copyright (C) 2024 Mike Snitzer <snitzer@hammerspace.com>
  8 * Copyright (C) 2024 NeilBrown <neilb@suse.de>
  9 */
 10
 11#include <linux/exportfs.h>
 12#include <linux/sunrpc/svcauth.h>
 13#include <linux/sunrpc/clnt.h>
 14#include <linux/nfs.h>
 15#include <linux/nfs_common.h>
 16#include <linux/nfslocalio.h>
 17#include <linux/nfs_fs.h>
 18#include <linux/nfs_xdr.h>
 19#include <linux/string.h>
 20
 21#include "nfsd.h"
 22#include "vfs.h"
 23#include "netns.h"
 24#include "filecache.h"
 25#include "cache.h"
 26
 27static const struct nfsd_localio_operations nfsd_localio_ops = {
 28	.nfsd_serv_try_get  = nfsd_serv_try_get,
 29	.nfsd_serv_put  = nfsd_serv_put,
 30	.nfsd_open_local_fh = nfsd_open_local_fh,
 31	.nfsd_file_put_local = nfsd_file_put_local,
 32	.nfsd_file_file = nfsd_file_file,
 33};
 34
 35void nfsd_localio_ops_init(void)
 36{
 37	nfs_to = &nfsd_localio_ops;
 38}
 39
 40/**
 41 * nfsd_open_local_fh - lookup a local filehandle @nfs_fh and map to nfsd_file
 42 *
 43 * @net: 'struct net' to get the proper nfsd_net required for LOCALIO access
 44 * @dom: 'struct auth_domain' required for LOCALIO access
 45 * @rpc_clnt: rpc_clnt that the client established
 46 * @cred: cred that the client established
 47 * @nfs_fh: filehandle to lookup
 48 * @fmode: fmode_t to use for open
 49 *
 50 * This function maps a local fh to a path on a local filesystem.
 51 * This is useful when the nfs client has the local server mounted - it can
 52 * avoid all the NFS overhead with reads, writes and commits.
 53 *
 54 * On successful return, returned nfsd_file will have its nf_net member
 55 * set. Caller (NFS client) is responsible for calling nfsd_serv_put and
 56 * nfsd_file_put (via nfs_to_nfsd_file_put_local).
 57 */
 58struct nfsd_file *
 59nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
 60		   struct rpc_clnt *rpc_clnt, const struct cred *cred,
 61		   const struct nfs_fh *nfs_fh, const fmode_t fmode)
 62{
 63	int mayflags = NFSD_MAY_LOCALIO;
 64	struct svc_cred rq_cred;
 65	struct svc_fh fh;
 66	struct nfsd_file *localio;
 67	__be32 beres;
 68
 69	if (nfs_fh->size > NFS4_FHSIZE)
 70		return ERR_PTR(-EINVAL);
 71
 72	/* nfs_fh -> svc_fh */
 73	fh_init(&fh, NFS4_FHSIZE);
 74	fh.fh_handle.fh_size = nfs_fh->size;
 75	memcpy(fh.fh_handle.fh_raw, nfs_fh->data, nfs_fh->size);
 76
 77	if (fmode & FMODE_READ)
 78		mayflags |= NFSD_MAY_READ;
 79	if (fmode & FMODE_WRITE)
 80		mayflags |= NFSD_MAY_WRITE;
 81
 82	svcauth_map_clnt_to_svc_cred_local(rpc_clnt, cred, &rq_cred);
 83
 84	beres = nfsd_file_acquire_local(net, &rq_cred, dom,
 85					&fh, mayflags, &localio);
 86	if (beres)
 87		localio = ERR_PTR(nfs_stat_to_errno(be32_to_cpu(beres)));
 88
 89	fh_put(&fh);
 90	if (rq_cred.cr_group_info)
 91		put_group_info(rq_cred.cr_group_info);
 92
 93	return localio;
 94}
 95EXPORT_SYMBOL_GPL(nfsd_open_local_fh);
 96
 97/*
 98 * UUID_IS_LOCAL XDR functions
 99 */
100
101static __be32 localio_proc_null(struct svc_rqst *rqstp)
102{
103	return rpc_success;
104}
105
106struct localio_uuidarg {
107	uuid_t			uuid;
108};
109
110static __be32 localio_proc_uuid_is_local(struct svc_rqst *rqstp)
111{
112	struct localio_uuidarg *argp = rqstp->rq_argp;
113	struct net *net = SVC_NET(rqstp);
114	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
115
116	nfs_uuid_is_local(&argp->uuid, &nn->local_clients,
117			  net, rqstp->rq_client, THIS_MODULE);
118
119	return rpc_success;
120}
121
122static bool localio_decode_uuidarg(struct svc_rqst *rqstp,
123				   struct xdr_stream *xdr)
124{
125	struct localio_uuidarg *argp = rqstp->rq_argp;
126	u8 uuid[UUID_SIZE];
127
128	if (decode_opaque_fixed(xdr, uuid, UUID_SIZE))
129		return false;
130	import_uuid(&argp->uuid, uuid);
131
132	return true;
133}
134
135static const struct svc_procedure localio_procedures1[] = {
136	[LOCALIOPROC_NULL] = {
137		.pc_func = localio_proc_null,
138		.pc_decode = nfssvc_decode_voidarg,
139		.pc_encode = nfssvc_encode_voidres,
140		.pc_argsize = sizeof(struct nfsd_voidargs),
141		.pc_ressize = sizeof(struct nfsd_voidres),
142		.pc_cachetype = RC_NOCACHE,
143		.pc_xdrressize = 0,
144		.pc_name = "NULL",
145	},
146	[LOCALIOPROC_UUID_IS_LOCAL] = {
147		.pc_func = localio_proc_uuid_is_local,
148		.pc_decode = localio_decode_uuidarg,
149		.pc_encode = nfssvc_encode_voidres,
150		.pc_argsize = sizeof(struct localio_uuidarg),
151		.pc_argzero = sizeof(struct localio_uuidarg),
152		.pc_ressize = sizeof(struct nfsd_voidres),
153		.pc_cachetype = RC_NOCACHE,
154		.pc_name = "UUID_IS_LOCAL",
155	},
156};
157
158#define LOCALIO_NR_PROCEDURES ARRAY_SIZE(localio_procedures1)
159static DEFINE_PER_CPU_ALIGNED(unsigned long,
160			      localio_count[LOCALIO_NR_PROCEDURES]);
161const struct svc_version localio_version1 = {
162	.vs_vers	= 1,
163	.vs_nproc	= LOCALIO_NR_PROCEDURES,
164	.vs_proc	= localio_procedures1,
165	.vs_dispatch	= nfsd_dispatch,
166	.vs_count	= localio_count,
167	.vs_xdrsize	= XDR_QUADLEN(UUID_SIZE),
168	.vs_hidden	= true,
169};