| 1 | /* |
|---|
| 2 | * linux/include/linux/sunrpc/svc.h |
|---|
| 3 | * |
|---|
| 4 | * RPC server declarations. |
|---|
| 5 | * |
|---|
| 6 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> |
|---|
| 7 | */ |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | #ifndef SUNRPC_SVC_H |
|---|
| 11 | #define SUNRPC_SVC_H |
|---|
| 12 | |
|---|
| 13 | #include <asm/types.h> |
|---|
| 14 | |
|---|
| 15 | #include <linux/in.h> |
|---|
| 16 | #include <linux/sunrpc/types.h> |
|---|
| 17 | #include <linux/wait.h> |
|---|
| 18 | |
|---|
| 19 | /* |
|---|
| 20 | * RPC service. |
|---|
| 21 | * |
|---|
| 22 | * An RPC service is a ``daemon,'' possibly multithreaded, which |
|---|
| 23 | * receives and processes incoming RPC messages. |
|---|
| 24 | * It has one or more transport sockets associated with it, and maintains |
|---|
| 25 | * a list of idle threads waiting for input. |
|---|
| 26 | * |
|---|
| 27 | * We currently do not support more than one RPC program per daemon. |
|---|
| 28 | */ |
|---|
| 29 | struct svc_serv { |
|---|
| 30 | struct list_head sv_threads; /* idle server threads */ |
|---|
| 31 | struct list_head sv_sockets; /* pending sockets */ |
|---|
| 32 | struct svc_program * sv_program; /* RPC program */ |
|---|
| 33 | struct svc_stat * sv_stats; /* RPC statistics */ |
|---|
| 34 | spinlock_t sv_lock; |
|---|
| 35 | unsigned int sv_nrthreads; /* # of server threads */ |
|---|
| 36 | unsigned int sv_bufsz; /* datagram buffer size */ |
|---|
| 37 | unsigned int sv_xdrsize; /* XDR buffer size */ |
|---|
| 38 | |
|---|
| 39 | struct list_head sv_permsocks; /* all permanent sockets */ |
|---|
| 40 | struct list_head sv_tempsocks; /* all temporary sockets */ |
|---|
| 41 | int sv_tmpcnt; /* count of temporary sockets */ |
|---|
| 42 | |
|---|
| 43 | char * sv_name; /* service name */ |
|---|
| 44 | }; |
|---|
| 45 | |
|---|
| 46 | /* |
|---|
| 47 | * Maximum payload size supported by a kernel RPC server. |
|---|
| 48 | * This is use to determine the max number of pages nfsd is |
|---|
| 49 | * willing to return in a single READ operation. |
|---|
| 50 | */ |
|---|
| 51 | #define RPCSVC_MAXPAYLOAD (64*1024u) |
|---|
| 52 | |
|---|
| 53 | /* |
|---|
| 54 | * RPC Requsts and replies are stored in one or more pages. |
|---|
| 55 | * We maintain an array of pages for each server thread. |
|---|
| 56 | * Requests are copied into these pages as they arrive. Remaining |
|---|
| 57 | * pages are available to write the reply into. |
|---|
| 58 | * |
|---|
| 59 | * Pages are sent using ->sendpage so each server thread needs to |
|---|
| 60 | * allocate more to replace those used in sending. To help keep track |
|---|
| 61 | * of these pages we have a receive list where all pages initialy live, |
|---|
| 62 | * and a send list where pages are moved to when there are to be part |
|---|
| 63 | * of a reply. |
|---|
| 64 | * |
|---|
| 65 | * We use xdr_buf for holding responses as it fits well with NFS |
|---|
| 66 | * read responses (that have a header, and some data pages, and possibly |
|---|
| 67 | * a tail) and means we can share some client side routines. |
|---|
| 68 | * |
|---|
| 69 | * The xdr_buf.head kvec always points to the first page in the rq_*pages |
|---|
| 70 | * list. The xdr_buf.pages pointer points to the second page on that |
|---|
| 71 | * list. xdr_buf.tail points to the end of the first page. |
|---|
| 72 | * This assumes that the non-page part of an rpc reply will fit |
|---|
| 73 | * in a page - NFSd ensures this. lockd also has no trouble. |
|---|
| 74 | * |
|---|
| 75 | * Each request/reply pair can have at most one "payload", plus two pages, |
|---|
| 76 | * one for the request, and one for the reply. |
|---|
| 77 | */ |
|---|
| 78 | #define RPCSVC_MAXPAGES ((RPCSVC_MAXPAYLOAD+PAGE_SIZE-1)/PAGE_SIZE + 2) |
|---|
| 79 | |
|---|
| 80 | static inline __u32 svc_getu32(struct kvec *iov) |
|---|
| 81 | { |
|---|
| 82 | __u32 val, *vp; |
|---|
| 83 | vp = iov->iov_base; |
|---|
| 84 | val = *vp++; |
|---|
| 85 | iov->iov_base = (void*)vp; |
|---|
| 86 | iov->iov_len -= sizeof(__u32); |
|---|
| 87 | return val; |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | static inline void svc_ungetu32(struct kvec *iov) |
|---|
| 91 | { |
|---|
| 92 | __u32 *vp = (__u32 *)iov->iov_base; |
|---|
| 93 | iov->iov_base = (void *)(vp - 1); |
|---|
| 94 | iov->iov_len += sizeof(*vp); |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | static inline void svc_putu32(struct kvec *iov, __u32 val) |
|---|
| 98 | { |
|---|
| 99 | __u32 *vp = iov->iov_base + iov->iov_len; |
|---|
| 100 | *vp = val; |
|---|
| 101 | iov->iov_len += sizeof(__u32); |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | |
|---|
| 105 | /* |
|---|
| 106 | * The context of a single thread, including the request currently being |
|---|
| 107 | * processed. |
|---|
| 108 | * NOTE: First two items must be prev/next. |
|---|
| 109 | */ |
|---|
| 110 | struct svc_rqst { |
|---|
| 111 | struct list_head rq_list; /* idle list */ |
|---|
| 112 | struct svc_sock * rq_sock; /* socket */ |
|---|
| 113 | struct sockaddr_in rq_addr; /* peer address */ |
|---|
| 114 | int rq_addrlen; |
|---|
| 115 | |
|---|
| 116 | struct svc_serv * rq_server; /* RPC service definition */ |
|---|
| 117 | struct svc_procedure * rq_procinfo; /* procedure info */ |
|---|
| 118 | struct auth_ops * rq_authop; /* authentication flavour */ |
|---|
| 119 | struct svc_cred rq_cred; /* auth info */ |
|---|
| 120 | struct sk_buff * rq_skbuff; /* fast recv inet buffer */ |
|---|
| 121 | struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */ |
|---|
| 122 | |
|---|
| 123 | struct xdr_buf rq_arg; |
|---|
| 124 | struct xdr_buf rq_res; |
|---|
| 125 | struct page * rq_argpages[RPCSVC_MAXPAGES]; |
|---|
| 126 | struct page * rq_respages[RPCSVC_MAXPAGES]; |
|---|
| 127 | int rq_restailpage; |
|---|
| 128 | short rq_argused; /* pages used for argument */ |
|---|
| 129 | short rq_arghi; /* pages available in argument page list */ |
|---|
| 130 | short rq_resused; /* pages used for result */ |
|---|
| 131 | |
|---|
| 132 | __u32 rq_xid; /* transmission id */ |
|---|
| 133 | __u32 rq_prog; /* program number */ |
|---|
| 134 | __u32 rq_vers; /* program version */ |
|---|
| 135 | __u32 rq_proc; /* procedure number */ |
|---|
| 136 | __u32 rq_prot; /* IP protocol */ |
|---|
| 137 | unsigned short |
|---|
| 138 | rq_secure : 1; /* secure port */ |
|---|
| 139 | |
|---|
| 140 | |
|---|
| 141 | __u32 rq_daddr; /* dest addr of request - reply from here */ |
|---|
| 142 | |
|---|
| 143 | void * rq_argp; /* decoded arguments */ |
|---|
| 144 | void * rq_resp; /* xdr'd results */ |
|---|
| 145 | void * rq_auth_data; /* flavor-specific data */ |
|---|
| 146 | |
|---|
| 147 | int rq_reserved; /* space on socket outq |
|---|
| 148 | * reserved for this request |
|---|
| 149 | */ |
|---|
| 150 | |
|---|
| 151 | struct cache_req rq_chandle; /* handle passed to caches for |
|---|
| 152 | * request delaying |
|---|
| 153 | */ |
|---|
| 154 | /* Catering to nfsd */ |
|---|
| 155 | struct auth_domain * rq_client; /* RPC peer info */ |
|---|
| 156 | struct svc_cacherep * rq_cacherep; /* cache info */ |
|---|
| 157 | struct knfsd_fh * rq_reffh; /* Referrence filehandle, used to |
|---|
| 158 | * determine what device number |
|---|
| 159 | * to report (real or virtual) |
|---|
| 160 | */ |
|---|
| 161 | |
|---|
| 162 | wait_queue_head_t rq_wait; /* synchronization */ |
|---|
| 163 | }; |
|---|
| 164 | |
|---|
| 165 | /* |
|---|
| 166 | * Check buffer bounds after decoding arguments |
|---|
| 167 | */ |
|---|
| 168 | static inline int |
|---|
| 169 | xdr_argsize_check(struct svc_rqst *rqstp, __u32 *p) |
|---|
| 170 | { |
|---|
| 171 | char *cp = (char *)p; |
|---|
| 172 | struct kvec *vec = &rqstp->rq_arg.head[0]; |
|---|
| 173 | return cp - (char*)vec->iov_base <= vec->iov_len; |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | static inline int |
|---|
| 177 | xdr_ressize_check(struct svc_rqst *rqstp, __u32 *p) |
|---|
| 178 | { |
|---|
| 179 | struct kvec *vec = &rqstp->rq_res.head[0]; |
|---|
| 180 | char *cp = (char*)p; |
|---|
| 181 | |
|---|
| 182 | vec->iov_len = cp - (char*)vec->iov_base; |
|---|
| 183 | |
|---|
| 184 | return vec->iov_len <= PAGE_SIZE; |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | static inline int svc_take_page(struct svc_rqst *rqstp) |
|---|
| 188 | { |
|---|
| 189 | if (rqstp->rq_arghi <= rqstp->rq_argused) |
|---|
| 190 | return -ENOMEM; |
|---|
| 191 | rqstp->rq_arghi--; |
|---|
| 192 | rqstp->rq_respages[rqstp->rq_resused] = |
|---|
| 193 | rqstp->rq_argpages[rqstp->rq_arghi]; |
|---|
| 194 | rqstp->rq_resused++; |
|---|
| 195 | return 0; |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | static inline void svc_pushback_allpages(struct svc_rqst *rqstp) |
|---|
| 199 | { |
|---|
| 200 | while (rqstp->rq_resused) { |
|---|
| 201 | if (rqstp->rq_respages[--rqstp->rq_resused] == NULL) |
|---|
| 202 | continue; |
|---|
| 203 | rqstp->rq_argpages[rqstp->rq_arghi++] = |
|---|
| 204 | rqstp->rq_respages[rqstp->rq_resused]; |
|---|
| 205 | rqstp->rq_respages[rqstp->rq_resused] = NULL; |
|---|
| 206 | } |
|---|
| 207 | } |
|---|
| 208 | |
|---|
| 209 | static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp) |
|---|
| 210 | { |
|---|
| 211 | while (rqstp->rq_resused && |
|---|
| 212 | rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) { |
|---|
| 213 | |
|---|
| 214 | if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) { |
|---|
| 215 | rqstp->rq_argpages[rqstp->rq_arghi++] = |
|---|
| 216 | rqstp->rq_respages[rqstp->rq_resused]; |
|---|
| 217 | rqstp->rq_respages[rqstp->rq_resused] = NULL; |
|---|
| 218 | } |
|---|
| 219 | } |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | static inline void svc_free_allpages(struct svc_rqst *rqstp) |
|---|
| 223 | { |
|---|
| 224 | while (rqstp->rq_resused) { |
|---|
| 225 | if (rqstp->rq_respages[--rqstp->rq_resused] == NULL) |
|---|
| 226 | continue; |
|---|
| 227 | put_page(rqstp->rq_respages[rqstp->rq_resused]); |
|---|
| 228 | rqstp->rq_respages[rqstp->rq_resused] = NULL; |
|---|
| 229 | } |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | struct svc_deferred_req { |
|---|
| 233 | __u32 prot; /* protocol (UDP or TCP) */ |
|---|
| 234 | struct sockaddr_in addr; |
|---|
| 235 | struct svc_sock *svsk; /* where reply must go */ |
|---|
| 236 | struct cache_deferred_req handle; |
|---|
| 237 | int argslen; |
|---|
| 238 | __u32 args[0]; |
|---|
| 239 | }; |
|---|
| 240 | |
|---|
| 241 | /* |
|---|
| 242 | * RPC program |
|---|
| 243 | */ |
|---|
| 244 | struct svc_program { |
|---|
| 245 | __u32 pg_prog; /* program number */ |
|---|
| 246 | unsigned int pg_lovers; /* lowest version */ |
|---|
| 247 | unsigned int pg_hivers; /* lowest version */ |
|---|
| 248 | unsigned int pg_nvers; /* number of versions */ |
|---|
| 249 | struct svc_version ** pg_vers; /* version array */ |
|---|
| 250 | char * pg_name; /* service name */ |
|---|
| 251 | char * pg_class; /* class name: services sharing authentication */ |
|---|
| 252 | struct svc_stat * pg_stats; /* rpc statistics */ |
|---|
| 253 | int (*pg_authenticate)(struct svc_rqst *); |
|---|
| 254 | }; |
|---|
| 255 | |
|---|
| 256 | /* |
|---|
| 257 | * RPC program version |
|---|
| 258 | */ |
|---|
| 259 | struct svc_version { |
|---|
| 260 | __u32 vs_vers; /* version number */ |
|---|
| 261 | __u32 vs_nproc; /* number of procedures */ |
|---|
| 262 | struct svc_procedure * vs_proc; /* per-procedure info */ |
|---|
| 263 | __u32 vs_xdrsize; /* xdrsize needed for this version */ |
|---|
| 264 | |
|---|
| 265 | /* Override dispatch function (e.g. when caching replies). |
|---|
| 266 | * A return value of 0 means drop the request. |
|---|
| 267 | * vs_dispatch == NULL means use default dispatcher. |
|---|
| 268 | */ |
|---|
| 269 | int (*vs_dispatch)(struct svc_rqst *, __u32 *); |
|---|
| 270 | }; |
|---|
| 271 | |
|---|
| 272 | /* |
|---|
| 273 | * RPC procedure info |
|---|
| 274 | */ |
|---|
| 275 | typedef int (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp); |
|---|
| 276 | struct svc_procedure { |
|---|
| 277 | svc_procfunc pc_func; /* process the request */ |
|---|
| 278 | kxdrproc_t pc_decode; /* XDR decode args */ |
|---|
| 279 | kxdrproc_t pc_encode; /* XDR encode result */ |
|---|
| 280 | kxdrproc_t pc_release; /* XDR free result */ |
|---|
| 281 | unsigned int pc_argsize; /* argument struct size */ |
|---|
| 282 | unsigned int pc_ressize; /* result struct size */ |
|---|
| 283 | unsigned int pc_count; /* call count */ |
|---|
| 284 | unsigned int pc_cachetype; /* cache info (NFS) */ |
|---|
| 285 | unsigned int pc_xdrressize; /* maximum size of XDR reply */ |
|---|
| 286 | }; |
|---|
| 287 | |
|---|
| 288 | /* |
|---|
| 289 | * This is the RPC server thread function prototype |
|---|
| 290 | */ |
|---|
| 291 | typedef void (*svc_thread_fn)(struct svc_rqst *); |
|---|
| 292 | |
|---|
| 293 | /* |
|---|
| 294 | * Function prototypes. |
|---|
| 295 | */ |
|---|
| 296 | struct svc_serv * svc_create(struct svc_program *, unsigned int); |
|---|
| 297 | int svc_create_thread(svc_thread_fn, struct svc_serv *); |
|---|
| 298 | void svc_exit_thread(struct svc_rqst *); |
|---|
| 299 | void svc_destroy(struct svc_serv *); |
|---|
| 300 | int svc_process(struct svc_serv *, struct svc_rqst *); |
|---|
| 301 | int svc_register(struct svc_serv *, int, unsigned short); |
|---|
| 302 | void svc_wake_up(struct svc_serv *); |
|---|
| 303 | void svc_reserve(struct svc_rqst *rqstp, int space); |
|---|
| 304 | |
|---|
| 305 | #endif /* SUNRPC_SVC_H */ |
|---|