On Wed,  3 Feb 2021 12:57:41 -0500
Mathieu Desnoyers <mathieu.desnoy...@efficios.com> wrote:

> This patch is only compile-tested.
> 

Yes it is. (crashed on boot)


> Signed-off-by: Mathieu Desnoyers <mathieu.desnoy...@efficios.com>
> ---
>  include/linux/tracepoint.h |  2 +-
>  kernel/tracepoint.c        | 80 +++++++++++++-------------------------
>  2 files changed, 28 insertions(+), 54 deletions(-)
> 
> diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
> index 0f21617f1a66..fae8d6d9588c 100644
> --- a/include/linux/tracepoint.h
> +++ b/include/linux/tracepoint.h
> @@ -308,7 +308,7 @@ static inline struct tracepoint 
> *tracepoint_ptr_deref(tracepoint_ptr_t *p)
>               it_func_ptr =                                           \
>                       rcu_dereference_raw((&__tracepoint_##_name)->funcs); \
>               do {                                                    \
> -                     it_func = (it_func_ptr)->func;                  \
> +                     it_func = READ_ONCE((it_func_ptr)->func);       \
>                       __data = (it_func_ptr)->data;                   \
>                       ((void(*)(void *, proto))(it_func))(__data, args); \
>               } while ((++it_func_ptr)->func);                        \
> diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
> index 3e261482296c..b1bec710f68a 100644
> --- a/kernel/tracepoint.c
> +++ b/kernel/tracepoint.c
> @@ -136,9 +136,10 @@ func_add(struct tracepoint_func **funcs, struct 
> tracepoint_func *tp_func,
>        int prio)
>  {
>       struct tracepoint_func *old, *new;
> -     int nr_probes = 0;
> -     int stub_funcs = 0;
> -     int pos = -1;
> +     int iter_probes = 0;    /* Iterate over old probe array. */
> +     int nr_old_probes = 0;  /* Count non-stub functions in old. */
> +     int nr_new_probes = 0;  /* Count functions in new. */
> +     int pos = -1;           /* Insert position in new. */
>  
>       if (WARN_ON(!tp_func->func))
>               return ERR_PTR(-EINVAL);
> @@ -147,54 +148,34 @@ func_add(struct tracepoint_func **funcs, struct 
> tracepoint_func *tp_func,
>       old = *funcs;
>       if (old) {
>               /* (N -> N+1), (N != 0, 1) probes */
> -             for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
> -                     /* Insert before probes of lower priority */
> -                     if (pos < 0 && old[nr_probes].prio < prio)
> -                             pos = nr_probes;
> -                     if (old[nr_probes].func == tp_func->func &&
> -                         old[nr_probes].data == tp_func->data)
> +             for (iter_probes = 0; old[iter_probes].func; iter_probes++) {
> +                     if (old[iter_probes].func == tp_stub_func)
> +                             continue;       /* Skip stub functions. */
> +                     if (old[iter_probes].func == tp_func->func &&
> +                         old[iter_probes].data == tp_func->data)
>                               return ERR_PTR(-EEXIST);
> -                     if (old[nr_probes].func == tp_stub_func)
> -                             stub_funcs++;
> +                     /* Insert before probes of lower priority */
> +                     if (pos < 0 && old[iter_probes].prio < prio)
> +                             pos = nr_old_probes;
> +                     nr_old_probes++;
>               }
>       }
> -     /* + 2 : one for new probe, one for NULL func - stub functions */
> -     new = allocate_probes(nr_probes + 2 - stub_funcs);
> +     /* + 2 : one for new probe, one for NULL func */
> +     new = allocate_probes(nr_old_probes + 2);
>       if (new == NULL)
>               return ERR_PTR(-ENOMEM);
>       if (old) {
> -             if (stub_funcs) {
> -                     /* Need to copy one at a time to remove stubs */
> -                     int probes = 0;
> -
> -                     pos = -1;
> -                     for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
> -                             if (old[nr_probes].func == tp_stub_func)
> -                                     continue;
> -                             if (pos < 0 && old[nr_probes].prio < prio)
> -                                     pos = probes++;
> -                             new[probes++] = old[nr_probes];
> -                     }
> -                     nr_probes = probes;
> -                     if (pos < 0)
> -                             pos = probes;
> -                     else
> -                             nr_probes--; /* Account for insertion */

The above "trick" is to handle the case that we inserted a probe with the:

                        if (pos < 0 && old[nr_probes].prio < prio)
                                pos = probes++;

Which in the below code, you missed.

> -
> -             } else if (pos < 0) {
> -                     pos = nr_probes;
> -                     memcpy(new, old, nr_probes * sizeof(struct 
> tracepoint_func));
> -             } else {
> -                     /* Copy higher priority probes ahead of the new probe */
> -                     memcpy(new, old, pos * sizeof(struct tracepoint_func));
> -                     /* Copy the rest after it. */
> -                     memcpy(new + pos + 1, old + pos,
> -                            (nr_probes - pos) * sizeof(struct 
> tracepoint_func));
> +             for (iter_probes = 0; old[iter_probes].func; iter_probes++) {
> +                     if (old[iter_probes].func == tp_stub_func)
> +                             continue;               /* Skip stub functions. 
> */
> +                     if (nr_new_probes != pos)
> +                             new[nr_new_probes] = old[iter_probes];

The problem is above, because we just skipped adding old[iter_probes].

> +                     nr_new_probes++;

I'm not sure this is any less confusing than my code. Because, I now have
to try and wrap my head around how to increment three different variables
instead of just two.

I agree that we can just make it one code, but I think I'll keep the
original logic, with slight modifications influenced by your code.

Instead of doing that "trick" that decrements nr_probes, I should increment
it if we are adding to the end (pos < 0):

                if (pos < 0)
                        pos = nr_probes++;
                /* nr_probes points to the end of the array */
        } else { /* !old */
                pos = 0;
                nr_probes = 1; /* points to end of array */
        }

        new[pos] = *tp_func;
        new[nr_probes].func = NULL;


>               }
>       } else
>               pos = 0;
>       new[pos] = *tp_func;
> -     new[nr_probes + 1].func = NULL;
> +     new[nr_new_probes + 1].func = NULL;
>       *funcs = new;
>       debug_print_probes(*funcs);
>       return old;
> @@ -238,9 +219,9 @@ static void *func_remove(struct tracepoint_func **funcs,
>               new = allocate_probes(nr_probes - nr_del + 1);
>               if (new) {
>                       for (i = 0; old[i].func; i++)
> -                             if ((old[i].func != tp_func->func
> -                                  || old[i].data != tp_func->data)
> -                                 && old[i].func != tp_stub_func)
> +                             if ((old[i].func != tp_func->func ||
> +                                  old[i].data != tp_func->data) &&
> +                                 old[i].func != tp_stub_func)
>                                       new[j++] = old[i];
>                       new[nr_probes - nr_del].func = NULL;
>                       *funcs = new;
> @@ -251,15 +232,8 @@ static void *func_remove(struct tracepoint_func **funcs,
>                        */
>                       for (i = 0; old[i].func; i++)
>                               if (old[i].func == tp_func->func &&
> -                                 old[i].data == tp_func->data) {
> -                                     old[i].func = tp_stub_func;
> -                                     /* Set the prio to the next event. */
> -                                     if (old[i + 1].func)
> -                                             old[i].prio =
> -                                                     old[i + 1].prio;
> -                                     else
> -                                             old[i].prio = -1;
> -                             }
> +                                 old[i].data == tp_func->data)
> +                                     WRITE_ONCE(old[i].func, tp_stub_func);

I'll add this change too.

>                       *funcs = old;
>               }
>       }

Here's an updated patch:

(tested against tools/testing/selftests/ftrace/ftracetest)

Index: linux-trace.git/include/linux/tracepoint.h
===================================================================
--- linux-trace.git.orig/include/linux/tracepoint.h
+++ linux-trace.git/include/linux/tracepoint.h
@@ -309,7 +309,7 @@ static inline struct tracepoint *tracepo
                        rcu_dereference_raw((&__tracepoint_##_name)->funcs); \
                if (it_func_ptr) {                                      \
                        do {                                            \
-                               it_func = (it_func_ptr)->func;          \
+                               it_func = READ_ONCE((it_func_ptr)->func); \
                                __data = (it_func_ptr)->data;           \
                                ((void(*)(void *, proto))(it_func))(__data, 
args); \
                        } while ((++it_func_ptr)->func);                \
Index: linux-trace.git/kernel/tracepoint.c
===================================================================
--- linux-trace.git.orig/kernel/tracepoint.c
+++ linux-trace.git/kernel/tracepoint.c
@@ -136,9 +136,9 @@ func_add(struct tracepoint_func **funcs,
         int prio)
 {
        struct tracepoint_func *old, *new;
-       int nr_probes = 0;
-       int stub_funcs = 0;
-       int pos = -1;
+       int iter_probes;        /* Iterate over old probe array. */
+       int nr_probes = 0;      /* Counter for probes */
+       int pos = -1;           /* New position */
 
        if (WARN_ON(!tp_func->func))
                return ERR_PTR(-EINVAL);
@@ -147,54 +147,39 @@ func_add(struct tracepoint_func **funcs,
        old = *funcs;
        if (old) {
                /* (N -> N+1), (N != 0, 1) probes */
-               for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
-                       /* Insert before probes of lower priority */
-                       if (pos < 0 && old[nr_probes].prio < prio)
-                               pos = nr_probes;
-                       if (old[nr_probes].func == tp_func->func &&
-                           old[nr_probes].data == tp_func->data)
+               for (iter_probes = 0; old[iter_probes].func; iter_probes++) {
+                       if (old[iter_probes].func == tp_stub_func)
+                               continue;       /* Skip stub functions. */
+                       if (old[iter_probes].func == tp_func->func &&
+                           old[iter_probes].data == tp_func->data)
                                return ERR_PTR(-EEXIST);
-                       if (old[nr_probes].func == tp_stub_func)
-                               stub_funcs++;
+                       nr_probes++;
                }
        }
-       /* + 2 : one for new probe, one for NULL func - stub functions */
-       new = allocate_probes(nr_probes + 2 - stub_funcs);
+       /* + 2 : one for new probe, one for NULL func */
+       new = allocate_probes(nr_probes + 2);
        if (new == NULL)
                return ERR_PTR(-ENOMEM);
        if (old) {
-               if (stub_funcs) {
-                       /* Need to copy one at a time to remove stubs */
-                       int probes = 0;
-
-                       pos = -1;
-                       for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
-                               if (old[nr_probes].func == tp_stub_func)
-                                       continue;
-                               if (pos < 0 && old[nr_probes].prio < prio)
-                                       pos = probes++;
-                               new[probes++] = old[nr_probes];
-                       }
-                       nr_probes = probes;
-                       if (pos < 0)
-                               pos = probes;
-                       else
-                               nr_probes--; /* Account for insertion */
-
-               } else if (pos < 0) {
-                       pos = nr_probes;
-                       memcpy(new, old, nr_probes * sizeof(struct 
tracepoint_func));
-               } else {
-                       /* Copy higher priority probes ahead of the new probe */
-                       memcpy(new, old, pos * sizeof(struct tracepoint_func));
-                       /* Copy the rest after it. */
-                       memcpy(new + pos + 1, old + pos,
-                              (nr_probes - pos) * sizeof(struct 
tracepoint_func));
+               pos = -1;
+               nr_probes = 0;
+               for (iter_probes = 0; old[iter_probes].func; iter_probes++) {
+                       if (old[iter_probes].func == tp_stub_func)
+                               continue;
+                       /* Insert before probes of lower priority */
+                       if (pos < 0 && old[iter_probes].prio < prio)
+                               pos = nr_probes++;
+                       new[nr_probes++] = old[iter_probes];
                }
-       } else
+               if (pos < 0)
+                       pos = nr_probes++;
+               /* nr_probes now points to the end of the new array */
+       } else {
                pos = 0;
+               nr_probes = 1; /* must point at end of array */
+       }
        new[pos] = *tp_func;
-       new[nr_probes + 1].func = NULL;
+       new[nr_probes].func = NULL;
        *funcs = new;
        debug_print_probes(*funcs);
        return old;
@@ -237,11 +222,12 @@ static void *func_remove(struct tracepoi
                /* + 1 for NULL */
                new = allocate_probes(nr_probes - nr_del + 1);
                if (new) {
-                       for (i = 0; old[i].func; i++)
-                               if ((old[i].func != tp_func->func
-                                    || old[i].data != tp_func->data)
-                                   && old[i].func != tp_stub_func)
+                       for (i = 0; old[i].func; i++) {
+                               if ((old[i].func != tp_func->func ||
+                                    old[i].data != tp_func->data) &&
+                                   old[i].func != tp_stub_func)
                                        new[j++] = old[i];
+                       }
                        new[nr_probes - nr_del].func = NULL;
                        *funcs = new;
                } else {
@@ -249,17 +235,11 @@ static void *func_remove(struct tracepoi
                         * Failed to allocate, replace the old function
                         * with calls to tp_stub_func.
                         */
-                       for (i = 0; old[i].func; i++)
+                       for (i = 0; old[i].func; i++) {
                                if (old[i].func == tp_func->func &&
-                                   old[i].data == tp_func->data) {
-                                       old[i].func = tp_stub_func;
-                                       /* Set the prio to the next event. */
-                                       if (old[i + 1].func)
-                                               old[i].prio =
-                                                       old[i + 1].prio;
-                                       else
-                                               old[i].prio = -1;
-                               }
+                                   old[i].data == tp_func->data)
+                                       WRITE_ONCE(old[i].func, tp_stub_func);
+                       }
                        *funcs = old;
                }
        }


Reply via email to