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

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
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -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");