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 18void 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. */ 25void 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 55void 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 78const 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