Fix: uprobes: make uprobe_register() return struct uprobe * (v6.12)
authorMichael Jeanson <mjeanson@efficios.com>
Thu, 17 Oct 2024 15:56:02 +0000 (11:56 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 4 Nov 2024 20:44:15 +0000 (15:44 -0500)
See upstream commits :

  commit 3c83a9ad0295eb63bdeb81d821b8c3b9417fbcac
  Author: Oleg Nesterov <oleg@redhat.com>
  Date:   Thu Aug 1 15:27:34 2024 +0200

    uprobes: make uprobe_register() return struct uprobe *

    This way uprobe_unregister() and uprobe_apply() can use "struct uprobe *"
    rather than inode + offset. This simplifies the code and allows to avoid
    the unnecessary find_uprobe() + put_uprobe() in these functions.

    TODO: uprobe_unregister() still needs get_uprobe/put_uprobe to ensure that
    this uprobe can't be freed before up_write(&uprobe->register_rwsem).

  commit 04b01625da130c7521b768996cd5e48052198b97
  Author: Peter Zijlstra <peterz@infradead.org>
  Date:   Tue Sep 3 10:46:00 2024 -0700

    perf/uprobe: split uprobe_unregister()

    With uprobe_unregister() having grown a synchronize_srcu(), it becomes
    fairly slow to call. Esp. since both users of this API call it in a
    loop.

    Peel off the sync_srcu() and do it once, after the loop.

    We also need to add uprobe_unregister_sync() into uprobe_register()'s
    error handling path, as we need to be careful about returning to the
    caller before we have a guarantee that partially attached consumer won't
    be called anymore. This is an unlikely slow path and this should be
    totally fine to be slow in the case of a failed attach.

  commit e04332ebc8ac128fa551e83f1161ab1c094d13a9
  Author: Oleg Nesterov <oleg@redhat.com>
  Date:   Thu Aug 1 15:27:28 2024 +0200

    uprobes: kill uprobe_register_refctr()

    It doesn't make any sense to have 2 versions of _register(). Note that
    trace_uprobe_enable(), the only user of uprobe_register(), doesn't need
    to check tu->ref_ctr_offset to decide which one should be used, it could
    safely pass ref_ctr_offset == 0 to uprobe_register_refctr().

    Add this argument to uprobe_register(), update the callers, and kill
    uprobe_register_refctr().

Change-Id: I8d1f9a5db1f19c2bc2029709ae36f82e86f6fe58
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
include/lttng/events-internal.h
src/lttng-uprobes.c

index 224bfec1854e876df063c12ed766784b094b607a..002ed6affc391254cb9df270fbbf424650bfb1d5 100644 (file)
@@ -49,6 +49,7 @@ struct lttng_krp;                             /* Kretprobe handling */
 struct lttng_uprobe_handler {
        struct lttng_kernel_event_common *event;
        loff_t offset;
+       struct uprobe *uprobe;
        struct uprobe_consumer up_consumer;
        struct list_head node;
 };
index 1c81b9de5ee8cbdaef7639fb3735a3afe51b4d7e..2d97155e492cd32b8ae2b38bd9f10fb7fea74d07 100644 (file)
@@ -232,8 +232,16 @@ int lttng_uprobes_add_callsite(struct lttng_uprobe *uprobe,
                goto register_error;
        }
 
+#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(6,12,0))
+       ret = 0;
+       uprobe_handler->uprobe = uprobe_register(uprobe->inode,
+                     uprobe_handler->offset, 0, &uprobe_handler->up_consumer);
+       if (IS_ERR(uprobe_handler->uprobe))
+               ret = -1;
+#else
        ret = uprobe_register(uprobe->inode,
                      uprobe_handler->offset, &uprobe_handler->up_consumer);
+#endif
        if (ret) {
                printk(KERN_WARNING "LTTng: Error registering probe on inode %lu "
                       "and offset 0x%llx\n", uprobe->inode->i_ino,
@@ -304,15 +312,39 @@ void lttng_uprobes_unregister(struct inode *inode, struct list_head *head)
 {
        struct lttng_uprobe_handler *iter, *tmp;
 
+#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(6,12,0))
+       /*
+        * Iterate over the list of handler, unregister each uprobe.
+        */
+       list_for_each_entry(iter, head, node) {
+               uprobe_unregister_nosync(iter->uprobe, &iter->up_consumer);
+               iter->uprobe = NULL;
+       }
+
+       /*
+        * Call synchronize_srcu() on uprobes_srcu.
+        */
+       uprobe_unregister_sync();
+
        /*
         * Iterate over the list of handler, remove each handler from the list
         * and free the struct.
         */
+       list_for_each_entry_safe(iter, tmp, head, node) {
+               list_del(&iter->node);
+               kfree(iter);
+       }
+#else
+       /*
+        * Iterate over the list of handler, unregister each uprobe, remove
+        * each handler from the list and free the struct.
+        */
        list_for_each_entry_safe(iter, tmp, head, node) {
                uprobe_unregister(inode, iter->offset, &iter->up_consumer);
                list_del(&iter->node);
                kfree(iter);
        }
+#endif
 }
 
 void lttng_uprobes_unregister_event(struct lttng_kernel_event_common *event)
This page took 0.030027 seconds and 4 git commands to generate.