struct trace_event      event;
        char                    *print_fmt;
        struct event_filter     *filter;
-       void                    *mod;
+       /*
+        * Static events can disappear with modules,
+        * where as dynamic ones need their own ref count.
+        */
+       union {
+               void                            *module;
+               atomic_t                        refcnt;
+       };
        void                    *data;
 
        /* See the TRACE_EVENT_FL_* flags above */
 #endif
 };
 
+#ifdef CONFIG_DYNAMIC_EVENTS
+bool trace_event_dyn_try_get_ref(struct trace_event_call *call);
+void trace_event_dyn_put_ref(struct trace_event_call *call);
+bool trace_event_dyn_busy(struct trace_event_call *call);
+#else
+static inline bool trace_event_dyn_try_get_ref(struct trace_event_call *call)
+{
+       /* Without DYNAMIC_EVENTS configured, nothing should be calling this */
+       return false;
+}
+static inline void trace_event_dyn_put_ref(struct trace_event_call *call)
+{
+}
+static inline bool trace_event_dyn_busy(struct trace_event_call *call)
+{
+       /* Nothing should call this without DYNAIMIC_EVENTS configured. */
+       return true;
+}
+#endif
+
+static inline bool trace_event_try_get_ref(struct trace_event_call *call)
+{
+       if (call->flags & TRACE_EVENT_FL_DYNAMIC)
+               return trace_event_dyn_try_get_ref(call);
+       else
+               return try_module_get(call->module);
+}
+
+static inline void trace_event_put_ref(struct trace_event_call *call)
+{
+       if (call->flags & TRACE_EVENT_FL_DYNAMIC)
+               trace_event_dyn_put_ref(call);
+       else
+               module_put(call->module);
+}
+
 #ifdef CONFIG_PERF_EVENTS
 static inline bool bpf_prog_array_valid(struct trace_event_call *call)
 {
 
                return false;
 
        event = container_of(trace_event, struct trace_event_call, event);
-       if (!event->mod)
+       if ((event->flags & TRACE_EVENT_FL_DYNAMIC) || !event->module)
                return false;
 
        /* Would rather have rodata, but this will suffice */
-       if (within_module_core(addr, event->mod))
+       if (within_module_core(addr, event->module))
                return true;
 
        return false;
 
 #include <linux/tracefs.h>
 
 #include "trace.h"
+#include "trace_output.h"      /* for trace_event_sem */
 #include "trace_dynevent.h"
 
 static DEFINE_MUTEX(dyn_event_ops_mutex);
 static LIST_HEAD(dyn_event_ops_list);
 
+bool trace_event_dyn_try_get_ref(struct trace_event_call *dyn_call)
+{
+       struct trace_event_call *call;
+       bool ret = false;
+
+       if (WARN_ON_ONCE(!(dyn_call->flags & TRACE_EVENT_FL_DYNAMIC)))
+               return false;
+
+       down_read(&trace_event_sem);
+       list_for_each_entry(call, &ftrace_events, list) {
+               if (call == dyn_call) {
+                       atomic_inc(&dyn_call->refcnt);
+                       ret = true;
+               }
+       }
+       up_read(&trace_event_sem);
+       return ret;
+}
+
+void trace_event_dyn_put_ref(struct trace_event_call *call)
+{
+       if (WARN_ON_ONCE(!(call->flags & TRACE_EVENT_FL_DYNAMIC)))
+               return;
+
+       if (WARN_ON_ONCE(atomic_read(&call->refcnt) <= 0)) {
+               atomic_set(&call->refcnt, 0);
+               return;
+       }
+
+       atomic_dec(&call->refcnt);
+}
+
+bool trace_event_dyn_busy(struct trace_event_call *call)
+{
+       return atomic_read(&call->refcnt) != 0;
+}
+
 int dyn_event_register(struct dyn_event_operations *ops)
 {
        if (!ops || !ops->create || !ops->show || !ops->is_busy ||
 
                }
        }
 out:
-       module_put(tp_event->mod);
+       trace_event_put_ref(tp_event);
 }
 
 static int perf_trace_event_open(struct perf_event *p_event)
        list_for_each_entry(tp_event, &ftrace_events, list) {
                if (tp_event->event.type == event_id &&
                    tp_event->class && tp_event->class->reg &&
-                   try_module_get(tp_event->mod)) {
+                   trace_event_try_get_ref(tp_event)) {
                        ret = perf_trace_event_init(tp_event, p_event);
                        if (ret)
-                               module_put(tp_event->mod);
+                               trace_event_put_ref(tp_event);
                        break;
                }
        }
 
                return ret;
 
        list_add(&call->list, &ftrace_events);
-       call->mod = mod;
+       if (call->flags & TRACE_EVENT_FL_DYNAMIC)
+               atomic_set(&call->refcnt, 0);
+       else
+               call->module = mod;
 
        return 0;
 }
 
        down_write(&trace_event_sem);
        list_for_each_entry_safe(call, p, &ftrace_events, list) {
-               if (call->mod == mod)
+               if ((call->flags & TRACE_EVENT_FL_DYNAMIC) || !call->module)
+                       continue;
+               if (call->module == mod)
                        __trace_remove_event_call(call);
        }
        up_write(&trace_event_sem);
        }
 
        /* Don't let event modules unload while in use */
-       ret = try_module_get(file->event_call->mod);
+       ret = trace_event_try_get_ref(file->event_call);
        if (!ret) {
                trace_array_put(tr);
                ret = -EBUSY;
 void trace_put_event_file(struct trace_event_file *file)
 {
        mutex_lock(&event_mutex);
-       module_put(file->event_call->mod);
+       trace_event_put_ref(file->event_call);
        mutex_unlock(&event_mutex);
 
        trace_array_put(file->tr);
        if (!edata->ref) {
                /* Remove the SOFT_MODE flag */
                __ftrace_event_enable_disable(edata->file, 0, 1);
-               module_put(edata->file->event_call->mod);
+               trace_event_put_ref(edata->file->event_call);
                kfree(edata);
        }
        return 0;
 
  out_reg:
        /* Don't let event modules unload while probe registered */
-       ret = try_module_get(file->event_call->mod);
+       ret = trace_event_try_get_ref(file->event_call);
        if (!ret) {
                ret = -EBUSY;
                goto out_free;
  out_disable:
        __ftrace_event_enable_disable(file, 0, 1);
  out_put:
-       module_put(file->event_call->mod);
+       trace_event_put_ref(file->event_call);
  out_free:
        kfree(data);
        goto out;
 
        list_for_each_entry(call, &ftrace_events, list) {
                /* Early boot up should not have any modules loaded */
-               if (WARN_ON_ONCE(call->mod))
+               if (!(call->flags & TRACE_EVENT_FL_DYNAMIC) &&
+                   WARN_ON_ONCE(call->module))
                        continue;
 
                ret = __trace_early_add_new_event(call, tr);
 
        int ret;
 
        if (se->ref)
-               ret = -EBUSY;
-       else {
-               ret = unregister_synth_event(se);
-               if (!ret) {
-                       dyn_event_remove(&se->devent);
-                       free_synth_event(se);
-               }
+               return -EBUSY;
+
+       if (trace_event_dyn_busy(&se->call))
+               return -EBUSY;
+
+       ret = unregister_synth_event(se);
+       if (!ret) {
+               dyn_event_remove(&se->devent);
+               free_synth_event(se);
        }
 
        return ret;
        if (event->ref)
                return -EBUSY;
 
+       if (trace_event_dyn_busy(&event->call))
+               return -EBUSY;
+
        ret = unregister_synth_event(event);
        if (ret)
                return ret;
 
        if (!data->ref) {
                /* Remove the SOFT_MODE flag */
                trace_event_enable_disable(enable_data->file, 0, 1);
-               module_put(enable_data->file->event_call->mod);
+               trace_event_put_ref(enable_data->file->event_call);
                trigger_data_free(data);
                kfree(enable_data);
        }
 
  out_reg:
        /* Don't let event modules unload while probe registered */
-       ret = try_module_get(event_enable_file->event_call->mod);
+       ret = trace_event_try_get_ref(event_enable_file->event_call);
        if (!ret) {
                ret = -EBUSY;
                goto out_free;
  out_disable:
        trace_event_enable_disable(event_enable_file, 0, 1);
  out_put:
-       module_put(event_enable_file->event_call->mod);
+       trace_event_put_ref(event_enable_file->event_call);
  out_free:
        if (cmd_ops->set_filter)
                cmd_ops->set_filter(NULL, trigger_data, NULL);
 
        if (trace_probe_is_enabled(&tk->tp))
                return -EBUSY;
 
+       /* If there's a reference to the dynamic event */
+       if (trace_event_dyn_busy(trace_probe_event_call(&tk->tp)))
+               return -EBUSY;
+
        /* Will fail if probe is being used by ftrace or perf */
        if (unregister_kprobe_event(tk))
                return -EBUSY;
 
        if (trace_probe_has_sibling(&tu->tp))
                goto unreg;
 
+       /* If there's a reference to the dynamic event */
+       if (trace_event_dyn_busy(trace_probe_event_call(&tu->tp)))
+               return -EBUSY;
+
        ret = unregister_uprobe_event(tu);
        if (ret)
                return ret;