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>
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>
19 #include <linux/uio.h>
20 #include <linux/version.h>
21 #include <linux/unistd.h>
22 #include <linux/slab.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 /* these signals will be delivered to an nfsd thread
40 * when handling a request
42 #define ALLOWED_SIGS (sigmask(SIGKILL))
43 /* these signals will be delivered to an nfsd thread
44 * when not handling a request. i.e. when waiting
46 #define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT))
47 /* if the last thread dies with SIGHUP, then the exports table is
48 * left unchanged ( like 2.4-{0-9} ). Any other signal will clear
49 * the exports table (like 2.2).
51 #define SIG_NOCLEAN SIGHUP
53 extern struct svc_program nfsd_program;
54 static void nfsd(struct svc_rqst *rqstp);
55 struct timeval nfssvc_boot;
56 static struct svc_serv *nfsd_serv;
58 static unsigned long nfsd_last_call;
61 struct list_head list;
62 struct task_struct *task;
64 struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list);
67 * Maximum number of nfsd processes
69 #define NFSD_MAXSERVS 8192
72 nfsd_svc(unsigned short port, int nrservs)
76 struct list_head *victim;
78 dprintk("nfsd: creating service\n");
82 if (nrservs > NFSD_MAXSERVS)
83 nrservs = NFSD_MAXSERVS;
85 /* Readahead param cache - will no-op if it already exists */
86 error = nfsd_racache_init(2*nrservs);
91 nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
92 if (nfsd_serv == NULL)
94 error = svc_makesock(nfsd_serv, IPPROTO_UDP, port);
99 error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
103 do_gettimeofday(&nfssvc_boot); /* record boot time */
105 nfsd_serv->sv_nrthreads++;
106 nrservs -= (nfsd_serv->sv_nrthreads-1);
107 while (nrservs > 0) {
109 error = svc_create_thread(nfsd, nfsd_serv);
113 victim = nfsd_list.next;
114 while (nrservs < 0 && victim != &nfsd_list) {
115 struct nfsd_list *nl =
116 list_entry(victim,struct nfsd_list, list);
117 victim = victim->next;
118 send_sig(SIG_NOCLEAN, nl->task, 1);
122 none_left = (nfsd_serv->sv_nrthreads == 1);
123 svc_destroy(nfsd_serv); /* Release server */
126 nfsd_racache_shutdown();
133 update_thread_usage(int busy_threads)
135 unsigned long prev_call;
139 prev_call = nfsd_last_call;
140 nfsd_last_call = jiffies;
141 decile = busy_threads*10/nfsdstats.th_cnt;
142 if (decile>0 && decile <= 10) {
143 diff = nfsd_last_call - prev_call;
144 if ( (nfsdstats.th_usage[decile-1] += diff) >= NFSD_USAGE_WRAP)
145 nfsdstats.th_usage[decile-1] -= NFSD_USAGE_WRAP;
147 nfsdstats.th_fullcnt++;
152 * This is the NFS server kernel thread
155 nfsd(struct svc_rqst *rqstp)
157 struct svc_serv *serv = rqstp->rq_server;
161 /* Lock module and set up kernel thread */
165 sprintf(current->comm, "nfsd");
166 current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
169 /* Let svc_process check client's authentication. */
172 lockd_up(); /* start lockd */
175 list_add(&me.list, &nfsd_list);
178 * The main request loop
181 /* Block all but the shutdown signals */
182 spin_lock_irq(¤t->sigmask_lock);
183 siginitsetinv(¤t->blocked, SHUTDOWN_SIGS);
184 recalc_sigpending(current);
185 spin_unlock_irq(¤t->sigmask_lock);
188 * Find a socket with data available and call its
191 while ((err = svc_recv(serv, rqstp,
192 5*60*HZ)) == -EAGAIN)
196 update_thread_usage(nfsd_busy);
199 /* Lock the export hash tables for reading. */
202 /* Validate the client's address. This will also defeat
203 * port probes on port 2049 by unauthorized clients.
205 rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
206 /* Process request with signals blocked. */
207 spin_lock_irq(¤t->sigmask_lock);
208 siginitsetinv(¤t->blocked, ALLOWED_SIGS);
209 recalc_sigpending(current);
210 spin_unlock_irq(¤t->sigmask_lock);
212 svc_process(serv, rqstp);
214 /* Unlock export hash tables */
216 update_thread_usage(nfsd_busy);
221 printk(KERN_WARNING "nfsd: terminating on error %d\n", -err);
225 for (signo = 1; signo <= _NSIG; signo++)
226 if (sigismember(¤t->pending.signal, signo) &&
227 !sigismember(¤t->blocked, signo))
235 /* Check if this is last thread */
236 if (serv->sv_nrthreads==1) {
238 printk(KERN_WARNING "nfsd: last server has exited\n");
239 if (err != SIG_NOCLEAN) {
240 printk(KERN_WARNING "nfsd: unexporting all filesystems\n");
241 nfsd_export_shutdown();
244 nfsd_racache_shutdown(); /* release read-ahead cache */
249 /* Release the thread */
250 svc_exit_thread(rqstp);
257 nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
259 struct svc_procedure *proc;
263 dprintk("nfsd_dispatch: vers %d proc %d\n",
264 rqstp->rq_vers, rqstp->rq_proc);
265 proc = rqstp->rq_procinfo;
267 /* Check whether we have this call in the cache. */
268 switch (nfsd_cache_lookup(rqstp, proc->pc_cachetype)) {
278 /* Decode arguments */
279 xdr = proc->pc_decode;
280 if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp)) {
281 dprintk("nfsd: failed to decode arguments!\n");
282 nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
283 *statp = rpc_garbage_args;
287 /* Now call the procedure handler, and encode NFS status. */
288 nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
289 if (nfserr == nfserr_dropit) {
290 dprintk("nfsd: Dropping request due to malloc failure!\n");
291 nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
295 if (rqstp->rq_proc != 0)
296 svc_putlong(&rqstp->rq_resbuf, nfserr);
299 * For NFSv2, additional info is never returned in case of an error.
301 if (!(nfserr && rqstp->rq_vers == 2)) {
302 xdr = proc->pc_encode;
303 if (xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
304 /* Failed to encode result. Release cache entry */
305 dprintk("nfsd: failed to encode result!\n");
306 nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
307 *statp = rpc_system_err;
312 /* Store reply in cache. */
313 nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
317 static struct svc_version nfsd_version2 = {
318 2, 18, nfsd_procedures2, nfsd_dispatch
320 #ifdef CONFIG_NFSD_V3
321 static struct svc_version nfsd_version3 = {
322 3, 22, nfsd_procedures3, nfsd_dispatch
325 static struct svc_version * nfsd_version[] = {
329 #ifdef CONFIG_NFSD_V3
334 #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
335 struct svc_program nfsd_program = {
336 NFS_PROGRAM, /* program number */
337 2, NFSD_NRVERS-1, /* version range */
338 NFSD_NRVERS, /* nr of entries in nfsd_version */
339 nfsd_version, /* version table */
340 "nfsd", /* program name */
341 &nfsd_svcstats, /* version table */