client.c 33.6 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2 3 4 5 6 7 8 9 10
/* client.c: NFS client sharing and management code
 *
 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 */


#include <linux/module.h>
#include <linux/init.h>
A
Alexey Dobriyan 已提交
11
#include <linux/sched.h>
12 13 14 15 16 17 18
#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>
19
#include <linux/sunrpc/addr.h>
20 21 22
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/metrics.h>
23
#include <linux/sunrpc/xprtsock.h>
\
\"Talpey, Thomas\ 已提交
24
#include <linux/sunrpc/xprtrdma.h>
25 26 27 28 29 30 31 32
#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>
33
#include <linux/in6.h>
34
#include <linux/slab.h>
A
Al Viro 已提交
35
#include <linux/idr.h>
36
#include <net/ipv6.h>
37
#include <linux/nfs_xdr.h>
A
Andy Adamson 已提交
38
#include <linux/sunrpc/bc_xprt.h>
39 40
#include <linux/nsproxy.h>
#include <linux/pid_namespace.h>
41 42 43 44 45 46 47


#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
#include "iostat.h"
#include "internal.h"
48
#include "fscache.h"
R
Ricardo Labiaga 已提交
49
#include "pnfs.h"
50
#include "nfs.h"
51
#include "netns.h"
52
#include "sysfs.h"
53 54 55 56

#define NFSDBG_FACILITY		NFSDBG_CLIENT

static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
57 58 59
static DEFINE_SPINLOCK(nfs_version_lock);
static DEFINE_MUTEX(nfs_version_mutex);
static LIST_HEAD(nfs_versions);
60

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

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

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

83 84 85 86 87 88 89 90 91 92
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;
		}
93
	}
94 95

	spin_unlock(&nfs_version_lock);
96
	return ERR_PTR(-EPROTONOSUPPORT);
97 98 99 100 101 102 103 104
}

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

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

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

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

156
	clp->cl_nfs_mod = cl_init->nfs_mod;
157 158
	if (!try_module_get(clp->cl_nfs_mod->owner))
		goto error_dealloc;
159 160

	clp->rpc_ops = clp->cl_nfs_mod->rpc_ops;
161

162
	refcount_set(&clp->cl_count, 1);
163 164
	clp->cl_cons_state = NFS_CS_INITING;

165 166
	memcpy(&clp->cl_addr, cl_init->addr, cl_init->addrlen);
	clp->cl_addrlen = cl_init->addrlen;
167

168
	if (cl_init->hostname) {
169
		err = -ENOMEM;
170
		clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL);
171
		if (!clp->cl_hostname)
172
			goto error_cleanup;
173 174 175 176 177
	}

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

178
	clp->cl_proto = cl_init->proto;
179
	clp->cl_nconnect = cl_init->nconnect;
180
	clp->cl_net = get_net(cl_init->net);
181

182
	clp->cl_principal = "*";
183 184
	nfs_fscache_get_client_cookie(clp);

185 186
	return clp;

187
error_cleanup:
188
	put_nfs_version(clp->cl_nfs_mod);
189
error_dealloc:
190 191
	kfree(clp);
error_0:
192
	return ERR_PTR(err);
193
}
B
Bryan Schumaker 已提交
194
EXPORT_SYMBOL_GPL(nfs_alloc_client);
195

B
Bryan Schumaker 已提交
196
#if IS_ENABLED(CONFIG_NFS_V4)
197
static void nfs_cleanup_cb_ident_idr(struct net *net)
A
Andy Adamson 已提交
198
{
199 200 201
	struct nfs_net *nn = net_generic(net, nfs_net_id);

	idr_destroy(&nn->cb_ident_idr);
A
Andy Adamson 已提交
202 203 204 205 206
}

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

A
Andy Adamson 已提交
209
	if (clp->cl_cb_ident)
210
		idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
A
Andy Adamson 已提交
211 212
}

F
Fred Isaman 已提交
213 214 215 216 217
static void pnfs_init_server(struct nfs_server *server)
{
	rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC");
}

218
#else
219
static void nfs_cleanup_cb_ident_idr(struct net *net)
A
Andy Adamson 已提交
220 221 222 223 224 225
{
}

static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
{
}
F
Fred Isaman 已提交
226 227 228 229 230

static void pnfs_init_server(struct nfs_server *server)
{
}

231
#endif /* CONFIG_NFS_V4 */
232

233 234 235
/*
 * Destroy a shared client record
 */
236
void nfs_free_client(struct nfs_client *clp)
237
{
238 239
	nfs_fscache_release_client_cookie(clp);

240 241 242 243
	/* -EIO all pending I/O */
	if (!IS_ERR(clp->cl_rpcclient))
		rpc_shutdown_client(clp->cl_rpcclient);

244
	put_net(clp->cl_net);
245
	put_nfs_version(clp->cl_nfs_mod);
246
	kfree(clp->cl_hostname);
247
	kfree(clp->cl_acceptor);
248 249
	kfree(clp);
}
B
Bryan Schumaker 已提交
250
EXPORT_SYMBOL_GPL(nfs_free_client);
251 252 253 254 255 256

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

D
David Howells 已提交
259 260 261
	if (!clp)
		return;

262
	nn = net_generic(clp->cl_net, nfs_net_id);
263

264
	if (refcount_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {
265
		list_del(&clp->cl_share_link);
A
Andy Adamson 已提交
266
		nfs_cb_idr_remove_locked(clp);
267
		spin_unlock(&nn->nfs_client_lock);
268

269
		WARN_ON_ONCE(!list_empty(&clp->cl_superblocks));
270

271
		clp->rpc_ops->free_client(clp);
272 273
	}
}
274
EXPORT_SYMBOL_GPL(nfs_put_client);
275 276

/*
277 278
 * Find an nfs_client on the list that matches the initialisation data
 * that is supplied.
279
 */
280
static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data)
281 282
{
	struct nfs_client *clp;
I
Ian Dall 已提交
283
	const struct sockaddr *sap = data->addr;
284
	struct nfs_net *nn = net_generic(data->net, nfs_net_id);
285
	int error;
286

287
again:
288
	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
I
Ian Dall 已提交
289
	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
290 291 292 293
		/* Don't match clients that failed to initialise properly */
		if (clp->cl_cons_state < 0)
			continue;

294 295 296 297
		/* If a client is still initializing then we need to wait */
		if (clp->cl_cons_state > NFS_CS_READY) {
			refcount_inc(&clp->cl_count);
			spin_unlock(&nn->nfs_client_lock);
298
			error = nfs_wait_client_init_complete(clp);
299
			nfs_put_client(clp);
300
			spin_lock(&nn->nfs_client_lock);
301 302
			if (error < 0)
				return ERR_PTR(error);
303 304 305
			goto again;
		}

306
		/* Different NFS versions cannot share the same nfs_client */
307
		if (clp->rpc_ops != data->nfs_mod->rpc_ops)
308 309
			continue;

310 311
		if (clp->cl_proto != data->proto)
			continue;
312 313 314
		/* Match nfsv4 minorversion */
		if (clp->cl_minorversion != data->minorversion)
			continue;
315 316 317 318 319 320

		/* Match request for a dedicated DS */
		if (test_bit(NFS_CS_DS, &data->init_flags) !=
		    test_bit(NFS_CS_DS, &clp->cl_flags))
			continue;

321
		/* Match the full socket address */
322
		if (!rpc_cmp_addr_port(sap, clap))
323
			/* Match all xprt_switch full socket addresses */
324 325
			if (IS_ERR(clp->cl_rpcclient) ||
                            !rpc_clnt_xprt_switch_has_addr(clp->cl_rpcclient,
326 327
							   sap))
				continue;
328

329
		refcount_inc(&clp->cl_count);
330
		return clp;
331
	}
332
	return NULL;
333 334
}

335 336 337 338 339 340
/*
 * Return true if @clp is done initializing, false if still working on it.
 *
 * Use nfs_client_init_status to check if it was successful.
 */
bool nfs_client_init_is_complete(const struct nfs_client *clp)
341
{
342
	return clp->cl_cons_state <= NFS_CS_READY;
343
}
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
EXPORT_SYMBOL_GPL(nfs_client_init_is_complete);

/*
 * Return 0 if @clp was successfully initialized, -errno otherwise.
 *
 * This must be called *after* nfs_client_init_is_complete() returns true,
 * otherwise it will pop WARN_ON_ONCE and return -EINVAL
 */
int nfs_client_init_status(const struct nfs_client *clp)
{
	/* called without checking nfs_client_init_is_complete */
	if (clp->cl_cons_state > NFS_CS_READY) {
		WARN_ON_ONCE(1);
		return -EINVAL;
	}
	return clp->cl_cons_state;
}
EXPORT_SYMBOL_GPL(nfs_client_init_status);
362 363 364 365 366 367

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 已提交
368
EXPORT_SYMBOL_GPL(nfs_wait_client_init_complete);
369

370 371 372 373 374 375 376 377 378
/*
 * 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;

379
	error = nfs_wait_client_init_complete(clp);
380 381 382 383 384 385 386 387 388 389 390
	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);
	}

391
	smp_rmb();
392 393 394
	return clp;
}

395 396 397 398
/*
 * Look up a client by IP address and protocol version
 * - creates a new record if one doesn't yet exist
 */
399
struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
400 401
{
	struct nfs_client *clp, *new = NULL;
402
	struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
403
	const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops;
404

P
Peng Tao 已提交
405 406 407 408 409
	if (cl_init->hostname == NULL) {
		WARN_ON(1);
		return NULL;
	}

410 411
	/* see if the client already exists */
	do {
412
		spin_lock(&nn->nfs_client_lock);
413

414
		clp = nfs_match_client(cl_init);
415 416 417
		if (clp) {
			spin_unlock(&nn->nfs_client_lock);
			if (new)
418
				new->rpc_ops->free_client(new);
419 420
			if (IS_ERR(clp))
				return clp;
421 422
			return nfs_found_client(cl_init, clp);
		}
423
		if (new) {
424 425
			list_add_tail(&new->cl_share_link,
					&nn->nfs_client_list);
426
			spin_unlock(&nn->nfs_client_lock);
C
Chuck Lever 已提交
427
			new->cl_flags = cl_init->init_flags;
428
			return rpc_ops->init_client(new, cl_init);
429
		}
430

431
		spin_unlock(&nn->nfs_client_lock);
432

433
		new = rpc_ops->alloc_client(cl_init);
434
	} while (!IS_ERR(new));
435

436
	return new;
437
}
B
Bryan Schumaker 已提交
438
EXPORT_SYMBOL_GPL(nfs_get_client);
439 440 441 442

/*
 * Mark a server as ready or failed
 */
443
void nfs_mark_client_ready(struct nfs_client *clp, int state)
444
{
445
	smp_wmb();
446 447 448
	clp->cl_cons_state = state;
	wake_up_all(&nfs_client_active_wq);
}
B
Bryan Schumaker 已提交
449
EXPORT_SYMBOL_GPL(nfs_mark_client_ready);
450 451 452 453

/*
 * Initialise the timeout values for a connection
 */
454
void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
455
				    int timeo, int retrans)
456 457 458 459 460
{
	to->to_initval = timeo * HZ / 10;
	to->to_retries = retrans;

	switch (proto) {
461
	case XPRT_TRANSPORT_TCP:
\
\"Talpey, Thomas\ 已提交
462
	case XPRT_TRANSPORT_RDMA:
463
		if (retrans == NFS_UNSPEC_RETRANS)
464
			to->to_retries = NFS_DEF_TCP_RETRANS;
465
		if (timeo == NFS_UNSPEC_TIMEO || to->to_initval == 0)
466
			to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10;
467 468 469 470
		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);
471 472 473 474
		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;
475 476
		to->to_exponential = 0;
		break;
477
	case XPRT_TRANSPORT_UDP:
478
		if (retrans == NFS_UNSPEC_RETRANS)
479
			to->to_retries = NFS_DEF_UDP_RETRANS;
480
		if (timeo == NFS_UNSPEC_TIMEO || to->to_initval == 0)
481
			to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10;
482 483 484 485 486
		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;
487 488
	default:
		BUG();
489 490
	}
}
B
Bryan Schumaker 已提交
491
EXPORT_SYMBOL_GPL(nfs_init_timeout_values);
492 493 494 495

/*
 * Create an RPC client handle
 */
496
int nfs_create_rpc_client(struct nfs_client *clp,
497
			  const struct nfs_client_initdata *cl_init,
498
			  rpc_authflavor_t flavor)
499 500
{
	struct rpc_clnt		*clnt = NULL;
501
	struct rpc_create_args args = {
502
		.net		= clp->cl_net,
503
		.protocol	= clp->cl_proto,
504
		.nconnect	= clp->cl_nconnect,
505
		.address	= (struct sockaddr *)&clp->cl_addr,
506
		.addrsize	= clp->cl_addrlen,
507
		.timeout	= cl_init->timeparms,
508
		.servername	= clp->cl_hostname,
509
		.nodename	= cl_init->nodename,
510 511 512
		.program	= &nfs_program,
		.version	= clp->rpc_ops->version,
		.authflavor	= flavor,
513
		.cred		= cl_init->cred,
514
	};
515

C
Chuck Lever 已提交
516
	if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags))
517
		args.flags |= RPC_CLNT_CREATE_DISCRTRY;
518 519
	if (test_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags))
		args.flags |= RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT;
C
Chuck Lever 已提交
520
	if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags))
521
		args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
522 523
	if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags))
		args.flags |= RPC_CLNT_CREATE_INFINITE_SLOTS;
524 525
	if (test_bit(NFS_CS_NOPING, &clp->cl_flags))
		args.flags |= RPC_CLNT_CREATE_NOPING;
526 527
	if (test_bit(NFS_CS_REUSEPORT, &clp->cl_flags))
		args.flags |= RPC_CLNT_CREATE_REUSEPORT;
528

529 530 531
	if (!IS_ERR(clp->cl_rpcclient))
		return 0;

532
	clnt = rpc_create(&args);
533 534
	if (IS_ERR(clnt)) {
		dprintk("%s: cannot create RPC client. Error = %ld\n",
535
				__func__, PTR_ERR(clnt));
536 537 538
		return PTR_ERR(clnt);
	}

539
	clnt->cl_principal = clp->cl_principal;
540 541 542
	clp->cl_rpcclient = clnt;
	return 0;
}
B
Bryan Schumaker 已提交
543
EXPORT_SYMBOL_GPL(nfs_create_rpc_client);
544 545 546 547 548 549

/*
 * Version 2 or 3 client destruction
 */
static void nfs_destroy_server(struct nfs_server *server)
{
550
	if (server->nlm_host)
551
		nlmclnt_done(server->nlm_host);
552 553 554 555 556 557 558
}

/*
 * Version 2 or 3 lockd setup
 */
static int nfs_start_lockd(struct nfs_server *server)
{
559 560
	struct nlm_host *host;
	struct nfs_client *clp = server->nfs_client;
561 562 563 564 565
	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,
566 567
		.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?
					1 : 0,
568
		.net		= clp->cl_net,
569
		.nlmclnt_ops 	= clp->cl_nfs_mod->rpc_ops->nlmclnt_ops,
570
		.cred		= current_cred(),
571
	};
572

573
	if (nlm_init.nfs_version > 3)
574
		return 0;
575 576
	if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) &&
			(server->flags & NFS_MOUNT_LOCAL_FCNTL))
577 578
		return 0;

579 580 581 582 583 584 585 586
	switch (clp->cl_proto) {
		default:
			nlm_init.protocol = IPPROTO_TCP;
			break;
		case XPRT_TRANSPORT_UDP:
			nlm_init.protocol = IPPROTO_UDP;
	}

587
	host = nlmclnt_init(&nlm_init);
588 589 590 591 592 593
	if (IS_ERR(host))
		return PTR_ERR(host);

	server->nlm_host = host;
	server->destroy = nfs_destroy_server;
	return 0;
594 595 596 597 598
}

/*
 * Create a general RPC client
 */
599
int nfs_init_server_rpcclient(struct nfs_server *server,
600 601
		const struct rpc_timeout *timeo,
		rpc_authflavor_t pseudoflavour)
602 603 604
{
	struct nfs_client *clp = server->nfs_client;

605 606
	server->client = rpc_clone_client_set_auth(clp->cl_rpcclient,
							pseudoflavour);
607
	if (IS_ERR(server->client)) {
608
		dprintk("%s: couldn't create rpc_client!\n", __func__);
609 610 611
		return PTR_ERR(server->client);
	}

612 613 614 615
	memcpy(&server->client->cl_timeout_default,
			timeo,
			sizeof(server->client->cl_timeout_default));
	server->client->cl_timeout = &server->client->cl_timeout_default;
616
	server->client->cl_softrtry = 0;
617 618
	if (server->flags & NFS_MOUNT_SOFTERR)
		server->client->cl_softerr = 1;
619 620 621 622 623
	if (server->flags & NFS_MOUNT_SOFT)
		server->client->cl_softrtry = 1;

	return 0;
}
B
Bryan Schumaker 已提交
624
EXPORT_SYMBOL_GPL(nfs_init_server_rpcclient);
625

626 627 628 629
/**
 * nfs_init_client - Initialise an NFS2 or NFS3 client
 *
 * @clp: nfs_client to initialise
630
 * @cl_init: Initialisation parameters
631 632
 *
 * Returns pointer to an NFS client, or an ERR_PTR value.
633
 */
634
struct nfs_client *nfs_init_client(struct nfs_client *clp,
635
				   const struct nfs_client_initdata *cl_init)
636 637 638
{
	int error;

A
Anna Schumaker 已提交
639 640
	/* the client is already initialised */
	if (clp->cl_cons_state == NFS_CS_READY)
641
		return clp;
642 643 644 645 646

	/*
	 * Create a client RPC handle for doing FSSTAT with UNIX auth only
	 * - RFC 2623, sec 2.3.2
	 */
647
	error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX);
A
Anna Schumaker 已提交
648 649 650 651 652
	nfs_mark_client_ready(clp, error == 0 ? NFS_CS_READY : error);
	if (error < 0) {
		nfs_put_client(clp);
		clp = ERR_PTR(error);
	}
653
	return clp;
654
}
B
Bryan Schumaker 已提交
655
EXPORT_SYMBOL_GPL(nfs_init_client);
656 657 658 659

/*
 * Create a version 2 or 3 client
 */
660
static int nfs_init_server(struct nfs_server *server,
661
			   const struct nfs_fs_context *ctx,
662
			   struct nfs_subversion *nfs_mod)
663
{
664
	struct rpc_timeout timeparms;
665
	struct nfs_client_initdata cl_init = {
666 667 668
		.hostname = ctx->nfs_server.hostname,
		.addr = (const struct sockaddr *)&ctx->nfs_server.address,
		.addrlen = ctx->nfs_server.addrlen,
669
		.nfs_mod = nfs_mod,
670 671
		.proto = ctx->nfs_server.protocol,
		.net = ctx->net,
672
		.timeparms = &timeparms,
673
		.cred = server->cred,
674
		.nconnect = ctx->nfs_server.nconnect,
675
		.init_flags = (1UL << NFS_CS_REUSEPORT),
676
	};
677
	struct nfs_client *clp;
678
	int error;
679

680 681 682
	nfs_init_timeout_values(&timeparms, ctx->nfs_server.protocol,
				ctx->timeo, ctx->retrans);
	if (ctx->flags & NFS_MOUNT_NORESVPORT)
C
Chuck Lever 已提交
683
		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
684

685
	/* Allocate or find a client reference we can use */
686
	clp = nfs_get_client(&cl_init);
687
	if (IS_ERR(clp))
688 689 690 691 692
		return PTR_ERR(clp);

	server->nfs_client = clp;

	/* Initialise the client representation from the mount data */
693 694
	server->flags = ctx->flags;
	server->options = ctx->options;
695 696
	server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
		NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
697
		NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
698

699 700 701 702
	if (ctx->rsize)
		server->rsize = nfs_block_size(ctx->rsize, NULL);
	if (ctx->wsize)
		server->wsize = nfs_block_size(ctx->wsize, NULL);
703

704 705 706 707
	server->acregmin = ctx->acregmin * HZ;
	server->acregmax = ctx->acregmax * HZ;
	server->acdirmin = ctx->acdirmin * HZ;
	server->acdirmax = ctx->acdirmax * HZ;
708 709 710 711 712 713

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

714 715
	server->port = ctx->nfs_server.port;
	server->auth_info = ctx->auth_info;
716

717
	error = nfs_init_server_rpcclient(server, &timeparms,
718
					  ctx->selected_flavor);
719 720 721
	if (error < 0)
		goto error;

722
	/* Preserve the values of mount_server-related mount options */
723 724 725 726
	if (ctx->mount_server.addrlen) {
		memcpy(&server->mountd_address, &ctx->mount_server.address,
			ctx->mount_server.addrlen);
		server->mountd_addrlen = ctx->mount_server.addrlen;
727
	}
728 729 730
	server->mountd_version = ctx->mount_server.version;
	server->mountd_port = ctx->mount_server.port;
	server->mountd_protocol = ctx->mount_server.protocol;
731

732
	server->namelen  = ctx->namlen;
733 734 735 736 737 738 739 740 741 742 743
	return 0;

error:
	server->nfs_client = NULL;
	nfs_put_client(clp);
	return error;
}

/*
 * Load up the server record from information gained in an fsinfo record
 */
744 745
static void nfs_server_set_fsinfo(struct nfs_server *server,
				  struct nfs_fsinfo *fsinfo)
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
{
	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;
765
	server->rpages = (server->rsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
P
Peter Zijlstra 已提交
766

767 768 769 770
	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;
771
	server->wpages = (server->wsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
R
Ricardo Labiaga 已提交
772

773 774 775
	server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);

	server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
776 777
	if (server->dtsize > PAGE_SIZE * NFS_MAX_READDIR_PAGES)
		server->dtsize = PAGE_SIZE * NFS_MAX_READDIR_PAGES;
778 779 780 781 782 783 784 785 786 787
	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 已提交
788 789
	server->time_delta = fsinfo->time_delta;

790
	server->clone_blksize = fsinfo->clone_blksize;
791 792 793 794 795 796 797
	/* 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
 */
798
int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
799 800 801 802 803 804 805 806
{
	struct nfs_fsinfo fsinfo;
	struct nfs_client *clp = server->nfs_client;
	int error;

	if (clp->rpc_ops->set_capabilities != NULL) {
		error = clp->rpc_ops->set_capabilities(server, mntfh);
		if (error < 0)
807
			return error;
808 809 810
	}

	fsinfo.fattr = fattr;
811
	fsinfo.nlayouttypes = 0;
812
	memset(fsinfo.layouttype, 0, sizeof(fsinfo.layouttype));
813 814
	error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
	if (error < 0)
815
		return error;
816

817
	nfs_server_set_fsinfo(server, &fsinfo);
818 819 820 821 822 823 824 825 826 827 828 829 830 831

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

	return 0;
}
B
Bryan Schumaker 已提交
832
EXPORT_SYMBOL_GPL(nfs_probe_fsinfo);
833 834 835 836

/*
 * Copy useful information when duplicating a server record
 */
837
void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
838 839
{
	target->flags = source->flags;
840 841
	target->rsize = source->rsize;
	target->wsize = source->wsize;
842 843 844 845 846
	target->acregmin = source->acregmin;
	target->acregmax = source->acregmax;
	target->acdirmin = source->acdirmin;
	target->acdirmax = source->acdirmax;
	target->caps = source->caps;
847
	target->options = source->options;
848
	target->auth_info = source->auth_info;
849
	target->port = source->port;
850
}
B
Bryan Schumaker 已提交
851
EXPORT_SYMBOL_GPL(nfs_server_copy_userdata);
852

853
void nfs_server_insert_lists(struct nfs_server *server)
854 855
{
	struct nfs_client *clp = server->nfs_client;
856
	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
857

858
	spin_lock(&nn->nfs_client_lock);
859
	list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
860
	list_add_tail(&server->master_link, &nn->nfs_volume_list);
861
	clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
862
	spin_unlock(&nn->nfs_client_lock);
863 864

}
B
Bryan Schumaker 已提交
865
EXPORT_SYMBOL_GPL(nfs_server_insert_lists);
866

C
Chuck Lever 已提交
867
void nfs_server_remove_lists(struct nfs_server *server)
868
{
869
	struct nfs_client *clp = server->nfs_client;
870
	struct nfs_net *nn;
871

872 873
	if (clp == NULL)
		return;
874
	nn = net_generic(clp->cl_net, nfs_net_id);
875
	spin_lock(&nn->nfs_client_lock);
876
	list_del_rcu(&server->client_link);
877
	if (list_empty(&clp->cl_superblocks))
878
		set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
879
	list_del(&server->master_link);
880
	spin_unlock(&nn->nfs_client_lock);
881 882 883

	synchronize_rcu();
}
C
Chuck Lever 已提交
884
EXPORT_SYMBOL_GPL(nfs_server_remove_lists);
885

886 887 888
/*
 * Allocate and initialise a server record
 */
889
struct nfs_server *nfs_alloc_server(void)
890 891 892 893 894 895 896 897 898 899 900 901
{
	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);
902
	INIT_LIST_HEAD(&server->delegations);
903
	INIT_LIST_HEAD(&server->layouts);
904
	INIT_LIST_HEAD(&server->state_owners_lru);
905
	INIT_LIST_HEAD(&server->ss_copies);
906

907 908
	atomic_set(&server->active, 0);

909 910 911 912 913 914
	server->io_stats = nfs_alloc_iostats();
	if (!server->io_stats) {
		kfree(server);
		return NULL;
	}

915
	ida_init(&server->openowner_id);
916
	ida_init(&server->lockowner_id);
F
Fred Isaman 已提交
917
	pnfs_init_server(server);
918
	rpc_init_wait_queue(&server->uoc_rpcwaitq, "NFS UOC");
F
Fred Isaman 已提交
919

920 921
	return server;
}
B
Bryan Schumaker 已提交
922
EXPORT_SYMBOL_GPL(nfs_alloc_server);
923 924 925 926 927 928

/*
 * Free up a server record
 */
void nfs_free_server(struct nfs_server *server)
{
929
	nfs_server_remove_lists(server);
930 931 932

	if (server->destroy != NULL)
		server->destroy(server);
933 934 935

	if (!IS_ERR(server->client_acl))
		rpc_shutdown_client(server->client_acl);
936 937 938 939 940
	if (!IS_ERR(server->client))
		rpc_shutdown_client(server->client);

	nfs_put_client(server->nfs_client);

941
	ida_destroy(&server->lockowner_id);
942
	ida_destroy(&server->openowner_id);
943
	nfs_free_iostats(server->io_stats);
944
	put_cred(server->cred);
945 946 947
	kfree(server);
	nfs_release_automount_timer();
}
B
Bryan Schumaker 已提交
948
EXPORT_SYMBOL_GPL(nfs_free_server);
949 950 951 952 953

/*
 * Create a version 2 or 3 volume record
 * - keyed on server and FSID
 */
954
struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info)
955 956
{
	struct nfs_server *server;
957
	struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
958
	struct nfs_fattr *fattr;
959 960 961 962 963 964
	int error;

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

965 966
	server->cred = get_cred(current_cred());

967 968 969 970 971
	error = -ENOMEM;
	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		goto error;

972
	/* Get a client representation */
973
	error = nfs_init_server(server, mount_info->ctx, nfs_mod);
974 975 976 977
	if (error < 0)
		goto error;

	/* Probe the root fh to retrieve its FSID */
978
	error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
979 980
	if (error < 0)
		goto error;
981 982 983
	if (server->nfs_client->rpc_ops->version == 3) {
		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
			server->namelen = NFS3_MAXNAMLEN;
984
		if (!(mount_info->ctx->flags & NFS_MOUNT_NORDIRPLUS))
985 986 987 988 989 990
			server->caps |= NFS_CAP_READDIRPLUS;
	} else {
		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
			server->namelen = NFS2_MAXNAMLEN;
	}

991
	if (!(fattr->valid & NFS_ATTR_FATTR)) {
992 993
		error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh,
				fattr, NULL, NULL);
994 995 996 997 998
		if (error < 0) {
			dprintk("nfs_create_server: getattr error = %d\n", -error);
			goto error;
		}
	}
999
	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
1000

1001 1002 1003
	dprintk("Server FSID: %llx:%llx\n",
		(unsigned long long) server->fsid.major,
		(unsigned long long) server->fsid.minor);
1004

1005
	nfs_server_insert_lists(server);
1006
	server->mount_time = jiffies;
1007
	nfs_free_fattr(fattr);
1008 1009 1010
	return server;

error:
1011
	nfs_free_fattr(fattr);
1012 1013 1014
	nfs_free_server(server);
	return ERR_PTR(error);
}
B
Bryan Schumaker 已提交
1015
EXPORT_SYMBOL_GPL(nfs_create_server);
1016 1017 1018 1019 1020 1021

/*
 * Clone an NFS2, NFS3 or NFS4 server record
 */
struct nfs_server *nfs_clone_server(struct nfs_server *source,
				    struct nfs_fh *fh,
1022 1023
				    struct nfs_fattr *fattr,
				    rpc_authflavor_t flavor)
1024 1025
{
	struct nfs_server *server;
1026
	struct nfs_fattr *fattr_fsinfo;
1027 1028 1029 1030 1031 1032
	int error;

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

1033 1034
	server->cred = get_cred(source->cred);

1035 1036 1037 1038 1039
	error = -ENOMEM;
	fattr_fsinfo = nfs_alloc_fattr();
	if (fattr_fsinfo == NULL)
		goto out_free_server;

1040 1041
	/* Copy data from the source */
	server->nfs_client = source->nfs_client;
1042
	server->destroy = source->destroy;
1043
	refcount_inc(&server->nfs_client->cl_count);
1044 1045 1046 1047
	nfs_server_copy_userdata(server, source);

	server->fsid = fattr->fsid;

1048 1049
	error = nfs_init_server_rpcclient(server,
			source->client->cl_timeout,
1050
			flavor);
1051 1052 1053 1054
	if (error < 0)
		goto out_free_server;

	/* probe the filesystem info for this server filesystem */
1055
	error = nfs_probe_fsinfo(server, fh, fattr_fsinfo);
1056 1057 1058
	if (error < 0)
		goto out_free_server;

1059 1060 1061
	if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
		server->namelen = NFS4_MAXNAMLEN;

1062 1063 1064 1065
	error = nfs_start_lockd(server);
	if (error < 0)
		goto out_free_server;

1066
	nfs_server_insert_lists(server);
1067 1068
	server->mount_time = jiffies;

1069
	nfs_free_fattr(fattr_fsinfo);
1070 1071 1072
	return server;

out_free_server:
1073
	nfs_free_fattr(fattr_fsinfo);
1074 1075 1076
	nfs_free_server(server);
	return ERR_PTR(error);
}
B
Bryan Schumaker 已提交
1077
EXPORT_SYMBOL_GPL(nfs_clone_server);
1078

1079 1080 1081 1082 1083
void nfs_clients_init(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);

	INIT_LIST_HEAD(&nn->nfs_client_list);
1084
	INIT_LIST_HEAD(&nn->nfs_volume_list);
B
Bryan Schumaker 已提交
1085
#if IS_ENABLED(CONFIG_NFS_V4)
1086 1087
	idr_init(&nn->cb_ident_idr);
#endif
1088
	spin_lock_init(&nn->nfs_client_lock);
1089
	nn->boot_time = ktime_get_real();
1090 1091

	nfs_netns_sysfs_setup(nn, net);
1092 1093
}

1094 1095 1096 1097
void nfs_clients_exit(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);

1098
	nfs_netns_sysfs_destroy(nn);
1099 1100 1101 1102 1103
	nfs_cleanup_cb_ident_idr(net);
	WARN_ON_ONCE(!list_empty(&nn->nfs_client_list));
	WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list));
}

1104 1105 1106 1107 1108 1109
#ifdef CONFIG_PROC_FS
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 已提交
1110
static const struct seq_operations nfs_server_list_ops = {
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
	.start	= nfs_server_list_start,
	.next	= nfs_server_list_next,
	.stop	= nfs_server_list_stop,
	.show	= nfs_server_list_show,
};

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 已提交
1122
static const struct seq_operations nfs_volume_list_ops = {
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
	.start	= nfs_volume_list_start,
	.next	= nfs_volume_list_next,
	.stop	= nfs_volume_list_stop,
	.show	= nfs_volume_list_show,
};

/*
 * 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)
1133
				__acquires(&nn->nfs_client_lock)
1134
{
1135
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1136

1137
	/* lock the list against modification */
1138
	spin_lock(&nn->nfs_client_lock);
1139
	return seq_list_start_head(&nn->nfs_client_list, *_pos);
1140 1141 1142 1143 1144 1145 1146
}

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

	return seq_list_next(v, &nn->nfs_client_list, pos);
1150 1151 1152 1153 1154 1155
}

/*
 * clean up after reading from the transports list
 */
static void nfs_server_list_stop(struct seq_file *p, void *v)
1156
				__releases(&nn->nfs_client_lock)
1157
{
1158
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1159 1160

	spin_unlock(&nn->nfs_client_lock);
1161 1162 1163 1164 1165 1166 1167 1168
}

/*
 * 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;
1169
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1170 1171

	/* display header on line 1 */
1172
	if (v == &nn->nfs_client_list) {
1173 1174 1175 1176 1177 1178 1179
		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);

1180 1181 1182 1183
	/* Check if the client is initialized */
	if (clp->cl_cons_state != NFS_CS_READY)
		return 0;

1184
	rcu_read_lock();
1185
	seq_printf(m, "v%u %s %s %3d %s\n",
1186
		   clp->rpc_ops->version,
1187 1188
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1189
		   refcount_read(&clp->cl_count),
1190
		   clp->cl_hostname);
1191
	rcu_read_unlock();
1192 1193 1194 1195 1196 1197 1198 1199

	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)
1200
				__acquires(&nn->nfs_client_lock)
1201
{
1202
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1203

1204
	/* lock the list against modification */
1205
	spin_lock(&nn->nfs_client_lock);
1206
	return seq_list_start_head(&nn->nfs_volume_list, *_pos);
1207 1208 1209 1210 1211 1212 1213
}

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

	return seq_list_next(v, &nn->nfs_volume_list, pos);
1217 1218 1219 1220 1221 1222
}

/*
 * clean up after reading from the transports list
 */
static void nfs_volume_list_stop(struct seq_file *p, void *v)
1223
				__releases(&nn->nfs_client_lock)
1224
{
1225
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1226 1227

	spin_unlock(&nn->nfs_client_lock);
1228 1229 1230 1231 1232 1233 1234 1235 1236
}

/*
 * 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;
1237 1238
	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'
1239
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1240 1241

	/* display header on line 1 */
1242
	if (v == &nn->nfs_volume_list) {
1243 1244
		seq_puts(m, "NV SERVER   PORT DEV          FSID"
			    "                              FSC\n");
1245 1246 1247 1248 1249 1250
		return 0;
	}
	/* display one transport per line on subsequent lines */
	server = list_entry(v, struct nfs_server, master_link);
	clp = server->nfs_client;

1251
	snprintf(dev, sizeof(dev), "%u:%u",
1252 1253
		 MAJOR(server->s_dev), MINOR(server->s_dev));

1254
	snprintf(fsid, sizeof(fsid), "%llx:%llx",
1255 1256
		 (unsigned long long) server->fsid.major,
		 (unsigned long long) server->fsid.minor);
1257

1258
	rcu_read_lock();
1259
	seq_printf(m, "v%u %s %s %-12s %-33s %s\n",
1260
		   clp->rpc_ops->version,
1261 1262
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1263
		   dev,
D
David Howells 已提交
1264 1265
		   fsid,
		   nfs_server_fscache_state(server));
1266
	rcu_read_unlock();
1267 1268 1269 1270

	return 0;
}

1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
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 */
1281 1282
	p = proc_create_net("servers", S_IFREG|S_IRUGO, nn->proc_nfsfs,
			&nfs_server_list_ops, sizeof(struct seq_net_private));
1283 1284 1285 1286
	if (!p)
		goto error_1;

	/* a file of volumes that we have mounted */
1287 1288
	p = proc_create_net("volumes", S_IFREG|S_IRUGO, nn->proc_nfsfs,
			&nfs_volume_list_ops, sizeof(struct seq_net_private));
1289
	if (!p)
1290
		goto error_1;
1291 1292 1293
	return 0;

error_1:
1294
	remove_proc_subtree("nfsfs", net->proc_net);
1295 1296 1297 1298 1299 1300
error_0:
	return -ENOMEM;
}

void nfs_fs_proc_net_exit(struct net *net)
{
1301
	remove_proc_subtree("nfsfs", net->proc_net);
1302 1303
}

1304 1305 1306 1307 1308
/*
 * initialise the /proc/fs/nfsfs/ directory
 */
int __init nfs_fs_proc_init(void)
{
1309
	if (!proc_mkdir("fs/nfsfs", NULL))
1310 1311 1312
		goto error_0;

	/* a file of servers with which we're dealing */
1313
	if (!proc_symlink("fs/nfsfs/servers", NULL, "../../net/nfsfs/servers"))
1314 1315 1316
		goto error_1;

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

1320
	return 0;
1321
error_1:
1322
	remove_proc_subtree("fs/nfsfs", NULL);
1323 1324 1325 1326 1327 1328 1329 1330 1331
error_0:
	return -ENOMEM;
}

/*
 * clean up the /proc/fs/nfsfs/ directory
 */
void nfs_fs_proc_exit(void)
{
1332
	remove_proc_subtree("fs/nfsfs", NULL);
1333 1334 1335
}

#endif /* CONFIG_PROC_FS */