struct codetag_type_desc {
        const char *section;
        size_t tag_size;
+       void (*module_load)(struct codetag_type *cttype,
+                           struct codetag_module *cmod);
+       void (*module_unload)(struct codetag_type *cttype,
+                             struct codetag_module *cmod);
 };
 
 struct codetag_iterator {
 struct codetag_type *
 codetag_register_type(const struct codetag_type_desc *desc);
 
+#if defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES)
+void codetag_load_module(struct module *mod);
+void codetag_unload_module(struct module *mod);
+#else
+static inline void codetag_load_module(struct module *mod) {}
+static inline void codetag_unload_module(struct module *mod) {}
+#endif
+
 #endif /* _LINUX_CODETAG_H */
 
 {
        DECLARE_SEQ_BUF(sb, KSYM_NAME_LEN);
        const char *buf;
+       void *ret;
 
        seq_buf_printf(&sb, "%s%s", prefix, name);
        if (seq_buf_has_overflowed(&sb))
                return NULL;
 
        buf = seq_buf_str(&sb);
-       return mod ?
+       preempt_disable();
+       ret = mod ?
                (void *)find_kallsyms_symbol_value(mod, buf) :
                (void *)kallsyms_lookup_name(buf);
+       preempt_enable();
+
+       return ret;
 }
 
 static struct codetag_range get_section_range(struct module *mod,
 
        down_write(&cttype->mod_lock);
        err = idr_alloc(&cttype->mod_idr, cmod, 0, 0, GFP_KERNEL);
-       if (err >= 0)
+       if (err >= 0) {
                cttype->count += range_size(cttype, &range);
+               if (cttype->desc.module_load)
+                       cttype->desc.module_load(cttype, cmod);
+       }
        up_write(&cttype->mod_lock);
 
        if (err < 0) {
        return 0;
 }
 
+void codetag_load_module(struct module *mod)
+{
+       struct codetag_type *cttype;
+
+       if (!mod)
+               return;
+
+       mutex_lock(&codetag_lock);
+       list_for_each_entry(cttype, &codetag_types, link)
+               codetag_module_init(cttype, mod);
+       mutex_unlock(&codetag_lock);
+}
+
+void codetag_unload_module(struct module *mod)
+{
+       struct codetag_type *cttype;
+
+       if (!mod)
+               return;
+
+       mutex_lock(&codetag_lock);
+       list_for_each_entry(cttype, &codetag_types, link) {
+               struct codetag_module *found = NULL;
+               struct codetag_module *cmod;
+               unsigned long mod_id, tmp;
+
+               down_write(&cttype->mod_lock);
+               idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, mod_id) {
+                       if (cmod->mod && cmod->mod == mod) {
+                               found = cmod;
+                               break;
+                       }
+               }
+               if (found) {
+                       if (cttype->desc.module_unload)
+                               cttype->desc.module_unload(cttype, cmod);
+
+                       cttype->count -= range_size(cttype, &cmod->range);
+                       idr_remove(&cttype->mod_idr, mod_id);
+                       kfree(cmod);
+               }
+               up_write(&cttype->mod_lock);
+       }
+       mutex_unlock(&codetag_lock);
+}
+
 #else /* CONFIG_MODULES */
 static int codetag_module_init(struct codetag_type *cttype, struct module *mod) { return 0; }
 #endif /* CONFIG_MODULES */