tree_lookup.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Modules tree lookup
  4. *
  5. * Copyright (C) 2015 Peter Zijlstra
  6. * Copyright (C) 2015 Rusty Russell
  7. */
  8. #include <linux/module.h>
  9. #include <linux/rbtree_latch.h>
  10. #include "internal.h"
  11. /*
  12. * Use a latched RB-tree for __module_address(); this allows us to use
  13. * RCU-sched lookups of the address from any context.
  14. *
  15. * This is conditional on PERF_EVENTS || TRACING because those can really hit
  16. * __module_address() hard by doing a lot of stack unwinding; potentially from
  17. * NMI context.
  18. */
  19. static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n)
  20. {
  21. struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
  22. return (unsigned long)layout->base;
  23. }
  24. static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
  25. {
  26. struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
  27. return (unsigned long)layout->size;
  28. }
  29. static __always_inline bool
  30. mod_tree_less(struct latch_tree_node *a, struct latch_tree_node *b)
  31. {
  32. return __mod_tree_val(a) < __mod_tree_val(b);
  33. }
  34. static __always_inline int
  35. mod_tree_comp(void *key, struct latch_tree_node *n)
  36. {
  37. unsigned long val = (unsigned long)key;
  38. unsigned long start, end;
  39. start = __mod_tree_val(n);
  40. if (val < start)
  41. return -1;
  42. end = start + __mod_tree_size(n);
  43. if (val >= end)
  44. return 1;
  45. return 0;
  46. }
  47. static const struct latch_tree_ops mod_tree_ops = {
  48. .less = mod_tree_less,
  49. .comp = mod_tree_comp,
  50. };
  51. static noinline void __mod_tree_insert(struct mod_tree_node *node, struct mod_tree_root *tree)
  52. {
  53. latch_tree_insert(&node->node, &tree->root, &mod_tree_ops);
  54. }
  55. static void __mod_tree_remove(struct mod_tree_node *node, struct mod_tree_root *tree)
  56. {
  57. latch_tree_erase(&node->node, &tree->root, &mod_tree_ops);
  58. }
  59. /*
  60. * These modifications: insert, remove_init and remove; are serialized by the
  61. * module_mutex.
  62. */
  63. void mod_tree_insert(struct module *mod)
  64. {
  65. mod->core_layout.mtn.mod = mod;
  66. mod->init_layout.mtn.mod = mod;
  67. __mod_tree_insert(&mod->core_layout.mtn, &mod_tree);
  68. if (mod->init_layout.size)
  69. __mod_tree_insert(&mod->init_layout.mtn, &mod_tree);
  70. #ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC
  71. mod->data_layout.mtn.mod = mod;
  72. __mod_tree_insert(&mod->data_layout.mtn, &mod_data_tree);
  73. #endif
  74. }
  75. void mod_tree_remove_init(struct module *mod)
  76. {
  77. if (mod->init_layout.size)
  78. __mod_tree_remove(&mod->init_layout.mtn, &mod_tree);
  79. }
  80. void mod_tree_remove(struct module *mod)
  81. {
  82. __mod_tree_remove(&mod->core_layout.mtn, &mod_tree);
  83. mod_tree_remove_init(mod);
  84. #ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC
  85. __mod_tree_remove(&mod->data_layout.mtn, &mod_data_tree);
  86. #endif
  87. }
  88. struct module *mod_find(unsigned long addr, struct mod_tree_root *tree)
  89. {
  90. struct latch_tree_node *ltn;
  91. ltn = latch_tree_find((void *)addr, &tree->root, &mod_tree_ops);
  92. if (!ltn)
  93. return NULL;
  94. return container_of(ltn, struct mod_tree_node, node)->mod;
  95. }