[PATCH] PATCH 9/16: NFSD: RPC init tidyup
[opensuse:kernel.git] / net / sunrpc / svc.c
1 /*
2  * linux/net/sunrpc/svc.c
3  *
4  * High-level RPC service routines
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #define __KERNEL_SYSCALLS__
10 #include <linux/linkage.h>
11 #include <linux/sched.h>
12 #include <linux/errno.h>
13 #include <linux/net.h>
14 #include <linux/in.h>
15 #include <linux/unistd.h>
16
17 #include <linux/sunrpc/types.h>
18 #include <linux/sunrpc/xdr.h>
19 #include <linux/sunrpc/stats.h>
20 #include <linux/sunrpc/svcsock.h>
21 #include <linux/sunrpc/clnt.h>
22
23 #define RPCDBG_FACILITY RPCDBG_SVCDSP
24 #define RPC_PARANOIA 1
25
26 /*
27  * Create an RPC service
28  */
29 struct svc_serv *
30 svc_create(struct svc_program *prog, unsigned int bufsize, unsigned int xdrsize)
31 {
32         struct svc_serv *serv;
33
34         if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL)))
35                 return NULL;
36
37         memset(serv, 0, sizeof(*serv));
38         serv->sv_program   = prog;
39         serv->sv_nrthreads = 1;
40         serv->sv_stats     = prog->pg_stats;
41         serv->sv_bufsz     = bufsize? bufsize : 4096;
42         serv->sv_xdrsize   = xdrsize;
43         INIT_LIST_HEAD(&serv->sv_threads);
44         INIT_LIST_HEAD(&serv->sv_sockets);
45         INIT_LIST_HEAD(&serv->sv_allsocks);
46         spin_lock_init(&serv->sv_lock);
47
48         serv->sv_name      = prog->pg_name;
49
50         /* Remove any stale portmap registrations */
51         svc_register(serv, 0, 0);
52
53         return serv;
54 }
55
56 /*
57  * Destroy an RPC service
58  */
59 void
60 svc_destroy(struct svc_serv *serv)
61 {
62         struct svc_sock *svsk;
63
64         dprintk("RPC: svc_destroy(%s, %d)\n",
65                                 serv->sv_program->pg_name,
66                                 serv->sv_nrthreads);
67
68         if (serv->sv_nrthreads) {
69                 if (--(serv->sv_nrthreads) != 0)
70                         return;
71         } else
72                 printk("svc_destroy: no threads for serv=%p!\n", serv);
73
74         while (!list_empty(&serv->sv_allsocks)) {
75                 svsk = list_entry(serv->sv_allsocks.next,
76                                   struct svc_sock,
77                                   sk_list);
78                 svc_delete_socket(svsk);
79         }
80
81         /* Unregister service with the portmapper */
82         svc_register(serv, 0, 0);
83         kfree(serv);
84 }
85
86 /*
87  * Allocate an RPC server buffer
88  * Later versions may do nifty things by allocating multiple pages
89  * of memory directly and putting them into the bufp->iov.
90  */
91 int
92 svc_init_buffer(struct svc_buf *bufp, unsigned int size)
93 {
94         if (!(bufp->area = (u32 *) kmalloc(size, GFP_KERNEL)))
95                 return 0;
96         bufp->base   = bufp->area;
97         bufp->buf    = bufp->area;
98         bufp->len    = 0;
99         bufp->buflen = size >> 2;
100
101         bufp->iov[0].iov_base = bufp->area;
102         bufp->iov[0].iov_len  = size;
103         bufp->nriov = 1;
104
105         return 1;
106 }
107
108 /*
109  * Release an RPC server buffer
110  */
111 void
112 svc_release_buffer(struct svc_buf *bufp)
113 {
114         kfree(bufp->area);
115         bufp->area = 0;
116 }
117
118 /*
119  * Create a server thread
120  */
121 int
122 svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
123 {
124         struct svc_rqst *rqstp;
125         int             error = -ENOMEM;
126
127         rqstp = kmalloc(sizeof(*rqstp), GFP_KERNEL);
128         if (!rqstp)
129                 goto out;
130
131         memset(rqstp, 0, sizeof(*rqstp));
132         init_waitqueue_head(&rqstp->rq_wait);
133
134         if (!(rqstp->rq_argp = (u32 *) kmalloc(serv->sv_xdrsize, GFP_KERNEL))
135          || !(rqstp->rq_resp = (u32 *) kmalloc(serv->sv_xdrsize, GFP_KERNEL))
136          || !svc_init_buffer(&rqstp->rq_defbuf, serv->sv_bufsz))
137                 goto out_thread;
138
139         serv->sv_nrthreads++;
140         rqstp->rq_server = serv;
141         error = kernel_thread((int (*)(void *)) func, rqstp, 0);
142         if (error < 0)
143                 goto out_thread;
144         error = 0;
145 out:
146         return error;
147
148 out_thread:
149         svc_exit_thread(rqstp);
150         goto out;
151 }
152
153 /*
154  * Destroy an RPC server thread
155  */
156 void
157 svc_exit_thread(struct svc_rqst *rqstp)
158 {
159         struct svc_serv *serv = rqstp->rq_server;
160
161         svc_release_buffer(&rqstp->rq_defbuf);
162         if (rqstp->rq_resp)
163                 kfree(rqstp->rq_resp);
164         if (rqstp->rq_argp)
165                 kfree(rqstp->rq_argp);
166         kfree(rqstp);
167
168         /* Release the server */
169         if (serv)
170                 svc_destroy(serv);
171 }
172
173 /*
174  * Register an RPC service with the local portmapper.
175  * To unregister a service, call this routine with 
176  * proto and port == 0.
177  */
178 int
179 svc_register(struct svc_serv *serv, int proto, unsigned short port)
180 {
181         struct svc_program      *progp;
182         unsigned long           flags;
183         int                     i, error = 0, dummy;
184
185         progp = serv->sv_program;
186
187         dprintk("RPC: svc_register(%s, %s, %d)\n",
188                 progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);
189
190         if (!port)
191                 clear_thread_flag(TIF_SIGPENDING);
192
193         for (i = 0; i < progp->pg_nvers; i++) {
194                 if (progp->pg_vers[i] == NULL)
195                         continue;
196                 error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
197                 if (error < 0)
198                         break;
199                 if (port && !dummy) {
200                         error = -EACCES;
201                         break;
202                 }
203         }
204
205         if (!port) {
206                 spin_lock_irqsave(&current->sigmask_lock, flags);
207                 recalc_sigpending();
208                 spin_unlock_irqrestore(&current->sigmask_lock, flags);
209         }
210
211         return error;
212 }
213
214 /*
215  * Process the RPC request.
216  */
217 int
218 svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
219 {
220         struct svc_program      *progp;
221         struct svc_version      *versp = NULL;  /* compiler food */
222         struct svc_procedure    *procp = NULL;
223         struct svc_buf *        argp = &rqstp->rq_argbuf;
224         struct svc_buf *        resp = &rqstp->rq_resbuf;
225         kxdrproc_t              xdr;
226         u32                     *bufp, *statp;
227         u32                     dir, prog, vers, proc,
228                                 auth_stat, rpc_stat;
229
230         rpc_stat = rpc_success;
231         bufp = argp->buf;
232
233         if (argp->len < 5)
234                 goto err_short_len;
235
236         dir  = ntohl(*bufp++);
237         vers = ntohl(*bufp++);
238
239         /* First words of reply: */
240         svc_putlong(resp, xdr_one);             /* REPLY */
241         svc_putlong(resp, xdr_zero);            /* ACCEPT */
242
243         if (dir != 0)           /* direction != CALL */
244                 goto err_bad_dir;
245         if (vers != 2)          /* RPC version number */
246                 goto err_bad_rpc;
247
248         rqstp->rq_prog = prog = ntohl(*bufp++); /* program number */
249         rqstp->rq_vers = vers = ntohl(*bufp++); /* version number */
250         rqstp->rq_proc = proc = ntohl(*bufp++); /* procedure number */
251
252         argp->buf += 5;
253         argp->len -= 5;
254
255         /* Used by nfsd to only allow the NULL procedure for amd. */
256         if (rqstp->rq_auth && !rqstp->rq_client && proc) {
257                 auth_stat = rpc_autherr_badcred;
258                 goto err_bad_auth;
259         }
260
261         /*
262          * Decode auth data, and add verifier to reply buffer.
263          * We do this before anything else in order to get a decent
264          * auth verifier.
265          */
266         svc_authenticate(rqstp, &rpc_stat, &auth_stat);
267
268         if (rpc_stat != rpc_success)
269                 goto err_garbage;
270
271         if (auth_stat != rpc_auth_ok)
272                 goto err_bad_auth;
273
274         progp = serv->sv_program;
275         if (prog != progp->pg_prog)
276                 goto err_bad_prog;
277
278         if (vers >= progp->pg_nvers ||
279           !(versp = progp->pg_vers[vers]))
280                 goto err_bad_vers;
281
282         procp = versp->vs_proc + proc;
283         if (proc >= versp->vs_nproc || !procp->pc_func)
284                 goto err_bad_proc;
285         rqstp->rq_server   = serv;
286         rqstp->rq_procinfo = procp;
287
288         /* Syntactic check complete */
289         serv->sv_stats->rpccnt++;
290
291         /* Build the reply header. */
292         statp = resp->buf;
293         svc_putlong(resp, rpc_success);         /* RPC_SUCCESS */
294
295         /* Bump per-procedure stats counter */
296         procp->pc_count++;
297
298         /* Initialize storage for argp and resp */
299         memset(rqstp->rq_argp, 0, procp->pc_argsize);
300         memset(rqstp->rq_resp, 0, procp->pc_ressize);
301
302         /* Call the function that processes the request. */
303         if (!versp->vs_dispatch) {
304                 /* Decode arguments */
305                 xdr = procp->pc_decode;
306                 if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp))
307                         goto err_garbage;
308
309                 *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
310
311                 /* Encode reply */
312                 if (*statp == rpc_success && (xdr = procp->pc_encode)
313                  && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
314                         dprintk("svc: failed to encode reply\n");
315                         /* serv->sv_stats->rpcsystemerr++; */
316                         *statp = rpc_system_err;
317                 }
318         } else {
319                 dprintk("svc: calling dispatcher\n");
320                 if (!versp->vs_dispatch(rqstp, statp))
321                         goto dropit;
322         }
323
324         /* Check RPC status result */
325         if (*statp != rpc_success)
326                 resp->len = statp + 1 - resp->base;
327
328         /* Release reply info */
329         if (procp->pc_release)
330                 procp->pc_release(rqstp, NULL, rqstp->rq_resp);
331
332         if (procp->pc_encode == NULL)
333                 goto dropit;
334 sendit:
335         return svc_send(rqstp);
336
337 dropit:
338         dprintk("svc: svc_process dropit\n");
339         svc_drop(rqstp);
340         return 0;
341
342 err_short_len:
343 #ifdef RPC_PARANOIA
344         printk("svc: short len %d, dropping request\n", argp->len);
345 #endif
346         goto dropit;                    /* drop request */
347
348 err_bad_dir:
349 #ifdef RPC_PARANOIA
350         printk("svc: bad direction %d, dropping request\n", dir);
351 #endif
352         serv->sv_stats->rpcbadfmt++;
353         goto dropit;                    /* drop request */
354
355 err_bad_rpc:
356         serv->sv_stats->rpcbadfmt++;
357         resp->buf[-1] = xdr_one;        /* REJECT */
358         svc_putlong(resp, xdr_zero);    /* RPC_MISMATCH */
359         svc_putlong(resp, xdr_two);     /* Only RPCv2 supported */
360         svc_putlong(resp, xdr_two);
361         goto sendit;
362
363 err_bad_auth:
364         dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
365         serv->sv_stats->rpcbadauth++;
366         resp->buf[-1] = xdr_one;        /* REJECT */
367         svc_putlong(resp, xdr_one);     /* AUTH_ERROR */
368         svc_putlong(resp, auth_stat);   /* status */
369         goto sendit;
370
371 err_bad_prog:
372 #ifdef RPC_PARANOIA
373         if (prog != 100227 || progp->pg_prog != 100003)
374                 printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog);
375         /* else it is just a Solaris client seeing if ACLs are supported */
376 #endif
377         serv->sv_stats->rpcbadfmt++;
378         svc_putlong(resp, rpc_prog_unavail);
379         goto sendit;
380
381 err_bad_vers:
382 #ifdef RPC_PARANOIA
383         printk("svc: unknown version (%d)\n", vers);
384 #endif
385         serv->sv_stats->rpcbadfmt++;
386         svc_putlong(resp, rpc_prog_mismatch);
387         svc_putlong(resp, htonl(progp->pg_lovers));
388         svc_putlong(resp, htonl(progp->pg_hivers));
389         goto sendit;
390
391 err_bad_proc:
392 #ifdef RPC_PARANOIA
393         printk("svc: unknown procedure (%d)\n", proc);
394 #endif
395         serv->sv_stats->rpcbadfmt++;
396         svc_putlong(resp, rpc_proc_unavail);
397         goto sendit;
398
399 err_garbage:
400 #ifdef RPC_PARANOIA
401         printk("svc: failed to decode args\n");
402 #endif
403         serv->sv_stats->rpcbadfmt++;
404         svc_putlong(resp, rpc_garbage_args);
405         goto sendit;
406 }