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