Commit ccf5a89e authored by Jiri Olsa's avatar Jiri Olsa Committed by Steven Rostedt (VMware)
Browse files

ftrace: Add multi direct modify interface

Adding interface to modify registered direct function
for ftrace_ops. Adding following function:

   modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)

The function changes the currently registered direct
function for all attached functions.

Link: https://lkml.kernel.org/r/20211008091336.33616-8-jolsa@kernel.org



Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent f64dd462
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -326,6 +326,8 @@ int ftrace_modify_direct_caller(struct ftrace_func_entry *entry,
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);

#else
struct ftrace_ops;
# define ftrace_direct_func_count 0
@@ -365,6 +367,10 @@ static inline int unregister_ftrace_direct_multi(struct ftrace_ops *ops, unsigne
{
	return -ENODEV;
}
static inline int modify_ftrace_direct_multi(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 −0
Original line number Diff line number Diff line
@@ -5543,6 +5543,68 @@ int unregister_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)
	return err;
}
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)
{
	struct ftrace_hash *hash = ops->func_hash->filter_hash;
	struct ftrace_func_entry *entry, *iter;
	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);
	mutex_lock(&ftrace_lock);

	/*
	 * Shutdown the ops, change 'direct' pointer for each
	 * ops entry in direct_functions hash and startup the
	 * ops back again.
	 *
	 * Note there is no callback called for @ops object after
	 * this ftrace_shutdown call until ftrace_startup is called
	 * later on.
	 */
	err = ftrace_shutdown(ops, 0);
	if (err)
		goto out_unlock;

	size = 1 << hash->size_bits;
	for (i = 0; i < size; i++) {
		hlist_for_each_entry(iter, &hash->buckets[i], hlist) {
			entry = __ftrace_lookup_ip(direct_functions, iter->ip);
			if (!entry)
				continue;
			entry->direct = addr;
		}
	}

	err = ftrace_startup(ops, 0);

 out_unlock:
	mutex_unlock(&ftrace_lock);
	mutex_unlock(&direct_mutex);
	return err;
}
EXPORT_SYMBOL_GPL(modify_ftrace_direct_multi);
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */

/**