Commit 684b0f68 authored by David Howells's avatar David Howells

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: dd9fbcb8 ("afs: Rearrange status mapping")
Reported-by: default avatarJeffrey Altman <jaltman@auristor.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent ec5a3b4b
...@@ -134,6 +134,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, ...@@ -134,6 +134,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
struct afs_read *read_req) struct afs_read *read_req)
{ {
const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
u64 data_version, size; u64 data_version, size;
u32 type, abort_code; u32 type, abort_code;
u8 flags = 0; u8 flags = 0;
...@@ -142,13 +143,32 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, ...@@ -142,13 +143,32 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
if (vnode) if (vnode)
write_seqlock(&vnode->cb_lock); write_seqlock(&vnode->cb_lock);
abort_code = ntohl(xdr->abort_code);
if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
if (xdr->if_version == htonl(0) &&
abort_code != 0 &&
inline_error) {
/* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
* whereby it doesn't set the interface version in the error
* case.
*/
status->abort_code = abort_code;
ret = 0;
goto out;
}
pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
goto bad; goto bad;
} }
if (abort_code != 0 && inline_error) {
status->abort_code = abort_code;
ret = 0;
goto out;
}
type = ntohl(xdr->type); type = ntohl(xdr->type);
abort_code = ntohl(xdr->abort_code);
switch (type) { switch (type) {
case AFS_FTYPE_FILE: case AFS_FTYPE_FILE:
case AFS_FTYPE_DIR: case AFS_FTYPE_DIR:
...@@ -165,13 +185,6 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, ...@@ -165,13 +185,6 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
} }
status->type = type; status->type = type;
break; break;
case AFS_FTYPE_INVALID:
if (abort_code != 0) {
status->abort_code = abort_code;
ret = 0;
goto out;
}
/* Fall through */
default: default:
goto bad; goto bad;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment