1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2015 Peter Zijlstra
6 * Copyright (C) 2015 Rusty Russell
9 #include <linux/module.h>
10 #include <linux/rbtree_latch.h>
14 * Use a latched RB-tree for __module_address(); this allows us to use
15 * RCU-sched lookups of the address from any context.
17 * This is conditional on PERF_EVENTS || TRACING because those can really hit
18 * __module_address() hard by doing a lot of stack unwinding; potentially from
22 static __always_inline
unsigned long __mod_tree_val(struct latch_tree_node
*n
)
24 struct module_memory
*mod_mem
= container_of(n
, struct module_memory
, mtn
.node
);
26 return (unsigned long)mod_mem
->base
;
29 static __always_inline
unsigned long __mod_tree_size(struct latch_tree_node
*n
)
31 struct module_memory
*mod_mem
= container_of(n
, struct module_memory
, mtn
.node
);
33 return (unsigned long)mod_mem
->size
;
36 static __always_inline
bool
37 mod_tree_less(struct latch_tree_node
*a
, struct latch_tree_node
*b
)
39 return __mod_tree_val(a
) < __mod_tree_val(b
);
42 static __always_inline
int
43 mod_tree_comp(void *key
, struct latch_tree_node
*n
)
45 unsigned long val
= (unsigned long)key
;
46 unsigned long start
, end
;
48 start
= __mod_tree_val(n
);
52 end
= start
+ __mod_tree_size(n
);
59 static const struct latch_tree_ops mod_tree_ops
= {
60 .less
= mod_tree_less
,
61 .comp
= mod_tree_comp
,
64 static noinline
void __mod_tree_insert(struct mod_tree_node
*node
, struct mod_tree_root
*tree
)
66 latch_tree_insert(&node
->node
, &tree
->root
, &mod_tree_ops
);
69 static void __mod_tree_remove(struct mod_tree_node
*node
, struct mod_tree_root
*tree
)
71 latch_tree_erase(&node
->node
, &tree
->root
, &mod_tree_ops
);
75 * These modifications: insert, remove_init and remove; are serialized by the
78 void mod_tree_insert(struct module
*mod
)
80 for_each_mod_mem_type(type
) {
81 mod
->mem
[type
].mtn
.mod
= mod
;
82 if (mod
->mem
[type
].size
)
83 __mod_tree_insert(&mod
->mem
[type
].mtn
, &mod_tree
);
87 void mod_tree_remove_init(struct module
*mod
)
89 for_class_mod_mem_type(type
, init
) {
90 if (mod
->mem
[type
].size
)
91 __mod_tree_remove(&mod
->mem
[type
].mtn
, &mod_tree
);
95 void mod_tree_remove(struct module
*mod
)
97 for_each_mod_mem_type(type
) {
98 if (mod
->mem
[type
].size
)
99 __mod_tree_remove(&mod
->mem
[type
].mtn
, &mod_tree
);
103 struct module
*mod_find(unsigned long addr
, struct mod_tree_root
*tree
)
105 struct latch_tree_node
*ltn
;
107 ltn
= latch_tree_find((void *)addr
, &tree
->root
, &mod_tree_ops
);
111 return container_of(ltn
, struct mod_tree_node
, node
)->mod
;