Commit 70af0e3b authored by David Howells's avatar David Howells

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