diff options
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 735 |
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 | ||
49 | static DEFINE_SPINLOCK(nfs_client_lock); | 49 | static DEFINE_SPINLOCK(nfs_client_lock); |
50 | static LIST_HEAD(nfs_client_list); | 50 | static LIST_HEAD(nfs_client_list); |
51 | static LIST_HEAD(nfs_volume_list); | ||
51 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | 52 | static 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 | */ |
271 | struct nfs_client *nfs_get_client(const char *hostname, | 272 | static 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 | */ |
350 | void nfs_mark_client_ready(struct nfs_client *clp, int state) | 353 | static 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 | */ |
392 | int nfs_create_rpc_client(struct nfs_client *clp, int proto, | 395 | static 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 | */ | ||
439 | static 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 | */ | ||
451 | static 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; | ||
464 | out: | ||
465 | return error; | ||
466 | } | ||
467 | |||
468 | /* | ||
469 | * Initialise an NFSv3 ACL client connection | ||
470 | */ | ||
471 | #ifdef CONFIG_NFS_V3_ACL | ||
472 | static 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 | |||
487 | out_noacl: | ||
488 | server->caps &= ~NFS_CAP_ACLS; | ||
489 | } | ||
490 | #else | ||
491 | static 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 | */ | ||
501 | static 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 | */ | ||
534 | static 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 | |||
562 | error: | ||
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 | */ | ||
571 | static 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 | |||
633 | error: | ||
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 | */ | ||
643 | static 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 | */ | ||
693 | static 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 | |||
729 | out_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 | */ | ||
737 | static 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 | */ | ||
750 | static 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 | */ | ||
776 | void 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 | */ | ||
802 | struct 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 | |||
849 | error: | ||
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 | */ | ||
858 | static 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 | |||
888 | error: | ||
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 | */ | ||
897 | static 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 | |||
921 | error_put: | ||
922 | nfs_put_client(clp); | ||
923 | error: | ||
924 | dprintk("<-- nfs4_set_client() = xerror %d\n", error); | ||
925 | return error; | ||
926 | } | ||
927 | |||
928 | /* | ||
929 | * Create a version 4 volume record | ||
930 | */ | ||
931 | static 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 | */ | ||
963 | struct 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 | |||
1021 | error: | ||
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 | */ | ||
1030 | struct 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 | |||
1085 | error: | ||
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 | */ | ||
1096 | struct 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 | |||
1146 | out_free_server: | ||
1147 | nfs_free_server(server); | ||
1148 | dprintk("<-- nfs_clone_server() = error %d\n", error); | ||
1149 | return ERR_PTR(error); | ||
1150 | } | ||