diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-05-06 12:19:11 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-05-08 09:40:59 -0400 |
commit | 28cf22d0ba283deccc30b71de5f34d222cf9aa4c (patch) | |
tree | 14438a4abda155261e1dccf8922c3e9b511f304a | |
parent | 2e84611b3f4fa50e1f4c12f2966fcc7fb955d944 (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.c | 75 |
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 | ||
1001 | static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | 1001 | static 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 | ||
1195 | static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr) | 1189 | static 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 | ||
1687 | static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr) | 1682 | static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr) |