]> Git Repo - linux.git/blob - fs/nfsd/localio.c
Linux 6.14-rc3
[linux.git] / fs / nfsd / localio.c
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 <[email protected]>
6  * Copyright (C) 2019 Trond Myklebust <[email protected]>
7  * Copyright (C) 2024 Mike Snitzer <[email protected]>
8  * Copyright (C) 2024 NeilBrown <[email protected]>
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
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,
35 };
36
37 void nfsd_localio_ops_init(void)
38 {
39         nfs_to = &nfsd_localio_ops;
40 }
41
42 /**
43  * nfsd_open_local_fh - lookup a local filehandle @nfs_fh and map to nfsd_file
44  *
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
51  *
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.
55  *
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).
59  */
60 struct nfsd_file *
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)
64 {
65         int mayflags = NFSD_MAY_LOCALIO;
66         struct svc_cred rq_cred;
67         struct svc_fh fh;
68         struct nfsd_file *localio;
69         __be32 beres;
70
71         if (nfs_fh->size > NFS4_FHSIZE)
72                 return ERR_PTR(-EINVAL);
73
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);
78
79         if (fmode & FMODE_READ)
80                 mayflags |= NFSD_MAY_READ;
81         if (fmode & FMODE_WRITE)
82                 mayflags |= NFSD_MAY_WRITE;
83
84         svcauth_map_clnt_to_svc_cred_local(rpc_clnt, cred, &rq_cred);
85
86         beres = nfsd_file_acquire_local(net, &rq_cred, dom,
87                                         &fh, mayflags, &localio);
88         if (beres)
89                 localio = ERR_PTR(nfs_stat_to_errno(be32_to_cpu(beres)));
90
91         fh_put(&fh);
92         if (rq_cred.cr_group_info)
93                 put_group_info(rq_cred.cr_group_info);
94
95         return localio;
96 }
97 EXPORT_SYMBOL_GPL(nfsd_open_local_fh);
98
99 /*
100  * UUID_IS_LOCAL XDR functions
101  */
102
103 static __be32 localio_proc_null(struct svc_rqst *rqstp)
104 {
105         return rpc_success;
106 }
107
108 struct localio_uuidarg {
109         uuid_t                  uuid;
110 };
111
112 static __be32 localio_proc_uuid_is_local(struct svc_rqst *rqstp)
113 {
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);
117
118         nfs_uuid_is_local(&argp->uuid, &nn->local_clients,
119                           &nn->local_clients_lock,
120                           net, rqstp->rq_client, THIS_MODULE);
121
122         return rpc_success;
123 }
124
125 static bool localio_decode_uuidarg(struct svc_rqst *rqstp,
126                                    struct xdr_stream *xdr)
127 {
128         struct localio_uuidarg *argp = rqstp->rq_argp;
129         u8 uuid[UUID_SIZE];
130
131         if (decode_opaque_fixed(xdr, uuid, UUID_SIZE))
132                 return false;
133         import_uuid(&argp->uuid, uuid);
134
135         return true;
136 }
137
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,
146                 .pc_xdrressize = 0,
147                 .pc_name = "NULL",
148         },
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",
158         },
159 };
160
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 = {
165         .vs_vers        = 1,
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),
171         .vs_hidden      = true,
172 };
This page took 0.038182 seconds and 4 git commands to generate.