diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-07-17 16:43:16 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-07-17 16:54:46 -0400 |
commit | b4a2cf76ab7c08628c62b2062dacefa496b59dfd (patch) | |
tree | 82bf8b6f4e48f7c2533beef0587ea0395d14f79f /fs | |
parent | 1540c5d3cbf7670eb68a0d02611ec73e5604a91a (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4xdr.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 0abfb8466e79..c74d6168db99 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -999,6 +999,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
999 | __be32 *p; | 999 | __be32 *p; |
1000 | __be32 *q; | 1000 | __be32 *q; |
1001 | int len; | 1001 | int len; |
1002 | uint32_t bmval_len = 2; | ||
1002 | uint32_t bmval0 = 0; | 1003 | uint32_t bmval0 = 0; |
1003 | uint32_t bmval1 = 0; | 1004 | uint32_t bmval1 = 0; |
1004 | uint32_t bmval2 = 0; | 1005 | uint32_t bmval2 = 0; |
@@ -1010,7 +1011,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
1010 | * = 40 bytes, plus any contribution from variable-length fields | 1011 | * = 40 bytes, plus any contribution from variable-length fields |
1011 | * such as owner/group. | 1012 | * such as owner/group. |
1012 | */ | 1013 | */ |
1013 | len = 20; | 1014 | len = 8; |
1014 | 1015 | ||
1015 | /* Sigh */ | 1016 | /* Sigh */ |
1016 | if (iap->ia_valid & ATTR_SIZE) | 1017 | if (iap->ia_valid & ATTR_SIZE) |
@@ -1040,8 +1041,6 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
1040 | } | 1041 | } |
1041 | len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); | 1042 | len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); |
1042 | } | 1043 | } |
1043 | if (label) | ||
1044 | len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); | ||
1045 | if (iap->ia_valid & ATTR_ATIME_SET) | 1044 | if (iap->ia_valid & ATTR_ATIME_SET) |
1046 | len += 16; | 1045 | len += 16; |
1047 | else if (iap->ia_valid & ATTR_ATIME) | 1046 | else if (iap->ia_valid & ATTR_ATIME) |
@@ -1050,15 +1049,22 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
1050 | len += 16; | 1049 | len += 16; |
1051 | else if (iap->ia_valid & ATTR_MTIME) | 1050 | else if (iap->ia_valid & ATTR_MTIME) |
1052 | len += 4; | 1051 | len += 4; |
1052 | if (label) { | ||
1053 | len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); | ||
1054 | bmval_len = 3; | ||
1055 | } | ||
1056 | |||
1057 | len += bmval_len << 2; | ||
1053 | p = reserve_space(xdr, len); | 1058 | p = reserve_space(xdr, len); |
1054 | 1059 | ||
1055 | /* | 1060 | /* |
1056 | * We write the bitmap length now, but leave the bitmap and the attribute | 1061 | * We write the bitmap length now, but leave the bitmap and the attribute |
1057 | * buffer length to be backfilled at the end of this routine. | 1062 | * buffer length to be backfilled at the end of this routine. |
1058 | */ | 1063 | */ |
1059 | *p++ = cpu_to_be32(3); | 1064 | *p++ = cpu_to_be32(bmval_len); |
1060 | q = p; | 1065 | q = p; |
1061 | p += 4; | 1066 | /* Skip bitmap entries + attrlen */ |
1067 | p += bmval_len + 1; | ||
1062 | 1068 | ||
1063 | if (iap->ia_valid & ATTR_SIZE) { | 1069 | if (iap->ia_valid & ATTR_SIZE) { |
1064 | bmval0 |= FATTR4_WORD0_SIZE; | 1070 | bmval0 |= FATTR4_WORD0_SIZE; |
@@ -1112,10 +1118,11 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
1112 | len, ((char *)p - (char *)q) + 4); | 1118 | len, ((char *)p - (char *)q) + 4); |
1113 | BUG(); | 1119 | BUG(); |
1114 | } | 1120 | } |
1115 | len = (char *)p - (char *)q - 16; | 1121 | len = (char *)p - (char *)q - (bmval_len << 2); |
1116 | *q++ = htonl(bmval0); | 1122 | *q++ = htonl(bmval0); |
1117 | *q++ = htonl(bmval1); | 1123 | *q++ = htonl(bmval1); |
1118 | *q++ = htonl(bmval2); | 1124 | if (bmval_len == 3) |
1125 | *q++ = htonl(bmval2); | ||
1119 | *q = htonl(len); | 1126 | *q = htonl(len); |
1120 | 1127 | ||
1121 | /* out: */ | 1128 | /* out: */ |