Before introduce feature "using". Klp transition will need an
easier way to get klp_ops from klp_func.

This patch make changes as follows:
1. Move klp_ops into klp_func structure.
Rewrite the logic of klp_find_ops and
other logic to get klp_ops of a function.

2. Move definition of struct klp_ops into
include/linux/livepatch.h

With this changes, we can get klp_ops of a klp_func easily. 
klp_find_ops can also be simple and straightforward. And we 
do not need to maintain one global list for now.

Signed-off-by: Wardenjohn <zhangwar...@gmail.com>

diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 51a258c24ff5..d874aecc817b 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -22,6 +22,25 @@
 #define KLP_TRANSITION_UNPATCHED        0
 #define KLP_TRANSITION_PATCHED          1
 
+/**
+ * struct klp_ops - structure for tracking registered ftrace ops structs
+ *
+ * A single ftrace_ops is shared between all enabled replacement functions
+ * (klp_func structs) which have the same old_func.  This allows the switch
+ * between function versions to happen instantaneously by updating the klp_ops
+ * struct's func_stack list.  The winner is the klp_func at the top of the
+ * func_stack (front of the list).
+ *
+ * @node:      node for the global klp_ops list
+ * @func_stack:        list head for the stack of klp_func's (active func is 
on top)
+ * @fops:      registered ftrace ops struct
+ */
+struct klp_ops {
+       struct list_head node;
+       struct list_head func_stack;
+       struct ftrace_ops fops;
+};
+
 /**
  * struct klp_func - function structure for live patching
  * @old_name:  name of the function to be patched
@@ -32,6 +51,7 @@
  * @kobj:      kobject for sysfs resources
  * @node:      list node for klp_object func_list
  * @stack_node:        list node for klp_ops func_stack list
+ * @ops:       pointer to klp_ops struct for this function
  * @old_size:  size of the old function
  * @new_size:  size of the new function
  * @nop:        temporary patch to use the original code again; dyn. allocated
@@ -71,6 +91,7 @@ struct klp_func {
        struct kobject kobj;
        struct list_head node;
        struct list_head stack_node;
+       struct klp_ops *ops;
        unsigned long old_size, new_size;
        bool nop;
        bool patched;
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 52426665eecc..e4572bf34316 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -760,6 +760,8 @@ static int klp_init_func(struct klp_object *obj, struct 
klp_func *func)
        if (!func->old_name)
                return -EINVAL;
 
+       func->ops = NULL;
+
        /*
         * NOPs get the address later. The patched module must be loaded,
         * see klp_init_object_loaded().
diff --git a/kernel/livepatch/patch.c b/kernel/livepatch/patch.c
index 90408500e5a3..8ab9c35570f4 100644
--- a/kernel/livepatch/patch.c
+++ b/kernel/livepatch/patch.c
@@ -20,18 +20,25 @@
 #include "patch.h"
 #include "transition.h"
 
-static LIST_HEAD(klp_ops);
 
 struct klp_ops *klp_find_ops(void *old_func)
 {
-       struct klp_ops *ops;
+       struct klp_patch *patch;
+       struct klp_object *obj;
        struct klp_func *func;
 
-       list_for_each_entry(ops, &klp_ops, node) {
-               func = list_first_entry(&ops->func_stack, struct klp_func,
-                                       stack_node);
-               if (func->old_func == old_func)
-                       return ops;
+       klp_for_each_patch(patch) {
+               klp_for_each_object(patch, obj) {
+                       klp_for_each_func(obj, func) {
+                               /*
+                                * Ignore entry where func->ops has not been
+                                * assigned yet. It is most likely the one
+                                * which is about to be created/added.
+                                */
+                               if (func->old_func == old_func && func->ops)
+                                       return func->ops;
+                       }
+               }
        }
 
        return NULL;
@@ -133,7 +140,7 @@ static void klp_unpatch_func(struct klp_func *func)
        if (WARN_ON(!func->old_func))
                return;
 
-       ops = klp_find_ops(func->old_func);
+       ops = func->ops;
        if (WARN_ON(!ops))
                return;
 
@@ -149,6 +156,7 @@ static void klp_unpatch_func(struct klp_func *func)
 
                list_del_rcu(&func->stack_node);
                list_del(&ops->node);
+               func->ops = NULL;
                kfree(ops);
        } else {
                list_del_rcu(&func->stack_node);
@@ -168,7 +176,7 @@ static int klp_patch_func(struct klp_func *func)
        if (WARN_ON(func->patched))
                return -EINVAL;
 
-       ops = klp_find_ops(func->old_func);
+       ops = func->ops;
        if (!ops) {
                unsigned long ftrace_loc;
 
@@ -191,8 +199,6 @@ static int klp_patch_func(struct klp_func *func)
                                  FTRACE_OPS_FL_IPMODIFY |
                                  FTRACE_OPS_FL_PERMANENT;
 
-               list_add(&ops->node, &klp_ops);
-
                INIT_LIST_HEAD(&ops->func_stack);
                list_add_rcu(&func->stack_node, &ops->func_stack);
 
@@ -211,7 +217,7 @@ static int klp_patch_func(struct klp_func *func)
                        goto err;
                }
 
-
+               func->ops = ops;
        } else {
                list_add_rcu(&func->stack_node, &ops->func_stack);
        }
@@ -224,6 +230,7 @@ static int klp_patch_func(struct klp_func *func)
        list_del_rcu(&func->stack_node);
        list_del(&ops->node);
        kfree(ops);
+       func->ops = NULL;
        return ret;
 }
 
diff --git a/kernel/livepatch/patch.h b/kernel/livepatch/patch.h
index d5f2fbe373e0..21d0d20b7189 100644
--- a/kernel/livepatch/patch.h
+++ b/kernel/livepatch/patch.h
@@ -6,25 +6,6 @@
 #include <linux/list.h>
 #include <linux/ftrace.h>
 
-/**
- * struct klp_ops - structure for tracking registered ftrace ops structs
- *
- * A single ftrace_ops is shared between all enabled replacement functions
- * (klp_func structs) which have the same old_func.  This allows the switch
- * between function versions to happen instantaneously by updating the klp_ops
- * struct's func_stack list.  The winner is the klp_func at the top of the
- * func_stack (front of the list).
- *
- * @node:      node for the global klp_ops list
- * @func_stack:        list head for the stack of klp_func's (active func is 
on top)
- * @fops:      registered ftrace ops struct
- */
-struct klp_ops {
-       struct list_head node;
-       struct list_head func_stack;
-       struct ftrace_ops fops;
-};
-
 struct klp_ops *klp_find_ops(void *old_func);
 
 int klp_patch_object(struct klp_object *obj);
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c
index ba069459c101..d9a3f9c7a93b 100644
--- a/kernel/livepatch/transition.c
+++ b/kernel/livepatch/transition.c
@@ -230,7 +230,7 @@ static int klp_check_stack_func(struct klp_func *func, 
unsigned long *entries,
                 * Check for the to-be-patched function
                 * (the previous func).
                 */
-               ops = klp_find_ops(func->old_func);
+               ops = func->ops;
 
                if (list_is_singular(&ops->func_stack)) {
                        /* original function */
-- 
2.18.2


Reply via email to