aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2017-05-06 12:19:11 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2017-05-08 09:40:59 -0400
commit28cf22d0ba283deccc30b71de5f34d222cf9aa4c (patch)
tree14438a4abda155261e1dccf8922c3e9b511f304a
parent2e84611b3f4fa50e1f4c12f2966fcc7fb955d944 (diff)
NFSv4: Fix exclusive create attributes encoding
When using NFS4_CREATE_EXCLUSIVE4_1 mode, the client will overestimate the amount of space that it needs for the attributes because it does so before checking whether or not the server supports a given attribute. Fix by checking the attribute mask earlier. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r--fs/nfs/nfs4xdr.c75
1 files changed, 35 insertions, 40 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index dbfe48ac3529..3aebfdc82b30 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1000,8 +1000,9 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
1000 1000
1001static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, 1001static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
1002 const struct nfs4_label *label, 1002 const struct nfs4_label *label,
1003 const umode_t *umask,
1003 const struct nfs_server *server, 1004 const struct nfs_server *server,
1004 bool excl_check, const umode_t *umask) 1005 const uint32_t attrmask[])
1005{ 1006{
1006 char owner_name[IDMAP_NAMESZ]; 1007 char owner_name[IDMAP_NAMESZ];
1007 char owner_group[IDMAP_NAMESZ]; 1008 char owner_group[IDMAP_NAMESZ];
@@ -1016,22 +1017,20 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
1016 /* 1017 /*
1017 * We reserve enough space to write the entire attribute buffer at once. 1018 * We reserve enough space to write the entire attribute buffer at once.
1018 */ 1019 */
1019 if (iap->ia_valid & ATTR_SIZE) { 1020 if ((iap->ia_valid & ATTR_SIZE) && (attrmask[0] & FATTR4_WORD0_SIZE)) {
1020 bmval[0] |= FATTR4_WORD0_SIZE; 1021 bmval[0] |= FATTR4_WORD0_SIZE;
1021 len += 8; 1022 len += 8;
1022 } 1023 }
1023 if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
1024 umask = NULL;
1025 if (iap->ia_valid & ATTR_MODE) { 1024 if (iap->ia_valid & ATTR_MODE) {
1026 if (umask) { 1025 if (umask && (attrmask[2] & FATTR4_WORD2_MODE_UMASK)) {
1027 bmval[2] |= FATTR4_WORD2_MODE_UMASK; 1026 bmval[2] |= FATTR4_WORD2_MODE_UMASK;
1028 len += 8; 1027 len += 8;
1029 } else { 1028 } else if (attrmask[1] & FATTR4_WORD1_MODE) {
1030 bmval[1] |= FATTR4_WORD1_MODE; 1029 bmval[1] |= FATTR4_WORD1_MODE;
1031 len += 4; 1030 len += 4;
1032 } 1031 }
1033 } 1032 }
1034 if (iap->ia_valid & ATTR_UID) { 1033 if ((iap->ia_valid & ATTR_UID) && (attrmask[1] & FATTR4_WORD1_OWNER)) {
1035 owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ); 1034 owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
1036 if (owner_namelen < 0) { 1035 if (owner_namelen < 0) {
1037 dprintk("nfs: couldn't resolve uid %d to string\n", 1036 dprintk("nfs: couldn't resolve uid %d to string\n",
@@ -1044,7 +1043,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
1044 bmval[1] |= FATTR4_WORD1_OWNER; 1043 bmval[1] |= FATTR4_WORD1_OWNER;
1045 len += 4 + (XDR_QUADLEN(owner_namelen) << 2); 1044 len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
1046 } 1045 }
1047 if (iap->ia_valid & ATTR_GID) { 1046 if ((iap->ia_valid & ATTR_GID) &&
1047 (attrmask[1] & FATTR4_WORD1_OWNER_GROUP)) {
1048 owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group, IDMAP_NAMESZ); 1048 owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group, IDMAP_NAMESZ);
1049 if (owner_grouplen < 0) { 1049 if (owner_grouplen < 0) {
1050 dprintk("nfs: couldn't resolve gid %d to string\n", 1050 dprintk("nfs: couldn't resolve gid %d to string\n",
@@ -1056,32 +1056,26 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
1056 bmval[1] |= FATTR4_WORD1_OWNER_GROUP; 1056 bmval[1] |= FATTR4_WORD1_OWNER_GROUP;
1057 len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); 1057 len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
1058 } 1058 }
1059 if (iap->ia_valid & ATTR_ATIME_SET) { 1059 if (attrmask[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
1060 bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET; 1060 if (iap->ia_valid & ATTR_ATIME_SET) {
1061 len += 16; 1061 bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
1062 } else if (iap->ia_valid & ATTR_ATIME) { 1062 len += 16;
1063 bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET; 1063 } else if (iap->ia_valid & ATTR_ATIME) {
1064 len += 4; 1064 bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
1065 } 1065 len += 4;
1066 if (iap->ia_valid & ATTR_MTIME_SET) { 1066 }
1067 bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
1068 len += 16;
1069 } else if (iap->ia_valid & ATTR_MTIME) {
1070 bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
1071 len += 4;
1072 } 1067 }
1073 1068 if (attrmask[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
1074 if (excl_check) { 1069 if (iap->ia_valid & ATTR_MTIME_SET) {
1075 const u32 *excl_bmval = server->exclcreat_bitmask; 1070 bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
1076 bmval[0] &= excl_bmval[0]; 1071 len += 16;
1077 bmval[1] &= excl_bmval[1]; 1072 } else if (iap->ia_valid & ATTR_MTIME) {
1078 bmval[2] &= excl_bmval[2]; 1073 bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
1079 1074 len += 4;
1080 if (!(excl_bmval[2] & FATTR4_WORD2_SECURITY_LABEL)) 1075 }
1081 label = NULL;
1082 } 1076 }
1083 1077
1084 if (label) { 1078 if (label && (attrmask[2] & FATTR4_WORD2_SECURITY_LABEL)) {
1085 len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); 1079 len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
1086 bmval[2] |= FATTR4_WORD2_SECURITY_LABEL; 1080 bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
1087 } 1081 }
@@ -1188,8 +1182,8 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
1188 } 1182 }
1189 1183
1190 encode_string(xdr, create->name->len, create->name->name); 1184 encode_string(xdr, create->name->len, create->name->name);
1191 encode_attrs(xdr, create->attrs, create->label, create->server, false, 1185 encode_attrs(xdr, create->attrs, create->label, &create->umask,
1192 &create->umask); 1186 create->server, create->server->attr_bitmask);
1193} 1187}
1194 1188
1195static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr) 1189static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
@@ -1409,13 +1403,13 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
1409 switch(arg->createmode) { 1403 switch(arg->createmode) {
1410 case NFS4_CREATE_UNCHECKED: 1404 case NFS4_CREATE_UNCHECKED:
1411 *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); 1405 *p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
1412 encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false, 1406 encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
1413 &arg->umask); 1407 arg->server, arg->server->attr_bitmask);
1414 break; 1408 break;
1415 case NFS4_CREATE_GUARDED: 1409 case NFS4_CREATE_GUARDED:
1416 *p = cpu_to_be32(NFS4_CREATE_GUARDED); 1410 *p = cpu_to_be32(NFS4_CREATE_GUARDED);
1417 encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false, 1411 encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
1418 &arg->umask); 1412 arg->server, arg->server->attr_bitmask);
1419 break; 1413 break;
1420 case NFS4_CREATE_EXCLUSIVE: 1414 case NFS4_CREATE_EXCLUSIVE:
1421 *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); 1415 *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
@@ -1424,8 +1418,8 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
1424 case NFS4_CREATE_EXCLUSIVE4_1: 1418 case NFS4_CREATE_EXCLUSIVE4_1:
1425 *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1); 1419 *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
1426 encode_nfs4_verifier(xdr, &arg->u.verifier); 1420 encode_nfs4_verifier(xdr, &arg->u.verifier);
1427 encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, true, 1421 encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
1428 &arg->umask); 1422 arg->server, arg->server->exclcreat_bitmask);
1429 } 1423 }
1430} 1424}
1431 1425
@@ -1681,7 +1675,8 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
1681{ 1675{
1682 encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr); 1676 encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
1683 encode_nfs4_stateid(xdr, &arg->stateid); 1677 encode_nfs4_stateid(xdr, &arg->stateid);
1684 encode_attrs(xdr, arg->iap, arg->label, server, false, NULL); 1678 encode_attrs(xdr, arg->iap, arg->label, NULL, server,
1679 server->attr_bitmask);
1685} 1680}
1686 1681
1687static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr) 1682static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)