import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / fs / nfsd / nfssvc.c
1 /*
2  * linux/fs/nfsd/nfssvc.c
3  *
4  * Central processing for nfsd.
5  *
6  * Authors:     Olaf Kirch (okir@monad.swb.de)
7  *
8  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
9  */
10
11 #define __NO_VERSION__
12 #include <linux/config.h>
13 #include <linux/module.h>
14
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/slab.h>
23 #include <linux/smp.h>
24 #include <linux/smp_lock.h>
25
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>
35
36 #define NFSDDBG_FACILITY        NFSDDBG_SVC
37 #define NFSD_BUFSIZE            (1024 + NFSSVC_MAXBLKSIZE)
38
39 /* these signals will be delivered to an nfsd thread 
40  * when handling a request
41  */
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
45  */
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).
50  */
51 #define SIG_NOCLEAN     SIGHUP
52
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;
57 static int                      nfsd_busy;
58 static unsigned long            nfsd_last_call;
59
60 struct nfsd_list {
61         struct list_head        list;
62         struct task_struct      *task;
63 };
64 struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list);
65
66 /*
67  * Maximum number of nfsd processes
68  */
69 #define NFSD_MAXSERVS           8192
70
71 int
72 nfsd_svc(unsigned short port, int nrservs)
73 {
74         int     error;
75         int     none_left;      
76         struct list_head *victim;
77
78         dprintk("nfsd: creating service\n");
79         error = -EINVAL;
80         if (nrservs <= 0)
81                 nrservs = 0;
82         if (nrservs > NFSD_MAXSERVS)
83                 nrservs = NFSD_MAXSERVS;
84         
85         /* Readahead param cache - will no-op if it already exists */
86         error = nfsd_racache_init(2*nrservs);
87         if (error<0)
88                 goto out;
89         if (!nfsd_serv) {
90                 error = -ENOMEM;
91                 nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
92                 if (nfsd_serv == NULL)
93                         goto out;
94                 error = svc_makesock(nfsd_serv, IPPROTO_UDP, port);
95                 if (error < 0)
96                         goto failure;
97
98 #if CONFIG_NFSD_TCP
99                 error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
100                 if (error < 0)
101                         goto failure;
102 #endif
103                 do_gettimeofday(&nfssvc_boot);          /* record boot time */
104         } else
105                 nfsd_serv->sv_nrthreads++;
106         nrservs -= (nfsd_serv->sv_nrthreads-1);
107         while (nrservs > 0) {
108                 nrservs--;
109                 error = svc_create_thread(nfsd, nfsd_serv);
110                 if (error < 0)
111                         break;
112         }
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);
119                 nrservs++;
120         }
121  failure:
122         none_left = (nfsd_serv->sv_nrthreads == 1);
123         svc_destroy(nfsd_serv);         /* Release server */
124         if (none_left) {
125                 nfsd_serv = NULL;
126                 nfsd_racache_shutdown();
127         }
128  out:
129         return error;
130 }
131
132 static inline void
133 update_thread_usage(int busy_threads)
134 {
135         unsigned long prev_call;
136         unsigned long diff;
137         int decile;
138
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;
146                 if (decile == 10)
147                         nfsdstats.th_fullcnt++;
148         }
149 }
150
151 /*
152  * This is the NFS server kernel thread
153  */
154 static void
155 nfsd(struct svc_rqst *rqstp)
156 {
157         struct svc_serv *serv = rqstp->rq_server;
158         int             err;
159         struct nfsd_list me;
160
161         /* Lock module and set up kernel thread */
162         MOD_INC_USE_COUNT;
163         lock_kernel();
164         daemonize();
165         sprintf(current->comm, "nfsd");
166         current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
167
168         nfsdstats.th_cnt++;
169         /* Let svc_process check client's authentication. */
170         rqstp->rq_auth = 1;
171
172         lockd_up();                             /* start lockd */
173
174         me.task = current;
175         list_add(&me.list, &nfsd_list);
176
177         /*
178          * The main request loop
179          */
180         for (;;) {
181                 /* Block all but the shutdown signals */
182                 spin_lock_irq(&current->sigmask_lock);
183                 siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
184                 recalc_sigpending(current);
185                 spin_unlock_irq(&current->sigmask_lock);
186
187                 /*
188                  * Find a socket with data available and call its
189                  * recvfrom routine.
190                  */
191                 while ((err = svc_recv(serv, rqstp,
192                                        5*60*HZ)) == -EAGAIN)
193                     ;
194                 if (err < 0)
195                         break;
196                 update_thread_usage(nfsd_busy);
197                 nfsd_busy++;
198
199                 /* Lock the export hash tables for reading. */
200                 exp_readlock();
201
202                 /* Validate the client's address. This will also defeat
203                  * port probes on port 2049 by unauthorized clients.
204                  */
205                 rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
206                 /* Process request with signals blocked.  */
207                 spin_lock_irq(&current->sigmask_lock);
208                 siginitsetinv(&current->blocked, ALLOWED_SIGS);
209                 recalc_sigpending(current);
210                 spin_unlock_irq(&current->sigmask_lock);
211
212                 svc_process(serv, rqstp);
213
214                 /* Unlock export hash tables */
215                 exp_unlock();
216                 update_thread_usage(nfsd_busy);
217                 nfsd_busy--;
218         }
219
220         if (err != -EINTR) {
221                 printk(KERN_WARNING "nfsd: terminating on error %d\n", -err);
222         } else {
223                 unsigned int    signo;
224
225                 for (signo = 1; signo <= _NSIG; signo++)
226                         if (sigismember(&current->pending.signal, signo) &&
227                             !sigismember(&current->blocked, signo))
228                                 break;
229                 err = signo;
230         }
231
232         /* Release lockd */
233         lockd_down();
234
235         /* Check if this is last thread */
236         if (serv->sv_nrthreads==1) {
237                 
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();
242                 }
243                 nfsd_serv = NULL;
244                 nfsd_racache_shutdown();        /* release read-ahead cache */
245         }
246         list_del(&me.list);
247         nfsdstats.th_cnt --;
248
249         /* Release the thread */
250         svc_exit_thread(rqstp);
251
252         /* Release module */
253         MOD_DEC_USE_COUNT;
254 }
255
256 static int
257 nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
258 {
259         struct svc_procedure    *proc;
260         kxdrproc_t              xdr;
261         u32                     nfserr;
262
263         dprintk("nfsd_dispatch: vers %d proc %d\n",
264                                 rqstp->rq_vers, rqstp->rq_proc);
265         proc = rqstp->rq_procinfo;
266
267         /* Check whether we have this call in the cache. */
268         switch (nfsd_cache_lookup(rqstp, proc->pc_cachetype)) {
269         case RC_INTR:
270         case RC_DROPIT:
271                 return 0;
272         case RC_REPLY:
273                 return 1;
274         case RC_DOIT:;
275                 /* do it */
276         }
277
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;
284                 return 1;
285         }
286
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);
292                 return 0;
293         }
294                 
295         if (rqstp->rq_proc != 0)
296                 svc_putlong(&rqstp->rq_resbuf, nfserr);
297
298         /* Encode result.
299          * For NFSv2, additional info is never returned in case of an error.
300          */
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;
308                         return 1;
309                 }
310         }
311
312         /* Store reply in cache. */
313         nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
314         return 1;
315 }
316
317 static struct svc_version       nfsd_version2 = {
318         2, 18, nfsd_procedures2, nfsd_dispatch
319 };
320 #ifdef CONFIG_NFSD_V3
321 static struct svc_version       nfsd_version3 = {
322         3, 22, nfsd_procedures3, nfsd_dispatch
323 };
324 #endif
325 static struct svc_version *     nfsd_version[] = {
326         NULL,
327         NULL,
328         &nfsd_version2,
329 #ifdef CONFIG_NFSD_V3
330         &nfsd_version3,
331 #endif
332 };
333
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 */
342 };