summaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4recover.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-09-27 20:00:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-27 20:00:27 -0400
commit298fb76a5583900a155d387efaf37a8b39e5dea2 (patch)
tree55b903ec587e8ec470c13084938303f542139557 /fs/nfsd/nfs4recover.c
parent8f744bdee4fefb17fac052c7418b830de2b59ac8 (diff)
parente41f9efb85d38d95744b9f35b9903109032b93d4 (diff)
Merge tag 'nfsd-5.4' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields: "Highlights: - Add a new knfsd file cache, so that we don't have to open and close on each (NFSv2/v3) READ or WRITE. This can speed up read and write in some cases. It also replaces our readahead cache. - Prevent silent data loss on write errors, by treating write errors like server reboots for the purposes of write caching, thus forcing clients to resend their writes. - Tweak the code that allocates sessions to be more forgiving, so that NFSv4.1 mounts are less likely to hang when a server already has a lot of clients. - Eliminate an arbitrary limit on NFSv4 ACL sizes; they should now be limited only by the backend filesystem and the maximum RPC size. - Allow the server to enforce use of the correct kerberos credentials when a client reclaims state after a reboot. And some miscellaneous smaller bugfixes and cleanup" * tag 'nfsd-5.4' of git://linux-nfs.org/~bfields/linux: (34 commits) sunrpc: clean up indentation issue nfsd: fix nfs read eof detection nfsd: Make nfsd_reset_boot_verifier_locked static nfsd: degraded slot-count more gracefully as allocation nears exhaustion. nfsd: handle drc over-allocation gracefully. nfsd: add support for upcall version 2 nfsd: add a "GetVersion" upcall for nfsdcld nfsd: Reset the boot verifier on all write I/O errors nfsd: Don't garbage collect files that might contain write errors nfsd: Support the server resetting the boot verifier nfsd: nfsd_file cache entries should be per net namespace nfsd: eliminate an unnecessary acl size limit Deprecate nfsd fault injection nfsd: remove duplicated include from filecache.c nfsd: Fix the documentation for svcxdr_tmpalloc() nfsd: Fix up some unused variable warnings nfsd: close cached files prior to a REMOVE or RENAME that would replace target nfsd: rip out the raparms cache nfsd: have nfsd_test_lock use the nfsd_file cache nfsd: hook up nfs4_preprocess_stateid_op to the nfsd_file cache ...
Diffstat (limited to 'fs/nfsd/nfs4recover.c')
-rw-r--r--fs/nfsd/nfs4recover.c388
1 files changed, 325 insertions, 63 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 87679557d0d6..cdc75ad4438b 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -59,8 +59,13 @@ struct nfsd4_client_tracking_ops {
59 void (*remove)(struct nfs4_client *); 59 void (*remove)(struct nfs4_client *);
60 int (*check)(struct nfs4_client *); 60 int (*check)(struct nfs4_client *);
61 void (*grace_done)(struct nfsd_net *); 61 void (*grace_done)(struct nfsd_net *);
62 uint8_t version;
63 size_t msglen;
62}; 64};
63 65
66static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops;
67static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2;
68
64/* Globals */ 69/* Globals */
65static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; 70static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
66 71
@@ -173,6 +178,7 @@ __nfsd4_create_reclaim_record_grace(struct nfs4_client *clp,
173 const char *dname, int len, struct nfsd_net *nn) 178 const char *dname, int len, struct nfsd_net *nn)
174{ 179{
175 struct xdr_netobj name; 180 struct xdr_netobj name;
181 struct xdr_netobj princhash = { .len = 0, .data = NULL };
176 struct nfs4_client_reclaim *crp; 182 struct nfs4_client_reclaim *crp;
177 183
178 name.data = kmemdup(dname, len, GFP_KERNEL); 184 name.data = kmemdup(dname, len, GFP_KERNEL);
@@ -182,7 +188,7 @@ __nfsd4_create_reclaim_record_grace(struct nfs4_client *clp,
182 return; 188 return;
183 } 189 }
184 name.len = len; 190 name.len = len;
185 crp = nfs4_client_to_reclaim(name, nn); 191 crp = nfs4_client_to_reclaim(name, princhash, nn);
186 if (!crp) { 192 if (!crp) {
187 kfree(name.data); 193 kfree(name.data);
188 return; 194 return;
@@ -482,6 +488,7 @@ static int
482load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) 488load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
483{ 489{
484 struct xdr_netobj name; 490 struct xdr_netobj name;
491 struct xdr_netobj princhash = { .len = 0, .data = NULL };
485 492
486 if (child->d_name.len != HEXDIR_LEN - 1) { 493 if (child->d_name.len != HEXDIR_LEN - 1) {
487 printk("%s: illegal name %pd in recovery directory\n", 494 printk("%s: illegal name %pd in recovery directory\n",
@@ -496,7 +503,7 @@ load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
496 goto out; 503 goto out;
497 } 504 }
498 name.len = HEXDIR_LEN; 505 name.len = HEXDIR_LEN;
499 if (!nfs4_client_to_reclaim(name, nn)) 506 if (!nfs4_client_to_reclaim(name, princhash, nn))
500 kfree(name.data); 507 kfree(name.data);
501out: 508out:
502 return 0; 509 return 0;
@@ -718,6 +725,8 @@ static const struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
718 .remove = nfsd4_remove_clid_dir, 725 .remove = nfsd4_remove_clid_dir,
719 .check = nfsd4_check_legacy_client, 726 .check = nfsd4_check_legacy_client,
720 .grace_done = nfsd4_recdir_purge_old, 727 .grace_done = nfsd4_recdir_purge_old,
728 .version = 1,
729 .msglen = 0,
721}; 730};
722 731
723/* Globals */ 732/* Globals */
@@ -731,25 +740,32 @@ struct cld_net {
731 struct list_head cn_list; 740 struct list_head cn_list;
732 unsigned int cn_xid; 741 unsigned int cn_xid;
733 bool cn_has_legacy; 742 bool cn_has_legacy;
743 struct crypto_shash *cn_tfm;
734}; 744};
735 745
736struct cld_upcall { 746struct cld_upcall {
737 struct list_head cu_list; 747 struct list_head cu_list;
738 struct cld_net *cu_net; 748 struct cld_net *cu_net;
739 struct completion cu_done; 749 struct completion cu_done;
740 struct cld_msg cu_msg; 750 union {
751 struct cld_msg_hdr cu_hdr;
752 struct cld_msg cu_msg;
753 struct cld_msg_v2 cu_msg_v2;
754 } cu_u;
741}; 755};
742 756
743static int 757static int
744__cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) 758__cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg)
745{ 759{
746 int ret; 760 int ret;
747 struct rpc_pipe_msg msg; 761 struct rpc_pipe_msg msg;
748 struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_msg); 762 struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_u);
763 struct nfsd_net *nn = net_generic(pipe->dentry->d_sb->s_fs_info,
764 nfsd_net_id);
749 765
750 memset(&msg, 0, sizeof(msg)); 766 memset(&msg, 0, sizeof(msg));
751 msg.data = cmsg; 767 msg.data = cmsg;
752 msg.len = sizeof(*cmsg); 768 msg.len = nn->client_tracking_ops->msglen;
753 769
754 ret = rpc_queue_upcall(pipe, &msg); 770 ret = rpc_queue_upcall(pipe, &msg);
755 if (ret < 0) { 771 if (ret < 0) {
@@ -765,7 +781,7 @@ out:
765} 781}
766 782
767static int 783static int
768cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) 784cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg)
769{ 785{
770 int ret; 786 int ret;
771 787
@@ -781,11 +797,11 @@ cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
781} 797}
782 798
783static ssize_t 799static ssize_t
784__cld_pipe_inprogress_downcall(const struct cld_msg __user *cmsg, 800__cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
785 struct nfsd_net *nn) 801 struct nfsd_net *nn)
786{ 802{
787 uint8_t cmd; 803 uint8_t cmd, princhashlen;
788 struct xdr_netobj name; 804 struct xdr_netobj name, princhash = { .len = 0, .data = NULL };
789 uint16_t namelen; 805 uint16_t namelen;
790 struct cld_net *cn = nn->cld_net; 806 struct cld_net *cn = nn->cld_net;
791 807
@@ -794,22 +810,48 @@ __cld_pipe_inprogress_downcall(const struct cld_msg __user *cmsg,
794 return -EFAULT; 810 return -EFAULT;
795 } 811 }
796 if (cmd == Cld_GraceStart) { 812 if (cmd == Cld_GraceStart) {
797 if (get_user(namelen, &cmsg->cm_u.cm_name.cn_len)) 813 if (nn->client_tracking_ops->version >= 2) {
798 return -EFAULT; 814 const struct cld_clntinfo __user *ci;
799 name.data = memdup_user(&cmsg->cm_u.cm_name.cn_id, namelen); 815
800 if (IS_ERR_OR_NULL(name.data)) 816 ci = &cmsg->cm_u.cm_clntinfo;
801 return -EFAULT; 817 if (get_user(namelen, &ci->cc_name.cn_len))
802 name.len = namelen; 818 return -EFAULT;
819 name.data = memdup_user(&ci->cc_name.cn_id, namelen);
820 if (IS_ERR_OR_NULL(name.data))
821 return -EFAULT;
822 name.len = namelen;
823 get_user(princhashlen, &ci->cc_princhash.cp_len);
824 if (princhashlen > 0) {
825 princhash.data = memdup_user(
826 &ci->cc_princhash.cp_data,
827 princhashlen);
828 if (IS_ERR_OR_NULL(princhash.data))
829 return -EFAULT;
830 princhash.len = princhashlen;
831 } else
832 princhash.len = 0;
833 } else {
834 const struct cld_name __user *cnm;
835
836 cnm = &cmsg->cm_u.cm_name;
837 if (get_user(namelen, &cnm->cn_len))
838 return -EFAULT;
839 name.data = memdup_user(&cnm->cn_id, namelen);
840 if (IS_ERR_OR_NULL(name.data))
841 return -EFAULT;
842 name.len = namelen;
843 }
803 if (name.len > 5 && memcmp(name.data, "hash:", 5) == 0) { 844 if (name.len > 5 && memcmp(name.data, "hash:", 5) == 0) {
804 name.len = name.len - 5; 845 name.len = name.len - 5;
805 memmove(name.data, name.data + 5, name.len); 846 memmove(name.data, name.data + 5, name.len);
806 cn->cn_has_legacy = true; 847 cn->cn_has_legacy = true;
807 } 848 }
808 if (!nfs4_client_to_reclaim(name, nn)) { 849 if (!nfs4_client_to_reclaim(name, princhash, nn)) {
809 kfree(name.data); 850 kfree(name.data);
851 kfree(princhash.data);
810 return -EFAULT; 852 return -EFAULT;
811 } 853 }
812 return sizeof(*cmsg); 854 return nn->client_tracking_ops->msglen;
813 } 855 }
814 return -EFAULT; 856 return -EFAULT;
815} 857}
@@ -818,21 +860,22 @@ static ssize_t
818cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) 860cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
819{ 861{
820 struct cld_upcall *tmp, *cup; 862 struct cld_upcall *tmp, *cup;
821 struct cld_msg __user *cmsg = (struct cld_msg __user *)src; 863 struct cld_msg_hdr __user *hdr = (struct cld_msg_hdr __user *)src;
864 struct cld_msg_v2 __user *cmsg = (struct cld_msg_v2 __user *)src;
822 uint32_t xid; 865 uint32_t xid;
823 struct nfsd_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info, 866 struct nfsd_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info,
824 nfsd_net_id); 867 nfsd_net_id);
825 struct cld_net *cn = nn->cld_net; 868 struct cld_net *cn = nn->cld_net;
826 int16_t status; 869 int16_t status;
827 870
828 if (mlen != sizeof(*cmsg)) { 871 if (mlen != nn->client_tracking_ops->msglen) {
829 dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen, 872 dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen,
830 sizeof(*cmsg)); 873 nn->client_tracking_ops->msglen);
831 return -EINVAL; 874 return -EINVAL;
832 } 875 }
833 876
834 /* copy just the xid so we can try to find that */ 877 /* copy just the xid so we can try to find that */
835 if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) { 878 if (copy_from_user(&xid, &hdr->cm_xid, sizeof(xid)) != 0) {
836 dprintk("%s: error when copying xid from userspace", __func__); 879 dprintk("%s: error when copying xid from userspace", __func__);
837 return -EFAULT; 880 return -EFAULT;
838 } 881 }
@@ -842,7 +885,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
842 * list (for -EINPROGRESS, we just want to make sure the xid is 885 * list (for -EINPROGRESS, we just want to make sure the xid is
843 * valid, not remove the upcall from the list) 886 * valid, not remove the upcall from the list)
844 */ 887 */
845 if (get_user(status, &cmsg->cm_status)) { 888 if (get_user(status, &hdr->cm_status)) {
846 dprintk("%s: error when copying status from userspace", __func__); 889 dprintk("%s: error when copying status from userspace", __func__);
847 return -EFAULT; 890 return -EFAULT;
848 } 891 }
@@ -851,7 +894,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
851 cup = NULL; 894 cup = NULL;
852 spin_lock(&cn->cn_lock); 895 spin_lock(&cn->cn_lock);
853 list_for_each_entry(tmp, &cn->cn_list, cu_list) { 896 list_for_each_entry(tmp, &cn->cn_list, cu_list) {
854 if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) { 897 if (get_unaligned(&tmp->cu_u.cu_hdr.cm_xid) == xid) {
855 cup = tmp; 898 cup = tmp;
856 if (status != -EINPROGRESS) 899 if (status != -EINPROGRESS)
857 list_del_init(&cup->cu_list); 900 list_del_init(&cup->cu_list);
@@ -869,7 +912,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
869 if (status == -EINPROGRESS) 912 if (status == -EINPROGRESS)
870 return __cld_pipe_inprogress_downcall(cmsg, nn); 913 return __cld_pipe_inprogress_downcall(cmsg, nn);
871 914
872 if (copy_from_user(&cup->cu_msg, src, mlen) != 0) 915 if (copy_from_user(&cup->cu_u.cu_msg_v2, src, mlen) != 0)
873 return -EFAULT; 916 return -EFAULT;
874 917
875 complete(&cup->cu_done); 918 complete(&cup->cu_done);
@@ -881,7 +924,7 @@ cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
881{ 924{
882 struct cld_msg *cmsg = msg->data; 925 struct cld_msg *cmsg = msg->data;
883 struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, 926 struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
884 cu_msg); 927 cu_u.cu_msg);
885 928
886 /* errno >= 0 means we got a downcall */ 929 /* errno >= 0 means we got a downcall */
887 if (msg->errno >= 0) 930 if (msg->errno >= 0)
@@ -1007,14 +1050,17 @@ nfsd4_remove_cld_pipe(struct net *net)
1007 1050
1008 nfsd4_cld_unregister_net(net, cn->cn_pipe); 1051 nfsd4_cld_unregister_net(net, cn->cn_pipe);
1009 rpc_destroy_pipe_data(cn->cn_pipe); 1052 rpc_destroy_pipe_data(cn->cn_pipe);
1053 if (cn->cn_tfm)
1054 crypto_free_shash(cn->cn_tfm);
1010 kfree(nn->cld_net); 1055 kfree(nn->cld_net);
1011 nn->cld_net = NULL; 1056 nn->cld_net = NULL;
1012} 1057}
1013 1058
1014static struct cld_upcall * 1059static struct cld_upcall *
1015alloc_cld_upcall(struct cld_net *cn) 1060alloc_cld_upcall(struct nfsd_net *nn)
1016{ 1061{
1017 struct cld_upcall *new, *tmp; 1062 struct cld_upcall *new, *tmp;
1063 struct cld_net *cn = nn->cld_net;
1018 1064
1019 new = kzalloc(sizeof(*new), GFP_KERNEL); 1065 new = kzalloc(sizeof(*new), GFP_KERNEL);
1020 if (!new) 1066 if (!new)
@@ -1024,20 +1070,20 @@ alloc_cld_upcall(struct cld_net *cn)
1024restart_search: 1070restart_search:
1025 spin_lock(&cn->cn_lock); 1071 spin_lock(&cn->cn_lock);
1026 list_for_each_entry(tmp, &cn->cn_list, cu_list) { 1072 list_for_each_entry(tmp, &cn->cn_list, cu_list) {
1027 if (tmp->cu_msg.cm_xid == cn->cn_xid) { 1073 if (tmp->cu_u.cu_msg.cm_xid == cn->cn_xid) {
1028 cn->cn_xid++; 1074 cn->cn_xid++;
1029 spin_unlock(&cn->cn_lock); 1075 spin_unlock(&cn->cn_lock);
1030 goto restart_search; 1076 goto restart_search;
1031 } 1077 }
1032 } 1078 }
1033 init_completion(&new->cu_done); 1079 init_completion(&new->cu_done);
1034 new->cu_msg.cm_vers = CLD_UPCALL_VERSION; 1080 new->cu_u.cu_msg.cm_vers = nn->client_tracking_ops->version;
1035 put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid); 1081 put_unaligned(cn->cn_xid++, &new->cu_u.cu_msg.cm_xid);
1036 new->cu_net = cn; 1082 new->cu_net = cn;
1037 list_add(&new->cu_list, &cn->cn_list); 1083 list_add(&new->cu_list, &cn->cn_list);
1038 spin_unlock(&cn->cn_lock); 1084 spin_unlock(&cn->cn_lock);
1039 1085
1040 dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid); 1086 dprintk("%s: allocated xid %u\n", __func__, new->cu_u.cu_msg.cm_xid);
1041 1087
1042 return new; 1088 return new;
1043} 1089}
@@ -1066,20 +1112,20 @@ nfsd4_cld_create(struct nfs4_client *clp)
1066 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 1112 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1067 return; 1113 return;
1068 1114
1069 cup = alloc_cld_upcall(cn); 1115 cup = alloc_cld_upcall(nn);
1070 if (!cup) { 1116 if (!cup) {
1071 ret = -ENOMEM; 1117 ret = -ENOMEM;
1072 goto out_err; 1118 goto out_err;
1073 } 1119 }
1074 1120
1075 cup->cu_msg.cm_cmd = Cld_Create; 1121 cup->cu_u.cu_msg.cm_cmd = Cld_Create;
1076 cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; 1122 cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
1077 memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, 1123 memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
1078 clp->cl_name.len); 1124 clp->cl_name.len);
1079 1125
1080 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 1126 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
1081 if (!ret) { 1127 if (!ret) {
1082 ret = cup->cu_msg.cm_status; 1128 ret = cup->cu_u.cu_msg.cm_status;
1083 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 1129 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1084 } 1130 }
1085 1131
@@ -1092,6 +1138,75 @@ out_err:
1092 1138
1093/* Ask daemon to create a new record */ 1139/* Ask daemon to create a new record */
1094static void 1140static void
1141nfsd4_cld_create_v2(struct nfs4_client *clp)
1142{
1143 int ret;
1144 struct cld_upcall *cup;
1145 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1146 struct cld_net *cn = nn->cld_net;
1147 struct cld_msg_v2 *cmsg;
1148 struct crypto_shash *tfm = cn->cn_tfm;
1149 struct xdr_netobj cksum;
1150 char *principal = NULL;
1151 SHASH_DESC_ON_STACK(desc, tfm);
1152
1153 /* Don't upcall if it's already stored */
1154 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1155 return;
1156
1157 cup = alloc_cld_upcall(nn);
1158 if (!cup) {
1159 ret = -ENOMEM;
1160 goto out_err;
1161 }
1162
1163 cmsg = &cup->cu_u.cu_msg_v2;
1164 cmsg->cm_cmd = Cld_Create;
1165 cmsg->cm_u.cm_clntinfo.cc_name.cn_len = clp->cl_name.len;
1166 memcpy(cmsg->cm_u.cm_clntinfo.cc_name.cn_id, clp->cl_name.data,
1167 clp->cl_name.len);
1168 if (clp->cl_cred.cr_raw_principal)
1169 principal = clp->cl_cred.cr_raw_principal;
1170 else if (clp->cl_cred.cr_principal)
1171 principal = clp->cl_cred.cr_principal;
1172 if (principal) {
1173 desc->tfm = tfm;
1174 cksum.len = crypto_shash_digestsize(tfm);
1175 cksum.data = kmalloc(cksum.len, GFP_KERNEL);
1176 if (cksum.data == NULL) {
1177 ret = -ENOMEM;
1178 goto out;
1179 }
1180 ret = crypto_shash_digest(desc, principal, strlen(principal),
1181 cksum.data);
1182 shash_desc_zero(desc);
1183 if (ret) {
1184 kfree(cksum.data);
1185 goto out;
1186 }
1187 cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = cksum.len;
1188 memcpy(cmsg->cm_u.cm_clntinfo.cc_princhash.cp_data,
1189 cksum.data, cksum.len);
1190 kfree(cksum.data);
1191 } else
1192 cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = 0;
1193
1194 ret = cld_pipe_upcall(cn->cn_pipe, cmsg);
1195 if (!ret) {
1196 ret = cmsg->cm_status;
1197 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1198 }
1199
1200out:
1201 free_cld_upcall(cup);
1202out_err:
1203 if (ret)
1204 pr_err("NFSD: Unable to create client record on stable storage: %d\n",
1205 ret);
1206}
1207
1208/* Ask daemon to create a new record */
1209static void
1095nfsd4_cld_remove(struct nfs4_client *clp) 1210nfsd4_cld_remove(struct nfs4_client *clp)
1096{ 1211{
1097 int ret; 1212 int ret;
@@ -1103,20 +1218,20 @@ nfsd4_cld_remove(struct nfs4_client *clp)
1103 if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 1218 if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1104 return; 1219 return;
1105 1220
1106 cup = alloc_cld_upcall(cn); 1221 cup = alloc_cld_upcall(nn);
1107 if (!cup) { 1222 if (!cup) {
1108 ret = -ENOMEM; 1223 ret = -ENOMEM;
1109 goto out_err; 1224 goto out_err;
1110 } 1225 }
1111 1226
1112 cup->cu_msg.cm_cmd = Cld_Remove; 1227 cup->cu_u.cu_msg.cm_cmd = Cld_Remove;
1113 cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; 1228 cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
1114 memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, 1229 memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
1115 clp->cl_name.len); 1230 clp->cl_name.len);
1116 1231
1117 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 1232 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
1118 if (!ret) { 1233 if (!ret) {
1119 ret = cup->cu_msg.cm_status; 1234 ret = cup->cu_u.cu_msg.cm_status;
1120 clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 1235 clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1121 } 1236 }
1122 1237
@@ -1145,21 +1260,21 @@ nfsd4_cld_check_v0(struct nfs4_client *clp)
1145 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 1260 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1146 return 0; 1261 return 0;
1147 1262
1148 cup = alloc_cld_upcall(cn); 1263 cup = alloc_cld_upcall(nn);
1149 if (!cup) { 1264 if (!cup) {
1150 printk(KERN_ERR "NFSD: Unable to check client record on " 1265 printk(KERN_ERR "NFSD: Unable to check client record on "
1151 "stable storage: %d\n", -ENOMEM); 1266 "stable storage: %d\n", -ENOMEM);
1152 return -ENOMEM; 1267 return -ENOMEM;
1153 } 1268 }
1154 1269
1155 cup->cu_msg.cm_cmd = Cld_Check; 1270 cup->cu_u.cu_msg.cm_cmd = Cld_Check;
1156 cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; 1271 cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
1157 memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, 1272 memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
1158 clp->cl_name.len); 1273 clp->cl_name.len);
1159 1274
1160 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 1275 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
1161 if (!ret) { 1276 if (!ret) {
1162 ret = cup->cu_msg.cm_status; 1277 ret = cup->cu_u.cu_msg.cm_status;
1163 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 1278 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1164 } 1279 }
1165 1280
@@ -1217,22 +1332,95 @@ found:
1217} 1332}
1218 1333
1219static int 1334static int
1335nfsd4_cld_check_v2(struct nfs4_client *clp)
1336{
1337 struct nfs4_client_reclaim *crp;
1338 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1339 struct cld_net *cn = nn->cld_net;
1340 int status;
1341 char dname[HEXDIR_LEN];
1342 struct xdr_netobj name;
1343 struct crypto_shash *tfm = cn->cn_tfm;
1344 struct xdr_netobj cksum;
1345 char *principal = NULL;
1346 SHASH_DESC_ON_STACK(desc, tfm);
1347
1348 /* did we already find that this client is stable? */
1349 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1350 return 0;
1351
1352 /* look for it in the reclaim hashtable otherwise */
1353 crp = nfsd4_find_reclaim_client(clp->cl_name, nn);
1354 if (crp)
1355 goto found;
1356
1357 if (cn->cn_has_legacy) {
1358 status = nfs4_make_rec_clidname(dname, &clp->cl_name);
1359 if (status)
1360 return -ENOENT;
1361
1362 name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
1363 if (!name.data) {
1364 dprintk("%s: failed to allocate memory for name.data\n",
1365 __func__);
1366 return -ENOENT;
1367 }
1368 name.len = HEXDIR_LEN;
1369 crp = nfsd4_find_reclaim_client(name, nn);
1370 kfree(name.data);
1371 if (crp)
1372 goto found;
1373
1374 }
1375 return -ENOENT;
1376found:
1377 if (crp->cr_princhash.len) {
1378 if (clp->cl_cred.cr_raw_principal)
1379 principal = clp->cl_cred.cr_raw_principal;
1380 else if (clp->cl_cred.cr_principal)
1381 principal = clp->cl_cred.cr_principal;
1382 if (principal == NULL)
1383 return -ENOENT;
1384 desc->tfm = tfm;
1385 cksum.len = crypto_shash_digestsize(tfm);
1386 cksum.data = kmalloc(cksum.len, GFP_KERNEL);
1387 if (cksum.data == NULL)
1388 return -ENOENT;
1389 status = crypto_shash_digest(desc, principal, strlen(principal),
1390 cksum.data);
1391 shash_desc_zero(desc);
1392 if (status) {
1393 kfree(cksum.data);
1394 return -ENOENT;
1395 }
1396 if (memcmp(crp->cr_princhash.data, cksum.data,
1397 crp->cr_princhash.len)) {
1398 kfree(cksum.data);
1399 return -ENOENT;
1400 }
1401 kfree(cksum.data);
1402 }
1403 crp->cr_clp = clp;
1404 return 0;
1405}
1406
1407static int
1220nfsd4_cld_grace_start(struct nfsd_net *nn) 1408nfsd4_cld_grace_start(struct nfsd_net *nn)
1221{ 1409{
1222 int ret; 1410 int ret;
1223 struct cld_upcall *cup; 1411 struct cld_upcall *cup;
1224 struct cld_net *cn = nn->cld_net; 1412 struct cld_net *cn = nn->cld_net;
1225 1413
1226 cup = alloc_cld_upcall(cn); 1414 cup = alloc_cld_upcall(nn);
1227 if (!cup) { 1415 if (!cup) {
1228 ret = -ENOMEM; 1416 ret = -ENOMEM;
1229 goto out_err; 1417 goto out_err;
1230 } 1418 }
1231 1419
1232 cup->cu_msg.cm_cmd = Cld_GraceStart; 1420 cup->cu_u.cu_msg.cm_cmd = Cld_GraceStart;
1233 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 1421 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
1234 if (!ret) 1422 if (!ret)
1235 ret = cup->cu_msg.cm_status; 1423 ret = cup->cu_u.cu_msg.cm_status;
1236 1424
1237 free_cld_upcall(cup); 1425 free_cld_upcall(cup);
1238out_err: 1426out_err:
@@ -1250,17 +1438,17 @@ nfsd4_cld_grace_done_v0(struct nfsd_net *nn)
1250 struct cld_upcall *cup; 1438 struct cld_upcall *cup;
1251 struct cld_net *cn = nn->cld_net; 1439 struct cld_net *cn = nn->cld_net;
1252 1440
1253 cup = alloc_cld_upcall(cn); 1441 cup = alloc_cld_upcall(nn);
1254 if (!cup) { 1442 if (!cup) {
1255 ret = -ENOMEM; 1443 ret = -ENOMEM;
1256 goto out_err; 1444 goto out_err;
1257 } 1445 }
1258 1446
1259 cup->cu_msg.cm_cmd = Cld_GraceDone; 1447 cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone;
1260 cup->cu_msg.cm_u.cm_gracetime = (int64_t)nn->boot_time; 1448 cup->cu_u.cu_msg.cm_u.cm_gracetime = (int64_t)nn->boot_time;
1261 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 1449 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
1262 if (!ret) 1450 if (!ret)
1263 ret = cup->cu_msg.cm_status; 1451 ret = cup->cu_u.cu_msg.cm_status;
1264 1452
1265 free_cld_upcall(cup); 1453 free_cld_upcall(cup);
1266out_err: 1454out_err:
@@ -1279,16 +1467,16 @@ nfsd4_cld_grace_done(struct nfsd_net *nn)
1279 struct cld_upcall *cup; 1467 struct cld_upcall *cup;
1280 struct cld_net *cn = nn->cld_net; 1468 struct cld_net *cn = nn->cld_net;
1281 1469
1282 cup = alloc_cld_upcall(cn); 1470 cup = alloc_cld_upcall(nn);
1283 if (!cup) { 1471 if (!cup) {
1284 ret = -ENOMEM; 1472 ret = -ENOMEM;
1285 goto out_err; 1473 goto out_err;
1286 } 1474 }
1287 1475
1288 cup->cu_msg.cm_cmd = Cld_GraceDone; 1476 cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone;
1289 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 1477 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
1290 if (!ret) 1478 if (!ret)
1291 ret = cup->cu_msg.cm_status; 1479 ret = cup->cu_u.cu_msg.cm_status;
1292 1480
1293 free_cld_upcall(cup); 1481 free_cld_upcall(cup);
1294out_err: 1482out_err:
@@ -1337,6 +1525,53 @@ cld_running(struct nfsd_net *nn)
1337} 1525}
1338 1526
1339static int 1527static int
1528nfsd4_cld_get_version(struct nfsd_net *nn)
1529{
1530 int ret = 0;
1531 struct cld_upcall *cup;
1532 struct cld_net *cn = nn->cld_net;
1533 uint8_t version;
1534
1535 cup = alloc_cld_upcall(nn);
1536 if (!cup) {
1537 ret = -ENOMEM;
1538 goto out_err;
1539 }
1540 cup->cu_u.cu_msg.cm_cmd = Cld_GetVersion;
1541 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg);
1542 if (!ret) {
1543 ret = cup->cu_u.cu_msg.cm_status;
1544 if (ret)
1545 goto out_free;
1546 version = cup->cu_u.cu_msg.cm_u.cm_version;
1547 dprintk("%s: userspace returned version %u\n",
1548 __func__, version);
1549 if (version < 1)
1550 version = 1;
1551 else if (version > CLD_UPCALL_VERSION)
1552 version = CLD_UPCALL_VERSION;
1553
1554 switch (version) {
1555 case 1:
1556 nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
1557 break;
1558 case 2:
1559 nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v2;
1560 break;
1561 default:
1562 break;
1563 }
1564 }
1565out_free:
1566 free_cld_upcall(cup);
1567out_err:
1568 if (ret)
1569 dprintk("%s: Unable to get version from userspace: %d\n",
1570 __func__, ret);
1571 return ret;
1572}
1573
1574static int
1340nfsd4_cld_tracking_init(struct net *net) 1575nfsd4_cld_tracking_init(struct net *net)
1341{ 1576{
1342 int status; 1577 int status;
@@ -1351,6 +1586,11 @@ nfsd4_cld_tracking_init(struct net *net)
1351 status = __nfsd4_init_cld_pipe(net); 1586 status = __nfsd4_init_cld_pipe(net);
1352 if (status) 1587 if (status)
1353 goto err_shutdown; 1588 goto err_shutdown;
1589 nn->cld_net->cn_tfm = crypto_alloc_shash("sha256", 0, 0);
1590 if (IS_ERR(nn->cld_net->cn_tfm)) {
1591 status = PTR_ERR(nn->cld_net->cn_tfm);
1592 goto err_remove;
1593 }
1354 1594
1355 /* 1595 /*
1356 * rpc pipe upcalls take 30 seconds to time out, so we don't want to 1596 * rpc pipe upcalls take 30 seconds to time out, so we don't want to
@@ -1368,10 +1608,14 @@ nfsd4_cld_tracking_init(struct net *net)
1368 goto err_remove; 1608 goto err_remove;
1369 } 1609 }
1370 1610
1611 status = nfsd4_cld_get_version(nn);
1612 if (status == -EOPNOTSUPP)
1613 pr_warn("NFSD: nfsdcld GetVersion upcall failed. Please upgrade nfsdcld.\n");
1614
1371 status = nfsd4_cld_grace_start(nn); 1615 status = nfsd4_cld_grace_start(nn);
1372 if (status) { 1616 if (status) {
1373 if (status == -EOPNOTSUPP) 1617 if (status == -EOPNOTSUPP)
1374 printk(KERN_WARNING "NFSD: Please upgrade nfsdcld.\n"); 1618 pr_warn("NFSD: nfsdcld GraceStart upcall failed. Please upgrade nfsdcld.\n");
1375 nfs4_release_reclaim(nn); 1619 nfs4_release_reclaim(nn);
1376 goto err_remove; 1620 goto err_remove;
1377 } else 1621 } else
@@ -1403,6 +1647,8 @@ static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v0 = {
1403 .remove = nfsd4_cld_remove, 1647 .remove = nfsd4_cld_remove,
1404 .check = nfsd4_cld_check_v0, 1648 .check = nfsd4_cld_check_v0,
1405 .grace_done = nfsd4_cld_grace_done_v0, 1649 .grace_done = nfsd4_cld_grace_done_v0,
1650 .version = 1,
1651 .msglen = sizeof(struct cld_msg),
1406}; 1652};
1407 1653
1408/* For newer nfsdcld's */ 1654/* For newer nfsdcld's */
@@ -1413,6 +1659,20 @@ static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
1413 .remove = nfsd4_cld_remove, 1659 .remove = nfsd4_cld_remove,
1414 .check = nfsd4_cld_check, 1660 .check = nfsd4_cld_check,
1415 .grace_done = nfsd4_cld_grace_done, 1661 .grace_done = nfsd4_cld_grace_done,
1662 .version = 1,
1663 .msglen = sizeof(struct cld_msg),
1664};
1665
1666/* v2 create/check ops include the principal, if available */
1667static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2 = {
1668 .init = nfsd4_cld_tracking_init,
1669 .exit = nfsd4_cld_tracking_exit,
1670 .create = nfsd4_cld_create_v2,
1671 .remove = nfsd4_cld_remove,
1672 .check = nfsd4_cld_check_v2,
1673 .grace_done = nfsd4_cld_grace_done,
1674 .version = 2,
1675 .msglen = sizeof(struct cld_msg_v2),
1416}; 1676};
1417 1677
1418/* upcall via usermodehelper */ 1678/* upcall via usermodehelper */
@@ -1760,6 +2020,8 @@ static const struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
1760 .remove = nfsd4_umh_cltrack_remove, 2020 .remove = nfsd4_umh_cltrack_remove,
1761 .check = nfsd4_umh_cltrack_check, 2021 .check = nfsd4_umh_cltrack_check,
1762 .grace_done = nfsd4_umh_cltrack_grace_done, 2022 .grace_done = nfsd4_umh_cltrack_grace_done,
2023 .version = 1,
2024 .msglen = 0,
1763}; 2025};
1764 2026
1765int 2027int