|
| 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/string.h> |
| 18 | + |
| 19 | +#include "nfsd.h" |
| 20 | +#include "vfs.h" |
| 21 | +#include "netns.h" |
| 22 | +#include "filecache.h" |
| 23 | + |
| 24 | +static const struct nfsd_localio_operations nfsd_localio_ops = { |
| 25 | + .nfsd_serv_try_get = nfsd_serv_try_get, |
| 26 | + .nfsd_serv_put = nfsd_serv_put, |
| 27 | + .nfsd_open_local_fh = nfsd_open_local_fh, |
| 28 | + .nfsd_file_put_local = nfsd_file_put_local, |
| 29 | + .nfsd_file_file = nfsd_file_file, |
| 30 | +}; |
| 31 | + |
| 32 | +void nfsd_localio_ops_init(void) |
| 33 | +{ |
| 34 | + nfs_to = &nfsd_localio_ops; |
| 35 | +} |
| 36 | + |
| 37 | +/** |
| 38 | + * nfsd_open_local_fh - lookup a local filehandle @nfs_fh and map to nfsd_file |
| 39 | + * |
| 40 | + * @net: 'struct net' to get the proper nfsd_net required for LOCALIO access |
| 41 | + * @dom: 'struct auth_domain' required for LOCALIO access |
| 42 | + * @rpc_clnt: rpc_clnt that the client established |
| 43 | + * @cred: cred that the client established |
| 44 | + * @nfs_fh: filehandle to lookup |
| 45 | + * @fmode: fmode_t to use for open |
| 46 | + * |
| 47 | + * This function maps a local fh to a path on a local filesystem. |
| 48 | + * This is useful when the nfs client has the local server mounted - it can |
| 49 | + * avoid all the NFS overhead with reads, writes and commits. |
| 50 | + * |
| 51 | + * On successful return, returned nfsd_file will have its nf_net member |
| 52 | + * set. Caller (NFS client) is responsible for calling nfsd_serv_put and |
| 53 | + * nfsd_file_put (via nfs_to->nfsd_file_put_local). |
| 54 | + */ |
| 55 | +struct nfsd_file * |
| 56 | +nfsd_open_local_fh(struct net *net, struct auth_domain *dom, |
| 57 | + struct rpc_clnt *rpc_clnt, const struct cred *cred, |
| 58 | + const struct nfs_fh *nfs_fh, const fmode_t fmode) |
| 59 | +{ |
| 60 | + int mayflags = NFSD_MAY_LOCALIO; |
| 61 | + struct svc_cred rq_cred; |
| 62 | + struct svc_fh fh; |
| 63 | + struct nfsd_file *localio; |
| 64 | + __be32 beres; |
| 65 | + |
| 66 | + if (nfs_fh->size > NFS4_FHSIZE) |
| 67 | + return ERR_PTR(-EINVAL); |
| 68 | + |
| 69 | + /* nfs_fh -> svc_fh */ |
| 70 | + fh_init(&fh, NFS4_FHSIZE); |
| 71 | + fh.fh_handle.fh_size = nfs_fh->size; |
| 72 | + memcpy(fh.fh_handle.fh_raw, nfs_fh->data, nfs_fh->size); |
| 73 | + |
| 74 | + if (fmode & FMODE_READ) |
| 75 | + mayflags |= NFSD_MAY_READ; |
| 76 | + if (fmode & FMODE_WRITE) |
| 77 | + mayflags |= NFSD_MAY_WRITE; |
| 78 | + |
| 79 | + svcauth_map_clnt_to_svc_cred_local(rpc_clnt, cred, &rq_cred); |
| 80 | + |
| 81 | + beres = nfsd_file_acquire_local(net, &rq_cred, dom, |
| 82 | + &fh, mayflags, &localio); |
| 83 | + if (beres) |
| 84 | + localio = ERR_PTR(nfs_stat_to_errno(be32_to_cpu(beres))); |
| 85 | + |
| 86 | + fh_put(&fh); |
| 87 | + if (rq_cred.cr_group_info) |
| 88 | + put_group_info(rq_cred.cr_group_info); |
| 89 | + |
| 90 | + return localio; |
| 91 | +} |
| 92 | +EXPORT_SYMBOL_GPL(nfsd_open_local_fh); |
0 commit comments