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


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


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

#define NFSDBG_FACILITY		NFSDBG_CLIENT

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

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

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

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

86 87 88 89 90 91 92 93 94 95
static struct nfs_subversion *find_nfs_version(unsigned int version)
{
	struct nfs_subversion *nfs;
	spin_lock(&nfs_version_lock);

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

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

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

	if (IS_ERR(nfs)) {
		mutex_lock(&nfs_version_mutex);
108
		request_module("nfsv%d", version);
109 110 111 112
		nfs = find_nfs_version(version);
		mutex_unlock(&nfs_version_mutex);
	}

113 114
	if (!IS_ERR(nfs) && !try_module_get(nfs->owner))
		return ERR_PTR(-EAGAIN);
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
	return nfs;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

190 191
	return clp;

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

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

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

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

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

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

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

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

static void pnfs_init_server(struct nfs_server *server)
{
}

236
#endif /* CONFIG_NFS_V4 */
237

238 239 240
/*
 * Destroy a shared client record
 */
241
void nfs_free_client(struct nfs_client *clp)
242
{
243 244
	nfs_fscache_release_client_cookie(clp);

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

249 250 251
	if (clp->cl_machine_cred != NULL)
		put_rpccred(clp->cl_machine_cred);

252
	put_net(clp->cl_net);
253
	put_nfs_version(clp->cl_nfs_mod);
254
	kfree(clp->cl_hostname);
255
	kfree(clp->cl_acceptor);
256 257
	kfree(clp);
}
B
Bryan Schumaker 已提交
258
EXPORT_SYMBOL_GPL(nfs_free_client);
259 260 261 262 263 264

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

D
David Howells 已提交
267 268 269
	if (!clp)
		return;

270
	nn = net_generic(clp->cl_net, nfs_net_id);
271

272
	if (refcount_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {
273
		list_del(&clp->cl_share_link);
A
Andy Adamson 已提交
274
		nfs_cb_idr_remove_locked(clp);
275
		spin_unlock(&nn->nfs_client_lock);
276

277
		WARN_ON_ONCE(!list_empty(&clp->cl_superblocks));
278

279
		clp->rpc_ops->free_client(clp);
280 281
	}
}
282
EXPORT_SYMBOL_GPL(nfs_put_client);
283 284

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

294
again:
295
	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
I
Ian Dall 已提交
296
	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
297 298 299 300
		/* Don't match clients that failed to initialise properly */
		if (clp->cl_cons_state < 0)
			continue;

301 302 303 304 305 306 307 308 309 310
		/* 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);
			nfs_wait_client_init_complete(clp);
			nfs_put_client(clp);
			spin_lock(&nn->nfs_client_lock);
			goto again;
		}

311
		/* Different NFS versions cannot share the same nfs_client */
312
		if (clp->rpc_ops != data->nfs_mod->rpc_ops)
313 314
			continue;

315 316
		if (clp->cl_proto != data->proto)
			continue;
317 318 319
		/* Match nfsv4 minorversion */
		if (clp->cl_minorversion != data->minorversion)
			continue;
320
		/* Match the full socket address */
321
		if (!rpc_cmp_addr_port(sap, clap))
322
			/* Match all xprt_switch full socket addresses */
323 324
			if (IS_ERR(clp->cl_rpcclient) ||
                            !rpc_clnt_xprt_switch_has_addr(clp->cl_rpcclient,
325 326
							   sap))
				continue;
327

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

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

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

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

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

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

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

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

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

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

428
		spin_unlock(&nn->nfs_client_lock);
429

430
		new = rpc_ops->alloc_client(cl_init);
431
	} while (!IS_ERR(new));
432

433
	return new;
434
}
B
Bryan Schumaker 已提交
435
EXPORT_SYMBOL_GPL(nfs_get_client);
436 437 438 439

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

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

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

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

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

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

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

	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
	};
561

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

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

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

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

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

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

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

	return 0;
}
B
Bryan Schumaker 已提交
611
EXPORT_SYMBOL_GPL(nfs_init_server_rpcclient);
612

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

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

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

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

664 665
	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
			data->timeo, data->retrans);
C
Chuck Lever 已提交
666 667
	if (data->flags & NFS_MOUNT_NORESVPORT)
		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
668

669
	/* Allocate or find a client reference we can use */
670
	clp = nfs_get_client(&cl_init);
671
	if (IS_ERR(clp))
672 673 674 675 676
		return PTR_ERR(clp);

	server->nfs_client = clp;

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

	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;

698
	server->port = data->nfs_server.port;
699
	server->auth_info = data->auth_info;
700

701 702
	error = nfs_init_server_rpcclient(server, &timeparms,
					  data->selected_flavor);
703 704 705
	if (error < 0)
		goto error;

706 707 708 709 710 711 712 713 714 715
	/* 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;

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

751 752 753 754
	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;
755
	server->wpages = (server->wsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
R
Ricardo Labiaga 已提交
756

757 758 759
	server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);

	server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
760 761
	if (server->dtsize > PAGE_SIZE * NFS_MAX_READDIR_PAGES)
		server->dtsize = PAGE_SIZE * NFS_MAX_READDIR_PAGES;
762 763 764 765 766 767 768 769 770 771
	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 已提交
772 773
	server->time_delta = fsinfo->time_delta;

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

	fsinfo.fattr = fattr;
795
	fsinfo.nlayouttypes = 0;
796
	memset(fsinfo.layouttype, 0, sizeof(fsinfo.layouttype));
797 798
	error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
	if (error < 0)
799
		return error;
800

801
	nfs_server_set_fsinfo(server, &fsinfo);
802 803 804 805 806 807 808 809 810 811 812 813 814 815

	/* 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 已提交
816
EXPORT_SYMBOL_GPL(nfs_probe_fsinfo);
817 818 819 820

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

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

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

}
B
Bryan Schumaker 已提交
849
EXPORT_SYMBOL_GPL(nfs_server_insert_lists);
850

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

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

	synchronize_rcu();
}
C
Chuck Lever 已提交
868
EXPORT_SYMBOL_GPL(nfs_server_remove_lists);
869

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

890 891
	atomic_set(&server->active, 0);

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

898
	ida_init(&server->openowner_id);
899
	ida_init(&server->lockowner_id);
F
Fred Isaman 已提交
900
	pnfs_init_server(server);
901
	rpc_init_wait_queue(&server->uoc_rpcwaitq, "NFS UOC");
F
Fred Isaman 已提交
902

903 904
	return server;
}
B
Bryan Schumaker 已提交
905
EXPORT_SYMBOL_GPL(nfs_alloc_server);
906 907 908 909 910 911

/*
 * Free up a server record
 */
void nfs_free_server(struct nfs_server *server)
{
912
	nfs_server_remove_lists(server);
913 914 915

	if (server->destroy != NULL)
		server->destroy(server);
916 917 918

	if (!IS_ERR(server->client_acl))
		rpc_shutdown_client(server->client_acl);
919 920 921 922 923
	if (!IS_ERR(server->client))
		rpc_shutdown_client(server->client);

	nfs_put_client(server->nfs_client);

924
	ida_destroy(&server->lockowner_id);
925
	ida_destroy(&server->openowner_id);
926 927 928 929
	nfs_free_iostats(server->io_stats);
	kfree(server);
	nfs_release_automount_timer();
}
B
Bryan Schumaker 已提交
930
EXPORT_SYMBOL_GPL(nfs_free_server);
931 932 933 934 935

/*
 * Create a version 2 or 3 volume record
 * - keyed on server and FSID
 */
936
struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
937
				     struct nfs_subversion *nfs_mod)
938 939
{
	struct nfs_server *server;
940
	struct nfs_fattr *fattr;
941 942 943 944 945 946
	int error;

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

947 948 949 950 951
	error = -ENOMEM;
	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		goto error;

952
	/* Get a client representation */
953
	error = nfs_init_server(server, mount_info->parsed, nfs_mod);
954 955 956 957
	if (error < 0)
		goto error;

	/* Probe the root fh to retrieve its FSID */
958
	error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
959 960
	if (error < 0)
		goto error;
961 962 963
	if (server->nfs_client->rpc_ops->version == 3) {
		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
			server->namelen = NFS3_MAXNAMLEN;
964
		if (!(mount_info->parsed->flags & NFS_MOUNT_NORDIRPLUS))
965 966 967 968 969 970
			server->caps |= NFS_CAP_READDIRPLUS;
	} else {
		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
			server->namelen = NFS2_MAXNAMLEN;
	}

971
	if (!(fattr->valid & NFS_ATTR_FATTR)) {
972 973
		error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh,
				fattr, NULL, NULL);
974 975 976 977 978
		if (error < 0) {
			dprintk("nfs_create_server: getattr error = %d\n", -error);
			goto error;
		}
	}
979
	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
980

981 982 983
	dprintk("Server FSID: %llx:%llx\n",
		(unsigned long long) server->fsid.major,
		(unsigned long long) server->fsid.minor);
984

985
	nfs_server_insert_lists(server);
986
	server->mount_time = jiffies;
987
	nfs_free_fattr(fattr);
988 989 990
	return server;

error:
991
	nfs_free_fattr(fattr);
992 993 994
	nfs_free_server(server);
	return ERR_PTR(error);
}
B
Bryan Schumaker 已提交
995
EXPORT_SYMBOL_GPL(nfs_create_server);
996 997 998 999 1000 1001

/*
 * Clone an NFS2, NFS3 or NFS4 server record
 */
struct nfs_server *nfs_clone_server(struct nfs_server *source,
				    struct nfs_fh *fh,
1002 1003
				    struct nfs_fattr *fattr,
				    rpc_authflavor_t flavor)
1004 1005
{
	struct nfs_server *server;
1006
	struct nfs_fattr *fattr_fsinfo;
1007 1008 1009 1010 1011 1012
	int error;

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

1013 1014 1015 1016 1017
	error = -ENOMEM;
	fattr_fsinfo = nfs_alloc_fattr();
	if (fattr_fsinfo == NULL)
		goto out_free_server;

1018 1019
	/* Copy data from the source */
	server->nfs_client = source->nfs_client;
1020
	server->destroy = source->destroy;
1021
	refcount_inc(&server->nfs_client->cl_count);
1022 1023 1024 1025
	nfs_server_copy_userdata(server, source);

	server->fsid = fattr->fsid;

1026 1027
	error = nfs_init_server_rpcclient(server,
			source->client->cl_timeout,
1028
			flavor);
1029 1030 1031 1032
	if (error < 0)
		goto out_free_server;

	/* probe the filesystem info for this server filesystem */
1033
	error = nfs_probe_fsinfo(server, fh, fattr_fsinfo);
1034 1035 1036
	if (error < 0)
		goto out_free_server;

1037 1038 1039
	if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
		server->namelen = NFS4_MAXNAMLEN;

1040 1041 1042 1043
	error = nfs_start_lockd(server);
	if (error < 0)
		goto out_free_server;

1044
	nfs_server_insert_lists(server);
1045 1046
	server->mount_time = jiffies;

1047
	nfs_free_fattr(fattr_fsinfo);
1048 1049 1050
	return server;

out_free_server:
1051
	nfs_free_fattr(fattr_fsinfo);
1052 1053 1054
	nfs_free_server(server);
	return ERR_PTR(error);
}
B
Bryan Schumaker 已提交
1055
EXPORT_SYMBOL_GPL(nfs_clone_server);
1056

1057 1058 1059 1060 1061
void nfs_clients_init(struct net *net)
{
	struct nfs_net *nn = net_generic(net, nfs_net_id);

	INIT_LIST_HEAD(&nn->nfs_client_list);
1062
	INIT_LIST_HEAD(&nn->nfs_volume_list);
B
Bryan Schumaker 已提交
1063
#if IS_ENABLED(CONFIG_NFS_V4)
1064 1065
	idr_init(&nn->cb_ident_idr);
#endif
1066
	spin_lock_init(&nn->nfs_client_lock);
1067
	nn->boot_time = ktime_get_real();
1068 1069
}

1070 1071 1072 1073 1074 1075
#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 已提交
1076
static const struct seq_operations nfs_server_list_ops = {
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
	.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 已提交
1088
static const struct seq_operations nfs_volume_list_ops = {
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
	.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)
1099
				__acquires(&nn->nfs_client_lock)
1100
{
1101
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1102

1103
	/* lock the list against modification */
1104
	spin_lock(&nn->nfs_client_lock);
1105
	return seq_list_start_head(&nn->nfs_client_list, *_pos);
1106 1107 1108 1109 1110 1111 1112
}

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

	return seq_list_next(v, &nn->nfs_client_list, pos);
1116 1117 1118 1119 1120 1121
}

/*
 * clean up after reading from the transports list
 */
static void nfs_server_list_stop(struct seq_file *p, void *v)
1122
				__releases(&nn->nfs_client_lock)
1123
{
1124
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1125 1126

	spin_unlock(&nn->nfs_client_lock);
1127 1128 1129 1130 1131 1132 1133 1134
}

/*
 * 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;
1135
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1136 1137

	/* display header on line 1 */
1138
	if (v == &nn->nfs_client_list) {
1139 1140 1141 1142 1143 1144 1145
		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);

1146 1147 1148 1149
	/* Check if the client is initialized */
	if (clp->cl_cons_state != NFS_CS_READY)
		return 0;

1150
	rcu_read_lock();
1151
	seq_printf(m, "v%u %s %s %3d %s\n",
1152
		   clp->rpc_ops->version,
1153 1154
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1155
		   refcount_read(&clp->cl_count),
1156
		   clp->cl_hostname);
1157
	rcu_read_unlock();
1158 1159 1160 1161 1162 1163 1164 1165

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

1170
	/* lock the list against modification */
1171
	spin_lock(&nn->nfs_client_lock);
1172
	return seq_list_start_head(&nn->nfs_volume_list, *_pos);
1173 1174 1175 1176 1177 1178 1179
}

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

	return seq_list_next(v, &nn->nfs_volume_list, pos);
1183 1184 1185 1186 1187 1188
}

/*
 * clean up after reading from the transports list
 */
static void nfs_volume_list_stop(struct seq_file *p, void *v)
1189
				__releases(&nn->nfs_client_lock)
1190
{
1191
	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
1192 1193

	spin_unlock(&nn->nfs_client_lock);
1194 1195 1196 1197 1198 1199 1200 1201 1202
}

/*
 * 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;
1203 1204
	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'
1205
	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
1206 1207

	/* display header on line 1 */
1208
	if (v == &nn->nfs_volume_list) {
1209 1210
		seq_puts(m, "NV SERVER   PORT DEV          FSID"
			    "                              FSC\n");
1211 1212 1213 1214 1215 1216
		return 0;
	}
	/* display one transport per line on subsequent lines */
	server = list_entry(v, struct nfs_server, master_link);
	clp = server->nfs_client;

1217
	snprintf(dev, sizeof(dev), "%u:%u",
1218 1219
		 MAJOR(server->s_dev), MINOR(server->s_dev));

1220
	snprintf(fsid, sizeof(fsid), "%llx:%llx",
1221 1222
		 (unsigned long long) server->fsid.major,
		 (unsigned long long) server->fsid.minor);
1223

1224
	rcu_read_lock();
1225
	seq_printf(m, "v%u %s %s %-12s %-33s %s\n",
1226
		   clp->rpc_ops->version,
1227 1228
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
1229
		   dev,
D
David Howells 已提交
1230 1231
		   fsid,
		   nfs_server_fscache_state(server));
1232
	rcu_read_unlock();
1233 1234 1235 1236

	return 0;
}

1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
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 */
1247 1248
	p = proc_create_net("servers", S_IFREG|S_IRUGO, nn->proc_nfsfs,
			&nfs_server_list_ops, sizeof(struct seq_net_private));
1249 1250 1251 1252
	if (!p)
		goto error_1;

	/* a file of volumes that we have mounted */
1253 1254
	p = proc_create_net("volumes", S_IFREG|S_IRUGO, nn->proc_nfsfs,
			&nfs_volume_list_ops, sizeof(struct seq_net_private));
1255
	if (!p)
1256
		goto error_1;
1257 1258 1259
	return 0;

error_1:
1260
	remove_proc_subtree("nfsfs", net->proc_net);
1261 1262 1263 1264 1265 1266
error_0:
	return -ENOMEM;
}

void nfs_fs_proc_net_exit(struct net *net)
{
1267
	remove_proc_subtree("nfsfs", net->proc_net);
1268 1269
}

1270 1271 1272 1273 1274
/*
 * initialise the /proc/fs/nfsfs/ directory
 */
int __init nfs_fs_proc_init(void)
{
1275
	if (!proc_mkdir("fs/nfsfs", NULL))
1276 1277 1278
		goto error_0;

	/* a file of servers with which we're dealing */
1279
	if (!proc_symlink("fs/nfsfs/servers", NULL, "../../net/nfsfs/servers"))
1280 1281 1282
		goto error_1;

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

1286
	return 0;
1287
error_1:
1288
	remove_proc_subtree("fs/nfsfs", NULL);
1289 1290 1291 1292 1293 1294 1295 1296 1297
error_0:
	return -ENOMEM;
}

/*
 * clean up the /proc/fs/nfsfs/ directory
 */
void nfs_fs_proc_exit(void)
{
1298
	remove_proc_subtree("fs/nfsfs", NULL);
1299 1300 1301
}

#endif /* CONFIG_PROC_FS */