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
nfsd_svc(unsigned short port,int nrservs)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
update_thread_usage(int busy_threads)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
nfsd(struct svc_rqst * rqstp)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(¤t->sigmask_lock);
183 siginitsetinv(¤t->blocked, SHUTDOWN_SIGS);
184 recalc_sigpending(current);
185 spin_unlock_irq(¤t->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(¤t->sigmask_lock);
208 siginitsetinv(¤t->blocked, ALLOWED_SIGS);
209 recalc_sigpending(current);
210 spin_unlock_irq(¤t->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(¤t->pending.signal, signo) &&
227 !sigismember(¤t->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
nfsd_dispatch(struct svc_rqst * rqstp,u32 * statp)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 };
343