diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-10-01 18:42:14 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-10-01 18:42:14 -0400 |
commit | 2afdfa5a846246de50e1881f71ba5c0aac0b415f (patch) | |
tree | ec9feec128aa105cabb1122806a8078a39be4ebb /fs | |
parent | 7297cb682acb506ada2e01fbc9b447b04d69936c (diff) | |
parent | 0cac120233305b614cfe3ad419f3655876066017 (diff) |
Merge branch 'bugfixes' into nfs-for-next
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/idmap.c | 104 |
1 files changed, 70 insertions, 34 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 27dde503a6b..675b389cba5 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -55,18 +55,19 @@ | |||
55 | static const struct cred *id_resolver_cache; | 55 | static const struct cred *id_resolver_cache; |
56 | static struct key_type key_type_id_resolver_legacy; | 56 | static struct key_type key_type_id_resolver_legacy; |
57 | 57 | ||
58 | struct idmap { | ||
59 | struct rpc_pipe *idmap_pipe; | ||
60 | struct key_construction *idmap_key_cons; | ||
61 | struct mutex idmap_mutex; | ||
62 | }; | ||
63 | |||
64 | struct idmap_legacy_upcalldata { | 58 | struct idmap_legacy_upcalldata { |
65 | struct rpc_pipe_msg pipe_msg; | 59 | struct rpc_pipe_msg pipe_msg; |
66 | struct idmap_msg idmap_msg; | 60 | struct idmap_msg idmap_msg; |
61 | struct key_construction *key_cons; | ||
67 | struct idmap *idmap; | 62 | struct idmap *idmap; |
68 | }; | 63 | }; |
69 | 64 | ||
65 | struct idmap { | ||
66 | struct rpc_pipe *idmap_pipe; | ||
67 | struct idmap_legacy_upcalldata *idmap_upcall_data; | ||
68 | struct mutex idmap_mutex; | ||
69 | }; | ||
70 | |||
70 | /** | 71 | /** |
71 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields | 72 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields |
72 | * @fattr: fully initialised struct nfs_fattr | 73 | * @fattr: fully initialised struct nfs_fattr |
@@ -330,7 +331,6 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, | |||
330 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, | 331 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, |
331 | name, namelen, type, data, | 332 | name, namelen, type, data, |
332 | data_size, idmap); | 333 | data_size, idmap); |
333 | idmap->idmap_key_cons = NULL; | ||
334 | mutex_unlock(&idmap->idmap_mutex); | 334 | mutex_unlock(&idmap->idmap_mutex); |
335 | } | 335 | } |
336 | return ret; | 336 | return ret; |
@@ -465,8 +465,6 @@ nfs_idmap_new(struct nfs_client *clp) | |||
465 | struct rpc_pipe *pipe; | 465 | struct rpc_pipe *pipe; |
466 | int error; | 466 | int error; |
467 | 467 | ||
468 | BUG_ON(clp->cl_idmap != NULL); | ||
469 | |||
470 | idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); | 468 | idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); |
471 | if (idmap == NULL) | 469 | if (idmap == NULL) |
472 | return -ENOMEM; | 470 | return -ENOMEM; |
@@ -510,7 +508,6 @@ static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, | |||
510 | 508 | ||
511 | switch (event) { | 509 | switch (event) { |
512 | case RPC_PIPEFS_MOUNT: | 510 | case RPC_PIPEFS_MOUNT: |
513 | BUG_ON(clp->cl_rpcclient->cl_dentry == NULL); | ||
514 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, | 511 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, |
515 | clp->cl_idmap, | 512 | clp->cl_idmap, |
516 | clp->cl_idmap->idmap_pipe); | 513 | clp->cl_idmap->idmap_pipe); |
@@ -662,6 +659,35 @@ out: | |||
662 | return ret; | 659 | return ret; |
663 | } | 660 | } |
664 | 661 | ||
662 | static bool | ||
663 | nfs_idmap_prepare_pipe_upcall(struct idmap *idmap, | ||
664 | struct idmap_legacy_upcalldata *data) | ||
665 | { | ||
666 | if (idmap->idmap_upcall_data != NULL) { | ||
667 | WARN_ON_ONCE(1); | ||
668 | return false; | ||
669 | } | ||
670 | idmap->idmap_upcall_data = data; | ||
671 | return true; | ||
672 | } | ||
673 | |||
674 | static void | ||
675 | nfs_idmap_complete_pipe_upcall_locked(struct idmap *idmap, int ret) | ||
676 | { | ||
677 | struct key_construction *cons = idmap->idmap_upcall_data->key_cons; | ||
678 | |||
679 | kfree(idmap->idmap_upcall_data); | ||
680 | idmap->idmap_upcall_data = NULL; | ||
681 | complete_request_key(cons, ret); | ||
682 | } | ||
683 | |||
684 | static void | ||
685 | nfs_idmap_abort_pipe_upcall(struct idmap *idmap, int ret) | ||
686 | { | ||
687 | if (idmap->idmap_upcall_data != NULL) | ||
688 | nfs_idmap_complete_pipe_upcall_locked(idmap, ret); | ||
689 | } | ||
690 | |||
665 | static int nfs_idmap_legacy_upcall(struct key_construction *cons, | 691 | static int nfs_idmap_legacy_upcall(struct key_construction *cons, |
666 | const char *op, | 692 | const char *op, |
667 | void *aux) | 693 | void *aux) |
@@ -686,17 +712,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, | |||
686 | if (ret < 0) | 712 | if (ret < 0) |
687 | goto out2; | 713 | goto out2; |
688 | 714 | ||
689 | BUG_ON(idmap->idmap_key_cons != NULL); | 715 | ret = -EAGAIN; |
690 | idmap->idmap_key_cons = cons; | 716 | if (!nfs_idmap_prepare_pipe_upcall(idmap, data)) |
717 | goto out2; | ||
691 | 718 | ||
692 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); | 719 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); |
693 | if (ret < 0) | 720 | if (ret < 0) |
694 | goto out3; | 721 | nfs_idmap_abort_pipe_upcall(idmap, ret); |
695 | 722 | ||
696 | return ret; | 723 | return ret; |
697 | |||
698 | out3: | ||
699 | idmap->idmap_key_cons = NULL; | ||
700 | out2: | 724 | out2: |
701 | kfree(data); | 725 | kfree(data); |
702 | out1: | 726 | out1: |
@@ -711,21 +735,32 @@ static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *dat | |||
711 | authkey); | 735 | authkey); |
712 | } | 736 | } |
713 | 737 | ||
714 | static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey) | 738 | static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, |
739 | struct idmap_msg *upcall, | ||
740 | struct key *key, struct key *authkey) | ||
715 | { | 741 | { |
716 | char id_str[NFS_UINT_MAXLEN]; | 742 | char id_str[NFS_UINT_MAXLEN]; |
717 | int ret = -EINVAL; | 743 | int ret = -ENOKEY; |
718 | 744 | ||
745 | /* ret = -ENOKEY */ | ||
746 | if (upcall->im_type != im->im_type || upcall->im_conv != im->im_conv) | ||
747 | goto out; | ||
719 | switch (im->im_conv) { | 748 | switch (im->im_conv) { |
720 | case IDMAP_CONV_NAMETOID: | 749 | case IDMAP_CONV_NAMETOID: |
750 | if (strcmp(upcall->im_name, im->im_name) != 0) | ||
751 | break; | ||
721 | sprintf(id_str, "%d", im->im_id); | 752 | sprintf(id_str, "%d", im->im_id); |
722 | ret = nfs_idmap_instantiate(key, authkey, id_str); | 753 | ret = nfs_idmap_instantiate(key, authkey, id_str); |
723 | break; | 754 | break; |
724 | case IDMAP_CONV_IDTONAME: | 755 | case IDMAP_CONV_IDTONAME: |
756 | if (upcall->im_id != im->im_id) | ||
757 | break; | ||
725 | ret = nfs_idmap_instantiate(key, authkey, im->im_name); | 758 | ret = nfs_idmap_instantiate(key, authkey, im->im_name); |
726 | break; | 759 | break; |
760 | default: | ||
761 | ret = -EINVAL; | ||
727 | } | 762 | } |
728 | 763 | out: | |
729 | return ret; | 764 | return ret; |
730 | } | 765 | } |
731 | 766 | ||
@@ -737,14 +772,16 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
737 | struct key_construction *cons; | 772 | struct key_construction *cons; |
738 | struct idmap_msg im; | 773 | struct idmap_msg im; |
739 | size_t namelen_in; | 774 | size_t namelen_in; |
740 | int ret; | 775 | int ret = -ENOKEY; |
741 | 776 | ||
742 | /* If instantiation is successful, anyone waiting for key construction | 777 | /* If instantiation is successful, anyone waiting for key construction |
743 | * will have been woken up and someone else may now have used | 778 | * will have been woken up and someone else may now have used |
744 | * idmap_key_cons - so after this point we may no longer touch it. | 779 | * idmap_key_cons - so after this point we may no longer touch it. |
745 | */ | 780 | */ |
746 | cons = ACCESS_ONCE(idmap->idmap_key_cons); | 781 | if (idmap->idmap_upcall_data == NULL) |
747 | idmap->idmap_key_cons = NULL; | 782 | goto out_noupcall; |
783 | |||
784 | cons = idmap->idmap_upcall_data->key_cons; | ||
748 | 785 | ||
749 | if (mlen != sizeof(im)) { | 786 | if (mlen != sizeof(im)) { |
750 | ret = -ENOSPC; | 787 | ret = -ENOSPC; |
@@ -765,16 +802,19 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
765 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) { | 802 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) { |
766 | ret = -EINVAL; | 803 | ret = -EINVAL; |
767 | goto out; | 804 | goto out; |
768 | } | 805 | } |
769 | 806 | ||
770 | ret = nfs_idmap_read_message(&im, cons->key, cons->authkey); | 807 | ret = nfs_idmap_read_and_verify_message(&im, |
808 | &idmap->idmap_upcall_data->idmap_msg, | ||
809 | cons->key, cons->authkey); | ||
771 | if (ret >= 0) { | 810 | if (ret >= 0) { |
772 | key_set_timeout(cons->key, nfs_idmap_cache_timeout); | 811 | key_set_timeout(cons->key, nfs_idmap_cache_timeout); |
773 | ret = mlen; | 812 | ret = mlen; |
774 | } | 813 | } |
775 | 814 | ||
776 | out: | 815 | out: |
777 | complete_request_key(cons, ret); | 816 | nfs_idmap_complete_pipe_upcall_locked(idmap, ret); |
817 | out_noupcall: | ||
778 | return ret; | 818 | return ret; |
779 | } | 819 | } |
780 | 820 | ||
@@ -785,14 +825,9 @@ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) | |||
785 | struct idmap_legacy_upcalldata, | 825 | struct idmap_legacy_upcalldata, |
786 | pipe_msg); | 826 | pipe_msg); |
787 | struct idmap *idmap = data->idmap; | 827 | struct idmap *idmap = data->idmap; |
788 | struct key_construction *cons; | 828 | |
789 | if (msg->errno) { | 829 | if (msg->errno) |
790 | cons = ACCESS_ONCE(idmap->idmap_key_cons); | 830 | nfs_idmap_abort_pipe_upcall(idmap, msg->errno); |
791 | idmap->idmap_key_cons = NULL; | ||
792 | complete_request_key(cons, msg->errno); | ||
793 | } | ||
794 | /* Free memory allocated in nfs_idmap_legacy_upcall() */ | ||
795 | kfree(data); | ||
796 | } | 831 | } |
797 | 832 | ||
798 | static void | 833 | static void |
@@ -800,7 +835,8 @@ idmap_release_pipe(struct inode *inode) | |||
800 | { | 835 | { |
801 | struct rpc_inode *rpci = RPC_I(inode); | 836 | struct rpc_inode *rpci = RPC_I(inode); |
802 | struct idmap *idmap = (struct idmap *)rpci->private; | 837 | struct idmap *idmap = (struct idmap *)rpci->private; |
803 | idmap->idmap_key_cons = NULL; | 838 | |
839 | nfs_idmap_abort_pipe_upcall(idmap, -EPIPE); | ||
804 | } | 840 | } |
805 | 841 | ||
806 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 842 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) |