~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/nfsd/nfssvc.c

Version: ~ [ linux-5.15-rc6 ] ~ [ linux-5.14.14 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.75 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.155 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.213 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.252 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.287 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.289 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 };
343 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp