aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-05-10 16:51:47 -0400
committerDavid Howells <dhowells@redhat.com>2018-05-14 10:15:18 -0400
commit684b0f68cf1c1cf4a40834818653491c5cad4435 (patch)
tree7130c6dbecf5792a13fac49feba84c2f2cee3a4b /fs/afs
parentec5a3b4b507efca903d848518dcf2ebf7b04b466 (diff)
afs: Fix AFSFetchStatus decoder to provide OpenAFS compatibility
The OpenAFS server's RXAFS_InlineBulkStatus implementation has a bug whereby if an error occurs on one of the vnodes being queried, then the errorCode field is set correctly in the corresponding status, but the interfaceVersion field is left unset. Fix kAFS to deal with this by evaluating the AFSFetchStatus blob against the following cases when called from FS.InlineBulkStatus delivery: (1) If InterfaceVersion == 0 then: (a) If errorCode != 0 then it indicates the abort code for the corresponding vnode. (b) If errorCode == 0 then the status record is invalid. (2) If InterfaceVersion == 1 then: (a) If errorCode != 0 then it indicates the abort code for the corresponding vnode. (b) If errorCode == 0 then the status record is valid and can be parsed. (3) If InterfaceVersion is anything else then the status record is invalid. Fixes: dd9fbcb8e103 ("afs: Rearrange status mapping") Reported-by: Jeffrey Altman <jaltman@auristor.com> Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/fsclient.c29
1 files changed, 21 insertions, 8 deletions
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index efacdb7c1dee..d16f26c6cdbe 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -134,6 +134,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
134 struct afs_read *read_req) 134 struct afs_read *read_req)
135{ 135{
136 const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; 136 const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
137 bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
137 u64 data_version, size; 138 u64 data_version, size;
138 u32 type, abort_code; 139 u32 type, abort_code;
139 u8 flags = 0; 140 u8 flags = 0;
@@ -142,13 +143,32 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
142 if (vnode) 143 if (vnode)
143 write_seqlock(&vnode->cb_lock); 144 write_seqlock(&vnode->cb_lock);
144 145
146 abort_code = ntohl(xdr->abort_code);
147
145 if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { 148 if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
149 if (xdr->if_version == htonl(0) &&
150 abort_code != 0 &&
151 inline_error) {
152 /* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
153 * whereby it doesn't set the interface version in the error
154 * case.
155 */
156 status->abort_code = abort_code;
157 ret = 0;
158 goto out;
159 }
160
146 pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); 161 pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
147 goto bad; 162 goto bad;
148 } 163 }
149 164
165 if (abort_code != 0 && inline_error) {
166 status->abort_code = abort_code;
167 ret = 0;
168 goto out;
169 }
170
150 type = ntohl(xdr->type); 171 type = ntohl(xdr->type);
151 abort_code = ntohl(xdr->abort_code);
152 switch (type) { 172 switch (type) {
153 case AFS_FTYPE_FILE: 173 case AFS_FTYPE_FILE:
154 case AFS_FTYPE_DIR: 174 case AFS_FTYPE_DIR:
@@ -165,13 +185,6 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
165 } 185 }
166 status->type = type; 186 status->type = type;
167 break; 187 break;
168 case AFS_FTYPE_INVALID:
169 if (abort_code != 0) {
170 status->abort_code = abort_code;
171 ret = 0;
172 goto out;
173 }
174 /* Fall through */
175 default: 188 default:
176 goto bad; 189 goto bad;
177 } 190 }