mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-17 06:52:43 +00:00
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>
This commit is contained in:
parent
ec5a3b4b50
commit
684b0f68cf
@ -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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user