NFSv4: Fix a regression against the FreeBSD server

Technically, the Linux client is allowed by the NFSv4 spec to send
3 word bitmaps as part of an OPEN request. However, this causes the
current FreeBSD server to return NFS4ERR_ATTRNOTSUPP errors.

Fix the regression by making the Linux client use a 2 word bitmap unless
doing NFSv4.2 with labeled NFS.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

+14 -7
+14 -7
fs/nfs/nfs4xdr.c
··· 999 999 __be32 *p; 1000 1000 __be32 *q; 1001 1001 int len; 1002 + uint32_t bmval_len = 2; 1002 1003 uint32_t bmval0 = 0; 1003 1004 uint32_t bmval1 = 0; 1004 1005 uint32_t bmval2 = 0; ··· 1011 1010 * = 40 bytes, plus any contribution from variable-length fields 1012 1011 * such as owner/group. 1013 1012 */ 1014 - len = 20; 1013 + len = 8; 1015 1014 1016 1015 /* Sigh */ 1017 1016 if (iap->ia_valid & ATTR_SIZE) ··· 1041 1040 } 1042 1041 len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); 1043 1042 } 1044 - if (label) 1045 - len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); 1046 1043 if (iap->ia_valid & ATTR_ATIME_SET) 1047 1044 len += 16; 1048 1045 else if (iap->ia_valid & ATTR_ATIME) ··· 1049 1050 len += 16; 1050 1051 else if (iap->ia_valid & ATTR_MTIME) 1051 1052 len += 4; 1053 + if (label) { 1054 + len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); 1055 + bmval_len = 3; 1056 + } 1057 + 1058 + len += bmval_len << 2; 1052 1059 p = reserve_space(xdr, len); 1053 1060 1054 1061 /* 1055 1062 * We write the bitmap length now, but leave the bitmap and the attribute 1056 1063 * buffer length to be backfilled at the end of this routine. 1057 1064 */ 1058 - *p++ = cpu_to_be32(3); 1065 + *p++ = cpu_to_be32(bmval_len); 1059 1066 q = p; 1060 - p += 4; 1067 + /* Skip bitmap entries + attrlen */ 1068 + p += bmval_len + 1; 1061 1069 1062 1070 if (iap->ia_valid & ATTR_SIZE) { 1063 1071 bmval0 |= FATTR4_WORD0_SIZE; ··· 1118 1112 len, ((char *)p - (char *)q) + 4); 1119 1113 BUG(); 1120 1114 } 1121 - len = (char *)p - (char *)q - 16; 1115 + len = (char *)p - (char *)q - (bmval_len << 2); 1122 1116 *q++ = htonl(bmval0); 1123 1117 *q++ = htonl(bmval1); 1124 - *q++ = htonl(bmval2); 1118 + if (bmval_len == 3) 1119 + *q++ = htonl(bmval2); 1125 1120 *q = htonl(len); 1126 1121 1127 1122 /* out: */