Message ID | 20240829010424.83693-18-snitzer@kernel.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | nfs/nfsd: add support for LOCALIO | expand |
On Wed, 2024-08-28 at 21:04 -0400, Mike Snitzer wrote: > The LOCALIO auxiliary RPC protocol consists of a single "UUID_IS_LOCAL" > RPC method that allows the Linux NFS client to verify the local Linux > NFS server can see the nonce (single-use UUID) the client generated and > made available in nfs_common. The server expects this protocol to use > the same transport as NFS and NFSACL for its RPCs. This protocol > isn't part of an IETF standard, nor does it need to be considering it > is Linux-to-Linux auxiliary RPC protocol that amounts to an > implementation detail. > > The UUID_IS_LOCAL method encodes the client generated uuid_t in terms of > the fixed UUID_SIZE (16 bytes). The fixed size opaque encode and decode > XDR methods are used instead of the less efficient variable sized > methods. > > The RPC program number for the NFS_LOCALIO_PROGRAM is 400122 (as assigned > by IANA, see https://www.iana.org/assignments/rpc-program-numbers/ ): > Linux Kernel Organization 400122 nfslocalio > > Acked-by: Chuck Lever <chuck.lever@oracle.com> > Signed-off-by: Mike Snitzer <snitzer@kernel.org> > [neilb: factored out and simplified single localio protocol] > Co-developed-by: NeilBrown <neil@brown.name> > Signed-off-by: NeilBrown <neil@brown.name> > --- > fs/nfsd/localio.c | 75 +++++++++++++++++++++++++++++++++++++++++++++ > fs/nfsd/nfsd.h | 4 +++ > fs/nfsd/nfssvc.c | 23 +++++++++++++- > include/linux/nfs.h | 7 +++++ > 4 files changed, 108 insertions(+), 1 deletion(-) > > diff --git a/fs/nfsd/localio.c b/fs/nfsd/localio.c > index 4b65c66be129..a192bbe308df 100644 > --- a/fs/nfsd/localio.c > +++ b/fs/nfsd/localio.c > @@ -13,12 +13,15 @@ > #include <linux/nfs.h> > #include <linux/nfs_common.h> > #include <linux/nfslocalio.h> > +#include <linux/nfs_fs.h> > +#include <linux/nfs_xdr.h> > #include <linux/string.h> > > #include "nfsd.h" > #include "vfs.h" > #include "netns.h" > #include "filecache.h" > +#include "cache.h" > > /** > * nfsd_open_local_fh - lookup a local filehandle @nfs_fh and map to nfsd_file > @@ -103,3 +106,75 @@ EXPORT_SYMBOL_GPL(nfsd_open_local_fh); > > /* Compile time type checking, not used by anything */ > static nfs_to_nfsd_open_local_fh_t __maybe_unused nfsd_open_local_fh_typecheck = nfsd_open_local_fh; > + > +/* > + * UUID_IS_LOCAL XDR functions > + */ > + > +static __be32 localio_proc_null(struct svc_rqst *rqstp) > +{ > + return rpc_success; > +} > + > +struct localio_uuidarg { > + uuid_t uuid; > +}; > + > +static __be32 localio_proc_uuid_is_local(struct svc_rqst *rqstp) > +{ > + struct localio_uuidarg *argp = rqstp->rq_argp; > + > + (void) nfs_uuid_is_local(&argp->uuid, SVC_NET(rqstp), > + rqstp->rq_client); > + > + return rpc_success; > +} > + > +static bool localio_decode_uuidarg(struct svc_rqst *rqstp, > + struct xdr_stream *xdr) > +{ > + struct localio_uuidarg *argp = rqstp->rq_argp; > + u8 uuid[UUID_SIZE]; > + > + if (decode_opaque_fixed(xdr, uuid, UUID_SIZE)) > + return false; > + import_uuid(&argp->uuid, uuid); > + > + return true; > +} > + > +static const struct svc_procedure localio_procedures1[] = { > + [LOCALIOPROC_NULL] = { > + .pc_func = localio_proc_null, > + .pc_decode = nfssvc_decode_voidarg, > + .pc_encode = nfssvc_encode_voidres, > + .pc_argsize = sizeof(struct nfsd_voidargs), > + .pc_ressize = sizeof(struct nfsd_voidres), > + .pc_cachetype = RC_NOCACHE, > + .pc_xdrressize = 0, > + .pc_name = "NULL", > + }, > + [LOCALIOPROC_UUID_IS_LOCAL] = { > + .pc_func = localio_proc_uuid_is_local, > + .pc_decode = localio_decode_uuidarg, > + .pc_encode = nfssvc_encode_voidres, > + .pc_argsize = sizeof(struct localio_uuidarg), > + .pc_argzero = sizeof(struct localio_uuidarg), > + .pc_ressize = sizeof(struct nfsd_voidres), > + .pc_cachetype = RC_NOCACHE, > + .pc_name = "UUID_IS_LOCAL", > + }, > +}; > + > +#define LOCALIO_NR_PROCEDURES ARRAY_SIZE(localio_procedures1) > +static DEFINE_PER_CPU_ALIGNED(unsigned long, > + localio_count[LOCALIO_NR_PROCEDURES]); > +const struct svc_version localio_version1 = { > + .vs_vers = 1, > + .vs_nproc = LOCALIO_NR_PROCEDURES, > + .vs_proc = localio_procedures1, > + .vs_dispatch = nfsd_dispatch, > + .vs_count = localio_count, > + .vs_xdrsize = XDR_QUADLEN(UUID_SIZE), > + .vs_hidden = true, > +}; > diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h > index b0d3e82d6dcd..232a873dc53a 100644 > --- a/fs/nfsd/nfsd.h > +++ b/fs/nfsd/nfsd.h > @@ -146,6 +146,10 @@ extern const struct svc_version nfsd_acl_version3; > #endif > #endif > > +#if IS_ENABLED(CONFIG_NFSD_LOCALIO) > +extern const struct svc_version localio_version1; > +#endif > + > struct nfsd_net; > > enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; > diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c > index 13c69aa40d1c..eec4a9803c4a 100644 > --- a/fs/nfsd/nfssvc.c > +++ b/fs/nfsd/nfssvc.c > @@ -80,6 +80,15 @@ DEFINE_SPINLOCK(nfsd_drc_lock); > unsigned long nfsd_drc_max_mem; > unsigned long nfsd_drc_mem_used; > > +#if IS_ENABLED(CONFIG_NFSD_LOCALIO) > +static const struct svc_version *localio_versions[] = { > + [1] = &localio_version1, > +}; > + > +#define NFSD_LOCALIO_NRVERS ARRAY_SIZE(localio_versions) > + > +#endif /* CONFIG_NFSD_LOCALIO */ > + > #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) > static const struct svc_version *nfsd_acl_version[] = { > # if defined(CONFIG_NFSD_V2_ACL) > @@ -128,6 +137,18 @@ struct svc_program nfsd_programs[] = { > .pg_rpcbind_set = nfsd_acl_rpcbind_set, > }, > #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ > +#if IS_ENABLED(CONFIG_NFSD_LOCALIO) > + { > + .pg_prog = NFS_LOCALIO_PROGRAM, > + .pg_nvers = NFSD_LOCALIO_NRVERS, > + .pg_vers = localio_versions, > + .pg_name = "nfslocalio", > + .pg_class = "nfsd", > + .pg_authenticate = svc_set_client, > + .pg_init_request = svc_generic_init_request, > + .pg_rpcbind_set = svc_generic_rpcbind_set, > + } > +#endif /* IS_ENABLED(CONFIG_NFSD_LOCALIO) */ > }; > > bool nfsd_support_version(int vers) > @@ -949,7 +970,7 @@ nfsd(void *vrqstp) > } > > /** > - * nfsd_dispatch - Process an NFS or NFSACL Request > + * nfsd_dispatch - Process an NFS or NFSACL or LOCALIO Request > * @rqstp: incoming request > * > * This RPC dispatcher integrates the NFS server's duplicate reply cache. > diff --git a/include/linux/nfs.h b/include/linux/nfs.h > index ceb70a926b95..5ff1a5b3b00c 100644 > --- a/include/linux/nfs.h > +++ b/include/linux/nfs.h > @@ -13,6 +13,13 @@ > #include <linux/crc32.h> > #include <uapi/linux/nfs.h> > > +/* The localio program is entirely private to Linux and is > + * NOT part of the uapi. > + */ > +#define NFS_LOCALIO_PROGRAM 400122 > +#define LOCALIOPROC_NULL 0 > +#define LOCALIOPROC_UUID_IS_LOCAL 1 > + > /* > * This is the kernel NFS client file handle representation > */ Reviewed-by: Jeff Layton <jlayton@kernel.org>
diff --git a/fs/nfsd/localio.c b/fs/nfsd/localio.c index 4b65c66be129..a192bbe308df 100644 --- a/fs/nfsd/localio.c +++ b/fs/nfsd/localio.c @@ -13,12 +13,15 @@ #include <linux/nfs.h> #include <linux/nfs_common.h> #include <linux/nfslocalio.h> +#include <linux/nfs_fs.h> +#include <linux/nfs_xdr.h> #include <linux/string.h> #include "nfsd.h" #include "vfs.h" #include "netns.h" #include "filecache.h" +#include "cache.h" /** * nfsd_open_local_fh - lookup a local filehandle @nfs_fh and map to nfsd_file @@ -103,3 +106,75 @@ EXPORT_SYMBOL_GPL(nfsd_open_local_fh); /* Compile time type checking, not used by anything */ static nfs_to_nfsd_open_local_fh_t __maybe_unused nfsd_open_local_fh_typecheck = nfsd_open_local_fh; + +/* + * UUID_IS_LOCAL XDR functions + */ + +static __be32 localio_proc_null(struct svc_rqst *rqstp) +{ + return rpc_success; +} + +struct localio_uuidarg { + uuid_t uuid; +}; + +static __be32 localio_proc_uuid_is_local(struct svc_rqst *rqstp) +{ + struct localio_uuidarg *argp = rqstp->rq_argp; + + (void) nfs_uuid_is_local(&argp->uuid, SVC_NET(rqstp), + rqstp->rq_client); + + return rpc_success; +} + +static bool localio_decode_uuidarg(struct svc_rqst *rqstp, + struct xdr_stream *xdr) +{ + struct localio_uuidarg *argp = rqstp->rq_argp; + u8 uuid[UUID_SIZE]; + + if (decode_opaque_fixed(xdr, uuid, UUID_SIZE)) + return false; + import_uuid(&argp->uuid, uuid); + + return true; +} + +static const struct svc_procedure localio_procedures1[] = { + [LOCALIOPROC_NULL] = { + .pc_func = localio_proc_null, + .pc_decode = nfssvc_decode_voidarg, + .pc_encode = nfssvc_encode_voidres, + .pc_argsize = sizeof(struct nfsd_voidargs), + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, + .pc_name = "NULL", + }, + [LOCALIOPROC_UUID_IS_LOCAL] = { + .pc_func = localio_proc_uuid_is_local, + .pc_decode = localio_decode_uuidarg, + .pc_encode = nfssvc_encode_voidres, + .pc_argsize = sizeof(struct localio_uuidarg), + .pc_argzero = sizeof(struct localio_uuidarg), + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_name = "UUID_IS_LOCAL", + }, +}; + +#define LOCALIO_NR_PROCEDURES ARRAY_SIZE(localio_procedures1) +static DEFINE_PER_CPU_ALIGNED(unsigned long, + localio_count[LOCALIO_NR_PROCEDURES]); +const struct svc_version localio_version1 = { + .vs_vers = 1, + .vs_nproc = LOCALIO_NR_PROCEDURES, + .vs_proc = localio_procedures1, + .vs_dispatch = nfsd_dispatch, + .vs_count = localio_count, + .vs_xdrsize = XDR_QUADLEN(UUID_SIZE), + .vs_hidden = true, +}; diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index b0d3e82d6dcd..232a873dc53a 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -146,6 +146,10 @@ extern const struct svc_version nfsd_acl_version3; #endif #endif +#if IS_ENABLED(CONFIG_NFSD_LOCALIO) +extern const struct svc_version localio_version1; +#endif + struct nfsd_net; enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 13c69aa40d1c..eec4a9803c4a 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -80,6 +80,15 @@ DEFINE_SPINLOCK(nfsd_drc_lock); unsigned long nfsd_drc_max_mem; unsigned long nfsd_drc_mem_used; +#if IS_ENABLED(CONFIG_NFSD_LOCALIO) +static const struct svc_version *localio_versions[] = { + [1] = &localio_version1, +}; + +#define NFSD_LOCALIO_NRVERS ARRAY_SIZE(localio_versions) + +#endif /* CONFIG_NFSD_LOCALIO */ + #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) static const struct svc_version *nfsd_acl_version[] = { # if defined(CONFIG_NFSD_V2_ACL) @@ -128,6 +137,18 @@ struct svc_program nfsd_programs[] = { .pg_rpcbind_set = nfsd_acl_rpcbind_set, }, #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ +#if IS_ENABLED(CONFIG_NFSD_LOCALIO) + { + .pg_prog = NFS_LOCALIO_PROGRAM, + .pg_nvers = NFSD_LOCALIO_NRVERS, + .pg_vers = localio_versions, + .pg_name = "nfslocalio", + .pg_class = "nfsd", + .pg_authenticate = svc_set_client, + .pg_init_request = svc_generic_init_request, + .pg_rpcbind_set = svc_generic_rpcbind_set, + } +#endif /* IS_ENABLED(CONFIG_NFSD_LOCALIO) */ }; bool nfsd_support_version(int vers) @@ -949,7 +970,7 @@ nfsd(void *vrqstp) } /** - * nfsd_dispatch - Process an NFS or NFSACL Request + * nfsd_dispatch - Process an NFS or NFSACL or LOCALIO Request * @rqstp: incoming request * * This RPC dispatcher integrates the NFS server's duplicate reply cache. diff --git a/include/linux/nfs.h b/include/linux/nfs.h index ceb70a926b95..5ff1a5b3b00c 100644 --- a/include/linux/nfs.h +++ b/include/linux/nfs.h @@ -13,6 +13,13 @@ #include <linux/crc32.h> #include <uapi/linux/nfs.h> +/* The localio program is entirely private to Linux and is + * NOT part of the uapi. + */ +#define NFS_LOCALIO_PROGRAM 400122 +#define LOCALIOPROC_NULL 0 +#define LOCALIOPROC_UUID_IS_LOCAL 1 + /* * This is the kernel NFS client file handle representation */