summaryrefslogtreecommitdiffstats
path: root/net/rxrpc/call_state.c
blob: 8fbb2112ed7e2a17c4d977a32cffb321d09f948e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// SPDX-License-Identifier: GPL-2.0-or-later
/* Call state changing functions.
 *
 * Copyright (C) 2022 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 */

#include "ar-internal.h"

/*
 * Transition a call to the complete state.
 */
bool __rxrpc_set_call_completion(struct rxrpc_call *call,
				 enum rxrpc_call_completion compl,
				 u32 abort_code,
				 int error)
{
	if (call->state < RXRPC_CALL_COMPLETE) {
		call->abort_code = abort_code;
		call->error = error;
		call->completion = compl;
		call->state = RXRPC_CALL_COMPLETE;
		trace_rxrpc_call_complete(call);
		wake_up(&call->waitq);
		rxrpc_notify_socket(call);
		return true;
	}
	return false;
}

bool rxrpc_set_call_completion(struct rxrpc_call *call,
			       enum rxrpc_call_completion compl,
			       u32 abort_code,
			       int error)
{
	bool ret = false;

	if (call->state < RXRPC_CALL_COMPLETE) {
		write_lock(&call->state_lock);
		ret = __rxrpc_set_call_completion(call, compl, abort_code, error);
		write_unlock(&call->state_lock);
	}
	return ret;
}

/*
 * Record that a call successfully completed.
 */
bool __rxrpc_call_completed(struct rxrpc_call *call)
{
	return __rxrpc_set_call_completion(call, RXRPC_CALL_SUCCEEDED, 0, 0);
}

bool rxrpc_call_completed(struct rxrpc_call *call)
{
	bool ret = false;

	if (call->state < RXRPC_CALL_COMPLETE) {
		write_lock(&call->state_lock);
		ret = __rxrpc_call_completed(call);
		write_unlock(&call->state_lock);
	}
	return ret;
}

/*
 * Record that a call is locally aborted.
 */
bool __rxrpc_abort_call(struct rxrpc_call *call, rxrpc_seq_t seq,
			u32 abort_code, int error, enum rxrpc_abort_reason why)
{
	trace_rxrpc_abort(call->debug_id, why, call->cid, call->call_id, seq,
			  abort_code, error);
	return __rxrpc_set_call_completion(call, RXRPC_CALL_LOCALLY_ABORTED,
					   abort_code, error);
}

bool rxrpc_abort_call(struct rxrpc_call *call, rxrpc_seq_t seq,
		      u32 abort_code, int error, enum rxrpc_abort_reason why)
{
	bool ret;

	write_lock(&call->state_lock);
	ret = __rxrpc_abort_call(call, seq, abort_code, error, why);
	write_unlock(&call->state_lock);
	if (ret && test_bit(RXRPC_CALL_EXPOSED, &call->flags))
		rxrpc_send_abort_packet(call);
	return ret;
}