tree_lookup.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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_memory *mod_mem = container_of(n, struct module_memory, mtn.node);
  22. return (unsigned long)mod_mem->base;
  23. }
  24. static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
  25. {
  26. struct module_memory *mod_mem = container_of(n, struct module_memory, mtn.node);
  27. return (unsigned long)mod_mem->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. for_each_mod_mem_type(type) {
  66. mod->mem[type].mtn.mod = mod;
  67. if (mod->mem[type].size)
  68. __mod_tree_insert(&mod->mem[type].mtn, &mod_tree);
  69. }
  70. }
  71. void mod_tree_remove_init(struct module *mod)
  72. {
  73. for_class_mod_mem_type(type, init) {
  74. if (mod->mem[type].size)
  75. __mod_tree_remove(&mod->mem[type].mtn, &mod_tree);
  76. }
  77. }
  78. void mod_tree_remove(struct module *mod)
  79. {
  80. for_each_mod_mem_type(type) {
  81. if (mod->mem[type].size)
  82. __mod_tree_remove(&mod->mem[type].mtn, &mod_tree);
  83. }
  84. }
  85. struct module *mod_find(unsigned long addr, struct mod_tree_root *tree)
  86. {
  87. struct latch_tree_node *ltn;
  88. ltn = latch_tree_find((void *)addr, &tree->root, &mod_tree_ops);
  89. if (!ltn)
  90. return NULL;
  91. return container_of(ltn, struct mod_tree_node, node)->mod;
  92. }