OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [nfsd/] [nfssvc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.