Linux-2.3.3 and a short hiatus..
[davej-history.git] / fs / nfsd / nfssvc.c
blobb7fa534e065b12bd54b748903ff9dbe5df73a4a8
1 /*
2 * linux/fs/nfsd/nfssvc.c
4 * Central processing for nfsd.
6 * Authors: Olaf Kirch (okir@monad.swb.de)
8 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
9 */
11 #define __NO_VERSION__
12 #include <linux/config.h>
13 #include <linux/module.h>
15 #include <linux/sched.h>
16 #include <linux/errno.h>
17 #include <linux/nfs.h>
18 #include <linux/in.h>
19 #include <linux/uio.h>
20 #include <linux/version.h>
21 #include <linux/unistd.h>
22 #include <linux/malloc.h>
23 #include <linux/smp.h>
24 #include <linux/smp_lock.h>
26 #include <linux/sunrpc/types.h>
27 #include <linux/sunrpc/stats.h>
28 #include <linux/sunrpc/svc.h>
29 #include <linux/sunrpc/svcsock.h>
30 #include <linux/nfsd/nfsd.h>
31 #include <linux/nfsd/stats.h>
32 #include <linux/nfsd/cache.h>
33 #include <linux/nfsd/xdr.h>
34 #include <linux/lockd/bind.h>
36 #define NFSDDBG_FACILITY NFSDDBG_SVC
37 #define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE)
39 #define ALLOWED_SIGS (sigmask(SIGKILL))
40 #define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT))
42 extern struct svc_program nfsd_program;
43 static void nfsd(struct svc_rqst *rqstp);
44 struct timeval nfssvc_boot = { 0, 0 };
45 static int nfsd_active = 0;
48 * Maximum number of nfsd processes
50 #define NFSD_MAXSERVS 128
52 int
53 nfsd_svc(unsigned short port, int nrservs)
55 struct svc_serv * serv;
56 int error;
58 dprintk("nfsd: creating service\n");
59 error = -EINVAL;
60 if (nrservs <= 0)
61 goto out;
62 if (nrservs > NFSD_MAXSERVS)
63 nrservs = NFSD_MAXSERVS;
64 nfsd_nservers = nrservs;
66 error = -ENOMEM;
67 nfsd_racache_init(); /* Readahead param cache */
68 if (nfsd_nservers == 0)
69 goto out;
71 serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
72 if (serv == NULL)
73 goto out;
75 error = svc_makesock(serv, IPPROTO_UDP, port);
76 if (error < 0)
77 goto failure;
79 #if 0 /* Don't even pretend that TCP works. It doesn't. */
80 error = svc_makesock(serv, IPPROTO_TCP, port);
81 if (error < 0)
82 goto failure;
83 #endif
85 while (nrservs--) {
86 error = svc_create_thread(nfsd, serv);
87 if (error < 0)
88 break;
91 failure:
92 svc_destroy(serv); /* Release server */
93 out:
94 return error;
98 * This is the NFS server kernel thread
100 static void
101 nfsd(struct svc_rqst *rqstp)
103 struct svc_serv *serv = rqstp->rq_server;
104 int oldumask, err, first = 0;
106 /* Lock module and set up kernel thread */
107 MOD_INC_USE_COUNT;
108 lock_kernel();
109 exit_mm(current);
110 current->session = 1;
111 current->pgrp = 1;
112 /* Let svc_process check client's authentication. */
113 rqstp->rq_auth = 1;
114 sprintf(current->comm, "nfsd");
116 oldumask = current->fs->umask; /* Set umask to 0. */
117 current->fs->umask = 0;
118 if (!nfsd_active++) {
119 nfssvc_boot = xtime; /* record boot time */
120 first = 1;
122 lockd_up(); /* start lockd */
125 * The main request loop
127 for (;;) {
128 /* Block all but the shutdown signals */
129 spin_lock_irq(&current->sigmask_lock);
130 siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
131 recalc_sigpending(current);
132 spin_unlock_irq(&current->sigmask_lock);
135 * Find a socket with data available and call its
136 * recvfrom routine.
138 while ((err = svc_recv(serv, rqstp,
139 first?5*HZ:MAX_SCHEDULE_TIMEOUT)) == -EAGAIN) {
140 if (first && 1) {
141 exp_readlock();
142 expire_all();
143 exp_unlock();
146 if (err < 0)
147 break;
149 /* Lock the export hash tables for reading. */
150 exp_readlock();
152 /* Validate the client's address. This will also defeat
153 * port probes on port 2049 by unauthorized clients.
155 rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
156 /* Process request with signals blocked. */
157 spin_lock_irq(&current->sigmask_lock);
158 siginitsetinv(&current->blocked, ALLOWED_SIGS);
159 recalc_sigpending(current);
160 spin_unlock_irq(&current->sigmask_lock);
162 svc_process(serv, rqstp);
164 /* Unlock export hash tables */
165 exp_unlock();
168 if (err != -EINTR) {
169 printk(KERN_WARNING "nfsd: terminating on error %d\n", -err);
170 } else {
171 unsigned int signo;
173 for (signo = 1; signo <= _NSIG; signo++)
174 if (sigismember(&current->signal, signo) &&
175 !sigismember(&current->blocked, signo))
176 break;
177 printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo);
180 /* Release lockd */
181 lockd_down();
182 if (!--nfsd_active) {
183 printk("nfsd: last server exiting\n");
184 /* revoke all exports */
185 nfsd_export_shutdown();
186 /* release read-ahead cache */
187 nfsd_racache_shutdown();
190 /* Destroy the thread */
191 svc_exit_thread(rqstp);
192 current->fs->umask = oldumask;
194 /* Release module */
195 MOD_DEC_USE_COUNT;
198 static int
199 nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
201 struct svc_procedure *proc;
202 kxdrproc_t xdr;
203 u32 nfserr;
205 dprintk("nfsd_dispatch: proc %d\n", rqstp->rq_proc);
206 proc = rqstp->rq_procinfo;
208 /* Check whether we have this call in the cache. */
209 switch (nfsd_cache_lookup(rqstp, proc->pc_cachetype)) {
210 case RC_INTR:
211 case RC_DROPIT:
212 return 0;
213 case RC_REPLY:
214 return 1;
215 case RC_DOIT:
216 /* do it */
219 /* Decode arguments */
220 xdr = proc->pc_decode;
221 if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp)) {
222 dprintk("nfsd: failed to decode arguments!\n");
223 nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
224 *statp = rpc_garbage_args;
225 return 1;
228 /* Now call the procedure handler, and encode NFS status. */
229 nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
230 if (rqstp->rq_proc != 0)
231 svc_putlong(&rqstp->rq_resbuf, nfserr);
233 /* Encode result.
234 * FIXME: Most NFSv3 calls return wcc data even when the call failed
236 xdr = proc->pc_encode;
237 if (!nfserr && xdr
238 && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
239 /* Failed to encode result. Release cache entry */
240 dprintk("nfsd: failed to encode result!\n");
241 nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
242 *statp = rpc_system_err;
243 return 1;
246 /* Store reply in cache. */
247 nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
248 return 1;
251 static struct svc_version nfsd_version2 = {
252 2, 18, nfsd_procedures2, nfsd_dispatch
254 #ifdef CONFIG_NFSD_NFS3
255 static struct svc_version nfsd_version3 = {
256 3, 23, nfsd_procedures3, nfsd_dispatch
258 #endif
259 static struct svc_version * nfsd_version[] = {
260 NULL,
261 NULL,
262 &nfsd_version2,
263 #ifdef CONFIG_NFSD_NFS3
264 &nfsd_version3,
265 #endif
268 #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
269 struct svc_program nfsd_program = {
270 NFS_PROGRAM, /* program number */
271 2, NFSD_NRVERS-1, /* version range */
272 NFSD_NRVERS, /* nr of entries in nfsd_version */
273 nfsd_version, /* version table */
274 "nfsd", /* program name */
275 &nfsd_svcstats, /* version table */