thread-registry.c 2.2 KB

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