client.c 34.1 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
#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>
23
#include <linux/sunrpc/addr.h>
24 25 26
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/metrics.h>
27
#include <linux/sunrpc/xprtsock.h>
\
\"Talpey, Thomas\ 已提交
28
#include <linux/sunrpc/xprtrdma.h>
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/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
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;
		}
96
	}
97 98

	spin_unlock(&nfs_version_lock);
99
	return ERR_PTR(-EPROTONOSUPPORT);
100 101 102 103 104 105 106 107
}

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);
108
		request_module("nfsv%d", version);
109 110 111 112
		nfs = find_nfs_version(version);
		mutex_unlock(&nfs_version_mutex);
	}

113 114
	if (!IS_ERR(nfs) && !try_module_get(nfs->owner))
		return ERR_PTR(-EAGAIN);
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
	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);

145 146 147 148 149 150
/*
 * Allocate a shared client record
 *
 * Since these are allocated/deallocated very rarely, we don't
 * bother putting them in a slab cache...
 */
151
struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
152 153
{
	struct nfs_client *clp;
154
	struct rpc_cred *cred;
155
	int err = -ENOMEM;
156 157 158 159

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

160
	clp->cl_nfs_mod = cl_init->nfs_mod;
161 162
	if (!try_module_get(clp->cl_nfs_mod->owner))
		goto error_dealloc;
163 164

	clp->rpc_ops = clp->cl_nfs_mod->rpc_ops;
165

166 167 168
	atomic_set(&clp->cl_count, 1);
	clp->cl_cons_state = NFS_CS_INITING;

169 170
	memcpy(&clp->cl_addr, cl_init->addr, cl_init->addrlen);
	clp->cl_addrlen = cl_init->addrlen;
171

172
	if (cl_init->hostname) {
173
		err = -ENOMEM;
174
		clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL);
175
		if (!clp->cl_hostname)
176
			goto error_cleanup;
177 178 179 180 181
	}

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

182
	clp->cl_proto = cl_init->proto;
183
	clp->cl_net = get_net(cl_init->net);
184

185
	cred = rpc_lookup_machine_cred("*");
186 187
	if (!IS_ERR(cred))
		clp->cl_machine_cred = cred;
188 189
	nfs_fscache_get_client_cookie(clp);

190 191
	return clp;

192
error_cleanup:
193
	put_nfs_version(clp->cl_nfs_mod);
194
error_dealloc:
195 196
	kfree(clp);
error_0:
197
	return ERR_PTR(err);
198
}
B
Bryan Schumaker 已提交
199
EXPORT_SYMBOL_GPL(nfs_alloc_client);
200

B
Bryan Schumaker 已提交
201
#if IS_ENABLED(CONFIG_NFS_V4)
202
void nfs_cleanup_cb_ident_idr(struct net *net)
A
Andy Adamson 已提交
203
{
204 205 206
	struct nfs_net *nn = net_generic(net, nfs_net_id);

	idr_destroy(&nn->cb_ident_idr);
A
Andy Adamson 已提交
207 208 209 210 211
}

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

A
Andy Adamson 已提交
214
	if (clp->cl_cb_ident)
215
		idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
A
Andy Adamson 已提交
216 217
}

F
Fred Isaman 已提交
218 219 220 221 222
static void pnfs_init_server(struct nfs_server *server)
{
	rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC");
}

223
#else
224
void nfs_cleanup_cb_ident_idr(struct net *net)
A
Andy Adamson 已提交
225 226 227 228 229 230
{
}

static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
{
}
F
Fred Isaman 已提交
231 232 233 234 235

static void pnfs_init_server(struct nfs_server *server)
{
}

236
#endif /* CONFIG_NFS_V4 */
237

238 239 240
/*
 * Destroy a shared client record
 */
241
void nfs_free_client(struct nfs_client *clp)
242
{
243
	dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version);
244

245 246
	nfs_fscache_release_client_cookie(clp);

247 248 249 250
	/* -EIO all pending I/O */
	if (!IS_ERR(clp->cl_rpcclient))
		rpc_shutdown_client(clp->cl_rpcclient);

251 252 253
	if (clp->cl_machine_cred != NULL)
		put_rpccred(clp->cl_machine_cred);

254
	put_net(clp->cl_net);
255
	put_nfs_version(clp->cl_nfs_mod);
256
	kfree(clp->cl_hostname);
257
	kfree(clp->cl_acceptor);
258 259 260 261
	kfree(clp);

	dprintk("<-- nfs_free_client()\n");
}
B
Bryan Schumaker 已提交
262
EXPORT_SYMBOL_GPL(nfs_free_client);
263 264 265 266 267 268

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

D
David Howells 已提交
271 272 273
	if (!clp)
		return;

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

277
	if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {
278
		list_del(&clp->cl_share_link);
A
Andy Adamson 已提交
279
		nfs_cb_idr_remove_locked(clp);
280
		spin_unlock(&nn->nfs_client_lock);
281

282
		WARN_ON_ONCE(!list_empty(&clp->cl_superblocks));
283

284
		clp->rpc_ops->free_client(clp);
285 286
	}
}
287
EXPORT_SYMBOL_GPL(nfs_put_client);
288 289

/*
290 291
 * Find an nfs_client on the list that matches the initialisation data
 * that is supplied.
292
 */
293
static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data)
294 295
{
	struct nfs_client *clp;
I
Ian Dall 已提交
296
	const struct sockaddr *sap = data->addr;
297
	struct nfs_net *nn = net_generic(data->net, nfs_net_id);
298

299
	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
I
Ian Dall 已提交
300
	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
301 302 303 304 305
		/* 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 */
306
		if (clp->rpc_ops != data->nfs_mod->rpc_ops)
307 308
			continue;

309 310
		if (clp->cl_proto != data->proto)
			continue;
311 312 313
		/* Match nfsv4 minorversion */
		if (clp->cl_minorversion != data->minorversion)
			continue;
314
		/* Match the full socket address */
315
		if (!rpc_cmp_addr_port(sap, clap))
316 317 318 319
			continue;

		atomic_inc(&clp->cl_count);
		return clp;
320
	}
321
	return NULL;
322 323
}

324 325
static bool nfs_client_init_is_complete(const struct nfs_client *clp)
{
326
	return clp->cl_cons_state <= NFS_CS_READY;
327 328 329 330 331 332 333
}

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));
}
B
Bryan Schumaker 已提交
334
EXPORT_SYMBOL_GPL(nfs_wait_client_init_complete);
335

336 337 338 339 340 341 342 343 344
/*
 * 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;

345
	error = nfs_wait_client_init_complete(clp);
346 347 348 349 350 351 352 353 354 355 356
	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);
	}

357 358
	smp_rmb();

359 360 361 362 363
	dprintk("<-- %s found nfs_client %p for %s\n",
		__func__, clp, cl_init->hostname ?: "");
	return clp;
}

364 365 366 367
/*
 * Look up a client by IP address and protocol version
 * - creates a new record if one doesn't yet exist
 */
368
struct nfs_client *
369 370 371
nfs_get_client(const struct nfs_client_initdata *cl_init,
	       const struct rpc_timeout *timeparms,
	       const char *ip_addr,
C
Chuck Lever 已提交
372
	       rpc_authflavor_t authflavour)
373 374
{
	struct nfs_client *clp, *new = NULL;
375
	struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
376
	const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops;
377

P
Peng Tao 已提交
378 379 380 381 382
	if (cl_init->hostname == NULL) {
		WARN_ON(1);
		return NULL;
	}

383
	dprintk("--> nfs_get_client(%s,v%u)\n",
P
Peng Tao 已提交
384
		cl_init->hostname, rpc_ops->version);
385 386 387

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

390
		clp = nfs_match_client(cl_init);
391 392 393
		if (clp) {
			spin_unlock(&nn->nfs_client_lock);
			if (new)
394
				new->rpc_ops->free_client(new);
395 396
			return nfs_found_client(cl_init, clp);
		}
397
		if (new) {
398 399
			list_add_tail(&new->cl_share_link,
					&nn->nfs_client_list);
400
			spin_unlock(&nn->nfs_client_lock);
C
Chuck Lever 已提交
401
			new->cl_flags = cl_init->init_flags;
402
			return rpc_ops->init_client(new, timeparms, ip_addr);
403
		}
404

405
		spin_unlock(&nn->nfs_client_lock);
406

407
		new = rpc_ops->alloc_client(cl_init);
408
	} while (!IS_ERR(new));
409

410
	dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n",
P
Peng Tao 已提交
411
		cl_init->hostname, PTR_ERR(new));
412
	return new;
413
}
B
Bryan Schumaker 已提交
414
EXPORT_SYMBOL_GPL(nfs_get_client);
415 416 417 418

/*
 * Mark a server as ready or failed
 */
419
void nfs_mark_client_ready(struct nfs_client *clp, int state)
420
{
421
	smp_wmb();
422 423 424
	clp->cl_cons_state = state;
	wake_up_all(&nfs_client_active_wq);
}
B
Bryan Schumaker 已提交
425
EXPORT_SYMBOL_GPL(nfs_mark_client_ready);
426 427 428 429

/*
 * Initialise the timeout values for a connection
 */
430
void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
431 432 433 434 435 436
				    unsigned int timeo, unsigned int retrans)
{
	to->to_initval = timeo * HZ / 10;
	to->to_retries = retrans;

	switch (proto) {
437
	case XPRT_TRANSPORT_TCP:
\
\"Talpey, Thomas\ 已提交
438
	case XPRT_TRANSPORT_RDMA:
439 440
		if (to->to_retries == 0)
			to->to_retries = NFS_DEF_TCP_RETRANS;
441
		if (to->to_initval == 0)
442
			to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10;
443 444 445 446
		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);
447 448 449 450
		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;
451 452
		to->to_exponential = 0;
		break;
453
	case XPRT_TRANSPORT_UDP:
454 455
		if (to->to_retries == 0)
			to->to_retries = NFS_DEF_UDP_RETRANS;
456
		if (!to->to_initval)
457
			to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10;
458 459 460 461 462
		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;
463 464
	default:
		BUG();
465 466
	}
}
B
Bryan Schumaker 已提交
467
EXPORT_SYMBOL_GPL(nfs_init_timeout_values);
468 469 470 471

/*
 * Create an RPC client handle
 */
472 473 474
int nfs_create_rpc_client(struct nfs_client *clp,
			  const struct rpc_timeout *timeparms,
			  rpc_authflavor_t flavor)
475 476
{
	struct rpc_clnt		*clnt = NULL;
477
	struct rpc_create_args args = {
478
		.net		= clp->cl_net,
479
		.protocol	= clp->cl_proto,
480
		.address	= (struct sockaddr *)&clp->cl_addr,
481
		.addrsize	= clp->cl_addrlen,
482
		.timeout	= timeparms,
483 484 485 486 487
		.servername	= clp->cl_hostname,
		.program	= &nfs_program,
		.version	= clp->rpc_ops->version,
		.authflavor	= flavor,
	};
488

C
Chuck Lever 已提交
489
	if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags))
490
		args.flags |= RPC_CLNT_CREATE_DISCRTRY;
491 492
	if (test_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags))
		args.flags |= RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT;
C
Chuck Lever 已提交
493
	if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags))
494
		args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
495 496
	if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags))
		args.flags |= RPC_CLNT_CREATE_INFINITE_SLOTS;
497

498 499 500
	if (!IS_ERR(clp->cl_rpcclient))
		return 0;

501
	clnt = rpc_create(&args);
502 503
	if (IS_ERR(clnt)) {
		dprintk("%s: cannot create RPC client. Error = %ld\n",
504
				__func__, PTR_ERR(clnt));
505 506 507 508 509 510
		return PTR_ERR(clnt);
	}

	clp->cl_rpcclient = clnt;
	return 0;
}
B
Bryan Schumaker 已提交
511
EXPORT_SYMBOL_GPL(nfs_create_rpc_client);
512 513 514 515 516 517

/*
 * Version 2 or 3 client destruction
 */
static void nfs_destroy_server(struct nfs_server *server)
{
518
	if (server->nlm_host)
519
		nlmclnt_done(server->nlm_host);
520 521 522 523 524 525 526
}

/*
 * Version 2 or 3 lockd setup
 */
static int nfs_start_lockd(struct nfs_server *server)
{
527 528
	struct nlm_host *host;
	struct nfs_client *clp = server->nfs_client;
529 530 531 532 533
	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,
534 535
		.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?
					1 : 0,
536
		.net		= clp->cl_net,
537
	};
538

539
	if (nlm_init.nfs_version > 3)
540
		return 0;
541 542
	if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) &&
			(server->flags & NFS_MOUNT_LOCAL_FCNTL))
543 544
		return 0;

545 546 547 548 549 550 551 552
	switch (clp->cl_proto) {
		default:
			nlm_init.protocol = IPPROTO_TCP;
			break;
		case XPRT_TRANSPORT_UDP:
			nlm_init.protocol = IPPROTO_UDP;
	}

553
	host = nlmclnt_init(&nlm_init);
554 555 556 557 558 559
	if (IS_ERR(host))
		return PTR_ERR(host);

	server->nlm_host = host;
	server->destroy = nfs_destroy_server;
	return 0;
560 561 562 563 564
}

/*
 * Create a general RPC client
 */
565
int nfs_init_server_rpcclient(struct nfs_server *server,
566 567
		const struct rpc_timeout *timeo,
		rpc_authflavor_t pseudoflavour)
568 569 570
{
	struct nfs_client *clp = server->nfs_client;

571 572
	server->client = rpc_clone_client_set_auth(clp->cl_rpcclient,
							pseudoflavour);
573
	if (IS_ERR(server->client)) {
574
		dprintk("%s: couldn't create rpc_client!\n", __func__);
575 576 577
		return PTR_ERR(server->client);
	}

578 579 580 581
	memcpy(&server->client->cl_timeout_default,
			timeo,
			sizeof(server->client->cl_timeout_default));
	server->client->cl_timeout = &server->client->cl_timeout_default;
582 583 584 585 586 587
	server->client->cl_softrtry = 0;
	if (server->flags & NFS_MOUNT_SOFT)
		server->client->cl_softrtry = 1;

	return 0;
}
B
Bryan Schumaker 已提交
588
EXPORT_SYMBOL_GPL(nfs_init_server_rpcclient);
589

590 591 592 593 594 595 596 597
/**
 * 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)
 *
 * Returns pointer to an NFS client, or an ERR_PTR value.
598
 */
599 600
struct nfs_client *nfs_init_client(struct nfs_client *clp,
		    const struct rpc_timeout *timeparms,
601
		    const char *ip_addr)
602 603 604 605 606 607
{
	int error;

	if (clp->cl_cons_state == NFS_CS_READY) {
		/* the client is already initialised */
		dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp);
608
		return clp;
609 610 611 612 613 614
	}

	/*
	 * Create a client RPC handle for doing FSSTAT with UNIX auth only
	 * - RFC 2623, sec 2.3.2
	 */
C
Chuck Lever 已提交
615
	error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX);
616 617 618
	if (error < 0)
		goto error;
	nfs_mark_client_ready(clp, NFS_CS_READY);
619
	return clp;
620 621 622

error:
	nfs_mark_client_ready(clp, error);
623
	nfs_put_client(clp);
624
	dprintk("<-- nfs_init_client() = xerror %d\n", error);
625
	return ERR_PTR(error);
626
}
B
Bryan Schumaker 已提交
627
EXPORT_SYMBOL_GPL(nfs_init_client);
628 629 630 631

/*
 * Create a version 2 or 3 client
 */
632
static int nfs_init_server(struct nfs_server *server,
633 634
			   const struct nfs_parsed_mount_data *data,
			   struct nfs_subversion *nfs_mod)
635
{
636 637
	struct nfs_client_initdata cl_init = {
		.hostname = data->nfs_server.hostname,
638
		.addr = (const struct sockaddr *)&data->nfs_server.address,
639
		.addrlen = data->nfs_server.addrlen,
640
		.nfs_mod = nfs_mod,
641
		.proto = data->nfs_server.protocol,
642
		.net = data->net,
643
	};
644
	struct rpc_timeout timeparms;
645
	struct nfs_client *clp;
646
	int error;
647 648 649

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

650 651
	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
			data->timeo, data->retrans);
C
Chuck Lever 已提交
652 653
	if (data->flags & NFS_MOUNT_NORESVPORT)
		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
654

655
	/* Allocate or find a client reference we can use */
C
Chuck Lever 已提交
656
	clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX);
657 658 659 660 661 662 663 664
	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 */
665
	server->flags = data->flags;
666
	server->options = data->options;
667 668
	server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
		NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
669
		NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685

	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;

686
	server->port = data->nfs_server.port;
687
	server->auth_info = data->auth_info;
688

689 690
	error = nfs_init_server_rpcclient(server, &timeparms,
					  data->selected_flavor);
691 692 693
	if (error < 0)
		goto error;

694 695 696 697 698 699 700 701 702 703
	/* 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;

704 705 706 707 708 709 710 711 712 713 714 715 716 717
	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
 */
718 719
static void nfs_server_set_fsinfo(struct nfs_server *server,
				  struct nfs_fsinfo *fsinfo)
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
{
	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;
739
	server->rpages = (server->rsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
P
Peter Zijlstra 已提交
740

741
	server->backing_dev_info.name = "nfs";
742 743 744 745 746 747
	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;
748
	server->wpages = (server->wsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
R
Ricardo Labiaga 已提交
749

750 751 752
	server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);

	server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
753 754
	if (server->dtsize > PAGE_SIZE * NFS_MAX_READDIR_PAGES)
		server->dtsize = PAGE_SIZE * NFS_MAX_READDIR_PAGES;
755 756 757 758 759 760 761 762 763 764
	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 已提交
765 766
	server->time_delta = fsinfo->time_delta;

767
	server->clone_blksize = fsinfo->clone_blksize;
768 769 770 771 772 773 774
	/* 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
 */
775
int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
776 777 778 779 780 781 782 783 784 785 786 787 788 789
{
	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 已提交
790
	fsinfo.layouttype = 0;
791 792 793 794
	error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
	if (error < 0)
		goto out_error;

795
	nfs_server_set_fsinfo(server, &fsinfo);
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814

	/* 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;
}
B
Bryan Schumaker 已提交
815
EXPORT_SYMBOL_GPL(nfs_probe_fsinfo);
816 817 818 819

/*
 * Copy useful information when duplicating a server record
 */
820
void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
821 822
{
	target->flags = source->flags;
823 824
	target->rsize = source->rsize;
	target->wsize = source->wsize;
825 826 827 828 829
	target->acregmin = source->acregmin;
	target->acregmax = source->acregmax;
	target->acdirmin = source->acdirmin;
	target->acdirmax = source->acdirmax;
	target->caps = source->caps;
830
	target->options = source->options;
831
	target->auth_info = source->auth_info;
832
}
B
Bryan Schumaker 已提交
833
EXPORT_SYMBOL_GPL(nfs_server_copy_userdata);
834

835
void nfs_server_insert_lists(struct nfs_server *server)
836 837
{
	struct nfs_client *clp = server->nfs_client;
838
	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
839

840
	spin_lock(&nn->nfs_client_lock);
841
	list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
842
	list_add_tail(&server->master_link, &nn->nfs_volume_list);
843
	clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
844
	spin_unlock(&nn->nfs_client_lock);
845 846

}
B
Bryan Schumaker 已提交
847
EXPORT_SYMBOL_GPL(nfs_server_insert_lists);
848

C
Chuck Lever 已提交
849
void nfs_server_remove_lists(struct nfs_server *server)
850
{
851
	struct nfs_client *clp = server->nfs_client;
852
	struct nfs_net *nn;
853

854 855
	if (clp == NULL)
		return;
856
	nn = net_generic(clp->cl_net, nfs_net_id);
857
	spin_lock(&nn->nfs_client_lock);
858
	list_del_rcu(&server->client_link);
859
	if (list_empty(&clp->cl_superblocks))
860
		set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
861
	list_del(&server->master_link);
862
	spin_unlock(&nn->nfs_client_lock);
863 864 865

	synchronize_rcu();
}
C
Chuck Lever 已提交
866
EXPORT_SYMBOL_GPL(nfs_server_remove_lists);
867

868 869 870
/*
 * Allocate and initialise a server record
 */
871
struct nfs_server *nfs_alloc_server(void)
872 873 874 875 876 877 878 879 880 881 882 883
{
	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);
884
	INIT_LIST_HEAD(&server->delegations);
885
	INIT_LIST_HEAD(&server->layouts);
886
	INIT_LIST_HEAD(&server->state_owners_lru);
887

888 889
	atomic_set(&server->active, 0);

890 891 892 893 894 895
	server->io_stats = nfs_alloc_iostats();
	if (!server->io_stats) {
		kfree(server);
		return NULL;
	}

896 897 898 899 900 901
	if (bdi_init(&server->backing_dev_info)) {
		nfs_free_iostats(server->io_stats);
		kfree(server);
		return NULL;
	}

902
	ida_init(&server->openowner_id);
903
	ida_init(&server->lockowner_id);
F
Fred Isaman 已提交
904 905
	pnfs_init_server(server);

906 907
	return server;
}
B
Bryan Schumaker 已提交
908
EXPORT_SYMBOL_GPL(nfs_alloc_server);
909 910 911 912 913 914 915 916

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

917
	nfs_server_remove_lists(server);
918 919 920

	if (server->destroy != NULL)
		server->destroy(server);
921 922 923

	if (!IS_ERR(server->client_acl))
		rpc_shutdown_client(server->client_acl);
924 925 926 927 928
	if (!IS_ERR(server->client))
		rpc_shutdown_client(server->client);

	nfs_put_client(server->nfs_client);

929
	ida_destroy(&server->lockowner_id);
930
	ida_destroy(&server->openowner_id);
931
	nfs_free_iostats(server->io_stats);
P
Peter Zijlstra 已提交
932
	bdi_destroy(&server->backing_dev_info);
933 934 935 936
	kfree(server);
	nfs_release_automount_timer();
	dprintk("<-- nfs_free_server()\n");
}
B
Bryan Schumaker 已提交
937
EXPORT_SYMBOL_GPL(nfs_free_server);
938 939 940 941 942

/*
 * Create a version 2 or 3 volume record
 * - keyed on server and FSID
 */
943
struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
944
				     struct nfs_subversion *nfs_mod)
945 946
{
	struct nfs_server *server;
947
	struct nfs_fattr *fattr;
948 949 950 951 952 953
	int error;

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

954 955 956 957 958
	error = -ENOMEM;
	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		goto error;

959
	/* Get a client representation */
960
	error = nfs_init_server(server, mount_info->parsed, nfs_mod);
961 962 963 964
	if (error < 0)
		goto error;

	/* Probe the root fh to retrieve its FSID */
965
	error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
966 967
	if (error < 0)
		goto error;
968 969 970
	if (server->nfs_client->rpc_ops->version == 3) {
		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
			server->namelen = NFS3_MAXNAMLEN;
971
		if (!(mount_info->parsed->flags & NFS_MOUNT_NORDIRPLUS))
972 973 974 975 976 977
			server->caps |= NFS_CAP_READDIRPLUS;
	} else {
		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
			server->namelen = NFS2_MAXNAMLEN;
	}

978
	if (!(fattr->valid & NFS_ATTR_FATTR)) {
979
		error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL);
980 981 982 983 984
		if (error < 0) {
			dprintk("nfs_create_server: getattr error = %d\n", -error);
			goto error;
		}
	}
985
	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
986

987 988 989
	dprintk("Server FSID: %llx:%llx\n",
		(unsigned long long) server->fsid.major,
		(unsigned long long) server->fsid.minor);
990

991
	nfs_server_insert_lists(server);
992
	server->mount_time = jiffies;
993
	nfs_free_fattr(fattr);
994 995 996
	return server;

error:
997
	nfs_free_fattr(fattr);
998 999 1000
	nfs_free_server(server);
	return ERR_PTR(error);
}
B
Bryan Schumaker 已提交
1001
EXPORT_SYMBOL_GPL(nfs_create_server);
1002 1003 1004 1005 1006 1007

/*
 * Clone an NFS2, NFS3 or NFS4 server record
 */
struct nfs_server *nfs_clone_server(struct nfs_server *source,
				    struct nfs_fh *fh,
1008 1009
				    struct nfs_fattr *fattr,
				    rpc_authflavor_t flavor)
1010 1011
{
	struct nfs_server *server;
1012
	struct nfs_fattr *fattr_fsinfo;
1013 1014 1015
	int error;

	dprintk("--> nfs_clone_server(,%llx:%llx,)\n",
1016 1017
		(unsigned long long) fattr->fsid.major,
		(unsigned long long) fattr->fsid.minor);
1018 1019 1020 1021 1022

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

1023 1024 1025 1026 1027
	error = -ENOMEM;
	fattr_fsinfo = nfs_alloc_fattr();
	if (fattr_fsinfo == NULL)
		goto out_free_server;

1028 1029
	/* Copy data from the source */
	server->nfs_client = source->nfs_client;
1030
	server->destroy = source->destroy;
1031 1032 1033 1034 1035
	atomic_inc(&server->nfs_client->cl_count);
	nfs_server_copy_userdata(server, source);

	server->fsid = fattr->fsid;

1036 1037
	error = nfs_init_server_rpcclient(server,
			source->client->cl_timeout,
1038
			flavor);
1039 1040 1041 1042
	if (error < 0)
		goto out_free_server;

	/* probe the filesystem info for this server filesystem */
1043
	error = nfs_probe_fsinfo(server, fh, fattr_fsinfo);
1044 1045 1046
	if (error < 0)
		goto out_free_server;

1047 1048 1049
	if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
		server->namelen = NFS4_MAXNAMLEN;

1050
	dprintk("Cloned FSID: %llx:%llx\n",
1051 1052
		(unsigned long long) server->fsid.major,
		(unsigned long long) server->fsid.minor);
1053 1054 1055 1056 1057

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

1058
	nfs_server_insert_lists(server);
1059 1060
	server->mount_time = jiffies;

1061
	nfs_free_fattr(fattr_fsinfo);
1062 1063 1064 1065
	dprintk("<-- nfs_clone_server() = %p\n", server);
	return server;

out_free_server:
1066
	nfs_free_fattr(fattr_fsinfo);
1067 1068 1069 1070
	nfs_free_server(server);
	dprintk("<-- nfs_clone_server() = error %d\n", error);
	return ERR_PTR(error);
}
B
Bryan Schumaker 已提交
1071
EXPORT_SYMBOL_GPL(nfs_clone_server);
1072

1073 1074 1075 1076 1077
void nfs_clients_init(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);

	INIT_LIST_HEAD(&nn->nfs_client_list);
1078
	INIT_LIST_HEAD(&nn->nfs_volume_list);
B
Bryan Schumaker 已提交
1079
#if IS_ENABLED(CONFIG_NFS_V4)
1080 1081
	idr_init(&nn->cb_ident_idr);
#endif
1082
	spin_lock_init(&nn->nfs_client_lock);
1083
	nn->boot_time = CURRENT_TIME;
1084 1085
}

1086 1087 1088 1089 1090 1091 1092
#ifdef CONFIG_PROC_FS
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 已提交
1093
static const struct seq_operations nfs_server_list_ops = {
1094 1095 1096 1097 1098 1099
	.start	= nfs_server_list_start,
	.next	= nfs_server_list_next,
	.stop	= nfs_server_list_stop,
	.show	= nfs_server_list_show,
};

1100
static const struct file_operations nfs_server_list_fops = {
1101 1102 1103
	.open		= nfs_server_list_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
1104
	.release	= seq_release_net,
1105
	.owner		= THIS_MODULE,
1106 1107 1108 1109 1110 1111 1112 1113
};

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 已提交
1114
static const struct seq_operations nfs_volume_list_ops = {
1115 1116 1117 1118 1119 1120
	.start	= nfs_volume_list_start,
	.next	= nfs_volume_list_next,
	.stop	= nfs_volume_list_stop,
	.show	= nfs_volume_list_show,
};

1121
static const struct file_operations nfs_volume_list_fops = {
1122 1123 1124
	.open		= nfs_volume_list_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
1125
	.release	= seq_release_net,
1126
	.owner		= THIS_MODULE,
1127 1128 1129 1130 1131 1132 1133 1134
};

/*
 * 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)
{
1135 1136
	return seq_open_net(inode, file, &nfs_server_list_ops,
			   sizeof(struct seq_net_private));
1137 1138 1139 1140 1141 1142
}

/*
 * 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)
1143
				__acquires(&nn->nfs_client_lock)
1144
{
1145
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1146

1147
	/* lock the list against modification */
1148
	spin_lock(&nn->nfs_client_lock);
1149
	return seq_list_start_head(&nn->nfs_client_list, *_pos);
1150 1151 1152 1153 1154 1155 1156
}

/*
 * move to next server
 */
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
{
1157
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1158 1159

	return seq_list_next(v, &nn->nfs_client_list, pos);
1160 1161 1162 1163 1164 1165
}

/*
 * clean up after reading from the transports list
 */
static void nfs_server_list_stop(struct seq_file *p, void *v)
1166
				__releases(&nn->nfs_client_lock)
1167
{
1168
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1169 1170

	spin_unlock(&nn->nfs_client_lock);
1171 1172 1173 1174 1175 1176 1177 1178
}

/*
 * 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;
1179
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1180 1181

	/* display header on line 1 */
1182
	if (v == &nn->nfs_client_list) {
1183 1184 1185 1186 1187 1188 1189
		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);

1190 1191 1192 1193
	/* Check if the client is initialized */
	if (clp->cl_cons_state != NFS_CS_READY)
		return 0;

1194
	rcu_read_lock();
1195
	seq_printf(m, "v%u %s %s %3d %s\n",
1196
		   clp->rpc_ops->version,
1197 1198
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1199 1200
		   atomic_read(&clp->cl_count),
		   clp->cl_hostname);
1201
	rcu_read_unlock();
1202 1203 1204 1205 1206 1207 1208 1209 1210

	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)
{
1211
	return seq_open_net(inode, file, &nfs_volume_list_ops,
1212
			   sizeof(struct seq_net_private));
1213 1214 1215 1216 1217 1218
}

/*
 * 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)
1219
				__acquires(&nn->nfs_client_lock)
1220
{
1221
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1222

1223
	/* lock the list against modification */
1224
	spin_lock(&nn->nfs_client_lock);
1225
	return seq_list_start_head(&nn->nfs_volume_list, *_pos);
1226 1227 1228 1229 1230 1231 1232
}

/*
 * move to next volume
 */
static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
{
1233
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1234 1235

	return seq_list_next(v, &nn->nfs_volume_list, pos);
1236 1237 1238 1239 1240 1241
}

/*
 * clean up after reading from the transports list
 */
static void nfs_volume_list_stop(struct seq_file *p, void *v)
1242
				__releases(&nn->nfs_client_lock)
1243
{
1244
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1245 1246

	spin_unlock(&nn->nfs_client_lock);
1247 1248 1249 1250 1251 1252 1253 1254 1255
}

/*
 * 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;
1256 1257
	char dev[13];	// 8 for 2^24, 1 for ':', 3 for 2^8, 1 for '\0'
	char fsid[34];	// 2 * 16 for %llx, 1 for ':', 1 for '\0'
1258
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1259 1260

	/* display header on line 1 */
1261
	if (v == &nn->nfs_volume_list) {
1262 1263
		seq_puts(m, "NV SERVER   PORT DEV          FSID"
			    "                              FSC\n");
1264 1265 1266 1267 1268 1269
		return 0;
	}
	/* display one transport per line on subsequent lines */
	server = list_entry(v, struct nfs_server, master_link);
	clp = server->nfs_client;

1270
	snprintf(dev, sizeof(dev), "%u:%u",
1271 1272
		 MAJOR(server->s_dev), MINOR(server->s_dev));

1273
	snprintf(fsid, sizeof(fsid), "%llx:%llx",
1274 1275
		 (unsigned long long) server->fsid.major,
		 (unsigned long long) server->fsid.minor);
1276

1277
	rcu_read_lock();
1278
	seq_printf(m, "v%u %s %s %-12s %-33s %s\n",
1279
		   clp->rpc_ops->version,
1280 1281
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1282
		   dev,
D
David Howells 已提交
1283 1284
		   fsid,
		   nfs_server_fscache_state(server));
1285
	rcu_read_unlock();
1286 1287 1288 1289

	return 0;
}

1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
int nfs_fs_proc_net_init(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);
	struct proc_dir_entry *p;

	nn->proc_nfsfs = proc_net_mkdir(net, "nfsfs", net->proc_net);
	if (!nn->proc_nfsfs)
		goto error_0;

	/* a file of servers with which we're dealing */
	p = proc_create("servers", S_IFREG|S_IRUGO,
			nn->proc_nfsfs, &nfs_server_list_fops);
	if (!p)
		goto error_1;

	/* a file of volumes that we have mounted */
	p = proc_create("volumes", S_IFREG|S_IRUGO,
			nn->proc_nfsfs, &nfs_volume_list_fops);
	if (!p)
1309
		goto error_1;
1310 1311 1312
	return 0;

error_1:
1313
	remove_proc_subtree("nfsfs", net->proc_net);
1314 1315 1316 1317 1318 1319
error_0:
	return -ENOMEM;
}

void nfs_fs_proc_net_exit(struct net *net)
{
1320
	remove_proc_subtree("nfsfs", net->proc_net);
1321 1322
}

1323 1324 1325 1326 1327
/*
 * initialise the /proc/fs/nfsfs/ directory
 */
int __init nfs_fs_proc_init(void)
{
1328
	if (!proc_mkdir("fs/nfsfs", NULL))
1329 1330 1331
		goto error_0;

	/* a file of servers with which we're dealing */
1332
	if (!proc_symlink("fs/nfsfs/servers", NULL, "../../net/nfsfs/servers"))
1333 1334 1335
		goto error_1;

	/* a file of volumes that we have mounted */
1336 1337
	if (!proc_symlink("fs/nfsfs/volumes", NULL, "../../net/nfsfs/volumes"))
		goto error_1;
1338

1339
	return 0;
1340
error_1:
1341
	remove_proc_subtree("fs/nfsfs", NULL);
1342 1343 1344 1345 1346 1347 1348 1349 1350
error_0:
	return -ENOMEM;
}

/*
 * clean up the /proc/fs/nfsfs/ directory
 */
void nfs_fs_proc_exit(void)
{
1351
	remove_proc_subtree("fs/nfsfs", NULL);
1352 1353 1354
}

#endif /* CONFIG_PROC_FS */