client.c 37.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* client.c: NFS client sharing and management code
 *
 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */


#include <linux/module.h>
#include <linux/init.h>
A
Alexey Dobriyan 已提交
15
#include <linux/sched.h>
16 17 18 19 20 21 22 23 24 25
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/metrics.h>
26
#include <linux/sunrpc/xprtsock.h>
\
\"Talpey, Thomas\ 已提交
27
#include <linux/sunrpc/xprtrdma.h>
28 29 30 31 32 33 34 35 36
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
#include <linux/lockd/bind.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/nfs_idmap.h>
#include <linux/vfs.h>
#include <linux/inet.h>
37
#include <linux/in6.h>
38
#include <linux/slab.h>
A
Al Viro 已提交
39
#include <linux/idr.h>
40
#include <net/ipv6.h>
41
#include <linux/nfs_xdr.h>
A
Andy Adamson 已提交
42
#include <linux/sunrpc/bc_xprt.h>
43 44
#include <linux/nsproxy.h>
#include <linux/pid_namespace.h>
45 46 47 48 49 50 51


#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
#include "iostat.h"
#include "internal.h"
52
#include "fscache.h"
R
Ricardo Labiaga 已提交
53
#include "pnfs.h"
54
#include "nfs.h"
55
#include "netns.h"
56 57 58 59

#define NFSDBG_FACILITY		NFSDBG_CLIENT

static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
60 61 62
static DEFINE_SPINLOCK(nfs_version_lock);
static DEFINE_MUTEX(nfs_version_mutex);
static LIST_HEAD(nfs_versions);
63

64 65 66
/*
 * RPC cruft for NFS
 */
67
static const struct rpc_version *nfs_version[5] = {
68 69 70
	[2] = NULL,
	[3] = NULL,
	[4] = NULL,
71 72
};

73
const struct rpc_program nfs_program = {
74 75 76 77 78
	.name			= "nfs",
	.number			= NFS_PROGRAM,
	.nrvers			= ARRAY_SIZE(nfs_version),
	.version		= nfs_version,
	.stats			= &nfs_rpcstat,
J
Jim Rees 已提交
79
	.pipe_dir_name		= NFS_PIPE_DIRNAME,
80 81 82 83 84 85
};

struct rpc_stat nfs_rpcstat = {
	.program		= &nfs_program
};

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
static struct nfs_subversion *find_nfs_version(unsigned int version)
{
	struct nfs_subversion *nfs;
	spin_lock(&nfs_version_lock);

	list_for_each_entry(nfs, &nfs_versions, list) {
		if (nfs->rpc_ops->version == version) {
			spin_unlock(&nfs_version_lock);
			return nfs;
		}
	};

	spin_unlock(&nfs_version_lock);
	return ERR_PTR(-EPROTONOSUPPORT);;
}

struct nfs_subversion *get_nfs_version(unsigned int version)
{
	struct nfs_subversion *nfs = find_nfs_version(version);

	if (IS_ERR(nfs)) {
		mutex_lock(&nfs_version_mutex);
		request_module("nfs%d", version);
		nfs = find_nfs_version(version);
		mutex_unlock(&nfs_version_mutex);
	}

	if (!IS_ERR(nfs))
		try_module_get(nfs->owner);
	return nfs;
}

void put_nfs_version(struct nfs_subversion *nfs)
{
	module_put(nfs->owner);
}

void register_nfs_version(struct nfs_subversion *nfs)
{
	spin_lock(&nfs_version_lock);

	list_add(&nfs->list, &nfs_versions);
	nfs_version[nfs->rpc_ops->version] = nfs->rpc_vers;

	spin_unlock(&nfs_version_lock);
}
EXPORT_SYMBOL_GPL(register_nfs_version);

void unregister_nfs_version(struct nfs_subversion *nfs)
{
	spin_lock(&nfs_version_lock);

	nfs_version[nfs->rpc_ops->version] = NULL;
	list_del(&nfs->list);

	spin_unlock(&nfs_version_lock);
}
EXPORT_SYMBOL_GPL(unregister_nfs_version);

/*
 * Preload all configured NFS versions during module init.
 * This function should be edited after each protocol is converted,
 * and eventually removed.
 */
int __init nfs_register_versions(void)
{
	return init_nfs_v4();
}

/*
 * Remove each pre-loaded NFS version
 */
void nfs_unregister_versions(void)
{
	exit_nfs_v4();
}

163 164 165 166 167 168
/*
 * Allocate a shared client record
 *
 * Since these are allocated/deallocated very rarely, we don't
 * bother putting them in a slab cache...
 */
169
struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
170 171
{
	struct nfs_client *clp;
172
	struct rpc_cred *cred;
173
	int err = -ENOMEM;
174 175 176 177

	if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
		goto error_0;

178 179 180 181
	clp->cl_nfs_mod = cl_init->nfs_mod;
	try_module_get(clp->cl_nfs_mod->owner);

	clp->rpc_ops = clp->cl_nfs_mod->rpc_ops;
182

183 184 185
	atomic_set(&clp->cl_count, 1);
	clp->cl_cons_state = NFS_CS_INITING;

186 187
	memcpy(&clp->cl_addr, cl_init->addr, cl_init->addrlen);
	clp->cl_addrlen = cl_init->addrlen;
188

189
	if (cl_init->hostname) {
190
		err = -ENOMEM;
191
		clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL);
192
		if (!clp->cl_hostname)
193
			goto error_cleanup;
194 195 196 197 198
	}

	INIT_LIST_HEAD(&clp->cl_superblocks);
	clp->cl_rpcclient = ERR_PTR(-EINVAL);

199
	clp->cl_proto = cl_init->proto;
200
	clp->cl_net = get_net(cl_init->net);
201

202
	cred = rpc_lookup_machine_cred("*");
203 204
	if (!IS_ERR(cred))
		clp->cl_machine_cred = cred;
205 206
	nfs_fscache_get_client_cookie(clp);

207 208
	return clp;

209
error_cleanup:
210
	put_nfs_version(clp->cl_nfs_mod);
211 212
	kfree(clp);
error_0:
213
	return ERR_PTR(err);
214
}
B
Bryan Schumaker 已提交
215
EXPORT_SYMBOL_GPL(nfs_alloc_client);
216

217
#ifdef CONFIG_NFS_V4
A
Andy Adamson 已提交
218
/* idr_remove_all is not needed as all id's are removed by nfs_put_client */
219
void nfs_cleanup_cb_ident_idr(struct net *net)
A
Andy Adamson 已提交
220
{
221 222 223
	struct nfs_net *nn = net_generic(net, nfs_net_id);

	idr_destroy(&nn->cb_ident_idr);
A
Andy Adamson 已提交
224 225 226 227 228
}

/* nfs_client_lock held */
static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
{
229
	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
230

A
Andy Adamson 已提交
231
	if (clp->cl_cb_ident)
232
		idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
A
Andy Adamson 已提交
233 234
}

F
Fred Isaman 已提交
235 236 237 238 239
static void pnfs_init_server(struct nfs_server *server)
{
	rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC");
}

240
#else
241
void nfs_cleanup_cb_ident_idr(struct net *net)
A
Andy Adamson 已提交
242 243 244 245 246 247
{
}

static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
{
}
F
Fred Isaman 已提交
248 249 250 251 252

static void pnfs_init_server(struct nfs_server *server)
{
}

253
#endif /* CONFIG_NFS_V4 */
254

255 256 257
/*
 * Destroy a shared client record
 */
258
void nfs_free_client(struct nfs_client *clp)
259
{
260
	dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version);
261

262 263
	nfs_fscache_release_client_cookie(clp);

264 265 266 267
	/* -EIO all pending I/O */
	if (!IS_ERR(clp->cl_rpcclient))
		rpc_shutdown_client(clp->cl_rpcclient);

268 269 270
	if (clp->cl_machine_cred != NULL)
		put_rpccred(clp->cl_machine_cred);

271
	put_net(clp->cl_net);
272
	put_nfs_version(clp->cl_nfs_mod);
273 274 275 276 277
	kfree(clp->cl_hostname);
	kfree(clp);

	dprintk("<-- nfs_free_client()\n");
}
B
Bryan Schumaker 已提交
278
EXPORT_SYMBOL_GPL(nfs_free_client);
279 280 281 282 283 284

/*
 * Release a reference to a shared client record
 */
void nfs_put_client(struct nfs_client *clp)
{
285 286
	struct nfs_net *nn;

D
David Howells 已提交
287 288 289
	if (!clp)
		return;

290
	dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
291
	nn = net_generic(clp->cl_net, nfs_net_id);
292

293
	if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {
294
		list_del(&clp->cl_share_link);
A
Andy Adamson 已提交
295
		nfs_cb_idr_remove_locked(clp);
296
		spin_unlock(&nn->nfs_client_lock);
297 298 299

		BUG_ON(!list_empty(&clp->cl_superblocks));

300
		clp->rpc_ops->free_client(clp);
301 302
	}
}
303
EXPORT_SYMBOL_GPL(nfs_put_client);
304

305
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
306 307 308 309 310 311 312 313 314 315 316
/*
 * Test if two ip6 socket addresses refer to the same socket by
 * comparing relevant fields. The padding bytes specifically, are not
 * compared. sin6_flowinfo is not compared because it only affects QoS
 * and sin6_scope_id is only compared if the address is "link local"
 * because "link local" addresses need only be unique to a specific
 * link. Conversely, ordinary unicast addresses might have different
 * sin6_scope_id.
 *
 * The caller should ensure both socket addresses are AF_INET6.
 */
317 318
static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
				      const struct sockaddr *sa2)
319
{
320 321
	const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
	const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
322

323
	if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
324
		return 0;
325 326
	else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL)
		return sin1->sin6_scope_id == sin2->sin6_scope_id;
327

328
	return 1;
329
}
330 331 332
#else	/* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */
static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
				      const struct sockaddr *sa2)
333 334 335
{
	return 0;
}
336
#endif
337

I
Ian Dall 已提交
338 339 340 341 342 343 344
/*
 * Test if two ip4 socket addresses refer to the same socket, by
 * comparing relevant fields. The padding bytes specifically, are
 * not compared.
 *
 * The caller should ensure both socket addresses are AF_INET.
 */
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
static int nfs_sockaddr_match_ipaddr4(const struct sockaddr *sa1,
				      const struct sockaddr *sa2)
{
	const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
	const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;

	return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
}

static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1,
				const struct sockaddr *sa2)
{
	const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
	const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;

	return nfs_sockaddr_match_ipaddr6(sa1, sa2) &&
		(sin1->sin6_port == sin2->sin6_port);
}

364 365
static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
				const struct sockaddr *sa2)
I
Ian Dall 已提交
366
{
367 368
	const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
	const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
369

370 371 372 373
	return nfs_sockaddr_match_ipaddr4(sa1, sa2) &&
		(sin1->sin_port == sin2->sin_port);
}

374
#if defined(CONFIG_NFS_V4_1)
375 376 377 378
/*
 * Test if two socket addresses represent the same actual socket,
 * by comparing (only) relevant fields, excluding the port number.
 */
379 380
int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
			      const struct sockaddr *sa2)
381 382
{
	if (sa1->sa_family != sa2->sa_family)
I
Ian Dall 已提交
383
		return 0;
384 385 386 387 388 389 390 391

	switch (sa1->sa_family) {
	case AF_INET:
		return nfs_sockaddr_match_ipaddr4(sa1, sa2);
	case AF_INET6:
		return nfs_sockaddr_match_ipaddr6(sa1, sa2);
	}
	return 0;
I
Ian Dall 已提交
392
}
393
#endif /* CONFIG_NFS_V4_1 */
I
Ian Dall 已提交
394 395 396

/*
 * Test if two socket addresses represent the same actual socket,
397
 * by comparing (only) relevant fields, including the port number.
I
Ian Dall 已提交
398 399 400 401 402 403 404 405 406
 */
static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
			    const struct sockaddr *sa2)
{
	if (sa1->sa_family != sa2->sa_family)
		return 0;

	switch (sa1->sa_family) {
	case AF_INET:
407
		return nfs_sockaddr_cmp_ip4(sa1, sa2);
I
Ian Dall 已提交
408
	case AF_INET6:
409
		return nfs_sockaddr_cmp_ip6(sa1, sa2);
I
Ian Dall 已提交
410 411 412 413
	}
	return 0;
}

414
/*
415 416
 * Find an nfs_client on the list that matches the initialisation data
 * that is supplied.
417
 */
418
static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data)
419 420
{
	struct nfs_client *clp;
I
Ian Dall 已提交
421
	const struct sockaddr *sap = data->addr;
422
	struct nfs_net *nn = net_generic(data->net, nfs_net_id);
423

424
	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
I
Ian Dall 已提交
425
	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
426 427 428 429 430
		/* Don't match clients that failed to initialise properly */
		if (clp->cl_cons_state < 0)
			continue;

		/* Different NFS versions cannot share the same nfs_client */
431
		if (clp->rpc_ops != data->nfs_mod->rpc_ops)
432 433
			continue;

434 435
		if (clp->cl_proto != data->proto)
			continue;
436 437 438
		/* Match nfsv4 minorversion */
		if (clp->cl_minorversion != data->minorversion)
			continue;
439
		/* Match the full socket address */
I
Ian Dall 已提交
440
		if (!nfs_sockaddr_cmp(sap, clap))
441 442 443 444
			continue;

		atomic_inc(&clp->cl_count);
		return clp;
445
	}
446
	return NULL;
447 448
}

449 450 451 452 453 454 455 456 457 458 459
static bool nfs_client_init_is_complete(const struct nfs_client *clp)
{
	return clp->cl_cons_state != NFS_CS_INITING;
}

int nfs_wait_client_init_complete(const struct nfs_client *clp)
{
	return wait_event_killable(nfs_client_active_wq,
			nfs_client_init_is_complete(clp));
}

460 461 462 463 464 465 466 467 468
/*
 * Found an existing client.  Make sure it's ready before returning.
 */
static struct nfs_client *
nfs_found_client(const struct nfs_client_initdata *cl_init,
		 struct nfs_client *clp)
{
	int error;

469
	error = nfs_wait_client_init_complete(clp);
470 471 472 473 474 475 476 477 478 479 480
	if (error < 0) {
		nfs_put_client(clp);
		return ERR_PTR(-ERESTARTSYS);
	}

	if (clp->cl_cons_state < NFS_CS_READY) {
		error = clp->cl_cons_state;
		nfs_put_client(clp);
		return ERR_PTR(error);
	}

481 482
	smp_rmb();

483 484 485 486 487
	dprintk("<-- %s found nfs_client %p for %s\n",
		__func__, clp, cl_init->hostname ?: "");
	return clp;
}

488 489 490 491
/*
 * Look up a client by IP address and protocol version
 * - creates a new record if one doesn't yet exist
 */
492
struct nfs_client *
493 494 495
nfs_get_client(const struct nfs_client_initdata *cl_init,
	       const struct rpc_timeout *timeparms,
	       const char *ip_addr,
C
Chuck Lever 已提交
496
	       rpc_authflavor_t authflavour)
497 498
{
	struct nfs_client *clp, *new = NULL;
499
	struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
500
	const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops;
501

502
	dprintk("--> nfs_get_client(%s,v%u)\n",
503
		cl_init->hostname ?: "", rpc_ops->version);
504 505 506

	/* see if the client already exists */
	do {
507
		spin_lock(&nn->nfs_client_lock);
508

509
		clp = nfs_match_client(cl_init);
510 511 512
		if (clp) {
			spin_unlock(&nn->nfs_client_lock);
			if (new)
513
				new->rpc_ops->free_client(new);
514 515
			return nfs_found_client(cl_init, clp);
		}
516 517 518
		if (new) {
			list_add(&new->cl_share_link, &nn->nfs_client_list);
			spin_unlock(&nn->nfs_client_lock);
C
Chuck Lever 已提交
519
			new->cl_flags = cl_init->init_flags;
520 521
			return rpc_ops->init_client(new, timeparms, ip_addr,
						    authflavour);
522
		}
523

524
		spin_unlock(&nn->nfs_client_lock);
525

526
		new = rpc_ops->alloc_client(cl_init);
527
	} while (!IS_ERR(new));
528

529 530
	dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n",
		cl_init->hostname ?: "", PTR_ERR(new));
531
	return new;
532 533 534 535 536
}

/*
 * Mark a server as ready or failed
 */
537
void nfs_mark_client_ready(struct nfs_client *clp, int state)
538
{
539
	smp_wmb();
540 541 542
	clp->cl_cons_state = state;
	wake_up_all(&nfs_client_active_wq);
}
543 544 545 546

/*
 * Initialise the timeout values for a connection
 */
547
void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
548 549 550 551 552 553
				    unsigned int timeo, unsigned int retrans)
{
	to->to_initval = timeo * HZ / 10;
	to->to_retries = retrans;

	switch (proto) {
554
	case XPRT_TRANSPORT_TCP:
\
\"Talpey, Thomas\ 已提交
555
	case XPRT_TRANSPORT_RDMA:
556 557
		if (to->to_retries == 0)
			to->to_retries = NFS_DEF_TCP_RETRANS;
558
		if (to->to_initval == 0)
559
			to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10;
560 561 562 563
		if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
			to->to_initval = NFS_MAX_TCP_TIMEOUT;
		to->to_increment = to->to_initval;
		to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
564 565 566 567
		if (to->to_maxval > NFS_MAX_TCP_TIMEOUT)
			to->to_maxval = NFS_MAX_TCP_TIMEOUT;
		if (to->to_maxval < to->to_initval)
			to->to_maxval = to->to_initval;
568 569
		to->to_exponential = 0;
		break;
570
	case XPRT_TRANSPORT_UDP:
571 572
		if (to->to_retries == 0)
			to->to_retries = NFS_DEF_UDP_RETRANS;
573
		if (!to->to_initval)
574
			to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10;
575 576 577 578 579
		if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
			to->to_initval = NFS_MAX_UDP_TIMEOUT;
		to->to_maxval = NFS_MAX_UDP_TIMEOUT;
		to->to_exponential = 1;
		break;
580 581
	default:
		BUG();
582 583 584 585 586 587
	}
}

/*
 * Create an RPC client handle
 */
588 589 590
int nfs_create_rpc_client(struct nfs_client *clp,
			  const struct rpc_timeout *timeparms,
			  rpc_authflavor_t flavor)
591 592
{
	struct rpc_clnt		*clnt = NULL;
593
	struct rpc_create_args args = {
594
		.net		= clp->cl_net,
595
		.protocol	= clp->cl_proto,
596
		.address	= (struct sockaddr *)&clp->cl_addr,
597
		.addrsize	= clp->cl_addrlen,
598
		.timeout	= timeparms,
599 600 601 602 603
		.servername	= clp->cl_hostname,
		.program	= &nfs_program,
		.version	= clp->rpc_ops->version,
		.authflavor	= flavor,
	};
604

C
Chuck Lever 已提交
605
	if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags))
606
		args.flags |= RPC_CLNT_CREATE_DISCRTRY;
C
Chuck Lever 已提交
607
	if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags))
608 609
		args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;

610 611 612
	if (!IS_ERR(clp->cl_rpcclient))
		return 0;

613
	clnt = rpc_create(&args);
614 615
	if (IS_ERR(clnt)) {
		dprintk("%s: cannot create RPC client. Error = %ld\n",
616
				__func__, PTR_ERR(clnt));
617 618 619 620 621 622
		return PTR_ERR(clnt);
	}

	clp->cl_rpcclient = clnt;
	return 0;
}
623 624 625 626 627 628

/*
 * Version 2 or 3 client destruction
 */
static void nfs_destroy_server(struct nfs_server *server)
{
629 630
	if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) ||
			!(server->flags & NFS_MOUNT_LOCAL_FCNTL))
631
		nlmclnt_done(server->nlm_host);
632 633 634 635 636 637 638
}

/*
 * Version 2 or 3 lockd setup
 */
static int nfs_start_lockd(struct nfs_server *server)
{
639 640
	struct nlm_host *host;
	struct nfs_client *clp = server->nfs_client;
641 642 643 644 645
	struct nlmclnt_initdata nlm_init = {
		.hostname	= clp->cl_hostname,
		.address	= (struct sockaddr *)&clp->cl_addr,
		.addrlen	= clp->cl_addrlen,
		.nfs_version	= clp->rpc_ops->version,
646 647
		.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?
					1 : 0,
648
		.net		= clp->cl_net,
649
	};
650

651
	if (nlm_init.nfs_version > 3)
652
		return 0;
653 654
	if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) &&
			(server->flags & NFS_MOUNT_LOCAL_FCNTL))
655 656
		return 0;

657 658 659 660 661 662 663 664
	switch (clp->cl_proto) {
		default:
			nlm_init.protocol = IPPROTO_TCP;
			break;
		case XPRT_TRANSPORT_UDP:
			nlm_init.protocol = IPPROTO_UDP;
	}

665
	host = nlmclnt_init(&nlm_init);
666 667 668 669 670 671
	if (IS_ERR(host))
		return PTR_ERR(host);

	server->nlm_host = host;
	server->destroy = nfs_destroy_server;
	return 0;
672 673 674 675 676
}

/*
 * Create a general RPC client
 */
677
int nfs_init_server_rpcclient(struct nfs_server *server,
678 679
		const struct rpc_timeout *timeo,
		rpc_authflavor_t pseudoflavour)
680 681 682 683 684
{
	struct nfs_client *clp = server->nfs_client;

	server->client = rpc_clone_client(clp->cl_rpcclient);
	if (IS_ERR(server->client)) {
685
		dprintk("%s: couldn't create rpc_client!\n", __func__);
686 687 688
		return PTR_ERR(server->client);
	}

689 690 691 692 693
	memcpy(&server->client->cl_timeout_default,
			timeo,
			sizeof(server->client->cl_timeout_default));
	server->client->cl_timeout = &server->client->cl_timeout_default;

694 695 696 697 698
	if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) {
		struct rpc_auth *auth;

		auth = rpcauth_create(pseudoflavour, server->client);
		if (IS_ERR(auth)) {
699
			dprintk("%s: couldn't create credcache!\n", __func__);
700 701 702 703 704 705 706 707 708 709
			return PTR_ERR(auth);
		}
	}
	server->client->cl_softrtry = 0;
	if (server->flags & NFS_MOUNT_SOFT)
		server->client->cl_softrtry = 1;

	return 0;
}

710 711 712 713 714 715 716 717 718
/**
 * nfs_init_client - Initialise an NFS2 or NFS3 client
 *
 * @clp: nfs_client to initialise
 * @timeparms: timeout parameters for underlying RPC transport
 * @ip_addr: IP presentation address (not used)
 * @authflavor: authentication flavor for underlying RPC transport
 *
 * Returns pointer to an NFS client, or an ERR_PTR value.
719
 */
720 721
struct nfs_client *nfs_init_client(struct nfs_client *clp,
		    const struct rpc_timeout *timeparms,
C
Chuck Lever 已提交
722
		    const char *ip_addr, rpc_authflavor_t authflavour)
723 724 725 726 727 728
{
	int error;

	if (clp->cl_cons_state == NFS_CS_READY) {
		/* the client is already initialised */
		dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp);
729
		return clp;
730 731 732 733 734 735
	}

	/*
	 * Create a client RPC handle for doing FSSTAT with UNIX auth only
	 * - RFC 2623, sec 2.3.2
	 */
C
Chuck Lever 已提交
736
	error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX);
737 738 739
	if (error < 0)
		goto error;
	nfs_mark_client_ready(clp, NFS_CS_READY);
740
	return clp;
741 742 743

error:
	nfs_mark_client_ready(clp, error);
744
	nfs_put_client(clp);
745
	dprintk("<-- nfs_init_client() = xerror %d\n", error);
746
	return ERR_PTR(error);
747
}
B
Bryan Schumaker 已提交
748
EXPORT_SYMBOL_GPL(nfs_init_client);
749 750 751 752

/*
 * Create a version 2 or 3 client
 */
753
static int nfs_init_server(struct nfs_server *server,
754 755
			   const struct nfs_parsed_mount_data *data,
			   struct nfs_subversion *nfs_mod)
756
{
757 758
	struct nfs_client_initdata cl_init = {
		.hostname = data->nfs_server.hostname,
759
		.addr = (const struct sockaddr *)&data->nfs_server.address,
760
		.addrlen = data->nfs_server.addrlen,
761
		.nfs_mod = nfs_mod,
762
		.proto = data->nfs_server.protocol,
763
		.net = data->net,
764
	};
765
	struct rpc_timeout timeparms;
766
	struct nfs_client *clp;
767
	int error;
768 769 770

	dprintk("--> nfs_init_server()\n");

771 772
	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
			data->timeo, data->retrans);
C
Chuck Lever 已提交
773 774
	if (data->flags & NFS_MOUNT_NORESVPORT)
		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
775

776
	/* Allocate or find a client reference we can use */
C
Chuck Lever 已提交
777
	clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX);
778 779 780 781 782 783 784 785
	if (IS_ERR(clp)) {
		dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
		return PTR_ERR(clp);
	}

	server->nfs_client = clp;

	/* Initialise the client representation from the mount data */
786
	server->flags = data->flags;
787
	server->options = data->options;
788 789
	server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
		NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
790
		NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME|NFS_CAP_CHANGE_ATTR;
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806

	if (data->rsize)
		server->rsize = nfs_block_size(data->rsize, NULL);
	if (data->wsize)
		server->wsize = nfs_block_size(data->wsize, NULL);

	server->acregmin = data->acregmin * HZ;
	server->acregmax = data->acregmax * HZ;
	server->acdirmin = data->acdirmin * HZ;
	server->acdirmax = data->acdirmax * HZ;

	/* Start lockd here, before we might error out */
	error = nfs_start_lockd(server);
	if (error < 0)
		goto error;

807 808
	server->port = data->nfs_server.port;

809
	error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]);
810 811 812
	if (error < 0)
		goto error;

813 814 815 816 817 818 819 820 821 822
	/* Preserve the values of mount_server-related mount options */
	if (data->mount_server.addrlen) {
		memcpy(&server->mountd_address, &data->mount_server.address,
			data->mount_server.addrlen);
		server->mountd_addrlen = data->mount_server.addrlen;
	}
	server->mountd_version = data->mount_server.version;
	server->mountd_port = data->mount_server.port;
	server->mountd_protocol = data->mount_server.protocol;

823 824 825 826 827 828 829 830 831 832 833 834 835 836
	server->namelen  = data->namlen;
	dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp);
	return 0;

error:
	server->nfs_client = NULL;
	nfs_put_client(clp);
	dprintk("<-- nfs_init_server() = xerror %d\n", error);
	return error;
}

/*
 * Load up the server record from information gained in an fsinfo record
 */
837 838 839
static void nfs_server_set_fsinfo(struct nfs_server *server,
				  struct nfs_fh *mntfh,
				  struct nfs_fsinfo *fsinfo)
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
{
	unsigned long max_rpc_payload;

	/* Work out a lot of parameters */
	if (server->rsize == 0)
		server->rsize = nfs_block_size(fsinfo->rtpref, NULL);
	if (server->wsize == 0)
		server->wsize = nfs_block_size(fsinfo->wtpref, NULL);

	if (fsinfo->rtmax >= 512 && server->rsize > fsinfo->rtmax)
		server->rsize = nfs_block_size(fsinfo->rtmax, NULL);
	if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax)
		server->wsize = nfs_block_size(fsinfo->wtmax, NULL);

	max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
	if (server->rsize > max_rpc_payload)
		server->rsize = max_rpc_payload;
	if (server->rsize > NFS_MAX_FILE_IO_SIZE)
		server->rsize = NFS_MAX_FILE_IO_SIZE;
	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
P
Peter Zijlstra 已提交
860

861
	server->backing_dev_info.name = "nfs";
862 863 864 865 866 867 868
	server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;

	if (server->wsize > max_rpc_payload)
		server->wsize = max_rpc_payload;
	if (server->wsize > NFS_MAX_FILE_IO_SIZE)
		server->wsize = NFS_MAX_FILE_IO_SIZE;
	server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
869
	server->pnfs_blksize = fsinfo->blksize;
R
Ricardo Labiaga 已提交
870

871 872 873
	server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);

	server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
B
Bryan Schumaker 已提交
874 875
	if (server->dtsize > PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES)
		server->dtsize = PAGE_CACHE_SIZE * NFS_MAX_READDIR_PAGES;
876 877 878 879 880 881 882 883 884 885
	if (server->dtsize > server->rsize)
		server->dtsize = server->rsize;

	if (server->flags & NFS_MOUNT_NOAC) {
		server->acregmin = server->acregmax = 0;
		server->acdirmin = server->acdirmax = 0;
	}

	server->maxfilesize = fsinfo->maxfilesize;

R
Ricardo Labiaga 已提交
886 887
	server->time_delta = fsinfo->time_delta;

888 889 890 891 892 893 894
	/* We're airborne Set socket buffersize */
	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
}

/*
 * Probe filesystem information, including the FSID on v2/v3
 */
895
int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
896 897 898 899 900 901 902 903 904 905 906 907 908 909
{
	struct nfs_fsinfo fsinfo;
	struct nfs_client *clp = server->nfs_client;
	int error;

	dprintk("--> nfs_probe_fsinfo()\n");

	if (clp->rpc_ops->set_capabilities != NULL) {
		error = clp->rpc_ops->set_capabilities(server, mntfh);
		if (error < 0)
			goto out_error;
	}

	fsinfo.fattr = fattr;
R
Ricardo Labiaga 已提交
910
	fsinfo.layouttype = 0;
911 912 913 914
	error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
	if (error < 0)
		goto out_error;

915
	nfs_server_set_fsinfo(server, mntfh, &fsinfo);
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938

	/* Get some general file system info */
	if (server->namelen == 0) {
		struct nfs_pathconf pathinfo;

		pathinfo.fattr = fattr;
		nfs_fattr_init(fattr);

		if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0)
			server->namelen = pathinfo.max_namelen;
	}

	dprintk("<-- nfs_probe_fsinfo() = 0\n");
	return 0;

out_error:
	dprintk("nfs_probe_fsinfo: error = %d\n", -error);
	return error;
}

/*
 * Copy useful information when duplicating a server record
 */
939
void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
940 941
{
	target->flags = source->flags;
942 943
	target->rsize = source->rsize;
	target->wsize = source->wsize;
944 945 946 947 948
	target->acregmin = source->acregmin;
	target->acregmax = source->acregmax;
	target->acdirmin = source->acdirmin;
	target->acdirmax = source->acdirmax;
	target->caps = source->caps;
949
	target->options = source->options;
950 951
}

952
void nfs_server_insert_lists(struct nfs_server *server)
953 954
{
	struct nfs_client *clp = server->nfs_client;
955
	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
956

957
	spin_lock(&nn->nfs_client_lock);
958
	list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
959
	list_add_tail(&server->master_link, &nn->nfs_volume_list);
960
	clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
961
	spin_unlock(&nn->nfs_client_lock);
962 963 964 965 966

}

static void nfs_server_remove_lists(struct nfs_server *server)
{
967
	struct nfs_client *clp = server->nfs_client;
968
	struct nfs_net *nn;
969

970 971
	if (clp == NULL)
		return;
972
	nn = net_generic(clp->cl_net, nfs_net_id);
973
	spin_lock(&nn->nfs_client_lock);
974
	list_del_rcu(&server->client_link);
975
	if (list_empty(&clp->cl_superblocks))
976
		set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
977
	list_del(&server->master_link);
978
	spin_unlock(&nn->nfs_client_lock);
979 980 981 982

	synchronize_rcu();
}

983 984 985
/*
 * Allocate and initialise a server record
 */
986
struct nfs_server *nfs_alloc_server(void)
987 988 989 990 991 992 993 994 995 996 997 998
{
	struct nfs_server *server;

	server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
	if (!server)
		return NULL;

	server->client = server->client_acl = ERR_PTR(-EINVAL);

	/* Zero out the NFS state stuff */
	INIT_LIST_HEAD(&server->client_link);
	INIT_LIST_HEAD(&server->master_link);
999
	INIT_LIST_HEAD(&server->delegations);
1000
	INIT_LIST_HEAD(&server->layouts);
1001
	INIT_LIST_HEAD(&server->state_owners_lru);
1002

1003 1004
	atomic_set(&server->active, 0);

1005 1006 1007 1008 1009 1010
	server->io_stats = nfs_alloc_iostats();
	if (!server->io_stats) {
		kfree(server);
		return NULL;
	}

1011 1012 1013 1014 1015 1016
	if (bdi_init(&server->backing_dev_info)) {
		nfs_free_iostats(server->io_stats);
		kfree(server);
		return NULL;
	}

1017
	ida_init(&server->openowner_id);
1018
	ida_init(&server->lockowner_id);
F
Fred Isaman 已提交
1019 1020
	pnfs_init_server(server);

1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
	return server;
}

/*
 * Free up a server record
 */
void nfs_free_server(struct nfs_server *server)
{
	dprintk("--> nfs_free_server()\n");

1031
	nfs_server_remove_lists(server);
1032 1033 1034

	if (server->destroy != NULL)
		server->destroy(server);
1035 1036 1037

	if (!IS_ERR(server->client_acl))
		rpc_shutdown_client(server->client_acl);
1038 1039 1040 1041 1042
	if (!IS_ERR(server->client))
		rpc_shutdown_client(server->client);

	nfs_put_client(server->nfs_client);

1043
	ida_destroy(&server->lockowner_id);
1044
	ida_destroy(&server->openowner_id);
1045
	nfs_free_iostats(server->io_stats);
P
Peter Zijlstra 已提交
1046
	bdi_destroy(&server->backing_dev_info);
1047 1048 1049 1050 1051 1052 1053 1054 1055
	kfree(server);
	nfs_release_automount_timer();
	dprintk("<-- nfs_free_server()\n");
}

/*
 * Create a version 2 or 3 volume record
 * - keyed on server and FSID
 */
1056
struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
1057
				     struct nfs_subversion *nfs_mod)
1058 1059
{
	struct nfs_server *server;
1060
	struct nfs_fattr *fattr;
1061 1062 1063 1064 1065 1066
	int error;

	server = nfs_alloc_server();
	if (!server)
		return ERR_PTR(-ENOMEM);

1067 1068 1069 1070 1071
	error = -ENOMEM;
	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		goto error;

1072
	/* Get a client representation */
1073
	error = nfs_init_server(server, mount_info->parsed, nfs_mod);
1074 1075 1076 1077 1078 1079 1080 1081
	if (error < 0)
		goto error;

	BUG_ON(!server->nfs_client);
	BUG_ON(!server->nfs_client->rpc_ops);
	BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);

	/* Probe the root fh to retrieve its FSID */
1082
	error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
1083 1084
	if (error < 0)
		goto error;
1085 1086 1087
	if (server->nfs_client->rpc_ops->version == 3) {
		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
			server->namelen = NFS3_MAXNAMLEN;
1088
		if (!(mount_info->parsed->flags & NFS_MOUNT_NORDIRPLUS))
1089 1090 1091 1092 1093 1094
			server->caps |= NFS_CAP_READDIRPLUS;
	} else {
		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
			server->namelen = NFS2_MAXNAMLEN;
	}

1095
	if (!(fattr->valid & NFS_ATTR_FATTR)) {
1096
		error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr);
1097 1098 1099 1100 1101
		if (error < 0) {
			dprintk("nfs_create_server: getattr error = %d\n", -error);
			goto error;
		}
	}
1102
	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
1103

1104 1105 1106
	dprintk("Server FSID: %llx:%llx\n",
		(unsigned long long) server->fsid.major,
		(unsigned long long) server->fsid.minor);
1107

1108
	nfs_server_insert_lists(server);
1109
	server->mount_time = jiffies;
1110
	nfs_free_fattr(fattr);
1111 1112 1113
	return server;

error:
1114
	nfs_free_fattr(fattr);
1115 1116 1117
	nfs_free_server(server);
	return ERR_PTR(error);
}
B
Bryan Schumaker 已提交
1118
EXPORT_SYMBOL_GPL(nfs_create_server);
1119 1120 1121 1122 1123 1124

/*
 * Clone an NFS2, NFS3 or NFS4 server record
 */
struct nfs_server *nfs_clone_server(struct nfs_server *source,
				    struct nfs_fh *fh,
1125 1126
				    struct nfs_fattr *fattr,
				    rpc_authflavor_t flavor)
1127 1128
{
	struct nfs_server *server;
1129
	struct nfs_fattr *fattr_fsinfo;
1130 1131 1132
	int error;

	dprintk("--> nfs_clone_server(,%llx:%llx,)\n",
1133 1134
		(unsigned long long) fattr->fsid.major,
		(unsigned long long) fattr->fsid.minor);
1135 1136 1137 1138 1139

	server = nfs_alloc_server();
	if (!server)
		return ERR_PTR(-ENOMEM);

1140 1141 1142 1143 1144
	error = -ENOMEM;
	fattr_fsinfo = nfs_alloc_fattr();
	if (fattr_fsinfo == NULL)
		goto out_free_server;

1145 1146
	/* Copy data from the source */
	server->nfs_client = source->nfs_client;
1147
	server->destroy = source->destroy;
1148 1149 1150 1151 1152
	atomic_inc(&server->nfs_client->cl_count);
	nfs_server_copy_userdata(server, source);

	server->fsid = fattr->fsid;

1153 1154
	error = nfs_init_server_rpcclient(server,
			source->client->cl_timeout,
1155
			flavor);
1156 1157 1158 1159
	if (error < 0)
		goto out_free_server;

	/* probe the filesystem info for this server filesystem */
1160
	error = nfs_probe_fsinfo(server, fh, fattr_fsinfo);
1161 1162 1163
	if (error < 0)
		goto out_free_server;

1164 1165 1166
	if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
		server->namelen = NFS4_MAXNAMLEN;

1167
	dprintk("Cloned FSID: %llx:%llx\n",
1168 1169
		(unsigned long long) server->fsid.major,
		(unsigned long long) server->fsid.minor);
1170 1171 1172 1173 1174

	error = nfs_start_lockd(server);
	if (error < 0)
		goto out_free_server;

1175
	nfs_server_insert_lists(server);
1176 1177
	server->mount_time = jiffies;

1178
	nfs_free_fattr(fattr_fsinfo);
1179 1180 1181 1182
	dprintk("<-- nfs_clone_server() = %p\n", server);
	return server;

out_free_server:
1183
	nfs_free_fattr(fattr_fsinfo);
1184 1185 1186 1187
	nfs_free_server(server);
	dprintk("<-- nfs_clone_server() = error %d\n", error);
	return ERR_PTR(error);
}
B
Bryan Schumaker 已提交
1188
EXPORT_SYMBOL_GPL(nfs_clone_server);
1189

1190 1191 1192 1193 1194
void nfs_clients_init(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);

	INIT_LIST_HEAD(&nn->nfs_client_list);
1195
	INIT_LIST_HEAD(&nn->nfs_volume_list);
1196 1197 1198
#ifdef CONFIG_NFS_V4
	idr_init(&nn->cb_ident_idr);
#endif
1199
	spin_lock_init(&nn->nfs_client_lock);
1200
	nn->boot_time = CURRENT_TIME;
1201 1202
}

1203 1204 1205 1206 1207 1208 1209 1210 1211
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_fs_nfs;

static int nfs_server_list_open(struct inode *inode, struct file *file);
static void *nfs_server_list_start(struct seq_file *p, loff_t *pos);
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos);
static void nfs_server_list_stop(struct seq_file *p, void *v);
static int nfs_server_list_show(struct seq_file *m, void *v);

J
James Morris 已提交
1212
static const struct seq_operations nfs_server_list_ops = {
1213 1214 1215 1216 1217 1218
	.start	= nfs_server_list_start,
	.next	= nfs_server_list_next,
	.stop	= nfs_server_list_stop,
	.show	= nfs_server_list_show,
};

1219
static const struct file_operations nfs_server_list_fops = {
1220 1221 1222 1223
	.open		= nfs_server_list_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
1224
	.owner		= THIS_MODULE,
1225 1226 1227 1228 1229 1230 1231 1232
};

static int nfs_volume_list_open(struct inode *inode, struct file *file);
static void *nfs_volume_list_start(struct seq_file *p, loff_t *pos);
static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos);
static void nfs_volume_list_stop(struct seq_file *p, void *v);
static int nfs_volume_list_show(struct seq_file *m, void *v);

J
James Morris 已提交
1233
static const struct seq_operations nfs_volume_list_ops = {
1234 1235 1236 1237 1238 1239
	.start	= nfs_volume_list_start,
	.next	= nfs_volume_list_next,
	.stop	= nfs_volume_list_stop,
	.show	= nfs_volume_list_show,
};

1240
static const struct file_operations nfs_volume_list_fops = {
1241 1242 1243 1244
	.open		= nfs_volume_list_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
1245
	.owner		= THIS_MODULE,
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
};

/*
 * open "/proc/fs/nfsfs/servers" which provides a summary of servers with which
 * we're dealing
 */
static int nfs_server_list_open(struct inode *inode, struct file *file)
{
	struct seq_file *m;
	int ret;
1256 1257
	struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
	struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
1258 1259 1260 1261 1262 1263

	ret = seq_open(file, &nfs_server_list_ops);
	if (ret < 0)
		return ret;

	m = file->private_data;
1264
	m->private = net;
1265 1266 1267 1268 1269 1270 1271 1272 1273

	return 0;
}

/*
 * set up the iterator to start reading from the server list and return the first item
 */
static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
{
1274 1275
	struct nfs_net *nn = net_generic(m->private, nfs_net_id);

1276
	/* lock the list against modification */
1277
	spin_lock(&nn->nfs_client_lock);
1278
	return seq_list_start_head(&nn->nfs_client_list, *_pos);
1279 1280 1281 1282 1283 1284 1285
}

/*
 * move to next server
 */
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
{
1286 1287 1288
	struct nfs_net *nn = net_generic(p->private, nfs_net_id);

	return seq_list_next(v, &nn->nfs_client_list, pos);
1289 1290 1291 1292 1293 1294 1295
}

/*
 * clean up after reading from the transports list
 */
static void nfs_server_list_stop(struct seq_file *p, void *v)
{
1296 1297 1298
	struct nfs_net *nn = net_generic(p->private, nfs_net_id);

	spin_unlock(&nn->nfs_client_lock);
1299 1300 1301 1302 1303 1304 1305 1306
}

/*
 * display a header line followed by a load of call lines
 */
static int nfs_server_list_show(struct seq_file *m, void *v)
{
	struct nfs_client *clp;
1307
	struct nfs_net *nn = net_generic(m->private, nfs_net_id);
1308 1309

	/* display header on line 1 */
1310
	if (v == &nn->nfs_client_list) {
1311 1312 1313 1314 1315 1316 1317
		seq_puts(m, "NV SERVER   PORT USE HOSTNAME\n");
		return 0;
	}

	/* display one transport per line on subsequent lines */
	clp = list_entry(v, struct nfs_client, cl_share_link);

1318 1319 1320 1321
	/* Check if the client is initialized */
	if (clp->cl_cons_state != NFS_CS_READY)
		return 0;

1322
	rcu_read_lock();
1323
	seq_printf(m, "v%u %s %s %3d %s\n",
1324
		   clp->rpc_ops->version,
1325 1326
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1327 1328
		   atomic_read(&clp->cl_count),
		   clp->cl_hostname);
1329
	rcu_read_unlock();
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340

	return 0;
}

/*
 * open "/proc/fs/nfsfs/volumes" which provides a summary of extant volumes
 */
static int nfs_volume_list_open(struct inode *inode, struct file *file)
{
	struct seq_file *m;
	int ret;
1341 1342
	struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
	struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
1343 1344 1345 1346 1347 1348

	ret = seq_open(file, &nfs_volume_list_ops);
	if (ret < 0)
		return ret;

	m = file->private_data;
1349
	m->private = net;
1350 1351 1352 1353 1354 1355 1356 1357 1358

	return 0;
}

/*
 * set up the iterator to start reading from the volume list and return the first item
 */
static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
{
1359 1360
	struct nfs_net *nn = net_generic(m->private, nfs_net_id);

1361
	/* lock the list against modification */
1362
	spin_lock(&nn->nfs_client_lock);
1363
	return seq_list_start_head(&nn->nfs_volume_list, *_pos);
1364 1365 1366 1367 1368 1369 1370
}

/*
 * move to next volume
 */
static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
{
1371 1372 1373
	struct nfs_net *nn = net_generic(p->private, nfs_net_id);

	return seq_list_next(v, &nn->nfs_volume_list, pos);
1374 1375 1376 1377 1378 1379 1380
}

/*
 * clean up after reading from the transports list
 */
static void nfs_volume_list_stop(struct seq_file *p, void *v)
{
1381 1382 1383
	struct nfs_net *nn = net_generic(p->private, nfs_net_id);

	spin_unlock(&nn->nfs_client_lock);
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
}

/*
 * display a header line followed by a load of call lines
 */
static int nfs_volume_list_show(struct seq_file *m, void *v)
{
	struct nfs_server *server;
	struct nfs_client *clp;
	char dev[8], fsid[17];
1394
	struct nfs_net *nn = net_generic(m->private, nfs_net_id);
1395 1396

	/* display header on line 1 */
1397
	if (v == &nn->nfs_volume_list) {
D
David Howells 已提交
1398
		seq_puts(m, "NV SERVER   PORT DEV     FSID              FSC\n");
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
		return 0;
	}
	/* display one transport per line on subsequent lines */
	server = list_entry(v, struct nfs_server, master_link);
	clp = server->nfs_client;

	snprintf(dev, 8, "%u:%u",
		 MAJOR(server->s_dev), MINOR(server->s_dev));

	snprintf(fsid, 17, "%llx:%llx",
1409 1410
		 (unsigned long long) server->fsid.major,
		 (unsigned long long) server->fsid.minor);
1411

1412
	rcu_read_lock();
D
David Howells 已提交
1413
	seq_printf(m, "v%u %s %s %-7s %-17s %s\n",
1414
		   clp->rpc_ops->version,
1415 1416
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1417
		   dev,
D
David Howells 已提交
1418 1419
		   fsid,
		   nfs_server_fscache_state(server));
1420
	rcu_read_unlock();
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431

	return 0;
}

/*
 * initialise the /proc/fs/nfsfs/ directory
 */
int __init nfs_fs_proc_init(void)
{
	struct proc_dir_entry *p;

A
Alexey Dobriyan 已提交
1432
	proc_fs_nfs = proc_mkdir("fs/nfsfs", NULL);
1433 1434 1435 1436
	if (!proc_fs_nfs)
		goto error_0;

	/* a file of servers with which we're dealing */
1437 1438
	p = proc_create("servers", S_IFREG|S_IRUGO,
			proc_fs_nfs, &nfs_server_list_fops);
1439 1440 1441 1442
	if (!p)
		goto error_1;

	/* a file of volumes that we have mounted */
1443 1444
	p = proc_create("volumes", S_IFREG|S_IRUGO,
			proc_fs_nfs, &nfs_volume_list_fops);
1445 1446 1447 1448 1449 1450 1451
	if (!p)
		goto error_2;
	return 0;

error_2:
	remove_proc_entry("servers", proc_fs_nfs);
error_1:
A
Alexey Dobriyan 已提交
1452
	remove_proc_entry("fs/nfsfs", NULL);
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
error_0:
	return -ENOMEM;
}

/*
 * clean up the /proc/fs/nfsfs/ directory
 */
void nfs_fs_proc_exit(void)
{
	remove_proc_entry("volumes", proc_fs_nfs);
	remove_proc_entry("servers", proc_fs_nfs);
A
Alexey Dobriyan 已提交
1464
	remove_proc_entry("fs/nfsfs", NULL);
1465 1466 1467
}

#endif /* CONFIG_PROC_FS */