Blame view

fs/nfsd/nfssvc.c 20 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>
366849966   Scott Mayhew   nfsd: Register ca...
16
  #include <linux/sunrpc/svc_xprt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/lockd/bind.h>
a257cdd0e   Andreas Gruenbacher   [PATCH] NFSD: Add...
18
  #include <linux/nfsacl.h>
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
19
  #include <linux/seq_file.h>
366849966   Scott Mayhew   nfsd: Register ca...
20
21
22
  #include <linux/inetdevice.h>
  #include <net/addrconf.h>
  #include <net/ipv6.h>
fc5d00b04   Pavel Emelyanov   sunrpc: Add net a...
23
  #include <net/net_namespace.h>
9a74af213   Boaz Harrosh   nfsd: Move privat...
24
25
  #include "nfsd.h"
  #include "cache.h"
0a3adadee   J. Bruce Fields   nfsd: make fs/nfs...
26
  #include "vfs.h"
2c2fe2909   Stanislav Kinsbursky   nfsd: per-net NFS...
27
  #include "netns.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  
  #define NFSDDBG_FACILITY	NFSDDBG_SVC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  extern struct svc_program	nfsd_program;
9867d76ca   Jeff Layton   knfsd: convert kn...
31
  static int			nfsd(void *vrqstp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32

bedbdd8ba   Neil Brown   knfsd: Replace lo...
33
  /*
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
34
   * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members
bedbdd8ba   Neil Brown   knfsd: Replace lo...
35
36
37
   * 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
   *
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
38
   * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a
bedbdd8ba   Neil Brown   knfsd: Replace lo...
39
40
41
42
43
44
45
   * 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...
46
47
48
49
50
51
52
53
   *
   * 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...
54
55
   */
  DEFINE_MUTEX(nfsd_mutex);
bedbdd8ba   Neil Brown   knfsd: Replace lo...
56

4bd9b0f4a   Andy Adamson   nfsd41: use globa...
57
58
59
60
61
62
63
  /*
   * 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;
697ce9be7   Zhang Yanfei   fs/nfsd: change t...
64
65
  unsigned long	nfsd_drc_max_mem;
  unsigned long	nfsd_drc_mem_used;
4bd9b0f4a   Andy Adamson   nfsd41: use globa...
66

3fb803a99   Andreas Gruenbacher   [PATCH] knfsd: Re...
67
68
69
70
71
72
73
74
  #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...
75
  #define NFSD_ACL_NRVERS		ARRAY_SIZE(nfsd_acl_version)
3fb803a99   Andreas Gruenbacher   [PATCH] knfsd: Re...
76
77
78
79
80
81
  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...
82
  	.pg_name		= "nfsacl",
3fb803a99   Andreas Gruenbacher   [PATCH] knfsd: Re...
83
84
85
86
87
88
89
90
91
  	.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...
92
93
94
95
96
97
98
99
100
101
102
  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...
103
  #define NFSD_NRVERS		ARRAY_SIZE(nfsd_version)
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
104
105
106
  static struct svc_version *nfsd_versions[NFSD_NRVERS];
  
  struct svc_program		nfsd_program = {
3fb803a99   Andreas Gruenbacher   [PATCH] knfsd: Re...
107
108
109
  #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  	.pg_next		= &nfsd_acl_program,
  #endif
70c3b76c2   NeilBrown   [PATCH] knfsd: Al...
110
111
112
113
114
115
116
117
118
  	.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 */
  
  };
35f7a14fc   J. Bruce Fields   nfsd4: fix minorv...
119
120
121
  static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = {
  	[0] = 1,
  	[1] = 1,
c23ae6017   J. Bruce Fields   nfsd: default NFS...
122
  	[2] = 1,
35f7a14fc   J. Bruce Fields   nfsd4: fix minorv...
123
  };
8daf220a6   Benny Halevy   nfsd41: control n...
124

6658d3a7b   NeilBrown   [PATCH] knfsd: re...
125
126
127
  int nfsd_vers(int vers, enum vers_op change)
  {
  	if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
15ddb4aec   Pavel Emelyanov   NFSD: don't repor...
128
  		return 0;
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
129
130
131
  	switch(change) {
  	case NFSD_SET:
  		nfsd_versions[vers] = nfsd_version[vers];
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
132
133
  #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  		if (vers < NFSD_ACL_NRVERS)
1a8eff6d9   NeilBrown   [PATCH] knfsd: fi...
134
  			nfsd_acl_versions[vers] = nfsd_acl_version[vers];
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
135
  #endif
1a8eff6d9   NeilBrown   [PATCH] knfsd: fi...
136
  		break;
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
137
138
139
140
  	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...
141
  			nfsd_acl_versions[vers] = NULL;
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
142
143
144
145
146
147
148
149
150
  #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...
151
152
153
154
155
156
157
  
  int nfsd_minorversion(u32 minorversion, enum vers_op change)
  {
  	if (minorversion > NFSD_SUPPORTED_MINOR_VERSION)
  		return -1;
  	switch(change) {
  	case NFSD_SET:
35f7a14fc   J. Bruce Fields   nfsd4: fix minorv...
158
  		nfsd_supported_minorversions[minorversion] = true;
8daf220a6   Benny Halevy   nfsd41: control n...
159
160
  		break;
  	case NFSD_CLEAR:
35f7a14fc   J. Bruce Fields   nfsd4: fix minorv...
161
  		nfsd_supported_minorversions[minorversion] = false;
8daf220a6   Benny Halevy   nfsd41: control n...
162
163
  		break;
  	case NFSD_TEST:
35f7a14fc   J. Bruce Fields   nfsd4: fix minorv...
164
  		return nfsd_supported_minorversions[minorversion];
8daf220a6   Benny Halevy   nfsd41: control n...
165
166
167
168
169
  	case NFSD_AVAIL:
  		return minorversion <= NFSD_SUPPORTED_MINOR_VERSION;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
  /*
   * Maximum number of nfsd processes
   */
  #define	NFSD_MAXSERVS		8192
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
174
  int nfsd_nrthreads(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  {
c7d106c90   Neil Brown   nfsd: fix race in...
176
  	int rv = 0;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
177
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
c7d106c90   Neil Brown   nfsd: fix race in...
178
  	mutex_lock(&nfsd_mutex);
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
179
180
  	if (nn->nfsd_serv)
  		rv = nn->nfsd_serv->sv_nrthreads;
c7d106c90   Neil Brown   nfsd: fix race in...
181
182
  	mutex_unlock(&nfsd_mutex);
  	return rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  }
db6e182c1   Stanislav Kinsbursky   nfsd: pass net to...
184
  static int nfsd_init_socks(struct net *net)
59db4a0c1   J. Bruce Fields   nfsd: move more i...
185
186
  {
  	int error;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
187
188
189
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  
  	if (!list_empty(&nn->nfsd_serv->sv_permsocks))
59db4a0c1   J. Bruce Fields   nfsd: move more i...
190
  		return 0;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
191
  	error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT,
59db4a0c1   J. Bruce Fields   nfsd: move more i...
192
193
194
  					SVC_SOCK_DEFAULTS);
  	if (error < 0)
  		return error;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
195
  	error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT,
59db4a0c1   J. Bruce Fields   nfsd: move more i...
196
197
198
199
200
201
  					SVC_SOCK_DEFAULTS);
  	if (error < 0)
  		return error;
  
  	return 0;
  }
4539f1498   Stanislav Kinsbursky   nfsd: replace boo...
202
  static int nfsd_users = 0;
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
203

bda9cac1d   Stanislav Kinsbursky   nfsd: introduce h...
204
205
206
  static int nfsd_startup_generic(int nrservs)
  {
  	int ret;
4539f1498   Stanislav Kinsbursky   nfsd: replace boo...
207
  	if (nfsd_users++)
bda9cac1d   Stanislav Kinsbursky   nfsd: introduce h...
208
209
210
211
212
213
214
215
216
  		return 0;
  
  	/*
  	 * 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)
d9499a957   Kinglong Mee   NFSD: Decrease nf...
217
  		goto dec_users;
bda9cac1d   Stanislav Kinsbursky   nfsd: introduce h...
218
219
220
221
222
223
224
  	ret = nfs4_state_start();
  	if (ret)
  		goto out_racache;
  	return 0;
  
  out_racache:
  	nfsd_racache_shutdown();
d9499a957   Kinglong Mee   NFSD: Decrease nf...
225
226
  dec_users:
  	nfsd_users--;
bda9cac1d   Stanislav Kinsbursky   nfsd: introduce h...
227
228
229
230
231
  	return ret;
  }
  
  static void nfsd_shutdown_generic(void)
  {
4539f1498   Stanislav Kinsbursky   nfsd: replace boo...
232
233
  	if (--nfsd_users)
  		return;
bda9cac1d   Stanislav Kinsbursky   nfsd: introduce h...
234
235
236
  	nfs4_state_shutdown();
  	nfsd_racache_shutdown();
  }
8ef667140   Kinglong Mee   NFSD: Don't start...
237
238
  static bool nfsd_needs_lockd(void)
  {
ff88825fb   Kinglong Mee   NFSD: fix compile...
239
  #if defined(CONFIG_NFSD_V3)
8ef667140   Kinglong Mee   NFSD: Don't start...
240
  	return (nfsd_versions[2] != NULL) || (nfsd_versions[3] != NULL);
ff88825fb   Kinglong Mee   NFSD: fix compile...
241
242
243
  #else
  	return (nfsd_versions[2] != NULL);
  #endif
8ef667140   Kinglong Mee   NFSD: Don't start...
244
  }
903d9bf0e   Stanislav Kinsbursky   nfsd: simplify NF...
245
  static int nfsd_startup_net(int nrservs, struct net *net)
6ff50b3de   Stanislav Kinsbursky   nfsd: move per-ne...
246
  {
2c2fe2909   Stanislav Kinsbursky   nfsd: per-net NFS...
247
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
6ff50b3de   Stanislav Kinsbursky   nfsd: move per-ne...
248
  	int ret;
2c2fe2909   Stanislav Kinsbursky   nfsd: per-net NFS...
249
250
  	if (nn->nfsd_net_up)
  		return 0;
903d9bf0e   Stanislav Kinsbursky   nfsd: simplify NF...
251
  	ret = nfsd_startup_generic(nrservs);
6ff50b3de   Stanislav Kinsbursky   nfsd: move per-ne...
252
253
  	if (ret)
  		return ret;
903d9bf0e   Stanislav Kinsbursky   nfsd: simplify NF...
254
255
256
  	ret = nfsd_init_socks(net);
  	if (ret)
  		goto out_socks;
8ef667140   Kinglong Mee   NFSD: Don't start...
257
258
259
260
261
262
263
  
  	if (nfsd_needs_lockd() && !nn->lockd_up) {
  		ret = lockd_up(net);
  		if (ret)
  			goto out_socks;
  		nn->lockd_up = 1;
  	}
6ff50b3de   Stanislav Kinsbursky   nfsd: move per-ne...
264
265
266
  	ret = nfs4_state_start_net(net);
  	if (ret)
  		goto out_lockd;
2c2fe2909   Stanislav Kinsbursky   nfsd: per-net NFS...
267
  	nn->nfsd_net_up = true;
6ff50b3de   Stanislav Kinsbursky   nfsd: move per-ne...
268
269
270
  	return 0;
  
  out_lockd:
8ef667140   Kinglong Mee   NFSD: Don't start...
271
272
273
274
  	if (nn->lockd_up) {
  		lockd_down(net);
  		nn->lockd_up = 0;
  	}
903d9bf0e   Stanislav Kinsbursky   nfsd: simplify NF...
275
  out_socks:
bda9cac1d   Stanislav Kinsbursky   nfsd: introduce h...
276
  	nfsd_shutdown_generic();
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
277
278
  	return ret;
  }
6ff50b3de   Stanislav Kinsbursky   nfsd: move per-ne...
279
280
  static void nfsd_shutdown_net(struct net *net)
  {
2c2fe2909   Stanislav Kinsbursky   nfsd: per-net NFS...
281
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
6ff50b3de   Stanislav Kinsbursky   nfsd: move per-ne...
282
  	nfs4_state_shutdown_net(net);
8ef667140   Kinglong Mee   NFSD: Don't start...
283
284
285
286
  	if (nn->lockd_up) {
  		lockd_down(net);
  		nn->lockd_up = 0;
  	}
2c2fe2909   Stanislav Kinsbursky   nfsd: per-net NFS...
287
  	nn->nfsd_net_up = false;
903d9bf0e   Stanislav Kinsbursky   nfsd: simplify NF...
288
  	nfsd_shutdown_generic();
6ff50b3de   Stanislav Kinsbursky   nfsd: move per-ne...
289
  }
366849966   Scott Mayhew   nfsd: Register ca...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event,
  	void *ptr)
  {
  	struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
  	struct net_device *dev = ifa->ifa_dev->dev;
  	struct net *net = dev_net(dev);
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  	struct sockaddr_in sin;
  
  	if (event != NETDEV_DOWN)
  		goto out;
  
  	if (nn->nfsd_serv) {
  		dprintk("nfsd_inetaddr_event: removed %pI4
  ", &ifa->ifa_local);
  		sin.sin_family = AF_INET;
  		sin.sin_addr.s_addr = ifa->ifa_local;
  		svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin);
  	}
  
  out:
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block nfsd_inetaddr_notifier = {
  	.notifier_call = nfsd_inetaddr_event,
  };
  
  #if IS_ENABLED(CONFIG_IPV6)
  static int nfsd_inet6addr_event(struct notifier_block *this,
  	unsigned long event, void *ptr)
  {
  	struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
  	struct net_device *dev = ifa->idev->dev;
  	struct net *net = dev_net(dev);
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  	struct sockaddr_in6 sin6;
  
  	if (event != NETDEV_DOWN)
  		goto out;
  
  	if (nn->nfsd_serv) {
  		dprintk("nfsd_inet6addr_event: removed %pI6
  ", &ifa->addr);
  		sin6.sin6_family = AF_INET6;
  		sin6.sin6_addr = ifa->addr;
  		svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin6);
  	}
  
  out:
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block nfsd_inet6addr_notifier = {
  	.notifier_call = nfsd_inet6addr_event,
  };
  #endif
1eca45f8a   Vasily Averin   NFSD: fix corrupt...
347
348
  /* Only used under nfsd_mutex, so this atomic may be overkill: */
  static atomic_t nfsd_notifier_refcount = ATOMIC_INIT(0);
541e864f0   Stanislav Kinsbursky   nfsd: simplify se...
349
  static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
350
  {
903d9bf0e   Stanislav Kinsbursky   nfsd: simplify NF...
351
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1eca45f8a   Vasily Averin   NFSD: fix corrupt...
352
353
354
  	/* check if the notifier still has clients */
  	if (atomic_dec_return(&nfsd_notifier_refcount) == 0) {
  		unregister_inetaddr_notifier(&nfsd_inetaddr_notifier);
366849966   Scott Mayhew   nfsd: Register ca...
355
  #if IS_ENABLED(CONFIG_IPV6)
1eca45f8a   Vasily Averin   NFSD: fix corrupt...
356
  		unregister_inet6addr_notifier(&nfsd_inet6addr_notifier);
366849966   Scott Mayhew   nfsd: Register ca...
357
  #endif
1eca45f8a   Vasily Averin   NFSD: fix corrupt...
358
  	}
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
359
360
361
362
  	/*
  	 * 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
691412b44   Kinglong Mee   nfsd: Fix nfsd le...
363
  	 * other initialization has been done except the rpcb information.
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
364
  	 */
691412b44   Kinglong Mee   nfsd: Fix nfsd le...
365
  	svc_rpcb_cleanup(serv, net);
903d9bf0e   Stanislav Kinsbursky   nfsd: simplify NF...
366
  	if (!nn->nfsd_net_up)
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
367
  		return;
16d058709   Stanislav Kinsbursky   NFSd: call svc rp...
368

691412b44   Kinglong Mee   nfsd: Fix nfsd le...
369
  	nfsd_shutdown_net(net);
e096bbc64   Jeff Layton   knfsd: remove spe...
370
371
372
  	printk(KERN_WARNING "nfsd: last server has exited, flushing export "
  			    "cache
  ");
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
373
  	nfsd_export_flush(net);
bc591ccff   NeilBrown   [PATCH] knfsd: ad...
374
  }
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  
  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...
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  /*
   * 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...
410
  	#define NFSD_DRC_SIZE_SHIFT	10
0c193054a   Andy Adamson   nfsd41: hange fro...
411
412
413
  	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...
414
  	spin_lock_init(&nfsd_drc_lock);
697ce9be7   Zhang Yanfei   fs/nfsd: change t...
415
416
  	dprintk("%s nfsd_drc_max_mem %lu 
  ", __func__, nfsd_drc_max_mem);
c3d06f9ce   Andy Adamson   nfsd41: hard page...
417
  }
bedbdd8ba   Neil Brown   knfsd: Replace lo...
418

87b0fc7de   J. Bruce Fields   nfsd: cleanup set...
419
  static int nfsd_get_default_max_blksize(void)
02a375f0a   NeilBrown   [PATCH] knfsd: se...
420
  {
87b0fc7de   J. Bruce Fields   nfsd: cleanup set...
421
422
423
  	struct sysinfo i;
  	unsigned long long target;
  	unsigned long ret;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
424

87b0fc7de   J. Bruce Fields   nfsd: cleanup set...
425
  	si_meminfo(&i);
508f92275   J. Bruce Fields   nfsd: fix default...
426
  	target = (i.totalram - i.totalhigh) << PAGE_SHIFT;
87b0fc7de   J. Bruce Fields   nfsd: cleanup set...
427
428
429
430
431
432
433
434
435
436
437
438
  	/*
  	 * 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.
  	 */
  	target >>= 12;
  
  	ret = NFSSVC_MAXBLKSIZE;
  	while (ret > target && ret >= 8*1024*2)
  		ret /= 2;
  	return ret;
  }
b9e13cdfa   Jeff Layton   nfsd/sunrpc: turn...
439
440
441
442
  static struct svc_serv_ops nfsd_thread_sv_ops = {
  	.svo_shutdown		= nfsd_last_thread,
  	.svo_function		= nfsd,
  	.svo_enqueue_xprt	= svc_xprt_do_enqueue,
598e23590   Jeff Layton   nfsd/sunrpc: abst...
443
  	.svo_setup		= svc_set_num_threads,
b9e13cdfa   Jeff Layton   nfsd/sunrpc: turn...
444
  	.svo_module		= THIS_MODULE,
ea126e743   Jeff Layton   nfsd/sunrpc: add ...
445
  };
6777436b0   Stanislav Kinsbursky   nfsd: pass net to...
446
  int nfsd_create_serv(struct net *net)
87b0fc7de   J. Bruce Fields   nfsd: cleanup set...
447
  {
9793f7c88   Stanislav Kinsbursky   SUNRPC: new svc_b...
448
  	int error;
b9c0ef857   Stanislav Kinsbursky   nfsd: make NFSd s...
449
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
9793f7c88   Stanislav Kinsbursky   SUNRPC: new svc_b...
450

bedbdd8ba   Neil Brown   knfsd: Replace lo...
451
  	WARN_ON(!mutex_is_locked(&nfsd_mutex));
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
452
453
  	if (nn->nfsd_serv) {
  		svc_get(nn->nfsd_serv);
02a375f0a   NeilBrown   [PATCH] knfsd: se...
454
455
  		return 0;
  	}
87b0fc7de   J. Bruce Fields   nfsd: cleanup set...
456
457
  	if (nfsd_max_blksize == 0)
  		nfsd_max_blksize = nfsd_get_default_max_blksize();
e844a7b98   J. Bruce Fields   nfsd: initialize ...
458
  	nfsd_reset_versions();
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
459
  	nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
b9e13cdfa   Jeff Layton   nfsd/sunrpc: turn...
460
  						&nfsd_thread_sv_ops);
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
461
  	if (nn->nfsd_serv == NULL)
628b36872   Jeff Layton   nfsd: clean up nf...
462
  		return -ENOMEM;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
463

5b8db00ba   Jeff Layton   nfsd: add a new /...
464
  	nn->nfsd_serv->sv_maxconn = nn->max_connections;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
465
  	error = svc_bind(nn->nfsd_serv, net);
9793f7c88   Stanislav Kinsbursky   SUNRPC: new svc_b...
466
  	if (error < 0) {
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
467
  		svc_destroy(nn->nfsd_serv);
9793f7c88   Stanislav Kinsbursky   SUNRPC: new svc_b...
468
469
  		return error;
  	}
628b36872   Jeff Layton   nfsd: clean up nf...
470
  	set_max_drc();
1eca45f8a   Vasily Averin   NFSD: fix corrupt...
471
472
473
  	/* check if the notifier is already set */
  	if (atomic_inc_return(&nfsd_notifier_refcount) == 1) {
  		register_inetaddr_notifier(&nfsd_inetaddr_notifier);
366849966   Scott Mayhew   nfsd: Register ca...
474
  #if IS_ENABLED(CONFIG_IPV6)
1eca45f8a   Vasily Averin   NFSD: fix corrupt...
475
  		register_inet6addr_notifier(&nfsd_inet6addr_notifier);
366849966   Scott Mayhew   nfsd: Register ca...
476
  #endif
1eca45f8a   Vasily Averin   NFSD: fix corrupt...
477
  	}
b9c0ef857   Stanislav Kinsbursky   nfsd: make NFSd s...
478
  	do_gettimeofday(&nn->nfssvc_boot);		/* record boot time */
87b0fc7de   J. Bruce Fields   nfsd: cleanup set...
479
  	return 0;
02a375f0a   NeilBrown   [PATCH] knfsd: se...
480
  }
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
481
  int nfsd_nrpools(struct net *net)
eed2965af   Greg Banks   [PATCH] knfsd: al...
482
  {
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
483
484
485
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  
  	if (nn->nfsd_serv == NULL)
eed2965af   Greg Banks   [PATCH] knfsd: al...
486
487
  		return 0;
  	else
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
488
  		return nn->nfsd_serv->sv_nrpools;
eed2965af   Greg Banks   [PATCH] knfsd: al...
489
  }
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
490
  int nfsd_get_nrthreads(int n, int *nthreads, struct net *net)
eed2965af   Greg Banks   [PATCH] knfsd: al...
491
492
  {
  	int i = 0;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
493
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
eed2965af   Greg Banks   [PATCH] knfsd: al...
494

9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
495
496
497
  	if (nn->nfsd_serv != NULL) {
  		for (i = 0; i < nn->nfsd_serv->sv_nrpools && i < n; i++)
  			nthreads[i] = nn->nfsd_serv->sv_pools[i].sp_nrthreads;
eed2965af   Greg Banks   [PATCH] knfsd: al...
498
499
500
501
  	}
  
  	return 0;
  }
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
502
503
504
505
506
507
508
509
510
511
512
  void nfsd_destroy(struct net *net)
  {
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  	int destroy = (nn->nfsd_serv->sv_nrthreads == 1);
  
  	if (destroy)
  		svc_shutdown_net(nn->nfsd_serv, net);
  	svc_destroy(nn->nfsd_serv);
  	if (destroy)
  		nn->nfsd_serv = NULL;
  }
3938a0d5e   Stanislav Kinsbursky   nfsd: pass net to...
513
  int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
eed2965af   Greg Banks   [PATCH] knfsd: al...
514
515
516
517
  {
  	int i = 0;
  	int tot = 0;
  	int err = 0;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
518
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
eed2965af   Greg Banks   [PATCH] knfsd: al...
519

bedbdd8ba   Neil Brown   knfsd: Replace lo...
520
  	WARN_ON(!mutex_is_locked(&nfsd_mutex));
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
521
  	if (nn->nfsd_serv == NULL || n <= 0)
eed2965af   Greg Banks   [PATCH] knfsd: al...
522
  		return 0;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
523
524
  	if (n > nn->nfsd_serv->sv_nrpools)
  		n = nn->nfsd_serv->sv_nrpools;
eed2965af   Greg Banks   [PATCH] knfsd: al...
525
526
527
528
  
  	/* enforce a global maximum number of threads */
  	tot = 0;
  	for (i = 0; i < n; i++) {
3c7aa15d2   Kinglong Mee   NFSD: Using min/m...
529
  		nthreads[i] = min(nthreads[i], NFSD_MAXSERVS);
eed2965af   Greg Banks   [PATCH] knfsd: al...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
  		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 */
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
553
  	svc_get(nn->nfsd_serv);
eed2965af   Greg Banks   [PATCH] knfsd: al...
554
  	for (i = 0; i < n; i++) {
598e23590   Jeff Layton   nfsd/sunrpc: abst...
555
556
  		err = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv,
  				&nn->nfsd_serv->sv_pools[i], nthreads[i]);
eed2965af   Greg Banks   [PATCH] knfsd: al...
557
558
559
  		if (err)
  			break;
  	}
19f7e2ca4   Stanislav Kinsbursky   NFSd: introduce n...
560
  	nfsd_destroy(net);
eed2965af   Greg Banks   [PATCH] knfsd: al...
561
562
  	return err;
  }
ac77efbe2   Jeff Layton   nfsd: just keep s...
563
564
565
566
567
  /*
   * 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
568
  int
d41a9417c   Stanislav Kinsbursky   nfsd: pass net to...
569
  nfsd_svc(int nrservs, struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
  {
  	int	error;
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
572
  	bool	nfsd_up_before;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
573
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
bedbdd8ba   Neil Brown   knfsd: Replace lo...
574
575
  
  	mutex_lock(&nfsd_mutex);
6658d3a7b   NeilBrown   [PATCH] knfsd: re...
576
577
  	dprintk("nfsd: creating service
  ");
3c7aa15d2   Kinglong Mee   NFSD: Using min/m...
578
579
580
  
  	nrservs = max(nrservs, 0);
  	nrservs = min(nrservs, NFSD_MAXSERVS);
671e1fcf6   NeilBrown   nfsd: optimise th...
581
  	error = 0;
3c7aa15d2   Kinglong Mee   NFSD: Using min/m...
582

9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
583
  	if (nrservs == 0 && nn->nfsd_serv == NULL)
671e1fcf6   NeilBrown   nfsd: optimise th...
584
  		goto out;
6777436b0   Stanislav Kinsbursky   nfsd: pass net to...
585
  	error = nfsd_create_serv(net);
02a375f0a   NeilBrown   [PATCH] knfsd: se...
586
  	if (error)
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
587
  		goto out;
903d9bf0e   Stanislav Kinsbursky   nfsd: simplify NF...
588
  	nfsd_up_before = nn->nfsd_net_up;
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
589

903d9bf0e   Stanislav Kinsbursky   nfsd: simplify NF...
590
  	error = nfsd_startup_net(nrservs, net);
af4718f3f   J. Bruce Fields   nfsd: minor nfsd_...
591
592
  	if (error)
  		goto out_destroy;
598e23590   Jeff Layton   nfsd/sunrpc: abst...
593
594
  	error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv,
  			NULL, nrservs);
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
595
596
  	if (error)
  		goto out_shutdown;
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
597
  	/* We are holding a reference to nn->nfsd_serv which
af4718f3f   J. Bruce Fields   nfsd: minor nfsd_...
598
599
600
  	 * we don't want to count in the return value,
  	 * so subtract 1
  	 */
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
601
  	error = nn->nfsd_serv->sv_nrthreads - 1;
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
602
  out_shutdown:
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
603
  	if (error < 0 && !nfsd_up_before)
541e864f0   Stanislav Kinsbursky   nfsd: simplify se...
604
  		nfsd_shutdown_net(net);
774f8bbd9   J. Bruce Fields   nfsd: fix startup...
605
  out_destroy:
19f7e2ca4   Stanislav Kinsbursky   NFSd: introduce n...
606
  	nfsd_destroy(net);		/* Release server */
4ad9a344b   Jeff Layton   nfsd4: fix v4 sta...
607
  out:
bedbdd8ba   Neil Brown   knfsd: Replace lo...
608
  	mutex_unlock(&nfsd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
614
  
  /*
   * This is the NFS server kernel thread
   */
9867d76ca   Jeff Layton   knfsd: convert kn...
615
616
  static int
  nfsd(void *vrqstp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  {
9867d76ca   Jeff Layton   knfsd: convert kn...
618
  	struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
88c476661   Stanislav Kinsbursky   nfsd: pass proper...
619
620
  	struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list);
  	struct net *net = perm_sock->xpt_net;
5b8db00ba   Jeff Layton   nfsd: add a new /...
621
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
5b444cc9a   J. Bruce Fields   svcrpc: remove ha...
622
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
  
  	/* Lock module and set up kernel thread */
bedbdd8ba   Neil Brown   knfsd: Replace lo...
625
  	mutex_lock(&nfsd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626

9867d76ca   Jeff Layton   knfsd: convert kn...
627
  	/* At this point, the thread shares current->fs
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
  	 * 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...
630
  	if (unshare_fs_struct() < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
  		printk("Unable to start nfsd thread: out of memory
  ");
  		goto out;
  	}
3e93cd671   Al Viro   Take fs_struct ha...
635

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  	current->fs->umask = 0;
9867d76ca   Jeff Layton   knfsd: convert kn...
637
638
  	/*
  	 * thread is spawned with all signals set to SIG_IGN, re-enable
100766f83   Jeff Layton   nfsd: treat all s...
639
  	 * the ones that will bring down the thread
9867d76ca   Jeff Layton   knfsd: convert kn...
640
  	 */
100766f83   Jeff Layton   nfsd: treat all s...
641
642
643
644
  	allow_signal(SIGKILL);
  	allow_signal(SIGHUP);
  	allow_signal(SIGINT);
  	allow_signal(SIGQUIT);
bedbdd8ba   Neil Brown   knfsd: Replace lo...
645

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  	nfsdstats.th_cnt++;
bedbdd8ba   Neil Brown   knfsd: Replace lo...
647
  	mutex_unlock(&nfsd_mutex);
831441862   Rafael J. Wysocki   Freezer: make ker...
648
  	set_freezable();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
  
  	/*
  	 * The main request loop
  	 */
  	for (;;) {
5b8db00ba   Jeff Layton   nfsd: add a new /...
654
655
  		/* Update sv_maxconn if it has changed */
  		rqstp->rq_server->sv_maxconn = nn->max_connections;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
659
  		/*
  		 * Find a socket with data available and call its
  		 * recvfrom routine.
  		 */
6fb2b47fa   NeilBrown   [PATCH] knfsd: Dr...
660
  		while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  			;
9867d76ca   Jeff Layton   knfsd: convert kn...
662
  		if (err == -EINTR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  			break;
e0e817392   David Howells   CRED: Add some co...
664
  		validate_process_creds();
6fb2b47fa   NeilBrown   [PATCH] knfsd: Dr...
665
  		svc_process(rqstp);
e0e817392   David Howells   CRED: Add some co...
666
  		validate_process_creds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  	}
24e36663c   NeilBrown   [PATCH] knfsd: be...
668
  	/* Clear signals before calling svc_exit_thread() */
9e416052f   NeilBrown   [PATCH] nfsd: cle...
669
  	flush_signals(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670

bedbdd8ba   Neil Brown   knfsd: Replace lo...
671
  	mutex_lock(&nfsd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
674
  	nfsdstats.th_cnt --;
  
  out:
57c8b13e3   Stanislav Kinsbursky   NFSd: set nfsd_se...
675
  	rqstp->rq_server = NULL;
786185b5f   Stanislav Kinsbursky   SUNRPC: move per-...
676

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
  	/* Release the thread */
  	svc_exit_thread(rqstp);
88c476661   Stanislav Kinsbursky   nfsd: pass proper...
679
  	nfsd_destroy(net);
57c8b13e3   Stanislav Kinsbursky   NFSd: set nfsd_se...
680

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  	/* Release module */
bedbdd8ba   Neil Brown   knfsd: Replace lo...
682
  	mutex_unlock(&nfsd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
  	module_put_and_exit(0);
9867d76ca   Jeff Layton   knfsd: convert kn...
684
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
  }
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
686
687
688
689
690
691
692
693
  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
694
  int
c7afef1f9   Al Viro   [PATCH] nfsd: mis...
695
  nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
  {
  	struct svc_procedure	*proc;
  	kxdrproc_t		xdr;
ad451d389   Al Viro   [PATCH] xdr annot...
699
700
  	__be32			nfserr;
  	__be32			*nfserrp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
704
705
  
  	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...
706
707
708
709
710
711
712
713
714
715
716
717
718
719
  	/*
  	 * 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
720
  	/* Check whether we have this call in the cache. */
1091006c5   J. Bruce Fields   nfsd: turn on rep...
721
  	switch (nfsd_cache_lookup(rqstp)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
726
727
728
  	case RC_DROPIT:
  		return 0;
  	case RC_REPLY:
  		return 1;
  	case RC_DOIT:;
  		/* do it */
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
730
731
732
733
  	/* 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...
734
  	rqstp->rq_res.head[0].iov_len += sizeof(__be32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
  
  	/* 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...
738
  	nfserr = map_new_errors(rqstp->rq_vers, nfserr);
78b65eb3f   Jeff Layton   sunrpc: move rq_d...
739
  	if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) {
45457e091   J. Bruce Fields   nfsd: tone down i...
740
741
  		dprintk("nfsd: Dropping request; may be revisited later
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
  		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. */
57d276d71   J. Bruce Fields   nfsd: fix v4 repl...
766
  	nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
  	return 1;
  }
03cf6c9f4   Greg Banks   knfsd: add file t...
769
770
771
  
  int nfsd_pool_stats_open(struct inode *inode, struct file *file)
  {
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
772
  	int ret;
11f779421   Stanislav Kinsbursky   nfsd: containeriz...
773
  	struct nfsd_net *nn = net_generic(inode->i_sb->s_fs_info, nfsd_net_id);
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
774

ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
775
  	mutex_lock(&nfsd_mutex);
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
776
  	if (nn->nfsd_serv == NULL) {
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
777
  		mutex_unlock(&nfsd_mutex);
03cf6c9f4   Greg Banks   knfsd: add file t...
778
  		return -ENODEV;
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
779
780
  	}
  	/* bump up the psudo refcount while traversing */
9dd9845f0   Stanislav Kinsbursky   nfsd: make NFSd s...
781
782
  	svc_get(nn->nfsd_serv);
  	ret = svc_pool_stats_open(nn->nfsd_serv, file);
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
783
784
785
786
787
788
789
  	mutex_unlock(&nfsd_mutex);
  	return ret;
  }
  
  int nfsd_pool_stats_release(struct inode *inode, struct file *file)
  {
  	int ret = seq_release(inode, file);
11f779421   Stanislav Kinsbursky   nfsd: containeriz...
790
  	struct net *net = inode->i_sb->s_fs_info;
786185b5f   Stanislav Kinsbursky   SUNRPC: move per-...
791

ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
792
793
  	mutex_lock(&nfsd_mutex);
  	/* this function really, really should have been called svc_put() */
19f7e2ca4   Stanislav Kinsbursky   NFSd: introduce n...
794
  	nfsd_destroy(net);
ed2d8aed5   Ryusei Yamaguchi   knfsd: Replace lo...
795
796
  	mutex_unlock(&nfsd_mutex);
  	return ret;
03cf6c9f4   Greg Banks   knfsd: add file t...
797
  }