aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/client.c
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 /fs/nfs/client.c
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>
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r--fs/nfs/client.c735
1 files changed, 727 insertions, 8 deletions
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}