1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2023 Red Hat 4 */ 5 6 #include "thread-registry.h" 7 8 #include <asm/current.h> 9 #include <linux/rculist.h> 10 11 #include "permassert.h" 12 13 /* 14 * We need to be careful when using other facilities that may use thread registry functions in 15 * their normal operation. For example, we do not want to invoke the logger while holding a lock. 16 */ 17 18 void vdo_initialize_thread_registry(struct thread_registry *registry) 19 { 20 INIT_LIST_HEAD(®istry->links); 21 spin_lock_init(®istry->lock); 22 } 23 24 /* Register the current thread and associate it with a data pointer. */ 25 void vdo_register_thread(struct thread_registry *registry, 26 struct registered_thread *new_thread, const void *pointer) 27 { 28 struct registered_thread *thread; 29 bool found_it = false; 30 31 INIT_LIST_HEAD(&new_thread->links); 32 new_thread->pointer = pointer; 33 new_thread->task = current; 34 35 spin_lock(®istry->lock); 36 list_for_each_entry(thread, ®istry->links, links) { 37 if (thread->task == current) { 38 /* There should be no existing entry. */ 39 list_del_rcu(&thread->links); 40 found_it = true; 41 break; 42 } 43 } 44 list_add_tail_rcu(&new_thread->links, ®istry->links); 45 spin_unlock(®istry->lock); 46 47 VDO_ASSERT_LOG_ONLY(!found_it, "new thread not already in registry"); 48 if (found_it) { 49 /* Ensure no RCU iterators see it before re-initializing. */ 50 synchronize_rcu(); 51 INIT_LIST_HEAD(&thread->links); 52 } 53 } 54 55 void vdo_unregister_thread(struct thread_registry *registry) 56 { 57 struct registered_thread *thread; 58 bool found_it = false; 59 60 spin_lock(®istry->lock); 61 list_for_each_entry(thread, ®istry->links, links) { 62 if (thread->task == current) { 63 list_del_rcu(&thread->links); 64 found_it = true; 65 break; 66 } 67 } 68 spin_unlock(®istry->lock); 69 70 VDO_ASSERT_LOG_ONLY(found_it, "thread found in registry"); 71 if (found_it) { 72 /* Ensure no RCU iterators see it before re-initializing. */ 73 synchronize_rcu(); 74 INIT_LIST_HEAD(&thread->links); 75 } 76 } 77 78 const void *vdo_lookup_thread(struct thread_registry *registry) 79 { 80 struct registered_thread *thread; 81 const void *result = NULL; 82 83 rcu_read_lock(); 84 list_for_each_entry_rcu(thread, ®istry->links, links) { 85 if (thread->task == current) { 86 result = thread->pointer; 87 break; 88 } 89 } 90 rcu_read_unlock(); 91 92 return result; 93 } 94