aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-08-22 20:06:13 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:24:37 -0400
commit54ceac4515986030c2502960be620198dd8fe25b (patch)
treeb4ae4305c5652c0fe883ef5ea3243da91dbd2b34
parentcf6d7b5de8535a9f0088c5cc28ee2dae87371b4a (diff)
NFS: Share NFS superblocks per-protocol per-server per-FSID
The attached patch makes NFS share superblocks between mounts from the same server and FSID over the same protocol. It does this by creating each superblock with a false root and returning the real root dentry in the vfsmount presented by get_sb(). The root dentry set starts off as an anonymous dentry if we don't already have the dentry for its inode, otherwise it simply returns the dentry we already have. We may thus end up with several trees of dentries in the superblock, and if at some later point one of anonymous tree roots is discovered by normal filesystem activity to be located in another tree within the superblock, the anonymous root is named and materialises attached to the second tree at the appropriate point. Why do it this way? Why not pass an extra argument to the mount() syscall to indicate the subpath and then pathwalk from the server root to the desired directory? You can't guarantee this will work for two reasons: (1) The root and intervening nodes may not be accessible to the client. With NFS2 and NFS3, for instance, mountd is called on the server to get the filehandle for the tip of a path. mountd won't give us handles for anything we don't have permission to access, and so we can't set up NFS inodes for such nodes, and so can't easily set up dentries (we'd have to have ghost inodes or something). With this patch we don't actually create dentries until we get handles from the server that we can use to set up their inodes, and we don't actually bind them into the tree until we know for sure where they go. (2) Inaccessible symbolic links. If we're asked to mount two exports from the server, eg: mount warthog:/warthog/aaa/xxx /mmm mount warthog:/warthog/bbb/yyy /nnn We may not be able to access anything nearer the root than xxx and yyy, but we may find out later that /mmm/www/yyy, say, is actually the same directory as the one mounted on /nnn. What we might then find out, for example, is that /warthog/bbb was actually a symbolic link to /warthog/aaa/xxx/www, but we can't actually determine that by talking to the server until /warthog is made available by NFS. This would lead to having constructed an errneous dentry tree which we can't easily fix. We can end up with a dentry marked as a directory when it should actually be a symlink, or we could end up with an apparently hardlinked directory. With this patch we need not make assumptions about the type of a dentry for which we can't retrieve information, nor need we assume we know its place in the grand scheme of things until we actually see that place. This patch reduces the possibility of aliasing in the inode and page caches for inodes that may be accessed by more than one NFS export. It also reduces the number of superblocks required for NFS where there are many NFS exports being used from a server (home directory server + autofs for example). This in turn makes it simpler to do local caching of network filesystems, as it can then be guaranteed that there won't be links from multiple inodes in separate superblocks to the same cache file. Obviously, cache aliasing between different levels of NFS protocol could still be a problem, but at least that gives us another key to use when indexing the cache. This patch makes the following changes: (1) The server record construction/destruction has been abstracted out into its own set of functions to make things easier to get right. These have been moved into fs/nfs/client.c. All the code in fs/nfs/client.c has to do with the management of connections to servers, and doesn't touch superblocks in any way; the remaining code in fs/nfs/super.c has to do with VFS superblock management. (2) The sequence of events undertaken by NFS mount is now reordered: (a) A volume representation (struct nfs_server) is allocated. (b) A server representation (struct nfs_client) is acquired. This may be allocated or shared, and is keyed on server address, port and NFS version. (c) If allocated, the client representation is initialised. The state member variable of nfs_client is used to prevent a race during initialisation from two mounts. (d) For NFS4 a simple pathwalk is performed, walking from FH to FH to find the root filehandle for the mount (fs/nfs/getroot.c). For NFS2/3 we are given the root FH in advance. (e) The volume FSID is probed for on the root FH. (f) The volume representation is initialised from the FSINFO record retrieved on the root FH. (g) sget() is called to acquire a superblock. This may be allocated or shared, keyed on client pointer and FSID. (h) If allocated, the superblock is initialised. (i) If the superblock is shared, then the new nfs_server record is discarded. (j) The root dentry for this mount is looked up from the root FH. (k) The root dentry for this mount is assigned to the vfsmount. (3) nfs_readdir_lookup() creates dentries for each of the entries readdir() returns; this function now attaches disconnected trees from alternate roots that happen to be discovered attached to a directory being read (in the same way nfs_lookup() is made to do for lookup ops). The new d_materialise_unique() function is now used to do this, thus permitting the whole thing to be done under one set of locks, and thus avoiding any race between mount and lookup operations on the same directory. (4) The client management code uses a new debug facility: NFSDBG_CLIENT which is set by echoing 1024 to /proc/net/sunrpc/nfs_debug. (5) Clone mounts are now called xdev mounts. (6) Use the dentry passed to the statfs() op as the handle for retrieving fs statistics rather than the root dentry of the superblock (which is now a dummy). Signed-Off-By: David Howells <dhowells@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/Makefile2
-rw-r--r--fs/nfs/client.c735
-rw-r--r--fs/nfs/dir.c16
-rw-r--r--fs/nfs/getroot.c306
-rw-r--r--fs/nfs/idmap.c3
-rw-r--r--fs/nfs/inode.c2
-rw-r--r--fs/nfs/internal.h82
-rw-r--r--fs/nfs/namespace.c25
-rw-r--r--fs/nfs/nfs3proc.c2
-rw-r--r--fs/nfs/nfs4_fs.h6
-rw-r--r--fs/nfs/nfs4namespace.c110
-rw-r--r--fs/nfs/nfs4proc.c59
-rw-r--r--fs/nfs/nfs4renewd.c13
-rw-r--r--fs/nfs/nfs4state.c18
-rw-r--r--fs/nfs/read.c2
-rw-r--r--fs/nfs/super.c1207
-rw-r--r--fs/nfs/write.c2
-rw-r--r--include/linux/nfs_fs_sb.h21
18 files changed, 1655 insertions, 956 deletions
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 3b993a6f8163..f4580b44eef4 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -4,7 +4,7 @@
4 4
5obj-$(CONFIG_NFS_FS) += nfs.o 5obj-$(CONFIG_NFS_FS) += nfs.o
6 6
7nfs-y := client.o dir.o file.o inode.o super.o nfs2xdr.o \ 7nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
8 pagelist.o proc.o read.o symlink.o unlink.o \ 8 pagelist.o proc.o read.o symlink.o unlink.o \
9 write.o namespace.o 9 write.o namespace.o
10nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o 10nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index c08cab935ad5..dafba608c0a0 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -48,6 +48,7 @@
48 48
49static DEFINE_SPINLOCK(nfs_client_lock); 49static DEFINE_SPINLOCK(nfs_client_lock);
50static LIST_HEAD(nfs_client_list); 50static LIST_HEAD(nfs_client_list);
51static LIST_HEAD(nfs_volume_list);
51static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); 52static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
52 53
53/* 54/*
@@ -268,9 +269,9 @@ struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversio
268 * Look up a client by IP address and protocol version 269 * Look up a client by IP address and protocol version
269 * - creates a new record if one doesn't yet exist 270 * - creates a new record if one doesn't yet exist
270 */ 271 */
271struct nfs_client *nfs_get_client(const char *hostname, 272static struct nfs_client *nfs_get_client(const char *hostname,
272 const struct sockaddr_in *addr, 273 const struct sockaddr_in *addr,
273 int nfsversion) 274 int nfsversion)
274{ 275{
275 struct nfs_client *clp, *new = NULL; 276 struct nfs_client *clp, *new = NULL;
276 int error; 277 int error;
@@ -340,6 +341,8 @@ found_client:
340 return ERR_PTR(error); 341 return ERR_PTR(error);
341 } 342 }
342 343
344 BUG_ON(clp->cl_cons_state != NFS_CS_READY);
345
343 dprintk("--> nfs_get_client() = %p [share]\n", clp); 346 dprintk("--> nfs_get_client() = %p [share]\n", clp);
344 return clp; 347 return clp;
345} 348}
@@ -347,7 +350,7 @@ found_client:
347/* 350/*
348 * Mark a server as ready or failed 351 * Mark a server as ready or failed
349 */ 352 */
350void nfs_mark_client_ready(struct nfs_client *clp, int state) 353static void nfs_mark_client_ready(struct nfs_client *clp, int state)
351{ 354{
352 clp->cl_cons_state = state; 355 clp->cl_cons_state = state;
353 wake_up_all(&nfs_client_active_wq); 356 wake_up_all(&nfs_client_active_wq);
@@ -389,10 +392,10 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
389/* 392/*
390 * Create an RPC client handle 393 * Create an RPC client handle
391 */ 394 */
392int nfs_create_rpc_client(struct nfs_client *clp, int proto, 395static int nfs_create_rpc_client(struct nfs_client *clp, int proto,
393 unsigned int timeo, 396 unsigned int timeo,
394 unsigned int retrans, 397 unsigned int retrans,
395 rpc_authflavor_t flavor) 398 rpc_authflavor_t flavor)
396{ 399{
397 struct rpc_timeout timeparms; 400 struct rpc_timeout timeparms;
398 struct rpc_xprt *xprt = NULL; 401 struct rpc_xprt *xprt = NULL;
@@ -429,3 +432,719 @@ int nfs_create_rpc_client(struct nfs_client *clp, int proto,
429 clp->cl_rpcclient = clnt; 432 clp->cl_rpcclient = clnt;
430 return 0; 433 return 0;
431} 434}
435
436/*
437 * Version 2 or 3 client destruction
438 */
439static void nfs_destroy_server(struct nfs_server *server)
440{
441 if (!IS_ERR(server->client_acl))
442 rpc_shutdown_client(server->client_acl);
443
444 if (!(server->flags & NFS_MOUNT_NONLM))
445 lockd_down(); /* release rpc.lockd */
446}
447
448/*
449 * Version 2 or 3 lockd setup
450 */
451static int nfs_start_lockd(struct nfs_server *server)
452{
453 int error = 0;
454
455 if (server->nfs_client->cl_nfsversion > 3)
456 goto out;
457 if (server->flags & NFS_MOUNT_NONLM)
458 goto out;
459 error = lockd_up();
460 if (error < 0)
461 server->flags |= NFS_MOUNT_NONLM;
462 else
463 server->destroy = nfs_destroy_server;
464out:
465 return error;
466}
467
468/*
469 * Initialise an NFSv3 ACL client connection
470 */
471#ifdef CONFIG_NFS_V3_ACL
472static void nfs_init_server_aclclient(struct nfs_server *server)
473{
474 if (server->nfs_client->cl_nfsversion != 3)
475 goto out_noacl;
476 if (server->flags & NFS_MOUNT_NOACL)
477 goto out_noacl;
478
479 server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
480 if (IS_ERR(server->client_acl))
481 goto out_noacl;
482
483 /* No errors! Assume that Sun nfsacls are supported */
484 server->caps |= NFS_CAP_ACLS;
485 return;
486
487out_noacl:
488 server->caps &= ~NFS_CAP_ACLS;
489}
490#else
491static inline void nfs_init_server_aclclient(struct nfs_server *server)
492{
493 server->flags &= ~NFS_MOUNT_NOACL;
494 server->caps &= ~NFS_CAP_ACLS;
495}
496#endif
497
498/*
499 * Create a general RPC client
500 */
501static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t pseudoflavour)
502{
503 struct nfs_client *clp = server->nfs_client;
504
505 server->client = rpc_clone_client(clp->cl_rpcclient);
506 if (IS_ERR(server->client)) {
507 dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__);
508 return PTR_ERR(server->client);
509 }
510
511 if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) {
512 struct rpc_auth *auth;
513
514 auth = rpcauth_create(pseudoflavour, server->client);
515 if (IS_ERR(auth)) {
516 dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
517 return PTR_ERR(auth);
518 }
519 }
520 server->client->cl_softrtry = 0;
521 if (server->flags & NFS_MOUNT_SOFT)
522 server->client->cl_softrtry = 1;
523
524 server->client->cl_intr = 0;
525 if (server->flags & NFS4_MOUNT_INTR)
526 server->client->cl_intr = 1;
527
528 return 0;
529}
530
531/*
532 * Initialise an NFS2 or NFS3 client
533 */
534static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *data)
535{
536 int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
537 int error;
538
539 if (clp->cl_cons_state == NFS_CS_READY) {
540 /* the client is already initialised */
541 dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp);
542 return 0;
543 }
544
545 /* Check NFS protocol revision and initialize RPC op vector */
546 clp->rpc_ops = &nfs_v2_clientops;
547#ifdef CONFIG_NFS_V3
548 if (clp->cl_nfsversion == 3)
549 clp->rpc_ops = &nfs_v3_clientops;
550#endif
551 /*
552 * Create a client RPC handle for doing FSSTAT with UNIX auth only
553 * - RFC 2623, sec 2.3.2
554 */
555 error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans,
556 RPC_AUTH_UNIX);
557 if (error < 0)
558 goto error;
559 nfs_mark_client_ready(clp, NFS_CS_READY);
560 return 0;
561
562error:
563 nfs_mark_client_ready(clp, error);
564 dprintk("<-- nfs_init_client() = xerror %d\n", error);
565 return error;
566}
567
568/*
569 * Create a version 2 or 3 client
570 */
571static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_data *data)
572{
573 struct nfs_client *clp;
574 int error, nfsvers = 2;
575
576 dprintk("--> nfs_init_server()\n");
577
578#ifdef CONFIG_NFS_V3
579 if (data->flags & NFS_MOUNT_VER3)
580 nfsvers = 3;
581#endif
582
583 /* Allocate or find a client reference we can use */
584 clp = nfs_get_client(data->hostname, &data->addr, nfsvers);
585 if (IS_ERR(clp)) {
586 dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
587 return PTR_ERR(clp);
588 }
589
590 error = nfs_init_client(clp, data);
591 if (error < 0)
592 goto error;
593
594 server->nfs_client = clp;
595
596 /* Initialise the client representation from the mount data */
597 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
598
599 if (data->rsize)
600 server->rsize = nfs_block_size(data->rsize, NULL);
601 if (data->wsize)
602 server->wsize = nfs_block_size(data->wsize, NULL);
603
604 server->acregmin = data->acregmin * HZ;
605 server->acregmax = data->acregmax * HZ;
606 server->acdirmin = data->acdirmin * HZ;
607 server->acdirmax = data->acdirmax * HZ;
608
609 /* Start lockd here, before we might error out */
610 error = nfs_start_lockd(server);
611 if (error < 0)
612 goto error;
613
614 error = nfs_init_server_rpcclient(server, data->pseudoflavor);
615 if (error < 0)
616 goto error;
617
618 server->namelen = data->namlen;
619 /* Create a client RPC handle for the NFSv3 ACL management interface */
620 nfs_init_server_aclclient(server);
621 if (clp->cl_nfsversion == 3) {
622 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
623 server->namelen = NFS3_MAXNAMLEN;
624 server->caps |= NFS_CAP_READDIRPLUS;
625 } else {
626 if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
627 server->namelen = NFS2_MAXNAMLEN;
628 }
629
630 dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp);
631 return 0;
632
633error:
634 server->nfs_client = NULL;
635 nfs_put_client(clp);
636 dprintk("<-- nfs_init_server() = xerror %d\n", error);
637 return error;
638}
639
640/*
641 * Load up the server record from information gained in an fsinfo record
642 */
643static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *fsinfo)
644{
645 unsigned long max_rpc_payload;
646
647 /* Work out a lot of parameters */
648 if (server->rsize == 0)
649 server->rsize = nfs_block_size(fsinfo->rtpref, NULL);
650 if (server->wsize == 0)
651 server->wsize = nfs_block_size(fsinfo->wtpref, NULL);
652
653 if (fsinfo->rtmax >= 512 && server->rsize > fsinfo->rtmax)
654 server->rsize = nfs_block_size(fsinfo->rtmax, NULL);
655 if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax)
656 server->wsize = nfs_block_size(fsinfo->wtmax, NULL);
657
658 max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
659 if (server->rsize > max_rpc_payload)
660 server->rsize = max_rpc_payload;
661 if (server->rsize > NFS_MAX_FILE_IO_SIZE)
662 server->rsize = NFS_MAX_FILE_IO_SIZE;
663 server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
664 server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
665
666 if (server->wsize > max_rpc_payload)
667 server->wsize = max_rpc_payload;
668 if (server->wsize > NFS_MAX_FILE_IO_SIZE)
669 server->wsize = NFS_MAX_FILE_IO_SIZE;
670 server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
671 server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
672
673 server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
674 if (server->dtsize > PAGE_CACHE_SIZE)
675 server->dtsize = PAGE_CACHE_SIZE;
676 if (server->dtsize > server->rsize)
677 server->dtsize = server->rsize;
678
679 if (server->flags & NFS_MOUNT_NOAC) {
680 server->acregmin = server->acregmax = 0;
681 server->acdirmin = server->acdirmax = 0;
682 }
683
684 server->maxfilesize = fsinfo->maxfilesize;
685
686 /* We're airborne Set socket buffersize */
687 rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
688}
689
690/*
691 * Probe filesystem information, including the FSID on v2/v3
692 */
693static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
694{
695 struct nfs_fsinfo fsinfo;
696 struct nfs_client *clp = server->nfs_client;
697 int error;
698
699 dprintk("--> nfs_probe_fsinfo()\n");
700
701 if (clp->rpc_ops->set_capabilities != NULL) {
702 error = clp->rpc_ops->set_capabilities(server, mntfh);
703 if (error < 0)
704 goto out_error;
705 }
706
707 fsinfo.fattr = fattr;
708 nfs_fattr_init(fattr);
709 error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
710 if (error < 0)
711 goto out_error;
712
713 nfs_server_set_fsinfo(server, &fsinfo);
714
715 /* Get some general file system info */
716 if (server->namelen == 0) {
717 struct nfs_pathconf pathinfo;
718
719 pathinfo.fattr = fattr;
720 nfs_fattr_init(fattr);
721
722 if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0)
723 server->namelen = pathinfo.max_namelen;
724 }
725
726 dprintk("<-- nfs_probe_fsinfo() = 0\n");
727 return 0;
728
729out_error:
730 dprintk("nfs_probe_fsinfo: error = %d\n", -error);
731 return error;
732}
733
734/*
735 * Copy useful information when duplicating a server record
736 */
737static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
738{
739 target->flags = source->flags;
740 target->acregmin = source->acregmin;
741 target->acregmax = source->acregmax;
742 target->acdirmin = source->acdirmin;
743 target->acdirmax = source->acdirmax;
744 target->caps = source->caps;
745}
746
747/*
748 * Allocate and initialise a server record
749 */
750static struct nfs_server *nfs_alloc_server(void)
751{
752 struct nfs_server *server;
753
754 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
755 if (!server)
756 return NULL;
757
758 server->client = server->client_acl = ERR_PTR(-EINVAL);
759
760 /* Zero out the NFS state stuff */
761 INIT_LIST_HEAD(&server->client_link);
762 INIT_LIST_HEAD(&server->master_link);
763
764 server->io_stats = nfs_alloc_iostats();
765 if (!server->io_stats) {
766 kfree(server);
767 return NULL;
768 }
769
770 return server;
771}
772
773/*
774 * Free up a server record
775 */
776void nfs_free_server(struct nfs_server *server)
777{
778 dprintk("--> nfs_free_server()\n");
779
780 spin_lock(&nfs_client_lock);
781 list_del(&server->client_link);
782 list_del(&server->master_link);
783 spin_unlock(&nfs_client_lock);
784
785 if (server->destroy != NULL)
786 server->destroy(server);
787 if (!IS_ERR(server->client))
788 rpc_shutdown_client(server->client);
789
790 nfs_put_client(server->nfs_client);
791
792 nfs_free_iostats(server->io_stats);
793 kfree(server);
794 nfs_release_automount_timer();
795 dprintk("<-- nfs_free_server()\n");
796}
797
798/*
799 * Create a version 2 or 3 volume record
800 * - keyed on server and FSID
801 */
802struct nfs_server *nfs_create_server(const struct nfs_mount_data *data,
803 struct nfs_fh *mntfh)
804{
805 struct nfs_server *server;
806 struct nfs_fattr fattr;
807 int error;
808
809 server = nfs_alloc_server();
810 if (!server)
811 return ERR_PTR(-ENOMEM);
812
813 /* Get a client representation */
814 error = nfs_init_server(server, data);
815 if (error < 0)
816 goto error;
817
818 BUG_ON(!server->nfs_client);
819 BUG_ON(!server->nfs_client->rpc_ops);
820 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
821
822 /* Probe the root fh to retrieve its FSID */
823 error = nfs_probe_fsinfo(server, mntfh, &fattr);
824 if (error < 0)
825 goto error;
826 if (!(fattr.valid & NFS_ATTR_FATTR)) {
827 error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
828 if (error < 0) {
829 dprintk("nfs_create_server: getattr error = %d\n", -error);
830 goto error;
831 }
832 }
833 memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
834
835 dprintk("Server FSID: %llx:%llx\n", server->fsid.major, server->fsid.minor);
836
837 BUG_ON(!server->nfs_client);
838 BUG_ON(!server->nfs_client->rpc_ops);
839 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
840
841 spin_lock(&nfs_client_lock);
842 list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
843 list_add_tail(&server->master_link, &nfs_volume_list);
844 spin_unlock(&nfs_client_lock);
845
846 server->mount_time = jiffies;
847 return server;
848
849error:
850 nfs_free_server(server);
851 return ERR_PTR(error);
852}
853
854#ifdef CONFIG_NFS_V4
855/*
856 * Initialise an NFS4 client record
857 */
858static int nfs4_init_client(struct nfs_client *clp,
859 int proto, int timeo, int retrans,
860 rpc_authflavor_t authflavour)
861{
862 int error;
863
864 if (clp->cl_cons_state == NFS_CS_READY) {
865 /* the client is initialised already */
866 dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
867 return 0;
868 }
869
870 /* Check NFS protocol revision and initialize RPC op vector */
871 clp->rpc_ops = &nfs_v4_clientops;
872
873 error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour);
874 if (error < 0)
875 goto error;
876
877 error = nfs_idmap_new(clp);
878 if (error < 0) {
879 dprintk("%s: failed to create idmapper. Error = %d\n",
880 __FUNCTION__, error);
881 __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
882 goto error;
883 }
884
885 nfs_mark_client_ready(clp, NFS_CS_READY);
886 return 0;
887
888error:
889 nfs_mark_client_ready(clp, error);
890 dprintk("<-- nfs4_init_client() = xerror %d\n", error);
891 return error;
892}
893
894/*
895 * Set up an NFS4 client
896 */
897static int nfs4_set_client(struct nfs_server *server,
898 const char *hostname, const struct sockaddr_in *addr,
899 rpc_authflavor_t authflavour,
900 int proto, int timeo, int retrans)
901{
902 struct nfs_client *clp;
903 int error;
904
905 dprintk("--> nfs4_set_client()\n");
906
907 /* Allocate or find a client reference we can use */
908 clp = nfs_get_client(hostname, addr, 4);
909 if (IS_ERR(clp)) {
910 error = PTR_ERR(clp);
911 goto error;
912 }
913 error = nfs4_init_client(clp, proto, timeo, retrans, authflavour);
914 if (error < 0)
915 goto error_put;
916
917 server->nfs_client = clp;
918 dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
919 return 0;
920
921error_put:
922 nfs_put_client(clp);
923error:
924 dprintk("<-- nfs4_set_client() = xerror %d\n", error);
925 return error;
926}
927
928/*
929 * Create a version 4 volume record
930 */
931static int nfs4_init_server(struct nfs_server *server,
932 const struct nfs4_mount_data *data, rpc_authflavor_t authflavour)
933{
934 int error;
935
936 dprintk("--> nfs4_init_server()\n");
937
938 /* Initialise the client representation from the mount data */
939 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
940 server->caps |= NFS_CAP_ATOMIC_OPEN;
941
942 if (data->rsize)
943 server->rsize = nfs_block_size(data->rsize, NULL);
944 if (data->wsize)
945 server->wsize = nfs_block_size(data->wsize, NULL);
946
947 server->acregmin = data->acregmin * HZ;
948 server->acregmax = data->acregmax * HZ;
949 server->acdirmin = data->acdirmin * HZ;
950 server->acdirmax = data->acdirmax * HZ;
951
952 error = nfs_init_server_rpcclient(server, authflavour);
953
954 /* Done */
955 dprintk("<-- nfs4_init_server() = %d\n", error);
956 return error;
957}
958
959/*
960 * Create a version 4 volume record
961 * - keyed on server and FSID
962 */
963struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
964 const char *hostname,
965 const struct sockaddr_in *addr,
966 const char *mntpath,
967 const char *ip_addr,
968 rpc_authflavor_t authflavour,
969 struct nfs_fh *mntfh)
970{
971 struct nfs_fattr fattr;
972 struct nfs_server *server;
973 int error;
974
975 dprintk("--> nfs4_create_server()\n");
976
977 server = nfs_alloc_server();
978 if (!server)
979 return ERR_PTR(-ENOMEM);
980
981 /* Get a client record */
982 error = nfs4_set_client(server, hostname, addr, authflavour,
983 data->proto, data->timeo, data->retrans);
984 if (error < 0)
985 goto error;
986
987 /* set up the general RPC client */
988 error = nfs4_init_server(server, data, authflavour);
989 if (error < 0)
990 goto error;
991
992 BUG_ON(!server->nfs_client);
993 BUG_ON(!server->nfs_client->rpc_ops);
994 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
995
996 /* Probe the root fh to retrieve its FSID */
997 error = nfs4_path_walk(server, mntfh, mntpath);
998 if (error < 0)
999 goto error;
1000
1001 dprintk("Server FSID: %llx:%llx\n", server->fsid.major, server->fsid.minor);
1002 dprintk("Mount FH: %d\n", mntfh->size);
1003
1004 error = nfs_probe_fsinfo(server, mntfh, &fattr);
1005 if (error < 0)
1006 goto error;
1007
1008 BUG_ON(!server->nfs_client);
1009 BUG_ON(!server->nfs_client->rpc_ops);
1010 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
1011
1012 spin_lock(&nfs_client_lock);
1013 list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
1014 list_add_tail(&server->master_link, &nfs_volume_list);
1015 spin_unlock(&nfs_client_lock);
1016
1017 server->mount_time = jiffies;
1018 dprintk("<-- nfs4_create_server() = %p\n", server);
1019 return server;
1020
1021error:
1022 nfs_free_server(server);
1023 dprintk("<-- nfs4_create_server() = error %d\n", error);
1024 return ERR_PTR(error);
1025}
1026
1027/*
1028 * Create an NFS4 referral server record
1029 */
1030struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
1031 struct nfs_fh *fh)
1032{
1033 struct nfs_client *parent_client;
1034 struct nfs_server *server, *parent_server;
1035 struct nfs_fattr fattr;
1036 int error;
1037
1038 dprintk("--> nfs4_create_referral_server()\n");
1039
1040 server = nfs_alloc_server();
1041 if (!server)
1042 return ERR_PTR(-ENOMEM);
1043
1044 parent_server = NFS_SB(data->sb);
1045 parent_client = parent_server->nfs_client;
1046
1047 /* Get a client representation.
1048 * Note: NFSv4 always uses TCP, */
1049 error = nfs4_set_client(server, data->hostname, data->addr,
1050 data->authflavor,
1051 parent_server->client->cl_xprt->prot,
1052 parent_client->retrans_timeo,
1053 parent_client->retrans_count);
1054
1055 /* Initialise the client representation from the parent server */
1056 nfs_server_copy_userdata(server, parent_server);
1057 server->caps |= NFS_CAP_ATOMIC_OPEN;
1058
1059 error = nfs_init_server_rpcclient(server, data->authflavor);
1060 if (error < 0)
1061 goto error;
1062
1063 BUG_ON(!server->nfs_client);
1064 BUG_ON(!server->nfs_client->rpc_ops);
1065 BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
1066
1067 /* probe the filesystem info for this server filesystem */
1068 error = nfs_probe_fsinfo(server, fh, &fattr);
1069 if (error < 0)
1070 goto error;
1071
1072 dprintk("Referral FSID: %llx:%llx\n",
1073 server->fsid.major, server->fsid.minor);
1074
1075 spin_lock(&nfs_client_lock);
1076 list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
1077 list_add_tail(&server->master_link, &nfs_volume_list);
1078 spin_unlock(&nfs_client_lock);
1079
1080 server->mount_time = jiffies;
1081
1082 dprintk("<-- nfs_create_referral_server() = %p\n", server);
1083 return server;
1084
1085error:
1086 nfs_free_server(server);
1087 dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
1088 return ERR_PTR(error);
1089}
1090
1091#endif /* CONFIG_NFS_V4 */
1092
1093/*
1094 * Clone an NFS2, NFS3 or NFS4 server record
1095 */
1096struct nfs_server *nfs_clone_server(struct nfs_server *source,
1097 struct nfs_fh *fh,
1098 struct nfs_fattr *fattr)
1099{
1100 struct nfs_server *server;
1101 struct nfs_fattr fattr_fsinfo;
1102 int error;
1103
1104 dprintk("--> nfs_clone_server(,%llx:%llx,)\n",
1105 fattr->fsid.major, fattr->fsid.minor);
1106
1107 server = nfs_alloc_server();
1108 if (!server)
1109 return ERR_PTR(-ENOMEM);
1110
1111 /* Copy data from the source */
1112 server->nfs_client = source->nfs_client;
1113 atomic_inc(&server->nfs_client->cl_count);
1114 nfs_server_copy_userdata(server, source);
1115
1116 server->fsid = fattr->fsid;
1117
1118 error = nfs_init_server_rpcclient(server, source->client->cl_auth->au_flavor);
1119 if (error < 0)
1120 goto out_free_server;
1121 if (!IS_ERR(source->client_acl))
1122 nfs_init_server_aclclient(server);
1123
1124 /* probe the filesystem info for this server filesystem */
1125 error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo);
1126 if (error < 0)
1127 goto out_free_server;
1128
1129 dprintk("Cloned FSID: %llx:%llx\n",
1130 server->fsid.major, server->fsid.minor);
1131
1132 error = nfs_start_lockd(server);
1133 if (error < 0)
1134 goto out_free_server;
1135
1136 spin_lock(&nfs_client_lock);
1137 list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
1138 list_add_tail(&server->master_link, &nfs_volume_list);
1139 spin_unlock(&nfs_client_lock);
1140
1141 server->mount_time = jiffies;
1142
1143 dprintk("<-- nfs_clone_server() = %p\n", server);
1144 return server;
1145
1146out_free_server:
1147 nfs_free_server(server);
1148 dprintk("<-- nfs_clone_server() = error %d\n", error);
1149 return ERR_PTR(error);
1150}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 19362712452f..9b496ef4abea 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -31,6 +31,7 @@
31#include <linux/pagemap.h> 31#include <linux/pagemap.h>
32#include <linux/smp_lock.h> 32#include <linux/smp_lock.h>
33#include <linux/namei.h> 33#include <linux/namei.h>
34#include <linux/mount.h>
34 35
35#include "nfs4_fs.h" 36#include "nfs4_fs.h"
36#include "delegation.h" 37#include "delegation.h"
@@ -870,14 +871,14 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
870 return (nd->intent.open.flags & O_EXCL) != 0; 871 return (nd->intent.open.flags & O_EXCL) != 0;
871} 872}
872 873
873static inline int nfs_reval_fsid(struct inode *dir, 874static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir,
874 struct nfs_fh *fh, struct nfs_fattr *fattr) 875 struct nfs_fh *fh, struct nfs_fattr *fattr)
875{ 876{
876 struct nfs_server *server = NFS_SERVER(dir); 877 struct nfs_server *server = NFS_SERVER(dir);
877 878
878 if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) 879 if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
879 /* Revalidate fsid on root dir */ 880 /* Revalidate fsid on root dir */
880 return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode); 881 return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode);
881 return 0; 882 return 0;
882} 883}
883 884
@@ -913,7 +914,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
913 res = ERR_PTR(error); 914 res = ERR_PTR(error);
914 goto out_unlock; 915 goto out_unlock;
915 } 916 }
916 error = nfs_reval_fsid(dir, &fhandle, &fattr); 917 error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr);
917 if (error < 0) { 918 if (error < 0) {
918 res = ERR_PTR(error); 919 res = ERR_PTR(error);
919 goto out_unlock; 920 goto out_unlock;
@@ -922,8 +923,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
922 res = (struct dentry *)inode; 923 res = (struct dentry *)inode;
923 if (IS_ERR(res)) 924 if (IS_ERR(res))
924 goto out_unlock; 925 goto out_unlock;
926
925no_entry: 927no_entry:
926 res = d_add_unique(dentry, inode); 928 res = d_materialise_unique(dentry, inode);
927 if (res != NULL) 929 if (res != NULL)
928 dentry = res; 930 dentry = res;
929 nfs_renew_times(dentry); 931 nfs_renew_times(dentry);
@@ -1117,11 +1119,13 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
1117 dput(dentry); 1119 dput(dentry);
1118 return NULL; 1120 return NULL;
1119 } 1121 }
1120 alias = d_add_unique(dentry, inode); 1122
1123 alias = d_materialise_unique(dentry, inode);
1121 if (alias != NULL) { 1124 if (alias != NULL) {
1122 dput(dentry); 1125 dput(dentry);
1123 dentry = alias; 1126 dentry = alias;
1124 } 1127 }
1128
1125 nfs_renew_times(dentry); 1129 nfs_renew_times(dentry);
1126 nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 1130 nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1127 return dentry; 1131 return dentry;
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
new file mode 100644
index 000000000000..977e59088eeb
--- /dev/null
+++ b/fs/nfs/getroot.c
@@ -0,0 +1,306 @@
1/* getroot.c: get the root dentry for an NFS mount
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#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/init.h>
15
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/nfs_fs.h>
26#include <linux/nfs_mount.h>
27#include <linux/nfs4_mount.h>
28#include <linux/lockd/bind.h>
29#include <linux/smp_lock.h>
30#include <linux/seq_file.h>
31#include <linux/mount.h>
32#include <linux/nfs_idmap.h>
33#include <linux/vfs.h>
34#include <linux/namei.h>
35#include <linux/namespace.h>
36
37#include <asm/system.h>
38#include <asm/uaccess.h>
39
40#include "nfs4_fs.h"
41#include "delegation.h"
42#include "internal.h"
43
44#define NFSDBG_FACILITY NFSDBG_CLIENT
45#define NFS_PARANOIA 1
46
47/*
48 * get an NFS2/NFS3 root dentry from the root filehandle
49 */
50struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
51{
52 struct nfs_server *server = NFS_SB(sb);
53 struct nfs_fsinfo fsinfo;
54 struct nfs_fattr fattr;
55 struct dentry *mntroot;
56 struct inode *inode;
57 int error;
58
59 /* create a dummy root dentry with dummy inode for this superblock */
60 if (!sb->s_root) {
61 struct nfs_fh dummyfh;
62 struct dentry *root;
63 struct inode *iroot;
64
65 memset(&dummyfh, 0, sizeof(dummyfh));
66 memset(&fattr, 0, sizeof(fattr));
67 nfs_fattr_init(&fattr);
68 fattr.valid = NFS_ATTR_FATTR;
69 fattr.type = NFDIR;
70 fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
71 fattr.nlink = 2;
72
73 iroot = nfs_fhget(sb, &dummyfh, &fattr);
74 if (IS_ERR(iroot))
75 return ERR_PTR(PTR_ERR(iroot));
76
77 root = d_alloc_root(iroot);
78 if (!root) {
79 iput(iroot);
80 return ERR_PTR(-ENOMEM);
81 }
82
83 sb->s_root = root;
84 }
85
86 /* get the actual root for this mount */
87 fsinfo.fattr = &fattr;
88
89 error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
90 if (error < 0) {
91 dprintk("nfs_get_root: getattr error = %d\n", -error);
92 return ERR_PTR(error);
93 }
94
95 inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
96 if (IS_ERR(inode)) {
97 dprintk("nfs_get_root: get root inode failed\n");
98 return ERR_PTR(PTR_ERR(inode));
99 }
100
101 /* root dentries normally start off anonymous and get spliced in later
102 * if the dentry tree reaches them; however if the dentry already
103 * exists, we'll pick it up at this point and use it as the root
104 */
105 mntroot = d_alloc_anon(inode);
106 if (!mntroot) {
107 iput(inode);
108 dprintk("nfs_get_root: get root dentry failed\n");
109 return ERR_PTR(-ENOMEM);
110 }
111
112 if (!mntroot->d_op)
113 mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
114
115 return mntroot;
116}
117
118#ifdef CONFIG_NFS_V4
119
120/*
121 * Do a simple pathwalk from the root FH of the server to the nominated target
122 * of the mountpoint
123 * - give error on symlinks
124 * - give error on ".." occurring in the path
125 * - follow traversals
126 */
127int nfs4_path_walk(struct nfs_server *server,
128 struct nfs_fh *mntfh,
129 const char *path)
130{
131 struct nfs_fsinfo fsinfo;
132 struct nfs_fattr fattr;
133 struct nfs_fh lastfh;
134 struct qstr name;
135 int ret;
136 //int referral_count = 0;
137
138 dprintk("--> nfs4_path_walk(,,%s)\n", path);
139
140 fsinfo.fattr = &fattr;
141 nfs_fattr_init(&fattr);
142
143 if (*path++ != '/') {
144 dprintk("nfs4_get_root: Path does not begin with a slash\n");
145 return -EINVAL;
146 }
147
148 /* Start by getting the root filehandle from the server */
149 ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
150 if (ret < 0) {
151 dprintk("nfs4_get_root: getroot error = %d\n", -ret);
152 return ret;
153 }
154
155 if (fattr.type != NFDIR) {
156 printk(KERN_ERR "nfs4_get_root:"
157 " getroot encountered non-directory\n");
158 return -ENOTDIR;
159 }
160
161 if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
162 printk(KERN_ERR "nfs4_get_root:"
163 " getroot obtained referral\n");
164 return -EREMOTE;
165 }
166
167next_component:
168 dprintk("Next: %s\n", path);
169
170 /* extract the next bit of the path */
171 if (!*path)
172 goto path_walk_complete;
173
174 name.name = path;
175 while (*path && *path != '/')
176 path++;
177 name.len = path - (const char *) name.name;
178
179eat_dot_dir:
180 while (*path == '/')
181 path++;
182
183 if (path[0] == '.' && (path[1] == '/' || !path[1])) {
184 path += 2;
185 goto eat_dot_dir;
186 }
187
188 if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2])
189 ) {
190 printk(KERN_ERR "nfs4_get_root:"
191 " Mount path contains reference to \"..\"\n");
192 return -EINVAL;
193 }
194
195 /* lookup the next FH in the sequence */
196 memcpy(&lastfh, mntfh, sizeof(lastfh));
197
198 dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path);
199
200 ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name,
201 mntfh, &fattr);
202 if (ret < 0) {
203 dprintk("nfs4_get_root: getroot error = %d\n", -ret);
204 return ret;
205 }
206
207 if (fattr.type != NFDIR) {
208 printk(KERN_ERR "nfs4_get_root:"
209 " lookupfh encountered non-directory\n");
210 return -ENOTDIR;
211 }
212
213 if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
214 printk(KERN_ERR "nfs4_get_root:"
215 " lookupfh obtained referral\n");
216 return -EREMOTE;
217 }
218
219 goto next_component;
220
221path_walk_complete:
222 memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
223 dprintk("<-- nfs4_path_walk() = 0\n");
224 return 0;
225}
226
227/*
228 * get an NFS4 root dentry from the root filehandle
229 */
230struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
231{
232 struct nfs_server *server = NFS_SB(sb);
233 struct nfs_fattr fattr;
234 struct dentry *mntroot;
235 struct inode *inode;
236 int error;
237
238 dprintk("--> nfs4_get_root()\n");
239
240 /* create a dummy root dentry with dummy inode for this superblock */
241 if (!sb->s_root) {
242 struct nfs_fh dummyfh;
243 struct dentry *root;
244 struct inode *iroot;
245
246 memset(&dummyfh, 0, sizeof(dummyfh));
247 memset(&fattr, 0, sizeof(fattr));
248 nfs_fattr_init(&fattr);
249 fattr.valid = NFS_ATTR_FATTR;
250 fattr.type = NFDIR;
251 fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
252 fattr.nlink = 2;
253
254 iroot = nfs_fhget(sb, &dummyfh, &fattr);
255 if (IS_ERR(iroot))
256 return ERR_PTR(PTR_ERR(iroot));
257
258 root = d_alloc_root(iroot);
259 if (!root) {
260 iput(iroot);
261 return ERR_PTR(-ENOMEM);
262 }
263
264 sb->s_root = root;
265 }
266
267 /* get the info about the server and filesystem */
268 error = nfs4_server_capabilities(server, mntfh);
269 if (error < 0) {
270 dprintk("nfs_get_root: getcaps error = %d\n",
271 -error);
272 return ERR_PTR(error);
273 }
274
275 /* get the actual root for this mount */
276 error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
277 if (error < 0) {
278 dprintk("nfs_get_root: getattr error = %d\n", -error);
279 return ERR_PTR(error);
280 }
281
282 inode = nfs_fhget(sb, mntfh, &fattr);
283 if (IS_ERR(inode)) {
284 dprintk("nfs_get_root: get root inode failed\n");
285 return ERR_PTR(PTR_ERR(inode));
286 }
287
288 /* root dentries normally start off anonymous and get spliced in later
289 * if the dentry tree reaches them; however if the dentry already
290 * exists, we'll pick it up at this point and use it as the root
291 */
292 mntroot = d_alloc_anon(inode);
293 if (!mntroot) {
294 iput(inode);
295 dprintk("nfs_get_root: get root dentry failed\n");
296 return ERR_PTR(-ENOMEM);
297 }
298
299 if (!mntroot->d_op)
300 mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
301
302 dprintk("<-- nfs4_get_root()\n");
303 return mntroot;
304}
305
306#endif /* CONFIG_NFS_V4 */
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 231c20ffc0ff..f96dfac7dc9a 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -114,8 +114,7 @@ nfs_idmap_new(struct nfs_client *clp)
114 struct idmap *idmap; 114 struct idmap *idmap;
115 int error; 115 int error;
116 116
117 if (clp->cl_idmap != NULL) 117 BUG_ON(clp->cl_idmap != NULL);
118 return 0;
119 118
120 if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) 119 if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
121 return -ENOMEM; 120 return -ENOMEM;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 771c3b833757..a547c58a83e6 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1020,7 +1020,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1020 out_fileid: 1020 out_fileid:
1021 printk(KERN_ERR "NFS: server %s error: fileid changed\n" 1021 printk(KERN_ERR "NFS: server %s error: fileid changed\n"
1022 "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n", 1022 "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
1023 NFS_SERVER(inode)->hostname, inode->i_sb->s_id, 1023 NFS_SERVER(inode)->nfs_client->cl_hostname, inode->i_sb->s_id,
1024 (long long)nfsi->fileid, (long long)fattr->fileid); 1024 (long long)nfsi->fileid, (long long)fattr->fileid);
1025 goto out_err; 1025 goto out_err;
1026} 1026}
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 2f3aa52fbefc..e73ba4f1052a 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -4,6 +4,18 @@
4 4
5#include <linux/mount.h> 5#include <linux/mount.h>
6 6
7struct nfs_string;
8struct nfs_mount_data;
9struct nfs4_mount_data;
10
11/* Maximum number of readahead requests
12 * FIXME: this should really be a sysctl so that users may tune it to suit
13 * their needs. People that do NFS over a slow network, might for
14 * instance want to reduce it to something closer to 1 for improved
15 * interactive response.
16 */
17#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
18
7struct nfs_clone_mount { 19struct nfs_clone_mount {
8 const struct super_block *sb; 20 const struct super_block *sb;
9 const struct dentry *dentry; 21 const struct dentry *dentry;
@@ -16,12 +28,25 @@ struct nfs_clone_mount {
16}; 28};
17 29
18/* client.c */ 30/* client.c */
31extern struct rpc_program nfs_program;
32
19extern void nfs_put_client(struct nfs_client *); 33extern void nfs_put_client(struct nfs_client *);
20extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int); 34extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int);
21extern struct nfs_client *nfs_get_client(const char *, const struct sockaddr_in *, int); 35extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *,
22extern void nfs_mark_client_ready(struct nfs_client *, int); 36 struct nfs_fh *);
23extern int nfs_create_rpc_client(struct nfs_client *, int, unsigned int, 37extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *,
24 unsigned int, rpc_authflavor_t); 38 const char *,
39 const struct sockaddr_in *,
40 const char *,
41 const char *,
42 rpc_authflavor_t,
43 struct nfs_fh *);
44extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
45 struct nfs_fh *);
46extern void nfs_free_server(struct nfs_server *server);
47extern struct nfs_server *nfs_clone_server(struct nfs_server *,
48 struct nfs_fh *,
49 struct nfs_fattr *);
25 50
26/* nfs4namespace.c */ 51/* nfs4namespace.c */
27#ifdef CONFIG_NFS_V4 52#ifdef CONFIG_NFS_V4
@@ -89,10 +114,10 @@ extern void nfs4_clear_inode(struct inode *);
89#endif 114#endif
90 115
91/* super.c */ 116/* super.c */
92extern struct file_system_type nfs_referral_nfs4_fs_type; 117extern struct file_system_type nfs_xdev_fs_type;
93extern struct file_system_type clone_nfs_fs_type;
94#ifdef CONFIG_NFS_V4 118#ifdef CONFIG_NFS_V4
95extern struct file_system_type clone_nfs4_fs_type; 119extern struct file_system_type nfs4_xdev_fs_type;
120extern struct file_system_type nfs4_referral_fs_type;
96#endif 121#endif
97 122
98extern struct rpc_stat nfs_rpcstat; 123extern struct rpc_stat nfs_rpcstat;
@@ -101,28 +126,30 @@ extern int __init register_nfs_fs(void);
101extern void __exit unregister_nfs_fs(void); 126extern void __exit unregister_nfs_fs(void);
102 127
103/* namespace.c */ 128/* namespace.c */
104extern char *nfs_path(const char *base, const struct dentry *dentry, 129extern char *nfs_path(const char *base,
130 const struct dentry *droot,
131 const struct dentry *dentry,
105 char *buffer, ssize_t buflen); 132 char *buffer, ssize_t buflen);
106 133
107/* 134/* getroot.c */
108 * Determine the mount path as a string 135extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
109 */
110#ifdef CONFIG_NFS_V4 136#ifdef CONFIG_NFS_V4
111static inline char * 137extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *);
112nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen) 138
113{ 139extern int nfs4_path_walk(struct nfs_server *server,
114 return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen); 140 struct nfs_fh *mntfh,
115} 141 const char *path);
116#endif 142#endif
117 143
118/* 144/*
119 * Determine the device name as a string 145 * Determine the device name as a string
120 */ 146 */
121static inline char *nfs_devname(const struct vfsmount *mnt_parent, 147static inline char *nfs_devname(const struct vfsmount *mnt_parent,
122 const struct dentry *dentry, 148 const struct dentry *dentry,
123 char *buffer, ssize_t buflen) 149 char *buffer, ssize_t buflen)
124{ 150{
125 return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen); 151 return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root,
152 dentry, buffer, buflen);
126} 153}
127 154
128/* 155/*
@@ -178,20 +205,3 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
178 if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0) 205 if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0)
179 sb->s_maxbytes = MAX_LFS_FILESIZE; 206 sb->s_maxbytes = MAX_LFS_FILESIZE;
180} 207}
181
182/*
183 * Check if the string represents a "valid" IPv4 address
184 */
185static inline int valid_ipaddr4(const char *buf)
186{
187 int rc, count, in[4];
188
189 rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
190 if (rc != 4)
191 return -EINVAL;
192 for (count = 0; count < 4; count++) {
193 if (in[count] > 255)
194 return -EINVAL;
195 }
196 return 0;
197}
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index d8b8d56266cb..77b00684894d 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -2,6 +2,7 @@
2 * linux/fs/nfs/namespace.c 2 * linux/fs/nfs/namespace.c
3 * 3 *
4 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> 4 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
5 * - Modified by David Howells <dhowells@redhat.com>
5 * 6 *
6 * NFS namespace 7 * NFS namespace
7 */ 8 */
@@ -28,6 +29,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
28/* 29/*
29 * nfs_path - reconstruct the path given an arbitrary dentry 30 * nfs_path - reconstruct the path given an arbitrary dentry
30 * @base - arbitrary string to prepend to the path 31 * @base - arbitrary string to prepend to the path
32 * @droot - pointer to root dentry for mountpoint
31 * @dentry - pointer to dentry 33 * @dentry - pointer to dentry
32 * @buffer - result buffer 34 * @buffer - result buffer
33 * @buflen - length of buffer 35 * @buflen - length of buffer
@@ -38,7 +40,9 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
38 * This is mainly for use in figuring out the path on the 40 * This is mainly for use in figuring out the path on the
39 * server side when automounting on top of an existing partition. 41 * server side when automounting on top of an existing partition.
40 */ 42 */
41char *nfs_path(const char *base, const struct dentry *dentry, 43char *nfs_path(const char *base,
44 const struct dentry *droot,
45 const struct dentry *dentry,
42 char *buffer, ssize_t buflen) 46 char *buffer, ssize_t buflen)
43{ 47{
44 char *end = buffer+buflen; 48 char *end = buffer+buflen;
@@ -47,7 +51,7 @@ char *nfs_path(const char *base, const struct dentry *dentry,
47 *--end = '\0'; 51 *--end = '\0';
48 buflen--; 52 buflen--;
49 spin_lock(&dcache_lock); 53 spin_lock(&dcache_lock);
50 while (!IS_ROOT(dentry)) { 54 while (!IS_ROOT(dentry) && dentry != droot) {
51 namelen = dentry->d_name.len; 55 namelen = dentry->d_name.len;
52 buflen -= namelen + 1; 56 buflen -= namelen + 1;
53 if (buflen < 0) 57 if (buflen < 0)
@@ -96,12 +100,13 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
96 struct nfs_fattr fattr; 100 struct nfs_fattr fattr;
97 int err; 101 int err;
98 102
103 dprintk("--> nfs_follow_mountpoint()\n");
104
99 BUG_ON(IS_ROOT(dentry)); 105 BUG_ON(IS_ROOT(dentry));
100 dprintk("%s: enter\n", __FUNCTION__); 106 dprintk("%s: enter\n", __FUNCTION__);
101 dput(nd->dentry); 107 dput(nd->dentry);
102 nd->dentry = dget(dentry); 108 nd->dentry = dget(dentry);
103 if (d_mountpoint(nd->dentry)) 109
104 goto out_follow;
105 /* Look it up again */ 110 /* Look it up again */
106 parent = dget_parent(nd->dentry); 111 parent = dget_parent(nd->dentry);
107 err = server->nfs_client->rpc_ops->lookup(parent->d_inode, 112 err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
@@ -134,6 +139,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
134 schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); 139 schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
135out: 140out:
136 dprintk("%s: done, returned %d\n", __FUNCTION__, err); 141 dprintk("%s: done, returned %d\n", __FUNCTION__, err);
142
143 dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
137 return ERR_PTR(err); 144 return ERR_PTR(err);
138out_err: 145out_err:
139 path_release(nd); 146 path_release(nd);
@@ -183,14 +190,14 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
183 switch (server->nfs_client->cl_nfsversion) { 190 switch (server->nfs_client->cl_nfsversion) {
184 case 2: 191 case 2:
185 case 3: 192 case 3:
186 mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata); 193 mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
187 break; 194 break;
188 case 4: 195 case 4:
189 mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata); 196 mnt = vfs_kern_mount(&nfs4_xdev_fs_type, 0, devname, mountdata);
190 } 197 }
191 return mnt; 198 return mnt;
192#else 199#else
193 return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata); 200 return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
194#endif 201#endif
195} 202}
196 203
@@ -216,6 +223,8 @@ struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
216 char *page = (char *) __get_free_page(GFP_USER); 223 char *page = (char *) __get_free_page(GFP_USER);
217 char *devname; 224 char *devname;
218 225
226 dprintk("--> nfs_do_submount()\n");
227
219 dprintk("%s: submounting on %s/%s\n", __FUNCTION__, 228 dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
220 dentry->d_parent->d_name.name, 229 dentry->d_parent->d_name.name,
221 dentry->d_name.name); 230 dentry->d_name.name);
@@ -230,5 +239,7 @@ free_page:
230 free_page((unsigned long)page); 239 free_page((unsigned long)page);
231out: 240out:
232 dprintk("%s: done\n", __FUNCTION__); 241 dprintk("%s: done\n", __FUNCTION__);
242
243 dprintk("<-- nfs_do_submount() = %p\n", mnt);
233 return mnt; 244 return mnt;
234} 245}
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 0622af0122be..9e8258ece6fd 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -81,7 +81,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
81} 81}
82 82
83/* 83/*
84 * Bare-bones access to getattr: this is for nfs_read_super. 84 * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb
85 */ 85 */
86static int 86static int
87nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, 87nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index e7879245361e..61095fe4b5ca 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -188,8 +188,6 @@ extern void nfs4_kill_renewd(struct nfs_client *);
188extern void nfs4_renew_state(void *); 188extern void nfs4_renew_state(void *);
189 189
190/* nfs4state.c */ 190/* nfs4state.c */
191extern void init_nfsv4_state(struct nfs_server *);
192extern void destroy_nfsv4_state(struct nfs_server *);
193struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); 191struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
194extern u32 nfs4_alloc_lockowner_id(struct nfs_client *); 192extern u32 nfs4_alloc_lockowner_id(struct nfs_client *);
195 193
@@ -224,10 +222,6 @@ extern struct svc_version nfs4_callback_version1;
224 222
225#else 223#else
226 224
227#define init_nfsv4_state(server) do { } while (0)
228#define destroy_nfsv4_state(server) do { } while (0)
229#define nfs4_put_state_owner(inode, owner) do { } while (0)
230#define nfs4_put_open_state(state) do { } while (0)
231#define nfs4_close_state(a, b) do { } while (0) 225#define nfs4_close_state(a, b) do { } while (0)
232 226
233#endif /* CONFIG_NFS_V4 */ 227#endif /* CONFIG_NFS_V4 */
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index faed9bcba50f..24e47f3bbd17 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -2,6 +2,7 @@
2 * linux/fs/nfs/nfs4namespace.c 2 * linux/fs/nfs/nfs4namespace.c
3 * 3 *
4 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> 4 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
5 * - Modified by David Howells <dhowells@redhat.com>
5 * 6 *
6 * NFSv4 namespace 7 * NFSv4 namespace
7 */ 8 */
@@ -47,6 +48,68 @@ Elong:
47 return ERR_PTR(-ENAMETOOLONG); 48 return ERR_PTR(-ENAMETOOLONG);
48} 49}
49 50
51/*
52 * Determine the mount path as a string
53 */
54static char *nfs4_path(const struct vfsmount *mnt_parent,
55 const struct dentry *dentry,
56 char *buffer, ssize_t buflen)
57{
58 const char *srvpath;
59
60 srvpath = strchr(mnt_parent->mnt_devname, ':');
61 if (srvpath)
62 srvpath++;
63 else
64 srvpath = mnt_parent->mnt_devname;
65
66 return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen);
67}
68
69/*
70 * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
71 * believe to be the server path to this dentry
72 */
73static int nfs4_validate_fspath(const struct vfsmount *mnt_parent,
74 const struct dentry *dentry,
75 const struct nfs4_fs_locations *locations,
76 char *page, char *page2)
77{
78 const char *path, *fs_path;
79
80 path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE);
81 if (IS_ERR(path))
82 return PTR_ERR(path);
83
84 fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
85 if (IS_ERR(fs_path))
86 return PTR_ERR(fs_path);
87
88 if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
89 dprintk("%s: path %s does not begin with fsroot %s\n",
90 __FUNCTION__, path, fs_path);
91 return -ENOENT;
92 }
93
94 return 0;
95}
96
97/*
98 * Check if the string represents a "valid" IPv4 address
99 */
100static inline int valid_ipaddr4(const char *buf)
101{
102 int rc, count, in[4];
103
104 rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
105 if (rc != 4)
106 return -EINVAL;
107 for (count = 0; count < 4; count++) {
108 if (in[count] > 255)
109 return -EINVAL;
110 }
111 return 0;
112}
50 113
51/** 114/**
52 * nfs_follow_referral - set up mountpoint when hitting a referral on moved error 115 * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
@@ -68,10 +131,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
68 .dentry = dentry, 131 .dentry = dentry,
69 .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, 132 .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
70 }; 133 };
71 char *page, *page2; 134 char *page = NULL, *page2 = NULL;
72 char *path, *fs_path;
73 char *devname; 135 char *devname;
74 int loc, s; 136 int loc, s, error;
75 137
76 if (locations == NULL || locations->nlocations <= 0) 138 if (locations == NULL || locations->nlocations <= 0)
77 goto out; 139 goto out;
@@ -79,31 +141,25 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
79 dprintk("%s: referral at %s/%s\n", __FUNCTION__, 141 dprintk("%s: referral at %s/%s\n", __FUNCTION__,
80 dentry->d_parent->d_name.name, dentry->d_name.name); 142 dentry->d_parent->d_name.name, dentry->d_name.name);
81 143
82 /* Ensure fs path is a prefix of current dentry path */
83 page = (char *) __get_free_page(GFP_USER); 144 page = (char *) __get_free_page(GFP_USER);
84 if (page == NULL) 145 if (!page)
85 goto out; 146 goto out;
147
86 page2 = (char *) __get_free_page(GFP_USER); 148 page2 = (char *) __get_free_page(GFP_USER);
87 if (page2 == NULL) 149 if (!page2)
88 goto out; 150 goto out;
89 151
90 path = nfs4_path(dentry, page, PAGE_SIZE); 152 /* Ensure fs path is a prefix of current dentry path */
91 if (IS_ERR(path)) 153 error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2);
92 goto out_free; 154 if (error < 0) {
93 155 mnt = ERR_PTR(error);
94 fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); 156 goto out;
95 if (IS_ERR(fs_path))
96 goto out_free;
97
98 if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
99 dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path);
100 goto out_free;
101 } 157 }
102 158
103 devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); 159 devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
104 if (IS_ERR(devname)) { 160 if (IS_ERR(devname)) {
105 mnt = (struct vfsmount *)devname; 161 mnt = (struct vfsmount *)devname;
106 goto out_free; 162 goto out;
107 } 163 }
108 164
109 loc = 0; 165 loc = 0;
@@ -140,7 +196,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
140 addr.sin_port = htons(NFS_PORT); 196 addr.sin_port = htons(NFS_PORT);
141 mountdata.addr = &addr; 197 mountdata.addr = &addr;
142 198
143 mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata); 199 mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata);
144 if (!IS_ERR(mnt)) { 200 if (!IS_ERR(mnt)) {
145 break; 201 break;
146 } 202 }
@@ -149,10 +205,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
149 loc++; 205 loc++;
150 } 206 }
151 207
152out_free:
153 free_page((unsigned long)page);
154 free_page((unsigned long)page2);
155out: 208out:
209 free_page((unsigned long) page);
210 free_page((unsigned long) page2);
156 dprintk("%s: done\n", __FUNCTION__); 211 dprintk("%s: done\n", __FUNCTION__);
157 return mnt; 212 return mnt;
158} 213}
@@ -165,7 +220,7 @@ out:
165 */ 220 */
166struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) 221struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
167{ 222{
168 struct vfsmount *mnt = ERR_PTR(-ENOENT); 223 struct vfsmount *mnt = ERR_PTR(-ENOMEM);
169 struct dentry *parent; 224 struct dentry *parent;
170 struct nfs4_fs_locations *fs_locations = NULL; 225 struct nfs4_fs_locations *fs_locations = NULL;
171 struct page *page; 226 struct page *page;
@@ -183,11 +238,16 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr
183 goto out_free; 238 goto out_free;
184 239
185 /* Get locations */ 240 /* Get locations */
241 mnt = ERR_PTR(-ENOENT);
242
186 parent = dget_parent(dentry); 243 parent = dget_parent(dentry);
187 dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name); 244 dprintk("%s: getting locations for %s/%s\n",
245 __FUNCTION__, parent->d_name.name, dentry->d_name.name);
246
188 err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); 247 err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page);
189 dput(parent); 248 dput(parent);
190 if (err != 0 || fs_locations->nlocations <= 0 || 249 if (err != 0 ||
250 fs_locations->nlocations <= 0 ||
191 fs_locations->fs_path.ncomponents <= 0) 251 fs_locations->fs_path.ncomponents <= 0)
192 goto out_free; 252 goto out_free;
193 253
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1573eeb07ce1..a825547e8214 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1393,70 +1393,19 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
1393 return err; 1393 return err;
1394} 1394}
1395 1395
1396/*
1397 * get the file handle for the "/" directory on the server
1398 */
1396static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, 1399static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
1397 struct nfs_fsinfo *info) 1400 struct nfs_fsinfo *info)
1398{ 1401{
1399 struct nfs_fattr * fattr = info->fattr;
1400 unsigned char * p;
1401 struct qstr q;
1402 struct nfs4_lookup_arg args = {
1403 .dir_fh = fhandle,
1404 .name = &q,
1405 .bitmask = nfs4_fattr_bitmap,
1406 };
1407 struct nfs4_lookup_res res = {
1408 .server = server,
1409 .fattr = fattr,
1410 .fh = fhandle,
1411 };
1412 struct rpc_message msg = {
1413 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
1414 .rpc_argp = &args,
1415 .rpc_resp = &res,
1416 };
1417 int status; 1402 int status;
1418 1403
1419 /*
1420 * Now we do a separate LOOKUP for each component of the mount path.
1421 * The LOOKUPs are done separately so that we can conveniently
1422 * catch an ERR_WRONGSEC if it occurs along the way...
1423 */
1424 status = nfs4_lookup_root(server, fhandle, info); 1404 status = nfs4_lookup_root(server, fhandle, info);
1425 if (status)
1426 goto out;
1427
1428 p = server->mnt_path;
1429 for (;;) {
1430 struct nfs4_exception exception = { };
1431
1432 while (*p == '/')
1433 p++;
1434 if (!*p)
1435 break;
1436 q.name = p;
1437 while (*p && (*p != '/'))
1438 p++;
1439 q.len = p - q.name;
1440
1441 do {
1442 nfs_fattr_init(fattr);
1443 status = nfs4_handle_exception(server,
1444 rpc_call_sync(server->client, &msg, 0),
1445 &exception);
1446 } while (exception.retry);
1447 if (status == 0)
1448 continue;
1449 if (status == -ENOENT) {
1450 printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path);
1451 printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n");
1452 }
1453 break;
1454 }
1455 if (status == 0) 1405 if (status == 0)
1456 status = nfs4_server_capabilities(server, fhandle); 1406 status = nfs4_server_capabilities(server, fhandle);
1457 if (status == 0) 1407 if (status == 0)
1458 status = nfs4_do_fsinfo(server, fhandle, info); 1408 status = nfs4_do_fsinfo(server, fhandle, info);
1459out:
1460 return nfs4_map_errors(status); 1409 return nfs4_map_errors(status);
1461} 1410}
1462 1411
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index ff947ecb8b81..f2c893690ac4 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -127,26 +127,13 @@ nfs4_schedule_state_renewal(struct nfs_client *clp)
127void 127void
128nfs4_renewd_prepare_shutdown(struct nfs_server *server) 128nfs4_renewd_prepare_shutdown(struct nfs_server *server)
129{ 129{
130 struct nfs_client *clp = server->nfs_client;
131
132 if (!clp)
133 return;
134 flush_scheduled_work(); 130 flush_scheduled_work();
135 down_write(&clp->cl_sem);
136 if (!list_empty(&server->nfs4_siblings))
137 list_del_init(&server->nfs4_siblings);
138 up_write(&clp->cl_sem);
139} 131}
140 132
141/* Must be called with clp->cl_sem locked for writes */
142void 133void
143nfs4_kill_renewd(struct nfs_client *clp) 134nfs4_kill_renewd(struct nfs_client *clp)
144{ 135{
145 down_read(&clp->cl_sem); 136 down_read(&clp->cl_sem);
146 if (!list_empty(&clp->cl_superblocks)) {
147 up_read(&clp->cl_sem);
148 return;
149 }
150 cancel_delayed_work(&clp->cl_renewd); 137 cancel_delayed_work(&clp->cl_renewd);
151 up_read(&clp->cl_sem); 138 up_read(&clp->cl_sem);
152 flush_scheduled_work(); 139 flush_scheduled_work();
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 058811e39555..5fffbdfa971f 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -58,24 +58,6 @@ const nfs4_stateid zero_stateid;
58 58
59static LIST_HEAD(nfs4_clientid_list); 59static LIST_HEAD(nfs4_clientid_list);
60 60
61void
62init_nfsv4_state(struct nfs_server *server)
63{
64 server->nfs_client = NULL;
65 INIT_LIST_HEAD(&server->nfs4_siblings);
66}
67
68void
69destroy_nfsv4_state(struct nfs_server *server)
70{
71 kfree(server->mnt_path);
72 server->mnt_path = NULL;
73 if (server->nfs_client) {
74 nfs_put_client(server->nfs_client);
75 server->nfs_client = NULL;
76 }
77}
78
79static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) 61static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
80{ 62{
81 int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, 63 int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index f0aff824a291..dae33c1e8a77 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -171,7 +171,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
171 rdata->args.offset = page_offset(page) + rdata->args.pgbase; 171 rdata->args.offset = page_offset(page) + rdata->args.pgbase;
172 172
173 dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n", 173 dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n",
174 NFS_SERVER(inode)->hostname, 174 NFS_SERVER(inode)->nfs_client->cl_hostname,
175 inode->i_sb->s_id, 175 inode->i_sb->s_id,
176 (long long)NFS_FILEID(inode), 176 (long long)NFS_FILEID(inode),
177 (unsigned long long)rdata->args.pgbase, 177 (unsigned long long)rdata->args.pgbase,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 5842d510d732..867b5dcd3a40 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -13,6 +13,11 @@
13 * 13 *
14 * Split from inode.c by David Howells <dhowells@redhat.com> 14 * Split from inode.c by David Howells <dhowells@redhat.com>
15 * 15 *
16 * - superblocks are indexed on server only - all inodes, dentries, etc. associated with a
17 * particular server are held in the same superblock
18 * - NFS superblocks can have several effective roots to the dentry tree
19 * - directory type roots are spliced into the tree when a path from one root reaches the root
20 * of another (see nfs_lookup())
16 */ 21 */
17 22
18#include <linux/config.h> 23#include <linux/config.h>
@@ -52,20 +57,12 @@
52 57
53#define NFSDBG_FACILITY NFSDBG_VFS 58#define NFSDBG_FACILITY NFSDBG_VFS
54 59
55/* Maximum number of readahead requests
56 * FIXME: this should really be a sysctl so that users may tune it to suit
57 * their needs. People that do NFS over a slow network, might for
58 * instance want to reduce it to something closer to 1 for improved
59 * interactive response.
60 */
61#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
62
63static void nfs_umount_begin(struct vfsmount *, int); 60static void nfs_umount_begin(struct vfsmount *, int);
64static int nfs_statfs(struct dentry *, struct kstatfs *); 61static int nfs_statfs(struct dentry *, struct kstatfs *);
65static int nfs_show_options(struct seq_file *, struct vfsmount *); 62static int nfs_show_options(struct seq_file *, struct vfsmount *);
66static int nfs_show_stats(struct seq_file *, struct vfsmount *); 63static int nfs_show_stats(struct seq_file *, struct vfsmount *);
67static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); 64static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *);
68static int nfs_clone_nfs_sb(struct file_system_type *fs_type, 65static int nfs_xdev_get_sb(struct file_system_type *fs_type,
69 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 66 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
70static void nfs_kill_super(struct super_block *); 67static void nfs_kill_super(struct super_block *);
71 68
@@ -77,10 +74,10 @@ static struct file_system_type nfs_fs_type = {
77 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 74 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
78}; 75};
79 76
80struct file_system_type clone_nfs_fs_type = { 77struct file_system_type nfs_xdev_fs_type = {
81 .owner = THIS_MODULE, 78 .owner = THIS_MODULE,
82 .name = "nfs", 79 .name = "nfs",
83 .get_sb = nfs_clone_nfs_sb, 80 .get_sb = nfs_xdev_get_sb,
84 .kill_sb = nfs_kill_super, 81 .kill_sb = nfs_kill_super,
85 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 82 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
86}; 83};
@@ -99,10 +96,10 @@ static struct super_operations nfs_sops = {
99#ifdef CONFIG_NFS_V4 96#ifdef CONFIG_NFS_V4
100static int nfs4_get_sb(struct file_system_type *fs_type, 97static int nfs4_get_sb(struct file_system_type *fs_type,
101 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 98 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
102static int nfs_clone_nfs4_sb(struct file_system_type *fs_type, 99static int nfs4_xdev_get_sb(struct file_system_type *fs_type,
103 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 100 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
104static int nfs_referral_nfs4_sb(struct file_system_type *fs_type, 101static int nfs4_referral_get_sb(struct file_system_type *fs_type,
105 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 102 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
106static void nfs4_kill_super(struct super_block *sb); 103static void nfs4_kill_super(struct super_block *sb);
107 104
108static struct file_system_type nfs4_fs_type = { 105static struct file_system_type nfs4_fs_type = {
@@ -113,18 +110,18 @@ static struct file_system_type nfs4_fs_type = {
113 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 110 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
114}; 111};
115 112
116struct file_system_type clone_nfs4_fs_type = { 113struct file_system_type nfs4_xdev_fs_type = {
117 .owner = THIS_MODULE, 114 .owner = THIS_MODULE,
118 .name = "nfs4", 115 .name = "nfs4",
119 .get_sb = nfs_clone_nfs4_sb, 116 .get_sb = nfs4_xdev_get_sb,
120 .kill_sb = nfs4_kill_super, 117 .kill_sb = nfs4_kill_super,
121 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 118 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
122}; 119};
123 120
124struct file_system_type nfs_referral_nfs4_fs_type = { 121struct file_system_type nfs4_referral_fs_type = {
125 .owner = THIS_MODULE, 122 .owner = THIS_MODULE,
126 .name = "nfs4", 123 .name = "nfs4",
127 .get_sb = nfs_referral_nfs4_sb, 124 .get_sb = nfs4_referral_get_sb,
128 .kill_sb = nfs4_kill_super, 125 .kill_sb = nfs4_kill_super,
129 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 126 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
130}; 127};
@@ -345,7 +342,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
345 nfs_show_mount_options(m, nfss, 0); 342 nfs_show_mount_options(m, nfss, 0);
346 343
347 seq_puts(m, ",addr="); 344 seq_puts(m, ",addr=");
348 seq_escape(m, nfss->hostname, " \t\n\\"); 345 seq_escape(m, nfss->nfs_client->cl_hostname, " \t\n\\");
349 346
350 return 0; 347 return 0;
351} 348}
@@ -429,714 +426,351 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
429 426
430/* 427/*
431 * Begin unmount by attempting to remove all automounted mountpoints we added 428 * Begin unmount by attempting to remove all automounted mountpoints we added
432 * in response to traversals 429 * in response to xdev traversals and referrals
433 */ 430 */
434static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) 431static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
435{ 432{
436 struct nfs_server *server;
437 struct rpc_clnt *rpc;
438
439 shrink_submounts(vfsmnt, &nfs_automount_list); 433 shrink_submounts(vfsmnt, &nfs_automount_list);
440 if (!(flags & MNT_FORCE))
441 return;
442 /* -EIO all pending I/O */
443 server = NFS_SB(vfsmnt->mnt_sb);
444 rpc = server->client;
445 if (!IS_ERR(rpc))
446 rpc_killall_tasks(rpc);
447 rpc = server->client_acl;
448 if (!IS_ERR(rpc))
449 rpc_killall_tasks(rpc);
450} 434}
451 435
452/* 436/*
453 * Obtain the root inode of the file system. 437 * Validate the NFS2/NFS3 mount data
438 * - fills in the mount root filehandle
454 */ 439 */
455static struct inode * 440static int nfs_validate_mount_data(struct nfs_mount_data *data,
456nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) 441 struct nfs_fh *mntfh)
457{ 442{
458 struct nfs_server *server = NFS_SB(sb); 443 if (data == NULL) {
459 int error; 444 dprintk("%s: missing data argument\n", __FUNCTION__);
460 445 return -EINVAL;
461 error = server->nfs_client->rpc_ops->getroot(server, rootfh, fsinfo);
462 if (error < 0) {
463 dprintk("nfs_get_root: getattr error = %d\n", -error);
464 return ERR_PTR(error);
465 } 446 }
466 447
467 server->fsid = fsinfo->fattr->fsid; 448 if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
468 return nfs_fhget(sb, rootfh, fsinfo->fattr); 449 dprintk("%s: bad mount version\n", __FUNCTION__);
469} 450 return -EINVAL;
470 451 }
471/*
472 * Do NFS version-independent mount processing, and sanity checking
473 */
474static int
475nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
476{
477 struct nfs_server *server;
478 struct inode *root_inode;
479 struct nfs_fattr fattr;
480 struct nfs_fsinfo fsinfo = {
481 .fattr = &fattr,
482 };
483 struct nfs_pathconf pathinfo = {
484 .fattr = &fattr,
485 };
486 int no_root_error = 0;
487 unsigned long max_rpc_payload;
488
489 /* We probably want something more informative here */
490 snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
491
492 server = NFS_SB(sb);
493
494 sb->s_magic = NFS_SUPER_MAGIC;
495
496 server->io_stats = nfs_alloc_iostats();
497 if (server->io_stats == NULL)
498 return -ENOMEM;
499 452
500 root_inode = nfs_get_root(sb, &server->fh, &fsinfo); 453 switch (data->version) {
501 /* Did getting the root inode fail? */ 454 case 1:
502 if (IS_ERR(root_inode)) { 455 data->namlen = 0;
503 no_root_error = PTR_ERR(root_inode); 456 case 2:
504 goto out_no_root; 457 data->bsize = 0;
458 case 3:
459 if (data->flags & NFS_MOUNT_VER3) {
460 dprintk("%s: mount structure version %d does not support NFSv3\n",
461 __FUNCTION__,
462 data->version);
463 return -EINVAL;
464 }
465 data->root.size = NFS2_FHSIZE;
466 memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
467 case 4:
468 if (data->flags & NFS_MOUNT_SECFLAVOUR) {
469 dprintk("%s: mount structure version %d does not support strong security\n",
470 __FUNCTION__,
471 data->version);
472 return -EINVAL;
473 }
474 /* Fill in pseudoflavor for mount version < 5 */
475 data->pseudoflavor = RPC_AUTH_UNIX;
476 case 5:
477 memset(data->context, 0, sizeof(data->context));
505 } 478 }
506 sb->s_root = d_alloc_root(root_inode); 479
507 if (!sb->s_root) { 480#ifndef CONFIG_NFS_V3
508 no_root_error = -ENOMEM; 481 /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
509 goto out_no_root; 482 if (data->flags & NFS_MOUNT_VER3) {
483 dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
484 return -EPROTONOSUPPORT;
510 } 485 }
511 sb->s_root->d_op = server->nfs_client->rpc_ops->dentry_ops; 486#endif /* CONFIG_NFS_V3 */
512
513 /* mount time stamp, in seconds */
514 server->mount_time = jiffies;
515
516 /* Get some general file system info */
517 if (server->namelen == 0 &&
518 server->nfs_client->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
519 server->namelen = pathinfo.max_namelen;
520 /* Work out a lot of parameters */
521 if (server->rsize == 0)
522 server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
523 if (server->wsize == 0)
524 server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
525
526 if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
527 server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
528 if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
529 server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
530
531 max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
532 if (server->rsize > max_rpc_payload)
533 server->rsize = max_rpc_payload;
534 if (server->rsize > NFS_MAX_FILE_IO_SIZE)
535 server->rsize = NFS_MAX_FILE_IO_SIZE;
536 server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
537
538 if (server->wsize > max_rpc_payload)
539 server->wsize = max_rpc_payload;
540 if (server->wsize > NFS_MAX_FILE_IO_SIZE)
541 server->wsize = NFS_MAX_FILE_IO_SIZE;
542 server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
543 487
544 if (sb->s_blocksize == 0) 488 /* We now require that the mount process passes the remote address */
545 sb->s_blocksize = nfs_block_bits(server->wsize, 489 if (data->addr.sin_addr.s_addr == INADDR_ANY) {
546 &sb->s_blocksize_bits); 490 dprintk("%s: mount program didn't pass remote address!\n",
547 server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL); 491 __FUNCTION__);
548 492 return -EINVAL;
549 server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
550 if (server->dtsize > PAGE_CACHE_SIZE)
551 server->dtsize = PAGE_CACHE_SIZE;
552 if (server->dtsize > server->rsize)
553 server->dtsize = server->rsize;
554
555 if (server->flags & NFS_MOUNT_NOAC) {
556 server->acregmin = server->acregmax = 0;
557 server->acdirmin = server->acdirmax = 0;
558 sb->s_flags |= MS_SYNCHRONOUS;
559 } 493 }
560 server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
561 494
562 nfs_super_set_maxbytes(sb, fsinfo.maxfilesize); 495 /* Prepare the root filehandle */
496 if (data->flags & NFS_MOUNT_VER3)
497 mntfh->size = data->root.size;
498 else
499 mntfh->size = NFS2_FHSIZE;
563 500
564 server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0; 501 if (mntfh->size > sizeof(mntfh->data)) {
565 server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0; 502 dprintk("%s: invalid root filehandle\n", __FUNCTION__);
503 return -EINVAL;
504 }
505
506 memcpy(mntfh->data, data->root.data, mntfh->size);
507 if (mntfh->size < sizeof(mntfh->data))
508 memset(mntfh->data + mntfh->size, 0,
509 sizeof(mntfh->data) - mntfh->size);
566 510
567 /* We're airborne Set socket buffersize */
568 rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
569 return 0; 511 return 0;
570 /* Yargs. It didn't work out. */
571out_no_root:
572 dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error);
573 if (!IS_ERR(root_inode))
574 iput(root_inode);
575 return no_root_error;
576} 512}
577 513
578/* 514/*
579 * Create an RPC client handle. 515 * Initialise the common bits of the superblock
580 */ 516 */
581static struct rpc_clnt * 517static inline void nfs_initialise_sb(struct super_block *sb)
582nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
583{ 518{
584 struct nfs_client *clp; 519 struct nfs_server *server = NFS_SB(sb);
585 struct rpc_clnt *clnt;
586 int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
587 int nfsversion = 2;
588 int err;
589
590#ifdef CONFIG_NFS_V3
591 if (server->flags & NFS_MOUNT_VER3)
592 nfsversion = 3;
593#endif
594
595 clp = nfs_get_client(server->hostname, &server->addr, nfsversion);
596 if (!clp) {
597 dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
598 return ERR_PTR(PTR_ERR(clp));
599 }
600
601 if (clp->cl_cons_state == NFS_CS_INITING) {
602 /* Check NFS protocol revision and initialize RPC op
603 * vector and file handle pool. */
604#ifdef CONFIG_NFS_V3
605 if (nfsversion == 3) {
606 clp->rpc_ops = &nfs_v3_clientops;
607 server->caps |= NFS_CAP_READDIRPLUS;
608 } else {
609 clp->rpc_ops = &nfs_v2_clientops;
610 }
611#else
612 clp->rpc_ops = &nfs_v2_clientops;
613#endif
614
615 /* create transport and client */
616 err = nfs_create_rpc_client(clp, proto, data->timeo,
617 data->retrans, RPC_AUTH_UNIX);
618 if (err < 0)
619 goto client_init_error;
620
621 nfs_mark_client_ready(clp, 0);
622 }
623 520
624 /* create an nfs_server-specific client */ 521 sb->s_magic = NFS_SUPER_MAGIC;
625 clnt = rpc_clone_client(clp->cl_rpcclient);
626 if (IS_ERR(clnt)) {
627 dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__);
628 nfs_put_client(clp);
629 return ERR_PTR(PTR_ERR(clnt));
630 }
631 522
632 if (data->pseudoflavor != clp->cl_rpcclient->cl_auth->au_flavor) { 523 /* We probably want something more informative here */
633 struct rpc_auth *auth; 524 snprintf(sb->s_id, sizeof(sb->s_id),
525 "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
634 526
635 auth = rpcauth_create(data->pseudoflavor, server->client); 527 if (sb->s_blocksize == 0)
636 if (IS_ERR(auth)) { 528 sb->s_blocksize = nfs_block_bits(server->wsize,
637 dprintk("%s: couldn't create credcache!\n", __FUNCTION__); 529 &sb->s_blocksize_bits);
638 return ERR_PTR(PTR_ERR(auth));
639 }
640 }
641 530
642 server->nfs_client = clp; 531 if (server->flags & NFS_MOUNT_NOAC)
643 return clnt; 532 sb->s_flags |= MS_SYNCHRONOUS;
644 533
645client_init_error: 534 nfs_super_set_maxbytes(sb, server->maxfilesize);
646 nfs_mark_client_ready(clp, err);
647 nfs_put_client(clp);
648 return ERR_PTR(err);
649} 535}
650 536
651/* 537/*
652 * Clone a server record 538 * Finish setting up an NFS2/3 superblock
653 */ 539 */
654static struct nfs_server *nfs_clone_server(struct super_block *sb, struct nfs_clone_mount *data) 540static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data)
655{ 541{
656 struct nfs_server *server = NFS_SB(sb); 542 struct nfs_server *server = NFS_SB(sb);
657 struct nfs_server *parent = NFS_SB(data->sb);
658 struct inode *root_inode;
659 struct nfs_fsinfo fsinfo;
660 void *err = ERR_PTR(-ENOMEM);
661
662 sb->s_op = data->sb->s_op;
663 sb->s_blocksize = data->sb->s_blocksize;
664 sb->s_blocksize_bits = data->sb->s_blocksize_bits;
665 sb->s_maxbytes = data->sb->s_maxbytes;
666
667 server->client_acl = ERR_PTR(-EINVAL);
668 server->io_stats = nfs_alloc_iostats();
669 if (server->io_stats == NULL)
670 goto out;
671
672 server->client = rpc_clone_client(parent->client);
673 if (IS_ERR((err = server->client)))
674 goto out;
675
676 if (!IS_ERR(parent->client_acl)) {
677 server->client_acl = rpc_clone_client(parent->client_acl);
678 if (IS_ERR((err = server->client_acl)))
679 goto out;
680 }
681 root_inode = nfs_fhget(sb, data->fh, data->fattr);
682 if (!root_inode)
683 goto out;
684 sb->s_root = d_alloc_root(root_inode);
685 if (!sb->s_root)
686 goto out_put_root;
687 fsinfo.fattr = data->fattr;
688 if (NFS_PROTO(root_inode)->fsinfo(server, data->fh, &fsinfo) == 0)
689 nfs_super_set_maxbytes(sb, fsinfo.maxfilesize);
690 sb->s_root->d_op = server->nfs_client->rpc_ops->dentry_ops;
691 sb->s_flags |= MS_ACTIVE;
692 return server;
693out_put_root:
694 iput(root_inode);
695out:
696 return err;
697}
698
699/*
700 * Copy an existing superblock and attach revised data
701 */
702static int nfs_clone_generic_sb(struct nfs_clone_mount *data,
703 struct super_block *(*fill_sb)(struct nfs_server *, struct nfs_clone_mount *),
704 struct nfs_server *(*fill_server)(struct super_block *, struct nfs_clone_mount *),
705 struct vfsmount *mnt)
706{
707 struct nfs_server *server;
708 struct nfs_server *parent = NFS_SB(data->sb);
709 struct super_block *sb = ERR_PTR(-EINVAL);
710 char *hostname;
711 int error = -ENOMEM;
712 int len;
713
714 server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL);
715 if (server == NULL)
716 goto out_err;
717 memcpy(server, parent, sizeof(*server));
718 atomic_inc(&server->nfs_client->cl_count);
719 hostname = (data->hostname != NULL) ? data->hostname : parent->hostname;
720 len = strlen(hostname) + 1;
721 server->hostname = kmalloc(len, GFP_KERNEL);
722 if (server->hostname == NULL)
723 goto free_server;
724 memcpy(server->hostname, hostname, len);
725
726 sb = fill_sb(server, data);
727 if (IS_ERR(sb)) {
728 error = PTR_ERR(sb);
729 goto free_hostname;
730 }
731 543
732 if (sb->s_root) 544 sb->s_blocksize_bits = 0;
733 goto out_share; 545 sb->s_blocksize = 0;
546 if (data->bsize)
547 sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
734 548
735 server = fill_server(sb, data); 549 if (server->flags & NFS_MOUNT_VER3) {
736 if (IS_ERR(server)) { 550 /* The VFS shouldn't apply the umask to mode bits. We will do
737 error = PTR_ERR(server); 551 * so ourselves when necessary.
738 goto out_deactivate; 552 */
553 sb->s_flags |= MS_POSIXACL;
554 sb->s_time_gran = 1;
739 } 555 }
740 return simple_set_mnt(mnt, sb); 556
741out_deactivate: 557 sb->s_op = &nfs_sops;
742 up_write(&sb->s_umount); 558 nfs_initialise_sb(sb);
743 deactivate_super(sb);
744 return error;
745out_share:
746 kfree(server->hostname);
747 nfs_put_client(server->nfs_client);
748 kfree(server);
749 return simple_set_mnt(mnt, sb);
750free_hostname:
751 kfree(server->hostname);
752free_server:
753 nfs_put_client(server->nfs_client);
754 kfree(server);
755out_err:
756 return error;
757} 559}
758 560
759/* 561/*
760 * Set up an NFS2/3 superblock 562 * Finish setting up a cloned NFS2/3 superblock
761 *
762 * The way this works is that the mount process passes a structure
763 * in the data argument which contains the server's IP address
764 * and the root file handle obtained from the server's mount
765 * daemon. We stash these away in the private superblock fields.
766 */ 563 */
767static int 564static void nfs_clone_super(struct super_block *sb,
768nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) 565 const struct super_block *old_sb)
769{ 566{
770 struct nfs_server *server; 567 struct nfs_server *server = NFS_SB(sb);
771 rpc_authflavor_t authflavor; 568
569 sb->s_blocksize_bits = old_sb->s_blocksize_bits;
570 sb->s_blocksize = old_sb->s_blocksize;
571 sb->s_maxbytes = old_sb->s_maxbytes;
772 572
773 server = NFS_SB(sb);
774 sb->s_blocksize_bits = 0;
775 sb->s_blocksize = 0;
776 if (data->bsize)
777 sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
778 if (data->rsize)
779 server->rsize = nfs_block_size(data->rsize, NULL);
780 if (data->wsize)
781 server->wsize = nfs_block_size(data->wsize, NULL);
782 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
783
784 server->acregmin = data->acregmin*HZ;
785 server->acregmax = data->acregmax*HZ;
786 server->acdirmin = data->acdirmin*HZ;
787 server->acdirmax = data->acdirmax*HZ;
788
789 /* Start lockd here, before we might error out */
790 if (!(server->flags & NFS_MOUNT_NONLM))
791 lockd_up();
792
793 server->namelen = data->namlen;
794 server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
795 if (!server->hostname)
796 return -ENOMEM;
797 strcpy(server->hostname, data->hostname);
798
799 /* Fill in pseudoflavor for mount version < 5 */
800 if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
801 data->pseudoflavor = RPC_AUTH_UNIX;
802 authflavor = data->pseudoflavor; /* save for sb_init() */
803 /* XXX maybe we want to add a server->pseudoflavor field */
804
805 /* Create RPC client handles */
806 server->client = nfs_create_client(server, data);
807 if (IS_ERR(server->client))
808 return PTR_ERR(server->client);
809
810 /* RFC 2623, sec 2.3.2 */
811 if (server->flags & NFS_MOUNT_VER3) { 573 if (server->flags & NFS_MOUNT_VER3) {
812#ifdef CONFIG_NFS_V3_ACL 574 /* The VFS shouldn't apply the umask to mode bits. We will do
813 if (!(server->flags & NFS_MOUNT_NOACL)) { 575 * so ourselves when necessary.
814 server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
815 /* No errors! Assume that Sun nfsacls are supported */
816 if (!IS_ERR(server->client_acl))
817 server->caps |= NFS_CAP_ACLS;
818 }
819#else
820 server->flags &= ~NFS_MOUNT_NOACL;
821#endif /* CONFIG_NFS_V3_ACL */
822 /*
823 * The VFS shouldn't apply the umask to mode bits. We will
824 * do so ourselves when necessary.
825 */ 576 */
826 sb->s_flags |= MS_POSIXACL; 577 sb->s_flags |= MS_POSIXACL;
827 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
828 server->namelen = NFS3_MAXNAMLEN;
829 sb->s_time_gran = 1; 578 sb->s_time_gran = 1;
830 } else {
831 if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
832 server->namelen = NFS2_MAXNAMLEN;
833 } 579 }
834 580
835 sb->s_op = &nfs_sops; 581 sb->s_op = old_sb->s_op;
836 return nfs_sb_init(sb, authflavor); 582 nfs_initialise_sb(sb);
837} 583}
838 584
839static int nfs_set_super(struct super_block *s, void *data) 585static int nfs_set_super(struct super_block *s, void *_server)
840{ 586{
841 s->s_fs_info = data; 587 struct nfs_server *server = _server;
842 return set_anon_super(s, data); 588 int ret;
589
590 s->s_fs_info = server;
591 ret = set_anon_super(s, server);
592 if (ret == 0)
593 server->s_dev = s->s_dev;
594 return ret;
843} 595}
844 596
845static int nfs_compare_super(struct super_block *sb, void *data) 597static int nfs_compare_super(struct super_block *sb, void *data)
846{ 598{
847 struct nfs_server *server = data; 599 struct nfs_server *server = data, *old = NFS_SB(sb);
848 struct nfs_server *old = NFS_SB(sb);
849 600
850 if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr) 601 if (old->nfs_client != server->nfs_client)
851 return 0; 602 return 0;
852 if (old->addr.sin_port != server->addr.sin_port) 603 if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
853 return 0; 604 return 0;
854 return !nfs_compare_fh(&old->fh, &server->fh); 605 return 1;
855} 606}
856 607
857static int nfs_get_sb(struct file_system_type *fs_type, 608static int nfs_get_sb(struct file_system_type *fs_type,
858 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) 609 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
859{ 610{
860 int error;
861 struct nfs_server *server = NULL; 611 struct nfs_server *server = NULL;
862 struct super_block *s; 612 struct super_block *s;
863 struct nfs_fh *root; 613 struct nfs_fh mntfh;
864 struct nfs_mount_data *data = raw_data; 614 struct nfs_mount_data *data = raw_data;
615 struct dentry *mntroot;
616 int error;
865 617
866 error = -EINVAL; 618 /* Validate the mount data */
867 if (data == NULL) { 619 error = nfs_validate_mount_data(data, &mntfh);
868 dprintk("%s: missing data argument\n", __FUNCTION__); 620 if (error < 0)
869 goto out_err_noserver; 621 return error;
870 }
871 if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
872 dprintk("%s: bad mount version\n", __FUNCTION__);
873 goto out_err_noserver;
874 }
875 switch (data->version) {
876 case 1:
877 data->namlen = 0;
878 case 2:
879 data->bsize = 0;
880 case 3:
881 if (data->flags & NFS_MOUNT_VER3) {
882 dprintk("%s: mount structure version %d does not support NFSv3\n",
883 __FUNCTION__,
884 data->version);
885 goto out_err_noserver;
886 }
887 data->root.size = NFS2_FHSIZE;
888 memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
889 case 4:
890 if (data->flags & NFS_MOUNT_SECFLAVOUR) {
891 dprintk("%s: mount structure version %d does not support strong security\n",
892 __FUNCTION__,
893 data->version);
894 goto out_err_noserver;
895 }
896 case 5:
897 memset(data->context, 0, sizeof(data->context));
898 }
899#ifndef CONFIG_NFS_V3
900 /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
901 error = -EPROTONOSUPPORT;
902 if (data->flags & NFS_MOUNT_VER3) {
903 dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
904 goto out_err_noserver;
905 }
906#endif /* CONFIG_NFS_V3 */
907 622
908 error = -ENOMEM; 623 /* Get a volume representation */
909 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); 624 server = nfs_create_server(data, &mntfh);
910 if (!server) 625 if (IS_ERR(server)) {
626 error = PTR_ERR(server);
911 goto out_err_noserver; 627 goto out_err_noserver;
912 /* Zero out the NFS state stuff */
913 init_nfsv4_state(server);
914 server->client = server->client_acl = ERR_PTR(-EINVAL);
915
916 root = &server->fh;
917 if (data->flags & NFS_MOUNT_VER3)
918 root->size = data->root.size;
919 else
920 root->size = NFS2_FHSIZE;
921 error = -EINVAL;
922 if (root->size > sizeof(root->data)) {
923 dprintk("%s: invalid root filehandle\n", __FUNCTION__);
924 goto out_err;
925 }
926 memcpy(root->data, data->root.data, root->size);
927
928 /* We now require that the mount process passes the remote address */
929 memcpy(&server->addr, &data->addr, sizeof(server->addr));
930 if (server->addr.sin_addr.s_addr == INADDR_ANY) {
931 dprintk("%s: mount program didn't pass remote address!\n",
932 __FUNCTION__);
933 goto out_err;
934 } 628 }
935 629
630 /* Get a superblock - note that we may end up sharing one that already exists */
936 s = sget(fs_type, nfs_compare_super, nfs_set_super, server); 631 s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
937 if (IS_ERR(s)) { 632 if (IS_ERR(s)) {
938 error = PTR_ERR(s); 633 error = PTR_ERR(s);
939 goto out_err; 634 goto out_err_nosb;
940 } 635 }
941 636
942 if (s->s_root) 637 if (s->s_fs_info != server) {
943 goto out_share; 638 nfs_free_server(server);
639 server = NULL;
640 }
944 641
945 s->s_flags = flags; 642 if (!s->s_root) {
643 /* initial superblock/root creation */
644 s->s_flags = flags;
645 nfs_fill_super(s, data);
646 }
946 647
947 error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0); 648 mntroot = nfs_get_root(s, &mntfh);
948 if (error) { 649 if (IS_ERR(mntroot)) {
949 up_write(&s->s_umount); 650 error = PTR_ERR(mntroot);
950 deactivate_super(s); 651 goto error_splat_super;
951 return error;
952 } 652 }
953 s->s_flags |= MS_ACTIVE;
954 return simple_set_mnt(mnt, s);
955 653
956out_share: 654 s->s_flags |= MS_ACTIVE;
957 kfree(server); 655 mnt->mnt_sb = s;
958 return simple_set_mnt(mnt, s); 656 mnt->mnt_root = mntroot;
657 return 0;
959 658
960out_err: 659out_err_nosb:
961 kfree(server); 660 nfs_free_server(server);
962out_err_noserver: 661out_err_noserver:
963 return error; 662 return error;
663
664error_splat_super:
665 up_write(&s->s_umount);
666 deactivate_super(s);
667 return error;
964} 668}
965 669
670/*
671 * Destroy an NFS2/3 superblock
672 */
966static void nfs_kill_super(struct super_block *s) 673static void nfs_kill_super(struct super_block *s)
967{ 674{
968 struct nfs_server *server = NFS_SB(s); 675 struct nfs_server *server = NFS_SB(s);
969 676
970 kill_anon_super(s); 677 kill_anon_super(s);
971 678 nfs_free_server(server);
972 if (!IS_ERR(server->client))
973 rpc_shutdown_client(server->client);
974 if (!IS_ERR(server->client_acl))
975 rpc_shutdown_client(server->client_acl);
976
977 if (!(server->flags & NFS_MOUNT_NONLM))
978 lockd_down(); /* release rpc.lockd */
979
980 nfs_free_iostats(server->io_stats);
981 kfree(server->hostname);
982 nfs_put_client(server->nfs_client);
983 kfree(server);
984 nfs_release_automount_timer();
985} 679}
986 680
987static struct super_block *nfs_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data) 681/*
988{ 682 * Clone an NFS2/3 server record on xdev traversal (FSID-change)
989 struct super_block *sb; 683 */
990 684static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
991 server->fsid = data->fattr->fsid; 685 const char *dev_name, void *raw_data,
992 nfs_copy_fh(&server->fh, data->fh); 686 struct vfsmount *mnt)
993 sb = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
994 if (!IS_ERR(sb) && sb->s_root == NULL && !(server->flags & NFS_MOUNT_NONLM))
995 lockd_up();
996 return sb;
997}
998
999static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
1000 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
1001{ 687{
1002 struct nfs_clone_mount *data = raw_data; 688 struct nfs_clone_mount *data = raw_data;
1003 return nfs_clone_generic_sb(data, nfs_clone_sb, nfs_clone_server, mnt); 689 struct super_block *s;
1004} 690 struct nfs_server *server;
691 struct dentry *mntroot;
692 int error;
1005 693
1006#ifdef CONFIG_NFS_V4 694 dprintk("--> nfs_xdev_get_sb()\n");
1007static struct rpc_clnt *nfs4_create_client(struct nfs_server *server,
1008 int timeo, int retrans, int proto, rpc_authflavor_t flavor)
1009{
1010 struct nfs_client *clp;
1011 struct rpc_clnt *clnt = NULL;
1012 int err = -EIO;
1013
1014 clp = nfs_get_client(server->hostname, &server->addr, 4);
1015 if (!clp) {
1016 dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
1017 return ERR_PTR(err);
1018 }
1019 695
1020 /* Now create transport and client */ 696 /* create a new volume representation */
1021 if (clp->cl_cons_state == NFS_CS_INITING) { 697 server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
1022 clp->rpc_ops = &nfs_v4_clientops; 698 if (IS_ERR(server)) {
699 error = PTR_ERR(server);
700 goto out_err_noserver;
701 }
1023 702
1024 err = nfs_create_rpc_client(clp, proto, timeo, retrans, flavor); 703 /* Get a superblock - note that we may end up sharing one that already exists */
1025 if (err < 0) 704 s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
1026 goto client_init_error; 705 if (IS_ERR(s)) {
706 error = PTR_ERR(s);
707 goto out_err_nosb;
708 }
1027 709
1028 memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); 710 if (s->s_fs_info != server) {
1029 err = nfs_idmap_new(clp); 711 nfs_free_server(server);
1030 if (err < 0) { 712 server = NULL;
1031 dprintk("%s: failed to create idmapper.\n",
1032 __FUNCTION__);
1033 goto client_init_error;
1034 }
1035 __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
1036 nfs_mark_client_ready(clp, 0);
1037 } 713 }
1038 714
1039 clnt = rpc_clone_client(clp->cl_rpcclient); 715 if (!s->s_root) {
716 /* initial superblock/root creation */
717 s->s_flags = flags;
718 nfs_clone_super(s, data->sb);
719 }
1040 720
1041 if (IS_ERR(clnt)) { 721 mntroot = nfs_get_root(s, data->fh);
1042 dprintk("%s: cannot create RPC client. Error = %d\n", 722 if (IS_ERR(mntroot)) {
1043 __FUNCTION__, err); 723 error = PTR_ERR(mntroot);
1044 return clnt; 724 goto error_splat_super;
1045 } 725 }
1046 726
1047 if (clnt->cl_auth->au_flavor != flavor) { 727 s->s_flags |= MS_ACTIVE;
1048 struct rpc_auth *auth; 728 mnt->mnt_sb = s;
729 mnt->mnt_root = mntroot;
1049 730
1050 auth = rpcauth_create(flavor, clnt); 731 dprintk("<-- nfs_xdev_get_sb() = 0\n");
1051 if (IS_ERR(auth)) { 732 return 0;
1052 dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
1053 return (struct rpc_clnt *)auth;
1054 }
1055 }
1056 733
1057 server->nfs_client = clp; 734out_err_nosb:
1058 down_write(&clp->cl_sem); 735 nfs_free_server(server);
1059 list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); 736out_err_noserver:
1060 up_write(&clp->cl_sem); 737 dprintk("<-- nfs_xdev_get_sb() = %d [error]\n", error);
1061 return clnt; 738 return error;
1062 739
1063client_init_error: 740error_splat_super:
1064 nfs_mark_client_ready(clp, err); 741 up_write(&s->s_umount);
1065 nfs_put_client(clp); 742 deactivate_super(s);
1066 return ERR_PTR(err); 743 dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error);
744 return error;
1067} 745}
1068 746
747#ifdef CONFIG_NFS_V4
748
1069/* 749/*
1070 * Set up an NFS4 superblock 750 * Finish setting up a cloned NFS4 superblock
1071 */ 751 */
1072static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent) 752static void nfs4_clone_super(struct super_block *sb,
753 const struct super_block *old_sb)
1073{ 754{
1074 struct nfs_server *server; 755 sb->s_blocksize_bits = old_sb->s_blocksize_bits;
1075 rpc_authflavor_t authflavour; 756 sb->s_blocksize = old_sb->s_blocksize;
1076 int err = -EIO; 757 sb->s_maxbytes = old_sb->s_maxbytes;
1077
1078 sb->s_blocksize_bits = 0;
1079 sb->s_blocksize = 0;
1080 server = NFS_SB(sb);
1081 if (data->rsize != 0)
1082 server->rsize = nfs_block_size(data->rsize, NULL);
1083 if (data->wsize != 0)
1084 server->wsize = nfs_block_size(data->wsize, NULL);
1085 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
1086 server->caps = NFS_CAP_ATOMIC_OPEN;
1087
1088 server->acregmin = data->acregmin*HZ;
1089 server->acregmax = data->acregmax*HZ;
1090 server->acdirmin = data->acdirmin*HZ;
1091 server->acdirmax = data->acdirmax*HZ;
1092
1093 /* Now create transport and client */
1094 authflavour = RPC_AUTH_UNIX;
1095 if (data->auth_flavourlen != 0) {
1096 if (data->auth_flavourlen != 1) {
1097 dprintk("%s: Invalid number of RPC auth flavours %d.\n",
1098 __FUNCTION__, data->auth_flavourlen);
1099 err = -EINVAL;
1100 goto out_fail;
1101 }
1102 if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) {
1103 err = -EFAULT;
1104 goto out_fail;
1105 }
1106 }
1107
1108 server->client = nfs4_create_client(server, data->timeo, data->retrans,
1109 data->proto, authflavour);
1110 if (IS_ERR(server->client)) {
1111 err = PTR_ERR(server->client);
1112 dprintk("%s: cannot create RPC client. Error = %d\n",
1113 __FUNCTION__, err);
1114 goto out_fail;
1115 }
1116
1117 sb->s_time_gran = 1; 758 sb->s_time_gran = 1;
1118 759 sb->s_op = old_sb->s_op;
1119 sb->s_op = &nfs4_sops; 760 nfs_initialise_sb(sb);
1120 err = nfs_sb_init(sb, authflavour);
1121
1122 out_fail:
1123 return err;
1124} 761}
1125 762
1126static int nfs4_compare_super(struct super_block *sb, void *data) 763/*
764 * Set up an NFS4 superblock
765 */
766static void nfs4_fill_super(struct super_block *sb)
1127{ 767{
1128 struct nfs_server *server = data; 768 sb->s_time_gran = 1;
1129 struct nfs_server *old = NFS_SB(sb); 769 sb->s_op = &nfs4_sops;
1130 770 nfs_initialise_sb(sb);
1131 if (strcmp(server->hostname, old->hostname) != 0)
1132 return 0;
1133 if (strcmp(server->mnt_path, old->mnt_path) != 0)
1134 return 0;
1135 return 1;
1136} 771}
1137 772
1138static void * 773static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
1139nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
1140{ 774{
1141 void *p = NULL; 775 void *p = NULL;
1142 776
@@ -1157,14 +791,22 @@ nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
1157 return dst; 791 return dst;
1158} 792}
1159 793
794/*
795 * Get the superblock for an NFS4 mountpoint
796 */
1160static int nfs4_get_sb(struct file_system_type *fs_type, 797static int nfs4_get_sb(struct file_system_type *fs_type,
1161 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) 798 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
1162{ 799{
1163 int error;
1164 struct nfs_server *server;
1165 struct super_block *s;
1166 struct nfs4_mount_data *data = raw_data; 800 struct nfs4_mount_data *data = raw_data;
801 struct super_block *s;
802 struct nfs_server *server;
803 struct sockaddr_in addr;
804 rpc_authflavor_t authflavour;
805 struct nfs_fh mntfh;
806 struct dentry *mntroot;
807 char *mntpath = NULL, *hostname = NULL, ip_addr[16];
1167 void *p; 808 void *p;
809 int error;
1168 810
1169 if (data == NULL) { 811 if (data == NULL) {
1170 dprintk("%s: missing data argument\n", __FUNCTION__); 812 dprintk("%s: missing data argument\n", __FUNCTION__);
@@ -1175,75 +817,107 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
1175 return -EINVAL; 817 return -EINVAL;
1176 } 818 }
1177 819
1178 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); 820 /* We now require that the mount process passes the remote address */
1179 if (!server) 821 if (data->host_addrlen != sizeof(addr))
1180 return -ENOMEM; 822 return -EINVAL;
1181 /* Zero out the NFS state stuff */ 823
1182 init_nfsv4_state(server); 824 if (copy_from_user(&addr, data->host_addr, sizeof(addr)))
1183 server->client = server->client_acl = ERR_PTR(-EINVAL); 825 return -EFAULT;
826
827 if (addr.sin_family != AF_INET ||
828 addr.sin_addr.s_addr == INADDR_ANY
829 ) {
830 dprintk("%s: mount program didn't pass remote IP address!\n",
831 __FUNCTION__);
832 return -EINVAL;
833 }
834
835 /* Grab the authentication type */
836 authflavour = RPC_AUTH_UNIX;
837 if (data->auth_flavourlen != 0) {
838 if (data->auth_flavourlen != 1) {
839 dprintk("%s: Invalid number of RPC auth flavours %d.\n",
840 __FUNCTION__, data->auth_flavourlen);
841 error = -EINVAL;
842 goto out_err_noserver;
843 }
844
845 if (copy_from_user(&authflavour, data->auth_flavours,
846 sizeof(authflavour))) {
847 error = -EFAULT;
848 goto out_err_noserver;
849 }
850 }
1184 851
1185 p = nfs_copy_user_string(NULL, &data->hostname, 256); 852 p = nfs_copy_user_string(NULL, &data->hostname, 256);
1186 if (IS_ERR(p)) 853 if (IS_ERR(p))
1187 goto out_err; 854 goto out_err;
1188 server->hostname = p; 855 hostname = p;
1189 856
1190 p = nfs_copy_user_string(NULL, &data->mnt_path, 1024); 857 p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
1191 if (IS_ERR(p)) 858 if (IS_ERR(p))
1192 goto out_err; 859 goto out_err;
1193 server->mnt_path = p; 860 mntpath = p;
1194 861
1195 p = nfs_copy_user_string(server->ip_addr, &data->client_addr, 862 dprintk("MNTPATH: %s\n", mntpath);
1196 sizeof(server->ip_addr) - 1); 863
864 p = nfs_copy_user_string(ip_addr, &data->client_addr,
865 sizeof(ip_addr) - 1);
1197 if (IS_ERR(p)) 866 if (IS_ERR(p))
1198 goto out_err; 867 goto out_err;
1199 868
1200 /* We now require that the mount process passes the remote address */ 869 /* Get a volume representation */
1201 if (data->host_addrlen != sizeof(server->addr)) { 870 server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
1202 error = -EINVAL; 871 authflavour, &mntfh);
1203 goto out_free; 872 if (IS_ERR(server)) {
1204 } 873 error = PTR_ERR(server);
1205 if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) { 874 goto out_err_noserver;
1206 error = -EFAULT;
1207 goto out_free;
1208 }
1209 if (server->addr.sin_family != AF_INET ||
1210 server->addr.sin_addr.s_addr == INADDR_ANY) {
1211 dprintk("%s: mount program didn't pass remote IP address!\n",
1212 __FUNCTION__);
1213 error = -EINVAL;
1214 goto out_free;
1215 } 875 }
1216 876
1217 s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); 877 /* Get a superblock - note that we may end up sharing one that already exists */
878 s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
1218 if (IS_ERR(s)) { 879 if (IS_ERR(s)) {
1219 error = PTR_ERR(s); 880 error = PTR_ERR(s);
1220 goto out_free; 881 goto out_free;
1221 } 882 }
1222 883
1223 if (s->s_root) { 884 if (!s->s_root) {
1224 kfree(server->mnt_path); 885 /* initial superblock/root creation */
1225 kfree(server->hostname); 886 s->s_flags = flags;
1226 kfree(server);
1227 return simple_set_mnt(mnt, s);
1228 }
1229 887
1230 s->s_flags = flags; 888 nfs4_fill_super(s);
889 } else {
890 nfs_free_server(server);
891 }
1231 892
1232 error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0); 893 mntroot = nfs4_get_root(s, &mntfh);
1233 if (error) { 894 if (IS_ERR(mntroot)) {
1234 up_write(&s->s_umount); 895 error = PTR_ERR(mntroot);
1235 deactivate_super(s); 896 goto error_splat_super;
1236 return error;
1237 } 897 }
898
1238 s->s_flags |= MS_ACTIVE; 899 s->s_flags |= MS_ACTIVE;
1239 return simple_set_mnt(mnt, s); 900 mnt->mnt_sb = s;
901 mnt->mnt_root = mntroot;
902 kfree(mntpath);
903 kfree(hostname);
904 return 0;
905
1240out_err: 906out_err:
1241 error = PTR_ERR(p); 907 error = PTR_ERR(p);
908 goto out_err_noserver;
909
1242out_free: 910out_free:
1243 kfree(server->mnt_path); 911 nfs_free_server(server);
1244 kfree(server->hostname); 912out_err_noserver:
1245 kfree(server); 913 kfree(mntpath);
914 kfree(hostname);
1246 return error; 915 return error;
916
917error_splat_super:
918 up_write(&s->s_umount);
919 deactivate_super(s);
920 goto out_err_noserver;
1247} 921}
1248 922
1249static void nfs4_kill_super(struct super_block *sb) 923static void nfs4_kill_super(struct super_block *sb)
@@ -1254,133 +928,140 @@ static void nfs4_kill_super(struct super_block *sb)
1254 kill_anon_super(sb); 928 kill_anon_super(sb);
1255 929
1256 nfs4_renewd_prepare_shutdown(server); 930 nfs4_renewd_prepare_shutdown(server);
1257 931 nfs_free_server(server);
1258 if (server->client != NULL && !IS_ERR(server->client))
1259 rpc_shutdown_client(server->client);
1260
1261 destroy_nfsv4_state(server);
1262
1263 nfs_free_iostats(server->io_stats);
1264 kfree(server->hostname);
1265 kfree(server);
1266 nfs_release_automount_timer();
1267} 932}
1268 933
1269/* 934/*
1270 * Constructs the SERVER-side path 935 * Clone an NFS4 server record on xdev traversal (FSID-change)
1271 */ 936 */
1272static inline char *nfs4_dup_path(const struct dentry *dentry) 937static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
938 const char *dev_name, void *raw_data,
939 struct vfsmount *mnt)
1273{ 940{
1274 char *page = (char *) __get_free_page(GFP_USER); 941 struct nfs_clone_mount *data = raw_data;
1275 char *path; 942 struct super_block *s;
943 struct nfs_server *server;
944 struct dentry *mntroot;
945 int error;
1276 946
1277 path = nfs4_path(dentry, page, PAGE_SIZE); 947 dprintk("--> nfs4_xdev_get_sb()\n");
1278 if (!IS_ERR(path)) {
1279 int len = PAGE_SIZE + page - path;
1280 char *tmp = path;
1281 948
1282 path = kmalloc(len, GFP_KERNEL); 949 /* create a new volume representation */
1283 if (path) 950 server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
1284 memcpy(path, tmp, len); 951 if (IS_ERR(server)) {
1285 else 952 error = PTR_ERR(server);
1286 path = ERR_PTR(-ENOMEM); 953 goto out_err_noserver;
1287 } 954 }
1288 free_page((unsigned long)page);
1289 return path;
1290}
1291 955
1292static struct super_block *nfs4_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data) 956 /* Get a superblock - note that we may end up sharing one that already exists */
1293{ 957 s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
1294 const struct dentry *dentry = data->dentry; 958 if (IS_ERR(s)) {
1295 struct nfs_client *clp = server->nfs_client; 959 error = PTR_ERR(s);
1296 struct super_block *sb; 960 goto out_err_nosb;
1297
1298 server->fsid = data->fattr->fsid;
1299 nfs_copy_fh(&server->fh, data->fh);
1300 server->mnt_path = nfs4_dup_path(dentry);
1301 if (IS_ERR(server->mnt_path)) {
1302 sb = (struct super_block *)server->mnt_path;
1303 goto err;
1304 } 961 }
1305 sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
1306 if (IS_ERR(sb) || sb->s_root)
1307 goto free_path;
1308 nfs4_server_capabilities(server, &server->fh);
1309
1310 down_write(&clp->cl_sem);
1311 list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
1312 up_write(&clp->cl_sem);
1313 return sb;
1314free_path:
1315 kfree(server->mnt_path);
1316err:
1317 server->mnt_path = NULL;
1318 return sb;
1319}
1320 962
1321static int nfs_clone_nfs4_sb(struct file_system_type *fs_type, 963 if (s->s_fs_info != server) {
1322 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) 964 nfs_free_server(server);
1323{ 965 server = NULL;
1324 struct nfs_clone_mount *data = raw_data; 966 }
1325 return nfs_clone_generic_sb(data, nfs4_clone_sb, nfs_clone_server, mnt);
1326}
1327 967
1328static struct super_block *nfs4_referral_sb(struct nfs_server *server, struct nfs_clone_mount *data) 968 if (!s->s_root) {
1329{ 969 /* initial superblock/root creation */
1330 struct super_block *sb = ERR_PTR(-ENOMEM); 970 s->s_flags = flags;
1331 int len; 971 nfs4_clone_super(s, data->sb);
1332 972 }
1333 len = strlen(data->mnt_path) + 1;
1334 server->mnt_path = kmalloc(len, GFP_KERNEL);
1335 if (server->mnt_path == NULL)
1336 goto err;
1337 memcpy(server->mnt_path, data->mnt_path, len);
1338 memcpy(&server->addr, data->addr, sizeof(struct sockaddr_in));
1339
1340 sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
1341 if (IS_ERR(sb) || sb->s_root)
1342 goto free_path;
1343 return sb;
1344free_path:
1345 kfree(server->mnt_path);
1346err:
1347 server->mnt_path = NULL;
1348 return sb;
1349}
1350 973
1351static struct nfs_server *nfs4_referral_server(struct super_block *sb, struct nfs_clone_mount *data) 974 mntroot = nfs4_get_root(s, data->fh);
1352{ 975 if (IS_ERR(mntroot)) {
1353 struct nfs_server *server = NFS_SB(sb); 976 error = PTR_ERR(mntroot);
1354 int proto, timeo, retrans; 977 goto error_splat_super;
1355 void *err; 978 }
1356
1357 proto = IPPROTO_TCP;
1358 /* Since we are following a referral and there may be alternatives,
1359 set the timeouts and retries to low values */
1360 timeo = 2;
1361 retrans = 1;
1362
1363 nfs_put_client(server->nfs_client);
1364 server->nfs_client = NULL;
1365 server->client = nfs4_create_client(server, timeo, retrans, proto,
1366 data->authflavor);
1367 if (IS_ERR((err = server->client)))
1368 goto out_err;
1369 979
1370 sb->s_time_gran = 1; 980 s->s_flags |= MS_ACTIVE;
1371 sb->s_op = &nfs4_sops; 981 mnt->mnt_sb = s;
1372 err = ERR_PTR(nfs_sb_init(sb, data->authflavor)); 982 mnt->mnt_root = mntroot;
1373 if (!IS_ERR(err)) 983
1374 return server; 984 dprintk("<-- nfs4_xdev_get_sb() = 0\n");
1375out_err: 985 return 0;
1376 return (struct nfs_server *)err; 986
987out_err_nosb:
988 nfs_free_server(server);
989out_err_noserver:
990 dprintk("<-- nfs4_xdev_get_sb() = %d [error]\n", error);
991 return error;
992
993error_splat_super:
994 up_write(&s->s_umount);
995 deactivate_super(s);
996 dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error);
997 return error;
1377} 998}
1378 999
1379static int nfs_referral_nfs4_sb(struct file_system_type *fs_type, 1000/*
1380 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) 1001 * Create an NFS4 server record on referral traversal
1002 */
1003static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
1004 const char *dev_name, void *raw_data,
1005 struct vfsmount *mnt)
1381{ 1006{
1382 struct nfs_clone_mount *data = raw_data; 1007 struct nfs_clone_mount *data = raw_data;
1383 return nfs_clone_generic_sb(data, nfs4_referral_sb, nfs4_referral_server, mnt); 1008 struct super_block *s;
1009 struct nfs_server *server;
1010 struct dentry *mntroot;
1011 struct nfs_fh mntfh;
1012 int error;
1013
1014 dprintk("--> nfs4_referral_get_sb()\n");
1015
1016 /* create a new volume representation */
1017 server = nfs4_create_referral_server(data, &mntfh);
1018 if (IS_ERR(server)) {
1019 error = PTR_ERR(server);
1020 goto out_err_noserver;
1021 }
1022
1023 /* Get a superblock - note that we may end up sharing one that already exists */
1024 s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
1025 if (IS_ERR(s)) {
1026 error = PTR_ERR(s);
1027 goto out_err_nosb;
1028 }
1029
1030 if (s->s_fs_info != server) {
1031 nfs_free_server(server);
1032 server = NULL;
1033 }
1034
1035 if (!s->s_root) {
1036 /* initial superblock/root creation */
1037 s->s_flags = flags;
1038 nfs4_fill_super(s);
1039 }
1040
1041 mntroot = nfs4_get_root(s, data->fh);
1042 if (IS_ERR(mntroot)) {
1043 error = PTR_ERR(mntroot);
1044 goto error_splat_super;
1045 }
1046
1047 s->s_flags |= MS_ACTIVE;
1048 mnt->mnt_sb = s;
1049 mnt->mnt_root = mntroot;
1050
1051 dprintk("<-- nfs4_referral_get_sb() = 0\n");
1052 return 0;
1053
1054out_err_nosb:
1055 nfs_free_server(server);
1056out_err_noserver:
1057 dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error);
1058 return error;
1059
1060error_splat_super:
1061 up_write(&s->s_umount);
1062 deactivate_super(s);
1063 dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error);
1064 return error;
1384} 1065}
1385 1066
1386#endif 1067#endif /* CONFIG_NFS_V4 */
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 7084ac9a6455..453d44666ea5 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1273,7 +1273,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
1273 if (time_before(complain, jiffies)) { 1273 if (time_before(complain, jiffies)) {
1274 dprintk("NFS: faulty NFS server %s:" 1274 dprintk("NFS: faulty NFS server %s:"
1275 " (committed = %d) != (stable = %d)\n", 1275 " (committed = %d) != (stable = %d)\n",
1276 NFS_SERVER(data->inode)->hostname, 1276 NFS_SERVER(data->inode)->nfs_client->cl_hostname,
1277 resp->verf->committed, argp->stable); 1277 resp->verf->committed, argp->stable);
1278 complain = jiffies + 300 * HZ; 1278 complain = jiffies + 300 * HZ;
1279 } 1279 }
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index d404ceca9168..6d0be0efd1b5 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -51,7 +51,6 @@ struct nfs_client {
51 unsigned long cl_lease_time; 51 unsigned long cl_lease_time;
52 unsigned long cl_last_renewal; 52 unsigned long cl_last_renewal;
53 struct work_struct cl_renewd; 53 struct work_struct cl_renewd;
54 struct work_struct cl_recoverd;
55 54
56 struct rpc_wait_queue cl_rpcwaitq; 55 struct rpc_wait_queue cl_rpcwaitq;
57 56
@@ -74,6 +73,10 @@ struct nfs_client {
74 */ 73 */
75struct nfs_server { 74struct nfs_server {
76 struct nfs_client * nfs_client; /* shared client and NFS4 state */ 75 struct nfs_client * nfs_client; /* shared client and NFS4 state */
76 struct list_head client_link; /* List of other nfs_server structs
77 * that share the same client
78 */
79 struct list_head master_link; /* link in master servers list */
77 struct rpc_clnt * client; /* RPC client handle */ 80 struct rpc_clnt * client; /* RPC client handle */
78 struct rpc_clnt * client_acl; /* ACL RPC client handle */ 81 struct rpc_clnt * client_acl; /* ACL RPC client handle */
79 struct nfs_iostats * io_stats; /* I/O statistics */ 82 struct nfs_iostats * io_stats; /* I/O statistics */
@@ -92,20 +95,13 @@ struct nfs_server {
92 unsigned int acdirmin; 95 unsigned int acdirmin;
93 unsigned int acdirmax; 96 unsigned int acdirmax;
94 unsigned int namelen; 97 unsigned int namelen;
95 char * hostname; /* remote hostname */ 98
96 struct nfs_fh fh;
97 struct sockaddr_in addr;
98 struct nfs_fsid fsid; 99 struct nfs_fsid fsid;
100 __u64 maxfilesize; /* maximum file size */
99 unsigned long mount_time; /* when this fs was mounted */ 101 unsigned long mount_time; /* when this fs was mounted */
102 dev_t s_dev; /* superblock dev numbers */
103
100#ifdef CONFIG_NFS_V4 104#ifdef CONFIG_NFS_V4
101 /* Our own IP address, as a null-terminated string.
102 * This is used to generate the clientid, and the callback address.
103 */
104 char ip_addr[16];
105 char * mnt_path;
106 struct list_head nfs4_siblings; /* List of other nfs_server structs
107 * that share the same clientid
108 */
109 u32 attr_bitmask[2];/* V4 bitmask representing the set 105 u32 attr_bitmask[2];/* V4 bitmask representing the set
110 of attributes supported on this 106 of attributes supported on this
111 filesystem */ 107 filesystem */
@@ -113,6 +109,7 @@ struct nfs_server {
113 that are supported on this 109 that are supported on this
114 filesystem */ 110 filesystem */
115#endif 111#endif
112 void (*destroy)(struct nfs_server *);
116}; 113};
117 114
118/* Server capabilities */ 115/* Server capabilities */