afs: Better abort and net error handling

If we receive a network error, a remote abort or a protocol error whilst
we're still transmitting data, make sure we return an appropriate error to
the caller rather than ESHUTDOWN or ECONNABORTED.

Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells 2017-03-16 16:27:47 +00:00
parent 1157f153f3
commit 70af0e3bd6
1 changed files with 27 additions and 8 deletions

View File

@ -340,6 +340,8 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
struct rxrpc_call *rxcall;
struct msghdr msg;
struct kvec iov[1];
size_t offset;
u32 abort_code;
int ret;
_enter("%x,{%d},", addr->s_addr, ntohs(call->port));
@ -388,9 +390,11 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
msg.msg_controllen = 0;
msg.msg_flags = (call->send_pages ? MSG_MORE : 0);
/* have to change the state *before* sending the last packet as RxRPC
* might give us the reply before it returns from sending the
* request */
/* We have to change the state *before* sending the last packet as
* rxrpc might give us the reply before it returns from sending the
* request. Further, if the send fails, we may already have been given
* a notification and may have collected it.
*/
if (!call->send_pages)
call->state = AFS_CALL_AWAIT_REPLY;
ret = rxrpc_kernel_send_data(afs_socket, rxcall,
@ -412,7 +416,17 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
return afs_wait_for_call_to_complete(call);
error_do_abort:
rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT, -ret, "KSD");
call->state = AFS_CALL_COMPLETE;
if (ret != -ECONNABORTED) {
rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT,
-ret, "KSD");
} else {
abort_code = 0;
offset = 0;
rxrpc_kernel_recv_data(afs_socket, rxcall, NULL, 0, &offset,
false, &abort_code);
ret = call->type->abort_to_error(abort_code);
}
error_kill_call:
afs_put_call(call);
_leave(" = %d", ret);
@ -459,16 +473,18 @@ static void afs_deliver_to_call(struct afs_call *call)
case -EINPROGRESS:
case -EAGAIN:
goto out;
case -ECONNABORTED:
goto call_complete;
case -ENOTCONN:
abort_code = RX_CALL_DEAD;
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
abort_code, -ret, "KNC");
goto do_abort;
goto save_error;
case -ENOTSUPP:
abort_code = RXGEN_OPCODE;
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
abort_code, -ret, "KIV");
goto do_abort;
goto save_error;
case -ENODATA:
case -EBADMSG:
case -EMSGSIZE:
@ -478,7 +494,7 @@ static void afs_deliver_to_call(struct afs_call *call)
abort_code = RXGEN_SS_UNMARSHAL;
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
abort_code, EBADMSG, "KUM");
goto do_abort;
goto save_error;
}
}
@ -489,8 +505,9 @@ out:
_leave("");
return;
do_abort:
save_error:
call->error = ret;
call_complete:
call->state = AFS_CALL_COMPLETE;
goto done;
}
@ -538,6 +555,8 @@ static int afs_wait_for_call_to_complete(struct afs_call *call)
_debug("call incomplete");
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
RX_CALL_DEAD, -ret, abort_why);
} else if (call->error < 0) {
ret = call->error;
}
_debug("call complete");