client.c 33.3 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
		/* Match the full socket address */
316
		if (!rpc_cmp_addr_port(sap, clap))
317
			/* Match all xprt_switch full socket addresses */
318 319
			if (IS_ERR(clp->cl_rpcclient) ||
                            !rpc_clnt_xprt_switch_has_addr(clp->cl_rpcclient,
320 321
							   sap))
				continue;
322

323
		refcount_inc(&clp->cl_count);
324
		return clp;
325
	}
326
	return NULL;
327 328
}

329 330 331 332 333 334
/*
 * 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)
335
{
336
	return clp->cl_cons_state <= NFS_CS_READY;
337
}
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
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);
356 357 358 359 360 361

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

364 365 366 367 368 369 370 371 372
/*
 * 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;

373
	error = nfs_wait_client_init_complete(clp);
374 375 376 377 378 379 380 381 382 383 384
	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);
	}

385
	smp_rmb();
386 387 388
	return clp;
}

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

P
Peng Tao 已提交
399 400 401 402 403
	if (cl_init->hostname == NULL) {
		WARN_ON(1);
		return NULL;
	}

404 405
	/* see if the client already exists */
	do {
406
		spin_lock(&nn->nfs_client_lock);
407

408
		clp = nfs_match_client(cl_init);
409 410
		if (clp) {
			spin_unlock(&nn->nfs_client_lock);
411 412
			if (IS_ERR(clp))
				return clp;
413
			if (new)
414
				new->rpc_ops->free_client(new);
415 416
			return nfs_found_client(cl_init, clp);
		}
417
		if (new) {
418 419
			list_add_tail(&new->cl_share_link,
					&nn->nfs_client_list);
420
			spin_unlock(&nn->nfs_client_lock);
C
Chuck Lever 已提交
421
			new->cl_flags = cl_init->init_flags;
422
			return rpc_ops->init_client(new, cl_init);
423
		}
424

425
		spin_unlock(&nn->nfs_client_lock);
426

427
		new = rpc_ops->alloc_client(cl_init);
428
	} while (!IS_ERR(new));
429

430
	return new;
431
}
B
Bryan Schumaker 已提交
432
EXPORT_SYMBOL_GPL(nfs_get_client);
433 434 435 436

/*
 * Mark a server as ready or failed
 */
437
void nfs_mark_client_ready(struct nfs_client *clp, int state)
438
{
439
	smp_wmb();
440 441 442
	clp->cl_cons_state = state;
	wake_up_all(&nfs_client_active_wq);
}
B
Bryan Schumaker 已提交
443
EXPORT_SYMBOL_GPL(nfs_mark_client_ready);
444 445 446 447

/*
 * Initialise the timeout values for a connection
 */
448
void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
449
				    int timeo, int retrans)
450 451 452 453 454
{
	to->to_initval = timeo * HZ / 10;
	to->to_retries = retrans;

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

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

C
Chuck Lever 已提交
510
	if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags))
511
		args.flags |= RPC_CLNT_CREATE_DISCRTRY;
512 513
	if (test_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags))
		args.flags |= RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT;
C
Chuck Lever 已提交
514
	if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags))
515
		args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
516 517
	if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags))
		args.flags |= RPC_CLNT_CREATE_INFINITE_SLOTS;
518

519 520 521
	if (!IS_ERR(clp->cl_rpcclient))
		return 0;

522
	clnt = rpc_create(&args);
523 524
	if (IS_ERR(clnt)) {
		dprintk("%s: cannot create RPC client. Error = %ld\n",
525
				__func__, PTR_ERR(clnt));
526 527 528
		return PTR_ERR(clnt);
	}

529
	clnt->cl_principal = clp->cl_principal;
530 531 532
	clp->cl_rpcclient = clnt;
	return 0;
}
B
Bryan Schumaker 已提交
533
EXPORT_SYMBOL_GPL(nfs_create_rpc_client);
534 535 536 537 538 539

/*
 * Version 2 or 3 client destruction
 */
static void nfs_destroy_server(struct nfs_server *server)
{
540
	if (server->nlm_host)
541
		nlmclnt_done(server->nlm_host);
542 543 544 545 546 547 548
}

/*
 * Version 2 or 3 lockd setup
 */
static int nfs_start_lockd(struct nfs_server *server)
{
549 550
	struct nlm_host *host;
	struct nfs_client *clp = server->nfs_client;
551 552 553 554 555
	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,
556 557
		.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?
					1 : 0,
558
		.net		= clp->cl_net,
559
		.nlmclnt_ops 	= clp->cl_nfs_mod->rpc_ops->nlmclnt_ops,
560
		.cred		= current_cred(),
561
	};
562

563
	if (nlm_init.nfs_version > 3)
564
		return 0;
565 566
	if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) &&
			(server->flags & NFS_MOUNT_LOCAL_FCNTL))
567 568
		return 0;

569 570 571 572 573 574 575 576
	switch (clp->cl_proto) {
		default:
			nlm_init.protocol = IPPROTO_TCP;
			break;
		case XPRT_TRANSPORT_UDP:
			nlm_init.protocol = IPPROTO_UDP;
	}

577
	host = nlmclnt_init(&nlm_init);
578 579 580 581 582 583
	if (IS_ERR(host))
		return PTR_ERR(host);

	server->nlm_host = host;
	server->destroy = nfs_destroy_server;
	return 0;
584 585 586 587 588
}

/*
 * Create a general RPC client
 */
589
int nfs_init_server_rpcclient(struct nfs_server *server,
590 591
		const struct rpc_timeout *timeo,
		rpc_authflavor_t pseudoflavour)
592 593 594
{
	struct nfs_client *clp = server->nfs_client;

595 596
	server->client = rpc_clone_client_set_auth(clp->cl_rpcclient,
							pseudoflavour);
597
	if (IS_ERR(server->client)) {
598
		dprintk("%s: couldn't create rpc_client!\n", __func__);
599 600 601
		return PTR_ERR(server->client);
	}

602 603 604 605
	memcpy(&server->client->cl_timeout_default,
			timeo,
			sizeof(server->client->cl_timeout_default));
	server->client->cl_timeout = &server->client->cl_timeout_default;
606
	server->client->cl_softrtry = 0;
607 608
	if (server->flags & NFS_MOUNT_SOFTERR)
		server->client->cl_softerr = 1;
609 610 611 612 613
	if (server->flags & NFS_MOUNT_SOFT)
		server->client->cl_softrtry = 1;

	return 0;
}
B
Bryan Schumaker 已提交
614
EXPORT_SYMBOL_GPL(nfs_init_server_rpcclient);
615

616 617 618 619
/**
 * nfs_init_client - Initialise an NFS2 or NFS3 client
 *
 * @clp: nfs_client to initialise
620
 * @cl_init: Initialisation parameters
621 622
 *
 * Returns pointer to an NFS client, or an ERR_PTR value.
623
 */
624
struct nfs_client *nfs_init_client(struct nfs_client *clp,
625
				   const struct nfs_client_initdata *cl_init)
626 627 628
{
	int error;

A
Anna Schumaker 已提交
629 630
	/* the client is already initialised */
	if (clp->cl_cons_state == NFS_CS_READY)
631
		return clp;
632 633 634 635 636

	/*
	 * Create a client RPC handle for doing FSSTAT with UNIX auth only
	 * - RFC 2623, sec 2.3.2
	 */
637
	error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX);
A
Anna Schumaker 已提交
638 639 640 641 642
	nfs_mark_client_ready(clp, error == 0 ? NFS_CS_READY : error);
	if (error < 0) {
		nfs_put_client(clp);
		clp = ERR_PTR(error);
	}
643
	return clp;
644
}
B
Bryan Schumaker 已提交
645
EXPORT_SYMBOL_GPL(nfs_init_client);
646 647 648 649

/*
 * Create a version 2 or 3 client
 */
650
static int nfs_init_server(struct nfs_server *server,
651 652
			   const struct nfs_parsed_mount_data *data,
			   struct nfs_subversion *nfs_mod)
653
{
654
	struct rpc_timeout timeparms;
655 656
	struct nfs_client_initdata cl_init = {
		.hostname = data->nfs_server.hostname,
657
		.addr = (const struct sockaddr *)&data->nfs_server.address,
658
		.addrlen = data->nfs_server.addrlen,
659
		.nfs_mod = nfs_mod,
660
		.proto = data->nfs_server.protocol,
661
		.net = data->net,
662
		.timeparms = &timeparms,
663
		.cred = server->cred,
664
		.nconnect = data->nfs_server.nconnect,
665
	};
666
	struct nfs_client *clp;
667
	int error;
668

669 670
	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
			data->timeo, data->retrans);
C
Chuck Lever 已提交
671 672
	if (data->flags & NFS_MOUNT_NORESVPORT)
		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
673

674
	/* Allocate or find a client reference we can use */
675
	clp = nfs_get_client(&cl_init);
676
	if (IS_ERR(clp))
677 678 679 680 681
		return PTR_ERR(clp);

	server->nfs_client = clp;

	/* Initialise the client representation from the mount data */
682
	server->flags = data->flags;
683
	server->options = data->options;
684 685
	server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
		NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
686
		NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702

	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;

703
	server->port = data->nfs_server.port;
704
	server->auth_info = data->auth_info;
705

706 707
	error = nfs_init_server_rpcclient(server, &timeparms,
					  data->selected_flavor);
708 709 710
	if (error < 0)
		goto error;

711 712 713 714 715 716 717 718 719 720
	/* 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;

721 722 723 724 725 726 727 728 729 730 731 732
	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
 */
733 734
static void nfs_server_set_fsinfo(struct nfs_server *server,
				  struct nfs_fsinfo *fsinfo)
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
{
	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;
754
	server->rpages = (server->rsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
P
Peter Zijlstra 已提交
755

756 757 758 759
	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;
760
	server->wpages = (server->wsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
R
Ricardo Labiaga 已提交
761

762 763 764
	server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);

	server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
765 766
	if (server->dtsize > PAGE_SIZE * NFS_MAX_READDIR_PAGES)
		server->dtsize = PAGE_SIZE * NFS_MAX_READDIR_PAGES;
767 768 769 770 771 772 773 774 775 776
	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 已提交
777 778
	server->time_delta = fsinfo->time_delta;

779
	server->clone_blksize = fsinfo->clone_blksize;
780 781 782 783 784 785 786
	/* 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
 */
787
int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
788 789 790 791 792 793 794 795
{
	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)
796
			return error;
797 798 799
	}

	fsinfo.fattr = fattr;
800
	fsinfo.nlayouttypes = 0;
801
	memset(fsinfo.layouttype, 0, sizeof(fsinfo.layouttype));
802 803
	error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
	if (error < 0)
804
		return error;
805

806
	nfs_server_set_fsinfo(server, &fsinfo);
807 808 809 810 811 812 813 814 815 816 817 818 819 820

	/* 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 已提交
821
EXPORT_SYMBOL_GPL(nfs_probe_fsinfo);
822 823 824 825

/*
 * Copy useful information when duplicating a server record
 */
826
void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
827 828
{
	target->flags = source->flags;
829 830
	target->rsize = source->rsize;
	target->wsize = source->wsize;
831 832 833 834 835
	target->acregmin = source->acregmin;
	target->acregmax = source->acregmax;
	target->acdirmin = source->acdirmin;
	target->acdirmax = source->acdirmax;
	target->caps = source->caps;
836
	target->options = source->options;
837
	target->auth_info = source->auth_info;
838
	target->port = source->port;
839
}
B
Bryan Schumaker 已提交
840
EXPORT_SYMBOL_GPL(nfs_server_copy_userdata);
841

842
void nfs_server_insert_lists(struct nfs_server *server)
843 844
{
	struct nfs_client *clp = server->nfs_client;
845
	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
846

847
	spin_lock(&nn->nfs_client_lock);
848
	list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
849
	list_add_tail(&server->master_link, &nn->nfs_volume_list);
850
	clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
851
	spin_unlock(&nn->nfs_client_lock);
852 853

}
B
Bryan Schumaker 已提交
854
EXPORT_SYMBOL_GPL(nfs_server_insert_lists);
855

C
Chuck Lever 已提交
856
void nfs_server_remove_lists(struct nfs_server *server)
857
{
858
	struct nfs_client *clp = server->nfs_client;
859
	struct nfs_net *nn;
860

861 862
	if (clp == NULL)
		return;
863
	nn = net_generic(clp->cl_net, nfs_net_id);
864
	spin_lock(&nn->nfs_client_lock);
865
	list_del_rcu(&server->client_link);
866
	if (list_empty(&clp->cl_superblocks))
867
		set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
868
	list_del(&server->master_link);
869
	spin_unlock(&nn->nfs_client_lock);
870 871 872

	synchronize_rcu();
}
C
Chuck Lever 已提交
873
EXPORT_SYMBOL_GPL(nfs_server_remove_lists);
874

875 876 877
/*
 * Allocate and initialise a server record
 */
878
struct nfs_server *nfs_alloc_server(void)
879 880 881 882 883 884 885 886 887 888 889 890
{
	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);
891
	INIT_LIST_HEAD(&server->delegations);
892
	INIT_LIST_HEAD(&server->layouts);
893
	INIT_LIST_HEAD(&server->state_owners_lru);
894
	INIT_LIST_HEAD(&server->ss_copies);
895

896 897
	atomic_set(&server->active, 0);

898 899 900 901 902 903
	server->io_stats = nfs_alloc_iostats();
	if (!server->io_stats) {
		kfree(server);
		return NULL;
	}

904
	ida_init(&server->openowner_id);
905
	ida_init(&server->lockowner_id);
F
Fred Isaman 已提交
906
	pnfs_init_server(server);
907
	rpc_init_wait_queue(&server->uoc_rpcwaitq, "NFS UOC");
F
Fred Isaman 已提交
908

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

/*
 * Free up a server record
 */
void nfs_free_server(struct nfs_server *server)
{
918
	nfs_server_remove_lists(server);
919 920 921

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

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

	nfs_put_client(server->nfs_client);

930
	ida_destroy(&server->lockowner_id);
931
	ida_destroy(&server->openowner_id);
932
	nfs_free_iostats(server->io_stats);
933
	put_cred(server->cred);
934 935 936
	kfree(server);
	nfs_release_automount_timer();
}
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
	server->cred = get_cred(current_cred());

956 957 958 959 960
	error = -ENOMEM;
	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		goto error;

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

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

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

990 991 992
	dprintk("Server FSID: %llx:%llx\n",
		(unsigned long long) server->fsid.major,
		(unsigned long long) server->fsid.minor);
993

994
	nfs_server_insert_lists(server);
995
	server->mount_time = jiffies;
996
	nfs_free_fattr(fattr);
997 998 999
	return server;

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

/*
 * Clone an NFS2, NFS3 or NFS4 server record
 */
struct nfs_server *nfs_clone_server(struct nfs_server *source,
				    struct nfs_fh *fh,
1011 1012
				    struct nfs_fattr *fattr,
				    rpc_authflavor_t flavor)
1013 1014
{
	struct nfs_server *server;
1015
	struct nfs_fattr *fattr_fsinfo;
1016 1017 1018 1019 1020 1021
	int error;

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

1022 1023
	server->cred = get_cred(source->cred);

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

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

	server->fsid = fattr->fsid;

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

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

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

1051 1052 1053 1054
	error = nfs_start_lockd(server);
	if (error < 0)
		goto out_free_server;

1055
	nfs_server_insert_lists(server);
1056 1057
	server->mount_time = jiffies;

1058
	nfs_free_fattr(fattr_fsinfo);
1059 1060 1061
	return server;

out_free_server:
1062
	nfs_free_fattr(fattr_fsinfo);
1063 1064 1065
	nfs_free_server(server);
	return ERR_PTR(error);
}
B
Bryan Schumaker 已提交
1066
EXPORT_SYMBOL_GPL(nfs_clone_server);
1067

1068 1069 1070 1071 1072
void nfs_clients_init(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);

	INIT_LIST_HEAD(&nn->nfs_client_list);
1073
	INIT_LIST_HEAD(&nn->nfs_volume_list);
B
Bryan Schumaker 已提交
1074
#if IS_ENABLED(CONFIG_NFS_V4)
1075 1076
	idr_init(&nn->cb_ident_idr);
#endif
1077
	spin_lock_init(&nn->nfs_client_lock);
1078
	nn->boot_time = ktime_get_real();
1079 1080

	nfs_netns_sysfs_setup(nn, net);
1081 1082
}

1083 1084 1085 1086
void nfs_clients_exit(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);

1087
	nfs_netns_sysfs_destroy(nn);
1088 1089 1090 1091 1092
	nfs_cleanup_cb_ident_idr(net);
	WARN_ON_ONCE(!list_empty(&nn->nfs_client_list));
	WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list));
}

1093 1094 1095 1096 1097 1098
#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 已提交
1099
static const struct seq_operations nfs_server_list_ops = {
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
	.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 已提交
1111
static const struct seq_operations nfs_volume_list_ops = {
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
	.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)
1122
				__acquires(&nn->nfs_client_lock)
1123
{
1124
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1125

1126
	/* lock the list against modification */
1127
	spin_lock(&nn->nfs_client_lock);
1128
	return seq_list_start_head(&nn->nfs_client_list, *_pos);
1129 1130 1131 1132 1133 1134 1135
}

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

	return seq_list_next(v, &nn->nfs_client_list, pos);
1139 1140 1141 1142 1143 1144
}

/*
 * clean up after reading from the transports list
 */
static void nfs_server_list_stop(struct seq_file *p, void *v)
1145
				__releases(&nn->nfs_client_lock)
1146
{
1147
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1148 1149

	spin_unlock(&nn->nfs_client_lock);
1150 1151 1152 1153 1154 1155 1156 1157
}

/*
 * 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;
1158
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1159 1160

	/* display header on line 1 */
1161
	if (v == &nn->nfs_client_list) {
1162 1163 1164 1165 1166 1167 1168
		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);

1169 1170 1171 1172
	/* Check if the client is initialized */
	if (clp->cl_cons_state != NFS_CS_READY)
		return 0;

1173
	rcu_read_lock();
1174
	seq_printf(m, "v%u %s %s %3d %s\n",
1175
		   clp->rpc_ops->version,
1176 1177
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1178
		   refcount_read(&clp->cl_count),
1179
		   clp->cl_hostname);
1180
	rcu_read_unlock();
1181 1182 1183 1184 1185 1186 1187 1188

	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)
1189
				__acquires(&nn->nfs_client_lock)
1190
{
1191
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1192

1193
	/* lock the list against modification */
1194
	spin_lock(&nn->nfs_client_lock);
1195
	return seq_list_start_head(&nn->nfs_volume_list, *_pos);
1196 1197 1198 1199 1200 1201 1202
}

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

	return seq_list_next(v, &nn->nfs_volume_list, pos);
1206 1207 1208 1209 1210 1211
}

/*
 * clean up after reading from the transports list
 */
static void nfs_volume_list_stop(struct seq_file *p, void *v)
1212
				__releases(&nn->nfs_client_lock)
1213
{
1214
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1215 1216

	spin_unlock(&nn->nfs_client_lock);
1217 1218 1219 1220 1221 1222 1223 1224 1225
}

/*
 * 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;
1226 1227
	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'
1228
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1229 1230

	/* display header on line 1 */
1231
	if (v == &nn->nfs_volume_list) {
1232 1233
		seq_puts(m, "NV SERVER   PORT DEV          FSID"
			    "                              FSC\n");
1234 1235 1236 1237 1238 1239
		return 0;
	}
	/* display one transport per line on subsequent lines */
	server = list_entry(v, struct nfs_server, master_link);
	clp = server->nfs_client;

1240
	snprintf(dev, sizeof(dev), "%u:%u",
1241 1242
		 MAJOR(server->s_dev), MINOR(server->s_dev));

1243
	snprintf(fsid, sizeof(fsid), "%llx:%llx",
1244 1245
		 (unsigned long long) server->fsid.major,
		 (unsigned long long) server->fsid.minor);
1246

1247
	rcu_read_lock();
1248
	seq_printf(m, "v%u %s %s %-12s %-33s %s\n",
1249
		   clp->rpc_ops->version,
1250 1251
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1252
		   dev,
D
David Howells 已提交
1253 1254
		   fsid,
		   nfs_server_fscache_state(server));
1255
	rcu_read_unlock();
1256 1257 1258 1259

	return 0;
}

1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
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 */
1270 1271
	p = proc_create_net("servers", S_IFREG|S_IRUGO, nn->proc_nfsfs,
			&nfs_server_list_ops, sizeof(struct seq_net_private));
1272 1273 1274 1275
	if (!p)
		goto error_1;

	/* a file of volumes that we have mounted */
1276 1277
	p = proc_create_net("volumes", S_IFREG|S_IRUGO, nn->proc_nfsfs,
			&nfs_volume_list_ops, sizeof(struct seq_net_private));
1278
	if (!p)
1279
		goto error_1;
1280 1281 1282
	return 0;

error_1:
1283
	remove_proc_subtree("nfsfs", net->proc_net);
1284 1285 1286 1287 1288 1289
error_0:
	return -ENOMEM;
}

void nfs_fs_proc_net_exit(struct net *net)
{
1290
	remove_proc_subtree("nfsfs", net->proc_net);
1291 1292
}

1293 1294 1295 1296 1297
/*
 * initialise the /proc/fs/nfsfs/ directory
 */
int __init nfs_fs_proc_init(void)
{
1298
	if (!proc_mkdir("fs/nfsfs", NULL))
1299 1300 1301
		goto error_0;

	/* a file of servers with which we're dealing */
1302
	if (!proc_symlink("fs/nfsfs/servers", NULL, "../../net/nfsfs/servers"))
1303 1304 1305
		goto error_1;

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

1309
	return 0;
1310
error_1:
1311
	remove_proc_subtree("fs/nfsfs", NULL);
1312 1313 1314 1315 1316 1317 1318 1319 1320
error_0:
	return -ENOMEM;
}

/*
 * clean up the /proc/fs/nfsfs/ directory
 */
void nfs_fs_proc_exit(void)
{
1321
	remove_proc_subtree("fs/nfsfs", NULL);
1322 1323 1324
}

#endif /* CONFIG_PROC_FS */