NFS: define a function to update nfsi->cache_change_attribute
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / nfs / client.c
CommitLineData
24c8dbbb
DH
1/* client.c: NFS client sharing and management code
2 *
3 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12
24c8dbbb
DH
13#include <linux/module.h>
14#include <linux/init.h>
e8edc6e0 15#include <linux/sched.h>
24c8dbbb
DH
16#include <linux/time.h>
17#include <linux/kernel.h>
18#include <linux/mm.h>
19#include <linux/string.h>
20#include <linux/stat.h>
21#include <linux/errno.h>
22#include <linux/unistd.h>
23#include <linux/sunrpc/clnt.h>
24#include <linux/sunrpc/stats.h>
25#include <linux/sunrpc/metrics.h>
0896a725 26#include <linux/sunrpc/xprtsock.h>
2cf7ff7a 27#include <linux/sunrpc/xprtrdma.h>
24c8dbbb
DH
28#include <linux/nfs_fs.h>
29#include <linux/nfs_mount.h>
30#include <linux/nfs4_mount.h>
31#include <linux/lockd/bind.h>
24c8dbbb
DH
32#include <linux/seq_file.h>
33#include <linux/mount.h>
34#include <linux/nfs_idmap.h>
35#include <linux/vfs.h>
36#include <linux/inet.h>
37#include <linux/nfs_xdr.h>
38
39#include <asm/system.h>
40
41#include "nfs4_fs.h"
42#include "callback.h"
43#include "delegation.h"
44#include "iostat.h"
45#include "internal.h"
46
47#define NFSDBG_FACILITY NFSDBG_CLIENT
48
49static DEFINE_SPINLOCK(nfs_client_lock);
50static LIST_HEAD(nfs_client_list);
54ceac45 51static LIST_HEAD(nfs_volume_list);
24c8dbbb
DH
52static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
53
5006a76c
DH
54/*
55 * RPC cruft for NFS
56 */
57static struct rpc_version *nfs_version[5] = {
58 [2] = &nfs_version2,
59#ifdef CONFIG_NFS_V3
60 [3] = &nfs_version3,
61#endif
62#ifdef CONFIG_NFS_V4
63 [4] = &nfs_version4,
64#endif
65};
66
67struct rpc_program nfs_program = {
68 .name = "nfs",
69 .number = NFS_PROGRAM,
70 .nrvers = ARRAY_SIZE(nfs_version),
71 .version = nfs_version,
72 .stats = &nfs_rpcstat,
73 .pipe_dir_name = "/nfs",
74};
75
76struct rpc_stat nfs_rpcstat = {
77 .program = &nfs_program
78};
79
80
81#ifdef CONFIG_NFS_V3_ACL
82static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
83static struct rpc_version * nfsacl_version[] = {
84 [3] = &nfsacl_version3,
85};
86
87struct rpc_program nfsacl_program = {
88 .name = "nfsacl",
89 .number = NFS_ACL_PROGRAM,
90 .nrvers = ARRAY_SIZE(nfsacl_version),
91 .version = nfsacl_version,
92 .stats = &nfsacl_rpcstat,
93};
94#endif /* CONFIG_NFS_V3_ACL */
95
24c8dbbb
DH
96/*
97 * Allocate a shared client record
98 *
99 * Since these are allocated/deallocated very rarely, we don't
100 * bother putting them in a slab cache...
101 */
102static struct nfs_client *nfs_alloc_client(const char *hostname,
103 const struct sockaddr_in *addr,
104 int nfsversion)
105{
106 struct nfs_client *clp;
24c8dbbb
DH
107
108 if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
109 goto error_0;
110
24c8dbbb
DH
111 if (nfsversion == 4) {
112 if (nfs_callback_up() < 0)
113 goto error_2;
114 __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
115 }
116
117 atomic_set(&clp->cl_count, 1);
118 clp->cl_cons_state = NFS_CS_INITING;
119
120 clp->cl_nfsversion = nfsversion;
121 memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
122
123 if (hostname) {
124 clp->cl_hostname = kstrdup(hostname, GFP_KERNEL);
125 if (!clp->cl_hostname)
126 goto error_3;
127 }
128
129 INIT_LIST_HEAD(&clp->cl_superblocks);
130 clp->cl_rpcclient = ERR_PTR(-EINVAL);
131
132#ifdef CONFIG_NFS_V4
133 init_rwsem(&clp->cl_sem);
134 INIT_LIST_HEAD(&clp->cl_delegations);
24c8dbbb 135 spin_lock_init(&clp->cl_lock);
65f27f38 136 INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
24c8dbbb
DH
137 rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
138 clp->cl_boot_time = CURRENT_TIME;
139 clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
140#endif
141
142 return clp;
143
144error_3:
9c5bf38d
TM
145 if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
146 nfs_callback_down();
24c8dbbb 147error_2:
24c8dbbb
DH
148 kfree(clp);
149error_0:
150 return NULL;
151}
152
5dd3177a
TM
153static void nfs4_shutdown_client(struct nfs_client *clp)
154{
155#ifdef CONFIG_NFS_V4
156 if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
157 nfs4_kill_renewd(clp);
9f958ab8 158 BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners));
5dd3177a
TM
159 if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
160 nfs_idmap_delete(clp);
161#endif
162}
163
24c8dbbb
DH
164/*
165 * Destroy a shared client record
166 */
167static void nfs_free_client(struct nfs_client *clp)
168{
169 dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion);
170
5dd3177a 171 nfs4_shutdown_client(clp);
24c8dbbb
DH
172
173 /* -EIO all pending I/O */
174 if (!IS_ERR(clp->cl_rpcclient))
175 rpc_shutdown_client(clp->cl_rpcclient);
176
177 if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
178 nfs_callback_down();
179
24c8dbbb
DH
180 kfree(clp->cl_hostname);
181 kfree(clp);
182
183 dprintk("<-- nfs_free_client()\n");
184}
185
186/*
187 * Release a reference to a shared client record
188 */
189void nfs_put_client(struct nfs_client *clp)
190{
27ba8512
DH
191 if (!clp)
192 return;
193
24c8dbbb
DH
194 dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
195
196 if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {
197 list_del(&clp->cl_share_link);
198 spin_unlock(&nfs_client_lock);
199
200 BUG_ON(!list_empty(&clp->cl_superblocks));
201
202 nfs_free_client(clp);
203 }
204}
205
206/*
207 * Find a client by address
208 * - caller must hold nfs_client_lock
209 */
13bbc06a 210static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion, int match_port)
24c8dbbb
DH
211{
212 struct nfs_client *clp;
213
214 list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
13bbc06a
TM
215 /* Don't match clients that failed to initialise properly */
216 if (clp->cl_cons_state < 0)
217 continue;
218
24c8dbbb
DH
219 /* Different NFS versions cannot share the same nfs_client */
220 if (clp->cl_nfsversion != nfsversion)
221 continue;
222
d45273ed 223 if (clp->cl_addr.sin_addr.s_addr != addr->sin_addr.s_addr)
24c8dbbb
DH
224 continue;
225
13bbc06a 226 if (!match_port || clp->cl_addr.sin_port == addr->sin_port)
24c8dbbb
DH
227 goto found;
228 }
229
230 return NULL;
231
232found:
233 atomic_inc(&clp->cl_count);
234 return clp;
235}
236
237/*
238 * Find a client by IP address and protocol version
239 * - returns NULL if no such client
240 */
241struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion)
242{
243 struct nfs_client *clp;
244
245 spin_lock(&nfs_client_lock);
13bbc06a 246 clp = __nfs_find_client(addr, nfsversion, 0);
24c8dbbb 247 spin_unlock(&nfs_client_lock);
13bbc06a
TM
248 if (clp != NULL && clp->cl_cons_state != NFS_CS_READY) {
249 nfs_put_client(clp);
250 clp = NULL;
251 }
24c8dbbb
DH
252 return clp;
253}
254
255/*
256 * Look up a client by IP address and protocol version
257 * - creates a new record if one doesn't yet exist
258 */
54ceac45
DH
259static struct nfs_client *nfs_get_client(const char *hostname,
260 const struct sockaddr_in *addr,
261 int nfsversion)
24c8dbbb
DH
262{
263 struct nfs_client *clp, *new = NULL;
264 int error;
265
266 dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n",
267 hostname ?: "", NIPQUAD(addr->sin_addr),
268 addr->sin_port, nfsversion);
269
270 /* see if the client already exists */
271 do {
272 spin_lock(&nfs_client_lock);
273
13bbc06a 274 clp = __nfs_find_client(addr, nfsversion, 1);
24c8dbbb
DH
275 if (clp)
276 goto found_client;
277 if (new)
278 goto install_client;
279
280 spin_unlock(&nfs_client_lock);
281
282 new = nfs_alloc_client(hostname, addr, nfsversion);
283 } while (new);
284
285 return ERR_PTR(-ENOMEM);
286
287 /* install a new client and return with it unready */
288install_client:
289 clp = new;
290 list_add(&clp->cl_share_link, &nfs_client_list);
291 spin_unlock(&nfs_client_lock);
292 dprintk("--> nfs_get_client() = %p [new]\n", clp);
293 return clp;
294
295 /* found an existing client
296 * - make sure it's ready before returning
297 */
298found_client:
299 spin_unlock(&nfs_client_lock);
300
301 if (new)
302 nfs_free_client(new);
303
83250493 304 error = wait_event_interruptible(nfs_client_active_wq,
0bae89ec
TM
305 clp->cl_cons_state != NFS_CS_INITING);
306 if (error < 0) {
307 nfs_put_client(clp);
308 return ERR_PTR(-ERESTARTSYS);
24c8dbbb
DH
309 }
310
311 if (clp->cl_cons_state < NFS_CS_READY) {
312 error = clp->cl_cons_state;
313 nfs_put_client(clp);
314 return ERR_PTR(error);
315 }
316
54ceac45
DH
317 BUG_ON(clp->cl_cons_state != NFS_CS_READY);
318
24c8dbbb
DH
319 dprintk("--> nfs_get_client() = %p [share]\n", clp);
320 return clp;
321}
322
323/*
324 * Mark a server as ready or failed
325 */
54ceac45 326static void nfs_mark_client_ready(struct nfs_client *clp, int state)
24c8dbbb
DH
327{
328 clp->cl_cons_state = state;
329 wake_up_all(&nfs_client_active_wq);
330}
5006a76c
DH
331
332/*
333 * Initialise the timeout values for a connection
334 */
335static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
336 unsigned int timeo, unsigned int retrans)
337{
338 to->to_initval = timeo * HZ / 10;
339 to->to_retries = retrans;
340 if (!to->to_retries)
341 to->to_retries = 2;
342
343 switch (proto) {
0896a725 344 case XPRT_TRANSPORT_TCP:
2cf7ff7a 345 case XPRT_TRANSPORT_RDMA:
5006a76c
DH
346 if (!to->to_initval)
347 to->to_initval = 60 * HZ;
348 if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
349 to->to_initval = NFS_MAX_TCP_TIMEOUT;
350 to->to_increment = to->to_initval;
351 to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
352 to->to_exponential = 0;
353 break;
0896a725 354 case XPRT_TRANSPORT_UDP:
5006a76c
DH
355 default:
356 if (!to->to_initval)
357 to->to_initval = 11 * HZ / 10;
358 if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
359 to->to_initval = NFS_MAX_UDP_TIMEOUT;
360 to->to_maxval = NFS_MAX_UDP_TIMEOUT;
361 to->to_exponential = 1;
362 break;
363 }
364}
365
366/*
367 * Create an RPC client handle
368 */
54ceac45
DH
369static int nfs_create_rpc_client(struct nfs_client *clp, int proto,
370 unsigned int timeo,
371 unsigned int retrans,
43d78ef2
CL
372 rpc_authflavor_t flavor,
373 int flags)
5006a76c
DH
374{
375 struct rpc_timeout timeparms;
5006a76c 376 struct rpc_clnt *clnt = NULL;
41877d20
CL
377 struct rpc_create_args args = {
378 .protocol = proto,
379 .address = (struct sockaddr *)&clp->cl_addr,
380 .addrsize = sizeof(clp->cl_addr),
381 .timeout = &timeparms,
382 .servername = clp->cl_hostname,
383 .program = &nfs_program,
384 .version = clp->rpc_ops->version,
385 .authflavor = flavor,
43d78ef2 386 .flags = flags,
41877d20 387 };
5006a76c
DH
388
389 if (!IS_ERR(clp->cl_rpcclient))
390 return 0;
391
392 nfs_init_timeout_values(&timeparms, proto, timeo, retrans);
393 clp->retrans_timeo = timeparms.to_initval;
394 clp->retrans_count = timeparms.to_retries;
395
41877d20 396 clnt = rpc_create(&args);
5006a76c
DH
397 if (IS_ERR(clnt)) {
398 dprintk("%s: cannot create RPC client. Error = %ld\n",
399 __FUNCTION__, PTR_ERR(clnt));
400 return PTR_ERR(clnt);
401 }
402
5006a76c
DH
403 clp->cl_rpcclient = clnt;
404 return 0;
405}
54ceac45
DH
406
407/*
408 * Version 2 or 3 client destruction
409 */
410static void nfs_destroy_server(struct nfs_server *server)
411{
54ceac45
DH
412 if (!(server->flags & NFS_MOUNT_NONLM))
413 lockd_down(); /* release rpc.lockd */
414}
415
416/*
417 * Version 2 or 3 lockd setup
418 */
419static int nfs_start_lockd(struct nfs_server *server)
420{
421 int error = 0;
422
423 if (server->nfs_client->cl_nfsversion > 3)
424 goto out;
425 if (server->flags & NFS_MOUNT_NONLM)
426 goto out;
24e36663
N
427 error = lockd_up((server->flags & NFS_MOUNT_TCP) ?
428 IPPROTO_TCP : IPPROTO_UDP);
54ceac45
DH
429 if (error < 0)
430 server->flags |= NFS_MOUNT_NONLM;
431 else
432 server->destroy = nfs_destroy_server;
433out:
434 return error;
435}
436
437/*
438 * Initialise an NFSv3 ACL client connection
439 */
440#ifdef CONFIG_NFS_V3_ACL
441static void nfs_init_server_aclclient(struct nfs_server *server)
442{
443 if (server->nfs_client->cl_nfsversion != 3)
444 goto out_noacl;
445 if (server->flags & NFS_MOUNT_NOACL)
446 goto out_noacl;
447
448 server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
449 if (IS_ERR(server->client_acl))
450 goto out_noacl;
451
452 /* No errors! Assume that Sun nfsacls are supported */
453 server->caps |= NFS_CAP_ACLS;
454 return;
455
456out_noacl:
457 server->caps &= ~NFS_CAP_ACLS;
458}
459#else
460static inline void nfs_init_server_aclclient(struct nfs_server *server)
461{
462 server->flags &= ~NFS_MOUNT_NOACL;
463 server->caps &= ~NFS_CAP_ACLS;
464}
465#endif
466
467/*
468 * Create a general RPC client
469 */
470static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t pseudoflavour)
471{
472 struct nfs_client *clp = server->nfs_client;
473
474 server->client = rpc_clone_client(clp->cl_rpcclient);
475 if (IS_ERR(server->client)) {
476 dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__);
477 return PTR_ERR(server->client);
478 }
479
480 if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) {
481 struct rpc_auth *auth;
482
483 auth = rpcauth_create(pseudoflavour, server->client);
484 if (IS_ERR(auth)) {
485 dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
486 return PTR_ERR(auth);
487 }
488 }
489 server->client->cl_softrtry = 0;
490 if (server->flags & NFS_MOUNT_SOFT)
491 server->client->cl_softrtry = 1;
492
493 server->client->cl_intr = 0;
494 if (server->flags & NFS4_MOUNT_INTR)
495 server->client->cl_intr = 1;
496
497 return 0;
498}
499
500/*
501 * Initialise an NFS2 or NFS3 client
502 */
2283f8d6
TT
503static int nfs_init_client(struct nfs_client *clp,
504 const struct nfs_parsed_mount_data *data)
54ceac45 505{
54ceac45
DH
506 int error;
507
508 if (clp->cl_cons_state == NFS_CS_READY) {
509 /* the client is already initialised */
510 dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp);
511 return 0;
512 }
513
514 /* Check NFS protocol revision and initialize RPC op vector */
515 clp->rpc_ops = &nfs_v2_clientops;
516#ifdef CONFIG_NFS_V3
517 if (clp->cl_nfsversion == 3)
518 clp->rpc_ops = &nfs_v3_clientops;
519#endif
520 /*
521 * Create a client RPC handle for doing FSSTAT with UNIX auth only
522 * - RFC 2623, sec 2.3.2
523 */
2283f8d6
TT
524 error = nfs_create_rpc_client(clp, data->nfs_server.protocol,
525 data->timeo, data->retrans, RPC_AUTH_UNIX, 0);
54ceac45
DH
526 if (error < 0)
527 goto error;
528 nfs_mark_client_ready(clp, NFS_CS_READY);
529 return 0;
530
531error:
532 nfs_mark_client_ready(clp, error);
533 dprintk("<-- nfs_init_client() = xerror %d\n", error);
534 return error;
535}
536
537/*
538 * Create a version 2 or 3 client
539 */
2283f8d6
TT
540static int nfs_init_server(struct nfs_server *server,
541 const struct nfs_parsed_mount_data *data)
54ceac45
DH
542{
543 struct nfs_client *clp;
544 int error, nfsvers = 2;
545
546 dprintk("--> nfs_init_server()\n");
547
548#ifdef CONFIG_NFS_V3
549 if (data->flags & NFS_MOUNT_VER3)
550 nfsvers = 3;
551#endif
552
553 /* Allocate or find a client reference we can use */
2283f8d6
TT
554 clp = nfs_get_client(data->nfs_server.hostname,
555 &data->nfs_server.address, nfsvers);
54ceac45
DH
556 if (IS_ERR(clp)) {
557 dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
558 return PTR_ERR(clp);
559 }
560
561 error = nfs_init_client(clp, data);
562 if (error < 0)
563 goto error;
564
565 server->nfs_client = clp;
566
567 /* Initialise the client representation from the mount data */
568 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
569
570 if (data->rsize)
571 server->rsize = nfs_block_size(data->rsize, NULL);
572 if (data->wsize)
573 server->wsize = nfs_block_size(data->wsize, NULL);
574
575 server->acregmin = data->acregmin * HZ;
576 server->acregmax = data->acregmax * HZ;
577 server->acdirmin = data->acdirmin * HZ;
578 server->acdirmax = data->acdirmax * HZ;
579
580 /* Start lockd here, before we might error out */
581 error = nfs_start_lockd(server);
582 if (error < 0)
583 goto error;
584
2283f8d6 585 error = nfs_init_server_rpcclient(server, data->auth_flavors[0]);
54ceac45
DH
586 if (error < 0)
587 goto error;
588
589 server->namelen = data->namlen;
590 /* Create a client RPC handle for the NFSv3 ACL management interface */
591 nfs_init_server_aclclient(server);
54ceac45
DH
592 dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp);
593 return 0;
594
595error:
596 server->nfs_client = NULL;
597 nfs_put_client(clp);
598 dprintk("<-- nfs_init_server() = xerror %d\n", error);
599 return error;
600}
601
602/*
603 * Load up the server record from information gained in an fsinfo record
604 */
605static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *fsinfo)
606{
607 unsigned long max_rpc_payload;
608
609 /* Work out a lot of parameters */
610 if (server->rsize == 0)
611 server->rsize = nfs_block_size(fsinfo->rtpref, NULL);
612 if (server->wsize == 0)
613 server->wsize = nfs_block_size(fsinfo->wtpref, NULL);
614
615 if (fsinfo->rtmax >= 512 && server->rsize > fsinfo->rtmax)
616 server->rsize = nfs_block_size(fsinfo->rtmax, NULL);
617 if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax)
618 server->wsize = nfs_block_size(fsinfo->wtmax, NULL);
619
620 max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
621 if (server->rsize > max_rpc_payload)
622 server->rsize = max_rpc_payload;
623 if (server->rsize > NFS_MAX_FILE_IO_SIZE)
624 server->rsize = NFS_MAX_FILE_IO_SIZE;
625 server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
e0bf68dd 626
54ceac45
DH
627 server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
628
629 if (server->wsize > max_rpc_payload)
630 server->wsize = max_rpc_payload;
631 if (server->wsize > NFS_MAX_FILE_IO_SIZE)
632 server->wsize = NFS_MAX_FILE_IO_SIZE;
633 server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
634 server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
635
636 server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
637 if (server->dtsize > PAGE_CACHE_SIZE)
638 server->dtsize = PAGE_CACHE_SIZE;
639 if (server->dtsize > server->rsize)
640 server->dtsize = server->rsize;
641
642 if (server->flags & NFS_MOUNT_NOAC) {
643 server->acregmin = server->acregmax = 0;
644 server->acdirmin = server->acdirmax = 0;
645 }
646
647 server->maxfilesize = fsinfo->maxfilesize;
648
649 /* We're airborne Set socket buffersize */
650 rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
651}
652
653/*
654 * Probe filesystem information, including the FSID on v2/v3
655 */
656static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
657{
658 struct nfs_fsinfo fsinfo;
659 struct nfs_client *clp = server->nfs_client;
660 int error;
661
662 dprintk("--> nfs_probe_fsinfo()\n");
663
664 if (clp->rpc_ops->set_capabilities != NULL) {
665 error = clp->rpc_ops->set_capabilities(server, mntfh);
666 if (error < 0)
667 goto out_error;
668 }
669
670 fsinfo.fattr = fattr;
671 nfs_fattr_init(fattr);
672 error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
673 if (error < 0)
674 goto out_error;
675
676 nfs_server_set_fsinfo(server, &fsinfo);
e0bf68dd
PZ
677 error = bdi_init(&server->backing_dev_info);
678 if (error)
679 goto out_error;
680
54ceac45
DH
681
682 /* Get some general file system info */
683 if (server->namelen == 0) {
684 struct nfs_pathconf pathinfo;
685
686 pathinfo.fattr = fattr;
687 nfs_fattr_init(fattr);
688
689 if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0)
690 server->namelen = pathinfo.max_namelen;
691 }
692
693 dprintk("<-- nfs_probe_fsinfo() = 0\n");
694 return 0;
695
696out_error:
697 dprintk("nfs_probe_fsinfo: error = %d\n", -error);
698 return error;
699}
700
701/*
702 * Copy useful information when duplicating a server record
703 */
704static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
705{
706 target->flags = source->flags;
707 target->acregmin = source->acregmin;
708 target->acregmax = source->acregmax;
709 target->acdirmin = source->acdirmin;
710 target->acdirmax = source->acdirmax;
711 target->caps = source->caps;
712}
713
714/*
715 * Allocate and initialise a server record
716 */
717static struct nfs_server *nfs_alloc_server(void)
718{
719 struct nfs_server *server;
720
721 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
722 if (!server)
723 return NULL;
724
725 server->client = server->client_acl = ERR_PTR(-EINVAL);
726
727 /* Zero out the NFS state stuff */
728 INIT_LIST_HEAD(&server->client_link);
729 INIT_LIST_HEAD(&server->master_link);
730
ef818a28
SD
731 init_waitqueue_head(&server->active_wq);
732 atomic_set(&server->active, 0);
733
54ceac45
DH
734 server->io_stats = nfs_alloc_iostats();
735 if (!server->io_stats) {
736 kfree(server);
737 return NULL;
738 }
739
740 return server;
741}
742
743/*
744 * Free up a server record
745 */
746void nfs_free_server(struct nfs_server *server)
747{
748 dprintk("--> nfs_free_server()\n");
749
750 spin_lock(&nfs_client_lock);
751 list_del(&server->client_link);
752 list_del(&server->master_link);
753 spin_unlock(&nfs_client_lock);
754
755 if (server->destroy != NULL)
756 server->destroy(server);
5cef338b
TM
757
758 if (!IS_ERR(server->client_acl))
759 rpc_shutdown_client(server->client_acl);
54ceac45
DH
760 if (!IS_ERR(server->client))
761 rpc_shutdown_client(server->client);
762
763 nfs_put_client(server->nfs_client);
764
765 nfs_free_iostats(server->io_stats);
e0bf68dd 766 bdi_destroy(&server->backing_dev_info);
54ceac45
DH
767 kfree(server);
768 nfs_release_automount_timer();
769 dprintk("<-- nfs_free_server()\n");
770}
771
772/*
773 * Create a version 2 or 3 volume record
774 * - keyed on server and FSID
775 */
2283f8d6 776struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
54ceac45
DH
777 struct nfs_fh *mntfh)
778{
779 struct nfs_server *server;
780 struct nfs_fattr fattr;
781 int error;
782
783 server = nfs_alloc_server();
784 if (!server)
785 return ERR_PTR(-ENOMEM);
786
787 /* Get a client representation */
788 error = nfs_init_server(server, data);
789 if (error < 0)
790 goto error;
791
792 BUG_ON(!server->nfs_client);
793 BUG_ON(!server->nfs_client->rpc_ops);
794 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
795
796 /* Probe the root fh to retrieve its FSID */
797 error = nfs_probe_fsinfo(server, mntfh, &fattr);
798 if (error < 0)
799 goto error;
54af3bb5
TM
800 if (server->nfs_client->rpc_ops->version == 3) {
801 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
802 server->namelen = NFS3_MAXNAMLEN;
803 if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
804 server->caps |= NFS_CAP_READDIRPLUS;
805 } else {
806 if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
807 server->namelen = NFS2_MAXNAMLEN;
808 }
809
54ceac45
DH
810 if (!(fattr.valid & NFS_ATTR_FATTR)) {
811 error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
812 if (error < 0) {
813 dprintk("nfs_create_server: getattr error = %d\n", -error);
814 goto error;
815 }
816 }
817 memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
818
6daabf1b
DH
819 dprintk("Server FSID: %llx:%llx\n",
820 (unsigned long long) server->fsid.major,
821 (unsigned long long) server->fsid.minor);
54ceac45
DH
822
823 BUG_ON(!server->nfs_client);
824 BUG_ON(!server->nfs_client->rpc_ops);
825 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
826
827 spin_lock(&nfs_client_lock);
828 list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
829 list_add_tail(&server->master_link, &nfs_volume_list);
830 spin_unlock(&nfs_client_lock);
831
832 server->mount_time = jiffies;
833 return server;
834
835error:
836 nfs_free_server(server);
837 return ERR_PTR(error);
838}
839
840#ifdef CONFIG_NFS_V4
841/*
842 * Initialise an NFS4 client record
843 */
844static int nfs4_init_client(struct nfs_client *clp,
845 int proto, int timeo, int retrans,
7d9ac06f 846 const char *ip_addr,
54ceac45
DH
847 rpc_authflavor_t authflavour)
848{
849 int error;
850
851 if (clp->cl_cons_state == NFS_CS_READY) {
852 /* the client is initialised already */
853 dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
854 return 0;
855 }
856
857 /* Check NFS protocol revision and initialize RPC op vector */
858 clp->rpc_ops = &nfs_v4_clientops;
859
43d78ef2
CL
860 error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour,
861 RPC_CLNT_CREATE_DISCRTRY);
54ceac45
DH
862 if (error < 0)
863 goto error;
7d9ac06f 864 memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
54ceac45
DH
865
866 error = nfs_idmap_new(clp);
867 if (error < 0) {
868 dprintk("%s: failed to create idmapper. Error = %d\n",
869 __FUNCTION__, error);
54ceac45
DH
870 goto error;
871 }
9c5bf38d 872 __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
54ceac45
DH
873
874 nfs_mark_client_ready(clp, NFS_CS_READY);
875 return 0;
876
877error:
878 nfs_mark_client_ready(clp, error);
879 dprintk("<-- nfs4_init_client() = xerror %d\n", error);
880 return error;
881}
882
883/*
884 * Set up an NFS4 client
885 */
886static int nfs4_set_client(struct nfs_server *server,
887 const char *hostname, const struct sockaddr_in *addr,
7d9ac06f 888 const char *ip_addr,
54ceac45
DH
889 rpc_authflavor_t authflavour,
890 int proto, int timeo, int retrans)
891{
892 struct nfs_client *clp;
893 int error;
894
895 dprintk("--> nfs4_set_client()\n");
896
897 /* Allocate or find a client reference we can use */
898 clp = nfs_get_client(hostname, addr, 4);
899 if (IS_ERR(clp)) {
900 error = PTR_ERR(clp);
901 goto error;
902 }
7d9ac06f 903 error = nfs4_init_client(clp, proto, timeo, retrans, ip_addr, authflavour);
54ceac45
DH
904 if (error < 0)
905 goto error_put;
906
907 server->nfs_client = clp;
908 dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
909 return 0;
910
911error_put:
912 nfs_put_client(clp);
913error:
914 dprintk("<-- nfs4_set_client() = xerror %d\n", error);
915 return error;
916}
917
918/*
919 * Create a version 4 volume record
920 */
921static int nfs4_init_server(struct nfs_server *server,
91ea40b9 922 const struct nfs_parsed_mount_data *data)
54ceac45
DH
923{
924 int error;
925
926 dprintk("--> nfs4_init_server()\n");
927
928 /* Initialise the client representation from the mount data */
929 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
930 server->caps |= NFS_CAP_ATOMIC_OPEN;
931
932 if (data->rsize)
933 server->rsize = nfs_block_size(data->rsize, NULL);
934 if (data->wsize)
935 server->wsize = nfs_block_size(data->wsize, NULL);
936
937 server->acregmin = data->acregmin * HZ;
938 server->acregmax = data->acregmax * HZ;
939 server->acdirmin = data->acdirmin * HZ;
940 server->acdirmax = data->acdirmax * HZ;
941
91ea40b9 942 error = nfs_init_server_rpcclient(server, data->auth_flavors[0]);
54ceac45
DH
943
944 /* Done */
945 dprintk("<-- nfs4_init_server() = %d\n", error);
946 return error;
947}
948
949/*
950 * Create a version 4 volume record
951 * - keyed on server and FSID
952 */
91ea40b9 953struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
54ceac45
DH
954 struct nfs_fh *mntfh)
955{
956 struct nfs_fattr fattr;
957 struct nfs_server *server;
958 int error;
959
960 dprintk("--> nfs4_create_server()\n");
961
962 server = nfs_alloc_server();
963 if (!server)
964 return ERR_PTR(-ENOMEM);
965
966 /* Get a client record */
91ea40b9
TT
967 error = nfs4_set_client(server,
968 data->nfs_server.hostname,
969 &data->nfs_server.address,
970 data->client_address,
971 data->auth_flavors[0],
972 data->nfs_server.protocol,
973 data->timeo, data->retrans);
54ceac45
DH
974 if (error < 0)
975 goto error;
976
977 /* set up the general RPC client */
91ea40b9 978 error = nfs4_init_server(server, data);
54ceac45
DH
979 if (error < 0)
980 goto error;
981
982 BUG_ON(!server->nfs_client);
983 BUG_ON(!server->nfs_client->rpc_ops);
984 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
985
986 /* Probe the root fh to retrieve its FSID */
91ea40b9 987 error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path);
54ceac45
DH
988 if (error < 0)
989 goto error;
990
6daabf1b
DH
991 dprintk("Server FSID: %llx:%llx\n",
992 (unsigned long long) server->fsid.major,
993 (unsigned long long) server->fsid.minor);
54ceac45
DH
994 dprintk("Mount FH: %d\n", mntfh->size);
995
996 error = nfs_probe_fsinfo(server, mntfh, &fattr);
997 if (error < 0)
998 goto error;
999
54af3bb5
TM
1000 if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
1001 server->namelen = NFS4_MAXNAMLEN;
1002
54ceac45
DH
1003 BUG_ON(!server->nfs_client);
1004 BUG_ON(!server->nfs_client->rpc_ops);
1005 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
1006
1007 spin_lock(&nfs_client_lock);
1008 list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
1009 list_add_tail(&server->master_link, &nfs_volume_list);
1010 spin_unlock(&nfs_client_lock);
1011
1012 server->mount_time = jiffies;
1013 dprintk("<-- nfs4_create_server() = %p\n", server);
1014 return server;
1015
1016error:
1017 nfs_free_server(server);
1018 dprintk("<-- nfs4_create_server() = error %d\n", error);
1019 return ERR_PTR(error);
1020}
1021
1022/*
1023 * Create an NFS4 referral server record
1024 */
1025struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
f2d0d85e 1026 struct nfs_fh *mntfh)
54ceac45
DH
1027{
1028 struct nfs_client *parent_client;
1029 struct nfs_server *server, *parent_server;
1030 struct nfs_fattr fattr;
1031 int error;
1032
1033 dprintk("--> nfs4_create_referral_server()\n");
1034
1035 server = nfs_alloc_server();
1036 if (!server)
1037 return ERR_PTR(-ENOMEM);
1038
1039 parent_server = NFS_SB(data->sb);
1040 parent_client = parent_server->nfs_client;
1041
1042 /* Get a client representation.
1043 * Note: NFSv4 always uses TCP, */
1044 error = nfs4_set_client(server, data->hostname, data->addr,
7d9ac06f 1045 parent_client->cl_ipaddr,
54ceac45
DH
1046 data->authflavor,
1047 parent_server->client->cl_xprt->prot,
1048 parent_client->retrans_timeo,
1049 parent_client->retrans_count);
297de4f6
AA
1050 if (error < 0)
1051 goto error;
54ceac45
DH
1052
1053 /* Initialise the client representation from the parent server */
1054 nfs_server_copy_userdata(server, parent_server);
1055 server->caps |= NFS_CAP_ATOMIC_OPEN;
1056
1057 error = nfs_init_server_rpcclient(server, data->authflavor);
1058 if (error < 0)
1059 goto error;
1060
1061 BUG_ON(!server->nfs_client);
1062 BUG_ON(!server->nfs_client->rpc_ops);
1063 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
1064
f2d0d85e
TM
1065 /* Probe the root fh to retrieve its FSID and filehandle */
1066 error = nfs4_path_walk(server, mntfh, data->mnt_path);
1067 if (error < 0)
1068 goto error;
1069
54ceac45 1070 /* probe the filesystem info for this server filesystem */
f2d0d85e 1071 error = nfs_probe_fsinfo(server, mntfh, &fattr);
54ceac45
DH
1072 if (error < 0)
1073 goto error;
1074
54af3bb5
TM
1075 if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
1076 server->namelen = NFS4_MAXNAMLEN;
1077
54ceac45 1078 dprintk("Referral FSID: %llx:%llx\n",
6daabf1b
DH
1079 (unsigned long long) server->fsid.major,
1080 (unsigned long long) server->fsid.minor);
54ceac45
DH
1081
1082 spin_lock(&nfs_client_lock);
1083 list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
1084 list_add_tail(&server->master_link, &nfs_volume_list);
1085 spin_unlock(&nfs_client_lock);
1086
1087 server->mount_time = jiffies;
1088
1089 dprintk("<-- nfs_create_referral_server() = %p\n", server);
1090 return server;
1091
1092error:
1093 nfs_free_server(server);
1094 dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
1095 return ERR_PTR(error);
1096}
1097
1098#endif /* CONFIG_NFS_V4 */
1099
1100/*
1101 * Clone an NFS2, NFS3 or NFS4 server record
1102 */
1103struct nfs_server *nfs_clone_server(struct nfs_server *source,
1104 struct nfs_fh *fh,
1105 struct nfs_fattr *fattr)
1106{
1107 struct nfs_server *server;
1108 struct nfs_fattr fattr_fsinfo;
1109 int error;
1110
1111 dprintk("--> nfs_clone_server(,%llx:%llx,)\n",
6daabf1b
DH
1112 (unsigned long long) fattr->fsid.major,
1113 (unsigned long long) fattr->fsid.minor);
54ceac45
DH
1114
1115 server = nfs_alloc_server();
1116 if (!server)
1117 return ERR_PTR(-ENOMEM);
1118
1119 /* Copy data from the source */
1120 server->nfs_client = source->nfs_client;
1121 atomic_inc(&server->nfs_client->cl_count);
1122 nfs_server_copy_userdata(server, source);
1123
1124 server->fsid = fattr->fsid;
1125
1126 error = nfs_init_server_rpcclient(server, source->client->cl_auth->au_flavor);
1127 if (error < 0)
1128 goto out_free_server;
1129 if (!IS_ERR(source->client_acl))
1130 nfs_init_server_aclclient(server);
1131
1132 /* probe the filesystem info for this server filesystem */
1133 error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo);
1134 if (error < 0)
1135 goto out_free_server;
1136
54af3bb5
TM
1137 if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
1138 server->namelen = NFS4_MAXNAMLEN;
1139
54ceac45 1140 dprintk("Cloned FSID: %llx:%llx\n",
6daabf1b
DH
1141 (unsigned long long) server->fsid.major,
1142 (unsigned long long) server->fsid.minor);
54ceac45
DH
1143
1144 error = nfs_start_lockd(server);
1145 if (error < 0)
1146 goto out_free_server;
1147
1148 spin_lock(&nfs_client_lock);
1149 list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
1150 list_add_tail(&server->master_link, &nfs_volume_list);
1151 spin_unlock(&nfs_client_lock);
1152
1153 server->mount_time = jiffies;
1154
1155 dprintk("<-- nfs_clone_server() = %p\n", server);
1156 return server;
1157
1158out_free_server:
1159 nfs_free_server(server);
1160 dprintk("<-- nfs_clone_server() = error %d\n", error);
1161 return ERR_PTR(error);
1162}
6aaca566
DH
1163
1164#ifdef CONFIG_PROC_FS
1165static struct proc_dir_entry *proc_fs_nfs;
1166
1167static int nfs_server_list_open(struct inode *inode, struct file *file);
1168static void *nfs_server_list_start(struct seq_file *p, loff_t *pos);
1169static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos);
1170static void nfs_server_list_stop(struct seq_file *p, void *v);
1171static int nfs_server_list_show(struct seq_file *m, void *v);
1172
1173static struct seq_operations nfs_server_list_ops = {
1174 .start = nfs_server_list_start,
1175 .next = nfs_server_list_next,
1176 .stop = nfs_server_list_stop,
1177 .show = nfs_server_list_show,
1178};
1179
00977a59 1180static const struct file_operations nfs_server_list_fops = {
6aaca566
DH
1181 .open = nfs_server_list_open,
1182 .read = seq_read,
1183 .llseek = seq_lseek,
1184 .release = seq_release,
1185};
1186
1187static int nfs_volume_list_open(struct inode *inode, struct file *file);
1188static void *nfs_volume_list_start(struct seq_file *p, loff_t *pos);
1189static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos);
1190static void nfs_volume_list_stop(struct seq_file *p, void *v);
1191static int nfs_volume_list_show(struct seq_file *m, void *v);
1192
1193static struct seq_operations nfs_volume_list_ops = {
1194 .start = nfs_volume_list_start,
1195 .next = nfs_volume_list_next,
1196 .stop = nfs_volume_list_stop,
1197 .show = nfs_volume_list_show,
1198};
1199
00977a59 1200static const struct file_operations nfs_volume_list_fops = {
6aaca566
DH
1201 .open = nfs_volume_list_open,
1202 .read = seq_read,
1203 .llseek = seq_lseek,
1204 .release = seq_release,
1205};
1206
1207/*
1208 * open "/proc/fs/nfsfs/servers" which provides a summary of servers with which
1209 * we're dealing
1210 */
1211static int nfs_server_list_open(struct inode *inode, struct file *file)
1212{
1213 struct seq_file *m;
1214 int ret;
1215
1216 ret = seq_open(file, &nfs_server_list_ops);
1217 if (ret < 0)
1218 return ret;
1219
1220 m = file->private_data;
1221 m->private = PDE(inode)->data;
1222
1223 return 0;
1224}
1225
1226/*
1227 * set up the iterator to start reading from the server list and return the first item
1228 */
1229static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
1230{
6aaca566
DH
1231 /* lock the list against modification */
1232 spin_lock(&nfs_client_lock);
259902ea 1233 return seq_list_start_head(&nfs_client_list, *_pos);
6aaca566
DH
1234}
1235
1236/*
1237 * move to next server
1238 */
1239static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
1240{
259902ea 1241 return seq_list_next(v, &nfs_client_list, pos);
6aaca566
DH
1242}
1243
1244/*
1245 * clean up after reading from the transports list
1246 */
1247static void nfs_server_list_stop(struct seq_file *p, void *v)
1248{
1249 spin_unlock(&nfs_client_lock);
1250}
1251
1252/*
1253 * display a header line followed by a load of call lines
1254 */
1255static int nfs_server_list_show(struct seq_file *m, void *v)
1256{
1257 struct nfs_client *clp;
1258
1259 /* display header on line 1 */
259902ea 1260 if (v == &nfs_client_list) {
6aaca566
DH
1261 seq_puts(m, "NV SERVER PORT USE HOSTNAME\n");
1262 return 0;
1263 }
1264
1265 /* display one transport per line on subsequent lines */
1266 clp = list_entry(v, struct nfs_client, cl_share_link);
1267
1268 seq_printf(m, "v%d %02x%02x%02x%02x %4hx %3d %s\n",
1269 clp->cl_nfsversion,
1270 NIPQUAD(clp->cl_addr.sin_addr),
1271 ntohs(clp->cl_addr.sin_port),
1272 atomic_read(&clp->cl_count),
1273 clp->cl_hostname);
1274
1275 return 0;
1276}
1277
1278/*
1279 * open "/proc/fs/nfsfs/volumes" which provides a summary of extant volumes
1280 */
1281static int nfs_volume_list_open(struct inode *inode, struct file *file)
1282{
1283 struct seq_file *m;
1284 int ret;
1285
1286 ret = seq_open(file, &nfs_volume_list_ops);
1287 if (ret < 0)
1288 return ret;
1289
1290 m = file->private_data;
1291 m->private = PDE(inode)->data;
1292
1293 return 0;
1294}
1295
1296/*
1297 * set up the iterator to start reading from the volume list and return the first item
1298 */
1299static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
1300{
6aaca566
DH
1301 /* lock the list against modification */
1302 spin_lock(&nfs_client_lock);
259902ea 1303 return seq_list_start_head(&nfs_volume_list, *_pos);
6aaca566
DH
1304}
1305
1306/*
1307 * move to next volume
1308 */
1309static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
1310{
259902ea 1311 return seq_list_next(v, &nfs_volume_list, pos);
6aaca566
DH
1312}
1313
1314/*
1315 * clean up after reading from the transports list
1316 */
1317static void nfs_volume_list_stop(struct seq_file *p, void *v)
1318{
1319 spin_unlock(&nfs_client_lock);
1320}
1321
1322/*
1323 * display a header line followed by a load of call lines
1324 */
1325static int nfs_volume_list_show(struct seq_file *m, void *v)
1326{
1327 struct nfs_server *server;
1328 struct nfs_client *clp;
1329 char dev[8], fsid[17];
1330
1331 /* display header on line 1 */
259902ea 1332 if (v == &nfs_volume_list) {
6aaca566
DH
1333 seq_puts(m, "NV SERVER PORT DEV FSID\n");
1334 return 0;
1335 }
1336 /* display one transport per line on subsequent lines */
1337 server = list_entry(v, struct nfs_server, master_link);
1338 clp = server->nfs_client;
1339
1340 snprintf(dev, 8, "%u:%u",
1341 MAJOR(server->s_dev), MINOR(server->s_dev));
1342
1343 snprintf(fsid, 17, "%llx:%llx",
6daabf1b
DH
1344 (unsigned long long) server->fsid.major,
1345 (unsigned long long) server->fsid.minor);
6aaca566
DH
1346
1347 seq_printf(m, "v%d %02x%02x%02x%02x %4hx %-7s %-17s\n",
1348 clp->cl_nfsversion,
1349 NIPQUAD(clp->cl_addr.sin_addr),
1350 ntohs(clp->cl_addr.sin_port),
1351 dev,
1352 fsid);
1353
1354 return 0;
1355}
1356
1357/*
1358 * initialise the /proc/fs/nfsfs/ directory
1359 */
1360int __init nfs_fs_proc_init(void)
1361{
1362 struct proc_dir_entry *p;
1363
1364 proc_fs_nfs = proc_mkdir("nfsfs", proc_root_fs);
1365 if (!proc_fs_nfs)
1366 goto error_0;
1367
1368 proc_fs_nfs->owner = THIS_MODULE;
1369
1370 /* a file of servers with which we're dealing */
1371 p = create_proc_entry("servers", S_IFREG|S_IRUGO, proc_fs_nfs);
1372 if (!p)
1373 goto error_1;
1374
1375 p->proc_fops = &nfs_server_list_fops;
1376 p->owner = THIS_MODULE;
1377
1378 /* a file of volumes that we have mounted */
1379 p = create_proc_entry("volumes", S_IFREG|S_IRUGO, proc_fs_nfs);
1380 if (!p)
1381 goto error_2;
1382
1383 p->proc_fops = &nfs_volume_list_fops;
1384 p->owner = THIS_MODULE;
1385 return 0;
1386
1387error_2:
1388 remove_proc_entry("servers", proc_fs_nfs);
1389error_1:
1390 remove_proc_entry("nfsfs", proc_root_fs);
1391error_0:
1392 return -ENOMEM;
1393}
1394
1395/*
1396 * clean up the /proc/fs/nfsfs/ directory
1397 */
1398void nfs_fs_proc_exit(void)
1399{
1400 remove_proc_entry("volumes", proc_fs_nfs);
1401 remove_proc_entry("servers", proc_fs_nfs);
1402 remove_proc_entry("nfsfs", proc_root_fs);
1403}
1404
1405#endif /* CONFIG_PROC_FS */