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