localio.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. #include <linux/exportfs.h>
  11. #include <linux/sunrpc/svcauth.h>
  12. #include <linux/sunrpc/clnt.h>
  13. #include <linux/nfs.h>
  14. #include <linux/nfs_common.h>
  15. #include <linux/nfslocalio.h>
  16. #include <linux/nfs_fs.h>
  17. #include <linux/nfs_xdr.h>
  18. #include <linux/string.h>
  19. #include "nfsd.h"
  20. #include "vfs.h"
  21. #include "netns.h"
  22. #include "filecache.h"
  23. #include "cache.h"
  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. void nfsd_localio_ops_init(void)
  32. {
  33. nfs_to = &nfsd_localio_ops;
  34. }
  35. /**
  36. * nfsd_open_local_fh - lookup a local filehandle @nfs_fh and map to nfsd_file
  37. *
  38. * @net: 'struct net' to get the proper nfsd_net required for LOCALIO access
  39. * @dom: 'struct auth_domain' required for LOCALIO access
  40. * @rpc_clnt: rpc_clnt that the client established
  41. * @cred: cred that the client established
  42. * @nfs_fh: filehandle to lookup
  43. * @fmode: fmode_t to use for open
  44. *
  45. * This function maps a local fh to a path on a local filesystem.
  46. * This is useful when the nfs client has the local server mounted - it can
  47. * avoid all the NFS overhead with reads, writes and commits.
  48. *
  49. * On successful return, returned nfsd_file will have its nf_net member
  50. * set. Caller (NFS client) is responsible for calling nfsd_serv_put and
  51. * nfsd_file_put (via nfs_to_nfsd_file_put_local).
  52. */
  53. struct nfsd_file *
  54. nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
  55. struct rpc_clnt *rpc_clnt, const struct cred *cred,
  56. const struct nfs_fh *nfs_fh, const fmode_t fmode)
  57. {
  58. int mayflags = NFSD_MAY_LOCALIO;
  59. struct svc_cred rq_cred;
  60. struct svc_fh fh;
  61. struct nfsd_file *localio;
  62. __be32 beres;
  63. if (nfs_fh->size > NFS4_FHSIZE)
  64. return ERR_PTR(-EINVAL);
  65. /* nfs_fh -> svc_fh */
  66. fh_init(&fh, NFS4_FHSIZE);
  67. fh.fh_handle.fh_size = nfs_fh->size;
  68. memcpy(fh.fh_handle.fh_raw, nfs_fh->data, nfs_fh->size);
  69. if (fmode & FMODE_READ)
  70. mayflags |= NFSD_MAY_READ;
  71. if (fmode & FMODE_WRITE)
  72. mayflags |= NFSD_MAY_WRITE;
  73. svcauth_map_clnt_to_svc_cred_local(rpc_clnt, cred, &rq_cred);
  74. beres = nfsd_file_acquire_local(net, &rq_cred, dom,
  75. &fh, mayflags, &localio);
  76. if (beres)
  77. localio = ERR_PTR(nfs_stat_to_errno(be32_to_cpu(beres)));
  78. fh_put(&fh);
  79. if (rq_cred.cr_group_info)
  80. put_group_info(rq_cred.cr_group_info);
  81. return localio;
  82. }
  83. EXPORT_SYMBOL_GPL(nfsd_open_local_fh);
  84. /*
  85. * UUID_IS_LOCAL XDR functions
  86. */
  87. static __be32 localio_proc_null(struct svc_rqst *rqstp)
  88. {
  89. return rpc_success;
  90. }
  91. struct localio_uuidarg {
  92. uuid_t uuid;
  93. };
  94. static __be32 localio_proc_uuid_is_local(struct svc_rqst *rqstp)
  95. {
  96. struct localio_uuidarg *argp = rqstp->rq_argp;
  97. struct net *net = SVC_NET(rqstp);
  98. struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  99. nfs_uuid_is_local(&argp->uuid, &nn->local_clients,
  100. net, rqstp->rq_client, THIS_MODULE);
  101. return rpc_success;
  102. }
  103. static bool localio_decode_uuidarg(struct svc_rqst *rqstp,
  104. struct xdr_stream *xdr)
  105. {
  106. struct localio_uuidarg *argp = rqstp->rq_argp;
  107. u8 uuid[UUID_SIZE];
  108. if (decode_opaque_fixed(xdr, uuid, UUID_SIZE))
  109. return false;
  110. import_uuid(&argp->uuid, uuid);
  111. return true;
  112. }
  113. static const struct svc_procedure localio_procedures1[] = {
  114. [LOCALIOPROC_NULL] = {
  115. .pc_func = localio_proc_null,
  116. .pc_decode = nfssvc_decode_voidarg,
  117. .pc_encode = nfssvc_encode_voidres,
  118. .pc_argsize = sizeof(struct nfsd_voidargs),
  119. .pc_ressize = sizeof(struct nfsd_voidres),
  120. .pc_cachetype = RC_NOCACHE,
  121. .pc_xdrressize = 0,
  122. .pc_name = "NULL",
  123. },
  124. [LOCALIOPROC_UUID_IS_LOCAL] = {
  125. .pc_func = localio_proc_uuid_is_local,
  126. .pc_decode = localio_decode_uuidarg,
  127. .pc_encode = nfssvc_encode_voidres,
  128. .pc_argsize = sizeof(struct localio_uuidarg),
  129. .pc_argzero = sizeof(struct localio_uuidarg),
  130. .pc_ressize = sizeof(struct nfsd_voidres),
  131. .pc_cachetype = RC_NOCACHE,
  132. .pc_name = "UUID_IS_LOCAL",
  133. },
  134. };
  135. #define LOCALIO_NR_PROCEDURES ARRAY_SIZE(localio_procedures1)
  136. static DEFINE_PER_CPU_ALIGNED(unsigned long,
  137. localio_count[LOCALIO_NR_PROCEDURES]);
  138. const struct svc_version localio_version1 = {
  139. .vs_vers = 1,
  140. .vs_nproc = LOCALIO_NR_PROCEDURES,
  141. .vs_proc = localio_procedures1,
  142. .vs_dispatch = nfsd_dispatch,
  143. .vs_count = localio_count,
  144. .vs_xdrsize = XDR_QUADLEN(UUID_SIZE),
  145. .vs_hidden = true,
  146. };