Blame view

fs/nfsd/nfssvc.c 15.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
   * Central processing for nfsd.
   *
   * Authors:	Olaf Kirch (okir@monad.swb.de)
   *
   * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
   */
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
8
  #include <linux/sched.h>
831441862   Rafael J. Wysocki   Freezer: make ker...
9
  #include <linux/freezer.h>
143cb494c   Paul Gortmaker   fs: add module.h ...
10
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/fs_struct.h>
c3d06f9ce   Andy Adamson   nfsd41: hard page...
12
  #include <linux/swap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/sunrpc/stats.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/sunrpc/svcsock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/lockd/bind.h>
a257cdd0e   Andreas Gruenbacher   [PATCH] NFSD: Add...
17
  #include <linux/nfsacl.h>
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
18
  #include <linux/seq_file.h>
fc5d00b04   Pavel Emelyanov   sunrpc: Add net a...
19
  #include <net/net_namespace.h>
9a74af213   Boaz Harrosh   nfsd: Move privat...
20
21
  #include "nfsd.h"
  #include "cache.h"
0a3adadee   J. Bruce Fields   nfsd: make fs/nfs...
22
  #include "vfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  
  #define NFSDDBG_FACILITY	NFSDDBG_SVC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  extern struct svc_program	nfsd_program;
9867d76ca   Jeff Layton   knfsd: convert kn...
26
  static int			nfsd(void *vrqstp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  struct timeval			nfssvc_boot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

bedbdd8ba   Neil Brown   knfsd: Replace lo...
29
30
31
32
33
34
35
36
37
38
39
40
41
  /*
   * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members
   * of the svc_serv struct. In particular, ->sv_nrthreads but also to some
   * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt
   *
   * If (out side the lock) nfsd_serv is non-NULL, then it must point to a
   * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number
   * of nfsd threads must exist and each must listed in ->sp_all_threads in each
   * entry of ->sv_pools[].
   *
   * Transitions of the thread count between zero and non-zero are of particular
   * interest since the svc_serv needs to be created and initialized at that
   * point, or freed.
3dd98a3bc   Jeff Layton   knfsd: clean up n...
42
43
44
45
46
47
48
49
   *
   * Finally, the nfsd_mutex also protects some of the global variables that are
   * accessed when nfsd starts and that are settable via the write_* routines in
   * nfsctl.c. In particular:
   *
   *	user_recovery_dirname
   *	user_lease_time
   *	nfsd_versions
bedbdd8ba   Neil Brown   knfsd: Replace lo...
50
51
52
   */
  DEFINE_MUTEX(nfsd_mutex);
  struct svc_serv 		*nfsd_serv;
4bd9b0f4a   Andy Adamson   nfsd41: use globa...
53
54
55
56
57
58
59
  /*
   * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used.
   * nfsd_drc_max_pages limits the total amount of memory available for
   * version 4.1 DRC caches.
   * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage.
   */
  spinlock_t	nfsd_drc_lock;
0c193054a   Andy Adamson   nfsd41: hange fro...
60
61
  unsigned int	nfsd_drc_max_mem;
  unsigned int	nfsd_drc_mem_used;
4bd9b0f4a   Andy Adamson   nfsd41: use globa...
62

3fb803a99   Andreas Gruenbacher   [PATCH] knfsd: Re...
63
64
65
66
67
68
69
70
  #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  static struct svc_stat	nfsd_acl_svcstats;
  static struct svc_version *	nfsd_acl_version[] = {
  	[2] = &nfsd_acl_version2,
  	[3] = &nfsd_acl_version3,
  };
  
  #define NFSD_ACL_MINVERS            2
e8c96f8c2   Tobias Klauser   [PATCH] fs: Use A...
71
  #define NFSD_ACL_NRVERS		ARRAY_SIZE(nfsd_acl_version)
3fb803a99   Andreas Gruenbacher   [PATCH] knfsd: Re...
72
73
74
75
76
77
  static struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS];
  
  static struct svc_program	nfsd_acl_program = {
  	.pg_prog		= NFS_ACL_PROGRAM,
  	.pg_nvers		= NFSD_ACL_NRVERS,
  	.pg_vers		= nfsd_acl_versions,
1a8eff6d9   NeilBrown   [PATCH] knfsd: fi...
78
  	.pg_name		= "nfsacl",
3fb803a99   Andreas Gruenbacher   [PATCH] knfsd: Re...
79
80
81
82
83
84
85
86
87
  	.pg_class		= "nfsd",
  	.pg_stats		= &nfsd_acl_svcstats,
  	.pg_authenticate	= &svc_set_client,
  };
  
  static struct svc_stat	nfsd_acl_svcstats = {
  	.program	= &nfsd_acl_program,
  };
  #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
88
89
90
91
92
93
94
95
96
97
98
  static struct svc_version *	nfsd_version[] = {
  	[2] = &nfsd_version2,
  #if defined(CONFIG_NFSD_V3)
  	[3] = &nfsd_version3,
  #endif
  #if defined(CONFIG_NFSD_V4)
  	[4] = &nfsd_version4,
  #endif
  };
  
  #define NFSD_MINVERS    	2
e8c96f8c2   Tobias Klauser   [PATCH] fs: Use A...
99
  #define NFSD_NRVERS		ARRAY_SIZE(nfsd_version)
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
100
101
102
  static struct svc_version *nfsd_versions[NFSD_NRVERS];
  
  struct svc_program		nfsd_program = {
3fb803a99   Andreas Gruenbacher   [PATCH] knfsd: Re...
103
104
105
  #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  	.pg_next		= &nfsd_acl_program,
  #endif
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
106
107
108
109
110
111
112
113
114
  	.pg_prog		= NFS_PROGRAM,		/* program number */
  	.pg_nvers		= NFSD_NRVERS,		/* nr of entries in nfsd_version */
  	.pg_vers		= nfsd_versions,	/* version table */
  	.pg_name		= "nfsd",		/* program name */
  	.pg_class		= "nfsd",		/* authentication class */
  	.pg_stats		= &nfsd_svcstats,	/* version table */
  	.pg_authenticate	= &svc_set_client,	/* export authentication */
  
  };
8daf220a6   Benny Halevy   nfsd41: control n...
115
  u32 nfsd_supported_minorversion;
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
116
117
118
  int nfsd_vers(int vers, enum vers_op change)
  {
  	if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
15ddb4aec   Pavel Emelyanov   NFSD: don't repor...
119
  		return 0;
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
120
121
122
  	switch(change) {
  	case NFSD_SET:
  		nfsd_versions[vers] = nfsd_version[vers];
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
123
124
  #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  		if (vers < NFSD_ACL_NRVERS)
1a8eff6d9   NeilBrown   [PATCH] knfsd: fi...
125
  			nfsd_acl_versions[vers] = nfsd_acl_version[vers];
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
126
  #endif
1a8eff6d9   NeilBrown   [PATCH] knfsd: fi...
127
  		break;
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
128
129
130
131
  	case NFSD_CLEAR:
  		nfsd_versions[vers] = NULL;
  #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  		if (vers < NFSD_ACL_NRVERS)
1a8eff6d9   NeilBrown   [PATCH] knfsd: fi...
132
  			nfsd_acl_versions[vers] = NULL;
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
133
134
135
136
137
138
139
140
141
  #endif
  		break;
  	case NFSD_TEST:
  		return nfsd_versions[vers] != NULL;
  	case NFSD_AVAIL:
  		return nfsd_version[vers] != NULL;
  	}
  	return 0;
  }
8daf220a6   Benny Halevy   nfsd41: control n...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  
  int nfsd_minorversion(u32 minorversion, enum vers_op change)
  {
  	if (minorversion > NFSD_SUPPORTED_MINOR_VERSION)
  		return -1;
  	switch(change) {
  	case NFSD_SET:
  		nfsd_supported_minorversion = minorversion;
  		break;
  	case NFSD_CLEAR:
  		if (minorversion == 0)
  			return -1;
  		nfsd_supported_minorversion = minorversion - 1;
  		break;
  	case NFSD_TEST:
  		return minorversion <= nfsd_supported_minorversion;
  	case NFSD_AVAIL:
  		return minorversion <= NFSD_SUPPORTED_MINOR_VERSION;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
  /*
   * Maximum number of nfsd processes
   */
  #define	NFSD_MAXSERVS		8192
  
  int nfsd_nrthreads(void)
  {
c7d106c90   Neil Brown   nfsd: fix race in...
170
171
172
173
174
175
  	int rv = 0;
  	mutex_lock(&nfsd_mutex);
  	if (nfsd_serv)
  		rv = nfsd_serv->sv_nrthreads;
  	mutex_unlock(&nfsd_mutex);
  	return rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  }
59db4a0c1   J. Bruce Fields   nfsd: move more i...
177
178
179
180
181
  static int nfsd_init_socks(int port)
  {
  	int error;
  	if (!list_empty(&nfsd_serv->sv_permsocks))
  		return 0;
fc5d00b04   Pavel Emelyanov   sunrpc: Add net a...
182
  	error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port,
59db4a0c1   J. Bruce Fields   nfsd: move more i...
183
184
185
  					SVC_SOCK_DEFAULTS);
  	if (error < 0)
  		return error;
fc5d00b04   Pavel Emelyanov   sunrpc: Add net a...
186
  	error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port,
59db4a0c1   J. Bruce Fields   nfsd: move more i...
187
188
189
190
191
192
  					SVC_SOCK_DEFAULTS);
  	if (error < 0)
  		return error;
  
  	return 0;
  }
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
193
194
195
196
197
  static bool nfsd_up = false;
  
  static int nfsd_startup(unsigned short port, int nrservs)
  {
  	int ret;
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
198
199
200
  
  	if (nfsd_up)
  		return 0;
59db4a0c1   J. Bruce Fields   nfsd: move more i...
201
202
203
204
205
206
207
208
209
210
211
  	/*
  	 * Readahead param cache - will no-op if it already exists.
  	 * (Note therefore results will be suboptimal if number of
  	 * threads is modified after nfsd start.)
  	 */
  	ret = nfsd_racache_init(2*nrservs);
  	if (ret)
  		return ret;
  	ret = nfsd_init_socks(port);
  	if (ret)
  		goto out_racache;
ac77efbe2   Jeff Layton   nfsd: just keep s...
212
213
  	ret = lockd_up();
  	if (ret)
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
214
  		goto out_racache;
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
215
  	ret = nfs4_state_start();
ac77efbe2   Jeff Layton   nfsd: just keep s...
216
217
  	if (ret)
  		goto out_lockd;
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
218
  	nfsd_up = true;
ac77efbe2   Jeff Layton   nfsd: just keep s...
219
220
221
  	return 0;
  out_lockd:
  	lockd_down();
59db4a0c1   J. Bruce Fields   nfsd: move more i...
222
223
  out_racache:
  	nfsd_racache_shutdown();
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  	return ret;
  }
  
  static void nfsd_shutdown(void)
  {
  	/*
  	 * write_ports can create the server without actually starting
  	 * any threads--if we get shut down before any threads are
  	 * started, then nfsd_last_thread will be run before any of this
  	 * other initialization has been done.
  	 */
  	if (!nfsd_up)
  		return;
  	nfs4_state_shutdown();
59db4a0c1   J. Bruce Fields   nfsd: move more i...
238
239
  	lockd_down();
  	nfsd_racache_shutdown();
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
240
241
  	nfsd_up = false;
  }
bc591ccff   NeilBrown   [PATCH] knfsd: ad...
242
243
244
245
  static void nfsd_last_thread(struct svc_serv *serv)
  {
  	/* When last nfsd thread exits we need to do some clean-up */
  	nfsd_serv = NULL;
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
246
  	nfsd_shutdown();
bc591ccff   NeilBrown   [PATCH] knfsd: ad...
247

16d058709   Stanislav Kinsbursky   NFSd: call svc rp...
248
  	svc_rpcb_cleanup(serv);
e096bbc64   Jeff Layton   knfsd: remove spe...
249
250
251
252
  	printk(KERN_WARNING "nfsd: last server has exited, flushing export "
  			    "cache
  ");
  	nfsd_export_flush();
bc591ccff   NeilBrown   [PATCH] knfsd: ad...
253
  }
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  
  void nfsd_reset_versions(void)
  {
  	int found_one = 0;
  	int i;
  
  	for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
  		if (nfsd_program.pg_vers[i])
  			found_one = 1;
  	}
  
  	if (!found_one) {
  		for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
  			nfsd_program.pg_vers[i] = nfsd_version[i];
  #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  		for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
  			nfsd_acl_program.pg_vers[i] =
  				nfsd_acl_version[i];
  #endif
  	}
  }
c3d06f9ce   Andy Adamson   nfsd41: hard page...
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  /*
   * Each session guarantees a negotiated per slot memory cache for replies
   * which in turn consumes memory beyond the v2/v3/v4.0 server. A dedicated
   * NFSv4.1 server might want to use more memory for a DRC than a machine
   * with mutiple services.
   *
   * Impose a hard limit on the number of pages for the DRC which varies
   * according to the machines free pages. This is of course only a default.
   *
   * For now this is a #defined shift which could be under admin control
   * in the future.
   */
  static void set_max_drc(void)
  {
6a14dd1a4   Andy Adamson   nfsd41: reserve l...
289
  	#define NFSD_DRC_SIZE_SHIFT	10
0c193054a   Andy Adamson   nfsd41: hange fro...
290
291
292
  	nfsd_drc_max_mem = (nr_free_buffer_pages()
  					>> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
  	nfsd_drc_mem_used = 0;
4bd9b0f4a   Andy Adamson   nfsd41: use globa...
293
  	spin_lock_init(&nfsd_drc_lock);
0c193054a   Andy Adamson   nfsd41: hange fro...
294
295
  	dprintk("%s nfsd_drc_max_mem %u 
  ", __func__, nfsd_drc_max_mem);
c3d06f9ce   Andy Adamson   nfsd41: hard page...
296
  }
bedbdd8ba   Neil Brown   knfsd: Replace lo...
297

b41b66d63   NeilBrown   [PATCH] knfsd: al...
298
  int nfsd_create_serv(void)
02a375f0a   NeilBrown   [PATCH] knfsd: se...
299
300
  {
  	int err = 0;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
301
302
  
  	WARN_ON(!mutex_is_locked(&nfsd_mutex));
02a375f0a   NeilBrown   [PATCH] knfsd: se...
303
  	if (nfsd_serv) {
9a24ab574   Greg Banks   [PATCH] knfsd: ad...
304
  		svc_get(nfsd_serv);
02a375f0a   NeilBrown   [PATCH] knfsd: se...
305
306
  		return 0;
  	}
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
307
308
309
310
311
312
313
314
315
316
317
  	if (nfsd_max_blksize == 0) {
  		/* choose a suitable default */
  		struct sysinfo i;
  		si_meminfo(&i);
  		/* Aim for 1/4096 of memory per thread
  		 * This gives 1MB on 4Gig machines
  		 * But only uses 32K on 128M machines.
  		 * Bottom out at 8K on 32M and smaller.
  		 * Of course, this is only a default.
  		 */
  		nfsd_max_blksize = NFSSVC_MAXBLKSIZE;
44c556000   NeilBrown   [PATCH] knfsd: fi...
318
  		i.totalram <<= PAGE_SHIFT - 12;
596bbe53e   NeilBrown   [PATCH] knfsd: Al...
319
320
321
322
  		while (nfsd_max_blksize > i.totalram &&
  		       nfsd_max_blksize >= 8*1024*2)
  			nfsd_max_blksize /= 2;
  	}
e844a7b98   J. Bruce Fields   nfsd: initialize ...
323
  	nfsd_reset_versions();
02a375f0a   NeilBrown   [PATCH] knfsd: se...
324

e096bbc64   Jeff Layton   knfsd: remove spe...
325
  	nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
a75c5d01e   Jeff Layton   sunrpc: remove sv...
326
  				      nfsd_last_thread, nfsd, THIS_MODULE);
02a375f0a   NeilBrown   [PATCH] knfsd: se...
327
  	if (nfsd_serv == NULL)
628b36872   Jeff Layton   nfsd: clean up nf...
328
  		return -ENOMEM;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
329

628b36872   Jeff Layton   nfsd: clean up nf...
330
  	set_max_drc();
02a375f0a   NeilBrown   [PATCH] knfsd: se...
331
332
333
  	do_gettimeofday(&nfssvc_boot);		/* record boot time */
  	return err;
  }
eed2965af   Greg Banks   [PATCH] knfsd: al...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  int nfsd_nrpools(void)
  {
  	if (nfsd_serv == NULL)
  		return 0;
  	else
  		return nfsd_serv->sv_nrpools;
  }
  
  int nfsd_get_nrthreads(int n, int *nthreads)
  {
  	int i = 0;
  
  	if (nfsd_serv != NULL) {
  		for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++)
  			nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads;
  	}
  
  	return 0;
  }
  
  int nfsd_set_nrthreads(int n, int *nthreads)
  {
  	int i = 0;
  	int tot = 0;
  	int err = 0;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
359
  	WARN_ON(!mutex_is_locked(&nfsd_mutex));
eed2965af   Greg Banks   [PATCH] knfsd: al...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  	if (nfsd_serv == NULL || n <= 0)
  		return 0;
  
  	if (n > nfsd_serv->sv_nrpools)
  		n = nfsd_serv->sv_nrpools;
  
  	/* enforce a global maximum number of threads */
  	tot = 0;
  	for (i = 0; i < n; i++) {
  		if (nthreads[i] > NFSD_MAXSERVS)
  			nthreads[i] = NFSD_MAXSERVS;
  		tot += nthreads[i];
  	}
  	if (tot > NFSD_MAXSERVS) {
  		/* total too large: scale down requested numbers */
  		for (i = 0; i < n && tot > 0; i++) {
  		    	int new = nthreads[i] * NFSD_MAXSERVS / tot;
  			tot -= (nthreads[i] - new);
  			nthreads[i] = new;
  		}
  		for (i = 0; i < n && tot > 0; i++) {
  			nthreads[i]--;
  			tot--;
  		}
  	}
  
  	/*
  	 * There must always be a thread in pool 0; the admin
  	 * can't shut down NFS completely using pool_threads.
  	 */
  	if (nthreads[0] == 0)
  		nthreads[0] = 1;
  
  	/* apply the new numbers */
eed2965af   Greg Banks   [PATCH] knfsd: al...
394
395
396
397
398
399
400
401
  	svc_get(nfsd_serv);
  	for (i = 0; i < n; i++) {
  		err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i],
  				    	  nthreads[i]);
  		if (err)
  			break;
  	}
  	svc_destroy(nfsd_serv);
eed2965af   Greg Banks   [PATCH] knfsd: al...
402
403
404
  
  	return err;
  }
ac77efbe2   Jeff Layton   nfsd: just keep s...
405
406
407
408
409
  /*
   * Adjust the number of threads and return the new number of threads.
   * This is also the function that starts the server if necessary, if
   * this is the first time nrservs is nonzero.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
413
  int
  nfsd_svc(unsigned short port, int nrservs)
  {
  	int	error;
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
414
  	bool	nfsd_up_before;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
415
416
  
  	mutex_lock(&nfsd_mutex);
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
417
418
  	dprintk("nfsd: creating service
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
421
422
  	if (nrservs <= 0)
  		nrservs = 0;
  	if (nrservs > NFSD_MAXSERVS)
  		nrservs = NFSD_MAXSERVS;
671e1fcf6   NeilBrown   nfsd: optimise th...
423
424
425
  	error = 0;
  	if (nrservs == 0 && nfsd_serv == NULL)
  		goto out;
02a375f0a   NeilBrown   [PATCH] knfsd: se...
426
  	error = nfsd_create_serv();
02a375f0a   NeilBrown   [PATCH] knfsd: se...
427
  	if (error)
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
428
429
430
431
432
  		goto out;
  
  	nfsd_up_before = nfsd_up;
  
  	error = nfsd_startup(port, nrservs);
af4718f3f   J. Bruce Fields   nfsd: minor nfsd_...
433
434
  	if (error)
  		goto out_destroy;
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
435
436
437
  	error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
  	if (error)
  		goto out_shutdown;
af4718f3f   J. Bruce Fields   nfsd: minor nfsd_...
438
439
440
441
442
  	/* We are holding a reference to nfsd_serv which
  	 * we don't want to count in the return value,
  	 * so subtract 1
  	 */
  	error = nfsd_serv->sv_nrthreads - 1;
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
443
  out_shutdown:
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
444
  	if (error < 0 && !nfsd_up_before)
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
445
  		nfsd_shutdown();
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
446
447
  out_destroy:
  	svc_destroy(nfsd_serv);		/* Release server */
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
448
  out:
bedbdd8ba   Neil Brown   knfsd: Replace lo...
449
  	mutex_unlock(&nfsd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
455
  
  /*
   * This is the NFS server kernel thread
   */
9867d76ca   Jeff Layton   knfsd: convert kn...
456
457
  static int
  nfsd(void *vrqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  {
9867d76ca   Jeff Layton   knfsd: convert kn...
459
  	struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
9867d76ca   Jeff Layton   knfsd: convert kn...
460
  	int err, preverr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
  
  	/* Lock module and set up kernel thread */
bedbdd8ba   Neil Brown   knfsd: Replace lo...
463
  	mutex_lock(&nfsd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464

9867d76ca   Jeff Layton   knfsd: convert kn...
465
  	/* At this point, the thread shares current->fs
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
  	 * with the init process. We need to create files with a
  	 * umask of 0 instead of init's umask. */
3e93cd671   Al Viro   Take fs_struct ha...
468
  	if (unshare_fs_struct() < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
472
  		printk("Unable to start nfsd thread: out of memory
  ");
  		goto out;
  	}
3e93cd671   Al Viro   Take fs_struct ha...
473

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  	current->fs->umask = 0;
9867d76ca   Jeff Layton   knfsd: convert kn...
475
476
  	/*
  	 * thread is spawned with all signals set to SIG_IGN, re-enable
100766f83   Jeff Layton   nfsd: treat all s...
477
  	 * the ones that will bring down the thread
9867d76ca   Jeff Layton   knfsd: convert kn...
478
  	 */
100766f83   Jeff Layton   nfsd: treat all s...
479
480
481
482
  	allow_signal(SIGKILL);
  	allow_signal(SIGHUP);
  	allow_signal(SIGINT);
  	allow_signal(SIGQUIT);
bedbdd8ba   Neil Brown   knfsd: Replace lo...
483

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
  	nfsdstats.th_cnt++;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
485
  	mutex_unlock(&nfsd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
489
490
491
  	/*
  	 * We want less throttling in balance_dirty_pages() so that nfs to
  	 * localhost doesn't cause nfsd to lock up due to all the client's
  	 * dirty pages.
  	 */
  	current->flags |= PF_LESS_THROTTLE;
831441862   Rafael J. Wysocki   Freezer: make ker...
492
  	set_freezable();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
496
497
  
  	/*
  	 * The main request loop
  	 */
  	for (;;) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
  		/*
  		 * Find a socket with data available and call its
  		 * recvfrom routine.
  		 */
6fb2b47fa   NeilBrown   [PATCH] knfsd: Dr...
502
  		while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  			;
9867d76ca   Jeff Layton   knfsd: convert kn...
504
  		if (err == -EINTR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  			break;
9867d76ca   Jeff Layton   knfsd: convert kn...
506
507
508
509
510
511
512
513
514
515
  		else if (err < 0) {
  			if (err != preverr) {
  				printk(KERN_WARNING "%s: unexpected error "
  					"from svc_recv (%d)
  ", __func__, -err);
  				preverr = err;
  			}
  			schedule_timeout_uninterruptible(HZ);
  			continue;
  		}
e0e817392   David Howells   CRED: Add some co...
516
  		validate_process_creds();
6fb2b47fa   NeilBrown   [PATCH] knfsd: Dr...
517
  		svc_process(rqstp);
e0e817392   David Howells   CRED: Add some co...
518
  		validate_process_creds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  	}
24e36663c   NeilBrown   [PATCH] knfsd: be...
520
  	/* Clear signals before calling svc_exit_thread() */
9e416052f   NeilBrown   [PATCH] nfsd: cle...
521
  	flush_signals(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522

bedbdd8ba   Neil Brown   knfsd: Replace lo...
523
  	mutex_lock(&nfsd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
527
528
529
530
  	nfsdstats.th_cnt --;
  
  out:
  	/* Release the thread */
  	svc_exit_thread(rqstp);
  
  	/* Release module */
bedbdd8ba   Neil Brown   knfsd: Replace lo...
531
  	mutex_unlock(&nfsd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  	module_put_and_exit(0);
9867d76ca   Jeff Layton   knfsd: convert kn...
533
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
  }
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
535
536
537
538
539
540
541
542
  static __be32 map_new_errors(u32 vers, __be32 nfserr)
  {
  	if (nfserr == nfserr_jukebox && vers == 2)
  		return nfserr_dropit;
  	if (nfserr == nfserr_wrongsec && vers < 4)
  		return nfserr_acces;
  	return nfserr;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  int
c7afef1f9   Al Viro   [PATCH] nfsd: mis...
544
  nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
  {
  	struct svc_procedure	*proc;
  	kxdrproc_t		xdr;
ad451d389   Al Viro   [PATCH] xdr annot...
548
549
  	__be32			nfserr;
  	__be32			*nfserrp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
  
  	dprintk("nfsd_dispatch: vers %d proc %d
  ",
  				rqstp->rq_vers, rqstp->rq_proc);
  	proc = rqstp->rq_procinfo;
1091006c5   J. Bruce Fields   nfsd: turn on rep...
555
556
557
558
559
560
561
562
563
564
565
566
567
568
  	/*
  	 * Give the xdr decoder a chance to change this if it wants
  	 * (necessary in the NFSv4.0 compound case)
  	 */
  	rqstp->rq_cachetype = proc->pc_cachetype;
  	/* Decode arguments */
  	xdr = proc->pc_decode;
  	if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
  			rqstp->rq_argp)) {
  		dprintk("nfsd: failed to decode arguments!
  ");
  		*statp = rpc_garbage_args;
  		return 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
  	/* Check whether we have this call in the cache. */
1091006c5   J. Bruce Fields   nfsd: turn on rep...
570
  	switch (nfsd_cache_lookup(rqstp)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
576
577
578
  	case RC_INTR:
  	case RC_DROPIT:
  		return 0;
  	case RC_REPLY:
  		return 1;
  	case RC_DOIT:;
  		/* do it */
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
581
582
583
  	/* need to grab the location to store the status, as
  	 * nfsv4 does some encoding while processing 
  	 */
  	nfserrp = rqstp->rq_res.head[0].iov_base
  		+ rqstp->rq_res.head[0].iov_len;
ad451d389   Al Viro   [PATCH] xdr annot...
584
  	rqstp->rq_res.head[0].iov_len += sizeof(__be32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
  
  	/* Now call the procedure handler, and encode NFS status. */
  	nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
588
  	nfserr = map_new_errors(rqstp->rq_vers, nfserr);
9e701c610   J. Bruce Fields   svcrpc: simpler r...
589
  	if (nfserr == nfserr_dropit || rqstp->rq_dropme) {
45457e091   J. Bruce Fields   nfsd: tone down i...
590
591
  		dprintk("nfsd: Dropping request; may be revisited later
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  		nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
  		return 0;
  	}
  
  	if (rqstp->rq_proc != 0)
  		*nfserrp++ = nfserr;
  
  	/* Encode result.
  	 * For NFSv2, additional info is never returned in case of an error.
  	 */
  	if (!(nfserr && rqstp->rq_vers == 2)) {
  		xdr = proc->pc_encode;
  		if (xdr && !xdr(rqstp, nfserrp,
  				rqstp->rq_resp)) {
  			/* Failed to encode result. Release cache entry */
  			dprintk("nfsd: failed to encode result!
  ");
  			nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
  			*statp = rpc_system_err;
  			return 1;
  		}
  	}
  
  	/* Store reply in cache. */
  	nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
  	return 1;
  }
03cf6c9f4   Greg Banks   knfsd: add file t...
619
620
621
  
  int nfsd_pool_stats_open(struct inode *inode, struct file *file)
  {
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
622
623
624
625
  	int ret;
  	mutex_lock(&nfsd_mutex);
  	if (nfsd_serv == NULL) {
  		mutex_unlock(&nfsd_mutex);
03cf6c9f4   Greg Banks   knfsd: add file t...
626
  		return -ENODEV;
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  	}
  	/* bump up the psudo refcount while traversing */
  	svc_get(nfsd_serv);
  	ret = svc_pool_stats_open(nfsd_serv, file);
  	mutex_unlock(&nfsd_mutex);
  	return ret;
  }
  
  int nfsd_pool_stats_release(struct inode *inode, struct file *file)
  {
  	int ret = seq_release(inode, file);
  	mutex_lock(&nfsd_mutex);
  	/* this function really, really should have been called svc_put() */
  	svc_destroy(nfsd_serv);
  	mutex_unlock(&nfsd_mutex);
  	return ret;
03cf6c9f4   Greg Banks   knfsd: add file t...
643
  }