Commit 53cd885b authored by Song Liu's avatar Song Liu Committed by Daniel Borkmann

ftrace: Allow IPMODIFY and DIRECT ops on the same function

IPMODIFY (livepatch) and DIRECT (bpf trampoline) ops are both important
users of ftrace. It is necessary to allow them work on the same function
at the same time.

First, DIRECT ops no longer specify IPMODIFY flag. Instead, DIRECT flag is
handled together with IPMODIFY flag in __ftrace_hash_update_ipmodify().

Then, a callback function, ops_func, is added to ftrace_ops. This is used
by ftrace core code to understand whether the DIRECT ops can share with an
IPMODIFY ops. To share with IPMODIFY ops, the DIRECT ops need to implement
the callback function and adjust the direct trampoline accordingly.

If DIRECT ops is attached before the IPMODIFY ops, ftrace core code calls
ENABLE_SHARE_IPMODIFY_PEER on the DIRECT ops before registering the
IPMODIFY ops.

If IPMODIFY ops is attached before the DIRECT ops, ftrace core code calls
ENABLE_SHARE_IPMODIFY_SELF in __ftrace_hash_update_ipmodify. Owner of the
DIRECT ops may return 0 if the DIRECT trampoline can share with IPMODIFY,
so error code otherwise. The error code is propagated to
register_ftrace_direct_multi so that onwer of the DIRECT trampoline can
handle it properly.

For more details, please refer to comment before enum ftrace_ops_cmd.
Signed-off-by: default avatarSong Liu <song@kernel.org>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Reviewed-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
Link: https://lore.kernel.org/all/20220602193706.2607681-2-song@kernel.org/
Link: https://lore.kernel.org/all/20220718055449.3960512-1-song@kernel.org/
Link: https://lore.kernel.org/bpf/20220720002126.803253-3-song@kernel.org
parent f96f644a
...@@ -208,6 +208,43 @@ enum { ...@@ -208,6 +208,43 @@ enum {
FTRACE_OPS_FL_DIRECT = BIT(17), FTRACE_OPS_FL_DIRECT = BIT(17),
}; };
/*
* FTRACE_OPS_CMD_* commands allow the ftrace core logic to request changes
* to a ftrace_ops. Note, the requests may fail.
*
* ENABLE_SHARE_IPMODIFY_SELF - enable a DIRECT ops to work on the same
* function as an ops with IPMODIFY. Called
* when the DIRECT ops is being registered.
* This is called with both direct_mutex and
* ftrace_lock are locked.
*
* ENABLE_SHARE_IPMODIFY_PEER - enable a DIRECT ops to work on the same
* function as an ops with IPMODIFY. Called
* when the other ops (the one with IPMODIFY)
* is being registered.
* This is called with direct_mutex locked.
*
* DISABLE_SHARE_IPMODIFY_PEER - disable a DIRECT ops to work on the same
* function as an ops with IPMODIFY. Called
* when the other ops (the one with IPMODIFY)
* is being unregistered.
* This is called with direct_mutex locked.
*/
enum ftrace_ops_cmd {
FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF,
FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_PEER,
FTRACE_OPS_CMD_DISABLE_SHARE_IPMODIFY_PEER,
};
/*
* For most ftrace_ops_cmd,
* Returns:
* 0 - Success.
* Negative on failure. The return value is dependent on the
* callback.
*/
typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
#ifdef CONFIG_DYNAMIC_FTRACE #ifdef CONFIG_DYNAMIC_FTRACE
/* The hash used to know what functions callbacks trace */ /* The hash used to know what functions callbacks trace */
struct ftrace_ops_hash { struct ftrace_ops_hash {
...@@ -250,6 +287,7 @@ struct ftrace_ops { ...@@ -250,6 +287,7 @@ struct ftrace_ops {
unsigned long trampoline; unsigned long trampoline;
unsigned long trampoline_size; unsigned long trampoline_size;
struct list_head list; struct list_head list;
ftrace_ops_func_t ops_func;
#endif #endif
}; };
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment