nfssvc.c 17.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8
/*
 * Central processing for nfsd.
 *
 * Authors:	Olaf Kirch (okir@monad.swb.de)
 *
 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
 */

A
Alexey Dobriyan 已提交
9
#include <linux/sched.h>
10
#include <linux/freezer.h>
11
#include <linux/module.h>
L
Linus Torvalds 已提交
12
#include <linux/fs_struct.h>
A
Andy Adamson 已提交
13
#include <linux/swap.h>
L
Linus Torvalds 已提交
14 15 16 17

#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/lockd/bind.h>
18
#include <linux/nfsacl.h>
19
#include <linux/seq_file.h>
20
#include <net/net_namespace.h>
21 22
#include "nfsd.h"
#include "cache.h"
23
#include "vfs.h"
24
#include "netns.h"
L
Linus Torvalds 已提交
25 26 27 28

#define NFSDDBG_FACILITY	NFSDDBG_SVC

extern struct svc_program	nfsd_program;
29
static int			nfsd(void *vrqstp);
L
Linus Torvalds 已提交
30

31
/*
32
 * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members
33 34 35
 * 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
 *
36
 * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a
37 38 39 40 41 42 43
 * 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.
44 45 46 47 48 49 50 51
 *
 * 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
52 53 54
 */
DEFINE_MUTEX(nfsd_mutex);

55 56 57 58 59 60 61
/*
 * 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;
62 63
unsigned int	nfsd_drc_max_mem;
unsigned int	nfsd_drc_mem_used;
64

65 66 67 68 69 70 71 72
#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
73
#define NFSD_ACL_NRVERS		ARRAY_SIZE(nfsd_acl_version)
74 75 76 77 78 79
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,
80
	.pg_name		= "nfsacl",
81 82 83 84 85 86 87 88 89 90
	.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) */

91 92 93 94 95 96 97 98 99 100 101
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
102
#define NFSD_NRVERS		ARRAY_SIZE(nfsd_version)
103 104 105
static struct svc_version *nfsd_versions[NFSD_NRVERS];

struct svc_program		nfsd_program = {
106 107 108
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
	.pg_next		= &nfsd_acl_program,
#endif
109 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 */

};

119 120
u32 nfsd_supported_minorversion;

121 122 123
int nfsd_vers(int vers, enum vers_op change)
{
	if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
124
		return 0;
125 126 127 128 129
	switch(change) {
	case NFSD_SET:
		nfsd_versions[vers] = nfsd_version[vers];
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
		if (vers < NFSD_ACL_NRVERS)
130
			nfsd_acl_versions[vers] = nfsd_acl_version[vers];
131
#endif
132
		break;
133 134 135 136
	case NFSD_CLEAR:
		nfsd_versions[vers] = NULL;
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
		if (vers < NFSD_ACL_NRVERS)
137
			nfsd_acl_versions[vers] = NULL;
138 139 140 141 142 143 144 145 146
#endif
		break;
	case NFSD_TEST:
		return nfsd_versions[vers] != NULL;
	case NFSD_AVAIL:
		return nfsd_version[vers] != NULL;
	}
	return 0;
}
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

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

L
Linus Torvalds 已提交
169 170 171 172 173
/*
 * Maximum number of nfsd processes
 */
#define	NFSD_MAXSERVS		8192

174
int nfsd_nrthreads(struct net *net)
L
Linus Torvalds 已提交
175
{
N
Neil Brown 已提交
176
	int rv = 0;
177 178
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);

N
Neil Brown 已提交
179
	mutex_lock(&nfsd_mutex);
180 181
	if (nn->nfsd_serv)
		rv = nn->nfsd_serv->sv_nrthreads;
N
Neil Brown 已提交
182 183
	mutex_unlock(&nfsd_mutex);
	return rv;
L
Linus Torvalds 已提交
184 185
}

186
static int nfsd_init_socks(struct net *net)
187 188
{
	int error;
189 190 191
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);

	if (!list_empty(&nn->nfsd_serv->sv_permsocks))
192 193
		return 0;

194
	error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT,
195 196 197 198
					SVC_SOCK_DEFAULTS);
	if (error < 0)
		return error;

199
	error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT,
200 201 202 203 204 205 206
					SVC_SOCK_DEFAULTS);
	if (error < 0)
		return error;

	return 0;
}

207 208
static bool nfsd_up = false;

209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
static int nfsd_startup_generic(int nrservs)
{
	int ret;

	if (nfsd_up)
		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)
		return ret;
	ret = nfs4_state_start();
	if (ret)
		goto out_racache;
	return 0;

out_racache:
	nfsd_racache_shutdown();
	return ret;
}

static void nfsd_shutdown_generic(void)
{
	nfs4_state_shutdown();
	nfsd_racache_shutdown();
238
	nfsd_up = false;
239 240
}

241
static int nfsd_startup_net(int nrservs, struct net *net)
242
{
243
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
244 245
	int ret;

246 247 248
	if (nn->nfsd_net_up)
		return 0;

249
	ret = nfsd_startup_generic(nrservs);
250 251
	if (ret)
		return ret;
252 253 254
	ret = nfsd_init_socks(net);
	if (ret)
		goto out_socks;
255 256
	ret = lockd_up(net);
	if (ret)
257
		goto out_socks;
258 259 260 261
	ret = nfs4_state_start_net(net);
	if (ret)
		goto out_lockd;

262
	nn->nfsd_net_up = true;
263
	nfsd_up = true;
264 265 266 267
	return 0;

out_lockd:
	lockd_down(net);
268
out_socks:
269
	nfsd_shutdown_generic();
270 271 272
	return ret;
}

273 274
static void nfsd_shutdown_net(struct net *net)
{
275 276
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);

277 278
	nfs4_state_shutdown_net(net);
	lockd_down(net);
279
	nn->nfsd_net_up = false;
280
	nfsd_shutdown_generic();
281 282
}

283
static void nfsd_shutdown(struct net *net)
284
{
285 286
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);

287 288 289 290 291 292
	/*
	 * 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.
	 */
293
	if (!nn->nfsd_net_up)
294
		return;
295
	nfsd_shutdown_net(net);
296 297
}

298
static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
299
{
300
	nfsd_shutdown(net);
301

302
	svc_rpcb_cleanup(serv, net);
303

304 305
	printk(KERN_WARNING "nfsd: last server has exited, flushing export "
			    "cache\n");
306
	nfsd_export_flush(net);
307
}
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

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

A
Andy Adamson 已提交
330 331 332 333 334 335 336 337 338 339 340 341 342 343
/*
 * 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)
{
344
	#define NFSD_DRC_SIZE_SHIFT	10
345 346 347
	nfsd_drc_max_mem = (nr_free_buffer_pages()
					>> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
	nfsd_drc_mem_used = 0;
348
	spin_lock_init(&nfsd_drc_lock);
349
	dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem);
A
Andy Adamson 已提交
350
}
351

352
static int nfsd_get_default_max_blksize(void)
353
{
354 355 356
	struct sysinfo i;
	unsigned long long target;
	unsigned long ret;
357

358
	si_meminfo(&i);
359
	target = (i.totalram - i.totalhigh) << PAGE_SHIFT;
360 361 362 363 364 365 366 367 368 369 370 371 372
	/*
	 * 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;
}

373
int nfsd_create_serv(struct net *net)
374
{
375
	int error;
376
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
377

378
	WARN_ON(!mutex_is_locked(&nfsd_mutex));
379 380
	if (nn->nfsd_serv) {
		svc_get(nn->nfsd_serv);
381 382
		return 0;
	}
383 384
	if (nfsd_max_blksize == 0)
		nfsd_max_blksize = nfsd_get_default_max_blksize();
385
	nfsd_reset_versions();
386
	nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
387
				      nfsd_last_thread, nfsd, THIS_MODULE);
388
	if (nn->nfsd_serv == NULL)
389
		return -ENOMEM;
390

391
	error = svc_bind(nn->nfsd_serv, net);
392
	if (error < 0) {
393
		svc_destroy(nn->nfsd_serv);
394 395 396
		return error;
	}

397
	set_max_drc();
398
	do_gettimeofday(&nn->nfssvc_boot);		/* record boot time */
399
	return 0;
400 401
}

402
int nfsd_nrpools(struct net *net)
403
{
404 405 406
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);

	if (nn->nfsd_serv == NULL)
407 408
		return 0;
	else
409
		return nn->nfsd_serv->sv_nrpools;
410 411
}

412
int nfsd_get_nrthreads(int n, int *nthreads, struct net *net)
413 414
{
	int i = 0;
415
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
416

417 418 419
	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;
420 421 422 423 424
	}

	return 0;
}

425 426 427 428 429 430 431 432 433 434 435 436
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;
}

437
int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
438 439 440 441
{
	int i = 0;
	int tot = 0;
	int err = 0;
442
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
443

444 445
	WARN_ON(!mutex_is_locked(&nfsd_mutex));

446
	if (nn->nfsd_serv == NULL || n <= 0)
447 448
		return 0;

449 450
	if (n > nn->nfsd_serv->sv_nrpools)
		n = nn->nfsd_serv->sv_nrpools;
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479

	/* 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 */
480
	svc_get(nn->nfsd_serv);
481
	for (i = 0; i < n; i++) {
482
		err = svc_set_num_threads(nn->nfsd_serv, &nn->nfsd_serv->sv_pools[i],
483 484 485 486
				    	  nthreads[i]);
		if (err)
			break;
	}
487
	nfsd_destroy(net);
488 489 490
	return err;
}

491 492 493 494 495
/*
 * 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.
 */
L
Linus Torvalds 已提交
496
int
497
nfsd_svc(int nrservs, struct net *net)
L
Linus Torvalds 已提交
498 499
{
	int	error;
500
	bool	nfsd_up_before;
501
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
502 503

	mutex_lock(&nfsd_mutex);
504
	dprintk("nfsd: creating service\n");
L
Linus Torvalds 已提交
505 506 507 508
	if (nrservs <= 0)
		nrservs = 0;
	if (nrservs > NFSD_MAXSERVS)
		nrservs = NFSD_MAXSERVS;
509
	error = 0;
510
	if (nrservs == 0 && nn->nfsd_serv == NULL)
511 512
		goto out;

513
	error = nfsd_create_serv(net);
514
	if (error)
515 516
		goto out;

517
	nfsd_up_before = nn->nfsd_net_up;
518

519
	error = nfsd_startup_net(nrservs, net);
J
J. Bruce Fields 已提交
520 521
	if (error)
		goto out_destroy;
522
	error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs);
523 524
	if (error)
		goto out_shutdown;
525
	/* We are holding a reference to nn->nfsd_serv which
J
J. Bruce Fields 已提交
526 527 528
	 * we don't want to count in the return value,
	 * so subtract 1
	 */
529
	error = nn->nfsd_serv->sv_nrthreads - 1;
530
out_shutdown:
531
	if (error < 0 && !nfsd_up_before)
532
		nfsd_shutdown(net);
533
out_destroy:
534
	nfsd_destroy(net);		/* Release server */
535
out:
536
	mutex_unlock(&nfsd_mutex);
L
Linus Torvalds 已提交
537 538 539 540 541 542 543
	return error;
}


/*
 * This is the NFS server kernel thread
 */
544 545
static int
nfsd(void *vrqstp)
L
Linus Torvalds 已提交
546
{
547
	struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
548
	int err;
L
Linus Torvalds 已提交
549 550

	/* Lock module and set up kernel thread */
551
	mutex_lock(&nfsd_mutex);
L
Linus Torvalds 已提交
552

553
	/* At this point, the thread shares current->fs
L
Linus Torvalds 已提交
554 555
	 * with the init process. We need to create files with a
	 * umask of 0 instead of init's umask. */
556
	if (unshare_fs_struct() < 0) {
L
Linus Torvalds 已提交
557 558 559
		printk("Unable to start nfsd thread: out of memory\n");
		goto out;
	}
560

L
Linus Torvalds 已提交
561 562
	current->fs->umask = 0;

563 564
	/*
	 * thread is spawned with all signals set to SIG_IGN, re-enable
565
	 * the ones that will bring down the thread
566
	 */
567 568 569 570
	allow_signal(SIGKILL);
	allow_signal(SIGHUP);
	allow_signal(SIGINT);
	allow_signal(SIGQUIT);
571

L
Linus Torvalds 已提交
572
	nfsdstats.th_cnt++;
573 574
	mutex_unlock(&nfsd_mutex);

L
Linus Torvalds 已提交
575 576 577 578 579 580
	/*
	 * 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;
581
	set_freezable();
L
Linus Torvalds 已提交
582 583 584 585 586 587 588 589 590

	/*
	 * The main request loop
	 */
	for (;;) {
		/*
		 * Find a socket with data available and call its
		 * recvfrom routine.
		 */
591
		while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
L
Linus Torvalds 已提交
592
			;
593
		if (err == -EINTR)
L
Linus Torvalds 已提交
594
			break;
595
		validate_process_creds();
596
		svc_process(rqstp);
597
		validate_process_creds();
L
Linus Torvalds 已提交
598 599
	}

600
	/* Clear signals before calling svc_exit_thread() */
601
	flush_signals(current);
L
Linus Torvalds 已提交
602

603
	mutex_lock(&nfsd_mutex);
L
Linus Torvalds 已提交
604 605 606
	nfsdstats.th_cnt --;

out:
607
	rqstp->rq_server = NULL;
608

L
Linus Torvalds 已提交
609 610 611
	/* Release the thread */
	svc_exit_thread(rqstp);

612 613
	nfsd_destroy(&init_net);

L
Linus Torvalds 已提交
614
	/* Release module */
615
	mutex_unlock(&nfsd_mutex);
L
Linus Torvalds 已提交
616
	module_put_and_exit(0);
617
	return 0;
L
Linus Torvalds 已提交
618 619
}

620 621 622 623 624 625 626 627 628
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;
}

L
Linus Torvalds 已提交
629
int
630
nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
L
Linus Torvalds 已提交
631 632 633
{
	struct svc_procedure	*proc;
	kxdrproc_t		xdr;
A
Al Viro 已提交
634 635
	__be32			nfserr;
	__be32			*nfserrp;
L
Linus Torvalds 已提交
636 637 638 639 640

	dprintk("nfsd_dispatch: vers %d proc %d\n",
				rqstp->rq_vers, rqstp->rq_proc);
	proc = rqstp->rq_procinfo;

641 642 643 644 645 646 647 648 649 650 651 652 653 654
	/*
	 * 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!\n");
		*statp = rpc_garbage_args;
		return 1;
	}

L
Linus Torvalds 已提交
655
	/* Check whether we have this call in the cache. */
656
	switch (nfsd_cache_lookup(rqstp)) {
L
Linus Torvalds 已提交
657 658 659 660 661 662 663 664 665 666 667 668 669 670
	case RC_INTR:
	case RC_DROPIT:
		return 0;
	case RC_REPLY:
		return 1;
	case RC_DOIT:;
		/* do it */
	}

	/* 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;
A
Al Viro 已提交
671
	rqstp->rq_res.head[0].iov_len += sizeof(__be32);
L
Linus Torvalds 已提交
672 673 674

	/* Now call the procedure handler, and encode NFS status. */
	nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
675
	nfserr = map_new_errors(rqstp->rq_vers, nfserr);
676
	if (nfserr == nfserr_dropit || rqstp->rq_dropme) {
677
		dprintk("nfsd: Dropping request; may be revisited later\n");
L
Linus Torvalds 已提交
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
		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!\n");
			nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
			*statp = rpc_system_err;
			return 1;
		}
	}

	/* Store reply in cache. */
J
J. Bruce Fields 已提交
701
	nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1);
L
Linus Torvalds 已提交
702 703
	return 1;
}
704 705 706

int nfsd_pool_stats_open(struct inode *inode, struct file *file)
{
707
	int ret;
708 709 710
	struct net *net = &init_net;
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);

711
	mutex_lock(&nfsd_mutex);
712
	if (nn->nfsd_serv == NULL) {
713
		mutex_unlock(&nfsd_mutex);
714
		return -ENODEV;
715 716
	}
	/* bump up the psudo refcount while traversing */
717 718
	svc_get(nn->nfsd_serv);
	ret = svc_pool_stats_open(nn->nfsd_serv, file);
719 720 721 722 723 724 725
	mutex_unlock(&nfsd_mutex);
	return ret;
}

int nfsd_pool_stats_release(struct inode *inode, struct file *file)
{
	int ret = seq_release(inode, file);
726 727
	struct net *net = &init_net;

728 729
	mutex_lock(&nfsd_mutex);
	/* this function really, really should have been called svc_put() */
730
	nfsd_destroy(net);
731 732
	mutex_unlock(&nfsd_mutex);
	return ret;
733
}