1916cc516SSuren Baghdasaryan // SPDX-License-Identifier: GPL-2.0-only
2916cc516SSuren Baghdasaryan #include <linux/codetag.h>
3916cc516SSuren Baghdasaryan #include <linux/idr.h>
4916cc516SSuren Baghdasaryan #include <linux/kallsyms.h>
5916cc516SSuren Baghdasaryan #include <linux/module.h>
6916cc516SSuren Baghdasaryan #include <linux/seq_buf.h>
7916cc516SSuren Baghdasaryan #include <linux/slab.h>
847a92dfbSSuren Baghdasaryan #include <linux/vmalloc.h>
9916cc516SSuren Baghdasaryan
10916cc516SSuren Baghdasaryan struct codetag_type {
11916cc516SSuren Baghdasaryan struct list_head link;
12916cc516SSuren Baghdasaryan unsigned int count;
13916cc516SSuren Baghdasaryan struct idr mod_idr;
14916cc516SSuren Baghdasaryan struct rw_semaphore mod_lock; /* protects mod_idr */
15916cc516SSuren Baghdasaryan struct codetag_type_desc desc;
16916cc516SSuren Baghdasaryan };
17916cc516SSuren Baghdasaryan
18916cc516SSuren Baghdasaryan struct codetag_range {
19916cc516SSuren Baghdasaryan struct codetag *start;
20916cc516SSuren Baghdasaryan struct codetag *stop;
21916cc516SSuren Baghdasaryan };
22916cc516SSuren Baghdasaryan
23916cc516SSuren Baghdasaryan struct codetag_module {
24916cc516SSuren Baghdasaryan struct module *mod;
25916cc516SSuren Baghdasaryan struct codetag_range range;
26916cc516SSuren Baghdasaryan };
27916cc516SSuren Baghdasaryan
28916cc516SSuren Baghdasaryan static DEFINE_MUTEX(codetag_lock);
29916cc516SSuren Baghdasaryan static LIST_HEAD(codetag_types);
30916cc516SSuren Baghdasaryan
codetag_lock_module_list(struct codetag_type * cttype,bool lock)31916cc516SSuren Baghdasaryan void codetag_lock_module_list(struct codetag_type *cttype, bool lock)
32916cc516SSuren Baghdasaryan {
33916cc516SSuren Baghdasaryan if (lock)
34916cc516SSuren Baghdasaryan down_read(&cttype->mod_lock);
35916cc516SSuren Baghdasaryan else
36916cc516SSuren Baghdasaryan up_read(&cttype->mod_lock);
37916cc516SSuren Baghdasaryan }
38916cc516SSuren Baghdasaryan
codetag_trylock_module_list(struct codetag_type * cttype)391438d349SSuren Baghdasaryan bool codetag_trylock_module_list(struct codetag_type *cttype)
401438d349SSuren Baghdasaryan {
411438d349SSuren Baghdasaryan return down_read_trylock(&cttype->mod_lock) != 0;
421438d349SSuren Baghdasaryan }
431438d349SSuren Baghdasaryan
codetag_get_ct_iter(struct codetag_type * cttype)44916cc516SSuren Baghdasaryan struct codetag_iterator codetag_get_ct_iter(struct codetag_type *cttype)
45916cc516SSuren Baghdasaryan {
46916cc516SSuren Baghdasaryan struct codetag_iterator iter = {
47916cc516SSuren Baghdasaryan .cttype = cttype,
48916cc516SSuren Baghdasaryan .cmod = NULL,
49916cc516SSuren Baghdasaryan .mod_id = 0,
50916cc516SSuren Baghdasaryan .ct = NULL,
51916cc516SSuren Baghdasaryan };
52916cc516SSuren Baghdasaryan
53916cc516SSuren Baghdasaryan return iter;
54916cc516SSuren Baghdasaryan }
55916cc516SSuren Baghdasaryan
get_first_module_ct(struct codetag_module * cmod)56916cc516SSuren Baghdasaryan static inline struct codetag *get_first_module_ct(struct codetag_module *cmod)
57916cc516SSuren Baghdasaryan {
58916cc516SSuren Baghdasaryan return cmod->range.start < cmod->range.stop ? cmod->range.start : NULL;
59916cc516SSuren Baghdasaryan }
60916cc516SSuren Baghdasaryan
61916cc516SSuren Baghdasaryan static inline
get_next_module_ct(struct codetag_iterator * iter)62916cc516SSuren Baghdasaryan struct codetag *get_next_module_ct(struct codetag_iterator *iter)
63916cc516SSuren Baghdasaryan {
64916cc516SSuren Baghdasaryan struct codetag *res = (struct codetag *)
65916cc516SSuren Baghdasaryan ((char *)iter->ct + iter->cttype->desc.tag_size);
66916cc516SSuren Baghdasaryan
67916cc516SSuren Baghdasaryan return res < iter->cmod->range.stop ? res : NULL;
68916cc516SSuren Baghdasaryan }
69916cc516SSuren Baghdasaryan
codetag_next_ct(struct codetag_iterator * iter)70916cc516SSuren Baghdasaryan struct codetag *codetag_next_ct(struct codetag_iterator *iter)
71916cc516SSuren Baghdasaryan {
72916cc516SSuren Baghdasaryan struct codetag_type *cttype = iter->cttype;
73916cc516SSuren Baghdasaryan struct codetag_module *cmod;
74916cc516SSuren Baghdasaryan struct codetag *ct;
75916cc516SSuren Baghdasaryan
76916cc516SSuren Baghdasaryan lockdep_assert_held(&cttype->mod_lock);
77916cc516SSuren Baghdasaryan
78916cc516SSuren Baghdasaryan if (unlikely(idr_is_empty(&cttype->mod_idr)))
79916cc516SSuren Baghdasaryan return NULL;
80916cc516SSuren Baghdasaryan
81916cc516SSuren Baghdasaryan ct = NULL;
82916cc516SSuren Baghdasaryan while (true) {
83916cc516SSuren Baghdasaryan cmod = idr_find(&cttype->mod_idr, iter->mod_id);
84916cc516SSuren Baghdasaryan
85916cc516SSuren Baghdasaryan /* If module was removed move to the next one */
86916cc516SSuren Baghdasaryan if (!cmod)
87916cc516SSuren Baghdasaryan cmod = idr_get_next_ul(&cttype->mod_idr,
88916cc516SSuren Baghdasaryan &iter->mod_id);
89916cc516SSuren Baghdasaryan
90916cc516SSuren Baghdasaryan /* Exit if no more modules */
91916cc516SSuren Baghdasaryan if (!cmod)
92916cc516SSuren Baghdasaryan break;
93916cc516SSuren Baghdasaryan
94916cc516SSuren Baghdasaryan if (cmod != iter->cmod) {
95916cc516SSuren Baghdasaryan iter->cmod = cmod;
96916cc516SSuren Baghdasaryan ct = get_first_module_ct(cmod);
97916cc516SSuren Baghdasaryan } else
98916cc516SSuren Baghdasaryan ct = get_next_module_ct(iter);
99916cc516SSuren Baghdasaryan
100916cc516SSuren Baghdasaryan if (ct)
101916cc516SSuren Baghdasaryan break;
102916cc516SSuren Baghdasaryan
103916cc516SSuren Baghdasaryan iter->mod_id++;
104916cc516SSuren Baghdasaryan }
105916cc516SSuren Baghdasaryan
106916cc516SSuren Baghdasaryan iter->ct = ct;
107916cc516SSuren Baghdasaryan return ct;
108916cc516SSuren Baghdasaryan }
109916cc516SSuren Baghdasaryan
codetag_to_text(struct seq_buf * out,struct codetag * ct)110916cc516SSuren Baghdasaryan void codetag_to_text(struct seq_buf *out, struct codetag *ct)
111916cc516SSuren Baghdasaryan {
112916cc516SSuren Baghdasaryan if (ct->modname)
113916cc516SSuren Baghdasaryan seq_buf_printf(out, "%s:%u [%s] func:%s",
114916cc516SSuren Baghdasaryan ct->filename, ct->lineno,
115916cc516SSuren Baghdasaryan ct->modname, ct->function);
116916cc516SSuren Baghdasaryan else
117916cc516SSuren Baghdasaryan seq_buf_printf(out, "%s:%u func:%s",
118916cc516SSuren Baghdasaryan ct->filename, ct->lineno, ct->function);
119916cc516SSuren Baghdasaryan }
120916cc516SSuren Baghdasaryan
range_size(const struct codetag_type * cttype,const struct codetag_range * range)121916cc516SSuren Baghdasaryan static inline size_t range_size(const struct codetag_type *cttype,
122916cc516SSuren Baghdasaryan const struct codetag_range *range)
123916cc516SSuren Baghdasaryan {
124916cc516SSuren Baghdasaryan return ((char *)range->stop - (char *)range->start) /
125916cc516SSuren Baghdasaryan cttype->desc.tag_size;
126916cc516SSuren Baghdasaryan }
127916cc516SSuren Baghdasaryan
get_symbol(struct module * mod,const char * prefix,const char * name)128916cc516SSuren Baghdasaryan static void *get_symbol(struct module *mod, const char *prefix, const char *name)
129916cc516SSuren Baghdasaryan {
130916cc516SSuren Baghdasaryan DECLARE_SEQ_BUF(sb, KSYM_NAME_LEN);
131916cc516SSuren Baghdasaryan const char *buf;
132a4735739SSuren Baghdasaryan void *ret;
133916cc516SSuren Baghdasaryan
134916cc516SSuren Baghdasaryan seq_buf_printf(&sb, "%s%s", prefix, name);
135916cc516SSuren Baghdasaryan if (seq_buf_has_overflowed(&sb))
136916cc516SSuren Baghdasaryan return NULL;
137916cc516SSuren Baghdasaryan
138916cc516SSuren Baghdasaryan buf = seq_buf_str(&sb);
139a4735739SSuren Baghdasaryan preempt_disable();
140a4735739SSuren Baghdasaryan ret = mod ?
141916cc516SSuren Baghdasaryan (void *)find_kallsyms_symbol_value(mod, buf) :
142916cc516SSuren Baghdasaryan (void *)kallsyms_lookup_name(buf);
143a4735739SSuren Baghdasaryan preempt_enable();
144a4735739SSuren Baghdasaryan
145a4735739SSuren Baghdasaryan return ret;
146916cc516SSuren Baghdasaryan }
147916cc516SSuren Baghdasaryan
get_section_range(struct module * mod,const char * section)148916cc516SSuren Baghdasaryan static struct codetag_range get_section_range(struct module *mod,
149916cc516SSuren Baghdasaryan const char *section)
150916cc516SSuren Baghdasaryan {
151916cc516SSuren Baghdasaryan return (struct codetag_range) {
1524835f747SSuren Baghdasaryan get_symbol(mod, CODETAG_SECTION_START_PREFIX, section),
1534835f747SSuren Baghdasaryan get_symbol(mod, CODETAG_SECTION_STOP_PREFIX, section),
154916cc516SSuren Baghdasaryan };
155916cc516SSuren Baghdasaryan }
156916cc516SSuren Baghdasaryan
get_mod_name(__maybe_unused struct module * mod)157052a45c1SSuren Baghdasaryan static const char *get_mod_name(__maybe_unused struct module *mod)
158052a45c1SSuren Baghdasaryan {
159052a45c1SSuren Baghdasaryan #ifdef CONFIG_MODULES
160052a45c1SSuren Baghdasaryan if (mod)
161052a45c1SSuren Baghdasaryan return mod->name;
162052a45c1SSuren Baghdasaryan #endif
163052a45c1SSuren Baghdasaryan return "(built-in)";
164052a45c1SSuren Baghdasaryan }
165052a45c1SSuren Baghdasaryan
codetag_module_init(struct codetag_type * cttype,struct module * mod)166916cc516SSuren Baghdasaryan static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
167916cc516SSuren Baghdasaryan {
168916cc516SSuren Baghdasaryan struct codetag_range range;
169916cc516SSuren Baghdasaryan struct codetag_module *cmod;
170916cc516SSuren Baghdasaryan int err;
171916cc516SSuren Baghdasaryan
172916cc516SSuren Baghdasaryan range = get_section_range(mod, cttype->desc.section);
173916cc516SSuren Baghdasaryan if (!range.start || !range.stop) {
174916cc516SSuren Baghdasaryan pr_warn("Failed to load code tags of type %s from the module %s\n",
175052a45c1SSuren Baghdasaryan cttype->desc.section, get_mod_name(mod));
176916cc516SSuren Baghdasaryan return -EINVAL;
177916cc516SSuren Baghdasaryan }
178916cc516SSuren Baghdasaryan
179916cc516SSuren Baghdasaryan /* Ignore empty ranges */
180916cc516SSuren Baghdasaryan if (range.start == range.stop)
181916cc516SSuren Baghdasaryan return 0;
182916cc516SSuren Baghdasaryan
183916cc516SSuren Baghdasaryan BUG_ON(range.start > range.stop);
184916cc516SSuren Baghdasaryan
185916cc516SSuren Baghdasaryan cmod = kmalloc(sizeof(*cmod), GFP_KERNEL);
186916cc516SSuren Baghdasaryan if (unlikely(!cmod))
187916cc516SSuren Baghdasaryan return -ENOMEM;
188916cc516SSuren Baghdasaryan
189916cc516SSuren Baghdasaryan cmod->mod = mod;
190916cc516SSuren Baghdasaryan cmod->range = range;
191916cc516SSuren Baghdasaryan
192916cc516SSuren Baghdasaryan down_write(&cttype->mod_lock);
193916cc516SSuren Baghdasaryan err = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
194a4735739SSuren Baghdasaryan if (err >= 0) {
195916cc516SSuren Baghdasaryan cttype->count += range_size(cttype, &range);
196a4735739SSuren Baghdasaryan if (cttype->desc.module_load)
197*12ca42c2SSuren Baghdasaryan cttype->desc.module_load(mod, range.start, range.stop);
198a4735739SSuren Baghdasaryan }
199916cc516SSuren Baghdasaryan up_write(&cttype->mod_lock);
200916cc516SSuren Baghdasaryan
201916cc516SSuren Baghdasaryan if (err < 0) {
202916cc516SSuren Baghdasaryan kfree(cmod);
203916cc516SSuren Baghdasaryan return err;
204916cc516SSuren Baghdasaryan }
205916cc516SSuren Baghdasaryan
206916cc516SSuren Baghdasaryan return 0;
207916cc516SSuren Baghdasaryan }
208916cc516SSuren Baghdasaryan
209052a45c1SSuren Baghdasaryan #ifdef CONFIG_MODULES
2100db6f8d7SSuren Baghdasaryan #define CODETAG_SECTION_PREFIX ".codetag."
2110db6f8d7SSuren Baghdasaryan
2120db6f8d7SSuren Baghdasaryan /* Some codetag types need a separate module section */
codetag_needs_module_section(struct module * mod,const char * name,unsigned long size)2130db6f8d7SSuren Baghdasaryan bool codetag_needs_module_section(struct module *mod, const char *name,
2140db6f8d7SSuren Baghdasaryan unsigned long size)
2150db6f8d7SSuren Baghdasaryan {
2160db6f8d7SSuren Baghdasaryan const char *type_name;
2170db6f8d7SSuren Baghdasaryan struct codetag_type *cttype;
2180db6f8d7SSuren Baghdasaryan bool ret = false;
2190db6f8d7SSuren Baghdasaryan
2200db6f8d7SSuren Baghdasaryan if (strncmp(name, CODETAG_SECTION_PREFIX, strlen(CODETAG_SECTION_PREFIX)))
2210db6f8d7SSuren Baghdasaryan return false;
2220db6f8d7SSuren Baghdasaryan
2230db6f8d7SSuren Baghdasaryan type_name = name + strlen(CODETAG_SECTION_PREFIX);
2240db6f8d7SSuren Baghdasaryan mutex_lock(&codetag_lock);
2250db6f8d7SSuren Baghdasaryan list_for_each_entry(cttype, &codetag_types, link) {
2260db6f8d7SSuren Baghdasaryan if (strcmp(type_name, cttype->desc.section) == 0) {
2270db6f8d7SSuren Baghdasaryan if (!cttype->desc.needs_section_mem)
2280db6f8d7SSuren Baghdasaryan break;
2290db6f8d7SSuren Baghdasaryan
2300db6f8d7SSuren Baghdasaryan down_write(&cttype->mod_lock);
2310db6f8d7SSuren Baghdasaryan ret = cttype->desc.needs_section_mem(mod, size);
2320db6f8d7SSuren Baghdasaryan up_write(&cttype->mod_lock);
2330db6f8d7SSuren Baghdasaryan break;
2340db6f8d7SSuren Baghdasaryan }
2350db6f8d7SSuren Baghdasaryan }
2360db6f8d7SSuren Baghdasaryan mutex_unlock(&codetag_lock);
2370db6f8d7SSuren Baghdasaryan
2380db6f8d7SSuren Baghdasaryan return ret;
2390db6f8d7SSuren Baghdasaryan }
2400db6f8d7SSuren Baghdasaryan
codetag_alloc_module_section(struct module * mod,const char * name,unsigned long size,unsigned int prepend,unsigned long align)2410db6f8d7SSuren Baghdasaryan void *codetag_alloc_module_section(struct module *mod, const char *name,
2420db6f8d7SSuren Baghdasaryan unsigned long size, unsigned int prepend,
2430db6f8d7SSuren Baghdasaryan unsigned long align)
2440db6f8d7SSuren Baghdasaryan {
2450db6f8d7SSuren Baghdasaryan const char *type_name = name + strlen(CODETAG_SECTION_PREFIX);
2460db6f8d7SSuren Baghdasaryan struct codetag_type *cttype;
2470db6f8d7SSuren Baghdasaryan void *ret = ERR_PTR(-EINVAL);
2480db6f8d7SSuren Baghdasaryan
2490db6f8d7SSuren Baghdasaryan mutex_lock(&codetag_lock);
2500db6f8d7SSuren Baghdasaryan list_for_each_entry(cttype, &codetag_types, link) {
2510db6f8d7SSuren Baghdasaryan if (strcmp(type_name, cttype->desc.section) == 0) {
2520db6f8d7SSuren Baghdasaryan if (WARN_ON(!cttype->desc.alloc_section_mem))
2530db6f8d7SSuren Baghdasaryan break;
2540db6f8d7SSuren Baghdasaryan
2550db6f8d7SSuren Baghdasaryan down_write(&cttype->mod_lock);
2560db6f8d7SSuren Baghdasaryan ret = cttype->desc.alloc_section_mem(mod, size, prepend, align);
2570db6f8d7SSuren Baghdasaryan up_write(&cttype->mod_lock);
2580db6f8d7SSuren Baghdasaryan break;
2590db6f8d7SSuren Baghdasaryan }
2600db6f8d7SSuren Baghdasaryan }
2610db6f8d7SSuren Baghdasaryan mutex_unlock(&codetag_lock);
2620db6f8d7SSuren Baghdasaryan
2630db6f8d7SSuren Baghdasaryan return ret;
2640db6f8d7SSuren Baghdasaryan }
2650db6f8d7SSuren Baghdasaryan
codetag_free_module_sections(struct module * mod)2660db6f8d7SSuren Baghdasaryan void codetag_free_module_sections(struct module *mod)
2670db6f8d7SSuren Baghdasaryan {
2680db6f8d7SSuren Baghdasaryan struct codetag_type *cttype;
2690db6f8d7SSuren Baghdasaryan
2700db6f8d7SSuren Baghdasaryan mutex_lock(&codetag_lock);
2710db6f8d7SSuren Baghdasaryan list_for_each_entry(cttype, &codetag_types, link) {
2720db6f8d7SSuren Baghdasaryan if (!cttype->desc.free_section_mem)
2730db6f8d7SSuren Baghdasaryan continue;
2740db6f8d7SSuren Baghdasaryan
2750db6f8d7SSuren Baghdasaryan down_write(&cttype->mod_lock);
2760db6f8d7SSuren Baghdasaryan cttype->desc.free_section_mem(mod, false);
2770db6f8d7SSuren Baghdasaryan up_write(&cttype->mod_lock);
2780db6f8d7SSuren Baghdasaryan }
2790db6f8d7SSuren Baghdasaryan mutex_unlock(&codetag_lock);
2800db6f8d7SSuren Baghdasaryan }
2810db6f8d7SSuren Baghdasaryan
codetag_module_replaced(struct module * mod,struct module * new_mod)2820db6f8d7SSuren Baghdasaryan void codetag_module_replaced(struct module *mod, struct module *new_mod)
2830db6f8d7SSuren Baghdasaryan {
2840db6f8d7SSuren Baghdasaryan struct codetag_type *cttype;
2850db6f8d7SSuren Baghdasaryan
2860db6f8d7SSuren Baghdasaryan mutex_lock(&codetag_lock);
2870db6f8d7SSuren Baghdasaryan list_for_each_entry(cttype, &codetag_types, link) {
2880db6f8d7SSuren Baghdasaryan if (!cttype->desc.module_replaced)
2890db6f8d7SSuren Baghdasaryan continue;
2900db6f8d7SSuren Baghdasaryan
2910db6f8d7SSuren Baghdasaryan down_write(&cttype->mod_lock);
2920db6f8d7SSuren Baghdasaryan cttype->desc.module_replaced(mod, new_mod);
2930db6f8d7SSuren Baghdasaryan up_write(&cttype->mod_lock);
2940db6f8d7SSuren Baghdasaryan }
2950db6f8d7SSuren Baghdasaryan mutex_unlock(&codetag_lock);
2960db6f8d7SSuren Baghdasaryan }
2970db6f8d7SSuren Baghdasaryan
codetag_load_module(struct module * mod)298a4735739SSuren Baghdasaryan void codetag_load_module(struct module *mod)
299a4735739SSuren Baghdasaryan {
300a4735739SSuren Baghdasaryan struct codetag_type *cttype;
301a4735739SSuren Baghdasaryan
302a4735739SSuren Baghdasaryan if (!mod)
303a4735739SSuren Baghdasaryan return;
304a4735739SSuren Baghdasaryan
305a4735739SSuren Baghdasaryan mutex_lock(&codetag_lock);
306a4735739SSuren Baghdasaryan list_for_each_entry(cttype, &codetag_types, link)
307a4735739SSuren Baghdasaryan codetag_module_init(cttype, mod);
308a4735739SSuren Baghdasaryan mutex_unlock(&codetag_lock);
309a4735739SSuren Baghdasaryan }
310a4735739SSuren Baghdasaryan
codetag_unload_module(struct module * mod)3110db6f8d7SSuren Baghdasaryan void codetag_unload_module(struct module *mod)
312a4735739SSuren Baghdasaryan {
313a4735739SSuren Baghdasaryan struct codetag_type *cttype;
314a4735739SSuren Baghdasaryan
315a4735739SSuren Baghdasaryan if (!mod)
3160db6f8d7SSuren Baghdasaryan return;
317a4735739SSuren Baghdasaryan
318dc783ba4SFlorian Westphal /* await any module's kfree_rcu() operations to complete */
319dc783ba4SFlorian Westphal kvfree_rcu_barrier();
320dc783ba4SFlorian Westphal
321a4735739SSuren Baghdasaryan mutex_lock(&codetag_lock);
322a4735739SSuren Baghdasaryan list_for_each_entry(cttype, &codetag_types, link) {
323a4735739SSuren Baghdasaryan struct codetag_module *found = NULL;
324a4735739SSuren Baghdasaryan struct codetag_module *cmod;
325a4735739SSuren Baghdasaryan unsigned long mod_id, tmp;
326a4735739SSuren Baghdasaryan
327a4735739SSuren Baghdasaryan down_write(&cttype->mod_lock);
328a4735739SSuren Baghdasaryan idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, mod_id) {
329a4735739SSuren Baghdasaryan if (cmod->mod && cmod->mod == mod) {
330a4735739SSuren Baghdasaryan found = cmod;
331a4735739SSuren Baghdasaryan break;
332a4735739SSuren Baghdasaryan }
333a4735739SSuren Baghdasaryan }
334a4735739SSuren Baghdasaryan if (found) {
335a4735739SSuren Baghdasaryan if (cttype->desc.module_unload)
336*12ca42c2SSuren Baghdasaryan cttype->desc.module_unload(cmod->mod,
337*12ca42c2SSuren Baghdasaryan cmod->range.start, cmod->range.stop);
338a4735739SSuren Baghdasaryan
339a4735739SSuren Baghdasaryan cttype->count -= range_size(cttype, &cmod->range);
340a4735739SSuren Baghdasaryan idr_remove(&cttype->mod_idr, mod_id);
341a4735739SSuren Baghdasaryan kfree(cmod);
342a4735739SSuren Baghdasaryan }
343a4735739SSuren Baghdasaryan up_write(&cttype->mod_lock);
3440db6f8d7SSuren Baghdasaryan if (found && cttype->desc.free_section_mem)
3450db6f8d7SSuren Baghdasaryan cttype->desc.free_section_mem(mod, true);
346a4735739SSuren Baghdasaryan }
347a4735739SSuren Baghdasaryan mutex_unlock(&codetag_lock);
348a4735739SSuren Baghdasaryan }
349916cc516SSuren Baghdasaryan #endif /* CONFIG_MODULES */
350916cc516SSuren Baghdasaryan
351916cc516SSuren Baghdasaryan struct codetag_type *
codetag_register_type(const struct codetag_type_desc * desc)352916cc516SSuren Baghdasaryan codetag_register_type(const struct codetag_type_desc *desc)
353916cc516SSuren Baghdasaryan {
354916cc516SSuren Baghdasaryan struct codetag_type *cttype;
355916cc516SSuren Baghdasaryan int err;
356916cc516SSuren Baghdasaryan
357916cc516SSuren Baghdasaryan BUG_ON(desc->tag_size <= 0);
358916cc516SSuren Baghdasaryan
359916cc516SSuren Baghdasaryan cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);
360916cc516SSuren Baghdasaryan if (unlikely(!cttype))
361916cc516SSuren Baghdasaryan return ERR_PTR(-ENOMEM);
362916cc516SSuren Baghdasaryan
363916cc516SSuren Baghdasaryan cttype->desc = *desc;
364916cc516SSuren Baghdasaryan idr_init(&cttype->mod_idr);
365916cc516SSuren Baghdasaryan init_rwsem(&cttype->mod_lock);
366916cc516SSuren Baghdasaryan
367916cc516SSuren Baghdasaryan err = codetag_module_init(cttype, NULL);
368916cc516SSuren Baghdasaryan if (unlikely(err)) {
369916cc516SSuren Baghdasaryan kfree(cttype);
370916cc516SSuren Baghdasaryan return ERR_PTR(err);
371916cc516SSuren Baghdasaryan }
372916cc516SSuren Baghdasaryan
373916cc516SSuren Baghdasaryan mutex_lock(&codetag_lock);
374916cc516SSuren Baghdasaryan list_add_tail(&cttype->link, &codetag_types);
375916cc516SSuren Baghdasaryan mutex_unlock(&codetag_lock);
376916cc516SSuren Baghdasaryan
377916cc516SSuren Baghdasaryan return cttype;
378916cc516SSuren Baghdasaryan }
379