restore lost packages from 0.2.3 + fix overwritten 0.2.4 files
- Restore 29 recipe symlinks (libdrm, qtbase, dbus, sddm, pipewire, etc.) - Restore 33 patches (KDE, libdrm, mesa, pipewire, sddm, wireplumber) - Restore 20+ local/scripts (audit, lint, test, build helpers) - Restore src/cook/scheduler.rs, status.rs, gnu-config/ - Restore scripts/patch-inclusion-gate.sh, run_mini1.sh, validate-collision-log.sh - Recover TLC source from HEAD (was overwritten by 0.2.3 checkout) - Recover 11 local/docs plans from HEAD (were overwritten) - Recover qt6-wayland-smoke symlink from HEAD - Fix MOTD: remove garbled ASCII art, use clean text - Update version: 0.2.0 -> 0.2.4 in os-release, motd, config - Reduce filesystem_size: 1536 -> 512 MiB - Add ABSOLUTE RULE to AGENTS.md: never delete/ignore packages - Reduce pcid scheme log verbosity: info -> debug
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/addr.h
|
||||
*
|
||||
* Various routines for copying and comparing sockaddrs and for
|
||||
* converting them to and from presentation format.
|
||||
*/
|
||||
#ifndef _LINUX_SUNRPC_ADDR_H
|
||||
#define _LINUX_SUNRPC_ADDR_H
|
||||
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <net/ipv6.h>
|
||||
|
||||
size_t rpc_ntop(const struct sockaddr *, char *, const size_t);
|
||||
size_t rpc_pton(struct net *, const char *, const size_t,
|
||||
struct sockaddr *, const size_t);
|
||||
char * rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t);
|
||||
size_t rpc_uaddr2sockaddr(struct net *, const char *, const size_t,
|
||||
struct sockaddr *, const size_t);
|
||||
|
||||
static inline unsigned short rpc_get_port(const struct sockaddr *sap)
|
||||
{
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
return ntohs(((struct sockaddr_in *)sap)->sin_port);
|
||||
case AF_INET6:
|
||||
return ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rpc_set_port(struct sockaddr *sap,
|
||||
const unsigned short port)
|
||||
{
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)sap)->sin_port = htons(port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define IPV6_SCOPE_DELIMITER '%'
|
||||
#define IPV6_SCOPE_ID_LEN sizeof("%nnnnnnnnnn")
|
||||
|
||||
static inline bool rpc_cmp_addr4(const struct sockaddr *sap1,
|
||||
const struct sockaddr *sap2)
|
||||
{
|
||||
const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1;
|
||||
const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2;
|
||||
|
||||
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
|
||||
}
|
||||
|
||||
static inline bool __rpc_copy_addr4(struct sockaddr *dst,
|
||||
const struct sockaddr *src)
|
||||
{
|
||||
const struct sockaddr_in *ssin = (struct sockaddr_in *) src;
|
||||
struct sockaddr_in *dsin = (struct sockaddr_in *) dst;
|
||||
|
||||
dsin->sin_family = ssin->sin_family;
|
||||
dsin->sin_addr.s_addr = ssin->sin_addr.s_addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static inline bool rpc_cmp_addr6(const struct sockaddr *sap1,
|
||||
const struct sockaddr *sap2)
|
||||
{
|
||||
const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
|
||||
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
|
||||
|
||||
if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
|
||||
return false;
|
||||
else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL)
|
||||
return sin1->sin6_scope_id == sin2->sin6_scope_id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool __rpc_copy_addr6(struct sockaddr *dst,
|
||||
const struct sockaddr *src)
|
||||
{
|
||||
const struct sockaddr_in6 *ssin6 = (const struct sockaddr_in6 *) src;
|
||||
struct sockaddr_in6 *dsin6 = (struct sockaddr_in6 *) dst;
|
||||
|
||||
dsin6->sin6_family = ssin6->sin6_family;
|
||||
dsin6->sin6_addr = ssin6->sin6_addr;
|
||||
dsin6->sin6_scope_id = ssin6->sin6_scope_id;
|
||||
return true;
|
||||
}
|
||||
#else /* !(IS_ENABLED(CONFIG_IPV6) */
|
||||
static inline bool rpc_cmp_addr6(const struct sockaddr *sap1,
|
||||
const struct sockaddr *sap2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool __rpc_copy_addr6(struct sockaddr *dst,
|
||||
const struct sockaddr *src)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* !(IS_ENABLED(CONFIG_IPV6) */
|
||||
|
||||
/**
|
||||
* rpc_cmp_addr - compare the address portion of two sockaddrs.
|
||||
* @sap1: first sockaddr
|
||||
* @sap2: second sockaddr
|
||||
*
|
||||
* Just compares the family and address portion. Ignores port, but
|
||||
* compares the scope if it's a link-local address.
|
||||
*
|
||||
* Returns true if the addrs are equal, false if they aren't.
|
||||
*/
|
||||
static inline bool rpc_cmp_addr(const struct sockaddr *sap1,
|
||||
const struct sockaddr *sap2)
|
||||
{
|
||||
if (sap1->sa_family == sap2->sa_family) {
|
||||
switch (sap1->sa_family) {
|
||||
case AF_INET:
|
||||
return rpc_cmp_addr4(sap1, sap2);
|
||||
case AF_INET6:
|
||||
return rpc_cmp_addr6(sap1, sap2);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_cmp_addr_port - compare the address and port number of two sockaddrs.
|
||||
* @sap1: first sockaddr
|
||||
* @sap2: second sockaddr
|
||||
*/
|
||||
static inline bool rpc_cmp_addr_port(const struct sockaddr *sap1,
|
||||
const struct sockaddr *sap2)
|
||||
{
|
||||
if (!rpc_cmp_addr(sap1, sap2))
|
||||
return false;
|
||||
return rpc_get_port(sap1) == rpc_get_port(sap2);
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_copy_addr - copy the address portion of one sockaddr to another
|
||||
* @dst: destination sockaddr
|
||||
* @src: source sockaddr
|
||||
*
|
||||
* Just copies the address portion and family. Ignores port, scope, etc.
|
||||
* Caller is responsible for making certain that dst is large enough to hold
|
||||
* the address in src. Returns true if address family is supported. Returns
|
||||
* false otherwise.
|
||||
*/
|
||||
static inline bool rpc_copy_addr(struct sockaddr *dst,
|
||||
const struct sockaddr *src)
|
||||
{
|
||||
switch (src->sa_family) {
|
||||
case AF_INET:
|
||||
return __rpc_copy_addr4(dst, src);
|
||||
case AF_INET6:
|
||||
return __rpc_copy_addr6(dst, src);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_get_scope_id - return scopeid for a given sockaddr
|
||||
* @sa: sockaddr to get scopeid from
|
||||
*
|
||||
* Returns the value of the sin6_scope_id for AF_INET6 addrs, or 0 if
|
||||
* not an AF_INET6 address.
|
||||
*/
|
||||
static inline u32 rpc_get_scope_id(const struct sockaddr *sa)
|
||||
{
|
||||
if (sa->sa_family != AF_INET6)
|
||||
return 0;
|
||||
|
||||
return ((struct sockaddr_in6 *) sa)->sin6_scope_id;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_SUNRPC_ADDR_H */
|
||||
@@ -0,0 +1,197 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/auth.h
|
||||
*
|
||||
* Declarations for the RPC client authentication machinery.
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_AUTH_H
|
||||
#define _LINUX_SUNRPC_AUTH_H
|
||||
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/sunrpc/msg_prot.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/uidgid.h>
|
||||
#include <linux/utsname.h>
|
||||
|
||||
/*
|
||||
* Maximum size of AUTH_NONE authentication information, in XDR words.
|
||||
*/
|
||||
#define NUL_CALLSLACK (4)
|
||||
#define NUL_REPLYSLACK (2)
|
||||
|
||||
/*
|
||||
* Size of the nodename buffer. RFC1831 specifies a hard limit of 255 bytes,
|
||||
* but Linux hostnames are actually limited to __NEW_UTS_LEN bytes.
|
||||
*/
|
||||
#define UNX_MAXNODENAME __NEW_UTS_LEN
|
||||
#define UNX_CALLSLACK (21 + XDR_QUADLEN(UNX_MAXNODENAME))
|
||||
#define UNX_NGROUPS 16
|
||||
|
||||
struct rpcsec_gss_info;
|
||||
|
||||
struct auth_cred {
|
||||
const struct cred *cred;
|
||||
const char *principal; /* If present, this is a machine credential */
|
||||
};
|
||||
|
||||
/*
|
||||
* Client user credentials
|
||||
*/
|
||||
struct rpc_auth;
|
||||
struct rpc_credops;
|
||||
struct rpc_cred {
|
||||
struct hlist_node cr_hash; /* hash chain */
|
||||
struct list_head cr_lru; /* lru garbage collection */
|
||||
struct rcu_head cr_rcu;
|
||||
struct rpc_auth * cr_auth;
|
||||
const struct rpc_credops *cr_ops;
|
||||
unsigned long cr_expire; /* when to gc */
|
||||
unsigned long cr_flags; /* various flags */
|
||||
refcount_t cr_count; /* ref count */
|
||||
const struct cred *cr_cred;
|
||||
|
||||
/* per-flavor data */
|
||||
};
|
||||
#define RPCAUTH_CRED_NEW 0
|
||||
#define RPCAUTH_CRED_UPTODATE 1
|
||||
#define RPCAUTH_CRED_HASHED 2
|
||||
#define RPCAUTH_CRED_NEGATIVE 3
|
||||
|
||||
const struct cred *rpc_machine_cred(void);
|
||||
|
||||
/*
|
||||
* Client authentication handle
|
||||
*/
|
||||
struct rpc_cred_cache;
|
||||
struct rpc_authops;
|
||||
struct rpc_auth {
|
||||
unsigned int au_cslack; /* call cred size estimate */
|
||||
unsigned int au_rslack; /* reply cred size estimate */
|
||||
unsigned int au_verfsize; /* size of reply verifier */
|
||||
unsigned int au_ralign; /* words before UL header */
|
||||
|
||||
unsigned long au_flags;
|
||||
const struct rpc_authops *au_ops;
|
||||
rpc_authflavor_t au_flavor; /* pseudoflavor (note may
|
||||
* differ from the flavor in
|
||||
* au_ops->au_flavor in gss
|
||||
* case) */
|
||||
refcount_t au_count; /* Reference counter */
|
||||
|
||||
struct rpc_cred_cache * au_credcache;
|
||||
/* per-flavor data */
|
||||
};
|
||||
|
||||
/* rpc_auth au_flags */
|
||||
#define RPCAUTH_AUTH_DATATOUCH (1)
|
||||
#define RPCAUTH_AUTH_UPDATE_SLACK (2)
|
||||
|
||||
struct rpc_auth_create_args {
|
||||
rpc_authflavor_t pseudoflavor;
|
||||
const char *target_name;
|
||||
};
|
||||
|
||||
/* Flags for rpcauth_lookupcred() */
|
||||
#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */
|
||||
#define RPCAUTH_LOOKUP_ASYNC 0x02 /* Don't block waiting for memory */
|
||||
|
||||
/*
|
||||
* Client authentication ops
|
||||
*/
|
||||
struct rpc_authops {
|
||||
struct module *owner;
|
||||
rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */
|
||||
char * au_name;
|
||||
struct rpc_auth * (*create)(const struct rpc_auth_create_args *,
|
||||
struct rpc_clnt *);
|
||||
void (*destroy)(struct rpc_auth *);
|
||||
|
||||
int (*hash_cred)(struct auth_cred *, unsigned int);
|
||||
struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
|
||||
struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int, gfp_t);
|
||||
rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *);
|
||||
int (*flavor2info)(rpc_authflavor_t,
|
||||
struct rpcsec_gss_info *);
|
||||
int (*key_timeout)(struct rpc_auth *,
|
||||
struct rpc_cred *);
|
||||
int (*ping)(struct rpc_clnt *clnt);
|
||||
};
|
||||
|
||||
struct rpc_credops {
|
||||
const char * cr_name; /* Name of the auth flavour */
|
||||
int (*cr_init)(struct rpc_auth *, struct rpc_cred *);
|
||||
void (*crdestroy)(struct rpc_cred *);
|
||||
|
||||
int (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
|
||||
int (*crmarshal)(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
int (*crrefresh)(struct rpc_task *);
|
||||
int (*crvalidate)(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
int (*crwrap_req)(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
int (*crunwrap_resp)(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
int (*crkey_timeout)(struct rpc_cred *);
|
||||
char * (*crstringify_acceptor)(struct rpc_cred *);
|
||||
bool (*crneed_reencode)(struct rpc_task *);
|
||||
};
|
||||
|
||||
extern const struct rpc_authops authunix_ops;
|
||||
extern const struct rpc_authops authnull_ops;
|
||||
extern const struct rpc_authops authtls_ops;
|
||||
|
||||
int __init rpc_init_authunix(void);
|
||||
int __init rpcauth_init_module(void);
|
||||
void rpcauth_remove_module(void);
|
||||
void rpc_destroy_authunix(void);
|
||||
|
||||
int rpcauth_register(const struct rpc_authops *);
|
||||
int rpcauth_unregister(const struct rpc_authops *);
|
||||
struct rpc_auth * rpcauth_create(const struct rpc_auth_create_args *,
|
||||
struct rpc_clnt *);
|
||||
void rpcauth_release(struct rpc_auth *);
|
||||
rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t,
|
||||
struct rpcsec_gss_info *);
|
||||
int rpcauth_get_gssinfo(rpc_authflavor_t,
|
||||
struct rpcsec_gss_info *);
|
||||
struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int, gfp_t);
|
||||
void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
|
||||
struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int);
|
||||
void put_rpccred(struct rpc_cred *);
|
||||
int rpcauth_marshcred(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
int rpcauth_checkverf(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
int rpcauth_wrap_req_encode(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
int rpcauth_wrap_req(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
int rpcauth_unwrap_resp_decode(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
int rpcauth_unwrap_resp(struct rpc_task *task,
|
||||
struct xdr_stream *xdr);
|
||||
bool rpcauth_xmit_need_reencode(struct rpc_task *task);
|
||||
int rpcauth_refreshcred(struct rpc_task *);
|
||||
void rpcauth_invalcred(struct rpc_task *);
|
||||
int rpcauth_uptodatecred(struct rpc_task *);
|
||||
int rpcauth_init_credcache(struct rpc_auth *);
|
||||
void rpcauth_destroy_credcache(struct rpc_auth *);
|
||||
void rpcauth_clear_credcache(struct rpc_cred_cache *);
|
||||
char * rpcauth_stringify_acceptor(struct rpc_cred *);
|
||||
|
||||
static inline
|
||||
struct rpc_cred *get_rpccred(struct rpc_cred *cred)
|
||||
{
|
||||
if (cred != NULL && refcount_inc_not_zero(&cred->cr_count))
|
||||
return cred;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_SUNRPC_AUTH_H */
|
||||
@@ -0,0 +1,93 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/auth_gss.h
|
||||
*
|
||||
* Declarations for RPCSEC_GSS
|
||||
*
|
||||
* Dug Song <dugsong@monkey.org>
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
* Bruce Fields <bfields@umich.edu>
|
||||
* Copyright (c) 2000 The Regents of the University of Michigan
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_AUTH_GSS_H
|
||||
#define _LINUX_SUNRPC_AUTH_GSS_H
|
||||
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/sunrpc/auth.h>
|
||||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/sunrpc/gss_api.h>
|
||||
|
||||
#define RPC_GSS_VERSION 1
|
||||
|
||||
#define MAXSEQ 0x80000000 /* maximum legal sequence number, from rfc 2203 */
|
||||
|
||||
enum rpc_gss_proc {
|
||||
RPC_GSS_PROC_DATA = 0,
|
||||
RPC_GSS_PROC_INIT = 1,
|
||||
RPC_GSS_PROC_CONTINUE_INIT = 2,
|
||||
RPC_GSS_PROC_DESTROY = 3
|
||||
};
|
||||
|
||||
enum rpc_gss_svc {
|
||||
RPC_GSS_SVC_NONE = 1,
|
||||
RPC_GSS_SVC_INTEGRITY = 2,
|
||||
RPC_GSS_SVC_PRIVACY = 3
|
||||
};
|
||||
|
||||
/* on-the-wire gss cred: */
|
||||
struct rpc_gss_wire_cred {
|
||||
u32 gc_v; /* version */
|
||||
u32 gc_proc; /* control procedure */
|
||||
u32 gc_seq; /* sequence number */
|
||||
u32 gc_svc; /* service */
|
||||
struct xdr_netobj gc_ctx; /* context handle */
|
||||
};
|
||||
|
||||
/* on-the-wire gss verifier: */
|
||||
struct rpc_gss_wire_verf {
|
||||
u32 gv_flavor;
|
||||
struct xdr_netobj gv_verf;
|
||||
};
|
||||
|
||||
/* return from gss NULL PROC init sec context */
|
||||
struct rpc_gss_init_res {
|
||||
struct xdr_netobj gr_ctx; /* context handle */
|
||||
u32 gr_major; /* major status */
|
||||
u32 gr_minor; /* minor status */
|
||||
u32 gr_win; /* sequence window */
|
||||
struct xdr_netobj gr_token; /* token */
|
||||
};
|
||||
|
||||
/* The gss_cl_ctx struct holds all the information the rpcsec_gss client
|
||||
* code needs to know about a single security context. In particular,
|
||||
* gc_gss_ctx is the context handle that is used to do gss-api calls, while
|
||||
* gc_wire_ctx is the context handle that is used to identify the context on
|
||||
* the wire when communicating with a server. */
|
||||
|
||||
struct gss_cl_ctx {
|
||||
refcount_t count;
|
||||
enum rpc_gss_proc gc_proc;
|
||||
u32 gc_seq;
|
||||
u32 gc_seq_xmit;
|
||||
spinlock_t gc_seq_lock;
|
||||
struct gss_ctx *gc_gss_ctx;
|
||||
struct xdr_netobj gc_wire_ctx;
|
||||
struct xdr_netobj gc_acceptor;
|
||||
u32 gc_win;
|
||||
unsigned long gc_expiry;
|
||||
struct rcu_head gc_rcu;
|
||||
};
|
||||
|
||||
struct gss_upcall_msg;
|
||||
struct gss_cred {
|
||||
struct rpc_cred gc_base;
|
||||
enum rpc_gss_svc gc_service;
|
||||
struct gss_cl_ctx __rcu *gc_ctx;
|
||||
struct gss_upcall_msg *gc_upcall;
|
||||
const char *gc_principal;
|
||||
unsigned long gc_upcall_timestamp;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_SUNRPC_AUTH_GSS_H */
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/******************************************************************************
|
||||
|
||||
(c) 2008 NetApp. All Rights Reserved.
|
||||
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Functions to create and manage the backchannel
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_BC_XPRT_H
|
||||
#define _LINUX_SUNRPC_BC_XPRT_H
|
||||
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
|
||||
#ifdef CONFIG_SUNRPC_BACKCHANNEL
|
||||
struct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid);
|
||||
void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied);
|
||||
void xprt_init_bc_request(struct rpc_rqst *req, struct rpc_task *task,
|
||||
const struct rpc_timeout *to);
|
||||
void xprt_free_bc_request(struct rpc_rqst *req);
|
||||
int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
|
||||
void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs);
|
||||
void xprt_enqueue_bc_request(struct rpc_rqst *req);
|
||||
|
||||
/* Socket backchannel transport methods */
|
||||
int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs);
|
||||
void xprt_destroy_bc(struct rpc_xprt *xprt, unsigned int max_reqs);
|
||||
void xprt_free_bc_rqst(struct rpc_rqst *req);
|
||||
unsigned int xprt_bc_max_slots(struct rpc_xprt *xprt);
|
||||
void xprt_svc_destroy_nullify_bc(struct rpc_xprt *xprt, struct svc_serv **serv);
|
||||
|
||||
/*
|
||||
* Determine if a shared backchannel is in use
|
||||
*/
|
||||
static inline bool svc_is_backchannel(const struct svc_rqst *rqstp)
|
||||
{
|
||||
return rqstp->rq_server->sv_bc_enabled;
|
||||
}
|
||||
|
||||
static inline void set_bc_enabled(struct svc_serv *serv)
|
||||
{
|
||||
serv->sv_bc_enabled = true;
|
||||
}
|
||||
#else /* CONFIG_SUNRPC_BACKCHANNEL */
|
||||
static inline int xprt_setup_backchannel(struct rpc_xprt *xprt,
|
||||
unsigned int min_reqs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void xprt_destroy_backchannel(struct rpc_xprt *xprt,
|
||||
unsigned int max_reqs)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool svc_is_backchannel(const struct svc_rqst *rqstp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void set_bc_enabled(struct svc_serv *serv)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void xprt_free_bc_request(struct rpc_rqst *req)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void xprt_svc_destroy_nullify_bc(struct rpc_xprt *xprt, struct svc_serv **serv)
|
||||
{
|
||||
svc_destroy(serv);
|
||||
}
|
||||
#endif /* CONFIG_SUNRPC_BACKCHANNEL */
|
||||
#endif /* _LINUX_SUNRPC_BC_XPRT_H */
|
||||
@@ -0,0 +1,328 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* include/linux/sunrpc/cache.h
|
||||
*
|
||||
* Generic code for various authentication-related caches
|
||||
* used by sunrpc clients and servers.
|
||||
*
|
||||
* Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_CACHE_H_
|
||||
#define _LINUX_SUNRPC_CACHE_H_
|
||||
|
||||
#include <linux/kref.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
/*
|
||||
* Each cache requires:
|
||||
* - A 'struct cache_detail' which contains information specific to the cache
|
||||
* for common code to use.
|
||||
* - An item structure that must contain a "struct cache_head"
|
||||
* - A lookup function defined using DefineCacheLookup
|
||||
* - A 'put' function that can release a cache item. It will only
|
||||
* be called after cache_put has succeed, so there are guarantee
|
||||
* to be no references.
|
||||
* - A function to calculate a hash of an item's key.
|
||||
*
|
||||
* as well as assorted code fragments (e.g. compare keys) and numbers
|
||||
* (e.g. hash size, goal_age, etc).
|
||||
*
|
||||
* Each cache must be registered so that it can be cleaned regularly.
|
||||
* When the cache is unregistered, it is flushed completely.
|
||||
*
|
||||
* Entries have a ref count and a 'hashed' flag which counts the existence
|
||||
* in the hash table.
|
||||
* We only expire entries when refcount is zero.
|
||||
* Existence in the cache is counted the refcount.
|
||||
*/
|
||||
|
||||
/* Every cache item has a common header that is used
|
||||
* for expiring and refreshing entries.
|
||||
*
|
||||
*/
|
||||
struct cache_head {
|
||||
struct hlist_node cache_list;
|
||||
time64_t expiry_time; /* After time expiry_time, don't use
|
||||
* the data */
|
||||
time64_t last_refresh; /* If CACHE_PENDING, this is when upcall was
|
||||
* sent, else this is when update was
|
||||
* received, though it is alway set to
|
||||
* be *after* ->flush_time.
|
||||
*/
|
||||
struct kref ref;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
/* cache_head.flags */
|
||||
enum {
|
||||
CACHE_VALID, /* Entry contains valid data */
|
||||
CACHE_NEGATIVE, /* Negative entry - there is no match for the key */
|
||||
CACHE_PENDING, /* An upcall has been sent but no reply received yet*/
|
||||
CACHE_CLEANED, /* Entry has been cleaned from cache */
|
||||
};
|
||||
|
||||
#define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */
|
||||
|
||||
struct cache_detail {
|
||||
struct module * owner;
|
||||
int hash_size;
|
||||
struct hlist_head * hash_table;
|
||||
spinlock_t hash_lock;
|
||||
|
||||
char *name;
|
||||
void (*cache_put)(struct kref *);
|
||||
|
||||
int (*cache_upcall)(struct cache_detail *,
|
||||
struct cache_head *);
|
||||
|
||||
void (*cache_request)(struct cache_detail *cd,
|
||||
struct cache_head *ch,
|
||||
char **bpp, int *blen);
|
||||
|
||||
int (*cache_parse)(struct cache_detail *,
|
||||
char *buf, int len);
|
||||
|
||||
int (*cache_show)(struct seq_file *m,
|
||||
struct cache_detail *cd,
|
||||
struct cache_head *h);
|
||||
void (*warn_no_listener)(struct cache_detail *cd,
|
||||
int has_died);
|
||||
|
||||
struct cache_head * (*alloc)(void);
|
||||
void (*flush)(void);
|
||||
int (*match)(struct cache_head *orig, struct cache_head *new);
|
||||
void (*init)(struct cache_head *orig, struct cache_head *new);
|
||||
void (*update)(struct cache_head *orig, struct cache_head *new);
|
||||
|
||||
/* fields below this comment are for internal use
|
||||
* and should not be touched by cache owners
|
||||
*/
|
||||
time64_t flush_time; /* flush all cache items with
|
||||
* last_refresh at or earlier
|
||||
* than this. last_refresh
|
||||
* is never set at or earlier
|
||||
* than this.
|
||||
*/
|
||||
struct list_head others;
|
||||
time64_t nextcheck;
|
||||
int entries;
|
||||
|
||||
/* fields for communication over channel */
|
||||
struct list_head requests;
|
||||
struct list_head readers;
|
||||
spinlock_t queue_lock;
|
||||
wait_queue_head_t queue_wait;
|
||||
u64 next_seqno;
|
||||
|
||||
atomic_t writers; /* how many time is /channel open */
|
||||
time64_t last_close; /* if no writers, when did last close */
|
||||
time64_t last_warn; /* when we last warned about no writers */
|
||||
|
||||
union {
|
||||
struct proc_dir_entry *procfs;
|
||||
struct dentry *pipefs;
|
||||
};
|
||||
struct net *net;
|
||||
};
|
||||
|
||||
/* this must be embedded in any request structure that
|
||||
* identifies an object that will want a callback on
|
||||
* a cache fill
|
||||
*/
|
||||
struct cache_req {
|
||||
struct cache_deferred_req *(*defer)(struct cache_req *req);
|
||||
unsigned long thread_wait; /* How long (jiffies) we can block the
|
||||
* current thread to wait for updates.
|
||||
*/
|
||||
};
|
||||
|
||||
/* this must be embedded in a deferred_request that is being
|
||||
* delayed awaiting cache-fill
|
||||
*/
|
||||
struct cache_deferred_req {
|
||||
struct hlist_node hash; /* on hash chain */
|
||||
struct list_head recent; /* on fifo */
|
||||
struct cache_head *item; /* cache item we wait on */
|
||||
void *owner; /* we might need to discard all defered requests
|
||||
* owned by someone */
|
||||
void (*revisit)(struct cache_deferred_req *req,
|
||||
int too_many);
|
||||
};
|
||||
|
||||
/*
|
||||
* timestamps kept in the cache are expressed in seconds
|
||||
* since boot. This is the best for measuring differences in
|
||||
* real time.
|
||||
* This reimplemnts ktime_get_boottime_seconds() in a slightly
|
||||
* faster but less accurate way. When we end up converting
|
||||
* back to wallclock (CLOCK_REALTIME), that error often
|
||||
* cancels out during the reverse operation.
|
||||
*/
|
||||
static inline time64_t seconds_since_boot(void)
|
||||
{
|
||||
struct timespec64 boot;
|
||||
getboottime64(&boot);
|
||||
return ktime_get_real_seconds() - boot.tv_sec;
|
||||
}
|
||||
|
||||
static inline time64_t convert_to_wallclock(time64_t sinceboot)
|
||||
{
|
||||
struct timespec64 boot;
|
||||
getboottime64(&boot);
|
||||
return boot.tv_sec + sinceboot;
|
||||
}
|
||||
|
||||
extern const struct file_operations cache_file_operations_pipefs;
|
||||
extern const struct file_operations content_file_operations_pipefs;
|
||||
extern const struct file_operations cache_flush_operations_pipefs;
|
||||
|
||||
extern struct cache_head *
|
||||
sunrpc_cache_lookup_rcu(struct cache_detail *detail,
|
||||
struct cache_head *key, int hash);
|
||||
extern struct cache_head *
|
||||
sunrpc_cache_update(struct cache_detail *detail,
|
||||
struct cache_head *new, struct cache_head *old, int hash);
|
||||
|
||||
extern int
|
||||
sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h);
|
||||
extern int
|
||||
sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail,
|
||||
struct cache_head *h);
|
||||
|
||||
|
||||
extern void cache_clean_deferred(void *owner);
|
||||
|
||||
static inline struct cache_head *cache_get(struct cache_head *h)
|
||||
{
|
||||
kref_get(&h->ref);
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline struct cache_head *cache_get_rcu(struct cache_head *h)
|
||||
{
|
||||
if (kref_get_unless_zero(&h->ref))
|
||||
return h;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void cache_put(struct cache_head *h, struct cache_detail *cd)
|
||||
{
|
||||
if (kref_read(&h->ref) <= 2 &&
|
||||
h->expiry_time < cd->nextcheck)
|
||||
cd->nextcheck = h->expiry_time;
|
||||
kref_put(&h->ref, cd->cache_put);
|
||||
}
|
||||
|
||||
static inline bool cache_is_expired(struct cache_detail *detail, struct cache_head *h)
|
||||
{
|
||||
if (h->expiry_time < seconds_since_boot())
|
||||
return true;
|
||||
if (!test_bit(CACHE_VALID, &h->flags))
|
||||
return false;
|
||||
return detail->flush_time >= h->last_refresh;
|
||||
}
|
||||
|
||||
extern int cache_check_rcu(struct cache_detail *detail,
|
||||
struct cache_head *h, struct cache_req *rqstp);
|
||||
extern int cache_check(struct cache_detail *detail,
|
||||
struct cache_head *h, struct cache_req *rqstp);
|
||||
extern void cache_flush(void);
|
||||
extern void cache_purge(struct cache_detail *detail);
|
||||
#define NEVER (0x7FFFFFFF)
|
||||
extern void __init cache_initialize(void);
|
||||
extern int cache_register_net(struct cache_detail *cd, struct net *net);
|
||||
extern void cache_unregister_net(struct cache_detail *cd, struct net *net);
|
||||
|
||||
extern struct cache_detail *cache_create_net(const struct cache_detail *tmpl, struct net *net);
|
||||
extern void cache_destroy_net(struct cache_detail *cd, struct net *net);
|
||||
|
||||
extern void sunrpc_init_cache_detail(struct cache_detail *cd);
|
||||
extern void sunrpc_destroy_cache_detail(struct cache_detail *cd);
|
||||
extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
|
||||
umode_t, struct cache_detail *);
|
||||
extern void sunrpc_cache_unregister_pipefs(struct cache_detail *);
|
||||
extern void sunrpc_cache_unhash(struct cache_detail *, struct cache_head *);
|
||||
|
||||
/* Must store cache_detail in seq_file->private if using next three functions */
|
||||
extern void *cache_seq_start_rcu(struct seq_file *file, loff_t *pos);
|
||||
extern void *cache_seq_next_rcu(struct seq_file *file, void *p, loff_t *pos);
|
||||
extern void cache_seq_stop_rcu(struct seq_file *file, void *p);
|
||||
|
||||
extern void qword_add(char **bpp, int *lp, char *str);
|
||||
extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
|
||||
extern int qword_get(char **bpp, char *dest, int bufsize);
|
||||
|
||||
static inline int get_int(char **bpp, int *anint)
|
||||
{
|
||||
char buf[50];
|
||||
char *ep;
|
||||
int rv;
|
||||
int len = qword_get(bpp, buf, sizeof(buf));
|
||||
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
if (len == 0)
|
||||
return -ENOENT;
|
||||
|
||||
rv = simple_strtol(buf, &ep, 0);
|
||||
if (*ep)
|
||||
return -EINVAL;
|
||||
|
||||
*anint = rv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int get_uint(char **bpp, unsigned int *anint)
|
||||
{
|
||||
char buf[50];
|
||||
int len = qword_get(bpp, buf, sizeof(buf));
|
||||
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
if (len == 0)
|
||||
return -ENOENT;
|
||||
|
||||
if (kstrtouint(buf, 0, anint))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int get_time(char **bpp, time64_t *time)
|
||||
{
|
||||
char buf[50];
|
||||
long long ll;
|
||||
int len = qword_get(bpp, buf, sizeof(buf));
|
||||
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
if (len == 0)
|
||||
return -ENOENT;
|
||||
|
||||
if (kstrtoll(buf, 0, &ll))
|
||||
return -EINVAL;
|
||||
|
||||
*time = ll;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int get_expiry(char **bpp, time64_t *rvp)
|
||||
{
|
||||
int error;
|
||||
struct timespec64 boot;
|
||||
|
||||
error = get_time(bpp, rvp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
getboottime64(&boot);
|
||||
(*rvp) -= boot.tv_sec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_SUNRPC_CACHE_H_ */
|
||||
@@ -0,0 +1,279 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/clnt.h
|
||||
*
|
||||
* Declarations for the high-level RPC client interface
|
||||
*
|
||||
* Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_CLNT_H
|
||||
#define _LINUX_SUNRPC_CLNT_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
#include <linux/sunrpc/msg_prot.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/sunrpc/auth.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/timer.h>
|
||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||
#include <asm/signal.h>
|
||||
#include <linux/path.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/sunrpc/xprtmultipath.h>
|
||||
|
||||
struct rpc_inode;
|
||||
struct rpc_sysfs_client {
|
||||
struct kobject kobject;
|
||||
struct net *net;
|
||||
struct rpc_clnt *clnt;
|
||||
struct rpc_xprt_switch *xprt_switch;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The high-level client handle
|
||||
*/
|
||||
struct rpc_clnt {
|
||||
refcount_t cl_count; /* Number of references */
|
||||
unsigned int cl_clid; /* client id */
|
||||
struct list_head cl_clients; /* Global list of clients */
|
||||
struct list_head cl_tasks; /* List of tasks */
|
||||
atomic_t cl_pid; /* task PID counter */
|
||||
spinlock_t cl_lock; /* spinlock */
|
||||
struct rpc_xprt __rcu * cl_xprt; /* transport */
|
||||
const struct rpc_procinfo *cl_procinfo; /* procedure info */
|
||||
u32 cl_prog, /* RPC program number */
|
||||
cl_vers, /* RPC version number */
|
||||
cl_maxproc; /* max procedure number */
|
||||
|
||||
struct rpc_auth * cl_auth; /* authenticator */
|
||||
struct rpc_stat * cl_stats; /* per-program statistics */
|
||||
struct rpc_iostats * cl_metrics; /* per-client statistics */
|
||||
|
||||
unsigned int cl_softrtry : 1,/* soft timeouts */
|
||||
cl_softerr : 1,/* Timeouts return errors */
|
||||
cl_discrtry : 1,/* disconnect before retry */
|
||||
cl_noretranstimeo: 1,/* No retransmit timeouts */
|
||||
cl_autobind : 1,/* use getport() */
|
||||
cl_chatty : 1,/* be verbose */
|
||||
cl_shutdown : 1,/* rpc immediate -EIO */
|
||||
cl_netunreach_fatal : 1;
|
||||
/* Treat ENETUNREACH errors as fatal */
|
||||
struct xprtsec_parms cl_xprtsec; /* transport security policy */
|
||||
|
||||
struct rpc_rtt * cl_rtt; /* RTO estimator data */
|
||||
const struct rpc_timeout *cl_timeout; /* Timeout strategy */
|
||||
|
||||
atomic_t cl_swapper; /* swapfile count */
|
||||
int cl_nodelen; /* nodename length */
|
||||
char cl_nodename[UNX_MAXNODENAME+1];
|
||||
struct rpc_pipe_dir_head cl_pipedir_objects;
|
||||
struct rpc_clnt * cl_parent; /* Points to parent of clones */
|
||||
struct rpc_rtt cl_rtt_default;
|
||||
struct rpc_timeout cl_timeout_default;
|
||||
const struct rpc_program *cl_program;
|
||||
const char * cl_principal; /* use for machine cred */
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
struct dentry *cl_debugfs; /* debugfs directory */
|
||||
#endif
|
||||
struct rpc_sysfs_client *cl_sysfs; /* sysfs directory */
|
||||
/* cl_work is only needed after cl_xpi is no longer used,
|
||||
* and that are of similar size
|
||||
*/
|
||||
union {
|
||||
struct rpc_xprt_iter cl_xpi;
|
||||
struct work_struct cl_work;
|
||||
};
|
||||
const struct cred *cl_cred;
|
||||
unsigned int cl_max_connect; /* max number of transports not to the same IP */
|
||||
struct super_block *pipefs_sb;
|
||||
atomic_t cl_task_count;
|
||||
};
|
||||
|
||||
/*
|
||||
* General RPC program info
|
||||
*/
|
||||
#define RPC_MAXVERSION 4
|
||||
struct rpc_program {
|
||||
const char * name; /* protocol name */
|
||||
u32 number; /* program number */
|
||||
unsigned int nrvers; /* number of versions */
|
||||
const struct rpc_version ** version; /* version array */
|
||||
struct rpc_stat * stats; /* statistics */
|
||||
const char * pipe_dir_name; /* path to rpc_pipefs dir */
|
||||
};
|
||||
|
||||
struct rpc_version {
|
||||
u32 number; /* version number */
|
||||
unsigned int nrprocs; /* number of procs */
|
||||
const struct rpc_procinfo *procs; /* procedure array */
|
||||
unsigned int *counts; /* call counts */
|
||||
};
|
||||
|
||||
/*
|
||||
* Procedure information
|
||||
*/
|
||||
struct rpc_procinfo {
|
||||
u32 p_proc; /* RPC procedure number */
|
||||
kxdreproc_t p_encode; /* XDR encode function */
|
||||
kxdrdproc_t p_decode; /* XDR decode function */
|
||||
unsigned int p_arglen; /* argument hdr length (u32) */
|
||||
unsigned int p_replen; /* reply hdr length (u32) */
|
||||
unsigned int p_timer; /* Which RTT timer to use */
|
||||
u32 p_statidx; /* Which procedure to account */
|
||||
const char * p_name; /* name of procedure */
|
||||
};
|
||||
|
||||
struct rpc_create_args {
|
||||
struct net *net;
|
||||
int protocol;
|
||||
struct sockaddr *address;
|
||||
size_t addrsize;
|
||||
struct sockaddr *saddress;
|
||||
const struct rpc_timeout *timeout;
|
||||
const char *servername;
|
||||
const char *nodename;
|
||||
const struct rpc_program *program;
|
||||
struct rpc_stat *stats;
|
||||
u32 prognumber; /* overrides program->number */
|
||||
u32 version;
|
||||
rpc_authflavor_t authflavor;
|
||||
u32 nconnect;
|
||||
unsigned long flags;
|
||||
char *client_name;
|
||||
struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
|
||||
const struct cred *cred;
|
||||
unsigned int max_connect;
|
||||
struct xprtsec_parms xprtsec;
|
||||
unsigned long connect_timeout;
|
||||
unsigned long reconnect_timeout;
|
||||
};
|
||||
|
||||
struct rpc_add_xprt_test {
|
||||
void (*add_xprt_test)(struct rpc_clnt *clnt,
|
||||
struct rpc_xprt *xprt,
|
||||
void *calldata);
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* Values for "flags" field */
|
||||
#define RPC_CLNT_CREATE_HARDRTRY (1UL << 0)
|
||||
#define RPC_CLNT_CREATE_AUTOBIND (1UL << 2)
|
||||
#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 3)
|
||||
#define RPC_CLNT_CREATE_NOPING (1UL << 4)
|
||||
#define RPC_CLNT_CREATE_DISCRTRY (1UL << 5)
|
||||
#define RPC_CLNT_CREATE_QUIET (1UL << 6)
|
||||
#define RPC_CLNT_CREATE_INFINITE_SLOTS (1UL << 7)
|
||||
#define RPC_CLNT_CREATE_NO_IDLE_TIMEOUT (1UL << 8)
|
||||
#define RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT (1UL << 9)
|
||||
#define RPC_CLNT_CREATE_SOFTERR (1UL << 10)
|
||||
#define RPC_CLNT_CREATE_REUSEPORT (1UL << 11)
|
||||
#define RPC_CLNT_CREATE_CONNECTED (1UL << 12)
|
||||
#define RPC_CLNT_CREATE_NETUNREACH_FATAL (1UL << 13)
|
||||
|
||||
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
|
||||
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
|
||||
const struct rpc_program *, u32);
|
||||
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
|
||||
struct rpc_clnt *rpc_clone_client_set_auth(struct rpc_clnt *,
|
||||
rpc_authflavor_t);
|
||||
int rpc_switch_client_transport(struct rpc_clnt *,
|
||||
struct xprt_create *,
|
||||
const struct rpc_timeout *);
|
||||
|
||||
void rpc_shutdown_client(struct rpc_clnt *);
|
||||
void rpc_release_client(struct rpc_clnt *);
|
||||
void rpc_task_release_transport(struct rpc_task *);
|
||||
void rpc_task_release_client(struct rpc_task *);
|
||||
struct rpc_xprt *rpc_task_get_xprt(struct rpc_clnt *clnt,
|
||||
struct rpc_xprt *xprt);
|
||||
|
||||
int rpcb_create_local(struct net *);
|
||||
void rpcb_put_local(struct net *);
|
||||
int rpcb_register(struct net *, u32, u32, int, unsigned short);
|
||||
int rpcb_v4_register(struct net *net, const u32 program,
|
||||
const u32 version,
|
||||
const struct sockaddr *address,
|
||||
const char *netid);
|
||||
void rpcb_getport_async(struct rpc_task *);
|
||||
|
||||
void rpc_prepare_reply_pages(struct rpc_rqst *req, struct page **pages,
|
||||
unsigned int base, unsigned int len,
|
||||
unsigned int hdrsize);
|
||||
void rpc_call_start(struct rpc_task *);
|
||||
int rpc_call_async(struct rpc_clnt *clnt,
|
||||
const struct rpc_message *msg, int flags,
|
||||
const struct rpc_call_ops *tk_ops,
|
||||
void *calldata);
|
||||
int rpc_call_sync(struct rpc_clnt *clnt,
|
||||
const struct rpc_message *msg, int flags);
|
||||
struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred,
|
||||
int flags);
|
||||
int rpc_restart_call_prepare(struct rpc_task *);
|
||||
int rpc_restart_call(struct rpc_task *);
|
||||
void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
|
||||
struct net * rpc_net_ns(struct rpc_clnt *);
|
||||
size_t rpc_max_payload(struct rpc_clnt *);
|
||||
size_t rpc_max_bc_payload(struct rpc_clnt *);
|
||||
unsigned int rpc_num_bc_slots(struct rpc_clnt *);
|
||||
void rpc_force_rebind(struct rpc_clnt *);
|
||||
size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
|
||||
const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
|
||||
int rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);
|
||||
|
||||
int rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt,
|
||||
int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *),
|
||||
void *data);
|
||||
|
||||
int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
|
||||
struct rpc_xprt_switch *xps,
|
||||
struct rpc_xprt *xprt,
|
||||
void *dummy);
|
||||
int rpc_clnt_add_xprt(struct rpc_clnt *, struct xprt_create *,
|
||||
int (*setup)(struct rpc_clnt *,
|
||||
struct rpc_xprt_switch *,
|
||||
struct rpc_xprt *,
|
||||
void *),
|
||||
void *data);
|
||||
void rpc_set_connect_timeout(struct rpc_clnt *clnt,
|
||||
unsigned long connect_timeout,
|
||||
unsigned long reconnect_timeout);
|
||||
|
||||
int rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *,
|
||||
struct rpc_xprt_switch *,
|
||||
struct rpc_xprt *,
|
||||
void *);
|
||||
void rpc_clnt_manage_trunked_xprts(struct rpc_clnt *);
|
||||
void rpc_clnt_probe_trunked_xprts(struct rpc_clnt *,
|
||||
struct rpc_add_xprt_test *);
|
||||
|
||||
const char *rpc_proc_name(const struct rpc_task *task);
|
||||
|
||||
void rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *, struct rpc_xprt *);
|
||||
void rpc_clnt_xprt_switch_remove_xprt(struct rpc_clnt *, struct rpc_xprt *);
|
||||
bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
|
||||
const struct sockaddr *sap);
|
||||
void rpc_clnt_xprt_set_online(struct rpc_clnt *clnt, struct rpc_xprt *xprt);
|
||||
void rpc_clnt_disconnect(struct rpc_clnt *clnt);
|
||||
void rpc_cleanup_clids(void);
|
||||
|
||||
static inline int rpc_reply_expected(struct rpc_task *task)
|
||||
{
|
||||
return (task->tk_msg.rpc_proc != NULL) &&
|
||||
(task->tk_msg.rpc_proc->p_decode != NULL);
|
||||
}
|
||||
|
||||
static inline void rpc_task_close_connection(struct rpc_task *task)
|
||||
{
|
||||
if (task->tk_xprt)
|
||||
xprt_force_disconnect(task->tk_xprt);
|
||||
}
|
||||
#endif /* _LINUX_SUNRPC_CLNT_H */
|
||||
@@ -0,0 +1,116 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/debug.h
|
||||
*
|
||||
* Debugging support for sunrpc module
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
#ifndef _LINUX_SUNRPC_DEBUG_H_
|
||||
#define _LINUX_SUNRPC_DEBUG_H_
|
||||
|
||||
#include <uapi/linux/sunrpc/debug.h>
|
||||
|
||||
/*
|
||||
* Debugging macros etc
|
||||
*/
|
||||
extern unsigned int rpc_debug;
|
||||
extern unsigned int nfs_debug;
|
||||
extern unsigned int nfsd_debug;
|
||||
extern unsigned int nlm_debug;
|
||||
|
||||
#define dprintk(fmt, ...) \
|
||||
dfprintk(FACILITY, fmt, ##__VA_ARGS__)
|
||||
#define dprintk_rcu(fmt, ...) \
|
||||
dfprintk_rcu(FACILITY, fmt, ##__VA_ARGS__)
|
||||
|
||||
#undef ifdebug
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
# define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac))
|
||||
|
||||
# if IS_ENABLED(CONFIG_SUNRPC_DEBUG_TRACE)
|
||||
# define __sunrpc_printk(fmt, ...) trace_printk(fmt, ##__VA_ARGS__)
|
||||
# else
|
||||
# define __sunrpc_printk(fmt, ...) printk(KERN_DEFAULT fmt, ##__VA_ARGS__)
|
||||
# endif
|
||||
|
||||
# define dfprintk(fac, fmt, ...) \
|
||||
do { \
|
||||
ifdebug(fac) \
|
||||
__sunrpc_printk(fmt, ##__VA_ARGS__); \
|
||||
else \
|
||||
no_printk(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
# define dfprintk_rcu(fac, fmt, ...) \
|
||||
do { \
|
||||
ifdebug(fac) { \
|
||||
rcu_read_lock(); \
|
||||
__sunrpc_printk(fmt, ##__VA_ARGS__); \
|
||||
rcu_read_unlock(); \
|
||||
} else { \
|
||||
no_printk(fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
# define ifdebug(fac) if (0)
|
||||
# define dfprintk(fac, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
|
||||
# define dfprintk_rcu(fac, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Sysctl interface for RPC debugging
|
||||
*/
|
||||
|
||||
struct rpc_clnt;
|
||||
struct rpc_xprt;
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
void rpc_register_sysctl(void);
|
||||
void rpc_unregister_sysctl(void);
|
||||
void sunrpc_debugfs_init(void);
|
||||
void sunrpc_debugfs_exit(void);
|
||||
void rpc_clnt_debugfs_register(struct rpc_clnt *);
|
||||
void rpc_clnt_debugfs_unregister(struct rpc_clnt *);
|
||||
void rpc_xprt_debugfs_register(struct rpc_xprt *);
|
||||
void rpc_xprt_debugfs_unregister(struct rpc_xprt *);
|
||||
#else
|
||||
static inline void
|
||||
sunrpc_debugfs_init(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
sunrpc_debugfs_exit(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rpc_xprt_debugfs_unregister(struct rpc_xprt *xprt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_SUNRPC_DEBUG_H_ */
|
||||
@@ -0,0 +1,164 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/gss_api.h
|
||||
*
|
||||
* Somewhat simplified version of the gss api.
|
||||
*
|
||||
* Dug Song <dugsong@monkey.org>
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
* Bruce Fields <bfields@umich.edu>
|
||||
* Copyright (c) 2000 The Regents of the University of Michigan
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_GSS_API_H
|
||||
#define _LINUX_SUNRPC_GSS_API_H
|
||||
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/msg_prot.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
/* The mechanism-independent gss-api context: */
|
||||
struct gss_ctx {
|
||||
struct gss_api_mech *mech_type;
|
||||
void *internal_ctx_id;
|
||||
unsigned int slack, align;
|
||||
};
|
||||
|
||||
#define GSS_C_NO_BUFFER ((struct xdr_netobj) 0)
|
||||
#define GSS_C_NO_CONTEXT ((struct gss_ctx *) 0)
|
||||
#define GSS_C_QOP_DEFAULT (0)
|
||||
|
||||
/*XXX arbitrary length - is this set somewhere? */
|
||||
#define GSS_OID_MAX_LEN 32
|
||||
struct rpcsec_gss_oid {
|
||||
unsigned int len;
|
||||
u8 data[GSS_OID_MAX_LEN];
|
||||
};
|
||||
|
||||
/* From RFC 3530 */
|
||||
struct rpcsec_gss_info {
|
||||
struct rpcsec_gss_oid oid;
|
||||
u32 qop;
|
||||
u32 service;
|
||||
};
|
||||
|
||||
/* gss-api prototypes; note that these are somewhat simplified versions of
|
||||
* the prototypes specified in RFC 2744. */
|
||||
int gss_import_sec_context(
|
||||
const void* input_token,
|
||||
size_t bufsize,
|
||||
struct gss_api_mech *mech,
|
||||
struct gss_ctx **ctx_id,
|
||||
time64_t *endtime,
|
||||
gfp_t gfp_mask);
|
||||
u32 gss_get_mic(
|
||||
struct gss_ctx *ctx_id,
|
||||
struct xdr_buf *message,
|
||||
struct xdr_netobj *mic_token);
|
||||
u32 gss_verify_mic(
|
||||
struct gss_ctx *ctx_id,
|
||||
struct xdr_buf *message,
|
||||
struct xdr_netobj *mic_token);
|
||||
u32 gss_wrap(
|
||||
struct gss_ctx *ctx_id,
|
||||
int offset,
|
||||
struct xdr_buf *outbuf,
|
||||
struct page **inpages);
|
||||
u32 gss_unwrap(
|
||||
struct gss_ctx *ctx_id,
|
||||
int offset,
|
||||
int len,
|
||||
struct xdr_buf *inbuf);
|
||||
u32 gss_delete_sec_context(
|
||||
struct gss_ctx **ctx_id);
|
||||
|
||||
rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 qop,
|
||||
u32 service);
|
||||
u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor);
|
||||
bool gss_pseudoflavor_to_datatouch(struct gss_api_mech *, u32 pseudoflavor);
|
||||
char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service);
|
||||
|
||||
struct pf_desc {
|
||||
u32 pseudoflavor;
|
||||
u32 qop;
|
||||
u32 service;
|
||||
char *name;
|
||||
char *auth_domain_name;
|
||||
struct auth_domain *domain;
|
||||
bool datatouch;
|
||||
};
|
||||
|
||||
/* Different mechanisms (e.g., krb5 or spkm3) may implement gss-api, and
|
||||
* mechanisms may be dynamically registered or unregistered by modules. */
|
||||
|
||||
/* Each mechanism is described by the following struct: */
|
||||
struct gss_api_mech {
|
||||
struct list_head gm_list;
|
||||
struct module *gm_owner;
|
||||
struct rpcsec_gss_oid gm_oid;
|
||||
char *gm_name;
|
||||
const struct gss_api_ops *gm_ops;
|
||||
/* pseudoflavors supported by this mechanism: */
|
||||
int gm_pf_num;
|
||||
struct pf_desc * gm_pfs;
|
||||
/* Should the following be a callback operation instead? */
|
||||
const char *gm_upcall_enctypes;
|
||||
};
|
||||
|
||||
/* and must provide the following operations: */
|
||||
struct gss_api_ops {
|
||||
int (*gss_import_sec_context)(
|
||||
const void *input_token,
|
||||
size_t bufsize,
|
||||
struct gss_ctx *ctx_id,
|
||||
time64_t *endtime,
|
||||
gfp_t gfp_mask);
|
||||
u32 (*gss_get_mic)(
|
||||
struct gss_ctx *ctx_id,
|
||||
struct xdr_buf *message,
|
||||
struct xdr_netobj *mic_token);
|
||||
u32 (*gss_verify_mic)(
|
||||
struct gss_ctx *ctx_id,
|
||||
struct xdr_buf *message,
|
||||
struct xdr_netobj *mic_token);
|
||||
u32 (*gss_wrap)(
|
||||
struct gss_ctx *ctx_id,
|
||||
int offset,
|
||||
struct xdr_buf *outbuf,
|
||||
struct page **inpages);
|
||||
u32 (*gss_unwrap)(
|
||||
struct gss_ctx *ctx_id,
|
||||
int offset,
|
||||
int len,
|
||||
struct xdr_buf *buf);
|
||||
void (*gss_delete_sec_context)(
|
||||
void *internal_ctx_id);
|
||||
};
|
||||
|
||||
int gss_mech_register(struct gss_api_mech *);
|
||||
void gss_mech_unregister(struct gss_api_mech *);
|
||||
|
||||
/* returns a mechanism descriptor given an OID, and increments the mechanism's
|
||||
* reference count. */
|
||||
struct gss_api_mech * gss_mech_get_by_OID(struct rpcsec_gss_oid *);
|
||||
|
||||
/* Given a GSS security tuple, look up a pseudoflavor */
|
||||
rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);
|
||||
|
||||
/* Given a pseudoflavor, look up a GSS security tuple */
|
||||
int gss_mech_flavor2info(rpc_authflavor_t, struct rpcsec_gss_info *);
|
||||
|
||||
/* Returns a reference to a mechanism, given a name like "krb5" etc. */
|
||||
struct gss_api_mech *gss_mech_get_by_name(const char *);
|
||||
|
||||
/* Similar, but get by pseudoflavor. */
|
||||
struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32);
|
||||
|
||||
struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
|
||||
|
||||
/* For every successful gss_mech_get or gss_mech_get_by_* call there must be a
|
||||
* corresponding call to gss_mech_put. */
|
||||
void gss_mech_put(struct gss_api_mech *);
|
||||
|
||||
#endif /* _LINUX_SUNRPC_GSS_API_H */
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* linux/include/sunrpc/gss_err.h
|
||||
*
|
||||
* Adapted from MIT Kerberos 5-1.2.1 include/gssapi/gssapi.h
|
||||
*
|
||||
* Copyright (c) 2002 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 1993 by OpenVision Technologies, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appears in all copies and
|
||||
* that both that copyright notice and this permission notice appear in
|
||||
* supporting documentation, and that the name of OpenVision not be used
|
||||
* in advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. OpenVision makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
||||
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_GSS_ERR_H
|
||||
#define _LINUX_SUNRPC_GSS_ERR_H
|
||||
|
||||
typedef unsigned int OM_uint32;
|
||||
|
||||
/*
|
||||
* Flag bits for context-level services.
|
||||
*/
|
||||
#define GSS_C_DELEG_FLAG 1
|
||||
#define GSS_C_MUTUAL_FLAG 2
|
||||
#define GSS_C_REPLAY_FLAG 4
|
||||
#define GSS_C_SEQUENCE_FLAG 8
|
||||
#define GSS_C_CONF_FLAG 16
|
||||
#define GSS_C_INTEG_FLAG 32
|
||||
#define GSS_C_ANON_FLAG 64
|
||||
#define GSS_C_PROT_READY_FLAG 128
|
||||
#define GSS_C_TRANS_FLAG 256
|
||||
|
||||
/*
|
||||
* Credential usage options
|
||||
*/
|
||||
#define GSS_C_BOTH 0
|
||||
#define GSS_C_INITIATE 1
|
||||
#define GSS_C_ACCEPT 2
|
||||
|
||||
/*
|
||||
* Status code types for gss_display_status
|
||||
*/
|
||||
#define GSS_C_GSS_CODE 1
|
||||
#define GSS_C_MECH_CODE 2
|
||||
|
||||
|
||||
/*
|
||||
* Expiration time of 2^32-1 seconds means infinite lifetime for a
|
||||
* credential or security context
|
||||
*/
|
||||
#define GSS_C_INDEFINITE ((OM_uint32) 0xfffffffful)
|
||||
|
||||
|
||||
/* Major status codes */
|
||||
|
||||
#define GSS_S_COMPLETE 0
|
||||
|
||||
/*
|
||||
* Some "helper" definitions to make the status code macros obvious.
|
||||
*/
|
||||
#define GSS_C_CALLING_ERROR_OFFSET 24
|
||||
#define GSS_C_ROUTINE_ERROR_OFFSET 16
|
||||
#define GSS_C_SUPPLEMENTARY_OFFSET 0
|
||||
#define GSS_C_CALLING_ERROR_MASK ((OM_uint32) 0377ul)
|
||||
#define GSS_C_ROUTINE_ERROR_MASK ((OM_uint32) 0377ul)
|
||||
#define GSS_C_SUPPLEMENTARY_MASK ((OM_uint32) 0177777ul)
|
||||
|
||||
/*
|
||||
* The macros that test status codes for error conditions. Note that the
|
||||
* GSS_ERROR() macro has changed slightly from the V1 GSSAPI so that it now
|
||||
* evaluates its argument only once.
|
||||
*/
|
||||
#define GSS_CALLING_ERROR(x) \
|
||||
((x) & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
|
||||
#define GSS_ROUTINE_ERROR(x) \
|
||||
((x) & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
|
||||
#define GSS_SUPPLEMENTARY_INFO(x) \
|
||||
((x) & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
|
||||
#define GSS_ERROR(x) \
|
||||
((x) & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
|
||||
(GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
|
||||
|
||||
/*
|
||||
* Now the actual status code definitions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Calling errors:
|
||||
*/
|
||||
#define GSS_S_CALL_INACCESSIBLE_READ \
|
||||
(((OM_uint32) 1ul) << GSS_C_CALLING_ERROR_OFFSET)
|
||||
#define GSS_S_CALL_INACCESSIBLE_WRITE \
|
||||
(((OM_uint32) 2ul) << GSS_C_CALLING_ERROR_OFFSET)
|
||||
#define GSS_S_CALL_BAD_STRUCTURE \
|
||||
(((OM_uint32) 3ul) << GSS_C_CALLING_ERROR_OFFSET)
|
||||
|
||||
/*
|
||||
* Routine errors:
|
||||
*/
|
||||
#define GSS_S_BAD_MECH (((OM_uint32) 1ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_NAME (((OM_uint32) 2ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_NAMETYPE (((OM_uint32) 3ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_BINDINGS (((OM_uint32) 4ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_STATUS (((OM_uint32) 5ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_SIG (((OM_uint32) 6ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_NO_CRED (((OM_uint32) 7ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_NO_CONTEXT (((OM_uint32) 8ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_DEFECTIVE_TOKEN (((OM_uint32) 9ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_DEFECTIVE_CREDENTIAL \
|
||||
(((OM_uint32) 10ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_CREDENTIALS_EXPIRED \
|
||||
(((OM_uint32) 11ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_CONTEXT_EXPIRED \
|
||||
(((OM_uint32) 12ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_FAILURE (((OM_uint32) 13ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_BAD_QOP (((OM_uint32) 14ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_UNAUTHORIZED (((OM_uint32) 15ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_UNAVAILABLE (((OM_uint32) 16ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_DUPLICATE_ELEMENT \
|
||||
(((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
#define GSS_S_NAME_NOT_MN \
|
||||
(((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET)
|
||||
|
||||
/*
|
||||
* Supplementary info bits:
|
||||
*/
|
||||
#define GSS_S_CONTINUE_NEEDED (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
|
||||
#define GSS_S_DUPLICATE_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
|
||||
#define GSS_S_OLD_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
|
||||
#define GSS_S_UNSEQ_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
|
||||
#define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
|
||||
|
||||
/* XXXX these are not part of the GSSAPI C bindings! (but should be) */
|
||||
|
||||
#define GSS_CALLING_ERROR_FIELD(x) \
|
||||
(((x) >> GSS_C_CALLING_ERROR_OFFSET) & GSS_C_CALLING_ERROR_MASK)
|
||||
#define GSS_ROUTINE_ERROR_FIELD(x) \
|
||||
(((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK)
|
||||
#define GSS_SUPPLEMENTARY_INFO_FIELD(x) \
|
||||
(((x) >> GSS_C_SUPPLEMENTARY_OFFSET) & GSS_C_SUPPLEMENTARY_MASK)
|
||||
|
||||
/* XXXX This is a necessary evil until the spec is fixed */
|
||||
#define GSS_S_CRED_UNAVAIL GSS_S_FAILURE
|
||||
|
||||
#endif /* __LINUX_SUNRPC_GSS_ERR_H */
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Adapted from MIT Kerberos 5-1.2.1 lib/include/krb5.h,
|
||||
* lib/gssapi/krb5/gssapiP_krb5.h, and others
|
||||
*
|
||||
* Copyright (c) 2000-2008 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Andy Adamson <andros@umich.edu>
|
||||
* Bruce Fields <bfields@umich.edu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 1995 by the Massachusetts Institute of Technology.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Export of this software from the United States of America may
|
||||
* require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. Furthermore if you modify this software you must label
|
||||
* your software as modified software and not distribute it in such a
|
||||
* fashion that it might be confused with the original M.I.T. software.
|
||||
* M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_GSS_KRB5_H
|
||||
#define _LINUX_SUNRPC_GSS_KRB5_H
|
||||
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/sunrpc/auth_gss.h>
|
||||
#include <linux/sunrpc/gss_err.h>
|
||||
|
||||
/* Length of constant used in key derivation */
|
||||
#define GSS_KRB5_K5CLENGTH (5)
|
||||
|
||||
/* Maximum key length (in bytes) for the supported crypto algorithms */
|
||||
#define GSS_KRB5_MAX_KEYLEN (32)
|
||||
|
||||
/* Maximum checksum function output for the supported enctypes */
|
||||
#define GSS_KRB5_MAX_CKSUM_LEN (24)
|
||||
|
||||
/* Maximum blocksize for the supported crypto algorithms */
|
||||
#define GSS_KRB5_MAX_BLOCKSIZE (16)
|
||||
|
||||
/* The length of the Kerberos GSS token header */
|
||||
#define GSS_KRB5_TOK_HDR_LEN (16)
|
||||
|
||||
#define KG_TOK_MIC_MSG 0x0101
|
||||
#define KG_TOK_WRAP_MSG 0x0201
|
||||
|
||||
#define KG2_TOK_INITIAL 0x0101
|
||||
#define KG2_TOK_RESPONSE 0x0202
|
||||
#define KG2_TOK_MIC 0x0404
|
||||
#define KG2_TOK_WRAP 0x0504
|
||||
|
||||
#define KG2_TOKEN_FLAG_SENTBYACCEPTOR 0x01
|
||||
#define KG2_TOKEN_FLAG_SEALED 0x02
|
||||
#define KG2_TOKEN_FLAG_ACCEPTORSUBKEY 0x04
|
||||
|
||||
#define KG2_RESP_FLAG_ERROR 0x0001
|
||||
#define KG2_RESP_FLAG_DELEG_OK 0x0002
|
||||
|
||||
enum sgn_alg {
|
||||
SGN_ALG_DES_MAC_MD5 = 0x0000,
|
||||
SGN_ALG_MD2_5 = 0x0001,
|
||||
SGN_ALG_DES_MAC = 0x0002,
|
||||
SGN_ALG_3 = 0x0003, /* not published */
|
||||
SGN_ALG_HMAC_SHA1_DES3_KD = 0x0004
|
||||
};
|
||||
enum seal_alg {
|
||||
SEAL_ALG_NONE = 0xffff,
|
||||
SEAL_ALG_DES = 0x0000,
|
||||
SEAL_ALG_1 = 0x0001, /* not published */
|
||||
SEAL_ALG_DES3KD = 0x0002
|
||||
};
|
||||
|
||||
/*
|
||||
* These values are assigned by IANA and published via the
|
||||
* subregistry at the link below:
|
||||
*
|
||||
* https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-2
|
||||
*/
|
||||
#define CKSUMTYPE_CRC32 0x0001
|
||||
#define CKSUMTYPE_RSA_MD4 0x0002
|
||||
#define CKSUMTYPE_RSA_MD4_DES 0x0003
|
||||
#define CKSUMTYPE_DESCBC 0x0004
|
||||
#define CKSUMTYPE_RSA_MD5 0x0007
|
||||
#define CKSUMTYPE_RSA_MD5_DES 0x0008
|
||||
#define CKSUMTYPE_NIST_SHA 0x0009
|
||||
#define CKSUMTYPE_HMAC_SHA1_DES3 0x000c
|
||||
#define CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f
|
||||
#define CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010
|
||||
#define CKSUMTYPE_CMAC_CAMELLIA128 0x0011
|
||||
#define CKSUMTYPE_CMAC_CAMELLIA256 0x0012
|
||||
#define CKSUMTYPE_HMAC_SHA256_128_AES128 0x0013
|
||||
#define CKSUMTYPE_HMAC_SHA384_192_AES256 0x0014
|
||||
#define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /* Microsoft md5 hmac cksumtype */
|
||||
|
||||
/* from gssapi_err_krb5.h */
|
||||
#define KG_CCACHE_NOMATCH (39756032L)
|
||||
#define KG_KEYTAB_NOMATCH (39756033L)
|
||||
#define KG_TGT_MISSING (39756034L)
|
||||
#define KG_NO_SUBKEY (39756035L)
|
||||
#define KG_CONTEXT_ESTABLISHED (39756036L)
|
||||
#define KG_BAD_SIGN_TYPE (39756037L)
|
||||
#define KG_BAD_LENGTH (39756038L)
|
||||
#define KG_CTX_INCOMPLETE (39756039L)
|
||||
#define KG_CONTEXT (39756040L)
|
||||
#define KG_CRED (39756041L)
|
||||
#define KG_ENC_DESC (39756042L)
|
||||
#define KG_BAD_SEQ (39756043L)
|
||||
#define KG_EMPTY_CCACHE (39756044L)
|
||||
#define KG_NO_CTYPES (39756045L)
|
||||
|
||||
/* per Kerberos v5 protocol spec crypto types from the wire.
|
||||
* these get mapped to linux kernel crypto routines.
|
||||
*
|
||||
* These values are assigned by IANA and published via the
|
||||
* subregistry at the link below:
|
||||
*
|
||||
* https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1
|
||||
*/
|
||||
#define ENCTYPE_NULL 0x0000
|
||||
#define ENCTYPE_DES_CBC_CRC 0x0001 /* DES cbc mode with CRC-32 */
|
||||
#define ENCTYPE_DES_CBC_MD4 0x0002 /* DES cbc mode with RSA-MD4 */
|
||||
#define ENCTYPE_DES_CBC_MD5 0x0003 /* DES cbc mode with RSA-MD5 */
|
||||
#define ENCTYPE_DES_CBC_RAW 0x0004 /* DES cbc mode raw */
|
||||
/* XXX deprecated? */
|
||||
#define ENCTYPE_DES3_CBC_SHA 0x0005 /* DES-3 cbc mode with NIST-SHA */
|
||||
#define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */
|
||||
#define ENCTYPE_DES_HMAC_SHA1 0x0008
|
||||
#define ENCTYPE_DES3_CBC_SHA1 0x0010
|
||||
#define ENCTYPE_AES128_CTS_HMAC_SHA1_96 0x0011
|
||||
#define ENCTYPE_AES256_CTS_HMAC_SHA1_96 0x0012
|
||||
#define ENCTYPE_AES128_CTS_HMAC_SHA256_128 0x0013
|
||||
#define ENCTYPE_AES256_CTS_HMAC_SHA384_192 0x0014
|
||||
#define ENCTYPE_ARCFOUR_HMAC 0x0017
|
||||
#define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018
|
||||
#define ENCTYPE_CAMELLIA128_CTS_CMAC 0x0019
|
||||
#define ENCTYPE_CAMELLIA256_CTS_CMAC 0x001A
|
||||
#define ENCTYPE_UNKNOWN 0x01ff
|
||||
|
||||
/*
|
||||
* Constants used for key derivation
|
||||
*/
|
||||
/* for 3DES */
|
||||
#define KG_USAGE_SEAL (22)
|
||||
#define KG_USAGE_SIGN (23)
|
||||
#define KG_USAGE_SEQ (24)
|
||||
|
||||
/* from rfc3961 */
|
||||
#define KEY_USAGE_SEED_CHECKSUM (0x99)
|
||||
#define KEY_USAGE_SEED_ENCRYPTION (0xAA)
|
||||
#define KEY_USAGE_SEED_INTEGRITY (0x55)
|
||||
|
||||
/* from rfc4121 */
|
||||
#define KG_USAGE_ACCEPTOR_SEAL (22)
|
||||
#define KG_USAGE_ACCEPTOR_SIGN (23)
|
||||
#define KG_USAGE_INITIATOR_SEAL (24)
|
||||
#define KG_USAGE_INITIATOR_SIGN (25)
|
||||
|
||||
#endif /* _LINUX_SUNRPC_GSS_KRB5_H */
|
||||
@@ -0,0 +1,108 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/metrics.h
|
||||
*
|
||||
* Declarations for RPC client per-operation metrics
|
||||
*
|
||||
* Copyright (C) 2005 Chuck Lever <cel@netapp.com>
|
||||
*
|
||||
* RPC client per-operation statistics provide latency and retry
|
||||
* information about each type of RPC procedure in a given RPC program.
|
||||
* These statistics are not for detailed problem diagnosis, but simply
|
||||
* to indicate whether the problem is local or remote.
|
||||
*
|
||||
* These counters are not meant to be human-readable, but are meant to be
|
||||
* integrated into system monitoring tools such as "sar" and "iostat". As
|
||||
* such, the counters are sampled by the tools over time, and are never
|
||||
* zeroed after a file system is mounted. Moving averages can be computed
|
||||
* by the tools by taking the difference between two instantaneous samples
|
||||
* and dividing that by the time between the samples.
|
||||
*
|
||||
* The counters are maintained in a single array per RPC client, indexed
|
||||
* by procedure number. There is no need to maintain separate counter
|
||||
* arrays per-CPU because these counters are always modified behind locks.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_METRICS_H
|
||||
#define _LINUX_SUNRPC_METRICS_H
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define RPC_IOSTATS_VERS "1.1"
|
||||
|
||||
struct rpc_iostats {
|
||||
spinlock_t om_lock;
|
||||
|
||||
/*
|
||||
* These counters give an idea about how many request
|
||||
* transmissions are required, on average, to complete that
|
||||
* particular procedure. Some procedures may require more
|
||||
* than one transmission because the server is unresponsive,
|
||||
* the client is retransmitting too aggressively, or the
|
||||
* requests are large and the network is congested.
|
||||
*/
|
||||
unsigned long om_ops, /* count of operations */
|
||||
om_ntrans, /* count of RPC transmissions */
|
||||
om_timeouts; /* count of major timeouts */
|
||||
|
||||
/*
|
||||
* These count how many bytes are sent and received for a
|
||||
* given RPC procedure type. This indicates how much load a
|
||||
* particular procedure is putting on the network. These
|
||||
* counts include the RPC and ULP headers, and the request
|
||||
* payload.
|
||||
*/
|
||||
unsigned long long om_bytes_sent, /* count of bytes out */
|
||||
om_bytes_recv; /* count of bytes in */
|
||||
|
||||
/*
|
||||
* The length of time an RPC request waits in queue before
|
||||
* transmission, the network + server latency of the request,
|
||||
* and the total time the request spent from init to release
|
||||
* are measured.
|
||||
*/
|
||||
ktime_t om_queue, /* queued for xmit */
|
||||
om_rtt, /* RPC RTT */
|
||||
om_execute; /* RPC execution */
|
||||
/*
|
||||
* The count of operations that complete with tk_status < 0.
|
||||
* These statuses usually indicate error conditions.
|
||||
*/
|
||||
unsigned long om_error_status;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
struct rpc_task;
|
||||
struct rpc_clnt;
|
||||
|
||||
/*
|
||||
* EXPORTed functions for managing rpc_iostats structures
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
struct rpc_iostats * rpc_alloc_iostats(struct rpc_clnt *);
|
||||
void rpc_count_iostats(const struct rpc_task *,
|
||||
struct rpc_iostats *);
|
||||
void rpc_count_iostats_metrics(const struct rpc_task *,
|
||||
struct rpc_iostats *);
|
||||
void rpc_clnt_show_stats(struct seq_file *, struct rpc_clnt *);
|
||||
void rpc_free_iostats(struct rpc_iostats *);
|
||||
|
||||
#else /* CONFIG_PROC_FS */
|
||||
|
||||
static inline struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) { return NULL; }
|
||||
static inline void rpc_count_iostats(const struct rpc_task *task,
|
||||
struct rpc_iostats *stats) {}
|
||||
static inline void rpc_count_iostats_metrics(const struct rpc_task *task,
|
||||
struct rpc_iostats *stats)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rpc_clnt_show_stats(struct seq_file *seq, struct rpc_clnt *clnt) {}
|
||||
static inline void rpc_free_iostats(struct rpc_iostats *stats) {}
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
#endif /* _LINUX_SUNRPC_METRICS_H */
|
||||
@@ -0,0 +1,223 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/msg_prot.h
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_MSGPROT_H_
|
||||
#define _LINUX_SUNRPC_MSGPROT_H_
|
||||
|
||||
#define RPC_VERSION 2
|
||||
|
||||
/* spec defines authentication flavor as an unsigned 32 bit integer */
|
||||
typedef u32 rpc_authflavor_t;
|
||||
|
||||
enum rpc_auth_flavors {
|
||||
RPC_AUTH_NULL = 0,
|
||||
RPC_AUTH_UNIX = 1,
|
||||
RPC_AUTH_SHORT = 2,
|
||||
RPC_AUTH_DES = 3,
|
||||
RPC_AUTH_KRB = 4,
|
||||
RPC_AUTH_GSS = 6,
|
||||
RPC_AUTH_TLS = 7,
|
||||
RPC_AUTH_MAXFLAVOR = 8,
|
||||
/* pseudoflavors: */
|
||||
RPC_AUTH_GSS_KRB5 = 390003,
|
||||
RPC_AUTH_GSS_KRB5I = 390004,
|
||||
RPC_AUTH_GSS_KRB5P = 390005,
|
||||
RPC_AUTH_GSS_LKEY = 390006,
|
||||
RPC_AUTH_GSS_LKEYI = 390007,
|
||||
RPC_AUTH_GSS_LKEYP = 390008,
|
||||
RPC_AUTH_GSS_SPKM = 390009,
|
||||
RPC_AUTH_GSS_SPKMI = 390010,
|
||||
RPC_AUTH_GSS_SPKMP = 390011,
|
||||
};
|
||||
|
||||
/* Maximum size (in octets) of the machinename in an AUTH_UNIX
|
||||
* credential (per RFC 5531 Appendix A)
|
||||
*/
|
||||
#define RPC_MAX_MACHINENAME (255)
|
||||
|
||||
/* Maximum size (in bytes) of an rpc credential or verifier */
|
||||
#define RPC_MAX_AUTH_SIZE (400)
|
||||
|
||||
enum rpc_msg_type {
|
||||
RPC_CALL = 0,
|
||||
RPC_REPLY = 1
|
||||
};
|
||||
|
||||
enum rpc_reply_stat {
|
||||
RPC_MSG_ACCEPTED = 0,
|
||||
RPC_MSG_DENIED = 1
|
||||
};
|
||||
|
||||
enum rpc_accept_stat {
|
||||
RPC_SUCCESS = 0,
|
||||
RPC_PROG_UNAVAIL = 1,
|
||||
RPC_PROG_MISMATCH = 2,
|
||||
RPC_PROC_UNAVAIL = 3,
|
||||
RPC_GARBAGE_ARGS = 4,
|
||||
RPC_SYSTEM_ERR = 5,
|
||||
/* internal use only */
|
||||
RPC_DROP_REPLY = 60000,
|
||||
};
|
||||
|
||||
enum rpc_reject_stat {
|
||||
RPC_MISMATCH = 0,
|
||||
RPC_AUTH_ERROR = 1
|
||||
};
|
||||
|
||||
enum rpc_auth_stat {
|
||||
RPC_AUTH_OK = 0, /* success */
|
||||
RPC_AUTH_BADCRED = 1, /* bad credential (seal broken) */
|
||||
RPC_AUTH_REJECTEDCRED = 2, /* client must begin new session */
|
||||
RPC_AUTH_BADVERF = 3, /* bad verifier (seal broken) */
|
||||
RPC_AUTH_REJECTEDVERF = 4, /* verifier expired or replayed */
|
||||
RPC_AUTH_TOOWEAK = 5, /* rejected for security reasons */
|
||||
RPC_AUTH_INVALIDRESP = 6, /* bogus response verifier */
|
||||
RPC_AUTH_FAILED = 7, /* reason unknown */
|
||||
/* RPCSEC_GSS errors */
|
||||
RPCSEC_GSS_CREDPROBLEM = 13, /* no credentials for user */
|
||||
RPCSEC_GSS_CTXPROBLEM = 14 /* problem with context */
|
||||
};
|
||||
|
||||
#define RPC_MAXNETNAMELEN 256
|
||||
|
||||
/*
|
||||
* From RFC 1831:
|
||||
*
|
||||
* "A record is composed of one or more record fragments. A record
|
||||
* fragment is a four-byte header followed by 0 to (2**31) - 1 bytes of
|
||||
* fragment data. The bytes encode an unsigned binary number; as with
|
||||
* XDR integers, the byte order is from highest to lowest. The number
|
||||
* encodes two values -- a boolean which indicates whether the fragment
|
||||
* is the last fragment of the record (bit value 1 implies the fragment
|
||||
* is the last fragment) and a 31-bit unsigned binary value which is the
|
||||
* length in bytes of the fragment's data. The boolean value is the
|
||||
* highest-order bit of the header; the length is the 31 low-order bits.
|
||||
* (Note that this record specification is NOT in XDR standard form!)"
|
||||
*
|
||||
* The Linux RPC client always sends its requests in a single record
|
||||
* fragment, limiting the maximum payload size for stream transports to
|
||||
* 2GB.
|
||||
*/
|
||||
|
||||
typedef __be32 rpc_fraghdr;
|
||||
|
||||
#define RPC_LAST_STREAM_FRAGMENT (1U << 31)
|
||||
#define RPC_FRAGMENT_SIZE_MASK (~RPC_LAST_STREAM_FRAGMENT)
|
||||
#define RPC_MAX_FRAGMENT_SIZE ((1U << 31) - 1)
|
||||
|
||||
/*
|
||||
* RPC call and reply header size as number of 32bit words (verifier
|
||||
* size computed separately, see below)
|
||||
*/
|
||||
#define RPC_CALLHDRSIZE (6)
|
||||
#define RPC_REPHDRSIZE (4)
|
||||
|
||||
|
||||
/*
|
||||
* Maximum RPC header size, including authentication,
|
||||
* as number of 32bit words (see RFCs 1831, 1832).
|
||||
*
|
||||
* xid 1 xdr unit = 4 bytes
|
||||
* mtype 1
|
||||
* rpc_version 1
|
||||
* program 1
|
||||
* prog_version 1
|
||||
* procedure 1
|
||||
* cred {
|
||||
* flavor 1
|
||||
* length 1
|
||||
* body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
|
||||
* }
|
||||
* verf {
|
||||
* flavor 1
|
||||
* length 1
|
||||
* body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
|
||||
* }
|
||||
* TOTAL 210 xdr units = 840 bytes
|
||||
*/
|
||||
#define RPC_MAX_HEADER_WITH_AUTH \
|
||||
(RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))
|
||||
|
||||
#define RPC_MAX_REPHEADER_WITH_AUTH \
|
||||
(RPC_REPHDRSIZE + (2 + RPC_MAX_AUTH_SIZE/4))
|
||||
|
||||
/*
|
||||
* Well-known netids. See:
|
||||
*
|
||||
* https://www.iana.org/assignments/rpc-netids/rpc-netids.xhtml
|
||||
*/
|
||||
#define RPCBIND_NETID_UDP "udp"
|
||||
#define RPCBIND_NETID_TCP "tcp"
|
||||
#define RPCBIND_NETID_RDMA "rdma"
|
||||
#define RPCBIND_NETID_SCTP "sctp"
|
||||
#define RPCBIND_NETID_UDP6 "udp6"
|
||||
#define RPCBIND_NETID_TCP6 "tcp6"
|
||||
#define RPCBIND_NETID_RDMA6 "rdma6"
|
||||
#define RPCBIND_NETID_SCTP6 "sctp6"
|
||||
#define RPCBIND_NETID_LOCAL "local"
|
||||
|
||||
/*
|
||||
* Note that RFC 1833 does not put any size restrictions on the
|
||||
* netid string, but all currently defined netid's fit in 5 bytes.
|
||||
*/
|
||||
#define RPCBIND_MAXNETIDLEN (5u)
|
||||
|
||||
/*
|
||||
* Universal addresses are introduced in RFC 1833 and further spelled
|
||||
* out in RFC 3530. RPCBIND_MAXUADDRLEN defines a maximum byte length
|
||||
* of a universal address for use in allocating buffers and character
|
||||
* arrays.
|
||||
*
|
||||
* Quoting RFC 3530, section 2.2:
|
||||
*
|
||||
* For TCP over IPv4 and for UDP over IPv4, the format of r_addr is the
|
||||
* US-ASCII string:
|
||||
*
|
||||
* h1.h2.h3.h4.p1.p2
|
||||
*
|
||||
* The prefix, "h1.h2.h3.h4", is the standard textual form for
|
||||
* representing an IPv4 address, which is always four octets long.
|
||||
* Assuming big-endian ordering, h1, h2, h3, and h4, are respectively,
|
||||
* the first through fourth octets each converted to ASCII-decimal.
|
||||
* Assuming big-endian ordering, p1 and p2 are, respectively, the first
|
||||
* and second octets each converted to ASCII-decimal. For example, if a
|
||||
* host, in big-endian order, has an address of 0x0A010307 and there is
|
||||
* a service listening on, in big endian order, port 0x020F (decimal
|
||||
* 527), then the complete universal address is "10.1.3.7.2.15".
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* For TCP over IPv6 and for UDP over IPv6, the format of r_addr is the
|
||||
* US-ASCII string:
|
||||
*
|
||||
* x1:x2:x3:x4:x5:x6:x7:x8.p1.p2
|
||||
*
|
||||
* The suffix "p1.p2" is the service port, and is computed the same way
|
||||
* as with universal addresses for TCP and UDP over IPv4. The prefix,
|
||||
* "x1:x2:x3:x4:x5:x6:x7:x8", is the standard textual form for
|
||||
* representing an IPv6 address as defined in Section 2.2 of [RFC2373].
|
||||
* Additionally, the two alternative forms specified in Section 2.2 of
|
||||
* [RFC2373] are also acceptable.
|
||||
*/
|
||||
|
||||
#include <linux/inet.h>
|
||||
|
||||
/* Maximum size of the port number part of a universal address */
|
||||
#define RPCBIND_MAXUADDRPLEN sizeof(".255.255")
|
||||
|
||||
/* Maximum size of an IPv4 universal address */
|
||||
#define RPCBIND_MAXUADDR4LEN \
|
||||
(INET_ADDRSTRLEN + RPCBIND_MAXUADDRPLEN)
|
||||
|
||||
/* Maximum size of an IPv6 universal address */
|
||||
#define RPCBIND_MAXUADDR6LEN \
|
||||
(INET6_ADDRSTRLEN + RPCBIND_MAXUADDRPLEN)
|
||||
|
||||
/* Assume INET6_ADDRSTRLEN will always be larger than INET_ADDRSTRLEN... */
|
||||
#define RPCBIND_MAXUADDRLEN RPCBIND_MAXUADDR6LEN
|
||||
|
||||
#endif /* _LINUX_SUNRPC_MSGPROT_H_ */
|
||||
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* * Copyright (c) 2024, Oracle and/or its affiliates.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_RDMA_RN_H
|
||||
#define _LINUX_SUNRPC_RDMA_RN_H
|
||||
|
||||
#include <rdma/ib_verbs.h>
|
||||
|
||||
/**
|
||||
* rpcrdma_notification - request removal notification
|
||||
*/
|
||||
struct rpcrdma_notification {
|
||||
void (*rn_done)(struct rpcrdma_notification *rn);
|
||||
u32 rn_index;
|
||||
};
|
||||
|
||||
int rpcrdma_rn_register(struct ib_device *device,
|
||||
struct rpcrdma_notification *rn,
|
||||
void (*done)(struct rpcrdma_notification *rn));
|
||||
void rpcrdma_rn_unregister(struct ib_device *device,
|
||||
struct rpcrdma_notification *rn);
|
||||
int rpcrdma_ib_client_register(void);
|
||||
void rpcrdma_ib_client_unregister(void);
|
||||
|
||||
#endif /* _LINUX_SUNRPC_RDMA_RN_H */
|
||||
@@ -0,0 +1,138 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_SUNRPC_RPC_PIPE_FS_H
|
||||
#define _LINUX_SUNRPC_RPC_PIPE_FS_H
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct rpc_pipe_dir_head {
|
||||
struct list_head pdh_entries;
|
||||
struct dentry *pdh_dentry;
|
||||
};
|
||||
|
||||
struct rpc_pipe_dir_object_ops;
|
||||
struct rpc_pipe_dir_object {
|
||||
struct list_head pdo_head;
|
||||
const struct rpc_pipe_dir_object_ops *pdo_ops;
|
||||
|
||||
void *pdo_data;
|
||||
};
|
||||
|
||||
struct rpc_pipe_dir_object_ops {
|
||||
int (*create)(struct dentry *dir,
|
||||
struct rpc_pipe_dir_object *pdo);
|
||||
void (*destroy)(struct dentry *dir,
|
||||
struct rpc_pipe_dir_object *pdo);
|
||||
};
|
||||
|
||||
struct rpc_pipe_msg {
|
||||
struct list_head list;
|
||||
void *data;
|
||||
size_t len;
|
||||
size_t copied;
|
||||
int errno;
|
||||
};
|
||||
|
||||
struct rpc_pipe_ops {
|
||||
ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t);
|
||||
ssize_t (*downcall)(struct file *, const char __user *, size_t);
|
||||
void (*release_pipe)(struct inode *);
|
||||
int (*open_pipe)(struct inode *);
|
||||
void (*destroy_msg)(struct rpc_pipe_msg *);
|
||||
};
|
||||
|
||||
struct rpc_pipe {
|
||||
struct list_head pipe;
|
||||
struct list_head in_upcall;
|
||||
struct list_head in_downcall;
|
||||
int pipelen;
|
||||
int nreaders;
|
||||
int nwriters;
|
||||
#define RPC_PIPE_WAIT_FOR_OPEN 1
|
||||
int flags;
|
||||
struct delayed_work queue_timeout;
|
||||
const struct rpc_pipe_ops *ops;
|
||||
spinlock_t lock;
|
||||
struct dentry *dentry;
|
||||
};
|
||||
|
||||
struct rpc_inode {
|
||||
struct inode vfs_inode;
|
||||
void *private;
|
||||
struct rpc_pipe *pipe;
|
||||
wait_queue_head_t waitq;
|
||||
};
|
||||
|
||||
static inline struct rpc_inode *
|
||||
RPC_I(struct inode *inode)
|
||||
{
|
||||
return container_of(inode, struct rpc_inode, vfs_inode);
|
||||
}
|
||||
|
||||
enum {
|
||||
SUNRPC_PIPEFS_NFS_PRIO,
|
||||
SUNRPC_PIPEFS_RPC_PRIO,
|
||||
};
|
||||
|
||||
extern int rpc_pipefs_notifier_register(struct notifier_block *);
|
||||
extern void rpc_pipefs_notifier_unregister(struct notifier_block *);
|
||||
|
||||
enum {
|
||||
RPC_PIPEFS_MOUNT,
|
||||
RPC_PIPEFS_UMOUNT,
|
||||
};
|
||||
|
||||
extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
|
||||
const unsigned char *dir_name);
|
||||
extern int rpc_pipefs_init_net(struct net *net);
|
||||
extern void rpc_pipefs_exit_net(struct net *net);
|
||||
extern struct super_block *rpc_get_sb_net(const struct net *net);
|
||||
extern void rpc_put_sb_net(const struct net *net);
|
||||
|
||||
extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *,
|
||||
char __user *, size_t);
|
||||
extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *);
|
||||
|
||||
/* returns true if the msg is in-flight, i.e., already eaten by the peer */
|
||||
static inline bool rpc_msg_is_inflight(const struct rpc_pipe_msg *msg) {
|
||||
return (msg->copied != 0 && list_empty(&msg->list));
|
||||
}
|
||||
|
||||
struct rpc_clnt;
|
||||
extern int rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *);
|
||||
extern int rpc_remove_client_dir(struct rpc_clnt *);
|
||||
|
||||
extern void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh);
|
||||
extern void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo,
|
||||
const struct rpc_pipe_dir_object_ops *pdo_ops,
|
||||
void *pdo_data);
|
||||
extern int rpc_add_pipe_dir_object(struct net *net,
|
||||
struct rpc_pipe_dir_head *pdh,
|
||||
struct rpc_pipe_dir_object *pdo);
|
||||
extern void rpc_remove_pipe_dir_object(struct net *net,
|
||||
struct rpc_pipe_dir_head *pdh,
|
||||
struct rpc_pipe_dir_object *pdo);
|
||||
extern struct rpc_pipe_dir_object *rpc_find_or_alloc_pipe_dir_object(
|
||||
struct net *net,
|
||||
struct rpc_pipe_dir_head *pdh,
|
||||
int (*match)(struct rpc_pipe_dir_object *, void *),
|
||||
struct rpc_pipe_dir_object *(*alloc)(void *),
|
||||
void *data);
|
||||
|
||||
struct cache_detail;
|
||||
extern struct dentry *rpc_create_cache_dir(struct dentry *,
|
||||
const char *,
|
||||
umode_t umode,
|
||||
struct cache_detail *);
|
||||
extern void rpc_remove_cache_dir(struct dentry *);
|
||||
|
||||
struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags);
|
||||
void rpc_destroy_pipe_data(struct rpc_pipe *pipe);
|
||||
extern int rpc_mkpipe_dentry(struct dentry *, const char *, void *,
|
||||
struct rpc_pipe *);
|
||||
extern void rpc_unlink(struct rpc_pipe *);
|
||||
extern int register_rpc_pipefs(void);
|
||||
extern void unregister_rpc_pipefs(void);
|
||||
|
||||
extern bool gssd_running(struct net *net);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,201 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Oracle. All rights reserved.
|
||||
* Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the BSD-type
|
||||
* license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* Neither the name of the Network Appliance, Inc. nor the names of
|
||||
* its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_RPC_RDMA_H
|
||||
#define _LINUX_SUNRPC_RPC_RDMA_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define RPCRDMA_VERSION 1
|
||||
#define rpcrdma_version cpu_to_be32(RPCRDMA_VERSION)
|
||||
|
||||
enum {
|
||||
RPCRDMA_V1_DEF_INLINE_SIZE = 1024,
|
||||
};
|
||||
|
||||
/*
|
||||
* XDR sizes, in quads
|
||||
*/
|
||||
enum {
|
||||
rpcrdma_fixed_maxsz = 4,
|
||||
rpcrdma_segment_maxsz = 4,
|
||||
rpcrdma_readseg_maxsz = 1 + rpcrdma_segment_maxsz,
|
||||
rpcrdma_readchunk_maxsz = 1 + rpcrdma_readseg_maxsz,
|
||||
};
|
||||
|
||||
/*
|
||||
* Smallest RPC/RDMA header: rm_xid through rm_type, then rm_nochunks
|
||||
*/
|
||||
#define RPCRDMA_HDRLEN_MIN (sizeof(__be32) * 7)
|
||||
#define RPCRDMA_HDRLEN_ERR (sizeof(__be32) * 5)
|
||||
|
||||
enum rpcrdma_errcode {
|
||||
ERR_VERS = 1,
|
||||
ERR_CHUNK = 2
|
||||
};
|
||||
|
||||
enum rpcrdma_proc {
|
||||
RDMA_MSG = 0, /* An RPC call or reply msg */
|
||||
RDMA_NOMSG = 1, /* An RPC call or reply msg - separate body */
|
||||
RDMA_MSGP = 2, /* An RPC call or reply msg with padding */
|
||||
RDMA_DONE = 3, /* Client signals reply completion */
|
||||
RDMA_ERROR = 4 /* An RPC RDMA encoding error */
|
||||
};
|
||||
|
||||
#define rdma_msg cpu_to_be32(RDMA_MSG)
|
||||
#define rdma_nomsg cpu_to_be32(RDMA_NOMSG)
|
||||
#define rdma_msgp cpu_to_be32(RDMA_MSGP)
|
||||
#define rdma_done cpu_to_be32(RDMA_DONE)
|
||||
#define rdma_error cpu_to_be32(RDMA_ERROR)
|
||||
|
||||
#define err_vers cpu_to_be32(ERR_VERS)
|
||||
#define err_chunk cpu_to_be32(ERR_CHUNK)
|
||||
|
||||
/*
|
||||
* Private extension to RPC-over-RDMA Version One.
|
||||
* Message passed during RDMA-CM connection set-up.
|
||||
*
|
||||
* Add new fields at the end, and don't permute existing
|
||||
* fields.
|
||||
*/
|
||||
struct rpcrdma_connect_private {
|
||||
__be32 cp_magic;
|
||||
u8 cp_version;
|
||||
u8 cp_flags;
|
||||
u8 cp_send_size;
|
||||
u8 cp_recv_size;
|
||||
} __packed;
|
||||
|
||||
#define rpcrdma_cmp_magic __cpu_to_be32(0xf6ab0e18)
|
||||
|
||||
enum {
|
||||
RPCRDMA_CMP_VERSION = 1,
|
||||
RPCRDMA_CMP_F_SND_W_INV_OK = BIT(0),
|
||||
};
|
||||
|
||||
static inline u8
|
||||
rpcrdma_encode_buffer_size(unsigned int size)
|
||||
{
|
||||
return (size >> 10) - 1;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
rpcrdma_decode_buffer_size(u8 val)
|
||||
{
|
||||
return ((unsigned int)val + 1) << 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_encode_rdma_segment - Encode contents of an RDMA segment
|
||||
* @p: Pointer into a send buffer
|
||||
* @handle: The RDMA handle to encode
|
||||
* @length: The RDMA length to encode
|
||||
* @offset: The RDMA offset to encode
|
||||
*
|
||||
* Return value:
|
||||
* Pointer to the XDR position that follows the encoded RDMA segment
|
||||
*/
|
||||
static inline __be32 *xdr_encode_rdma_segment(__be32 *p, u32 handle,
|
||||
u32 length, u64 offset)
|
||||
{
|
||||
*p++ = cpu_to_be32(handle);
|
||||
*p++ = cpu_to_be32(length);
|
||||
return xdr_encode_hyper(p, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_encode_read_segment - Encode contents of a Read segment
|
||||
* @p: Pointer into a send buffer
|
||||
* @position: The position to encode
|
||||
* @handle: The RDMA handle to encode
|
||||
* @length: The RDMA length to encode
|
||||
* @offset: The RDMA offset to encode
|
||||
*
|
||||
* Return value:
|
||||
* Pointer to the XDR position that follows the encoded Read segment
|
||||
*/
|
||||
static inline __be32 *xdr_encode_read_segment(__be32 *p, u32 position,
|
||||
u32 handle, u32 length,
|
||||
u64 offset)
|
||||
{
|
||||
*p++ = cpu_to_be32(position);
|
||||
return xdr_encode_rdma_segment(p, handle, length, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_decode_rdma_segment - Decode contents of an RDMA segment
|
||||
* @p: Pointer to the undecoded RDMA segment
|
||||
* @handle: Upon return, the RDMA handle
|
||||
* @length: Upon return, the RDMA length
|
||||
* @offset: Upon return, the RDMA offset
|
||||
*
|
||||
* Return value:
|
||||
* Pointer to the XDR item that follows the RDMA segment
|
||||
*/
|
||||
static inline __be32 *xdr_decode_rdma_segment(__be32 *p, u32 *handle,
|
||||
u32 *length, u64 *offset)
|
||||
{
|
||||
*handle = be32_to_cpup(p++);
|
||||
*length = be32_to_cpup(p++);
|
||||
return xdr_decode_hyper(p, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_decode_read_segment - Decode contents of a Read segment
|
||||
* @p: Pointer to the undecoded Read segment
|
||||
* @position: Upon return, the segment's position
|
||||
* @handle: Upon return, the RDMA handle
|
||||
* @length: Upon return, the RDMA length
|
||||
* @offset: Upon return, the RDMA offset
|
||||
*
|
||||
* Return value:
|
||||
* Pointer to the XDR item that follows the Read segment
|
||||
*/
|
||||
static inline __be32 *xdr_decode_read_segment(__be32 *p, u32 *position,
|
||||
u32 *handle, u32 *length,
|
||||
u64 *offset)
|
||||
{
|
||||
*position = be32_to_cpup(p++);
|
||||
return xdr_decode_rdma_segment(p, handle, length, offset);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_SUNRPC_RPC_RDMA_H */
|
||||
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* * Copyright (c) 2020, Oracle and/or its affiliates.
|
||||
*/
|
||||
|
||||
#ifndef RPC_RDMA_CID_H
|
||||
#define RPC_RDMA_CID_H
|
||||
|
||||
/*
|
||||
* The rpc_rdma_cid struct records completion ID information. A
|
||||
* completion ID matches an incoming Send or Receive completion
|
||||
* to a Completion Queue and to a previous ib_post_*(). The ID
|
||||
* can then be displayed in an error message or recorded in a
|
||||
* trace record.
|
||||
*
|
||||
* This struct is shared between the server and client RPC/RDMA
|
||||
* transport implementations.
|
||||
*/
|
||||
struct rpc_rdma_cid {
|
||||
u32 ci_queue_id;
|
||||
int ci_completion_id;
|
||||
};
|
||||
|
||||
#endif /* RPC_RDMA_CID_H */
|
||||
@@ -0,0 +1,317 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/sched.h
|
||||
*
|
||||
* Scheduling primitives for kernel Sun RPC.
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_SCHED_H_
|
||||
#define _LINUX_SUNRPC_SCHED_H_
|
||||
|
||||
#include <linux/timer.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/sunrpc/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/wait_bit.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
|
||||
/*
|
||||
* This is the actual RPC procedure call info.
|
||||
*/
|
||||
struct rpc_procinfo;
|
||||
struct rpc_message {
|
||||
const struct rpc_procinfo *rpc_proc; /* Procedure information */
|
||||
void * rpc_argp; /* Arguments */
|
||||
void * rpc_resp; /* Result */
|
||||
const struct cred * rpc_cred; /* Credentials */
|
||||
};
|
||||
|
||||
struct rpc_call_ops;
|
||||
struct rpc_wait_queue;
|
||||
struct rpc_wait {
|
||||
struct list_head list; /* wait queue links */
|
||||
struct list_head links; /* Links to related tasks */
|
||||
struct list_head timer_list; /* Timer list */
|
||||
};
|
||||
|
||||
/*
|
||||
* This describes a timeout strategy
|
||||
*/
|
||||
struct rpc_timeout {
|
||||
unsigned long to_initval, /* initial timeout */
|
||||
to_maxval, /* max timeout */
|
||||
to_increment; /* if !exponential */
|
||||
unsigned int to_retries; /* max # of retries */
|
||||
unsigned char to_exponential;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the RPC task struct
|
||||
*/
|
||||
struct rpc_task {
|
||||
atomic_t tk_count; /* Reference count */
|
||||
int tk_status; /* result of last operation */
|
||||
struct list_head tk_task; /* global list of tasks */
|
||||
|
||||
/*
|
||||
* callback to be executed after waking up
|
||||
* action next procedure for async tasks
|
||||
*/
|
||||
void (*tk_callback)(struct rpc_task *);
|
||||
void (*tk_action)(struct rpc_task *);
|
||||
|
||||
unsigned long tk_timeout; /* timeout for rpc_sleep() */
|
||||
unsigned long tk_runstate; /* Task run status */
|
||||
|
||||
struct rpc_wait_queue *tk_waitqueue; /* RPC wait queue we're on */
|
||||
union {
|
||||
struct work_struct tk_work; /* Async task work queue */
|
||||
struct rpc_wait tk_wait; /* RPC wait */
|
||||
} u;
|
||||
|
||||
/*
|
||||
* RPC call state
|
||||
*/
|
||||
struct rpc_message tk_msg; /* RPC call info */
|
||||
void * tk_calldata; /* Caller private data */
|
||||
const struct rpc_call_ops *tk_ops; /* Caller callbacks */
|
||||
|
||||
struct rpc_clnt * tk_client; /* RPC client */
|
||||
struct rpc_xprt * tk_xprt; /* Transport */
|
||||
struct rpc_cred * tk_op_cred; /* cred being operated on */
|
||||
|
||||
struct rpc_rqst * tk_rqstp; /* RPC request */
|
||||
|
||||
struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could
|
||||
* be any workqueue
|
||||
*/
|
||||
ktime_t tk_start; /* RPC task init timestamp */
|
||||
|
||||
pid_t tk_owner; /* Process id for batching tasks */
|
||||
|
||||
int tk_rpc_status; /* Result of last RPC operation */
|
||||
unsigned short tk_flags; /* misc flags */
|
||||
unsigned short tk_timeouts; /* maj timeouts */
|
||||
unsigned short tk_pid; /* debugging aid */
|
||||
unsigned char tk_priority : 2,/* Task priority */
|
||||
tk_garb_retry : 2,
|
||||
tk_cred_retry : 2;
|
||||
};
|
||||
|
||||
typedef void (*rpc_action)(struct rpc_task *);
|
||||
|
||||
struct rpc_call_ops {
|
||||
void (*rpc_call_prepare)(struct rpc_task *, void *);
|
||||
void (*rpc_call_done)(struct rpc_task *, void *);
|
||||
void (*rpc_count_stats)(struct rpc_task *, void *);
|
||||
void (*rpc_release)(void *);
|
||||
};
|
||||
|
||||
struct rpc_task_setup {
|
||||
struct rpc_task *task;
|
||||
struct rpc_clnt *rpc_client;
|
||||
struct rpc_xprt *rpc_xprt;
|
||||
struct rpc_cred *rpc_op_cred; /* credential being operated on */
|
||||
const struct rpc_message *rpc_message;
|
||||
const struct rpc_call_ops *callback_ops;
|
||||
void *callback_data;
|
||||
struct workqueue_struct *workqueue;
|
||||
unsigned short flags;
|
||||
signed char priority;
|
||||
};
|
||||
|
||||
/*
|
||||
* RPC task flags
|
||||
*/
|
||||
#define RPC_TASK_ASYNC 0x0001 /* is an async task */
|
||||
#define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */
|
||||
#define RPC_TASK_MOVEABLE 0x0004 /* nfs4.1+ rpc tasks */
|
||||
#define RPC_TASK_NULLCREDS 0x0010 /* Use AUTH_NULL credential */
|
||||
#define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */
|
||||
#define RPC_TASK_NETUNREACH_FATAL 0x0040 /* ENETUNREACH is fatal */
|
||||
#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */
|
||||
#define RPC_TASK_NO_ROUND_ROBIN 0x0100 /* send requests on "main" xprt */
|
||||
#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
|
||||
#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */
|
||||
#define RPC_TASK_SENT 0x0800 /* message was sent */
|
||||
#define RPC_TASK_TIMEOUT 0x1000 /* fail with ETIMEDOUT on timeout */
|
||||
#define RPC_TASK_NOCONNECT 0x2000 /* return ENOTCONN if not connected */
|
||||
#define RPC_TASK_NO_RETRANS_TIMEOUT 0x4000 /* wait forever for a reply */
|
||||
#define RPC_TASK_CRED_NOREF 0x8000 /* No refcount on the credential */
|
||||
|
||||
#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
|
||||
#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
|
||||
#define RPC_IS_SOFT(t) ((t)->tk_flags & (RPC_TASK_SOFT|RPC_TASK_TIMEOUT))
|
||||
#define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN)
|
||||
#define RPC_WAS_SENT(t) ((t)->tk_flags & RPC_TASK_SENT)
|
||||
#define RPC_IS_MOVEABLE(t) ((t)->tk_flags & RPC_TASK_MOVEABLE)
|
||||
|
||||
enum {
|
||||
RPC_TASK_RUNNING,
|
||||
RPC_TASK_QUEUED,
|
||||
RPC_TASK_ACTIVE,
|
||||
RPC_TASK_NEED_XMIT,
|
||||
RPC_TASK_NEED_RECV,
|
||||
RPC_TASK_MSG_PIN_WAIT,
|
||||
};
|
||||
|
||||
#define rpc_test_and_set_running(t) \
|
||||
test_and_set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
|
||||
#define rpc_clear_running(t) clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
|
||||
|
||||
#define RPC_IS_QUEUED(t) test_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)
|
||||
#define rpc_set_queued(t) set_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)
|
||||
#define rpc_clear_queued(t) clear_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)
|
||||
|
||||
#define RPC_IS_ACTIVATED(t) test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate)
|
||||
|
||||
#define RPC_SIGNALLED(t) (READ_ONCE(task->tk_rpc_status) == -ERESTARTSYS)
|
||||
|
||||
/*
|
||||
* Task priorities.
|
||||
* Note: if you change these, you must also change
|
||||
* the task initialization definitions below.
|
||||
*/
|
||||
#define RPC_PRIORITY_LOW (-1)
|
||||
#define RPC_PRIORITY_NORMAL (0)
|
||||
#define RPC_PRIORITY_HIGH (1)
|
||||
#define RPC_PRIORITY_PRIVILEGED (2)
|
||||
#define RPC_NR_PRIORITY (1 + RPC_PRIORITY_PRIVILEGED - RPC_PRIORITY_LOW)
|
||||
|
||||
struct rpc_timer {
|
||||
struct list_head list;
|
||||
unsigned long expires;
|
||||
struct delayed_work dwork;
|
||||
};
|
||||
|
||||
/*
|
||||
* RPC synchronization objects
|
||||
*/
|
||||
struct rpc_wait_queue {
|
||||
spinlock_t lock;
|
||||
struct list_head tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */
|
||||
unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */
|
||||
unsigned char priority; /* current priority */
|
||||
unsigned char nr; /* # tasks remaining for cookie */
|
||||
unsigned int qlen; /* total # tasks waiting in queue */
|
||||
struct rpc_timer timer_list;
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
|
||||
const char * name;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the # requests to send consecutively
|
||||
* from a single cookie. The aim is to improve
|
||||
* performance of NFS operations such as read/write.
|
||||
*/
|
||||
#define RPC_IS_PRIORITY(q) ((q)->maxpriority > 0)
|
||||
|
||||
/*
|
||||
* Function prototypes
|
||||
*/
|
||||
struct rpc_task *rpc_new_task(const struct rpc_task_setup *);
|
||||
struct rpc_task *rpc_run_task(const struct rpc_task_setup *);
|
||||
struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req,
|
||||
struct rpc_timeout *timeout);
|
||||
void rpc_put_task(struct rpc_task *);
|
||||
void rpc_put_task_async(struct rpc_task *);
|
||||
bool rpc_task_set_rpc_status(struct rpc_task *task, int rpc_status);
|
||||
void rpc_task_try_cancel(struct rpc_task *task, int error);
|
||||
void rpc_signal_task(struct rpc_task *);
|
||||
void rpc_exit_task(struct rpc_task *);
|
||||
void rpc_exit(struct rpc_task *, int);
|
||||
void rpc_release_calldata(const struct rpc_call_ops *, void *);
|
||||
void rpc_killall_tasks(struct rpc_clnt *);
|
||||
unsigned long rpc_cancel_tasks(struct rpc_clnt *clnt, int error,
|
||||
bool (*fnmatch)(const struct rpc_task *,
|
||||
const void *),
|
||||
const void *data);
|
||||
void rpc_execute(struct rpc_task *);
|
||||
void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *);
|
||||
void rpc_init_wait_queue(struct rpc_wait_queue *, const char *);
|
||||
void rpc_destroy_wait_queue(struct rpc_wait_queue *);
|
||||
unsigned long rpc_task_timeout(const struct rpc_task *task);
|
||||
void rpc_sleep_on_timeout(struct rpc_wait_queue *queue,
|
||||
struct rpc_task *task,
|
||||
rpc_action action,
|
||||
unsigned long timeout);
|
||||
void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
|
||||
rpc_action action);
|
||||
void rpc_sleep_on_priority_timeout(struct rpc_wait_queue *queue,
|
||||
struct rpc_task *task,
|
||||
unsigned long timeout,
|
||||
int priority);
|
||||
void rpc_sleep_on_priority(struct rpc_wait_queue *,
|
||||
struct rpc_task *,
|
||||
int priority);
|
||||
void rpc_wake_up_queued_task(struct rpc_wait_queue *,
|
||||
struct rpc_task *);
|
||||
void rpc_wake_up_queued_task_set_status(struct rpc_wait_queue *,
|
||||
struct rpc_task *,
|
||||
int);
|
||||
void rpc_wake_up(struct rpc_wait_queue *);
|
||||
struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
|
||||
struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq,
|
||||
struct rpc_wait_queue *,
|
||||
bool (*)(struct rpc_task *, void *),
|
||||
void *);
|
||||
struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *,
|
||||
bool (*)(struct rpc_task *, void *),
|
||||
void *);
|
||||
void rpc_wake_up_status(struct rpc_wait_queue *, int);
|
||||
void rpc_delay(struct rpc_task *, unsigned long);
|
||||
int rpc_malloc(struct rpc_task *);
|
||||
void rpc_free(struct rpc_task *);
|
||||
int rpciod_up(void);
|
||||
void rpciod_down(void);
|
||||
int rpc_wait_for_completion_task(struct rpc_task *task);
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
struct net;
|
||||
void rpc_show_tasks(struct net *);
|
||||
#endif
|
||||
int rpc_init_mempool(void);
|
||||
void rpc_destroy_mempool(void);
|
||||
extern struct workqueue_struct *rpciod_workqueue;
|
||||
extern struct workqueue_struct *xprtiod_workqueue;
|
||||
void rpc_prepare_task(struct rpc_task *task);
|
||||
gfp_t rpc_task_gfp_mask(void);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
|
||||
static inline const char * rpc_qname(const struct rpc_wait_queue *q)
|
||||
{
|
||||
return ((q && q->name) ? q->name : "unknown");
|
||||
}
|
||||
|
||||
static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q,
|
||||
const char *name)
|
||||
{
|
||||
q->name = name;
|
||||
}
|
||||
#else
|
||||
static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q,
|
||||
const char *name)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_SWAP)
|
||||
int rpc_clnt_swap_activate(struct rpc_clnt *clnt);
|
||||
void rpc_clnt_swap_deactivate(struct rpc_clnt *clnt);
|
||||
#else
|
||||
static inline int
|
||||
rpc_clnt_swap_activate(struct rpc_clnt *clnt)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rpc_clnt_swap_deactivate(struct rpc_clnt *clnt)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_SUNRPC_SWAP */
|
||||
|
||||
#endif /* _LINUX_SUNRPC_SCHED_H_ */
|
||||
@@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/stats.h
|
||||
*
|
||||
* Client statistics collection for SUN RPC
|
||||
*
|
||||
* Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_STATS_H
|
||||
#define _LINUX_SUNRPC_STATS_H
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
struct rpc_stat {
|
||||
const struct rpc_program *program;
|
||||
|
||||
unsigned int netcnt,
|
||||
netudpcnt,
|
||||
nettcpcnt,
|
||||
nettcpconn,
|
||||
netreconn;
|
||||
unsigned int rpccnt,
|
||||
rpcretrans,
|
||||
rpcauthrefresh,
|
||||
rpcgarbage;
|
||||
};
|
||||
|
||||
struct svc_stat {
|
||||
struct svc_program * program;
|
||||
|
||||
unsigned int netcnt,
|
||||
netudpcnt,
|
||||
nettcpcnt,
|
||||
nettcpconn;
|
||||
unsigned int rpccnt,
|
||||
rpcbadfmt,
|
||||
rpcbadauth,
|
||||
rpcbadclnt;
|
||||
};
|
||||
|
||||
struct net;
|
||||
#ifdef CONFIG_PROC_FS
|
||||
int rpc_proc_init(struct net *);
|
||||
void rpc_proc_exit(struct net *);
|
||||
struct proc_dir_entry * rpc_proc_register(struct net *,struct rpc_stat *);
|
||||
void rpc_proc_unregister(struct net *,const char *);
|
||||
void rpc_proc_zero(const struct rpc_program *);
|
||||
struct proc_dir_entry * svc_proc_register(struct net *, struct svc_stat *,
|
||||
const struct proc_ops *);
|
||||
void svc_proc_unregister(struct net *, const char *);
|
||||
|
||||
void svc_seq_show(struct seq_file *,
|
||||
const struct svc_stat *);
|
||||
#else
|
||||
static inline int rpc_proc_init(struct net *net)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rpc_proc_exit(struct net *net)
|
||||
{
|
||||
}
|
||||
static inline struct proc_dir_entry *rpc_proc_register(struct net *net, struct rpc_stat *s) { return NULL; }
|
||||
static inline void rpc_proc_unregister(struct net *net, const char *p) {}
|
||||
static inline void rpc_proc_zero(const struct rpc_program *p) {}
|
||||
|
||||
static inline struct proc_dir_entry *svc_proc_register(struct net *net, struct svc_stat *s,
|
||||
const struct proc_ops *proc_ops) { return NULL; }
|
||||
static inline void svc_proc_unregister(struct net *net, const char *p) {}
|
||||
|
||||
static inline void svc_seq_show(struct seq_file *seq,
|
||||
const struct svc_stat *st) {}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_SUNRPC_STATS_H */
|
||||
@@ -0,0 +1,632 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/svc.h
|
||||
*
|
||||
* RPC server declarations.
|
||||
*
|
||||
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SUNRPC_SVC_H
|
||||
#define SUNRPC_SVC_H
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/sunrpc/types.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/auth.h>
|
||||
#include <linux/sunrpc/svcauth.h>
|
||||
#include <linux/lwq.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/folio_batch.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
/*
|
||||
*
|
||||
* RPC service thread pool.
|
||||
*
|
||||
* Pool of threads and temporary sockets. Generally there is only
|
||||
* a single one of these per RPC service, but on NUMA machines those
|
||||
* services that can benefit from it (i.e. nfs but not lockd) will
|
||||
* have one pool per NUMA node. This optimisation reduces cross-
|
||||
* node traffic on multi-node NUMA NFS servers.
|
||||
*/
|
||||
struct svc_pool {
|
||||
unsigned int sp_id; /* pool id; also node id on NUMA */
|
||||
unsigned int sp_nrthreads; /* # of threads currently running in pool */
|
||||
unsigned int sp_nrthrmin; /* Min number of threads to run per pool */
|
||||
unsigned int sp_nrthrmax; /* Max requested number of threads in pool */
|
||||
struct lwq sp_xprts; /* pending transports */
|
||||
struct list_head sp_all_threads; /* all server threads */
|
||||
struct llist_head sp_idle_threads; /* idle server threads */
|
||||
|
||||
/* statistics on pool operation */
|
||||
struct percpu_counter sp_messages_arrived;
|
||||
struct percpu_counter sp_sockets_queued;
|
||||
struct percpu_counter sp_threads_woken;
|
||||
|
||||
unsigned long sp_flags;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
/* bits for sp_flags */
|
||||
enum {
|
||||
SP_TASK_PENDING, /* still work to do even if no xprt is queued */
|
||||
SP_NEED_VICTIM, /* One thread needs to agree to exit */
|
||||
SP_VICTIM_REMAINS, /* One thread needs to actually exit */
|
||||
SP_TASK_STARTING, /* Task has started but not added to idle yet */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* RPC service.
|
||||
*
|
||||
* An RPC service is a ``daemon,'' possibly multithreaded, which
|
||||
* receives and processes incoming RPC messages.
|
||||
* It has one or more transport sockets associated with it, and maintains
|
||||
* a list of idle threads waiting for input.
|
||||
*
|
||||
* We currently do not support more than one RPC program per daemon.
|
||||
*/
|
||||
struct svc_serv {
|
||||
struct svc_program * sv_programs; /* RPC programs */
|
||||
struct svc_stat * sv_stats; /* RPC statistics */
|
||||
spinlock_t sv_lock;
|
||||
unsigned int sv_nprogs; /* Number of sv_programs */
|
||||
unsigned int sv_nrthreads; /* # of running server threads */
|
||||
unsigned int sv_max_payload; /* datagram payload size */
|
||||
unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */
|
||||
unsigned int sv_xdrsize; /* XDR buffer size */
|
||||
struct list_head sv_permsocks; /* all permanent sockets */
|
||||
struct list_head sv_tempsocks; /* all temporary sockets */
|
||||
int sv_tmpcnt; /* count of temporary "valid" sockets */
|
||||
struct timer_list sv_temptimer; /* timer for aging temporary sockets */
|
||||
|
||||
char * sv_name; /* service name */
|
||||
|
||||
unsigned int sv_nrpools; /* number of thread pools */
|
||||
bool sv_is_pooled; /* is this a pooled service? */
|
||||
struct svc_pool * sv_pools; /* array of thread pools */
|
||||
int (*sv_threadfn)(void *data);
|
||||
|
||||
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
|
||||
struct lwq sv_cb_list; /* queue for callback requests
|
||||
* that arrive over the same
|
||||
* connection */
|
||||
bool sv_bc_enabled; /* service uses backchannel */
|
||||
#endif /* CONFIG_SUNRPC_BACKCHANNEL */
|
||||
};
|
||||
|
||||
/* This is used by pool_stats to find and lock an svc */
|
||||
struct svc_info {
|
||||
struct svc_serv *serv;
|
||||
struct mutex *mutex;
|
||||
};
|
||||
|
||||
void svc_destroy(struct svc_serv **svcp);
|
||||
|
||||
/*
|
||||
* Maximum payload size supported by a kernel RPC server.
|
||||
* This is use to determine the max number of pages nfsd is
|
||||
* willing to return in a single READ operation.
|
||||
*
|
||||
* These happen to all be powers of 2, which is not strictly
|
||||
* necessary but helps enforce the real limitation, which is
|
||||
* that they should be multiples of PAGE_SIZE.
|
||||
*
|
||||
* For UDP transports, a block plus NFS,RPC, and UDP headers
|
||||
* has to fit into the IP datagram limit of 64K. The largest
|
||||
* feasible number for all known page sizes is probably 48K,
|
||||
* but we choose 32K here. This is the same as the historical
|
||||
* Linux limit; someone who cares more about NFS/UDP performance
|
||||
* can test a larger number.
|
||||
*
|
||||
* For non-UDP transports we have more freedom. A size of 4MB is
|
||||
* chosen to accommodate clients that support larger I/O sizes.
|
||||
*/
|
||||
enum {
|
||||
RPCSVC_MAXPAYLOAD = 4 * 1024 * 1024,
|
||||
RPCSVC_MAXPAYLOAD_TCP = RPCSVC_MAXPAYLOAD,
|
||||
RPCSVC_MAXPAYLOAD_UDP = 32 * 1024,
|
||||
};
|
||||
|
||||
extern u32 svc_max_payload(const struct svc_rqst *rqstp);
|
||||
|
||||
/*
|
||||
* RPC Call and Reply messages each have their own page array.
|
||||
* rq_pages holds the incoming Call message; rq_respages holds
|
||||
* the outgoing Reply message. Both arrays are sized to
|
||||
* svc_serv_maxpages() entries and are allocated dynamically.
|
||||
*
|
||||
* Pages are sent using ->sendmsg with MSG_SPLICE_PAGES so each
|
||||
* server thread needs to allocate more to replace those used in
|
||||
* sending.
|
||||
*
|
||||
* rq_pages request page contract:
|
||||
*
|
||||
* Transport receive paths that move request data pages out of
|
||||
* rq_pages -- TCP multi-fragment reassembly (svc_tcp_save_pages)
|
||||
* and RDMA Read I/O (svc_rdma_clear_rqst_pages) -- NULL those
|
||||
* entries to prevent svc_rqst_release_pages() from freeing pages
|
||||
* still in transport use, and set rq_pages_nfree to the count.
|
||||
* svc_alloc_arg() refills only that many rq_pages entries.
|
||||
*
|
||||
* For rq_respages, svc_rqst_release_pages() NULLs entries in
|
||||
* [rq_respages, rq_next_page) after each RPC. svc_alloc_arg()
|
||||
* refills only that range.
|
||||
*
|
||||
* xdr_buf holds responses; the structure fits NFS read responses
|
||||
* (header, data pages, optional tail) and enables sharing of
|
||||
* client-side routines.
|
||||
*
|
||||
* The xdr_buf.head kvec always points to the first page in the
|
||||
* rq_*pages list. The xdr_buf.pages pointer points to the second
|
||||
* page on that list. xdr_buf.tail points to the end of the first
|
||||
* page. This assumes that the non-page part of an rpc reply will
|
||||
* fit in a page - NFSd ensures this. lockd also has no trouble.
|
||||
*/
|
||||
|
||||
/**
|
||||
* svc_serv_maxpages - maximum count of pages needed for one RPC message
|
||||
* @serv: RPC service context
|
||||
*
|
||||
* Returns a count of pages or vectors that can hold the maximum
|
||||
* size RPC message for @serv.
|
||||
*
|
||||
* Each page array can hold at most one payload plus two
|
||||
* overhead pages (one for the RPC header, one for tail data).
|
||||
* nfsd_splice_actor() might need an extra page when a READ
|
||||
* payload is not page-aligned.
|
||||
*/
|
||||
static inline unsigned long svc_serv_maxpages(const struct svc_serv *serv)
|
||||
{
|
||||
return DIV_ROUND_UP(serv->sv_max_mesg, PAGE_SIZE) + 2 + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The context of a single thread, including the request currently being
|
||||
* processed.
|
||||
*
|
||||
* RPC programs are free to use rq_private to stash thread-local information.
|
||||
* The sunrpc layer will not access it.
|
||||
*/
|
||||
struct svc_rqst {
|
||||
struct list_head rq_all; /* all threads list */
|
||||
struct llist_node rq_idle; /* On the idle list */
|
||||
struct rcu_head rq_rcu_head; /* for RCU deferred kfree */
|
||||
struct svc_xprt * rq_xprt; /* transport ptr */
|
||||
|
||||
struct sockaddr_storage rq_addr; /* peer address */
|
||||
size_t rq_addrlen;
|
||||
struct sockaddr_storage rq_daddr; /* dest addr of request
|
||||
* - reply from here */
|
||||
size_t rq_daddrlen;
|
||||
|
||||
struct svc_serv * rq_server; /* RPC service definition */
|
||||
struct svc_pool * rq_pool; /* thread pool */
|
||||
const struct svc_procedure *rq_procinfo;/* procedure info */
|
||||
struct auth_ops * rq_authop; /* authentication flavour */
|
||||
struct svc_cred rq_cred; /* auth info */
|
||||
void * rq_xprt_ctxt; /* transport specific context ptr */
|
||||
struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */
|
||||
|
||||
struct xdr_buf rq_arg;
|
||||
struct xdr_stream rq_arg_stream;
|
||||
struct xdr_stream rq_res_stream;
|
||||
struct folio *rq_scratch_folio;
|
||||
struct xdr_buf rq_res;
|
||||
unsigned long rq_maxpages; /* entries per page array */
|
||||
unsigned long rq_pages_nfree; /* rq_pages entries NULLed by transport */
|
||||
struct page * *rq_pages; /* Call buffer pages */
|
||||
struct page * *rq_respages; /* Reply buffer pages */
|
||||
struct page * *rq_next_page; /* next reply page to use */
|
||||
struct page * *rq_page_end; /* one past the last reply page */
|
||||
|
||||
struct folio_batch rq_fbatch;
|
||||
struct bio_vec *rq_bvec;
|
||||
|
||||
__be32 rq_xid; /* transmission id */
|
||||
u32 rq_prog; /* program number */
|
||||
u32 rq_vers; /* program version */
|
||||
u32 rq_proc; /* procedure number */
|
||||
u32 rq_prot; /* IP protocol */
|
||||
unsigned long rq_flags; /* flags field */
|
||||
ktime_t rq_qtime; /* enqueue time */
|
||||
|
||||
void * rq_argp; /* decoded arguments */
|
||||
void * rq_resp; /* xdr'd results */
|
||||
__be32 *rq_accept_statp;
|
||||
void * rq_auth_data; /* flavor-specific data */
|
||||
__be32 rq_auth_stat; /* authentication status */
|
||||
int rq_auth_slack; /* extra space xdr code
|
||||
* should leave in head
|
||||
* for krb5i, krb5p.
|
||||
*/
|
||||
int rq_reserved; /* space on socket outq
|
||||
* reserved for this request
|
||||
*/
|
||||
ktime_t rq_stime; /* start time */
|
||||
|
||||
struct cache_req rq_chandle; /* handle passed to caches for
|
||||
* request delaying
|
||||
*/
|
||||
/* Catering to nfsd */
|
||||
struct auth_domain * rq_client; /* RPC peer info */
|
||||
struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
|
||||
struct task_struct *rq_task; /* service thread */
|
||||
struct net *rq_bc_net; /* pointer to backchannel's
|
||||
* net namespace
|
||||
*/
|
||||
|
||||
int rq_err; /* Thread sets this to inidicate
|
||||
* initialisation success.
|
||||
*/
|
||||
|
||||
unsigned long bc_to_initval;
|
||||
unsigned int bc_to_retries;
|
||||
unsigned int rq_status_counter; /* RPC processing counter */
|
||||
void *rq_private; /* For use by the service thread */
|
||||
};
|
||||
|
||||
/* bits for rq_flags */
|
||||
enum {
|
||||
RQ_SECURE, /* secure port */
|
||||
RQ_LOCAL, /* local request */
|
||||
RQ_USEDEFERRAL, /* use deferral */
|
||||
RQ_DROPME, /* drop current reply */
|
||||
RQ_VICTIM, /* Have agreed to shut down */
|
||||
RQ_DATA, /* request has data */
|
||||
};
|
||||
|
||||
#define SVC_NET(rqst) (rqst->rq_xprt ? rqst->rq_xprt->xpt_net : rqst->rq_bc_net)
|
||||
|
||||
/*
|
||||
* Rigorous type checking on sockaddr type conversions
|
||||
*/
|
||||
static inline struct sockaddr_in *svc_addr_in(const struct svc_rqst *rqst)
|
||||
{
|
||||
return (struct sockaddr_in *) &rqst->rq_addr;
|
||||
}
|
||||
|
||||
static inline struct sockaddr_in6 *svc_addr_in6(const struct svc_rqst *rqst)
|
||||
{
|
||||
return (struct sockaddr_in6 *) &rqst->rq_addr;
|
||||
}
|
||||
|
||||
static inline struct sockaddr *svc_addr(const struct svc_rqst *rqst)
|
||||
{
|
||||
return (struct sockaddr *) &rqst->rq_addr;
|
||||
}
|
||||
|
||||
static inline struct sockaddr_in *svc_daddr_in(const struct svc_rqst *rqst)
|
||||
{
|
||||
return (struct sockaddr_in *) &rqst->rq_daddr;
|
||||
}
|
||||
|
||||
static inline struct sockaddr_in6 *svc_daddr_in6(const struct svc_rqst *rqst)
|
||||
{
|
||||
return (struct sockaddr_in6 *) &rqst->rq_daddr;
|
||||
}
|
||||
|
||||
static inline struct sockaddr *svc_daddr(const struct svc_rqst *rqst)
|
||||
{
|
||||
return (struct sockaddr *) &rqst->rq_daddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_thread_should_stop - check if this thread should stop
|
||||
* @rqstp: the thread that might need to stop
|
||||
*
|
||||
* To stop an svc thread, the pool flags SP_NEED_VICTIM and SP_VICTIM_REMAINS
|
||||
* are set. The first thread which sees SP_NEED_VICTIM clears it, becoming
|
||||
* the victim using this function. It should then promptly call
|
||||
* svc_exit_thread() to complete the process, clearing SP_VICTIM_REMAINS
|
||||
* so the task waiting for a thread to exit can wake and continue.
|
||||
*
|
||||
* Return values:
|
||||
* %true: caller should invoke svc_exit_thread()
|
||||
* %false: caller should do nothing
|
||||
*/
|
||||
static inline bool svc_thread_should_stop(struct svc_rqst *rqstp)
|
||||
{
|
||||
if (test_and_clear_bit(SP_NEED_VICTIM, &rqstp->rq_pool->sp_flags))
|
||||
set_bit(RQ_VICTIM, &rqstp->rq_flags);
|
||||
|
||||
return test_bit(RQ_VICTIM, &rqstp->rq_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_thread_init_status - report whether thread has initialised successfully
|
||||
* @rqstp: the thread in question
|
||||
* @err: errno code
|
||||
*
|
||||
* After performing any initialisation that could fail, and before starting
|
||||
* normal work, each sunrpc svc_thread must call svc_thread_init_status()
|
||||
* with an appropriate error, or zero.
|
||||
*
|
||||
* If zero is passed, the thread is ready and must continue until
|
||||
* svc_thread_should_stop() returns true. If a non-zero error is passed
|
||||
* the call will not return - the thread will exit.
|
||||
*/
|
||||
static inline void svc_thread_init_status(struct svc_rqst *rqstp, int err)
|
||||
{
|
||||
store_release_wake_up(&rqstp->rq_err, err);
|
||||
if (err)
|
||||
kthread_exit(1);
|
||||
}
|
||||
|
||||
struct svc_deferred_req {
|
||||
u32 prot; /* protocol (UDP or TCP) */
|
||||
struct svc_xprt *xprt;
|
||||
struct sockaddr_storage addr; /* where reply must go */
|
||||
size_t addrlen;
|
||||
struct sockaddr_storage daddr; /* where reply must come from */
|
||||
size_t daddrlen;
|
||||
void *xprt_ctxt;
|
||||
struct cache_deferred_req handle;
|
||||
int argslen;
|
||||
__be32 args[];
|
||||
};
|
||||
|
||||
struct svc_process_info {
|
||||
union {
|
||||
int (*dispatch)(struct svc_rqst *rqstp);
|
||||
struct {
|
||||
unsigned int lovers;
|
||||
unsigned int hivers;
|
||||
} mismatch;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* RPC program - an array of these can use the same transport endpoint
|
||||
*/
|
||||
struct svc_program {
|
||||
u32 pg_prog; /* program number */
|
||||
unsigned int pg_lovers; /* lowest version */
|
||||
unsigned int pg_hivers; /* highest version */
|
||||
unsigned int pg_nvers; /* number of versions */
|
||||
const struct svc_version **pg_vers; /* version array */
|
||||
char * pg_name; /* service name */
|
||||
char * pg_class; /* class name: services sharing authentication */
|
||||
enum svc_auth_status (*pg_authenticate)(struct svc_rqst *rqstp);
|
||||
__be32 (*pg_init_request)(struct svc_rqst *,
|
||||
const struct svc_program *,
|
||||
struct svc_process_info *);
|
||||
int (*pg_rpcbind_set)(struct net *net,
|
||||
const struct svc_program *,
|
||||
u32 version, int family,
|
||||
unsigned short proto,
|
||||
unsigned short port);
|
||||
};
|
||||
|
||||
/*
|
||||
* RPC program version
|
||||
*/
|
||||
struct svc_version {
|
||||
u32 vs_vers; /* version number */
|
||||
u32 vs_nproc; /* number of procedures */
|
||||
const struct svc_procedure *vs_proc; /* per-procedure info */
|
||||
unsigned long __percpu *vs_count; /* call counts */
|
||||
u32 vs_xdrsize; /* xdrsize needed for this version */
|
||||
|
||||
/* Don't register with rpcbind */
|
||||
bool vs_hidden;
|
||||
|
||||
/* Don't care if the rpcbind registration fails */
|
||||
bool vs_rpcb_optnl;
|
||||
|
||||
/* Need xprt with congestion control */
|
||||
bool vs_need_cong_ctrl;
|
||||
|
||||
/* Dispatch function */
|
||||
int (*vs_dispatch)(struct svc_rqst *rqstp);
|
||||
};
|
||||
|
||||
/*
|
||||
* RPC procedure info
|
||||
*/
|
||||
struct svc_procedure {
|
||||
/* process the request: */
|
||||
__be32 (*pc_func)(struct svc_rqst *);
|
||||
/* XDR decode args: */
|
||||
bool (*pc_decode)(struct svc_rqst *rqstp,
|
||||
struct xdr_stream *xdr);
|
||||
/* XDR encode result: */
|
||||
bool (*pc_encode)(struct svc_rqst *rqstp,
|
||||
struct xdr_stream *xdr);
|
||||
/* XDR free result: */
|
||||
void (*pc_release)(struct svc_rqst *);
|
||||
unsigned int pc_argsize; /* argument struct size */
|
||||
unsigned int pc_argzero; /* how much of argument to clear */
|
||||
unsigned int pc_ressize; /* result struct size */
|
||||
unsigned int pc_cachetype; /* cache info (NFS) */
|
||||
unsigned int pc_xdrressize; /* maximum size of XDR reply */
|
||||
const char * pc_name; /* for display */
|
||||
};
|
||||
|
||||
/*
|
||||
* Function prototypes.
|
||||
*/
|
||||
int sunrpc_set_pool_mode(const char *val);
|
||||
int sunrpc_get_pool_mode(char *val, size_t size);
|
||||
void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
|
||||
int svc_bind(struct svc_serv *serv, struct net *net);
|
||||
struct svc_serv *svc_create(struct svc_program *, unsigned int,
|
||||
int (*threadfn)(void *data));
|
||||
bool svc_rqst_replace_page(struct svc_rqst *rqstp,
|
||||
struct page *page);
|
||||
void svc_rqst_release_pages(struct svc_rqst *rqstp);
|
||||
int svc_new_thread(struct svc_serv *serv, struct svc_pool *pool);
|
||||
void svc_exit_thread(struct svc_rqst *);
|
||||
struct svc_serv * svc_create_pooled(struct svc_program *prog,
|
||||
unsigned int nprog,
|
||||
struct svc_stat *stats,
|
||||
unsigned int bufsize,
|
||||
int (*threadfn)(void *data));
|
||||
int svc_set_pool_threads(struct svc_serv *serv, struct svc_pool *pool,
|
||||
unsigned int min_threads, unsigned int max_threads);
|
||||
int svc_set_num_threads(struct svc_serv *serv, unsigned int min_threads,
|
||||
unsigned int nrservs);
|
||||
int svc_pool_stats_open(struct svc_info *si, struct file *file);
|
||||
void svc_process(struct svc_rqst *rqstp);
|
||||
void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp);
|
||||
int svc_register(const struct svc_serv *, struct net *, const int,
|
||||
const unsigned short, const unsigned short);
|
||||
|
||||
void svc_wake_up(struct svc_serv *);
|
||||
void svc_reserve(struct svc_rqst *rqstp, int space);
|
||||
void svc_pool_wake_idle_thread(struct svc_pool *pool);
|
||||
struct svc_pool *svc_pool_for_cpu(struct svc_serv *serv);
|
||||
char * svc_print_addr(struct svc_rqst *, char *, size_t);
|
||||
const char * svc_proc_name(const struct svc_rqst *rqstp);
|
||||
int svc_encode_result_payload(struct svc_rqst *rqstp,
|
||||
unsigned int offset,
|
||||
unsigned int length);
|
||||
char *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
|
||||
struct kvec *first, void *p,
|
||||
size_t total);
|
||||
__be32 svc_generic_init_request(struct svc_rqst *rqstp,
|
||||
const struct svc_program *progp,
|
||||
struct svc_process_info *procinfo);
|
||||
int svc_generic_rpcbind_set(struct net *net,
|
||||
const struct svc_program *progp,
|
||||
u32 version, int family,
|
||||
unsigned short proto,
|
||||
unsigned short port);
|
||||
|
||||
#define RPC_MAX_ADDRBUFLEN (63U)
|
||||
|
||||
/**
|
||||
* svc_rqst_page_release - release a page associated with an RPC transaction
|
||||
* @rqstp: RPC transaction context
|
||||
* @page: page to release
|
||||
*
|
||||
* Released pages are batched and freed together, reducing
|
||||
* allocator pressure under heavy RPC workloads.
|
||||
*/
|
||||
static inline void svc_rqst_page_release(struct svc_rqst *rqstp,
|
||||
struct page *page)
|
||||
{
|
||||
if (!folio_batch_add(&rqstp->rq_fbatch, page_folio(page)))
|
||||
__folio_batch_release(&rqstp->rq_fbatch);
|
||||
}
|
||||
|
||||
/*
|
||||
* When we want to reduce the size of the reserved space in the response
|
||||
* buffer, we need to take into account the size of any checksum data that
|
||||
* may be at the end of the packet. This is difficult to determine exactly
|
||||
* for all cases without actually generating the checksum, so we just use a
|
||||
* static value.
|
||||
*/
|
||||
static inline void svc_reserve_auth(struct svc_rqst *rqstp, int space)
|
||||
{
|
||||
svc_reserve(rqstp, space + rqstp->rq_auth_slack);
|
||||
}
|
||||
|
||||
/**
|
||||
* svcxdr_init_decode - Prepare an xdr_stream for Call decoding
|
||||
* @rqstp: controlling server RPC transaction context
|
||||
*
|
||||
*/
|
||||
static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct xdr_buf *buf = &rqstp->rq_arg;
|
||||
struct kvec *argv = buf->head;
|
||||
|
||||
WARN_ON(buf->len != buf->head->iov_len + buf->page_len + buf->tail->iov_len);
|
||||
buf->len = buf->head->iov_len + buf->page_len + buf->tail->iov_len;
|
||||
|
||||
xdr_init_decode(xdr, buf, argv->iov_base, NULL);
|
||||
xdr_set_scratch_folio(xdr, rqstp->rq_scratch_folio);
|
||||
}
|
||||
|
||||
/**
|
||||
* svcxdr_init_encode - Prepare an xdr_stream for svc Reply encoding
|
||||
* @rqstp: controlling server RPC transaction context
|
||||
*
|
||||
*/
|
||||
static inline void svcxdr_init_encode(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_res_stream;
|
||||
struct xdr_buf *buf = &rqstp->rq_res;
|
||||
struct kvec *resv = buf->head;
|
||||
|
||||
xdr_reset_scratch_buffer(xdr);
|
||||
|
||||
xdr->buf = buf;
|
||||
xdr->iov = resv;
|
||||
xdr->p = resv->iov_base + resv->iov_len;
|
||||
xdr->end = resv->iov_base + PAGE_SIZE;
|
||||
buf->len = resv->iov_len;
|
||||
xdr->page_ptr = buf->pages - 1;
|
||||
buf->buflen = PAGE_SIZE * (rqstp->rq_page_end - buf->pages);
|
||||
xdr->rqst = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* svcxdr_encode_opaque_pages - Insert pages into an xdr_stream
|
||||
* @xdr: xdr_stream to be updated
|
||||
* @pages: array of pages to insert
|
||||
* @base: starting offset of first data byte in @pages
|
||||
* @len: number of data bytes in @pages to insert
|
||||
*
|
||||
* After the @pages are added, the tail iovec is instantiated pointing
|
||||
* to end of the head buffer, and the stream is set up to encode
|
||||
* subsequent items into the tail.
|
||||
*/
|
||||
static inline void svcxdr_encode_opaque_pages(struct svc_rqst *rqstp,
|
||||
struct xdr_stream *xdr,
|
||||
struct page **pages,
|
||||
unsigned int base,
|
||||
unsigned int len)
|
||||
{
|
||||
xdr_write_pages(xdr, pages, base, len);
|
||||
xdr->page_ptr = rqstp->rq_next_page - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* svcxdr_set_auth_slack -
|
||||
* @rqstp: RPC transaction
|
||||
* @slack: buffer space to reserve for the transaction's security flavor
|
||||
*
|
||||
* Set the request's slack space requirement, and set aside that much
|
||||
* space in the rqstp's rq_res.head for use when the auth wraps the Reply.
|
||||
*/
|
||||
static inline void svcxdr_set_auth_slack(struct svc_rqst *rqstp, int slack)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_res_stream;
|
||||
struct xdr_buf *buf = &rqstp->rq_res;
|
||||
struct kvec *resv = buf->head;
|
||||
|
||||
rqstp->rq_auth_slack = slack;
|
||||
|
||||
xdr->end -= XDR_QUADLEN(slack);
|
||||
buf->buflen -= rqstp->rq_auth_slack;
|
||||
|
||||
WARN_ON(xdr->iov != resv);
|
||||
WARN_ON(xdr->p > xdr->end);
|
||||
}
|
||||
|
||||
/**
|
||||
* svcxdr_set_accept_stat - Reserve space for the accept_stat field
|
||||
* @rqstp: RPC transaction context
|
||||
*
|
||||
* Return values:
|
||||
* %true: Success
|
||||
* %false: No response buffer space was available
|
||||
*/
|
||||
static inline bool svcxdr_set_accept_stat(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_res_stream;
|
||||
|
||||
rqstp->rq_accept_statp = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
if (unlikely(!rqstp->rq_accept_statp))
|
||||
return false;
|
||||
*rqstp->rq_accept_statp = rpc_success;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* SUNRPC_SVC_H */
|
||||
@@ -0,0 +1,340 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the BSD-type
|
||||
* license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* Neither the name of the Network Appliance, Inc. nor the names of
|
||||
* its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Author: Tom Tucker <tom@opengridcomputing.com>
|
||||
*/
|
||||
|
||||
#ifndef SVC_RDMA_H
|
||||
#define SVC_RDMA_H
|
||||
#include <linux/llist.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/sunrpc/rpc_rdma.h>
|
||||
#include <linux/sunrpc/rpc_rdma_cid.h>
|
||||
#include <linux/sunrpc/svc_rdma_pcl.h>
|
||||
#include <linux/sunrpc/rdma_rn.h>
|
||||
|
||||
#include <linux/percpu_counter.h>
|
||||
#include <rdma/ib_verbs.h>
|
||||
#include <rdma/rdma_cm.h>
|
||||
|
||||
/* Default and maximum inline threshold sizes */
|
||||
enum {
|
||||
RPCRDMA_PULLUP_THRESH = RPCRDMA_V1_DEF_INLINE_SIZE >> 1,
|
||||
RPCRDMA_DEF_INLINE_THRESH = 4096,
|
||||
RPCRDMA_MAX_INLINE_THRESH = 65536
|
||||
};
|
||||
|
||||
/* RPC/RDMA parameters and stats */
|
||||
extern unsigned int svcrdma_ord;
|
||||
extern unsigned int svcrdma_max_requests;
|
||||
extern unsigned int svcrdma_max_bc_requests;
|
||||
extern unsigned int svcrdma_max_req_size;
|
||||
extern struct workqueue_struct *svcrdma_wq;
|
||||
|
||||
extern struct percpu_counter svcrdma_stat_read;
|
||||
extern struct percpu_counter svcrdma_stat_recv;
|
||||
extern struct percpu_counter svcrdma_stat_sq_starve;
|
||||
extern struct percpu_counter svcrdma_stat_write;
|
||||
|
||||
struct svcxprt_rdma {
|
||||
struct svc_xprt sc_xprt; /* SVC transport structure */
|
||||
struct rdma_cm_id *sc_cm_id; /* RDMA connection id */
|
||||
struct list_head sc_accept_q; /* Conn. waiting accept */
|
||||
struct rpcrdma_notification sc_rn; /* removal notification */
|
||||
int sc_ord; /* RDMA read limit */
|
||||
int sc_max_send_sges;
|
||||
bool sc_snd_w_inv; /* OK to use Send With Invalidate */
|
||||
|
||||
atomic_t sc_sq_avail; /* SQEs ready to be consumed */
|
||||
unsigned int sc_sq_depth; /* Depth of SQ */
|
||||
atomic_t sc_sq_ticket_head; /* Next ticket to issue */
|
||||
atomic_t sc_sq_ticket_tail; /* Ticket currently serving */
|
||||
wait_queue_head_t sc_sq_ticket_wait; /* Ticket ordering waitlist */
|
||||
__be32 sc_fc_credits; /* Forward credits */
|
||||
u32 sc_max_requests; /* Max requests */
|
||||
u32 sc_max_bc_requests;/* Backward credits */
|
||||
int sc_max_req_size; /* Size of each RQ WR buf */
|
||||
u8 sc_port_num;
|
||||
|
||||
struct ib_pd *sc_pd;
|
||||
|
||||
spinlock_t sc_send_lock;
|
||||
struct llist_head sc_send_ctxts;
|
||||
spinlock_t sc_rw_ctxt_lock;
|
||||
struct llist_head sc_rw_ctxts;
|
||||
|
||||
u32 sc_pending_recvs;
|
||||
u32 sc_recv_batch;
|
||||
struct list_head sc_rq_dto_q;
|
||||
struct list_head sc_read_complete_q;
|
||||
spinlock_t sc_rq_dto_lock;
|
||||
struct ib_qp *sc_qp;
|
||||
struct ib_cq *sc_rq_cq;
|
||||
struct ib_cq *sc_sq_cq;
|
||||
|
||||
spinlock_t sc_lock; /* transport lock */
|
||||
|
||||
wait_queue_head_t sc_send_wait; /* SQ exhaustion waitlist */
|
||||
unsigned long sc_flags;
|
||||
struct work_struct sc_work;
|
||||
|
||||
struct llist_head sc_recv_ctxts;
|
||||
|
||||
atomic_t sc_completion_ids;
|
||||
};
|
||||
/* sc_flags */
|
||||
#define RDMAXPRT_CONN_PENDING 3
|
||||
|
||||
static inline struct svcxprt_rdma *svc_rdma_rqst_rdma(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct svc_xprt *xprt = rqstp->rq_xprt;
|
||||
|
||||
return container_of(xprt, struct svcxprt_rdma, sc_xprt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Default connection parameters
|
||||
*/
|
||||
enum {
|
||||
RPCRDMA_LISTEN_BACKLOG = 10,
|
||||
RPCRDMA_MAX_REQUESTS = 128,
|
||||
RPCRDMA_MAX_BC_REQUESTS = 2,
|
||||
};
|
||||
|
||||
#define RPCSVC_MAXPAYLOAD_RDMA RPCSVC_MAXPAYLOAD
|
||||
|
||||
/**
|
||||
* svc_rdma_send_cid_init - Initialize a Receive Queue completion ID
|
||||
* @rdma: controlling transport
|
||||
* @cid: completion ID to initialize
|
||||
*/
|
||||
static inline void svc_rdma_recv_cid_init(struct svcxprt_rdma *rdma,
|
||||
struct rpc_rdma_cid *cid)
|
||||
{
|
||||
cid->ci_queue_id = rdma->sc_rq_cq->res.id;
|
||||
cid->ci_completion_id = atomic_inc_return(&rdma->sc_completion_ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_rdma_send_cid_init - Initialize a Send Queue completion ID
|
||||
* @rdma: controlling transport
|
||||
* @cid: completion ID to initialize
|
||||
*/
|
||||
static inline void svc_rdma_send_cid_init(struct svcxprt_rdma *rdma,
|
||||
struct rpc_rdma_cid *cid)
|
||||
{
|
||||
cid->ci_queue_id = rdma->sc_sq_cq->res.id;
|
||||
cid->ci_completion_id = atomic_inc_return(&rdma->sc_completion_ids);
|
||||
}
|
||||
|
||||
/*
|
||||
* A chunk context tracks all I/O for moving one Read or Write
|
||||
* chunk. This is a set of rdma_rw's that handle data movement
|
||||
* for all segments of one chunk.
|
||||
*/
|
||||
struct svc_rdma_chunk_ctxt {
|
||||
struct rpc_rdma_cid cc_cid;
|
||||
struct ib_cqe cc_cqe;
|
||||
struct list_head cc_rwctxts;
|
||||
ktime_t cc_posttime;
|
||||
int cc_sqecount;
|
||||
};
|
||||
|
||||
struct svc_rdma_recv_ctxt {
|
||||
struct llist_node rc_node;
|
||||
struct list_head rc_list;
|
||||
struct ib_recv_wr rc_recv_wr;
|
||||
struct ib_cqe rc_cqe;
|
||||
struct rpc_rdma_cid rc_cid;
|
||||
struct ib_sge rc_recv_sge;
|
||||
void *rc_recv_buf;
|
||||
struct xdr_stream rc_stream;
|
||||
u32 rc_byte_len;
|
||||
u32 rc_inv_rkey;
|
||||
__be32 rc_msgtype;
|
||||
|
||||
/* State for pulling a Read chunk */
|
||||
unsigned int rc_pageoff;
|
||||
unsigned int rc_curpage;
|
||||
unsigned int rc_readbytes;
|
||||
struct xdr_buf rc_saved_arg;
|
||||
struct svc_rdma_chunk_ctxt rc_cc;
|
||||
|
||||
struct svc_rdma_pcl rc_call_pcl;
|
||||
|
||||
struct svc_rdma_pcl rc_read_pcl;
|
||||
struct svc_rdma_chunk *rc_cur_result_payload;
|
||||
struct svc_rdma_pcl rc_write_pcl;
|
||||
struct svc_rdma_pcl rc_reply_pcl;
|
||||
|
||||
unsigned int rc_page_count;
|
||||
unsigned long rc_maxpages;
|
||||
struct page *rc_pages[] __counted_by(rc_maxpages);
|
||||
};
|
||||
|
||||
/*
|
||||
* State for sending a Write chunk.
|
||||
* - Tracks progress of writing one chunk over all its segments
|
||||
* - Stores arguments for the SGL constructor functions
|
||||
*/
|
||||
struct svc_rdma_write_info {
|
||||
struct svcxprt_rdma *wi_rdma;
|
||||
struct list_head wi_list;
|
||||
|
||||
const struct svc_rdma_chunk *wi_chunk;
|
||||
|
||||
/* write state of this chunk */
|
||||
unsigned int wi_seg_off;
|
||||
unsigned int wi_seg_no;
|
||||
|
||||
/* SGL constructor arguments */
|
||||
const struct xdr_buf *wi_xdr;
|
||||
unsigned char *wi_base;
|
||||
unsigned int wi_next_off;
|
||||
|
||||
struct svc_rdma_chunk_ctxt wi_cc;
|
||||
struct work_struct wi_work;
|
||||
};
|
||||
|
||||
struct svc_rdma_send_ctxt {
|
||||
struct llist_node sc_node;
|
||||
struct rpc_rdma_cid sc_cid;
|
||||
struct work_struct sc_work;
|
||||
|
||||
struct svcxprt_rdma *sc_rdma;
|
||||
struct ib_send_wr sc_send_wr;
|
||||
struct ib_send_wr *sc_wr_chain;
|
||||
int sc_sqecount;
|
||||
struct ib_cqe sc_cqe;
|
||||
struct xdr_buf sc_hdrbuf;
|
||||
struct xdr_stream sc_stream;
|
||||
|
||||
struct list_head sc_write_info_list;
|
||||
struct svc_rdma_write_info sc_reply_info;
|
||||
|
||||
void *sc_xprt_buf;
|
||||
int sc_page_count;
|
||||
int sc_cur_sge_no;
|
||||
unsigned long sc_maxpages;
|
||||
struct page **sc_pages;
|
||||
struct ib_sge sc_sges[];
|
||||
};
|
||||
|
||||
/* svc_rdma_backchannel.c */
|
||||
extern void svc_rdma_handle_bc_reply(struct svc_rqst *rqstp,
|
||||
struct svc_rdma_recv_ctxt *rctxt);
|
||||
|
||||
/* svc_rdma_recvfrom.c */
|
||||
extern void svc_rdma_recv_ctxts_destroy(struct svcxprt_rdma *rdma);
|
||||
extern bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma);
|
||||
extern struct svc_rdma_recv_ctxt *
|
||||
svc_rdma_recv_ctxt_get(struct svcxprt_rdma *rdma);
|
||||
extern void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_recv_ctxt *ctxt);
|
||||
extern void svc_rdma_flush_recv_queues(struct svcxprt_rdma *rdma);
|
||||
extern void svc_rdma_release_ctxt(struct svc_xprt *xprt, void *ctxt);
|
||||
extern int svc_rdma_recvfrom(struct svc_rqst *);
|
||||
|
||||
/* svc_rdma_rw.c */
|
||||
extern void svc_rdma_cc_init(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_chunk_ctxt *cc);
|
||||
extern void svc_rdma_destroy_rw_ctxts(struct svcxprt_rdma *rdma);
|
||||
extern void svc_rdma_cc_init(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_chunk_ctxt *cc);
|
||||
extern void svc_rdma_cc_release(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_chunk_ctxt *cc,
|
||||
enum dma_data_direction dir);
|
||||
extern void svc_rdma_write_chunk_release(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *ctxt);
|
||||
extern void svc_rdma_reply_chunk_release(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *ctxt);
|
||||
extern int svc_rdma_prepare_write_list(struct svcxprt_rdma *rdma,
|
||||
const struct svc_rdma_recv_ctxt *rctxt,
|
||||
struct svc_rdma_send_ctxt *sctxt,
|
||||
const struct xdr_buf *xdr);
|
||||
extern int svc_rdma_prepare_reply_chunk(struct svcxprt_rdma *rdma,
|
||||
const struct svc_rdma_pcl *write_pcl,
|
||||
const struct svc_rdma_pcl *reply_pcl,
|
||||
struct svc_rdma_send_ctxt *sctxt,
|
||||
const struct xdr_buf *xdr);
|
||||
extern int svc_rdma_process_read_list(struct svcxprt_rdma *rdma,
|
||||
struct svc_rqst *rqstp,
|
||||
struct svc_rdma_recv_ctxt *head);
|
||||
|
||||
/* svc_rdma_sendto.c */
|
||||
extern void svc_rdma_send_ctxts_destroy(struct svcxprt_rdma *rdma);
|
||||
extern struct svc_rdma_send_ctxt *
|
||||
svc_rdma_send_ctxt_get(struct svcxprt_rdma *rdma);
|
||||
extern void svc_rdma_send_ctxt_put(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *ctxt);
|
||||
extern int svc_rdma_post_send(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *ctxt);
|
||||
extern int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *sctxt,
|
||||
const struct svc_rdma_pcl *write_pcl,
|
||||
const struct svc_rdma_pcl *reply_pcl,
|
||||
const struct xdr_buf *xdr);
|
||||
extern void svc_rdma_send_error_msg(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *sctxt,
|
||||
struct svc_rdma_recv_ctxt *rctxt,
|
||||
int status);
|
||||
extern void svc_rdma_wake_send_waiters(struct svcxprt_rdma *rdma, int avail);
|
||||
extern int svc_rdma_sq_wait(struct svcxprt_rdma *rdma,
|
||||
const struct rpc_rdma_cid *cid, int sqecount);
|
||||
extern int svc_rdma_post_send_err(struct svcxprt_rdma *rdma,
|
||||
const struct rpc_rdma_cid *cid,
|
||||
const struct ib_send_wr *bad_wr,
|
||||
const struct ib_send_wr *first_wr,
|
||||
int sqecount, int ret);
|
||||
extern int svc_rdma_sendto(struct svc_rqst *);
|
||||
extern int svc_rdma_result_payload(struct svc_rqst *rqstp, unsigned int offset,
|
||||
unsigned int length);
|
||||
|
||||
/* svc_rdma_transport.c */
|
||||
extern struct svc_xprt_class svc_rdma_class;
|
||||
#ifdef CONFIG_SUNRPC_BACKCHANNEL
|
||||
extern struct svc_xprt_class svc_rdma_bc_class;
|
||||
#endif
|
||||
|
||||
/* svc_rdma.c */
|
||||
extern int svc_rdma_init(void);
|
||||
extern void svc_rdma_cleanup(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates
|
||||
*/
|
||||
|
||||
#ifndef SVC_RDMA_PCL_H
|
||||
#define SVC_RDMA_PCL_H
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
struct svc_rdma_segment {
|
||||
u32 rs_handle;
|
||||
u32 rs_length;
|
||||
u64 rs_offset;
|
||||
};
|
||||
|
||||
struct svc_rdma_chunk {
|
||||
struct list_head ch_list;
|
||||
|
||||
u32 ch_position;
|
||||
u32 ch_length;
|
||||
u32 ch_payload_length;
|
||||
|
||||
u32 ch_segcount;
|
||||
struct svc_rdma_segment ch_segments[];
|
||||
};
|
||||
|
||||
struct svc_rdma_pcl {
|
||||
unsigned int cl_count;
|
||||
struct list_head cl_chunks;
|
||||
};
|
||||
|
||||
/**
|
||||
* pcl_init - Initialize a parsed chunk list
|
||||
* @pcl: parsed chunk list to initialize
|
||||
*
|
||||
*/
|
||||
static inline void pcl_init(struct svc_rdma_pcl *pcl)
|
||||
{
|
||||
INIT_LIST_HEAD(&pcl->cl_chunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* pcl_is_empty - Return true if parsed chunk list is empty
|
||||
* @pcl: parsed chunk list
|
||||
*
|
||||
*/
|
||||
static inline bool pcl_is_empty(const struct svc_rdma_pcl *pcl)
|
||||
{
|
||||
return list_empty(&pcl->cl_chunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* pcl_first_chunk - Return first chunk in a parsed chunk list
|
||||
* @pcl: parsed chunk list
|
||||
*
|
||||
* Returns the first chunk in the list, or NULL if the list is empty.
|
||||
*/
|
||||
static inline struct svc_rdma_chunk *
|
||||
pcl_first_chunk(const struct svc_rdma_pcl *pcl)
|
||||
{
|
||||
if (pcl_is_empty(pcl))
|
||||
return NULL;
|
||||
return list_first_entry(&pcl->cl_chunks, struct svc_rdma_chunk,
|
||||
ch_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* pcl_next_chunk - Return next chunk in a parsed chunk list
|
||||
* @pcl: a parsed chunk list
|
||||
* @chunk: chunk in @pcl
|
||||
*
|
||||
* Returns the next chunk in the list, or NULL if @chunk is already last.
|
||||
*/
|
||||
static inline struct svc_rdma_chunk *
|
||||
pcl_next_chunk(const struct svc_rdma_pcl *pcl, struct svc_rdma_chunk *chunk)
|
||||
{
|
||||
if (list_is_last(&chunk->ch_list, &pcl->cl_chunks))
|
||||
return NULL;
|
||||
return list_next_entry(chunk, ch_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* pcl_for_each_chunk - Iterate over chunks in a parsed chunk list
|
||||
* @pos: the loop cursor
|
||||
* @pcl: a parsed chunk list
|
||||
*/
|
||||
#define pcl_for_each_chunk(pos, pcl) \
|
||||
for (pos = list_first_entry(&(pcl)->cl_chunks, struct svc_rdma_chunk, ch_list); \
|
||||
&pos->ch_list != &(pcl)->cl_chunks; \
|
||||
pos = list_next_entry(pos, ch_list))
|
||||
|
||||
/**
|
||||
* pcl_for_each_segment - Iterate over segments in a parsed chunk
|
||||
* @pos: the loop cursor
|
||||
* @chunk: a parsed chunk
|
||||
*/
|
||||
#define pcl_for_each_segment(pos, chunk) \
|
||||
for (pos = &(chunk)->ch_segments[0]; \
|
||||
pos <= &(chunk)->ch_segments[(chunk)->ch_segcount - 1]; \
|
||||
pos++)
|
||||
|
||||
/**
|
||||
* pcl_chunk_end_offset - Return offset of byte range following @chunk
|
||||
* @chunk: chunk in @pcl
|
||||
*
|
||||
* Returns starting offset of the region just after @chunk
|
||||
*/
|
||||
static inline unsigned int
|
||||
pcl_chunk_end_offset(const struct svc_rdma_chunk *chunk)
|
||||
{
|
||||
return xdr_align_size(chunk->ch_position + chunk->ch_payload_length);
|
||||
}
|
||||
|
||||
struct svc_rdma_recv_ctxt;
|
||||
|
||||
extern void pcl_free(struct svc_rdma_pcl *pcl);
|
||||
extern bool pcl_alloc_call(struct svc_rdma_recv_ctxt *rctxt, __be32 *p);
|
||||
extern bool pcl_alloc_read(struct svc_rdma_recv_ctxt *rctxt, __be32 *p);
|
||||
extern bool pcl_alloc_write(struct svc_rdma_recv_ctxt *rctxt,
|
||||
struct svc_rdma_pcl *pcl, __be32 *p);
|
||||
extern int pcl_process_nonpayloads(const struct svc_rdma_pcl *pcl,
|
||||
const struct xdr_buf *xdr,
|
||||
int (*actor)(const struct xdr_buf *,
|
||||
void *),
|
||||
void *data);
|
||||
|
||||
#endif /* SVC_RDMA_PCL_H */
|
||||
@@ -0,0 +1,272 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/svc_xprt.h
|
||||
*
|
||||
* RPC server transport I/O
|
||||
*/
|
||||
|
||||
#ifndef SUNRPC_SVC_XPRT_H
|
||||
#define SUNRPC_SVC_XPRT_H
|
||||
|
||||
#include <linux/sunrpc/svc.h>
|
||||
|
||||
struct module;
|
||||
|
||||
struct svc_xprt_ops {
|
||||
struct svc_xprt *(*xpo_create)(struct svc_serv *,
|
||||
struct net *net,
|
||||
struct sockaddr *, int,
|
||||
int);
|
||||
struct svc_xprt *(*xpo_accept)(struct svc_xprt *);
|
||||
int (*xpo_has_wspace)(struct svc_xprt *);
|
||||
int (*xpo_recvfrom)(struct svc_rqst *);
|
||||
int (*xpo_sendto)(struct svc_rqst *);
|
||||
int (*xpo_result_payload)(struct svc_rqst *, unsigned int,
|
||||
unsigned int);
|
||||
void (*xpo_release_ctxt)(struct svc_xprt *xprt, void *ctxt);
|
||||
void (*xpo_detach)(struct svc_xprt *);
|
||||
void (*xpo_free)(struct svc_xprt *);
|
||||
void (*xpo_kill_temp_xprt)(struct svc_xprt *);
|
||||
void (*xpo_handshake)(struct svc_xprt *xprt);
|
||||
};
|
||||
|
||||
struct svc_xprt_class {
|
||||
const char *xcl_name;
|
||||
struct module *xcl_owner;
|
||||
const struct svc_xprt_ops *xcl_ops;
|
||||
struct list_head xcl_list;
|
||||
u32 xcl_max_payload;
|
||||
int xcl_ident;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is embedded in an object that wants a callback before deleting
|
||||
* an xprt; intended for use by NFSv4.1, which needs to know when a
|
||||
* client's tcp connection (and hence possibly a backchannel) goes away.
|
||||
*/
|
||||
struct svc_xpt_user {
|
||||
struct list_head list;
|
||||
void (*callback)(struct svc_xpt_user *);
|
||||
};
|
||||
|
||||
struct svc_xprt {
|
||||
struct svc_xprt_class *xpt_class;
|
||||
const struct svc_xprt_ops *xpt_ops;
|
||||
struct kref xpt_ref;
|
||||
ktime_t xpt_qtime;
|
||||
struct list_head xpt_list;
|
||||
struct lwq_node xpt_ready;
|
||||
unsigned long xpt_flags;
|
||||
|
||||
struct svc_serv *xpt_server; /* service for transport */
|
||||
atomic_t xpt_reserved; /* space on outq that is rsvd */
|
||||
atomic_t xpt_nr_rqsts; /* Number of requests */
|
||||
struct mutex xpt_mutex; /* to serialize sending data */
|
||||
spinlock_t xpt_lock; /* protects sk_deferred
|
||||
* and xpt_auth_cache */
|
||||
void *xpt_auth_cache;/* auth cache */
|
||||
struct list_head xpt_deferred; /* deferred requests that need
|
||||
* to be revisted */
|
||||
struct sockaddr_storage xpt_local; /* local address */
|
||||
size_t xpt_locallen; /* length of address */
|
||||
struct sockaddr_storage xpt_remote; /* remote peer's address */
|
||||
size_t xpt_remotelen; /* length of address */
|
||||
char xpt_remotebuf[INET6_ADDRSTRLEN + 10];
|
||||
struct list_head xpt_users; /* callbacks on free */
|
||||
|
||||
struct net *xpt_net;
|
||||
netns_tracker ns_tracker;
|
||||
const struct cred *xpt_cred;
|
||||
struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */
|
||||
struct rpc_xprt_switch *xpt_bc_xps; /* NFSv4.1 backchannel */
|
||||
};
|
||||
|
||||
/* flag bits for xpt_flags */
|
||||
enum {
|
||||
XPT_BUSY, /* enqueued/receiving */
|
||||
XPT_CONN, /* conn pending */
|
||||
XPT_CLOSE, /* dead or dying */
|
||||
XPT_DATA, /* data pending */
|
||||
XPT_TEMP, /* connected transport */
|
||||
XPT_DEAD, /* transport closed */
|
||||
XPT_CHNGBUF, /* need to change snd/rcv buf sizes */
|
||||
XPT_DEFERRED, /* deferred request pending */
|
||||
XPT_OLD, /* used for xprt aging mark+sweep */
|
||||
XPT_LISTENER, /* listening endpoint */
|
||||
XPT_CACHE_AUTH, /* cache auth info */
|
||||
XPT_LOCAL, /* connection from loopback interface */
|
||||
XPT_KILL_TEMP, /* call xpo_kill_temp_xprt before closing */
|
||||
XPT_CONG_CTRL, /* has congestion control */
|
||||
XPT_HANDSHAKE, /* xprt requests a handshake */
|
||||
XPT_TLS_SESSION, /* transport-layer security established */
|
||||
XPT_PEER_AUTH, /* peer has been authenticated */
|
||||
XPT_PEER_VALID, /* peer has presented a filehandle that
|
||||
* it has access to. It is NOT counted
|
||||
* in ->sv_tmpcnt.
|
||||
*/
|
||||
XPT_RPCB_UNREG, /* transport that needs unregistering
|
||||
* with rpcbind (TCP, UDP) on destroy
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum number of "tmp" connections - those without XPT_PEER_VALID -
|
||||
* permitted on any service.
|
||||
*/
|
||||
#define XPT_MAX_TMP_CONN 64
|
||||
|
||||
static inline void svc_xprt_set_valid(struct svc_xprt *xpt)
|
||||
{
|
||||
if (test_bit(XPT_TEMP, &xpt->xpt_flags) &&
|
||||
!test_and_set_bit(XPT_PEER_VALID, &xpt->xpt_flags)) {
|
||||
struct svc_serv *serv = xpt->xpt_server;
|
||||
|
||||
spin_lock(&serv->sv_lock);
|
||||
serv->sv_tmpcnt -= 1;
|
||||
spin_unlock(&serv->sv_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
|
||||
{
|
||||
spin_lock(&xpt->xpt_lock);
|
||||
list_del_init(&u->list);
|
||||
spin_unlock(&xpt->xpt_lock);
|
||||
}
|
||||
|
||||
static inline int register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
|
||||
{
|
||||
spin_lock(&xpt->xpt_lock);
|
||||
if (test_bit(XPT_CLOSE, &xpt->xpt_flags)) {
|
||||
/*
|
||||
* The connection is about to be deleted soon (or,
|
||||
* worse, may already be deleted--in which case we've
|
||||
* already notified the xpt_users).
|
||||
*/
|
||||
spin_unlock(&xpt->xpt_lock);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
list_add(&u->list, &xpt->xpt_users);
|
||||
spin_unlock(&xpt->xpt_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool svc_xprt_is_dead(const struct svc_xprt *xprt)
|
||||
{
|
||||
return (test_bit(XPT_DEAD, &xprt->xpt_flags) != 0) ||
|
||||
(test_bit(XPT_CLOSE, &xprt->xpt_flags) != 0);
|
||||
}
|
||||
|
||||
int svc_reg_xprt_class(struct svc_xprt_class *);
|
||||
void svc_unreg_xprt_class(struct svc_xprt_class *);
|
||||
void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *,
|
||||
struct svc_serv *);
|
||||
int svc_xprt_create_from_sa(struct svc_serv *serv, const char *xprt_name,
|
||||
struct net *net, struct sockaddr *sap,
|
||||
int flags, const struct cred *cred);
|
||||
int svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
|
||||
struct net *net, const int family,
|
||||
const unsigned short port, int flags,
|
||||
const struct cred *cred);
|
||||
void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net,
|
||||
bool unregister);
|
||||
void svc_xprt_received(struct svc_xprt *xprt);
|
||||
void svc_xprt_enqueue(struct svc_xprt *xprt);
|
||||
void svc_xprt_put(struct svc_xprt *xprt);
|
||||
void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt);
|
||||
void svc_xprt_close(struct svc_xprt *xprt);
|
||||
int svc_port_is_privileged(struct sockaddr *sin);
|
||||
int svc_print_xprts(char *buf, int maxlen);
|
||||
struct svc_xprt *svc_find_listener(struct svc_serv *serv, const char *xcl_name,
|
||||
struct net *net, const struct sockaddr *sa);
|
||||
struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
|
||||
struct net *net, const sa_family_t af,
|
||||
const unsigned short port);
|
||||
int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
|
||||
void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt);
|
||||
void svc_age_temp_xprts_now(struct svc_serv *, struct sockaddr *);
|
||||
void svc_xprt_deferred_close(struct svc_xprt *xprt);
|
||||
|
||||
static inline void svc_xprt_get(struct svc_xprt *xprt)
|
||||
{
|
||||
kref_get(&xprt->xpt_ref);
|
||||
}
|
||||
static inline void svc_xprt_set_local(struct svc_xprt *xprt,
|
||||
const struct sockaddr *sa,
|
||||
const size_t salen)
|
||||
{
|
||||
memcpy(&xprt->xpt_local, sa, salen);
|
||||
xprt->xpt_locallen = salen;
|
||||
}
|
||||
static inline void svc_xprt_set_remote(struct svc_xprt *xprt,
|
||||
const struct sockaddr *sa,
|
||||
const size_t salen)
|
||||
{
|
||||
memcpy(&xprt->xpt_remote, sa, salen);
|
||||
xprt->xpt_remotelen = salen;
|
||||
snprintf(xprt->xpt_remotebuf, sizeof(xprt->xpt_remotebuf) - 1,
|
||||
"%pISpc", sa);
|
||||
}
|
||||
|
||||
static inline unsigned short svc_addr_port(const struct sockaddr *sa)
|
||||
{
|
||||
const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
|
||||
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
return ntohs(sin->sin_port);
|
||||
case AF_INET6:
|
||||
return ntohs(sin6->sin6_port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t svc_addr_len(const struct sockaddr *sa)
|
||||
{
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_INET6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
}
|
||||
BUG();
|
||||
}
|
||||
|
||||
static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt)
|
||||
{
|
||||
return svc_addr_port((const struct sockaddr *)&xprt->xpt_local);
|
||||
}
|
||||
|
||||
static inline unsigned short svc_xprt_remote_port(const struct svc_xprt *xprt)
|
||||
{
|
||||
return svc_addr_port((const struct sockaddr *)&xprt->xpt_remote);
|
||||
}
|
||||
|
||||
static inline char *__svc_print_addr(const struct sockaddr *addr,
|
||||
char *buf, const size_t len)
|
||||
{
|
||||
const struct sockaddr_in *sin = (const struct sockaddr_in *)addr;
|
||||
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)addr;
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET:
|
||||
snprintf(buf, len, "%pI4, port=%u", &sin->sin_addr,
|
||||
ntohs(sin->sin_port));
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
snprintf(buf, len, "%pI6, port=%u",
|
||||
&sin6->sin6_addr,
|
||||
ntohs(sin6->sin6_port));
|
||||
break;
|
||||
|
||||
default:
|
||||
snprintf(buf, len, "unknown address type: %d", addr->sa_family);
|
||||
break;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif /* SUNRPC_SVC_XPRT_H */
|
||||
@@ -0,0 +1,189 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/svcauth.h
|
||||
*
|
||||
* RPC server-side authentication stuff.
|
||||
*
|
||||
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_SVCAUTH_H_
|
||||
#define _LINUX_SUNRPC_SVCAUTH_H_
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/sunrpc/msg_prot.h>
|
||||
#include <linux/sunrpc/cache.h>
|
||||
#include <linux/sunrpc/gss_api.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/stringhash.h>
|
||||
#include <linux/cred.h>
|
||||
|
||||
struct svc_cred {
|
||||
kuid_t cr_uid;
|
||||
kgid_t cr_gid;
|
||||
struct group_info *cr_group_info;
|
||||
u32 cr_flavor; /* pseudoflavor */
|
||||
/* name of form servicetype/hostname@REALM, passed down by
|
||||
* gss-proxy: */
|
||||
char *cr_raw_principal;
|
||||
/* name of form servicetype@hostname, passed down by
|
||||
* rpc.svcgssd, or computed from the above: */
|
||||
char *cr_principal;
|
||||
char *cr_targ_princ;
|
||||
struct gss_api_mech *cr_gss_mech;
|
||||
};
|
||||
|
||||
static inline void init_svc_cred(struct svc_cred *cred)
|
||||
{
|
||||
cred->cr_group_info = NULL;
|
||||
cred->cr_raw_principal = NULL;
|
||||
cred->cr_principal = NULL;
|
||||
cred->cr_targ_princ = NULL;
|
||||
cred->cr_gss_mech = NULL;
|
||||
}
|
||||
|
||||
static inline void free_svc_cred(struct svc_cred *cred)
|
||||
{
|
||||
if (cred->cr_group_info)
|
||||
put_group_info(cred->cr_group_info);
|
||||
kfree(cred->cr_raw_principal);
|
||||
kfree(cred->cr_principal);
|
||||
kfree(cred->cr_targ_princ);
|
||||
gss_mech_put(cred->cr_gss_mech);
|
||||
init_svc_cred(cred);
|
||||
}
|
||||
|
||||
struct svc_rqst; /* forward decl */
|
||||
struct in6_addr;
|
||||
|
||||
/* Authentication is done in the context of a domain.
|
||||
*
|
||||
* Currently, the nfs server uses the auth_domain to stand
|
||||
* for the "client" listed in /etc/exports.
|
||||
*
|
||||
* More generally, a domain might represent a group of clients using
|
||||
* a common mechanism for authentication and having a common mapping
|
||||
* between local identity (uid) and network identity. All clients
|
||||
* in a domain have similar general access rights. Each domain can
|
||||
* contain multiple principals which will have different specific right
|
||||
* based on normal Discretionary Access Control.
|
||||
*
|
||||
* A domain is created by an authentication flavour module based on name
|
||||
* only. Userspace then fills in detail on demand.
|
||||
*
|
||||
* In the case of auth_unix and auth_null, the auth_domain is also
|
||||
* associated with entries in another cache representing the mapping
|
||||
* of ip addresses to the given client.
|
||||
*/
|
||||
struct auth_domain {
|
||||
struct kref ref;
|
||||
struct hlist_node hash;
|
||||
char *name;
|
||||
struct auth_ops *flavour;
|
||||
struct rcu_head rcu_head;
|
||||
};
|
||||
|
||||
enum svc_auth_status {
|
||||
SVC_GARBAGE = 1,
|
||||
SVC_VALID,
|
||||
SVC_NEGATIVE,
|
||||
SVC_OK,
|
||||
SVC_DROP,
|
||||
SVC_CLOSE,
|
||||
SVC_DENIED,
|
||||
SVC_PENDING,
|
||||
SVC_COMPLETE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Each authentication flavour registers an auth_ops
|
||||
* structure.
|
||||
* name is simply the name.
|
||||
* flavour gives the auth flavour. It determines where the flavour is registered
|
||||
* accept() is given a request and should verify it.
|
||||
* It should inspect the authenticator and verifier, and possibly the data.
|
||||
* If there is a problem with the authentication *authp should be set.
|
||||
* The return value of accept() can indicate:
|
||||
* OK - authorised. client and credential are set in rqstp.
|
||||
* reqbuf points to arguments
|
||||
* resbuf points to good place for results. verfier
|
||||
* is (probably) already in place. Certainly space is
|
||||
* reserved for it.
|
||||
* DROP - simply drop the request. It may have been deferred
|
||||
* CLOSE - like SVC_DROP, but request is definitely lost.
|
||||
* If there is a tcp connection, it should be closed.
|
||||
* GARBAGE - rpc garbage_args error
|
||||
* SYSERR - rpc system_err error
|
||||
* DENIED - authp holds reason for denial.
|
||||
* COMPLETE - the reply is encoded already and ready to be sent; no
|
||||
* further processing is necessary. (This is used for processing
|
||||
* null procedure calls which are used to set up encryption
|
||||
* contexts.)
|
||||
*
|
||||
* accept is passed the proc number so that it can accept NULL rpc requests
|
||||
* even if it cannot authenticate the client (as is sometimes appropriate).
|
||||
*
|
||||
* release() is given a request after the procedure has been run.
|
||||
* It should sign/encrypt the results if needed
|
||||
*
|
||||
* domain_release()
|
||||
* This call releases a domain.
|
||||
*
|
||||
* set_client()
|
||||
* Given a pending request (struct svc_rqst), finds and assigns
|
||||
* an appropriate 'auth_domain' as the client.
|
||||
*
|
||||
* pseudoflavor()
|
||||
* Returns RPC_AUTH pseudoflavor in use by @rqstp.
|
||||
*/
|
||||
struct auth_ops {
|
||||
char * name;
|
||||
struct module *owner;
|
||||
int flavour;
|
||||
|
||||
enum svc_auth_status (*accept)(struct svc_rqst *rqstp);
|
||||
int (*release)(struct svc_rqst *rqstp);
|
||||
void (*domain_release)(struct auth_domain *dom);
|
||||
enum svc_auth_status (*set_client)(struct svc_rqst *rqstp);
|
||||
rpc_authflavor_t (*pseudoflavor)(struct svc_rqst *rqstp);
|
||||
};
|
||||
|
||||
struct svc_xprt;
|
||||
|
||||
extern rpc_authflavor_t svc_auth_flavor(struct svc_rqst *rqstp);
|
||||
extern int svc_authorise(struct svc_rqst *rqstp);
|
||||
extern enum svc_auth_status svc_set_client(struct svc_rqst *rqstp);
|
||||
extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
|
||||
extern void svc_auth_unregister(rpc_authflavor_t flavor);
|
||||
|
||||
extern void svcauth_map_clnt_to_svc_cred_local(struct rpc_clnt *clnt,
|
||||
const struct cred *,
|
||||
struct svc_cred *);
|
||||
|
||||
extern struct auth_domain *unix_domain_find(char *name);
|
||||
extern void auth_domain_put(struct auth_domain *item);
|
||||
extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
|
||||
extern struct auth_domain *auth_domain_find(char *name);
|
||||
extern void svcauth_unix_purge(struct net *net);
|
||||
extern void svcauth_unix_info_release(struct svc_xprt *xpt);
|
||||
extern enum svc_auth_status svcauth_unix_set_client(struct svc_rqst *rqstp);
|
||||
|
||||
extern int unix_gid_cache_create(struct net *net);
|
||||
extern void unix_gid_cache_destroy(struct net *net);
|
||||
|
||||
/*
|
||||
* The <stringhash.h> functions are good enough that we don't need to
|
||||
* use hash_32() on them; just extracting the high bits is enough.
|
||||
*/
|
||||
static inline unsigned long hash_str(char const *name, int bits)
|
||||
{
|
||||
return hashlen_hash(hashlen_string(NULL, name)) >> (32 - bits);
|
||||
}
|
||||
|
||||
static inline unsigned long hash_mem(char const *buf, int length, int bits)
|
||||
{
|
||||
return full_name_hash(NULL, buf, length) >> (32 - bits);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_SUNRPC_SVCAUTH_H_ */
|
||||
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/svcauth_gss.h
|
||||
*
|
||||
* Bruce Fields <bfields@umich.edu>
|
||||
* Copyright (c) 2002 The Regents of the University of Michigan
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_SVCAUTH_GSS_H
|
||||
#define _LINUX_SUNRPC_SVCAUTH_GSS_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sunrpc/types.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/svcauth.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/sunrpc/auth_gss.h>
|
||||
|
||||
int gss_svc_init(void);
|
||||
void gss_svc_shutdown(void);
|
||||
int gss_svc_init_net(struct net *net);
|
||||
void gss_svc_shutdown_net(struct net *net);
|
||||
struct auth_domain *svcauth_gss_register_pseudoflavor(u32 pseudoflavor,
|
||||
char *name);
|
||||
u32 svcauth_gss_flavor(struct auth_domain *dom);
|
||||
|
||||
#endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */
|
||||
@@ -0,0 +1,79 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/svcsock.h
|
||||
*
|
||||
* RPC server socket I/O.
|
||||
*
|
||||
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef SUNRPC_SVCSOCK_H
|
||||
#define SUNRPC_SVCSOCK_H
|
||||
|
||||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/sunrpc/svc_xprt.h>
|
||||
|
||||
/*
|
||||
* RPC server socket.
|
||||
*/
|
||||
struct svc_sock {
|
||||
struct svc_xprt sk_xprt;
|
||||
struct socket * sk_sock; /* berkeley socket layer */
|
||||
struct sock * sk_sk; /* INET layer */
|
||||
|
||||
/* We keep the old state_change and data_ready CB's here */
|
||||
void (*sk_ostate)(struct sock *);
|
||||
void (*sk_odata)(struct sock *);
|
||||
void (*sk_owspace)(struct sock *);
|
||||
|
||||
/* For sends (protected by xpt_mutex) */
|
||||
struct bio_vec *sk_bvec;
|
||||
|
||||
/* private TCP part */
|
||||
/* On-the-wire fragment header: */
|
||||
__be32 sk_marker;
|
||||
/* As we receive a record, this includes the length received so
|
||||
* far (including the fragment header): */
|
||||
u32 sk_tcplen;
|
||||
/* Total length of the data (not including fragment headers)
|
||||
* received so far in the fragments making up this rpc: */
|
||||
u32 sk_datalen;
|
||||
|
||||
struct page_frag_cache sk_frag_cache;
|
||||
|
||||
struct completion sk_handshake_done;
|
||||
|
||||
/* received data */
|
||||
unsigned long sk_maxpages;
|
||||
struct page * sk_pages[] __counted_by(sk_maxpages);
|
||||
};
|
||||
|
||||
static inline u32 svc_sock_reclen(struct svc_sock *svsk)
|
||||
{
|
||||
return be32_to_cpu(svsk->sk_marker) & RPC_FRAGMENT_SIZE_MASK;
|
||||
}
|
||||
|
||||
static inline u32 svc_sock_final_rec(struct svc_sock *svsk)
|
||||
{
|
||||
return be32_to_cpu(svsk->sk_marker) & RPC_LAST_STREAM_FRAGMENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function prototypes.
|
||||
*/
|
||||
int svc_recv(struct svc_rqst *rqstp, long timeo);
|
||||
void svc_send(struct svc_rqst *rqstp);
|
||||
int svc_addsock(struct svc_serv *serv, struct net *net,
|
||||
const int fd, char *name_return, const size_t len,
|
||||
const struct cred *cred);
|
||||
void svc_init_xprt_sock(void);
|
||||
void svc_cleanup_xprt_sock(void);
|
||||
|
||||
/*
|
||||
* svc_makesock socket characteristics
|
||||
*/
|
||||
#define SVC_SOCK_DEFAULTS (0U)
|
||||
#define SVC_SOCK_ANONYMOUS (1U << 0) /* don't register with pmap */
|
||||
#define SVC_SOCK_TEMPORARY (1U << 1) /* flag socket as temporary */
|
||||
|
||||
#endif /* SUNRPC_SVCSOCK_H */
|
||||
@@ -0,0 +1,50 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/timer.h
|
||||
*
|
||||
* Declarations for the RPC transport timer.
|
||||
*
|
||||
* Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_TIMER_H
|
||||
#define _LINUX_SUNRPC_TIMER_H
|
||||
|
||||
#include <linux/atomic.h>
|
||||
|
||||
struct rpc_rtt {
|
||||
unsigned long timeo; /* default timeout value */
|
||||
unsigned long srtt[5]; /* smoothed round trip time << 3 */
|
||||
unsigned long sdrtt[5]; /* smoothed medium deviation of RTT */
|
||||
int ntimeouts[5]; /* Number of timeouts for the last request */
|
||||
};
|
||||
|
||||
|
||||
extern void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo);
|
||||
extern void rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m);
|
||||
extern unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned timer);
|
||||
|
||||
static inline void rpc_set_timeo(struct rpc_rtt *rt, int timer, int ntimeo)
|
||||
{
|
||||
int *t;
|
||||
if (!timer)
|
||||
return;
|
||||
t = &rt->ntimeouts[timer-1];
|
||||
if (ntimeo < *t) {
|
||||
if (*t > 0)
|
||||
(*t)--;
|
||||
} else {
|
||||
if (ntimeo > 8)
|
||||
ntimeo = 8;
|
||||
*t = ntimeo;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int rpc_ntimeo(struct rpc_rtt *rt, int timer)
|
||||
{
|
||||
if (!timer)
|
||||
return 0;
|
||||
return rt->ntimeouts[timer-1];
|
||||
}
|
||||
|
||||
#endif /* _LINUX_SUNRPC_TIMER_H */
|
||||
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/types.h
|
||||
*
|
||||
* Generic types and misc stuff for RPC.
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_TYPES_H_
|
||||
#define _LINUX_SUNRPC_TYPES_H_
|
||||
|
||||
#include <linux/timer.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sunrpc/debug.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
/*
|
||||
* Shorthands
|
||||
*/
|
||||
#define signalled() (signal_pending(current))
|
||||
|
||||
#endif /* _LINUX_SUNRPC_TYPES_H_ */
|
||||
@@ -0,0 +1,814 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* XDR standard data types and function declarations
|
||||
*
|
||||
* Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
|
||||
*
|
||||
* Based on:
|
||||
* RFC 4506 "XDR: External Data Representation Standard", May 2006
|
||||
*/
|
||||
|
||||
#ifndef _SUNRPC_XDR_H_
|
||||
#define _SUNRPC_XDR_H_
|
||||
|
||||
#include <linux/uio.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
struct bio_vec;
|
||||
struct rpc_rqst;
|
||||
|
||||
/*
|
||||
* Size of an XDR encoding unit in bytes, i.e. 32 bits,
|
||||
* as defined in Section 3 of RFC 4506. All encoded
|
||||
* XDR data items are aligned on a boundary of 32 bits.
|
||||
*/
|
||||
#define XDR_UNIT sizeof(__be32)
|
||||
|
||||
/*
|
||||
* Buffer adjustment
|
||||
*/
|
||||
#define XDR_QUADLEN(l) (((l) + 3) >> 2)
|
||||
|
||||
/*
|
||||
* Generic opaque `network object.'
|
||||
*/
|
||||
#define XDR_MAX_NETOBJ 1024
|
||||
struct xdr_netobj {
|
||||
unsigned int len;
|
||||
u8 * data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Basic structure for transmission/reception of a client XDR message.
|
||||
* Features a header (for a linear buffer containing RPC headers
|
||||
* and the data payload for short messages), and then an array of
|
||||
* pages.
|
||||
* The tail iovec allows you to append data after the page array. Its
|
||||
* main interest is for appending padding to the pages in order to
|
||||
* satisfy the int_32-alignment requirements in RFC1832.
|
||||
*
|
||||
* For the future, we might want to string several of these together
|
||||
* in a list if anybody wants to make use of NFSv4 COMPOUND
|
||||
* operations and/or has a need for scatter/gather involving pages.
|
||||
*/
|
||||
struct xdr_buf {
|
||||
struct kvec head[1], /* RPC header + non-page data */
|
||||
tail[1]; /* Appended after page data */
|
||||
|
||||
struct bio_vec *bvec;
|
||||
struct page ** pages; /* Array of pages */
|
||||
unsigned int page_base, /* Start of page data */
|
||||
page_len, /* Length of page data */
|
||||
flags; /* Flags for data disposition */
|
||||
#define XDRBUF_READ 0x01 /* target of file read */
|
||||
#define XDRBUF_WRITE 0x02 /* source of file write */
|
||||
#define XDRBUF_SPARSE_PAGES 0x04 /* Page array is sparse */
|
||||
|
||||
unsigned int buflen, /* Total length of storage buffer */
|
||||
len; /* Length of XDR encoded message */
|
||||
};
|
||||
|
||||
static inline void
|
||||
xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
|
||||
{
|
||||
buf->head[0].iov_base = start;
|
||||
buf->head[0].iov_len = len;
|
||||
buf->tail[0].iov_len = 0;
|
||||
buf->pages = NULL;
|
||||
buf->page_len = 0;
|
||||
buf->flags = 0;
|
||||
buf->len = 0;
|
||||
buf->buflen = len;
|
||||
}
|
||||
|
||||
/*
|
||||
* pre-xdr'ed macros.
|
||||
*/
|
||||
|
||||
#define xdr_zero cpu_to_be32(0)
|
||||
#define xdr_one cpu_to_be32(1)
|
||||
#define xdr_two cpu_to_be32(2)
|
||||
|
||||
#define rpc_auth_null cpu_to_be32(RPC_AUTH_NULL)
|
||||
#define rpc_auth_unix cpu_to_be32(RPC_AUTH_UNIX)
|
||||
#define rpc_auth_short cpu_to_be32(RPC_AUTH_SHORT)
|
||||
#define rpc_auth_gss cpu_to_be32(RPC_AUTH_GSS)
|
||||
#define rpc_auth_tls cpu_to_be32(RPC_AUTH_TLS)
|
||||
|
||||
#define rpc_call cpu_to_be32(RPC_CALL)
|
||||
#define rpc_reply cpu_to_be32(RPC_REPLY)
|
||||
|
||||
#define rpc_msg_accepted cpu_to_be32(RPC_MSG_ACCEPTED)
|
||||
|
||||
#define rpc_success cpu_to_be32(RPC_SUCCESS)
|
||||
#define rpc_prog_unavail cpu_to_be32(RPC_PROG_UNAVAIL)
|
||||
#define rpc_prog_mismatch cpu_to_be32(RPC_PROG_MISMATCH)
|
||||
#define rpc_proc_unavail cpu_to_be32(RPC_PROC_UNAVAIL)
|
||||
#define rpc_garbage_args cpu_to_be32(RPC_GARBAGE_ARGS)
|
||||
#define rpc_system_err cpu_to_be32(RPC_SYSTEM_ERR)
|
||||
#define rpc_drop_reply cpu_to_be32(RPC_DROP_REPLY)
|
||||
|
||||
#define rpc_mismatch cpu_to_be32(RPC_MISMATCH)
|
||||
#define rpc_auth_error cpu_to_be32(RPC_AUTH_ERROR)
|
||||
|
||||
#define rpc_auth_ok cpu_to_be32(RPC_AUTH_OK)
|
||||
#define rpc_autherr_badcred cpu_to_be32(RPC_AUTH_BADCRED)
|
||||
#define rpc_autherr_rejectedcred cpu_to_be32(RPC_AUTH_REJECTEDCRED)
|
||||
#define rpc_autherr_badverf cpu_to_be32(RPC_AUTH_BADVERF)
|
||||
#define rpc_autherr_rejectedverf cpu_to_be32(RPC_AUTH_REJECTEDVERF)
|
||||
#define rpc_autherr_tooweak cpu_to_be32(RPC_AUTH_TOOWEAK)
|
||||
#define rpc_autherr_invalidresp cpu_to_be32(RPC_AUTH_INVALIDRESP)
|
||||
#define rpc_autherr_failed cpu_to_be32(RPC_AUTH_FAILED)
|
||||
#define rpcsec_gsserr_credproblem cpu_to_be32(RPCSEC_GSS_CREDPROBLEM)
|
||||
#define rpcsec_gsserr_ctxproblem cpu_to_be32(RPCSEC_GSS_CTXPROBLEM)
|
||||
|
||||
/*
|
||||
* Miscellaneous XDR helper functions
|
||||
*/
|
||||
__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len);
|
||||
__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len);
|
||||
__be32 *xdr_encode_string(__be32 *p, const char *s);
|
||||
__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
|
||||
|
||||
void xdr_inline_pages(struct xdr_buf *, unsigned int,
|
||||
struct page **, unsigned int, unsigned int);
|
||||
void xdr_terminate_string(const struct xdr_buf *, const u32);
|
||||
size_t xdr_buf_pagecount(const struct xdr_buf *buf);
|
||||
int xdr_alloc_bvec(struct xdr_buf *buf, gfp_t gfp);
|
||||
void xdr_free_bvec(struct xdr_buf *buf);
|
||||
unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
|
||||
const struct xdr_buf *xdr);
|
||||
|
||||
static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len)
|
||||
{
|
||||
return xdr_encode_opaque(p, s, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode 64bit quantities (NFSv3 support)
|
||||
*/
|
||||
static inline __be32 *
|
||||
xdr_encode_hyper(__be32 *p, __u64 val)
|
||||
{
|
||||
put_unaligned_be64(val, p);
|
||||
return p + 2;
|
||||
}
|
||||
|
||||
static inline __be32 *
|
||||
xdr_decode_hyper(__be32 *p, __u64 *valp)
|
||||
{
|
||||
*valp = get_unaligned_be64(p);
|
||||
return p + 2;
|
||||
}
|
||||
|
||||
static inline __be32 *
|
||||
xdr_decode_opaque_fixed(__be32 *p, void *ptr, unsigned int len)
|
||||
{
|
||||
memcpy(ptr, p, len);
|
||||
return p + XDR_QUADLEN(len);
|
||||
}
|
||||
|
||||
static inline void xdr_netobj_dup(struct xdr_netobj *dst,
|
||||
struct xdr_netobj *src, gfp_t gfp_mask)
|
||||
{
|
||||
dst->data = kmemdup(src->data, src->len, gfp_mask);
|
||||
dst->len = src->len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust kvec to reflect end of xdr'ed data (RPC client XDR)
|
||||
*/
|
||||
static inline int
|
||||
xdr_adjust_iovec(struct kvec *iov, __be32 *p)
|
||||
{
|
||||
return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base);
|
||||
}
|
||||
|
||||
/*
|
||||
* XDR buffer helper functions
|
||||
*/
|
||||
extern void xdr_buf_from_iov(const struct kvec *, struct xdr_buf *);
|
||||
extern int xdr_buf_subsegment(const struct xdr_buf *, struct xdr_buf *, unsigned int, unsigned int);
|
||||
extern void xdr_buf_trim(struct xdr_buf *, unsigned int);
|
||||
extern int read_bytes_from_xdr_buf(const struct xdr_buf *, unsigned int, void *, unsigned int);
|
||||
extern int write_bytes_to_xdr_buf(const struct xdr_buf *, unsigned int, void *, unsigned int);
|
||||
|
||||
extern int xdr_encode_word(const struct xdr_buf *, unsigned int, u32);
|
||||
extern int xdr_decode_word(const struct xdr_buf *, unsigned int, u32 *);
|
||||
|
||||
struct xdr_array2_desc;
|
||||
typedef int (*xdr_xcode_elem_t)(struct xdr_array2_desc *desc, void *elem);
|
||||
struct xdr_array2_desc {
|
||||
unsigned int elem_size;
|
||||
unsigned int array_len;
|
||||
unsigned int array_maxlen;
|
||||
xdr_xcode_elem_t xcode;
|
||||
};
|
||||
|
||||
extern int xdr_decode_array2(const struct xdr_buf *buf, unsigned int base,
|
||||
struct xdr_array2_desc *desc);
|
||||
extern int xdr_encode_array2(const struct xdr_buf *buf, unsigned int base,
|
||||
struct xdr_array2_desc *desc);
|
||||
extern void _copy_from_pages(char *p, struct page **pages, size_t pgbase,
|
||||
size_t len);
|
||||
|
||||
/*
|
||||
* Provide some simple tools for XDR buffer overflow-checking etc.
|
||||
*/
|
||||
struct xdr_stream {
|
||||
__be32 *p; /* start of available buffer */
|
||||
struct xdr_buf *buf; /* XDR buffer to read/write */
|
||||
|
||||
__be32 *end; /* end of available buffer space */
|
||||
struct kvec *iov; /* pointer to the current kvec */
|
||||
struct kvec scratch; /* Scratch buffer */
|
||||
struct page **page_ptr; /* pointer to the current page */
|
||||
void *page_kaddr; /* kmapped address of the current page */
|
||||
unsigned int nwords; /* Remaining decode buffer length */
|
||||
|
||||
struct rpc_rqst *rqst; /* For debugging */
|
||||
};
|
||||
|
||||
/*
|
||||
* These are the xdr_stream style generic XDR encode and decode functions.
|
||||
*/
|
||||
typedef void (*kxdreproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
|
||||
const void *obj);
|
||||
typedef int (*kxdrdproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
|
||||
void *obj);
|
||||
|
||||
extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf,
|
||||
__be32 *p, struct rpc_rqst *rqst);
|
||||
void xdr_init_encode_pages(struct xdr_stream *xdr, struct xdr_buf *buf);
|
||||
extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
|
||||
extern int xdr_reserve_space_vec(struct xdr_stream *xdr, size_t nbytes);
|
||||
extern void __xdr_commit_encode(struct xdr_stream *xdr);
|
||||
extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len);
|
||||
extern void xdr_truncate_decode(struct xdr_stream *xdr, size_t len);
|
||||
extern int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen);
|
||||
extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
|
||||
unsigned int base, unsigned int len);
|
||||
extern unsigned int xdr_stream_pos(const struct xdr_stream *xdr);
|
||||
extern unsigned int xdr_page_pos(const struct xdr_stream *xdr);
|
||||
extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf,
|
||||
__be32 *p, struct rpc_rqst *rqst);
|
||||
extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
|
||||
struct page **pages, unsigned int len);
|
||||
extern void xdr_finish_decode(struct xdr_stream *xdr);
|
||||
extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
|
||||
extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
|
||||
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
|
||||
extern int xdr_process_buf(const struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data);
|
||||
extern void xdr_set_pagelen(struct xdr_stream *, unsigned int len);
|
||||
extern bool xdr_stream_subsegment(struct xdr_stream *xdr, struct xdr_buf *subbuf,
|
||||
unsigned int len);
|
||||
extern unsigned int xdr_stream_move_subsegment(struct xdr_stream *xdr, unsigned int offset,
|
||||
unsigned int target, unsigned int length);
|
||||
extern unsigned int xdr_stream_zero(struct xdr_stream *xdr, unsigned int offset,
|
||||
unsigned int length);
|
||||
|
||||
/**
|
||||
* xdr_set_scratch_buffer - Attach a scratch buffer for decoding data.
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
* @buf: pointer to an empty buffer
|
||||
* @buflen: size of 'buf'
|
||||
*
|
||||
* The scratch buffer is used when decoding from an array of pages.
|
||||
* If an xdr_inline_decode() call spans across page boundaries, then
|
||||
* we copy the data into the scratch buffer in order to allow linear
|
||||
* access.
|
||||
*/
|
||||
static inline void
|
||||
xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen)
|
||||
{
|
||||
xdr->scratch.iov_base = buf;
|
||||
xdr->scratch.iov_len = buflen;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_set_scratch_folio - Attach a scratch buffer for decoding data
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
* @folio: an anonymous folio
|
||||
*
|
||||
* See xdr_set_scratch_buffer().
|
||||
*/
|
||||
static inline void
|
||||
xdr_set_scratch_folio(struct xdr_stream *xdr, struct folio *folio)
|
||||
{
|
||||
xdr_set_scratch_buffer(xdr, folio_address(folio), folio_size(folio));
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_reset_scratch_buffer - Clear scratch buffer information
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
*
|
||||
* See xdr_set_scratch_buffer().
|
||||
*/
|
||||
static inline void
|
||||
xdr_reset_scratch_buffer(struct xdr_stream *xdr)
|
||||
{
|
||||
xdr_set_scratch_buffer(xdr, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_commit_encode - Ensure all data is written to xdr->buf
|
||||
* @xdr: pointer to xdr_stream
|
||||
*
|
||||
* Handle encoding across page boundaries by giving the caller a
|
||||
* temporary location to write to, then later copying the data into
|
||||
* place. __xdr_commit_encode() does that copying.
|
||||
*/
|
||||
static inline void xdr_commit_encode(struct xdr_stream *xdr)
|
||||
{
|
||||
if (unlikely(xdr->scratch.iov_len))
|
||||
__xdr_commit_encode(xdr);
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_remaining - Return the number of bytes remaining in the stream
|
||||
* @xdr: pointer to struct xdr_stream
|
||||
*
|
||||
* Returns:
|
||||
* Number of bytes remaining in @xdr before xdr->end
|
||||
*/
|
||||
static inline size_t
|
||||
xdr_stream_remaining(const struct xdr_stream *xdr)
|
||||
{
|
||||
return xdr->nwords << 2;
|
||||
}
|
||||
|
||||
ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str,
|
||||
size_t maxlen, gfp_t gfp_flags);
|
||||
ssize_t xdr_stream_decode_opaque_auth(struct xdr_stream *xdr, u32 *flavor,
|
||||
void **body, unsigned int *body_len);
|
||||
ssize_t xdr_stream_encode_opaque_auth(struct xdr_stream *xdr, u32 flavor,
|
||||
void *body, unsigned int body_len);
|
||||
|
||||
/**
|
||||
* xdr_align_size - Calculate padded size of an object
|
||||
* @n: Size of an object being XDR encoded (in bytes)
|
||||
*
|
||||
* Returns:
|
||||
* Size (in bytes) of the object including xdr padding
|
||||
*/
|
||||
static inline size_t
|
||||
xdr_align_size(size_t n)
|
||||
{
|
||||
const size_t mask = XDR_UNIT - 1;
|
||||
|
||||
return (n + mask) & ~mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_pad_size - Calculate size of an object's pad
|
||||
* @n: Size of an object being XDR encoded (in bytes)
|
||||
*
|
||||
* This implementation avoids the need for conditional
|
||||
* branches or modulo division.
|
||||
*
|
||||
* Returns:
|
||||
* Size (in bytes) of the needed XDR pad
|
||||
*/
|
||||
static inline size_t xdr_pad_size(size_t n)
|
||||
{
|
||||
return xdr_align_size(n) - n;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_item_present - Encode a "present" list item
|
||||
* @xdr: pointer to xdr_stream
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t xdr_stream_encode_item_present(struct xdr_stream *xdr)
|
||||
{
|
||||
const size_t len = XDR_UNIT;
|
||||
__be32 *p = xdr_reserve_space(xdr, len);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EMSGSIZE;
|
||||
*p = xdr_one;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_item_absent - Encode a "not present" list item
|
||||
* @xdr: pointer to xdr_stream
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr)
|
||||
{
|
||||
const size_t len = XDR_UNIT;
|
||||
__be32 *p = xdr_reserve_space(xdr, len);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EMSGSIZE;
|
||||
*p = xdr_zero;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_encode_bool - Encode a boolean item
|
||||
* @p: address in a buffer into which to encode
|
||||
* @n: boolean value to encode
|
||||
*
|
||||
* Returns:
|
||||
* Address of item following the encoded boolean
|
||||
*/
|
||||
static inline __be32 *xdr_encode_bool(__be32 *p, u32 n)
|
||||
{
|
||||
*p++ = n ? xdr_one : xdr_zero;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_bool - Encode a boolean item
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @n: boolean value to encode
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline int xdr_stream_encode_bool(struct xdr_stream *xdr, __u32 n)
|
||||
{
|
||||
const size_t len = XDR_UNIT;
|
||||
__be32 *p = xdr_reserve_space(xdr, len);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EMSGSIZE;
|
||||
xdr_encode_bool(p, n);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_u32 - Encode a 32-bit integer
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @n: integer to encode
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_encode_u32(struct xdr_stream *xdr, __u32 n)
|
||||
{
|
||||
const size_t len = sizeof(n);
|
||||
__be32 *p = xdr_reserve_space(xdr, len);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EMSGSIZE;
|
||||
*p = cpu_to_be32(n);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_be32 - Encode a big-endian 32-bit integer
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @n: integer to encode
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_encode_be32(struct xdr_stream *xdr, __be32 n)
|
||||
{
|
||||
const size_t len = sizeof(n);
|
||||
__be32 *p = xdr_reserve_space(xdr, len);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EMSGSIZE;
|
||||
*p = n;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_u64 - Encode a 64-bit integer
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @n: 64-bit integer to encode
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_encode_u64(struct xdr_stream *xdr, __u64 n)
|
||||
{
|
||||
const size_t len = sizeof(n);
|
||||
__be32 *p = xdr_reserve_space(xdr, len);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EMSGSIZE;
|
||||
xdr_encode_hyper(p, n);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_opaque_inline - Encode opaque xdr data
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @ptr: pointer to void pointer
|
||||
* @len: size of object
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_encode_opaque_inline(struct xdr_stream *xdr, void **ptr, size_t len)
|
||||
{
|
||||
size_t count = sizeof(__u32) + xdr_align_size(len);
|
||||
__be32 *p = xdr_reserve_space(xdr, count);
|
||||
|
||||
if (unlikely(!p)) {
|
||||
*ptr = NULL;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
xdr_encode_opaque(p, NULL, len);
|
||||
*ptr = ++p;
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_opaque_fixed - Encode fixed length opaque xdr data
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @ptr: pointer to opaque data object
|
||||
* @len: size of object pointed to by @ptr
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_encode_opaque_fixed(struct xdr_stream *xdr, const void *ptr, size_t len)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, len);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EMSGSIZE;
|
||||
xdr_encode_opaque_fixed(p, ptr, len);
|
||||
return xdr_align_size(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_opaque - Encode variable length opaque xdr data
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @ptr: pointer to opaque data object
|
||||
* @len: size of object pointed to by @ptr
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_encode_opaque(struct xdr_stream *xdr, const void *ptr, size_t len)
|
||||
{
|
||||
size_t count = sizeof(__u32) + xdr_align_size(len);
|
||||
__be32 *p = xdr_reserve_space(xdr, count);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EMSGSIZE;
|
||||
xdr_encode_opaque(p, ptr, len);
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_encode_uint32_array - Encode variable length array of integers
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @array: array of integers
|
||||
* @array_size: number of elements in @array
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns length in bytes of XDR buffer consumed
|
||||
* %-EMSGSIZE on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_encode_uint32_array(struct xdr_stream *xdr,
|
||||
const __u32 *array, size_t array_size)
|
||||
{
|
||||
ssize_t ret = (array_size+1) * sizeof(__u32);
|
||||
__be32 *p = xdr_reserve_space(xdr, ret);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EMSGSIZE;
|
||||
*p++ = cpu_to_be32(array_size);
|
||||
for (; array_size > 0; p++, array++, array_size--)
|
||||
*p = cpu_to_be32p(array);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_item_is_absent - symbolically handle XDR discriminators
|
||||
* @p: pointer to undecoded discriminator
|
||||
*
|
||||
* Returns:
|
||||
* %true if the following XDR item is absent
|
||||
* %false if the following XDR item is present
|
||||
*/
|
||||
static inline bool xdr_item_is_absent(const __be32 *p)
|
||||
{
|
||||
return *p == xdr_zero;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_item_is_present - symbolically handle XDR discriminators
|
||||
* @p: pointer to undecoded discriminator
|
||||
*
|
||||
* Returns:
|
||||
* %true if the following XDR item is present
|
||||
* %false if the following XDR item is absent
|
||||
*/
|
||||
static inline bool xdr_item_is_present(const __be32 *p)
|
||||
{
|
||||
return *p != xdr_zero;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_decode_bool - Decode a boolean
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @ptr: pointer to a u32 in which to store the result
|
||||
*
|
||||
* Returns:
|
||||
* %0 on success
|
||||
* %-EBADMSG on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_decode_bool(struct xdr_stream *xdr, __u32 *ptr)
|
||||
{
|
||||
const size_t count = sizeof(*ptr);
|
||||
__be32 *p = xdr_inline_decode(xdr, count);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EBADMSG;
|
||||
*ptr = (*p != xdr_zero);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_decode_u32 - Decode a 32-bit integer
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @ptr: location to store integer
|
||||
*
|
||||
* Returns:
|
||||
* %0 on success
|
||||
* %-EBADMSG on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_decode_u32(struct xdr_stream *xdr, __u32 *ptr)
|
||||
{
|
||||
const size_t count = sizeof(*ptr);
|
||||
__be32 *p = xdr_inline_decode(xdr, count);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EBADMSG;
|
||||
*ptr = be32_to_cpup(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_decode_be32 - Decode a big-endian 32-bit integer
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @ptr: location to store integer
|
||||
*
|
||||
* Returns:
|
||||
* %0 on success
|
||||
* %-EBADMSG on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_decode_be32(struct xdr_stream *xdr, __be32 *ptr)
|
||||
{
|
||||
const size_t count = sizeof(*ptr);
|
||||
__be32 *p = xdr_inline_decode(xdr, count);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EBADMSG;
|
||||
*ptr = *p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_decode_u64 - Decode a 64-bit integer
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @ptr: location to store 64-bit integer
|
||||
*
|
||||
* Returns:
|
||||
* %0 on success
|
||||
* %-EBADMSG on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_decode_u64(struct xdr_stream *xdr, __u64 *ptr)
|
||||
{
|
||||
const size_t count = sizeof(*ptr);
|
||||
__be32 *p = xdr_inline_decode(xdr, count);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EBADMSG;
|
||||
xdr_decode_hyper(p, ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_decode_opaque_fixed - Decode fixed length opaque xdr data
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @ptr: location to store data
|
||||
* @len: size of buffer pointed to by @ptr
|
||||
*
|
||||
* Returns:
|
||||
* %0 on success
|
||||
* %-EBADMSG on XDR buffer overflow
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_decode_opaque_fixed(struct xdr_stream *xdr, void *ptr, size_t len)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, len);
|
||||
|
||||
if (unlikely(!p))
|
||||
return -EBADMSG;
|
||||
xdr_decode_opaque_fixed(p, ptr, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_decode_opaque_inline - Decode variable length opaque xdr data
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @ptr: location to store pointer to opaque data
|
||||
* @maxlen: maximum acceptable object size
|
||||
*
|
||||
* Note: the pointer stored in @ptr cannot be assumed valid after the XDR
|
||||
* buffer has been destroyed, or even after calling xdr_inline_decode()
|
||||
* on @xdr. It is therefore expected that the object it points to should
|
||||
* be processed immediately.
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns size of object stored in *@ptr
|
||||
* %-EBADMSG on XDR buffer overflow
|
||||
* %-EMSGSIZE if the size of the object would exceed @maxlen
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_decode_opaque_inline(struct xdr_stream *xdr, void **ptr, size_t maxlen)
|
||||
{
|
||||
__be32 *p;
|
||||
__u32 len;
|
||||
|
||||
*ptr = NULL;
|
||||
if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0))
|
||||
return -EBADMSG;
|
||||
if (len != 0) {
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (unlikely(!p))
|
||||
return -EBADMSG;
|
||||
if (unlikely(len > maxlen))
|
||||
return -EMSGSIZE;
|
||||
*ptr = p;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_stream_decode_uint32_array - Decode variable length array of integers
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @array: location to store the integer array or NULL
|
||||
* @array_size: number of elements to store
|
||||
*
|
||||
* Returns:
|
||||
* On success, returns number of elements stored in @array
|
||||
* %-EBADMSG on XDR buffer overflow
|
||||
* %-EMSGSIZE if the size of the array exceeds @array_size
|
||||
*/
|
||||
static inline ssize_t
|
||||
xdr_stream_decode_uint32_array(struct xdr_stream *xdr,
|
||||
__u32 *array, size_t array_size)
|
||||
{
|
||||
__be32 *p;
|
||||
__u32 len;
|
||||
ssize_t retval;
|
||||
|
||||
if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0))
|
||||
return -EBADMSG;
|
||||
if (U32_MAX >= SIZE_MAX / sizeof(*p) && len > SIZE_MAX / sizeof(*p))
|
||||
return -EBADMSG;
|
||||
p = xdr_inline_decode(xdr, len * sizeof(*p));
|
||||
if (unlikely(!p))
|
||||
return -EBADMSG;
|
||||
if (array == NULL)
|
||||
return len;
|
||||
if (len <= array_size) {
|
||||
if (len < array_size)
|
||||
memset(array+len, 0, (array_size-len)*sizeof(*array));
|
||||
array_size = len;
|
||||
retval = len;
|
||||
} else
|
||||
retval = -EMSGSIZE;
|
||||
for (; array_size > 0; p++, array++, array_size--)
|
||||
*array = be32_to_cpup(p);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif /* _SUNRPC_XDR_H_ */
|
||||
@@ -0,0 +1,299 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2024 Oracle and/or its affiliates.
|
||||
*
|
||||
* This header defines XDR data type primitives specified in
|
||||
* Section 4 of RFC 4506, used by RPC programs implemented
|
||||
* in the Linux kernel.
|
||||
*/
|
||||
|
||||
#ifndef _SUNRPC_XDRGEN__BUILTINS_H_
|
||||
#define _SUNRPC_XDRGEN__BUILTINS_H_
|
||||
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_void(struct xdr_stream *xdr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_void(struct xdr_stream *xdr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_bool(struct xdr_stream *xdr, bool *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = (*p != xdr_zero);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_bool(struct xdr_stream *xdr, bool val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = val ? xdr_one : xdr_zero;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* De facto (non-standard but commonly implemented) signed short type:
|
||||
* - Wire sends sign-extended 32-bit value (e.g., 0xFFFFFFFF)
|
||||
* - be32_to_cpup() returns u32 (0xFFFFFFFF)
|
||||
* - Explicit (s16) cast truncates to 16 bits (0xFFFF = -1)
|
||||
*/
|
||||
static inline bool
|
||||
xdrgen_decode_short(struct xdr_stream *xdr, s16 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = (s16)be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* De facto (non-standard but commonly implemented) signed short type:
|
||||
* - C integer promotion sign-extends s16 val to int before passing to
|
||||
* cpu_to_be32()
|
||||
* - This is well-defined: -1 as s16 -1 as int 0xFFFFFFFF on wire
|
||||
*/
|
||||
static inline bool
|
||||
xdrgen_encode_short(struct xdr_stream *xdr, s16 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* De facto (non-standard but commonly implemented) unsigned short type:
|
||||
* 16-bit integer zero-extended to fill one XDR_UNIT.
|
||||
*/
|
||||
static inline bool
|
||||
xdrgen_decode_unsigned_short(struct xdr_stream *xdr, u16 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = (u16)be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_unsigned_short(struct xdr_stream *xdr, u16 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_int(struct xdr_stream *xdr, s32 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_int(struct xdr_stream *xdr, s32 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_unsigned_int(struct xdr_stream *xdr, u32 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_unsigned_int(struct xdr_stream *xdr, u32 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_long(struct xdr_stream *xdr, s32 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_long(struct xdr_stream *xdr, s32 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_unsigned_long(struct xdr_stream *xdr, u32 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = be32_to_cpup(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_unsigned_long(struct xdr_stream *xdr, u32 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*p = cpu_to_be32(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_hyper(struct xdr_stream *xdr, s64 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT * 2);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = get_unaligned_be64(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_hyper(struct xdr_stream *xdr, s64 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT * 2);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
put_unaligned_be64(val, p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_unsigned_hyper(struct xdr_stream *xdr, u64 *ptr)
|
||||
{
|
||||
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT * 2);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
*ptr = get_unaligned_be64(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_unsigned_hyper(struct xdr_stream *xdr, u64 val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT * 2);
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
put_unaligned_be64(val, p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_string(struct xdr_stream *xdr, string *ptr, u32 maxlen)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0))
|
||||
return false;
|
||||
if (unlikely(maxlen && len > maxlen))
|
||||
return false;
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
ptr->data = (unsigned char *)p;
|
||||
ptr->len = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_string(struct xdr_stream *xdr, string val, u32 maxlen)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT + xdr_align_size(val.len));
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
xdr_encode_opaque(p, val.data, val.len);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_decode_opaque(struct xdr_stream *xdr, opaque *ptr, u32 maxlen)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0))
|
||||
return false;
|
||||
if (unlikely(maxlen && len > maxlen))
|
||||
return false;
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
ptr->data = (u8 *)p;
|
||||
ptr->len = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xdrgen_encode_opaque(struct xdr_stream *xdr, opaque val)
|
||||
{
|
||||
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT + xdr_align_size(val.len));
|
||||
|
||||
if (unlikely(!p))
|
||||
return false;
|
||||
xdr_encode_opaque(p, val.data, val.len);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* _SUNRPC_XDRGEN__BUILTINS_H_ */
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2024 Oracle and/or its affiliates.
|
||||
*
|
||||
* This header defines XDR data type primitives specified in
|
||||
* Section 4 of RFC 4506, used by RPC programs implemented
|
||||
* in the Linux kernel.
|
||||
*/
|
||||
|
||||
#ifndef _SUNRPC_XDRGEN__DEFS_H_
|
||||
#define _SUNRPC_XDRGEN__DEFS_H_
|
||||
|
||||
#define TRUE (true)
|
||||
#define FALSE (false)
|
||||
|
||||
typedef struct {
|
||||
u32 len;
|
||||
unsigned char *data;
|
||||
} string;
|
||||
|
||||
typedef struct {
|
||||
u32 len;
|
||||
u8 *data;
|
||||
} opaque;
|
||||
|
||||
#define XDR_void (0)
|
||||
#define XDR_bool (1)
|
||||
#define XDR_int (1)
|
||||
#define XDR_unsigned_int (1)
|
||||
#define XDR_long (1)
|
||||
#define XDR_unsigned_long (1)
|
||||
#define XDR_hyper (2)
|
||||
#define XDR_unsigned_hyper (2)
|
||||
|
||||
#endif /* _SUNRPC_XDRGEN__DEFS_H_ */
|
||||
@@ -0,0 +1,263 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x */
|
||||
/* XDR specification modification time: Thu Jan 8 23:12:07 2026 */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_NFS4_1_DEF_H
|
||||
#define _LINUX_XDRGEN_NFS4_1_DEF_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sunrpc/xdrgen/_defs.h>
|
||||
|
||||
typedef s64 int64_t;
|
||||
|
||||
typedef u32 uint32_t;
|
||||
|
||||
typedef struct {
|
||||
u32 count;
|
||||
uint32_t *element;
|
||||
} bitmap4;
|
||||
|
||||
typedef opaque utf8string;
|
||||
|
||||
typedef utf8string utf8str_cis;
|
||||
|
||||
typedef utf8string utf8str_cs;
|
||||
|
||||
typedef utf8string utf8str_mixed;
|
||||
|
||||
struct nfstime4 {
|
||||
int64_t seconds;
|
||||
uint32_t nseconds;
|
||||
};
|
||||
|
||||
typedef bool fattr4_offline;
|
||||
|
||||
enum { FATTR4_OFFLINE = 83 };
|
||||
|
||||
struct open_arguments4 {
|
||||
bitmap4 oa_share_access;
|
||||
bitmap4 oa_share_deny;
|
||||
bitmap4 oa_share_access_want;
|
||||
bitmap4 oa_open_claim;
|
||||
bitmap4 oa_create_mode;
|
||||
};
|
||||
|
||||
enum open_args_share_access4 {
|
||||
OPEN_ARGS_SHARE_ACCESS_READ = 1,
|
||||
OPEN_ARGS_SHARE_ACCESS_WRITE = 2,
|
||||
OPEN_ARGS_SHARE_ACCESS_BOTH = 3,
|
||||
};
|
||||
|
||||
typedef enum open_args_share_access4 open_args_share_access4;
|
||||
|
||||
enum open_args_share_deny4 {
|
||||
OPEN_ARGS_SHARE_DENY_NONE = 0,
|
||||
OPEN_ARGS_SHARE_DENY_READ = 1,
|
||||
OPEN_ARGS_SHARE_DENY_WRITE = 2,
|
||||
OPEN_ARGS_SHARE_DENY_BOTH = 3,
|
||||
};
|
||||
|
||||
typedef enum open_args_share_deny4 open_args_share_deny4;
|
||||
|
||||
enum open_args_share_access_want4 {
|
||||
OPEN_ARGS_SHARE_ACCESS_WANT_ANY_DELEG = 3,
|
||||
OPEN_ARGS_SHARE_ACCESS_WANT_NO_DELEG = 4,
|
||||
OPEN_ARGS_SHARE_ACCESS_WANT_CANCEL = 5,
|
||||
OPEN_ARGS_SHARE_ACCESS_WANT_SIGNAL_DELEG_WHEN_RESRC_AVAIL = 17,
|
||||
OPEN_ARGS_SHARE_ACCESS_WANT_PUSH_DELEG_WHEN_UNCONTENDED = 18,
|
||||
OPEN_ARGS_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS = 20,
|
||||
OPEN_ARGS_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION = 21,
|
||||
};
|
||||
|
||||
typedef enum open_args_share_access_want4 open_args_share_access_want4;
|
||||
|
||||
enum open_args_open_claim4 {
|
||||
OPEN_ARGS_OPEN_CLAIM_NULL = 0,
|
||||
OPEN_ARGS_OPEN_CLAIM_PREVIOUS = 1,
|
||||
OPEN_ARGS_OPEN_CLAIM_DELEGATE_CUR = 2,
|
||||
OPEN_ARGS_OPEN_CLAIM_DELEGATE_PREV = 3,
|
||||
OPEN_ARGS_OPEN_CLAIM_FH = 4,
|
||||
OPEN_ARGS_OPEN_CLAIM_DELEG_CUR_FH = 5,
|
||||
OPEN_ARGS_OPEN_CLAIM_DELEG_PREV_FH = 6,
|
||||
};
|
||||
|
||||
typedef enum open_args_open_claim4 open_args_open_claim4;
|
||||
|
||||
enum open_args_createmode4 {
|
||||
OPEN_ARGS_CREATEMODE_UNCHECKED4 = 0,
|
||||
OPEN_ARGS_CREATE_MODE_GUARDED = 1,
|
||||
OPEN_ARGS_CREATEMODE_EXCLUSIVE4 = 2,
|
||||
OPEN_ARGS_CREATE_MODE_EXCLUSIVE4_1 = 3,
|
||||
};
|
||||
|
||||
typedef enum open_args_createmode4 open_args_createmode4;
|
||||
|
||||
typedef struct open_arguments4 fattr4_open_arguments;
|
||||
|
||||
/*
|
||||
* Determine what OPEN supports.
|
||||
*/
|
||||
|
||||
enum { FATTR4_OPEN_ARGUMENTS = 86 };
|
||||
|
||||
enum { OPEN4_RESULT_NO_OPEN_STATEID = 0x00000010 };
|
||||
|
||||
typedef struct nfstime4 fattr4_time_deleg_access;
|
||||
|
||||
typedef struct nfstime4 fattr4_time_deleg_modify;
|
||||
|
||||
/*
|
||||
* New RECOMMENDED Attribute for
|
||||
* delegation caching of times
|
||||
*/
|
||||
|
||||
enum { FATTR4_TIME_DELEG_ACCESS = 84 };
|
||||
|
||||
enum { FATTR4_TIME_DELEG_MODIFY = 85 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_DELEG_MASK = 0xFF00 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_NO_PREFERENCE = 0x0000 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_READ_DELEG = 0x0100 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG = 0x0200 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_ANY_DELEG = 0x0300 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_NO_DELEG = 0x0400 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_CANCEL = 0x0500 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_SIGNAL_DELEG_WHEN_RESRC_AVAIL = 0x10000 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_PUSH_DELEG_WHEN_UNCONTENDED = 0x20000 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS = 0x100000 };
|
||||
|
||||
enum { OPEN4_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION = 0x200000 };
|
||||
|
||||
enum open_delegation_type4 {
|
||||
OPEN_DELEGATE_NONE = 0,
|
||||
OPEN_DELEGATE_READ = 1,
|
||||
OPEN_DELEGATE_WRITE = 2,
|
||||
OPEN_DELEGATE_NONE_EXT = 3,
|
||||
OPEN_DELEGATE_READ_ATTRS_DELEG = 4,
|
||||
OPEN_DELEGATE_WRITE_ATTRS_DELEG = 5,
|
||||
};
|
||||
|
||||
typedef enum open_delegation_type4 open_delegation_type4;
|
||||
|
||||
enum aclmodel4 {
|
||||
ACL_MODEL_NFS4 = 1,
|
||||
ACL_MODEL_POSIX_DRAFT = 2,
|
||||
ACL_MODEL_NONE = 3,
|
||||
};
|
||||
|
||||
typedef enum aclmodel4 aclmodel4;
|
||||
|
||||
enum aclscope4 {
|
||||
ACL_SCOPE_FILE_OBJECT = 1,
|
||||
ACL_SCOPE_FILE_SYSTEM = 2,
|
||||
ACL_SCOPE_SERVER = 3,
|
||||
};
|
||||
|
||||
typedef enum aclscope4 aclscope4;
|
||||
|
||||
enum posixacetag4 {
|
||||
POSIXACE4_TAG_USER_OBJ = 1,
|
||||
POSIXACE4_TAG_USER = 2,
|
||||
POSIXACE4_TAG_GROUP_OBJ = 3,
|
||||
POSIXACE4_TAG_GROUP = 4,
|
||||
POSIXACE4_TAG_MASK = 5,
|
||||
POSIXACE4_TAG_OTHER = 6,
|
||||
};
|
||||
|
||||
typedef enum posixacetag4 posixacetag4;
|
||||
|
||||
typedef uint32_t posixaceperm4;
|
||||
|
||||
enum { POSIXACE4_PERM_EXECUTE = 0x00000001 };
|
||||
|
||||
enum { POSIXACE4_PERM_WRITE = 0x00000002 };
|
||||
|
||||
enum { POSIXACE4_PERM_READ = 0x00000004 };
|
||||
|
||||
struct posixace4 {
|
||||
posixacetag4 tag;
|
||||
posixaceperm4 perm;
|
||||
utf8str_mixed who;
|
||||
};
|
||||
|
||||
typedef aclmodel4 fattr4_acl_trueform;
|
||||
|
||||
typedef aclscope4 fattr4_acl_trueform_scope;
|
||||
|
||||
typedef struct {
|
||||
u32 count;
|
||||
struct posixace4 *element;
|
||||
} fattr4_posix_default_acl;
|
||||
|
||||
typedef struct {
|
||||
u32 count;
|
||||
struct posixace4 *element;
|
||||
} fattr4_posix_access_acl;
|
||||
|
||||
/*
|
||||
* New for POSIX ACL extension
|
||||
*/
|
||||
|
||||
enum { FATTR4_ACL_TRUEFORM = 89 };
|
||||
|
||||
enum { FATTR4_ACL_TRUEFORM_SCOPE = 90 };
|
||||
|
||||
enum { FATTR4_POSIX_DEFAULT_ACL = 91 };
|
||||
|
||||
enum { FATTR4_POSIX_ACCESS_ACL = 92 };
|
||||
|
||||
#define NFS4_int64_t_sz \
|
||||
(XDR_hyper)
|
||||
#define NFS4_uint32_t_sz \
|
||||
(XDR_unsigned_int)
|
||||
#define NFS4_bitmap4_sz (XDR_unsigned_int)
|
||||
#define NFS4_utf8string_sz (XDR_unsigned_int)
|
||||
#define NFS4_utf8str_cis_sz \
|
||||
(NFS4_utf8string_sz)
|
||||
#define NFS4_utf8str_cs_sz \
|
||||
(NFS4_utf8string_sz)
|
||||
#define NFS4_utf8str_mixed_sz \
|
||||
(NFS4_utf8string_sz)
|
||||
#define NFS4_nfstime4_sz \
|
||||
(NFS4_int64_t_sz + NFS4_uint32_t_sz)
|
||||
#define NFS4_fattr4_offline_sz \
|
||||
(XDR_bool)
|
||||
#define NFS4_open_arguments4_sz \
|
||||
(NFS4_bitmap4_sz + NFS4_bitmap4_sz + NFS4_bitmap4_sz + NFS4_bitmap4_sz + NFS4_bitmap4_sz)
|
||||
#define NFS4_open_args_share_access4_sz (XDR_int)
|
||||
#define NFS4_open_args_share_deny4_sz (XDR_int)
|
||||
#define NFS4_open_args_share_access_want4_sz (XDR_int)
|
||||
#define NFS4_open_args_open_claim4_sz (XDR_int)
|
||||
#define NFS4_open_args_createmode4_sz (XDR_int)
|
||||
#define NFS4_fattr4_open_arguments_sz \
|
||||
(NFS4_open_arguments4_sz)
|
||||
#define NFS4_fattr4_time_deleg_access_sz \
|
||||
(NFS4_nfstime4_sz)
|
||||
#define NFS4_fattr4_time_deleg_modify_sz \
|
||||
(NFS4_nfstime4_sz)
|
||||
#define NFS4_open_delegation_type4_sz (XDR_int)
|
||||
#define NFS4_aclmodel4_sz (XDR_int)
|
||||
#define NFS4_aclscope4_sz (XDR_int)
|
||||
#define NFS4_posixacetag4_sz (XDR_int)
|
||||
#define NFS4_posixaceperm4_sz \
|
||||
(NFS4_uint32_t_sz)
|
||||
#define NFS4_posixace4_sz \
|
||||
(NFS4_posixacetag4_sz + NFS4_posixaceperm4_sz + NFS4_utf8str_mixed_sz)
|
||||
#define NFS4_fattr4_acl_trueform_sz \
|
||||
(NFS4_aclmodel4_sz)
|
||||
#define NFS4_fattr4_acl_trueform_scope_sz \
|
||||
(NFS4_aclscope4_sz)
|
||||
#define NFS4_fattr4_posix_default_acl_sz (XDR_unsigned_int)
|
||||
#define NFS4_fattr4_posix_access_acl_sz (XDR_unsigned_int)
|
||||
|
||||
#endif /* _LINUX_XDRGEN_NFS4_1_DEF_H */
|
||||
@@ -0,0 +1,233 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x */
|
||||
/* XDR specification modification time: Thu Dec 25 13:10:19 2025 */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_NLM4_DEF_H
|
||||
#define _LINUX_XDRGEN_NLM4_DEF_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sunrpc/xdrgen/_defs.h>
|
||||
|
||||
enum { LM_MAXSTRLEN = 1024 };
|
||||
|
||||
enum { LM_MAXNAMELEN = 1025 };
|
||||
|
||||
enum { MAXNETOBJ_SZ = 1024 };
|
||||
|
||||
typedef opaque netobj;
|
||||
|
||||
enum fsh4_mode {
|
||||
fsm_DN = 0,
|
||||
fsm_DR = 1,
|
||||
fsm_DW = 2,
|
||||
fsm_DRW = 3,
|
||||
};
|
||||
|
||||
typedef enum fsh4_mode fsh4_mode;
|
||||
|
||||
enum fsh4_access {
|
||||
fsa_NONE = 0,
|
||||
fsa_R = 1,
|
||||
fsa_W = 2,
|
||||
fsa_RW = 3,
|
||||
};
|
||||
|
||||
typedef enum fsh4_access fsh4_access;
|
||||
|
||||
enum { SM_MAXSTRLEN = 1024 };
|
||||
|
||||
typedef u64 uint64;
|
||||
|
||||
typedef s64 int64;
|
||||
|
||||
typedef u32 uint32;
|
||||
|
||||
typedef s32 int32;
|
||||
|
||||
enum nlm4_stats {
|
||||
NLM4_GRANTED = 0,
|
||||
NLM4_DENIED = 1,
|
||||
NLM4_DENIED_NOLOCKS = 2,
|
||||
NLM4_BLOCKED = 3,
|
||||
NLM4_DENIED_GRACE_PERIOD = 4,
|
||||
NLM4_DEADLCK = 5,
|
||||
NLM4_ROFS = 6,
|
||||
NLM4_STALE_FH = 7,
|
||||
NLM4_FBIG = 8,
|
||||
NLM4_FAILED = 9,
|
||||
};
|
||||
|
||||
typedef __be32 nlm4_stats;
|
||||
|
||||
struct nlm4_holder {
|
||||
bool exclusive;
|
||||
int32 svid;
|
||||
netobj oh;
|
||||
uint64 l_offset;
|
||||
uint64 l_len;
|
||||
};
|
||||
|
||||
struct nlm4_testrply {
|
||||
nlm4_stats stat;
|
||||
union {
|
||||
struct nlm4_holder holder;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct nlm4_stat {
|
||||
nlm4_stats stat;
|
||||
};
|
||||
|
||||
struct nlm4_res {
|
||||
netobj cookie;
|
||||
struct nlm4_stat stat;
|
||||
};
|
||||
|
||||
struct nlm4_testres {
|
||||
netobj cookie;
|
||||
struct nlm4_testrply stat;
|
||||
};
|
||||
|
||||
struct nlm4_lock {
|
||||
string caller_name;
|
||||
netobj fh;
|
||||
netobj oh;
|
||||
int32 svid;
|
||||
uint64 l_offset;
|
||||
uint64 l_len;
|
||||
};
|
||||
|
||||
struct nlm4_lockargs {
|
||||
netobj cookie;
|
||||
bool block;
|
||||
bool exclusive;
|
||||
struct nlm4_lock alock;
|
||||
bool reclaim;
|
||||
int32 state;
|
||||
};
|
||||
|
||||
struct nlm4_cancargs {
|
||||
netobj cookie;
|
||||
bool block;
|
||||
bool exclusive;
|
||||
struct nlm4_lock alock;
|
||||
};
|
||||
|
||||
struct nlm4_testargs {
|
||||
netobj cookie;
|
||||
bool exclusive;
|
||||
struct nlm4_lock alock;
|
||||
};
|
||||
|
||||
struct nlm4_unlockargs {
|
||||
netobj cookie;
|
||||
struct nlm4_lock alock;
|
||||
};
|
||||
|
||||
struct nlm4_share {
|
||||
string caller_name;
|
||||
netobj fh;
|
||||
netobj oh;
|
||||
fsh4_mode mode;
|
||||
fsh4_access access;
|
||||
};
|
||||
|
||||
struct nlm4_shareargs {
|
||||
netobj cookie;
|
||||
struct nlm4_share share;
|
||||
bool reclaim;
|
||||
};
|
||||
|
||||
struct nlm4_shareres {
|
||||
netobj cookie;
|
||||
nlm4_stats stat;
|
||||
int32 sequence;
|
||||
};
|
||||
|
||||
struct nlm4_notify {
|
||||
string name;
|
||||
int32 state;
|
||||
};
|
||||
|
||||
enum { SM_PRIV_SIZE = 16 };
|
||||
|
||||
struct nlm4_notifyargs {
|
||||
struct nlm4_notify notify;
|
||||
u8 private[SM_PRIV_SIZE];
|
||||
};
|
||||
|
||||
enum {
|
||||
NLMPROC4_NULL = 0,
|
||||
NLMPROC4_TEST = 1,
|
||||
NLMPROC4_LOCK = 2,
|
||||
NLMPROC4_CANCEL = 3,
|
||||
NLMPROC4_UNLOCK = 4,
|
||||
NLMPROC4_GRANTED = 5,
|
||||
NLMPROC4_TEST_MSG = 6,
|
||||
NLMPROC4_LOCK_MSG = 7,
|
||||
NLMPROC4_CANCEL_MSG = 8,
|
||||
NLMPROC4_UNLOCK_MSG = 9,
|
||||
NLMPROC4_GRANTED_MSG = 10,
|
||||
NLMPROC4_TEST_RES = 11,
|
||||
NLMPROC4_LOCK_RES = 12,
|
||||
NLMPROC4_CANCEL_RES = 13,
|
||||
NLMPROC4_UNLOCK_RES = 14,
|
||||
NLMPROC4_GRANTED_RES = 15,
|
||||
NLMPROC4_SM_NOTIFY = 16,
|
||||
NLMPROC4_SHARE = 20,
|
||||
NLMPROC4_UNSHARE = 21,
|
||||
NLMPROC4_NM_LOCK = 22,
|
||||
NLMPROC4_FREE_ALL = 23,
|
||||
};
|
||||
|
||||
#ifndef NLM4_PROG
|
||||
#define NLM4_PROG (100021)
|
||||
#endif
|
||||
|
||||
#define NLM4_netobj_sz (XDR_unsigned_int + XDR_QUADLEN(MAXNETOBJ_SZ))
|
||||
#define NLM4_fsh4_mode_sz (XDR_int)
|
||||
#define NLM4_fsh4_access_sz (XDR_int)
|
||||
#define NLM4_uint64_sz \
|
||||
(XDR_unsigned_hyper)
|
||||
#define NLM4_int64_sz \
|
||||
(XDR_hyper)
|
||||
#define NLM4_uint32_sz \
|
||||
(XDR_unsigned_long)
|
||||
#define NLM4_int32_sz \
|
||||
(XDR_long)
|
||||
#define NLM4_nlm4_stats_sz (XDR_int)
|
||||
#define NLM4_nlm4_holder_sz \
|
||||
(XDR_bool + NLM4_int32_sz + NLM4_netobj_sz + NLM4_uint64_sz + NLM4_uint64_sz)
|
||||
#define NLM4_nlm4_testrply_sz \
|
||||
(NLM4_nlm4_stats_sz + NLM4_nlm4_holder_sz)
|
||||
#define NLM4_nlm4_stat_sz \
|
||||
(NLM4_nlm4_stats_sz)
|
||||
#define NLM4_nlm4_res_sz \
|
||||
(NLM4_netobj_sz + NLM4_nlm4_stat_sz)
|
||||
#define NLM4_nlm4_testres_sz \
|
||||
(NLM4_netobj_sz + NLM4_nlm4_testrply_sz)
|
||||
#define NLM4_nlm4_lock_sz \
|
||||
(XDR_unsigned_int + XDR_QUADLEN(LM_MAXSTRLEN) + NLM4_netobj_sz + NLM4_netobj_sz + NLM4_int32_sz + NLM4_uint64_sz + NLM4_uint64_sz)
|
||||
#define NLM4_nlm4_lockargs_sz \
|
||||
(NLM4_netobj_sz + XDR_bool + XDR_bool + NLM4_nlm4_lock_sz + XDR_bool + NLM4_int32_sz)
|
||||
#define NLM4_nlm4_cancargs_sz \
|
||||
(NLM4_netobj_sz + XDR_bool + XDR_bool + NLM4_nlm4_lock_sz)
|
||||
#define NLM4_nlm4_testargs_sz \
|
||||
(NLM4_netobj_sz + XDR_bool + NLM4_nlm4_lock_sz)
|
||||
#define NLM4_nlm4_unlockargs_sz \
|
||||
(NLM4_netobj_sz + NLM4_nlm4_lock_sz)
|
||||
#define NLM4_nlm4_share_sz \
|
||||
(XDR_unsigned_int + XDR_QUADLEN(LM_MAXSTRLEN) + NLM4_netobj_sz + NLM4_netobj_sz + NLM4_fsh4_mode_sz + NLM4_fsh4_access_sz)
|
||||
#define NLM4_nlm4_shareargs_sz \
|
||||
(NLM4_netobj_sz + NLM4_nlm4_share_sz + XDR_bool)
|
||||
#define NLM4_nlm4_shareres_sz \
|
||||
(NLM4_netobj_sz + NLM4_nlm4_stats_sz + NLM4_int32_sz)
|
||||
#define NLM4_nlm4_notify_sz \
|
||||
(XDR_unsigned_int + XDR_QUADLEN(LM_MAXNAMELEN) + NLM4_int32_sz)
|
||||
#define NLM4_nlm4_notifyargs_sz \
|
||||
(NLM4_nlm4_notify_sz + XDR_QUADLEN(SM_PRIV_SIZE))
|
||||
#define NLM4_MAX_ARGS_SZ \
|
||||
(NLM4_nlm4_lockargs_sz)
|
||||
|
||||
#endif /* _LINUX_XDRGEN_NLM4_DEF_H */
|
||||
@@ -0,0 +1,540 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/xprt.h
|
||||
*
|
||||
* Declarations for the RPC transport interface.
|
||||
*
|
||||
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_XPRT_H
|
||||
#define _LINUX_SUNRPC_XPRT_H
|
||||
|
||||
#include <linux/uio.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/msg_prot.h>
|
||||
|
||||
#define RPC_MIN_SLOT_TABLE (2U)
|
||||
#define RPC_DEF_SLOT_TABLE (16U)
|
||||
#define RPC_MAX_SLOT_TABLE_LIMIT (65536U)
|
||||
#define RPC_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE_LIMIT
|
||||
|
||||
#define RPC_CWNDSHIFT (8U)
|
||||
#define RPC_CWNDSCALE (1U << RPC_CWNDSHIFT)
|
||||
#define RPC_INITCWND RPC_CWNDSCALE
|
||||
#define RPC_MAXCWND(xprt) ((xprt)->max_reqs << RPC_CWNDSHIFT)
|
||||
#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
|
||||
|
||||
#define RPC_GSS_SEQNO_ARRAY_SIZE 3U
|
||||
|
||||
enum rpc_display_format_t {
|
||||
RPC_DISPLAY_ADDR = 0,
|
||||
RPC_DISPLAY_PORT,
|
||||
RPC_DISPLAY_PROTO,
|
||||
RPC_DISPLAY_HEX_ADDR,
|
||||
RPC_DISPLAY_HEX_PORT,
|
||||
RPC_DISPLAY_NETID,
|
||||
RPC_DISPLAY_MAX,
|
||||
};
|
||||
|
||||
struct rpc_task;
|
||||
struct rpc_xprt;
|
||||
struct xprt_class;
|
||||
struct seq_file;
|
||||
struct svc_serv;
|
||||
struct net;
|
||||
#include <linux/lwq.h>
|
||||
|
||||
/*
|
||||
* This describes a complete RPC request
|
||||
*/
|
||||
struct rpc_rqst {
|
||||
/*
|
||||
* This is the user-visible part
|
||||
*/
|
||||
struct rpc_xprt * rq_xprt; /* RPC client */
|
||||
struct xdr_buf rq_snd_buf; /* send buffer */
|
||||
struct xdr_buf rq_rcv_buf; /* recv buffer */
|
||||
|
||||
/*
|
||||
* This is the private part
|
||||
*/
|
||||
struct rpc_task * rq_task; /* RPC task data */
|
||||
struct rpc_cred * rq_cred; /* Bound cred */
|
||||
__be32 rq_xid; /* request XID */
|
||||
int rq_cong; /* has incremented xprt->cong */
|
||||
u32 rq_seqnos[RPC_GSS_SEQNO_ARRAY_SIZE]; /* past gss req seq nos. */
|
||||
unsigned int rq_seqno_count; /* number of entries in rq_seqnos */
|
||||
int rq_enc_pages_num;
|
||||
struct page **rq_enc_pages; /* scratch pages for use by
|
||||
gss privacy code */
|
||||
void (*rq_release_snd_buf)(struct rpc_rqst *); /* release rq_enc_pages */
|
||||
|
||||
union {
|
||||
struct list_head rq_list; /* Slot allocation list */
|
||||
struct rb_node rq_recv; /* Receive queue */
|
||||
};
|
||||
|
||||
struct list_head rq_xmit; /* Send queue */
|
||||
struct list_head rq_xmit2; /* Send queue */
|
||||
|
||||
void *rq_buffer; /* Call XDR encode buffer */
|
||||
size_t rq_callsize;
|
||||
void *rq_rbuffer; /* Reply XDR decode buffer */
|
||||
size_t rq_rcvsize;
|
||||
size_t rq_xmit_bytes_sent; /* total bytes sent */
|
||||
size_t rq_reply_bytes_recvd; /* total reply bytes */
|
||||
/* received */
|
||||
|
||||
struct xdr_buf rq_private_buf; /* The receive buffer
|
||||
* used in the softirq.
|
||||
*/
|
||||
unsigned long rq_majortimeo; /* major timeout alarm */
|
||||
unsigned long rq_minortimeo; /* minor timeout alarm */
|
||||
unsigned long rq_timeout; /* Current timeout value */
|
||||
ktime_t rq_rtt; /* round-trip time */
|
||||
unsigned int rq_retries; /* # of retries */
|
||||
unsigned int rq_connect_cookie;
|
||||
/* A cookie used to track the
|
||||
state of the transport
|
||||
connection */
|
||||
atomic_t rq_pin;
|
||||
|
||||
/*
|
||||
* Partial send handling
|
||||
*/
|
||||
u32 rq_bytes_sent; /* Bytes we have sent */
|
||||
|
||||
ktime_t rq_xtime; /* transmit time stamp */
|
||||
int rq_ntrans;
|
||||
|
||||
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
|
||||
struct lwq_node rq_bc_list; /* Callback service list */
|
||||
unsigned long rq_bc_pa_state; /* Backchannel prealloc state */
|
||||
struct list_head rq_bc_pa_list; /* Backchannel prealloc list */
|
||||
#endif /* CONFIG_SUNRPC_BACKCHANEL */
|
||||
};
|
||||
#define rq_svec rq_snd_buf.head
|
||||
#define rq_slen rq_snd_buf.len
|
||||
|
||||
static inline int xprt_rqst_add_seqno(struct rpc_rqst *req, u32 seqno)
|
||||
{
|
||||
if (likely(req->rq_seqno_count < RPC_GSS_SEQNO_ARRAY_SIZE))
|
||||
req->rq_seqno_count++;
|
||||
|
||||
/* Shift array to make room for the newest element at the beginning */
|
||||
memmove(&req->rq_seqnos[1], &req->rq_seqnos[0],
|
||||
(RPC_GSS_SEQNO_ARRAY_SIZE - 1) * sizeof(req->rq_seqnos[0]));
|
||||
req->rq_seqnos[0] = seqno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RPC transport layer security policies */
|
||||
enum xprtsec_policies {
|
||||
RPC_XPRTSEC_NONE = 0,
|
||||
RPC_XPRTSEC_TLS_ANON,
|
||||
RPC_XPRTSEC_TLS_X509,
|
||||
};
|
||||
|
||||
struct xprtsec_parms {
|
||||
enum xprtsec_policies policy;
|
||||
|
||||
/* authentication material */
|
||||
key_serial_t cert_serial;
|
||||
key_serial_t privkey_serial;
|
||||
};
|
||||
|
||||
struct rpc_xprt_ops {
|
||||
void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize);
|
||||
int (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void (*alloc_slot)(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void (*free_slot)(struct rpc_xprt *xprt,
|
||||
struct rpc_rqst *req);
|
||||
void (*rpcbind)(struct rpc_task *task);
|
||||
void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
|
||||
void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
int (*get_srcaddr)(struct rpc_xprt *xprt, char *buf,
|
||||
size_t buflen);
|
||||
unsigned short (*get_srcport)(struct rpc_xprt *xprt);
|
||||
int (*buf_alloc)(struct rpc_task *task);
|
||||
void (*buf_free)(struct rpc_task *task);
|
||||
int (*prepare_request)(struct rpc_rqst *req,
|
||||
struct xdr_buf *buf);
|
||||
int (*send_request)(struct rpc_rqst *req);
|
||||
void (*abort_send_request)(struct rpc_rqst *req);
|
||||
void (*wait_for_reply_request)(struct rpc_task *task);
|
||||
void (*timer)(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void (*release_request)(struct rpc_task *task);
|
||||
void (*close)(struct rpc_xprt *xprt);
|
||||
void (*destroy)(struct rpc_xprt *xprt);
|
||||
void (*set_connect_timeout)(struct rpc_xprt *xprt,
|
||||
unsigned long connect_timeout,
|
||||
unsigned long reconnect_timeout);
|
||||
void (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq);
|
||||
int (*enable_swap)(struct rpc_xprt *xprt);
|
||||
void (*disable_swap)(struct rpc_xprt *xprt);
|
||||
void (*inject_disconnect)(struct rpc_xprt *xprt);
|
||||
int (*bc_setup)(struct rpc_xprt *xprt,
|
||||
unsigned int min_reqs);
|
||||
size_t (*bc_maxpayload)(struct rpc_xprt *xprt);
|
||||
unsigned int (*bc_num_slots)(struct rpc_xprt *xprt);
|
||||
void (*bc_free_rqst)(struct rpc_rqst *rqst);
|
||||
void (*bc_destroy)(struct rpc_xprt *xprt,
|
||||
unsigned int max_reqs);
|
||||
};
|
||||
|
||||
/*
|
||||
* RPC transport identifiers
|
||||
*
|
||||
* To preserve compatibility with the historical use of raw IP protocol
|
||||
* id's for transport selection, UDP and TCP identifiers are specified
|
||||
* with the previous values. No such restriction exists for new transports,
|
||||
* except that they may not collide with these values (17 and 6,
|
||||
* respectively).
|
||||
*/
|
||||
#define XPRT_TRANSPORT_BC (1 << 31)
|
||||
enum xprt_transports {
|
||||
XPRT_TRANSPORT_UDP = IPPROTO_UDP,
|
||||
XPRT_TRANSPORT_TCP = IPPROTO_TCP,
|
||||
XPRT_TRANSPORT_BC_TCP = IPPROTO_TCP | XPRT_TRANSPORT_BC,
|
||||
XPRT_TRANSPORT_RDMA = 256,
|
||||
XPRT_TRANSPORT_BC_RDMA = XPRT_TRANSPORT_RDMA | XPRT_TRANSPORT_BC,
|
||||
XPRT_TRANSPORT_LOCAL = 257,
|
||||
XPRT_TRANSPORT_TCP_TLS = 258,
|
||||
};
|
||||
|
||||
struct rpc_sysfs_xprt;
|
||||
struct rpc_xprt {
|
||||
struct kref kref; /* Reference count */
|
||||
const struct rpc_xprt_ops *ops; /* transport methods */
|
||||
unsigned int id; /* transport id */
|
||||
|
||||
const struct rpc_timeout *timeout; /* timeout parms */
|
||||
struct sockaddr_storage addr; /* server address */
|
||||
size_t addrlen; /* size of server address */
|
||||
int prot; /* IP protocol */
|
||||
|
||||
unsigned long cong; /* current congestion */
|
||||
unsigned long cwnd; /* congestion window */
|
||||
|
||||
size_t max_payload; /* largest RPC payload size,
|
||||
in bytes */
|
||||
|
||||
struct rpc_wait_queue binding; /* requests waiting on rpcbind */
|
||||
struct rpc_wait_queue sending; /* requests waiting to send */
|
||||
struct rpc_wait_queue pending; /* requests in flight */
|
||||
struct rpc_wait_queue backlog; /* waiting for slot */
|
||||
struct list_head free; /* free slots */
|
||||
unsigned int max_reqs; /* max number of slots */
|
||||
unsigned int min_reqs; /* min number of slots */
|
||||
unsigned int num_reqs; /* total slots */
|
||||
unsigned long state; /* transport state */
|
||||
unsigned char resvport : 1, /* use a reserved port */
|
||||
reuseport : 1; /* reuse port on reconnect */
|
||||
atomic_t swapper; /* we're swapping over this
|
||||
transport */
|
||||
unsigned int bind_index; /* bind function index */
|
||||
|
||||
/*
|
||||
* Multipath
|
||||
*/
|
||||
struct list_head xprt_switch;
|
||||
|
||||
/*
|
||||
* Connection of transports
|
||||
*/
|
||||
unsigned long bind_timeout,
|
||||
reestablish_timeout;
|
||||
struct xprtsec_parms xprtsec;
|
||||
unsigned int connect_cookie; /* A cookie that gets bumped
|
||||
every time the transport
|
||||
is reconnected */
|
||||
|
||||
/*
|
||||
* Disconnection of idle transports
|
||||
*/
|
||||
struct work_struct task_cleanup;
|
||||
struct timer_list timer;
|
||||
unsigned long last_used,
|
||||
idle_timeout,
|
||||
connect_timeout,
|
||||
max_reconnect_timeout;
|
||||
|
||||
/*
|
||||
* Send stuff
|
||||
*/
|
||||
atomic_long_t queuelen;
|
||||
spinlock_t transport_lock; /* lock transport info */
|
||||
spinlock_t reserve_lock; /* lock slot table */
|
||||
spinlock_t queue_lock; /* send/receive queue lock */
|
||||
u32 xid; /* Next XID value to use */
|
||||
struct rpc_task * snd_task; /* Task blocked in send */
|
||||
|
||||
struct list_head xmit_queue; /* Send queue */
|
||||
atomic_long_t xmit_queuelen;
|
||||
|
||||
struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
|
||||
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
|
||||
struct svc_serv *bc_serv; /* The RPC service which will */
|
||||
/* process the callback */
|
||||
unsigned int bc_alloc_max;
|
||||
unsigned int bc_alloc_count; /* Total number of preallocs */
|
||||
atomic_t bc_slot_count; /* Number of allocated slots */
|
||||
spinlock_t bc_pa_lock; /* Protects the preallocated
|
||||
* items */
|
||||
struct list_head bc_pa_list; /* List of preallocated
|
||||
* backchannel rpc_rqst's */
|
||||
#endif /* CONFIG_SUNRPC_BACKCHANNEL */
|
||||
|
||||
struct rb_root recv_queue; /* Receive queue */
|
||||
|
||||
struct {
|
||||
unsigned long bind_count, /* total number of binds */
|
||||
connect_count, /* total number of connects */
|
||||
connect_start, /* connect start timestamp */
|
||||
connect_time, /* jiffies waiting for connect */
|
||||
sends, /* how many complete requests */
|
||||
recvs, /* how many complete requests */
|
||||
bad_xids, /* lookup_rqst didn't find XID */
|
||||
max_slots; /* max rpc_slots used */
|
||||
|
||||
unsigned long long req_u, /* average requests on the wire */
|
||||
bklog_u, /* backlog queue utilization */
|
||||
sending_u, /* send q utilization */
|
||||
pending_u; /* pend q utilization */
|
||||
} stat;
|
||||
|
||||
struct net *xprt_net;
|
||||
netns_tracker ns_tracker;
|
||||
const char *servername;
|
||||
const char *address_strings[RPC_DISPLAY_MAX];
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
struct dentry *debugfs; /* debugfs directory */
|
||||
#endif
|
||||
struct rcu_head rcu;
|
||||
const struct xprt_class *xprt_class;
|
||||
struct rpc_sysfs_xprt *xprt_sysfs;
|
||||
bool main; /*mark if this is the 1st transport */
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
|
||||
/*
|
||||
* Backchannel flags
|
||||
*/
|
||||
#define RPC_BC_PA_IN_USE 0x0001 /* Preallocated backchannel */
|
||||
/* buffer in use */
|
||||
#endif /* CONFIG_SUNRPC_BACKCHANNEL */
|
||||
|
||||
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
|
||||
static inline int bc_prealloc(struct rpc_rqst *req)
|
||||
{
|
||||
return test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
|
||||
}
|
||||
#else
|
||||
static inline int bc_prealloc(struct rpc_rqst *req)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SUNRPC_BACKCHANNEL */
|
||||
|
||||
#define XPRT_CREATE_INFINITE_SLOTS (1U)
|
||||
#define XPRT_CREATE_NO_IDLE_TIMEOUT (1U << 1)
|
||||
|
||||
struct xprt_create {
|
||||
int ident; /* XPRT_TRANSPORT identifier */
|
||||
struct net * net;
|
||||
struct sockaddr * srcaddr; /* optional local address */
|
||||
struct sockaddr * dstaddr; /* remote peer address */
|
||||
size_t addrlen;
|
||||
const char *servername;
|
||||
struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
|
||||
struct rpc_xprt_switch *bc_xps;
|
||||
unsigned int flags;
|
||||
struct xprtsec_parms xprtsec;
|
||||
unsigned long connect_timeout;
|
||||
unsigned long reconnect_timeout;
|
||||
};
|
||||
|
||||
struct xprt_class {
|
||||
struct list_head list;
|
||||
int ident; /* XPRT_TRANSPORT identifier */
|
||||
struct rpc_xprt * (*setup)(struct xprt_create *);
|
||||
struct module *owner;
|
||||
char name[32];
|
||||
const char * netid[];
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic internal transport functions
|
||||
*/
|
||||
struct rpc_xprt *xprt_create_transport(struct xprt_create *args);
|
||||
void xprt_connect(struct rpc_task *task);
|
||||
unsigned long xprt_reconnect_delay(const struct rpc_xprt *xprt);
|
||||
void xprt_reconnect_backoff(struct rpc_xprt *xprt,
|
||||
unsigned long init_to);
|
||||
void xprt_reserve(struct rpc_task *task);
|
||||
void xprt_retry_reserve(struct rpc_task *task);
|
||||
int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void xprt_free_slot(struct rpc_xprt *xprt,
|
||||
struct rpc_rqst *req);
|
||||
bool xprt_prepare_transmit(struct rpc_task *task);
|
||||
void xprt_request_enqueue_transmit(struct rpc_task *task);
|
||||
int xprt_request_enqueue_receive(struct rpc_task *task);
|
||||
void xprt_request_wait_receive(struct rpc_task *task);
|
||||
void xprt_request_dequeue_xprt(struct rpc_task *task);
|
||||
bool xprt_request_need_retransmit(struct rpc_task *task);
|
||||
void xprt_transmit(struct rpc_task *task);
|
||||
void xprt_end_transmit(struct rpc_task *task);
|
||||
int xprt_adjust_timeout(struct rpc_rqst *req);
|
||||
void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void xprt_release(struct rpc_task *task);
|
||||
struct rpc_xprt * xprt_get(struct rpc_xprt *xprt);
|
||||
void xprt_put(struct rpc_xprt *xprt);
|
||||
struct rpc_xprt * xprt_alloc(struct net *net, size_t size,
|
||||
unsigned int num_prealloc,
|
||||
unsigned int max_req);
|
||||
void xprt_free(struct rpc_xprt *);
|
||||
void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void xprt_add_backlog_noncongested(struct rpc_xprt *xprt,
|
||||
struct rpc_task *task);
|
||||
bool xprt_wake_up_backlog(struct rpc_xprt *xprt, struct rpc_rqst *req);
|
||||
void xprt_cleanup_ids(void);
|
||||
|
||||
static inline int
|
||||
xprt_enable_swap(struct rpc_xprt *xprt)
|
||||
{
|
||||
return xprt->ops->enable_swap(xprt);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xprt_disable_swap(struct rpc_xprt *xprt)
|
||||
{
|
||||
xprt->ops->disable_swap(xprt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transport switch helper functions
|
||||
*/
|
||||
int xprt_register_transport(struct xprt_class *type);
|
||||
int xprt_unregister_transport(struct xprt_class *type);
|
||||
int xprt_find_transport_ident(const char *);
|
||||
void xprt_wait_for_reply_request_def(struct rpc_task *task);
|
||||
void xprt_wait_for_reply_request_rtt(struct rpc_task *task);
|
||||
void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
|
||||
void xprt_wait_for_buffer_space(struct rpc_xprt *xprt);
|
||||
bool xprt_write_space(struct rpc_xprt *xprt);
|
||||
void xprt_adjust_cwnd(struct rpc_xprt *xprt, struct rpc_task *task, int result);
|
||||
struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid);
|
||||
void xprt_update_rtt(struct rpc_task *task);
|
||||
void xprt_complete_rqst(struct rpc_task *task, int copied);
|
||||
void xprt_pin_rqst(struct rpc_rqst *req);
|
||||
void xprt_unpin_rqst(struct rpc_rqst *req);
|
||||
void xprt_release_rqst_cong(struct rpc_task *task);
|
||||
bool xprt_request_get_cong(struct rpc_xprt *xprt, struct rpc_rqst *req);
|
||||
void xprt_disconnect_done(struct rpc_xprt *xprt);
|
||||
void xprt_force_disconnect(struct rpc_xprt *xprt);
|
||||
void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
|
||||
|
||||
bool xprt_lock_connect(struct rpc_xprt *, struct rpc_task *, void *);
|
||||
void xprt_unlock_connect(struct rpc_xprt *, void *);
|
||||
void xprt_release_write(struct rpc_xprt *, struct rpc_task *);
|
||||
|
||||
/*
|
||||
* Reserved bit positions in xprt->state
|
||||
*/
|
||||
#define XPRT_LOCKED (0)
|
||||
#define XPRT_CONNECTED (1)
|
||||
#define XPRT_CONNECTING (2)
|
||||
#define XPRT_CLOSE_WAIT (3)
|
||||
#define XPRT_BOUND (4)
|
||||
#define XPRT_BINDING (5)
|
||||
#define XPRT_CLOSING (6)
|
||||
#define XPRT_OFFLINE (7)
|
||||
#define XPRT_REMOVE (8)
|
||||
#define XPRT_CONGESTED (9)
|
||||
#define XPRT_CWND_WAIT (10)
|
||||
#define XPRT_WRITE_SPACE (11)
|
||||
#define XPRT_SND_IS_COOKIE (12)
|
||||
|
||||
static inline void xprt_set_connected(struct rpc_xprt *xprt)
|
||||
{
|
||||
set_bit(XPRT_CONNECTED, &xprt->state);
|
||||
}
|
||||
|
||||
static inline void xprt_clear_connected(struct rpc_xprt *xprt)
|
||||
{
|
||||
clear_bit(XPRT_CONNECTED, &xprt->state);
|
||||
}
|
||||
|
||||
static inline int xprt_connected(struct rpc_xprt *xprt)
|
||||
{
|
||||
return test_bit(XPRT_CONNECTED, &xprt->state);
|
||||
}
|
||||
|
||||
static inline int xprt_test_and_set_connected(struct rpc_xprt *xprt)
|
||||
{
|
||||
return test_and_set_bit(XPRT_CONNECTED, &xprt->state);
|
||||
}
|
||||
|
||||
static inline int xprt_test_and_clear_connected(struct rpc_xprt *xprt)
|
||||
{
|
||||
return test_and_clear_bit(XPRT_CONNECTED, &xprt->state);
|
||||
}
|
||||
|
||||
static inline void xprt_clear_connecting(struct rpc_xprt *xprt)
|
||||
{
|
||||
smp_mb__before_atomic();
|
||||
clear_bit(XPRT_CONNECTING, &xprt->state);
|
||||
smp_mb__after_atomic();
|
||||
}
|
||||
|
||||
static inline int xprt_connecting(struct rpc_xprt *xprt)
|
||||
{
|
||||
return test_bit(XPRT_CONNECTING, &xprt->state);
|
||||
}
|
||||
|
||||
static inline int xprt_test_and_set_connecting(struct rpc_xprt *xprt)
|
||||
{
|
||||
return test_and_set_bit(XPRT_CONNECTING, &xprt->state);
|
||||
}
|
||||
|
||||
static inline void xprt_set_bound(struct rpc_xprt *xprt)
|
||||
{
|
||||
test_and_set_bit(XPRT_BOUND, &xprt->state);
|
||||
}
|
||||
|
||||
static inline int xprt_bound(struct rpc_xprt *xprt)
|
||||
{
|
||||
return test_bit(XPRT_BOUND, &xprt->state);
|
||||
}
|
||||
|
||||
static inline void xprt_clear_bound(struct rpc_xprt *xprt)
|
||||
{
|
||||
clear_bit(XPRT_BOUND, &xprt->state);
|
||||
}
|
||||
|
||||
static inline void xprt_clear_binding(struct rpc_xprt *xprt)
|
||||
{
|
||||
smp_mb__before_atomic();
|
||||
clear_bit(XPRT_BINDING, &xprt->state);
|
||||
smp_mb__after_atomic();
|
||||
}
|
||||
|
||||
static inline int xprt_test_and_set_binding(struct rpc_xprt *xprt)
|
||||
{
|
||||
return test_and_set_bit(XPRT_BINDING, &xprt->state);
|
||||
}
|
||||
|
||||
void xprt_set_offline_locked(struct rpc_xprt *xprt, struct rpc_xprt_switch *xps);
|
||||
void xprt_set_online_locked(struct rpc_xprt *xprt, struct rpc_xprt_switch *xps);
|
||||
void xprt_delete_locked(struct rpc_xprt *xprt, struct rpc_xprt_switch *xps);
|
||||
#endif /* _LINUX_SUNRPC_XPRT_H */
|
||||
@@ -0,0 +1,86 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* RPC client multipathing definitions
|
||||
*
|
||||
* Copyright (c) 2015, 2016, Primary Data, Inc. All rights reserved.
|
||||
*
|
||||
* Trond Myklebust <trond.myklebust@primarydata.com>
|
||||
*/
|
||||
#ifndef _NET_SUNRPC_XPRTMULTIPATH_H
|
||||
#define _NET_SUNRPC_XPRTMULTIPATH_H
|
||||
|
||||
struct rpc_xprt_iter_ops;
|
||||
struct rpc_sysfs_xprt_switch;
|
||||
struct rpc_xprt_switch {
|
||||
spinlock_t xps_lock;
|
||||
struct kref xps_kref;
|
||||
|
||||
unsigned int xps_id;
|
||||
unsigned int xps_nxprts;
|
||||
unsigned int xps_nactive;
|
||||
unsigned int xps_nunique_destaddr_xprts;
|
||||
atomic_long_t xps_queuelen;
|
||||
struct list_head xps_xprt_list;
|
||||
|
||||
struct net * xps_net;
|
||||
|
||||
const struct rpc_xprt_iter_ops *xps_iter_ops;
|
||||
|
||||
struct rpc_sysfs_xprt_switch *xps_sysfs;
|
||||
struct rcu_head xps_rcu;
|
||||
};
|
||||
|
||||
struct rpc_xprt_iter {
|
||||
struct rpc_xprt_switch __rcu *xpi_xpswitch;
|
||||
struct rpc_xprt * xpi_cursor;
|
||||
|
||||
const struct rpc_xprt_iter_ops *xpi_ops;
|
||||
};
|
||||
|
||||
|
||||
struct rpc_xprt_iter_ops {
|
||||
void (*xpi_rewind)(struct rpc_xprt_iter *);
|
||||
struct rpc_xprt *(*xpi_xprt)(struct rpc_xprt_iter *);
|
||||
struct rpc_xprt *(*xpi_next)(struct rpc_xprt_iter *);
|
||||
};
|
||||
|
||||
extern struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
|
||||
gfp_t gfp_flags);
|
||||
|
||||
extern struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps);
|
||||
extern void xprt_switch_put(struct rpc_xprt_switch *xps);
|
||||
|
||||
extern void rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps);
|
||||
|
||||
extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
|
||||
struct rpc_xprt *xprt);
|
||||
extern void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
|
||||
struct rpc_xprt *xprt, bool offline);
|
||||
extern struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps);
|
||||
|
||||
extern void xprt_iter_init(struct rpc_xprt_iter *xpi,
|
||||
struct rpc_xprt_switch *xps);
|
||||
|
||||
extern void xprt_iter_init_listall(struct rpc_xprt_iter *xpi,
|
||||
struct rpc_xprt_switch *xps);
|
||||
|
||||
extern void xprt_iter_init_listoffline(struct rpc_xprt_iter *xpi,
|
||||
struct rpc_xprt_switch *xps);
|
||||
|
||||
extern void xprt_iter_destroy(struct rpc_xprt_iter *xpi);
|
||||
|
||||
extern void xprt_iter_rewind(struct rpc_xprt_iter *xpi);
|
||||
|
||||
extern struct rpc_xprt_switch *xprt_iter_xchg_switch(
|
||||
struct rpc_xprt_iter *xpi,
|
||||
struct rpc_xprt_switch *newswitch);
|
||||
|
||||
extern struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi);
|
||||
extern struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi);
|
||||
|
||||
extern bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
|
||||
const struct sockaddr *sap);
|
||||
|
||||
extern void xprt_multipath_cleanup_ids(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the BSD-type
|
||||
* license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* Neither the name of the Network Appliance, Inc. nor the names of
|
||||
* its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_XPRTRDMA_H
|
||||
#define _LINUX_SUNRPC_XPRTRDMA_H
|
||||
|
||||
/*
|
||||
* Constants. Max RPC/NFS header is big enough to account for
|
||||
* additional marshaling buffers passed down by Linux client.
|
||||
*
|
||||
* RDMA header is currently fixed max size, and is big enough for a
|
||||
* fully-chunked NFS message (read chunks are the largest). Note only
|
||||
* a single chunk type per message is supported currently.
|
||||
*/
|
||||
#define RPCRDMA_MIN_SLOT_TABLE (4U)
|
||||
#define RPCRDMA_DEF_SLOT_TABLE (128U)
|
||||
#define RPCRDMA_MAX_SLOT_TABLE (16384U)
|
||||
|
||||
#define RPCRDMA_MIN_INLINE (1024) /* min inline thresh */
|
||||
#define RPCRDMA_DEF_INLINE (4096) /* default inline thresh */
|
||||
#define RPCRDMA_MAX_INLINE (65536) /* max inline thresh */
|
||||
|
||||
/* Memory registration strategies, by number.
|
||||
* This is part of a kernel / user space API. Do not remove. */
|
||||
enum rpcrdma_memreg {
|
||||
RPCRDMA_BOUNCEBUFFERS = 0,
|
||||
RPCRDMA_REGISTER,
|
||||
RPCRDMA_MEMWINDOWS,
|
||||
RPCRDMA_MEMWINDOWS_ASYNC,
|
||||
RPCRDMA_MTHCAFMR,
|
||||
RPCRDMA_FRWR,
|
||||
RPCRDMA_ALLPHYSICAL,
|
||||
RPCRDMA_LAST
|
||||
};
|
||||
|
||||
#endif /* _LINUX_SUNRPC_XPRTRDMA_H */
|
||||
@@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/linux/sunrpc/xprtsock.h
|
||||
*
|
||||
* Declarations for the RPC transport socket provider.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_XPRTSOCK_H
|
||||
#define _LINUX_SUNRPC_XPRTSOCK_H
|
||||
|
||||
int init_socket_xprt(void);
|
||||
void cleanup_socket_xprt(void);
|
||||
|
||||
#define RPC_MIN_RESVPORT (1U)
|
||||
#define RPC_MAX_RESVPORT (65535U)
|
||||
#define RPC_DEF_MIN_RESVPORT (665U)
|
||||
#define RPC_DEF_MAX_RESVPORT (1023U)
|
||||
|
||||
struct sock_xprt {
|
||||
struct rpc_xprt xprt;
|
||||
|
||||
/*
|
||||
* Network layer
|
||||
*/
|
||||
struct socket * sock;
|
||||
struct sock * inet;
|
||||
struct file * file;
|
||||
|
||||
/*
|
||||
* State of TCP reply receive
|
||||
*/
|
||||
struct {
|
||||
struct {
|
||||
__be32 fraghdr,
|
||||
xid,
|
||||
calldir;
|
||||
} __attribute__((packed));
|
||||
|
||||
u32 offset,
|
||||
len;
|
||||
|
||||
unsigned long copied;
|
||||
} recv;
|
||||
|
||||
/*
|
||||
* State of TCP transmit queue
|
||||
*/
|
||||
struct {
|
||||
u32 offset;
|
||||
} xmit;
|
||||
|
||||
/*
|
||||
* Connection of transports
|
||||
*/
|
||||
unsigned long sock_state;
|
||||
struct delayed_work connect_worker;
|
||||
struct work_struct error_worker;
|
||||
struct work_struct recv_worker;
|
||||
struct mutex recv_mutex;
|
||||
struct completion handshake_done;
|
||||
struct sockaddr_storage srcaddr;
|
||||
unsigned short srcport;
|
||||
int xprt_err;
|
||||
struct rpc_clnt *clnt;
|
||||
|
||||
/*
|
||||
* UDP socket buffer size parameters
|
||||
*/
|
||||
size_t rcvsize,
|
||||
sndsize;
|
||||
|
||||
struct rpc_timeout tcp_timeout;
|
||||
|
||||
/*
|
||||
* Saved socket callback addresses
|
||||
*/
|
||||
void (*old_data_ready)(struct sock *);
|
||||
void (*old_state_change)(struct sock *);
|
||||
void (*old_write_space)(struct sock *);
|
||||
void (*old_error_report)(struct sock *);
|
||||
};
|
||||
|
||||
/*
|
||||
* TCP RPC flags
|
||||
*/
|
||||
#define XPRT_SOCK_CONNECTING 1U
|
||||
#define XPRT_SOCK_DATA_READY (2)
|
||||
#define XPRT_SOCK_UPD_TIMEOUT (3)
|
||||
#define XPRT_SOCK_WAKE_ERROR (4)
|
||||
#define XPRT_SOCK_WAKE_WRITE (5)
|
||||
#define XPRT_SOCK_WAKE_PENDING (6)
|
||||
#define XPRT_SOCK_WAKE_DISCONNECT (7)
|
||||
#define XPRT_SOCK_CONNECT_SENT (8)
|
||||
#define XPRT_SOCK_NOSPACE (9)
|
||||
#define XPRT_SOCK_IGNORE_RECV (10)
|
||||
|
||||
#endif /* _LINUX_SUNRPC_XPRTSOCK_H */
|
||||
Reference in New Issue
Block a user