client.c 33.5 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 528 529
	if (!IS_ERR(clp->cl_rpcclient))
		return 0;

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

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

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

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

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

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

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

	server->nlm_host = host;
	server->destroy = nfs_destroy_server;
	return 0;
592 593 594 595 596
}

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

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

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

	return 0;
}
B
Bryan Schumaker 已提交
622
EXPORT_SYMBOL_GPL(nfs_init_server_rpcclient);
623

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

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

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

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

677 678
	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
			data->timeo, data->retrans);
C
Chuck Lever 已提交
679 680
	if (data->flags & NFS_MOUNT_NORESVPORT)
		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
681

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

	server->nfs_client = clp;

	/* Initialise the client representation from the mount data */
690
	server->flags = data->flags;
691
	server->options = data->options;
692 693
	server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
		NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
694
		NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710

	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;

711
	server->port = data->nfs_server.port;
712
	server->auth_info = data->auth_info;
713

714 715
	error = nfs_init_server_rpcclient(server, &timeparms,
					  data->selected_flavor);
716 717 718
	if (error < 0)
		goto error;

719 720 721 722 723 724 725 726 727 728
	/* 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;

729 730 731 732 733 734 735 736 737 738 739 740
	server->namelen  = data->namlen;
	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
 */
741 742
static void nfs_server_set_fsinfo(struct nfs_server *server,
				  struct nfs_fsinfo *fsinfo)
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
{
	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;
762
	server->rpages = (server->rsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
P
Peter Zijlstra 已提交
763

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

770 771 772
	server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);

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

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

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

814
	nfs_server_set_fsinfo(server, &fsinfo);
815 816 817 818 819 820 821 822 823 824 825 826 827 828

	/* 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 已提交
829
EXPORT_SYMBOL_GPL(nfs_probe_fsinfo);
830 831 832 833

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

850
void nfs_server_insert_lists(struct nfs_server *server)
851 852
{
	struct nfs_client *clp = server->nfs_client;
853
	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
854

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

}
B
Bryan Schumaker 已提交
862
EXPORT_SYMBOL_GPL(nfs_server_insert_lists);
863

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

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

	synchronize_rcu();
}
C
Chuck Lever 已提交
881
EXPORT_SYMBOL_GPL(nfs_server_remove_lists);
882

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

904 905
	atomic_set(&server->active, 0);

906 907 908 909 910 911
	server->io_stats = nfs_alloc_iostats();
	if (!server->io_stats) {
		kfree(server);
		return NULL;
	}

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

917 918
	return server;
}
B
Bryan Schumaker 已提交
919
EXPORT_SYMBOL_GPL(nfs_alloc_server);
920 921 922 923 924 925

/*
 * Free up a server record
 */
void nfs_free_server(struct nfs_server *server)
{
926
	nfs_server_remove_lists(server);
927 928 929

	if (server->destroy != NULL)
		server->destroy(server);
930 931 932

	if (!IS_ERR(server->client_acl))
		rpc_shutdown_client(server->client_acl);
933 934 935 936 937
	if (!IS_ERR(server->client))
		rpc_shutdown_client(server->client);

	nfs_put_client(server->nfs_client);

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

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

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

962 963
	server->cred = get_cred(current_cred());

964 965 966 967 968
	error = -ENOMEM;
	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		goto error;

969
	/* Get a client representation */
970
	error = nfs_init_server(server, mount_info->parsed, nfs_mod);
971 972 973 974
	if (error < 0)
		goto error;

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

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

998 999 1000
	dprintk("Server FSID: %llx:%llx\n",
		(unsigned long long) server->fsid.major,
		(unsigned long long) server->fsid.minor);
1001

1002
	nfs_server_insert_lists(server);
1003
	server->mount_time = jiffies;
1004
	nfs_free_fattr(fattr);
1005 1006 1007
	return server;

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

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

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

1030 1031
	server->cred = get_cred(source->cred);

1032 1033 1034 1035 1036
	error = -ENOMEM;
	fattr_fsinfo = nfs_alloc_fattr();
	if (fattr_fsinfo == NULL)
		goto out_free_server;

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

	server->fsid = fattr->fsid;

1045 1046
	error = nfs_init_server_rpcclient(server,
			source->client->cl_timeout,
1047
			flavor);
1048 1049 1050 1051
	if (error < 0)
		goto out_free_server;

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

1056 1057 1058
	if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
		server->namelen = NFS4_MAXNAMLEN;

1059 1060 1061 1062
	error = nfs_start_lockd(server);
	if (error < 0)
		goto out_free_server;

1063
	nfs_server_insert_lists(server);
1064 1065
	server->mount_time = jiffies;

1066
	nfs_free_fattr(fattr_fsinfo);
1067 1068 1069
	return server;

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

1076 1077 1078 1079 1080
void nfs_clients_init(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);

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

	nfs_netns_sysfs_setup(nn, net);
1089 1090
}

1091 1092 1093 1094
void nfs_clients_exit(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);

1095
	nfs_netns_sysfs_destroy(nn);
1096 1097 1098 1099 1100
	nfs_cleanup_cb_ident_idr(net);
	WARN_ON_ONCE(!list_empty(&nn->nfs_client_list));
	WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list));
}

1101 1102 1103 1104 1105 1106
#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 已提交
1107
static const struct seq_operations nfs_server_list_ops = {
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
	.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 已提交
1119
static const struct seq_operations nfs_volume_list_ops = {
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
	.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)
1130
				__acquires(&nn->nfs_client_lock)
1131
{
1132
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1133

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

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

	return seq_list_next(v, &nn->nfs_client_list, pos);
1147 1148 1149 1150 1151 1152
}

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

	spin_unlock(&nn->nfs_client_lock);
1158 1159 1160 1161 1162 1163 1164 1165
}

/*
 * 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;
1166
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1167 1168

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

1177 1178 1179 1180
	/* Check if the client is initialized */
	if (clp->cl_cons_state != NFS_CS_READY)
		return 0;

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

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

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

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

	return seq_list_next(v, &nn->nfs_volume_list, pos);
1214 1215 1216 1217 1218 1219
}

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

	spin_unlock(&nn->nfs_client_lock);
1225 1226 1227 1228 1229 1230 1231 1232 1233
}

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

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

1248
	snprintf(dev, sizeof(dev), "%u:%u",
1249 1250
		 MAJOR(server->s_dev), MINOR(server->s_dev));

1251
	snprintf(fsid, sizeof(fsid), "%llx:%llx",
1252 1253
		 (unsigned long long) server->fsid.major,
		 (unsigned long long) server->fsid.minor);
1254

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

	return 0;
}

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

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

error_1:
1291
	remove_proc_subtree("nfsfs", net->proc_net);
1292 1293 1294 1295 1296 1297
error_0:
	return -ENOMEM;
}

void nfs_fs_proc_net_exit(struct net *net)
{
1298
	remove_proc_subtree("nfsfs", net->proc_net);
1299 1300
}

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

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

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

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

/*
 * clean up the /proc/fs/nfsfs/ directory
 */
void nfs_fs_proc_exit(void)
{
1329
	remove_proc_subtree("fs/nfsfs", NULL);
1330 1331 1332
}

#endif /* CONFIG_PROC_FS */