xref: /optee_os/core/kernel/lockdep.c (revision 5ee85d76897c95c21fa5eb86d66b288b9b19c62b)
1b3fd78c4SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2b3fd78c4SJerome Forissier /*
3b3fd78c4SJerome Forissier  * Copyright (c) 2018, Linaro Limited
4b3fd78c4SJerome Forissier  */
5b3fd78c4SJerome Forissier 
6b3fd78c4SJerome Forissier #include <assert.h>
7b3fd78c4SJerome Forissier #include <kernel/lockdep.h>
8b3fd78c4SJerome Forissier #include <kernel/unwind.h>
9b3fd78c4SJerome Forissier #include <stdlib.h>
10b3fd78c4SJerome Forissier #include <string.h>
11b3fd78c4SJerome Forissier #include <sys/queue.h>
12b3fd78c4SJerome Forissier #include <util.h>
13b3fd78c4SJerome Forissier 
14b3fd78c4SJerome Forissier /* lockdep_node::flags values */
15b3fd78c4SJerome Forissier /* Flags used for depth-first topological sorting */
16b3fd78c4SJerome Forissier #define LOCKDEP_NODE_TEMP_MARK		BIT(0)
17b3fd78c4SJerome Forissier #define LOCKDEP_NODE_PERM_MARK		BIT(1)
18b3fd78c4SJerome Forissier /* Flag used during breadth-first search (print shortest cycle) */
19b3fd78c4SJerome Forissier #define LOCKDEP_NODE_BFS_VISITED	BIT(2)
20b3fd78c4SJerome Forissier 
21b3fd78c4SJerome Forissier /* Find node in graph or add it */
22b3fd78c4SJerome Forissier static struct lockdep_node *lockdep_add_to_graph(
23b3fd78c4SJerome Forissier 				struct lockdep_node_head *graph,
24b3fd78c4SJerome Forissier 				uintptr_t lock_id)
25b3fd78c4SJerome Forissier {
26b3fd78c4SJerome Forissier 	struct lockdep_node *node = NULL;
27b3fd78c4SJerome Forissier 
28b3fd78c4SJerome Forissier 	assert(graph);
29b3fd78c4SJerome Forissier 	TAILQ_FOREACH(node, graph, link)
30b3fd78c4SJerome Forissier 		if (node->lock_id == lock_id)
31b3fd78c4SJerome Forissier 			return node;
32b3fd78c4SJerome Forissier 
33b3fd78c4SJerome Forissier 	node = calloc(1, sizeof(*node));
34b3fd78c4SJerome Forissier 	if (!node)
35b3fd78c4SJerome Forissier 		return NULL;
36b3fd78c4SJerome Forissier 
37b3fd78c4SJerome Forissier 	node->lock_id = lock_id;
38b3fd78c4SJerome Forissier 	STAILQ_INIT(&node->edges);
39b3fd78c4SJerome Forissier 	TAILQ_INSERT_TAIL(graph, node, link);
40b3fd78c4SJerome Forissier 
41b3fd78c4SJerome Forissier 	return node;
42b3fd78c4SJerome Forissier }
43b3fd78c4SJerome Forissier 
44b3fd78c4SJerome Forissier static vaddr_t *dup_call_stack(vaddr_t *stack)
45b3fd78c4SJerome Forissier {
46*5ee85d76SJerome Forissier 	vaddr_t *nstack = NULL;
47*5ee85d76SJerome Forissier 	int n = 0;
48*5ee85d76SJerome Forissier 
49b3fd78c4SJerome Forissier 	if (!stack)
50b3fd78c4SJerome Forissier 		return NULL;
51b3fd78c4SJerome Forissier 
52b3fd78c4SJerome Forissier 	while (stack[n])
53b3fd78c4SJerome Forissier 		n++;
54b3fd78c4SJerome Forissier 
55*5ee85d76SJerome Forissier 	nstack = malloc((n + 1) * sizeof(vaddr_t));
56b3fd78c4SJerome Forissier 	if (!nstack)
57b3fd78c4SJerome Forissier 		return NULL;
58*5ee85d76SJerome Forissier 
59*5ee85d76SJerome Forissier 	memcpy(nstack, stack, (n + 1) * sizeof(vaddr_t));
60*5ee85d76SJerome Forissier 
61b3fd78c4SJerome Forissier 	return nstack;
62b3fd78c4SJerome Forissier }
63b3fd78c4SJerome Forissier 
64b3fd78c4SJerome Forissier static void lockdep_print_call_stack(vaddr_t *stack)
65b3fd78c4SJerome Forissier {
66b3fd78c4SJerome Forissier 	vaddr_t *p = NULL;
67b3fd78c4SJerome Forissier 
68b3fd78c4SJerome Forissier 	EMSG_RAW("Call stack:");
69b3fd78c4SJerome Forissier 	for (p = stack; p && *p; p++)
70b3fd78c4SJerome Forissier 		EMSG_RAW(" %#" PRIxPTR, *p);
71b3fd78c4SJerome Forissier }
72b3fd78c4SJerome Forissier 
73b3fd78c4SJerome Forissier static TEE_Result lockdep_add_edge(struct lockdep_node *from,
74b3fd78c4SJerome Forissier 				   struct lockdep_node *to,
75b3fd78c4SJerome Forissier 				   vaddr_t *call_stack_from,
76b3fd78c4SJerome Forissier 				   vaddr_t *call_stack_to,
77b3fd78c4SJerome Forissier 				   uintptr_t thread_id)
78b3fd78c4SJerome Forissier {
79b3fd78c4SJerome Forissier 	struct lockdep_edge *edge = NULL;
80b3fd78c4SJerome Forissier 
81b3fd78c4SJerome Forissier 	STAILQ_FOREACH(edge, &from->edges, link)
82b3fd78c4SJerome Forissier 		if (edge->to == to)
83b3fd78c4SJerome Forissier 			return TEE_SUCCESS;
84b3fd78c4SJerome Forissier 
85b3fd78c4SJerome Forissier 	edge = calloc(1, sizeof(*edge));
86b3fd78c4SJerome Forissier 	if (!edge)
87b3fd78c4SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
88b3fd78c4SJerome Forissier 	edge->to = to;
89b3fd78c4SJerome Forissier 	edge->call_stack_from = dup_call_stack(call_stack_from);
90b3fd78c4SJerome Forissier 	edge->call_stack_to = dup_call_stack(call_stack_to);
91b3fd78c4SJerome Forissier 	edge->thread_id = thread_id;
92b3fd78c4SJerome Forissier 	STAILQ_INSERT_TAIL(&from->edges, edge, link);
93b3fd78c4SJerome Forissier 
94b3fd78c4SJerome Forissier 	return TEE_SUCCESS;
95b3fd78c4SJerome Forissier }
96b3fd78c4SJerome Forissier 
97b3fd78c4SJerome Forissier struct lockdep_bfs {
98b3fd78c4SJerome Forissier 	struct lockdep_node *node;
99b3fd78c4SJerome Forissier 	uintptr_t *path;
100b3fd78c4SJerome Forissier 	int pathlen;
101b3fd78c4SJerome Forissier 	TAILQ_ENTRY(lockdep_bfs) link;
102b3fd78c4SJerome Forissier };
103b3fd78c4SJerome Forissier 
104b3fd78c4SJerome Forissier TAILQ_HEAD(lockdep_bfs_head, lockdep_bfs);
105b3fd78c4SJerome Forissier 
106b3fd78c4SJerome Forissier static void lockdep_bfs_queue_delete(struct lockdep_bfs_head *queue)
107b3fd78c4SJerome Forissier {
108b3fd78c4SJerome Forissier 	struct lockdep_bfs *cur = NULL;
109b3fd78c4SJerome Forissier 	struct lockdep_bfs *next = NULL;
110b3fd78c4SJerome Forissier 
111b3fd78c4SJerome Forissier 	TAILQ_FOREACH_SAFE(cur, queue, link, next) {
112b3fd78c4SJerome Forissier 		TAILQ_REMOVE(queue, cur, link);
113b3fd78c4SJerome Forissier 		free(cur->path);
114b3fd78c4SJerome Forissier 		free(cur);
115b3fd78c4SJerome Forissier 	}
116b3fd78c4SJerome Forissier }
117b3fd78c4SJerome Forissier 
118b3fd78c4SJerome Forissier /*
119b3fd78c4SJerome Forissier  * Print shortest cycle in @graph that contains @node.
120b3fd78c4SJerome Forissier  * This function performs an iterative breadth-first search starting from @node,
121b3fd78c4SJerome Forissier  * and stops when it reaches @node again. In each node we're tracking the path
122b3fd78c4SJerome Forissier  * from the start node.
123b3fd78c4SJerome Forissier  */
124b3fd78c4SJerome Forissier static uintptr_t *lockdep_graph_get_shortest_cycle(struct lockdep_node *node)
125b3fd78c4SJerome Forissier {
126b3fd78c4SJerome Forissier 	struct lockdep_bfs_head queue;
127b3fd78c4SJerome Forissier 	struct lockdep_bfs *qe = NULL;
128b3fd78c4SJerome Forissier 	uintptr_t *ret = NULL;
129b3fd78c4SJerome Forissier 
130b3fd78c4SJerome Forissier 	TAILQ_INIT(&queue);
131b3fd78c4SJerome Forissier 	node->flags |= LOCKDEP_NODE_BFS_VISITED;
132b3fd78c4SJerome Forissier 
133b3fd78c4SJerome Forissier 	qe = calloc(1, sizeof(*qe));
134b3fd78c4SJerome Forissier 	if (!qe)
135b3fd78c4SJerome Forissier 		goto out;
136b3fd78c4SJerome Forissier 	qe->node = node;
137b3fd78c4SJerome Forissier 	qe->path = malloc(sizeof(uintptr_t));
138b3fd78c4SJerome Forissier 	if (!qe->path)
139b3fd78c4SJerome Forissier 		goto out;
140b3fd78c4SJerome Forissier 	qe->path[0] = node->lock_id;
141b3fd78c4SJerome Forissier 	qe->pathlen = 1;
142b3fd78c4SJerome Forissier 	TAILQ_INSERT_TAIL(&queue, qe, link);
143b3fd78c4SJerome Forissier 
144b3fd78c4SJerome Forissier 	while (!TAILQ_EMPTY(&queue)) {
145b3fd78c4SJerome Forissier 		qe = TAILQ_FIRST(&queue);
146b3fd78c4SJerome Forissier 
147b3fd78c4SJerome Forissier 		struct lockdep_node *n = qe->node;
148b3fd78c4SJerome Forissier 
149b3fd78c4SJerome Forissier 		TAILQ_REMOVE(&queue, qe, link);
150b3fd78c4SJerome Forissier 
151b3fd78c4SJerome Forissier 		struct lockdep_edge *e = NULL;
152b3fd78c4SJerome Forissier 
153b3fd78c4SJerome Forissier 		STAILQ_FOREACH(e, &n->edges, link) {
154b3fd78c4SJerome Forissier 			if (e->to->lock_id == node->lock_id) {
155b3fd78c4SJerome Forissier 				uintptr_t *tmp = NULL;
156b3fd78c4SJerome Forissier 				size_t nlen = qe->pathlen + 1;
157b3fd78c4SJerome Forissier 
158b3fd78c4SJerome Forissier 				/*
159b3fd78c4SJerome Forissier 				 * Cycle found. Terminate cycle path with NULL
160b3fd78c4SJerome Forissier 				 * and return it.
161b3fd78c4SJerome Forissier 				 */
162b3fd78c4SJerome Forissier 				tmp = realloc(qe->path,
163b3fd78c4SJerome Forissier 					      nlen * sizeof(uintptr_t));
164b3fd78c4SJerome Forissier 				if (!tmp) {
165b3fd78c4SJerome Forissier 					EMSG("Out of memory");
166b3fd78c4SJerome Forissier 					free(qe->path);
167b3fd78c4SJerome Forissier 					ret = NULL;
168b3fd78c4SJerome Forissier 					goto out;
169b3fd78c4SJerome Forissier 				}
170b3fd78c4SJerome Forissier 				qe->path = tmp;
171b3fd78c4SJerome Forissier 				qe->path[nlen - 1] = 0;
172b3fd78c4SJerome Forissier 				ret = qe->path;
173b3fd78c4SJerome Forissier 				goto out;
174b3fd78c4SJerome Forissier 			}
175b3fd78c4SJerome Forissier 
176b3fd78c4SJerome Forissier 			if (!(e->to->flags & LOCKDEP_NODE_BFS_VISITED)) {
177b3fd78c4SJerome Forissier 				e->to->flags |= LOCKDEP_NODE_BFS_VISITED;
178b3fd78c4SJerome Forissier 
179b3fd78c4SJerome Forissier 				size_t nlen = qe->pathlen + 1;
180b3fd78c4SJerome Forissier 				struct lockdep_bfs *nqe = calloc(1,
181b3fd78c4SJerome Forissier 								 sizeof(*nqe));
182b3fd78c4SJerome Forissier 
183b3fd78c4SJerome Forissier 				if (!nqe)
184b3fd78c4SJerome Forissier 					goto out;
185b3fd78c4SJerome Forissier 				nqe->node = e->to;
186b3fd78c4SJerome Forissier 				nqe->path = malloc(nlen * sizeof(uintptr_t));
187b3fd78c4SJerome Forissier 				if (!nqe->path)
188b3fd78c4SJerome Forissier 					goto out;
189b3fd78c4SJerome Forissier 				nqe->pathlen = nlen;
190b3fd78c4SJerome Forissier 				memcpy(nqe->path, qe->path,
191b3fd78c4SJerome Forissier 				       qe->pathlen * sizeof(uintptr_t));
192b3fd78c4SJerome Forissier 				nqe->path[nlen - 1] = e->to->lock_id;
193b3fd78c4SJerome Forissier 				TAILQ_INSERT_TAIL(&queue, nqe, link);
194b3fd78c4SJerome Forissier 			}
195b3fd78c4SJerome Forissier 		}
196b3fd78c4SJerome Forissier 		free(qe->path);
197b3fd78c4SJerome Forissier 		free(qe);
198b3fd78c4SJerome Forissier 		qe = NULL;
199b3fd78c4SJerome Forissier 	}
200b3fd78c4SJerome Forissier 
201b3fd78c4SJerome Forissier out:
202b3fd78c4SJerome Forissier 	free(qe);
203b3fd78c4SJerome Forissier 	lockdep_bfs_queue_delete(&queue);
204b3fd78c4SJerome Forissier 	return ret;
205b3fd78c4SJerome Forissier }
206b3fd78c4SJerome Forissier 
207b3fd78c4SJerome Forissier static TEE_Result lockdep_visit(struct lockdep_node *node)
208b3fd78c4SJerome Forissier {
209b3fd78c4SJerome Forissier 	if (node->flags & LOCKDEP_NODE_PERM_MARK)
210b3fd78c4SJerome Forissier 		return TEE_SUCCESS;
211b3fd78c4SJerome Forissier 
212b3fd78c4SJerome Forissier 	if (node->flags & LOCKDEP_NODE_TEMP_MARK)
213b3fd78c4SJerome Forissier 		return TEE_ERROR_BAD_STATE;	/* Not a DAG! */
214b3fd78c4SJerome Forissier 
215b3fd78c4SJerome Forissier 	node->flags |= LOCKDEP_NODE_TEMP_MARK;
216b3fd78c4SJerome Forissier 
217b3fd78c4SJerome Forissier 	struct lockdep_edge *e;
218b3fd78c4SJerome Forissier 
219b3fd78c4SJerome Forissier 	STAILQ_FOREACH(e, &node->edges, link) {
220b3fd78c4SJerome Forissier 		TEE_Result res = lockdep_visit(e->to);
221b3fd78c4SJerome Forissier 
222b3fd78c4SJerome Forissier 		if (res)
223b3fd78c4SJerome Forissier 			return res;
224b3fd78c4SJerome Forissier 	}
225b3fd78c4SJerome Forissier 
226b3fd78c4SJerome Forissier 	node->flags |= LOCKDEP_NODE_PERM_MARK;
227b3fd78c4SJerome Forissier 	return TEE_SUCCESS;
228b3fd78c4SJerome Forissier }
229b3fd78c4SJerome Forissier 
230b3fd78c4SJerome Forissier static TEE_Result lockdep_graph_sort(struct lockdep_node_head *graph)
231b3fd78c4SJerome Forissier {
232b3fd78c4SJerome Forissier 	struct lockdep_node *node = NULL;
233b3fd78c4SJerome Forissier 
234b3fd78c4SJerome Forissier 	TAILQ_FOREACH(node, graph, link) {
235b3fd78c4SJerome Forissier 		if (!node->flags) {
236b3fd78c4SJerome Forissier 			/* Unmarked node */
237b3fd78c4SJerome Forissier 			TEE_Result res = lockdep_visit(node);
238b3fd78c4SJerome Forissier 
239b3fd78c4SJerome Forissier 			if (res)
240b3fd78c4SJerome Forissier 				return res;
241b3fd78c4SJerome Forissier 		}
242b3fd78c4SJerome Forissier 	}
243b3fd78c4SJerome Forissier 
244b3fd78c4SJerome Forissier 	TAILQ_FOREACH(node, graph, link)
245b3fd78c4SJerome Forissier 		node->flags = 0;
246b3fd78c4SJerome Forissier 
247b3fd78c4SJerome Forissier 	return TEE_SUCCESS;
248b3fd78c4SJerome Forissier }
249b3fd78c4SJerome Forissier 
250b3fd78c4SJerome Forissier static struct lockdep_edge *lockdep_find_edge(struct lockdep_node_head *graph,
251b3fd78c4SJerome Forissier 					      uintptr_t from, uintptr_t to)
252b3fd78c4SJerome Forissier {
253b3fd78c4SJerome Forissier 	struct lockdep_node *node = NULL;
254b3fd78c4SJerome Forissier 	struct lockdep_edge *edge = NULL;
255b3fd78c4SJerome Forissier 
256b3fd78c4SJerome Forissier 	TAILQ_FOREACH(node, graph, link)
257b3fd78c4SJerome Forissier 		if (node->lock_id == from)
258b3fd78c4SJerome Forissier 			STAILQ_FOREACH(edge, &node->edges, link)
259b3fd78c4SJerome Forissier 				if (edge->to->lock_id == to)
260b3fd78c4SJerome Forissier 					return edge;
261b3fd78c4SJerome Forissier 	return NULL;
262b3fd78c4SJerome Forissier }
263b3fd78c4SJerome Forissier 
264b3fd78c4SJerome Forissier static void lockdep_print_edge_info(uintptr_t from __maybe_unused,
265b3fd78c4SJerome Forissier 				    struct lockdep_edge *edge)
266b3fd78c4SJerome Forissier {
267b3fd78c4SJerome Forissier 	uintptr_t __maybe_unused to = edge->to->lock_id;
268b3fd78c4SJerome Forissier 
269b3fd78c4SJerome Forissier 	EMSG_RAW("-> Thread %#" PRIxPTR " acquired lock %#" PRIxPTR " at:",
270b3fd78c4SJerome Forissier 		 edge->thread_id, to);
271b3fd78c4SJerome Forissier 	lockdep_print_call_stack(edge->call_stack_to);
272b3fd78c4SJerome Forissier 	EMSG_RAW("...while holding lock %#" PRIxPTR " acquired at:",
273b3fd78c4SJerome Forissier 		 from);
274b3fd78c4SJerome Forissier 	lockdep_print_call_stack(edge->call_stack_from);
275b3fd78c4SJerome Forissier }
276b3fd78c4SJerome Forissier 
277b3fd78c4SJerome Forissier /*
278b3fd78c4SJerome Forissier  * Find cycle containing @node in the lock graph, then print full debug
279b3fd78c4SJerome Forissier  * information about each edge (thread that acquired the locks and call stacks)
280b3fd78c4SJerome Forissier  */
281b3fd78c4SJerome Forissier static void lockdep_print_cycle_info(struct lockdep_node_head *graph,
282b3fd78c4SJerome Forissier 				     struct lockdep_node *node)
283b3fd78c4SJerome Forissier {
284b3fd78c4SJerome Forissier 	struct lockdep_edge *edge = NULL;
285b3fd78c4SJerome Forissier 	uintptr_t *cycle = NULL;
286b3fd78c4SJerome Forissier 	uintptr_t *p = NULL;
287b3fd78c4SJerome Forissier 	uintptr_t from = 0;
288b3fd78c4SJerome Forissier 	uintptr_t to = 0;
289b3fd78c4SJerome Forissier 
290b3fd78c4SJerome Forissier 	cycle = lockdep_graph_get_shortest_cycle(node);
291b3fd78c4SJerome Forissier 	assert(cycle && cycle[0]);
292b3fd78c4SJerome Forissier 	EMSG_RAW("-> Shortest cycle:");
293b3fd78c4SJerome Forissier 	for (p = cycle; *p; p++)
294b3fd78c4SJerome Forissier 		EMSG_RAW(" Lock %#" PRIxPTR, *p);
295b3fd78c4SJerome Forissier 	for (p = cycle; ; p++) {
296b3fd78c4SJerome Forissier 		if (!*p) {
297b3fd78c4SJerome Forissier 			assert(p != cycle);
298b3fd78c4SJerome Forissier 			from = to;
299b3fd78c4SJerome Forissier 			to = cycle[0];
300b3fd78c4SJerome Forissier 			edge = lockdep_find_edge(graph, from, to);
301b3fd78c4SJerome Forissier 			lockdep_print_edge_info(from, edge);
302b3fd78c4SJerome Forissier 			break;
303b3fd78c4SJerome Forissier 		}
304b3fd78c4SJerome Forissier 		if (p != cycle)
305b3fd78c4SJerome Forissier 			from = to;
306b3fd78c4SJerome Forissier 		to = *p;
307b3fd78c4SJerome Forissier 		if (p != cycle) {
308b3fd78c4SJerome Forissier 			edge = lockdep_find_edge(graph, from, to);
309b3fd78c4SJerome Forissier 			lockdep_print_edge_info(from, edge);
310b3fd78c4SJerome Forissier 		}
311b3fd78c4SJerome Forissier 	}
312b3fd78c4SJerome Forissier 	free(cycle);
313b3fd78c4SJerome Forissier }
314b3fd78c4SJerome Forissier 
315b3fd78c4SJerome Forissier TEE_Result __lockdep_lock_acquire(struct lockdep_node_head *graph,
316b3fd78c4SJerome Forissier 				  struct lockdep_lock_head *owned,
317b3fd78c4SJerome Forissier 				  uintptr_t id)
318b3fd78c4SJerome Forissier {
319b3fd78c4SJerome Forissier 	struct lockdep_node *node = lockdep_add_to_graph(graph, id);
320b3fd78c4SJerome Forissier 
321b3fd78c4SJerome Forissier 	if (!node)
322b3fd78c4SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
323b3fd78c4SJerome Forissier 
324b3fd78c4SJerome Forissier 	struct lockdep_lock *lock = NULL;
325b3fd78c4SJerome Forissier 	vaddr_t *acq_stack = unw_get_kernel_stack();
326b3fd78c4SJerome Forissier 
327b3fd78c4SJerome Forissier 	TAILQ_FOREACH(lock, owned, link) {
328b3fd78c4SJerome Forissier 		TEE_Result res = lockdep_add_edge(lock->node, node,
329b3fd78c4SJerome Forissier 						  lock->call_stack,
330b3fd78c4SJerome Forissier 						  acq_stack,
331b3fd78c4SJerome Forissier 						  (uintptr_t)owned);
332b3fd78c4SJerome Forissier 
333b3fd78c4SJerome Forissier 		if (res)
334b3fd78c4SJerome Forissier 			return res;
335b3fd78c4SJerome Forissier 	}
336b3fd78c4SJerome Forissier 
337b3fd78c4SJerome Forissier 	TEE_Result res = lockdep_graph_sort(graph);
338b3fd78c4SJerome Forissier 
339b3fd78c4SJerome Forissier 	if (res) {
340b3fd78c4SJerome Forissier 		EMSG_RAW("Potential deadlock detected!");
341b3fd78c4SJerome Forissier 		EMSG_RAW("When trying to acquire lock %#" PRIxPTR, id);
342b3fd78c4SJerome Forissier 		lockdep_print_cycle_info(graph, node);
343b3fd78c4SJerome Forissier 		return res;
344b3fd78c4SJerome Forissier 	}
345b3fd78c4SJerome Forissier 
346b3fd78c4SJerome Forissier 	lock = calloc(1, sizeof(*lock));
347b3fd78c4SJerome Forissier 	if (!lock)
348b3fd78c4SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
349b3fd78c4SJerome Forissier 
350b3fd78c4SJerome Forissier 	lock->node = node;
351b3fd78c4SJerome Forissier 	lock->call_stack = acq_stack;
352b3fd78c4SJerome Forissier 	TAILQ_INSERT_TAIL(owned, lock, link);
353b3fd78c4SJerome Forissier 
354b3fd78c4SJerome Forissier 	return TEE_SUCCESS;
355b3fd78c4SJerome Forissier }
356b3fd78c4SJerome Forissier 
357b3fd78c4SJerome Forissier TEE_Result __lockdep_lock_release(struct lockdep_lock_head *owned, uintptr_t id)
358b3fd78c4SJerome Forissier {
359b3fd78c4SJerome Forissier 	struct lockdep_lock *lock = NULL;
360b3fd78c4SJerome Forissier 
361b3fd78c4SJerome Forissier 	TAILQ_FOREACH_REVERSE(lock, owned, lockdep_lock_head, link) {
362b3fd78c4SJerome Forissier 		if (lock->node->lock_id == id) {
363b3fd78c4SJerome Forissier 			TAILQ_REMOVE(owned, lock, link);
364b3fd78c4SJerome Forissier 			free(lock->call_stack);
365b3fd78c4SJerome Forissier 			free(lock);
366b3fd78c4SJerome Forissier 			return TEE_SUCCESS;
367b3fd78c4SJerome Forissier 		}
368b3fd78c4SJerome Forissier 	}
369b3fd78c4SJerome Forissier 
370b3fd78c4SJerome Forissier 	EMSG_RAW("Thread %p does not own lock %#" PRIxPTR, (void *)owned, id);
371b3fd78c4SJerome Forissier 	return TEE_ERROR_ITEM_NOT_FOUND;
372b3fd78c4SJerome Forissier }
373b3fd78c4SJerome Forissier 
374b3fd78c4SJerome Forissier static void lockdep_node_delete(struct lockdep_node *node)
375b3fd78c4SJerome Forissier {
376b3fd78c4SJerome Forissier 	struct lockdep_edge *edge = NULL;
377b3fd78c4SJerome Forissier 	struct lockdep_edge *next = NULL;
378b3fd78c4SJerome Forissier 
379b3fd78c4SJerome Forissier 	STAILQ_FOREACH_SAFE(edge, &node->edges, link, next) {
380b3fd78c4SJerome Forissier 		free(edge->call_stack_from);
381b3fd78c4SJerome Forissier 		free(edge->call_stack_to);
382b3fd78c4SJerome Forissier 		free(edge);
383b3fd78c4SJerome Forissier 	}
384b3fd78c4SJerome Forissier 	free(node);
385b3fd78c4SJerome Forissier }
386b3fd78c4SJerome Forissier 
387b3fd78c4SJerome Forissier void lockdep_graph_delete(struct lockdep_node_head *graph)
388b3fd78c4SJerome Forissier {
389b3fd78c4SJerome Forissier 	struct lockdep_node *node = NULL;
390b3fd78c4SJerome Forissier 	struct lockdep_node *next = NULL;
391b3fd78c4SJerome Forissier 
392b3fd78c4SJerome Forissier 	TAILQ_FOREACH_SAFE(node, graph, link, next) {
393b3fd78c4SJerome Forissier 		TAILQ_REMOVE(graph, node, link);
394b3fd78c4SJerome Forissier 		lockdep_node_delete(node);
395b3fd78c4SJerome Forissier 	}
396b3fd78c4SJerome Forissier }
397b3fd78c4SJerome Forissier 
398b3fd78c4SJerome Forissier void lockdep_queue_delete(struct lockdep_lock_head *owned)
399b3fd78c4SJerome Forissier {
400b3fd78c4SJerome Forissier 	struct lockdep_lock *lock = NULL;
401b3fd78c4SJerome Forissier 	struct lockdep_lock *next = NULL;
402b3fd78c4SJerome Forissier 
403b3fd78c4SJerome Forissier 	TAILQ_FOREACH_SAFE(lock, owned, link, next) {
404b3fd78c4SJerome Forissier 		TAILQ_REMOVE(owned, lock, link);
405b3fd78c4SJerome Forissier 		free(lock);
406b3fd78c4SJerome Forissier 	}
407b3fd78c4SJerome Forissier }
408