94 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright 2023 Red Hat4 */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 in15 * 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