1 // SPDX-License-Identifier: GPL-2.0-only
3 * NFS server support for local clients to bypass network stack
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>
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>
24 #include "filecache.h"
27 static const struct nfsd_localio_operations nfsd_localio_ops
= {
28 .nfsd_net_try_get
= nfsd_net_try_get
,
29 .nfsd_net_put
= nfsd_net_put
,
30 .nfsd_open_local_fh
= nfsd_open_local_fh
,
31 .nfsd_file_put_local
= nfsd_file_put_local
,
32 .nfsd_file_get
= nfsd_file_get
,
33 .nfsd_file_put
= nfsd_file_put
,
34 .nfsd_file_file
= nfsd_file_file
,
37 void nfsd_localio_ops_init(void)
39 nfs_to
= &nfsd_localio_ops
;
43 * nfsd_open_local_fh - lookup a local filehandle @nfs_fh and map to nfsd_file
45 * @net: 'struct net' to get the proper nfsd_net required for LOCALIO access
46 * @dom: 'struct auth_domain' required for LOCALIO access
47 * @rpc_clnt: rpc_clnt that the client established
48 * @cred: cred that the client established
49 * @nfs_fh: filehandle to lookup
50 * @fmode: fmode_t to use for open
52 * This function maps a local fh to a path on a local filesystem.
53 * This is useful when the nfs client has the local server mounted - it can
54 * avoid all the NFS overhead with reads, writes and commits.
56 * On successful return, returned nfsd_file will have its nf_net member
57 * set. Caller (NFS client) is responsible for calling nfsd_net_put and
58 * nfsd_file_put (via nfs_to_nfsd_file_put_local).
61 nfsd_open_local_fh(struct net
*net
, struct auth_domain
*dom
,
62 struct rpc_clnt
*rpc_clnt
, const struct cred
*cred
,
63 const struct nfs_fh
*nfs_fh
, const fmode_t fmode
)
65 int mayflags
= NFSD_MAY_LOCALIO
;
66 struct svc_cred rq_cred
;
68 struct nfsd_file
*localio
;
71 if (nfs_fh
->size
> NFS4_FHSIZE
)
72 return ERR_PTR(-EINVAL
);
74 /* nfs_fh -> svc_fh */
75 fh_init(&fh
, NFS4_FHSIZE
);
76 fh
.fh_handle
.fh_size
= nfs_fh
->size
;
77 memcpy(fh
.fh_handle
.fh_raw
, nfs_fh
->data
, nfs_fh
->size
);
79 if (fmode
& FMODE_READ
)
80 mayflags
|= NFSD_MAY_READ
;
81 if (fmode
& FMODE_WRITE
)
82 mayflags
|= NFSD_MAY_WRITE
;
84 svcauth_map_clnt_to_svc_cred_local(rpc_clnt
, cred
, &rq_cred
);
86 beres
= nfsd_file_acquire_local(net
, &rq_cred
, dom
,
87 &fh
, mayflags
, &localio
);
89 localio
= ERR_PTR(nfs_stat_to_errno(be32_to_cpu(beres
)));
92 if (rq_cred
.cr_group_info
)
93 put_group_info(rq_cred
.cr_group_info
);
97 EXPORT_SYMBOL_GPL(nfsd_open_local_fh
);
100 * UUID_IS_LOCAL XDR functions
103 static __be32
localio_proc_null(struct svc_rqst
*rqstp
)
108 struct localio_uuidarg
{
112 static __be32
localio_proc_uuid_is_local(struct svc_rqst
*rqstp
)
114 struct localio_uuidarg
*argp
= rqstp
->rq_argp
;
115 struct net
*net
= SVC_NET(rqstp
);
116 struct nfsd_net
*nn
= net_generic(net
, nfsd_net_id
);
118 nfs_uuid_is_local(&argp
->uuid
, &nn
->local_clients
,
119 &nn
->local_clients_lock
,
120 net
, rqstp
->rq_client
, THIS_MODULE
);
125 static bool localio_decode_uuidarg(struct svc_rqst
*rqstp
,
126 struct xdr_stream
*xdr
)
128 struct localio_uuidarg
*argp
= rqstp
->rq_argp
;
131 if (decode_opaque_fixed(xdr
, uuid
, UUID_SIZE
))
133 import_uuid(&argp
->uuid
, uuid
);
138 static const struct svc_procedure localio_procedures1
[] = {
139 [LOCALIOPROC_NULL
] = {
140 .pc_func
= localio_proc_null
,
141 .pc_decode
= nfssvc_decode_voidarg
,
142 .pc_encode
= nfssvc_encode_voidres
,
143 .pc_argsize
= sizeof(struct nfsd_voidargs
),
144 .pc_ressize
= sizeof(struct nfsd_voidres
),
145 .pc_cachetype
= RC_NOCACHE
,
149 [LOCALIOPROC_UUID_IS_LOCAL
] = {
150 .pc_func
= localio_proc_uuid_is_local
,
151 .pc_decode
= localio_decode_uuidarg
,
152 .pc_encode
= nfssvc_encode_voidres
,
153 .pc_argsize
= sizeof(struct localio_uuidarg
),
154 .pc_argzero
= sizeof(struct localio_uuidarg
),
155 .pc_ressize
= sizeof(struct nfsd_voidres
),
156 .pc_cachetype
= RC_NOCACHE
,
157 .pc_name
= "UUID_IS_LOCAL",
161 #define LOCALIO_NR_PROCEDURES ARRAY_SIZE(localio_procedures1)
162 static DEFINE_PER_CPU_ALIGNED(unsigned long,
163 localio_count
[LOCALIO_NR_PROCEDURES
]);
164 const struct svc_version localio_version1
= {
166 .vs_nproc
= LOCALIO_NR_PROCEDURES
,
167 .vs_proc
= localio_procedures1
,
168 .vs_dispatch
= nfsd_dispatch
,
169 .vs_count
= localio_count
,
170 .vs_xdrsize
= XDR_QUADLEN(UUID_SIZE
),