Commit f96f644a authored by Song Liu's avatar Song Liu Committed by Daniel Borkmann
Browse files

ftrace: Add modify_ftrace_direct_multi_nolock



This is similar to modify_ftrace_direct_multi, but does not acquire
direct_mutex. This is useful when direct_mutex is already locked by the
user.

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/bpf/20220720002126.803253-2-song@kernel.org
parent f664f9c6
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -340,6 +340,7 @@ unsigned long ftrace_find_rec_direct(unsigned long ip);
int register_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr);
int unregister_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr);
int modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr);
int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsigned long addr);

#else
struct ftrace_ops;
@@ -384,6 +385,10 @@ static inline int modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned lo
{
	return -ENODEV;
}
static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsigned long addr)
{
	return -ENODEV;
}
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */

#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+62 −24
Original line number Diff line number Diff line
@@ -5691,22 +5691,8 @@ int unregister_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)
}
EXPORT_SYMBOL_GPL(unregister_ftrace_direct_multi);

/**
 * modify_ftrace_direct_multi - Modify an existing direct 'multi' call
 * to call something else
 * @ops: The address of the struct ftrace_ops object
 * @addr: The address of the new trampoline to call at @ops functions
 *
 * This is used to unregister currently registered direct caller and
 * register new one @addr on functions registered in @ops object.
 *
 * Note there's window between ftrace_shutdown and ftrace_startup calls
 * where there will be no callbacks called.
 *
 * Returns: zero on success. Non zero on error, which includes:
 *  -EINVAL - The @ops object was not properly registered.
 */
int modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)
static int
__modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)
{
	struct ftrace_hash *hash;
	struct ftrace_func_entry *entry, *iter;
@@ -5717,12 +5703,7 @@ int modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)
	int i, size;
	int err;

	if (check_direct_multi(ops))
		return -EINVAL;
	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
		return -EINVAL;

	mutex_lock(&direct_mutex);
	lockdep_assert_held_once(&direct_mutex);

	/* Enable the tmp_ops to have the same functions as the direct ops */
	ftrace_ops_init(&tmp_ops);
@@ -5730,7 +5711,7 @@ int modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)

	err = register_ftrace_function(&tmp_ops);
	if (err)
		goto out_direct;
		return err;

	/*
	 * Now the ftrace_ops_list_func() is called to do the direct callers.
@@ -5754,7 +5735,64 @@ int modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)
	/* Removing the tmp_ops will add the updated direct callers to the functions */
	unregister_ftrace_function(&tmp_ops);

 out_direct:
	return err;
}

/**
 * modify_ftrace_direct_multi_nolock - Modify an existing direct 'multi' call
 * to call something else
 * @ops: The address of the struct ftrace_ops object
 * @addr: The address of the new trampoline to call at @ops functions
 *
 * This is used to unregister currently registered direct caller and
 * register new one @addr on functions registered in @ops object.
 *
 * Note there's window between ftrace_shutdown and ftrace_startup calls
 * where there will be no callbacks called.
 *
 * Caller should already have direct_mutex locked, so we don't lock
 * direct_mutex here.
 *
 * Returns: zero on success. Non zero on error, which includes:
 *  -EINVAL - The @ops object was not properly registered.
 */
int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsigned long addr)
{
	if (check_direct_multi(ops))
		return -EINVAL;
	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
		return -EINVAL;

	return __modify_ftrace_direct_multi(ops, addr);
}
EXPORT_SYMBOL_GPL(modify_ftrace_direct_multi_nolock);

/**
 * modify_ftrace_direct_multi - Modify an existing direct 'multi' call
 * to call something else
 * @ops: The address of the struct ftrace_ops object
 * @addr: The address of the new trampoline to call at @ops functions
 *
 * This is used to unregister currently registered direct caller and
 * register new one @addr on functions registered in @ops object.
 *
 * Note there's window between ftrace_shutdown and ftrace_startup calls
 * where there will be no callbacks called.
 *
 * Returns: zero on success. Non zero on error, which includes:
 *  -EINVAL - The @ops object was not properly registered.
 */
int modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)
{
	int err;

	if (check_direct_multi(ops))
		return -EINVAL;
	if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
		return -EINVAL;

	mutex_lock(&direct_mutex);
	err = __modify_ftrace_direct_multi(ops, addr);
	mutex_unlock(&direct_mutex);
	return err;
}