From: Wen Yang <[email protected]>

rv_react() is exported to modules, but the reactor registration helpers
are not.  Export them with EXPORT_SYMBOL_GPL() so reactor modules and
the tristate KUnit test module can register and unregister reactors
without hitting undefined symbol errors at link time(modpost).

Commit 3d3800b4f7f4 ("rv: Remove reactor's reference counter") noted
that if module-based reactors are supported, try_module_get()/module_put()
should be used. Add struct module *owner to struct rv_reactor so a module
cat set owner = THIS_MODULE; pin the module in monitor_swap_reactors_gingle()
and release it when a monitor detaches or is unregistered.

In-tree reactors leave owner = NULL and are unaffected.

Reviewed-by: Gabriele Monaco <[email protected]>
Signed-off-by: Wen Yang <[email protected]>
---
 include/linux/rv.h            |  3 +++
 kernel/trace/rv/rv.c          |  5 +++++
 kernel/trace/rv/rv_reactors.c | 38 +++++++++++++++++++++++++++++------
 3 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/include/linux/rv.h b/include/linux/rv.h
index 541ba404926a..ff3289ba4f02 100644
--- a/include/linux/rv.h
+++ b/include/linux/rv.h
@@ -128,10 +128,13 @@ union rv_task_monitor {
 };
 
 #ifdef CONFIG_RV_REACTORS
+struct module;
+
 struct rv_reactor {
        const char              *name;
        const char              *description;
        __printf(1, 0) void     (*react)(const char *msg, va_list args);
+       struct module           *owner;
        struct list_head        list;
 };
 #endif
diff --git a/kernel/trace/rv/rv.c b/kernel/trace/rv/rv.c
index 29f155c6968b..458b17c005b3 100644
--- a/kernel/trace/rv/rv.c
+++ b/kernel/trace/rv/rv.c
@@ -803,6 +803,11 @@ int rv_unregister_monitor(struct rv_monitor *monitor)
        guard(mutex)(&rv_interface_lock);
 
        rv_disable_monitor(monitor);
+#ifdef CONFIG_RV_REACTORS
+       if (monitor->reactor)
+               module_put(monitor->reactor->owner);
+
+#endif
        list_del(&monitor->list);
        destroy_monitor_dir(monitor);
 
diff --git a/kernel/trace/rv/rv_reactors.c b/kernel/trace/rv/rv_reactors.c
index ff7d478227c3..136eb7f47c4a 100644
--- a/kernel/trace/rv/rv_reactors.c
+++ b/kernel/trace/rv/rv_reactors.c
@@ -62,6 +62,7 @@
  */
 
 #include <linux/lockdep.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 
 #include "rv.h"
@@ -159,7 +160,7 @@ static const struct seq_operations monitor_reactors_seq_ops 
= {
        .show   = monitor_reactor_show
 };
 
-static void monitor_swap_reactors_single(struct rv_monitor *mon,
+static int monitor_swap_reactors_single(struct rv_monitor *mon,
                                         struct rv_reactor *reactor,
                                         bool nested)
 {
@@ -167,29 +168,39 @@ static void monitor_swap_reactors_single(struct 
rv_monitor *mon,
 
        /* nothing to do */
        if (mon->reactor == reactor)
-               return;
+               return 0;
+
+       if (reactor->owner && !try_module_get(reactor->owner))
+               return -EBUSY;
 
        monitor_enabled = mon->enabled;
        if (monitor_enabled)
                rv_disable_monitor(mon);
 
+       if (mon->reactor)
+               module_put(mon->reactor->owner);
        mon->reactor = reactor;
        mon->react = reactor->react;
 
        /* enable only once if iterating through a container */
        if (monitor_enabled && !nested)
                rv_enable_monitor(mon);
+
+       return 0;
 }
 
-static void monitor_swap_reactors(struct rv_monitor *mon, struct rv_reactor 
*reactor)
+static int monitor_swap_reactors(struct rv_monitor *mon, struct rv_reactor 
*reactor)
 {
        struct rv_monitor *p = mon;
+       int ret;
 
        if (rv_is_container_monitor(mon))
                list_for_each_entry_continue(p, &rv_monitors_list, list) {
                        if (p->parent != mon)
                                break;
-                       monitor_swap_reactors_single(p, reactor, true);
+                       ret = monitor_swap_reactors_single(p, reactor, true);
+                       if (ret)
+                               return ret;
                }
        /*
         * This call enables and disables the monitor if they were active.
@@ -197,7 +208,7 @@ static void monitor_swap_reactors(struct rv_monitor *mon, 
struct rv_reactor *rea
         * All nested monitors are enabled also if they were off, we may refine
         * this logic in the future.
         */
-       monitor_swap_reactors_single(mon, reactor, false);
+       return monitor_swap_reactors_single(mon, reactor, false);
 }
 
 static ssize_t
@@ -236,10 +247,14 @@ monitor_reactors_write(struct file *file, const char 
__user *user_buf,
        guard(mutex)(&rv_interface_lock);
 
        list_for_each_entry(reactor, &rv_reactors_list, list) {
+               int ret;
+
                if (strcmp(ptr, reactor->name) != 0)
                        continue;
 
-               monitor_swap_reactors(mon, reactor);
+               ret = monitor_swap_reactors(mon, reactor);
+               if (ret)
+                       return ret;
 
                return count;
        }
@@ -314,6 +329,7 @@ int rv_register_reactor(struct rv_reactor *reactor)
        guard(mutex)(&rv_interface_lock);
        return __rv_register_reactor(reactor);
 }
+EXPORT_SYMBOL_GPL(rv_register_reactor);
 
 /**
  * rv_unregister_reactor - unregister a rv reactor.
@@ -327,6 +343,7 @@ int rv_unregister_reactor(struct rv_reactor *reactor)
        list_del(&reactor->list);
        return 0;
 }
+EXPORT_SYMBOL_GPL(rv_unregister_reactor);
 
 /*
  * reacting_on interface.
@@ -421,6 +438,15 @@ int reactor_populate_monitor(struct rv_monitor *mon, 
struct dentry *root)
         * Configure as the rv_nop reactor.
         */
        mon->reactor = get_reactor_rdef_by_name("nop");
+       if (WARN_ON(!mon->reactor)) {
+               rv_remove(tmp);
+               return -EINVAL;
+       }
+
+       if (mon->reactor->owner && !try_module_get(mon->reactor->owner)) {
+               rv_remove(tmp);
+               return -EBUSY;
+       }
 
        return 0;
 }
-- 
2.25.1


Reply via email to