Skip to content

Commit 28cf22d

Browse files
committed
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>
1 parent 2e84611 commit 28cf22d

File tree

1 file changed

+35
-40
lines changed

1 file changed

+35
-40
lines changed

fs/nfs/nfs4xdr.c

Lines changed: 35 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,8 +1000,9 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
10001000

10011001
static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
10021002
const struct nfs4_label *label,
1003+
const umode_t *umask,
10031004
const struct nfs_server *server,
1004-
bool excl_check, const umode_t *umask)
1005+
const uint32_t attrmask[])
10051006
{
10061007
char owner_name[IDMAP_NAMESZ];
10071008
char owner_group[IDMAP_NAMESZ];
@@ -1016,22 +1017,20 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
10161017
/*
10171018
* We reserve enough space to write the entire attribute buffer at once.
10181019
*/
1019-
if (iap->ia_valid & ATTR_SIZE) {
1020+
if ((iap->ia_valid & ATTR_SIZE) && (attrmask[0] & FATTR4_WORD0_SIZE)) {
10201021
bmval[0] |= FATTR4_WORD0_SIZE;
10211022
len += 8;
10221023
}
1023-
if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
1024-
umask = NULL;
10251024
if (iap->ia_valid & ATTR_MODE) {
1026-
if (umask) {
1025+
if (umask && (attrmask[2] & FATTR4_WORD2_MODE_UMASK)) {
10271026
bmval[2] |= FATTR4_WORD2_MODE_UMASK;
10281027
len += 8;
1029-
} else {
1028+
} else if (attrmask[1] & FATTR4_WORD1_MODE) {
10301029
bmval[1] |= FATTR4_WORD1_MODE;
10311030
len += 4;
10321031
}
10331032
}
1034-
if (iap->ia_valid & ATTR_UID) {
1033+
if ((iap->ia_valid & ATTR_UID) && (attrmask[1] & FATTR4_WORD1_OWNER)) {
10351034
owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
10361035
if (owner_namelen < 0) {
10371036
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,
10441043
bmval[1] |= FATTR4_WORD1_OWNER;
10451044
len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
10461045
}
1047-
if (iap->ia_valid & ATTR_GID) {
1046+
if ((iap->ia_valid & ATTR_GID) &&
1047+
(attrmask[1] & FATTR4_WORD1_OWNER_GROUP)) {
10481048
owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group, IDMAP_NAMESZ);
10491049
if (owner_grouplen < 0) {
10501050
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,
10561056
bmval[1] |= FATTR4_WORD1_OWNER_GROUP;
10571057
len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
10581058
}
1059-
if (iap->ia_valid & ATTR_ATIME_SET) {
1060-
bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
1061-
len += 16;
1062-
} else if (iap->ia_valid & ATTR_ATIME) {
1063-
bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
1064-
len += 4;
1065-
}
1066-
if (iap->ia_valid & ATTR_MTIME_SET) {
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;
1059+
if (attrmask[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
1060+
if (iap->ia_valid & ATTR_ATIME_SET) {
1061+
bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
1062+
len += 16;
1063+
} else if (iap->ia_valid & ATTR_ATIME) {
1064+
bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
1065+
len += 4;
1066+
}
10721067
}
1073-
1074-
if (excl_check) {
1075-
const u32 *excl_bmval = server->exclcreat_bitmask;
1076-
bmval[0] &= excl_bmval[0];
1077-
bmval[1] &= excl_bmval[1];
1078-
bmval[2] &= excl_bmval[2];
1079-
1080-
if (!(excl_bmval[2] & FATTR4_WORD2_SECURITY_LABEL))
1081-
label = NULL;
1068+
if (attrmask[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
1069+
if (iap->ia_valid & ATTR_MTIME_SET) {
1070+
bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
1071+
len += 16;
1072+
} else if (iap->ia_valid & ATTR_MTIME) {
1073+
bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
1074+
len += 4;
1075+
}
10821076
}
10831077

1084-
if (label) {
1078+
if (label && (attrmask[2] & FATTR4_WORD2_SECURITY_LABEL)) {
10851079
len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
10861080
bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
10871081
}
@@ -1188,8 +1182,8 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
11881182
}
11891183

11901184
encode_string(xdr, create->name->len, create->name->name);
1191-
encode_attrs(xdr, create->attrs, create->label, create->server, false,
1192-
&create->umask);
1185+
encode_attrs(xdr, create->attrs, create->label, &create->umask,
1186+
create->server, create->server->attr_bitmask);
11931187
}
11941188

11951189
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
14091403
switch(arg->createmode) {
14101404
case NFS4_CREATE_UNCHECKED:
14111405
*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
1412-
encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false,
1413-
&arg->umask);
1406+
encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
1407+
arg->server, arg->server->attr_bitmask);
14141408
break;
14151409
case NFS4_CREATE_GUARDED:
14161410
*p = cpu_to_be32(NFS4_CREATE_GUARDED);
1417-
encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false,
1418-
&arg->umask);
1411+
encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
1412+
arg->server, arg->server->attr_bitmask);
14191413
break;
14201414
case NFS4_CREATE_EXCLUSIVE:
14211415
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
@@ -1424,8 +1418,8 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
14241418
case NFS4_CREATE_EXCLUSIVE4_1:
14251419
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
14261420
encode_nfs4_verifier(xdr, &arg->u.verifier);
1427-
encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, true,
1428-
&arg->umask);
1421+
encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
1422+
arg->server, arg->server->exclcreat_bitmask);
14291423
}
14301424
}
14311425

@@ -1681,7 +1675,8 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
16811675
{
16821676
encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
16831677
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);
16851680
}
16861681

16871682
static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)

0 commit comments

Comments
 (0)