In preparation to introducing atomic replace, introduce iterators for klp_func and klp_object, such that objects and functions can be dynmically allocated (needed for atomic replace). This patch is intended to effectively be a no-op until atomic replace is introduced. Signed-off-by: Jason Baron <jbaron@xxxxxxxxxx> Cc: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> Cc: Jessica Yu <jeyu@xxxxxxxxxx> Cc: Jiri Kosina <jikos@xxxxxxxxxx> Cc: Miroslav Benes <mbenes@xxxxxxx> Cc: Petr Mladek <pmladek@xxxxxxxx> --- include/linux/livepatch.h | 94 +++++++++++++++++++++++++++++++++++++++++++++-- kernel/livepatch/core.c | 4 ++ 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index 194991e..8d3df55 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h @@ -24,6 +24,7 @@ #include <linux/module.h> #include <linux/ftrace.h> #include <linux/completion.h> +#include <linux/list.h> #if IS_ENABLED(CONFIG_LIVEPATCH) @@ -44,6 +45,7 @@ * @old_addr: the address of the function being patched * @kobj: kobject for sysfs resources * @stack_node: list node for klp_ops func_stack list + * @func_entry: used to link struct klp_func to struct klp_object * @old_size: size of the old function * @new_size: size of the new function * @patched: the func has been added to the klp_ops list @@ -82,6 +84,7 @@ struct klp_func { unsigned long old_addr; struct kobject kobj; struct list_head stack_node; + struct list_head func_entry; unsigned long old_size, new_size; bool patched; bool transition; @@ -92,6 +95,8 @@ struct klp_func { * @name: module name (or NULL for vmlinux) * @funcs: function entries for functions to be patched in the object * @kobj: kobject for sysfs resources + * @func_list: head of list for dynamically allocate struct klp_func + * @obj_entry: used to link struct klp_object to struct klp_patch * @mod: kernel module associated with the patched object * (NULL for vmlinux) * @patched: the object's funcs have been added to the klp_ops list @@ -103,6 +108,8 @@ struct klp_object { /* internal */ struct kobject kobj; + struct list_head func_list; + struct list_head obj_entry; struct module *mod; bool patched; }; @@ -114,6 +121,7 @@ struct klp_object { * @immediate: patch all funcs immediately, bypassing safety mechanisms * @list: list node for global list of registered patches * @kobj: kobject for sysfs resources + * @obj_list: head of list for dynamically allocated struct klp_object * @enabled: the patch is enabled (but operation may be incomplete) * @finish: for waiting till it is safe to remove the patch module */ @@ -126,17 +134,95 @@ struct klp_patch { /* internal */ struct list_head list; struct kobject kobj; + struct list_head obj_list; bool enabled; struct completion finish; }; +static inline struct klp_object *obj_iter_next(struct klp_patch *patch, + struct klp_object *obj) +{ + struct klp_object *next_obj = NULL; + + if (list_empty(&obj->obj_entry)) { + next_obj = obj + 1; + if (next_obj->funcs || next_obj->name) + goto out; + else + next_obj = NULL; + if (!list_empty(&patch->obj_list)) + next_obj = container_of(patch->obj_list.next, + struct klp_object, + obj_entry); + goto out; + } + if (obj->obj_entry.next != &patch->obj_list) + next_obj = container_of(obj->obj_entry.next, + struct klp_object, + obj_entry); +out: + return next_obj; +} + +static inline struct klp_object *obj_iter_init(struct klp_patch *patch) +{ + if (patch->objs->funcs || patch->objs->name) + return patch->objs; + else + return NULL; +} + #define klp_for_each_object(patch, obj) \ - for (obj = patch->objs; obj->funcs || obj->name; obj++) + for (obj = obj_iter_init(patch); obj; obj = obj_iter_next(patch, obj)) + +static inline struct klp_func *func_iter_next(struct klp_object *obj, + struct klp_func *func) +{ + struct klp_func *next_func = NULL; + + if (list_empty(&func->func_entry)) { + next_func = func + 1; + if (next_func->old_name || next_func->new_func || + next_func->old_sympos) + goto out; + else + next_func = NULL; + if (!list_empty(&obj->func_list)) + next_func = container_of(obj->func_list.next, + struct klp_func, + func_entry); + goto out; + } + if (func->func_entry.next != &obj->func_list) + next_func = container_of(func->func_entry.next, + struct klp_func, + func_entry); +out: + return next_func; +} + +static inline struct klp_func *func_iter_init(struct klp_object *obj) +{ + /* statically allocated */ + if (list_empty(&obj->obj_entry)) { + if (obj->funcs->old_name || obj->funcs->new_func || + obj->funcs->old_sympos) + return obj->funcs; + else + return NULL; + } else { + if (!list_empty(obj->func_list.next)) + return container_of(obj->func_list.next, + struct klp_func, + func_entry); + else + return NULL; + } +} #define klp_for_each_func(obj, func) \ - for (func = obj->funcs; \ - func->old_name || func->new_func || func->old_sympos; \ - func++) + for (func = func_iter_init(obj); func; \ + func = func_iter_next(obj, func)) int klp_register_patch(struct klp_patch *); int klp_unregister_patch(struct klp_patch *); diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index b9628e4..6004be3 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -606,6 +606,7 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func) return -EINVAL; INIT_LIST_HEAD(&func->stack_node); + INIT_LIST_HEAD(&func->func_entry); func->patched = false; func->transition = false; @@ -729,7 +730,10 @@ static int klp_init_patch(struct klp_patch *patch) return ret; } + INIT_LIST_HEAD(&patch->obj_list); klp_for_each_object(patch, obj) { + INIT_LIST_HEAD(&obj->obj_entry); + INIT_LIST_HEAD(&obj->func_list); ret = klp_init_object(patch, obj); if (ret) goto free; -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe live-patching" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html