Import 2.1.81
[davej-history.git] / fs / nfsd / nfssvc.c
blobcba32eea781c186ef9208c5705351b4448bee5e5
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) | sigmask(SIGSTOP))
40 #define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGTERM))
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;
47 int
48 nfsd_svc(unsigned short port, int nrservs)
50 struct svc_serv * serv;
51 int error;
53 dprintk("nfsd: creating service\n");
54 error = -EINVAL;
55 if (nrservs < 0)
56 goto out;
57 if (nrservs > NFSD_MAXSERVS)
58 nrservs = NFSD_MAXSERVS;
60 error = -ENOMEM;
61 serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
62 if (serv == NULL)
63 goto out;
65 if ((error = svc_makesock(serv, IPPROTO_UDP, port)) < 0
66 || (error = svc_makesock(serv, IPPROTO_TCP, port)) < 0)
67 goto failure;
69 while (nrservs--) {
70 error = svc_create_thread(nfsd, serv);
71 if (error < 0)
72 break;
75 failure:
76 svc_destroy(serv); /* Release server */
77 out:
78 return error;
82 * This is the NFS server kernel thread
84 static void
85 nfsd(struct svc_rqst *rqstp)
87 struct svc_serv *serv = rqstp->rq_server;
88 int oldumask, err;
90 /* Lock module and set up kernel thread */
91 MOD_INC_USE_COUNT;
92 lock_kernel();
93 exit_mm(current);
94 current->session = 1;
95 current->pgrp = 1;
96 sprintf(current->comm, "nfsd");
98 oldumask = current->fs->umask; /* Set umask to 0. */
99 current->fs->umask = 0;
100 nfssvc_boot = xtime; /* record boot time */
101 nfsd_active++;
102 lockd_up(); /* start lockd */
105 * The main request loop
107 for (;;) {
108 /* Block all but the shutdown signals */
109 spin_lock_irq(&current->sigmask_lock);
110 siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
111 recalc_sigpending(current);
112 spin_unlock_irq(&current->sigmask_lock);
115 * Find a socket with data available and call its
116 * recvfrom routine.
118 while ((err = svc_recv(serv, rqstp)) == -EAGAIN)
120 if (err < 0)
121 break;
123 /* Lock the export hash tables for reading. */
124 exp_readlock();
126 /* Validate the client's address. This will also defeat
127 * port probes on port 2049 by unauthorized clients.
129 rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
130 if (!rqstp->rq_client) {
131 printk(KERN_WARNING "nfsd: unauthenticated request "
132 "from (%08lx:%d)\n",
133 ntohl(rqstp->rq_addr.sin_addr.s_addr),
134 ntohs(rqstp->rq_addr.sin_port));
135 svc_drop(rqstp);
136 serv->sv_stats->rpcbadclnt++;
137 } else {
138 /* Process request with signals blocked. */
139 spin_lock_irq(&current->sigmask_lock);
140 siginitsetinv(&current->blocked, ALLOWED_SIGS);
141 recalc_sigpending(current);
142 spin_unlock_irq(&current->sigmask_lock);
144 svc_process(serv, rqstp);
147 /* Unlock export hash tables */
148 exp_unlock();
151 if (err != -EINTR) {
152 printk(KERN_WARNING "nfsd: terminating on error %d\n", -err);
153 } else {
154 unsigned int signo;
156 for (signo = 1; signo <= _NSIG; signo++)
157 if (sigismember(&current->signal, signo) &&
158 !sigismember(&current->blocked, signo))
159 break;
160 printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo);
163 /* Release lockd */
164 lockd_down();
165 if (!--nfsd_active) {
166 printk("nfsd: last server exiting\n");
167 /* revoke all exports */
168 nfsd_export_shutdown();
171 /* Destroy the thread */
172 svc_exit_thread(rqstp);
173 current->fs->umask = oldumask;
175 /* Release module */
176 MOD_DEC_USE_COUNT;
179 static int
180 nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
182 struct svc_procedure *proc;
183 kxdrproc_t xdr;
184 u32 nfserr;
186 dprintk("nfsd_dispatch: proc %d\n", rqstp->rq_proc);
187 proc = rqstp->rq_procinfo;
189 /* Check whether we have this call in the cache. */
190 switch (nfsd_cache_lookup(rqstp, proc->pc_cachetype)) {
191 case RC_INTR:
192 case RC_DROPIT:
193 return 0;
194 case RC_REPLY:
195 return 1;
196 case RC_DOIT:
197 /* do it */
200 /* Decode arguments */
201 xdr = proc->pc_decode;
202 if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp)) {
203 dprintk("nfsd: failed to decode arguments!\n");
204 nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
205 *statp = rpc_garbage_args;
206 return 1;
209 /* Now call the procedure handler, and encode NFS status. */
210 nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
211 if (rqstp->rq_proc != 0)
212 svc_putlong(&rqstp->rq_resbuf, nfserr);
214 /* Encode result.
215 * FIXME: Most NFSv3 calls return wcc data even when the call failed
217 xdr = proc->pc_encode;
218 if (!nfserr && xdr
219 && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
220 /* Failed to encode result. Release cache entry */
221 dprintk("nfsd: failed to encode result!\n");
222 nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
223 *statp = rpc_system_err;
224 return 1;
227 /* Store reply in cache. */
228 nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
229 return 1;
232 static struct svc_version nfsd_version2 = {
233 2, 18, nfsd_procedures2, nfsd_dispatch
235 #ifdef CONFIG_NFSD_NFS3
236 static struct svc_version nfsd_version3 = {
237 3, 23, nfsd_procedures3, nfsd_dispatch
239 #endif
240 static struct svc_version * nfsd_version[] = {
241 NULL,
242 NULL,
243 &nfsd_version2,
244 #ifdef CONFIG_NFSD_NFS3
245 &nfsd_version3,
246 #endif
249 #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
250 struct svc_program nfsd_program = {
251 NFS_PROGRAM, /* program number */
252 2, NFSD_NRVERS-1, /* version range */
253 NFSD_NRVERS, /* nr of entries in nfsd_version */
254 nfsd_version, /* version table */
255 "nfsd", /* program name */
256 &nfsd_svcstats, /* version table */