* [PATCHv3 bpf-next 1/8] ftrace: Make alloc_and_copy_ftrace_hash direct friendly
2025-11-20 21:23 [PATCHv3 bpf-next 0/8] ftrace,bpf: Use single direct ops for bpf trampolines Jiri Olsa
@ 2025-11-20 21:23 ` Jiri Olsa
2025-11-20 21:23 ` [PATCHv3 bpf-next 2/8] ftrace: Export some of hash related functions Jiri Olsa
` (6 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2025-11-20 21:23 UTC (permalink / raw)
To: Steven Rostedt, Florent Revest, Mark Rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Menglong Dong, Song Liu
Make alloc_and_copy_ftrace_hash to copy also direct address
for each hash entry.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/trace/ftrace.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 59cfacb8a5bb..0e3714b796d9 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1186,7 +1186,7 @@ static void __add_hash_entry(struct ftrace_hash *hash,
}
static struct ftrace_func_entry *
-add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
+add_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long direct)
{
struct ftrace_func_entry *entry;
@@ -1195,11 +1195,18 @@ add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
return NULL;
entry->ip = ip;
+ entry->direct = direct;
__add_hash_entry(hash, entry);
return entry;
}
+static struct ftrace_func_entry *
+add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
+{
+ return add_hash_entry_direct(hash, ip, 0);
+}
+
static void
free_hash_entry(struct ftrace_hash *hash,
struct ftrace_func_entry *entry)
@@ -1372,7 +1379,7 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
size = 1 << hash->size_bits;
for (i = 0; i < size; i++) {
hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
- if (add_hash_entry(new_hash, entry->ip) == NULL)
+ if (add_hash_entry_direct(new_hash, entry->ip, entry->direct) == NULL)
goto free_hash;
}
}
--
2.51.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCHv3 bpf-next 2/8] ftrace: Export some of hash related functions
2025-11-20 21:23 [PATCHv3 bpf-next 0/8] ftrace,bpf: Use single direct ops for bpf trampolines Jiri Olsa
2025-11-20 21:23 ` [PATCHv3 bpf-next 1/8] ftrace: Make alloc_and_copy_ftrace_hash direct friendly Jiri Olsa
@ 2025-11-20 21:23 ` Jiri Olsa
2025-11-20 21:23 ` [PATCHv3 bpf-next 3/8] ftrace: Add update_ftrace_direct_add function Jiri Olsa
` (5 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2025-11-20 21:23 UTC (permalink / raw)
To: Steven Rostedt, Florent Revest, Mark Rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Menglong Dong, Song Liu
We are going to use these functions in following changes.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
include/linux/ftrace.h | 16 ++++++++++++++++
kernel/trace/ftrace.c | 7 +++----
kernel/trace/trace.h | 8 --------
3 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 07f8c309e432..5752553bff60 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -405,6 +405,22 @@ enum ftrace_ops_cmd {
typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, enum ftrace_ops_cmd cmd);
#ifdef CONFIG_DYNAMIC_FTRACE
+
+#define FTRACE_HASH_DEFAULT_BITS 10
+
+struct ftrace_hash {
+ unsigned long size_bits;
+ struct hlist_head *buckets;
+ unsigned long count;
+ unsigned long flags;
+ struct rcu_head rcu;
+};
+
+struct ftrace_hash *alloc_ftrace_hash(int size_bits);
+void free_ftrace_hash(struct ftrace_hash *hash);
+struct ftrace_func_entry *add_hash_entry_direct(struct ftrace_hash *hash,
+ unsigned long ip, unsigned long direct);
+
/* The hash used to know what functions callbacks trace */
struct ftrace_ops_hash {
struct ftrace_hash __rcu *notrace_hash;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 0e3714b796d9..e6ccf572c5f6 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -68,7 +68,6 @@
})
/* hash bits for specific function selection */
-#define FTRACE_HASH_DEFAULT_BITS 10
#define FTRACE_HASH_MAX_BITS 12
#ifdef CONFIG_DYNAMIC_FTRACE
@@ -1185,7 +1184,7 @@ static void __add_hash_entry(struct ftrace_hash *hash,
hash->count++;
}
-static struct ftrace_func_entry *
+struct ftrace_func_entry *
add_hash_entry_direct(struct ftrace_hash *hash, unsigned long ip, unsigned long direct)
{
struct ftrace_func_entry *entry;
@@ -1265,7 +1264,7 @@ static void clear_ftrace_mod_list(struct list_head *head)
mutex_unlock(&ftrace_lock);
}
-static void free_ftrace_hash(struct ftrace_hash *hash)
+void free_ftrace_hash(struct ftrace_hash *hash)
{
if (!hash || hash == EMPTY_HASH)
return;
@@ -1305,7 +1304,7 @@ void ftrace_free_filter(struct ftrace_ops *ops)
}
EXPORT_SYMBOL_GPL(ftrace_free_filter);
-static struct ftrace_hash *alloc_ftrace_hash(int size_bits)
+struct ftrace_hash *alloc_ftrace_hash(int size_bits)
{
struct ftrace_hash *hash;
int size;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 85eabb454bee..62e0ac625f65 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -899,14 +899,6 @@ enum {
FTRACE_HASH_FL_MOD = (1 << 0),
};
-struct ftrace_hash {
- unsigned long size_bits;
- struct hlist_head *buckets;
- unsigned long count;
- unsigned long flags;
- struct rcu_head rcu;
-};
-
struct ftrace_func_entry *
ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip);
--
2.51.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCHv3 bpf-next 3/8] ftrace: Add update_ftrace_direct_add function
2025-11-20 21:23 [PATCHv3 bpf-next 0/8] ftrace,bpf: Use single direct ops for bpf trampolines Jiri Olsa
2025-11-20 21:23 ` [PATCHv3 bpf-next 1/8] ftrace: Make alloc_and_copy_ftrace_hash direct friendly Jiri Olsa
2025-11-20 21:23 ` [PATCHv3 bpf-next 2/8] ftrace: Export some of hash related functions Jiri Olsa
@ 2025-11-20 21:23 ` Jiri Olsa
2025-11-21 16:20 ` kernel test robot
2025-11-20 21:23 ` [PATCHv3 bpf-next 4/8] ftrace: Add update_ftrace_direct_del function Jiri Olsa
` (4 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2025-11-20 21:23 UTC (permalink / raw)
To: Steven Rostedt, Florent Revest, Mark Rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Menglong Dong, Song Liu
Adding update_ftrace_direct_add function that adds all entries
(ip -> addr) provided in hash argument to direct ftrace ops
and updates its attachments.
The difference to current register_ftrace_direct is
- hash argument that allows to register multiple ip -> direct
entries at once
- we can call update_ftrace_direct_add multiple times on the
same ftrace_ops object, becase after first registration with
register_ftrace_function_nolock, it uses ftrace_update_ops to
update the ftrace_ops object
This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
include/linux/ftrace.h | 7 +++
kernel/trace/ftrace.c | 128 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 135 insertions(+)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 5752553bff60..9cf4cd56d982 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -550,6 +550,8 @@ int unregister_ftrace_direct(struct ftrace_ops *ops, unsigned long addr,
int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
+int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
+
void ftrace_stub_direct_tramp(void);
#else
@@ -576,6 +578,11 @@ static inline int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned l
return -ENODEV;
}
+static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+ return -ENODEV;
+}
+
/*
* This must be implemented by the architecture.
* It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index e6ccf572c5f6..850ff55ff25e 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6248,6 +6248,134 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
return err;
}
EXPORT_SYMBOL_GPL(modify_ftrace_direct);
+
+static unsigned long hash_count(struct ftrace_hash *hash)
+{
+ return hash ? hash->count : 0;
+}
+
+/**
+ * hash_add - adds two struct ftrace_hash and returns the result
+ * @a: struct ftrace_hash object
+ * @b: struct ftrace_hash object
+ *
+ * Returns struct ftrace_hash object on success, NULL on error.
+ */
+static struct ftrace_hash *hash_add(struct ftrace_hash *a, struct ftrace_hash *b)
+{
+ struct ftrace_func_entry *entry;
+ struct ftrace_hash *add;
+ int size, i;
+
+ size = hash_count(a) + hash_count(b);
+ if (size > 32)
+ size = 32;
+
+ add = alloc_and_copy_ftrace_hash(fls(size), a);
+ if (!add)
+ goto error;
+
+ size = 1 << b->size_bits;
+ for (i = 0; i < size; i++) {
+ hlist_for_each_entry(entry, &b->buckets[i], hlist) {
+ if (add_hash_entry_direct(add, entry->ip, entry->direct) == NULL)
+ goto error;
+ }
+ }
+ return add;
+
+ error:
+ free_ftrace_hash(add);
+ return NULL;
+}
+
+int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+ struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions = NULL;
+ struct ftrace_hash *old_filter_hash = NULL, *new_filter_hash = NULL;
+ struct ftrace_func_entry *entry;
+ int i, size, err = -EINVAL;
+ bool reg;
+
+ if (!hash_count(hash))
+ return -EINVAL;
+
+ mutex_lock(&direct_mutex);
+
+ /* Make sure requested entries are not already registered. */
+ size = 1 << hash->size_bits;
+ for (i = 0; i < size; i++) {
+ hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+ if (__ftrace_lookup_ip(direct_functions, entry->ip))
+ goto out_unlock;
+ }
+ }
+
+ old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+ old_direct_functions = direct_functions;
+
+ /* If there's nothing in filter_hash we need to register the ops. */
+ reg = hash_count(old_filter_hash) == 0;
+ if (reg) {
+ if (ops->func || ops->trampoline)
+ goto out_unlock;
+ if (ops->flags & FTRACE_OPS_FL_ENABLED)
+ goto out_unlock;
+ }
+
+ err = -ENOMEM;
+ new_filter_hash = hash_add(old_filter_hash, hash);
+ if (!new_filter_hash)
+ goto out_unlock;
+
+ new_direct_functions = hash_add(old_direct_functions, hash);
+ if (!new_direct_functions)
+ goto out_unlock;
+
+ rcu_assign_pointer(direct_functions, new_direct_functions);
+
+ if (reg) {
+ ops->func = call_direct_funcs;
+ ops->flags |= MULTI_FLAGS;
+ ops->trampoline = FTRACE_REGS_ADDR;
+ ops->local_hash.filter_hash = new_filter_hash;
+
+ err = register_ftrace_function_nolock(ops);
+ if (err) {
+ /* restore old filter on error */
+ ops->local_hash.filter_hash = old_filter_hash;
+ old_filter_hash = new_filter_hash;
+
+ /* cleanup for possible another register call */
+ ops->func = NULL;
+ ops->trampoline = 0;
+ }
+ } else {
+ err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
+ /*
+ * new_filter_hash is dup-ed, so we need to release it anyway,
+ * old_filter_hash either stays on error or is released already
+ */
+ old_filter_hash = new_filter_hash;
+ }
+
+ if (err) {
+ /* reset direct_functions and free the new one */
+ rcu_assign_pointer(direct_functions, old_direct_functions);
+ old_direct_functions = new_direct_functions;
+ }
+
+ out_unlock:
+ mutex_unlock(&direct_mutex);
+
+ if (old_direct_functions && old_direct_functions != EMPTY_HASH)
+ call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
+ if (old_filter_hash)
+ free_ftrace_hash(old_filter_hash);
+
+ return err;
+}
+
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
/**
--
2.51.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCHv3 bpf-next 3/8] ftrace: Add update_ftrace_direct_add function
2025-11-20 21:23 ` [PATCHv3 bpf-next 3/8] ftrace: Add update_ftrace_direct_add function Jiri Olsa
@ 2025-11-21 16:20 ` kernel test robot
0 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2025-11-21 16:20 UTC (permalink / raw)
To: Jiri Olsa; +Cc: oe-kbuild-all
Hi Jiri,
kernel test robot noticed the following build warnings:
[auto build test WARNING on bpf-next/master]
url: https://github.com/intel-lab-lkp/linux/commits/Jiri-Olsa/ftrace-Make-alloc_and_copy_ftrace_hash-direct-friendly/20251121-052934
base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link: https://lore.kernel.org/r/20251120212402.466524-4-jolsa%40kernel.org
patch subject: [PATCHv3 bpf-next 3/8] ftrace: Add update_ftrace_direct_add function
config: s390-randconfig-r132-20251121 (https://download.01.org/0day-ci/archive/20251122/202511220041.UvsDWyEm-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 12.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251122/202511220041.UvsDWyEm-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511220041.UvsDWyEm-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
kernel/trace/ftrace.c:317:50: sparse: expected struct ftrace_ops **p
kernel/trace/ftrace.c:317:50: sparse: got struct ftrace_ops [noderef] __rcu **
kernel/trace/ftrace.c:324:12: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_ops * @@ got struct ftrace_ops [noderef] __rcu *next @@
kernel/trace/ftrace.c:324:12: sparse: expected struct ftrace_ops *
kernel/trace/ftrace.c:324:12: sparse: got struct ftrace_ops [noderef] __rcu *next
kernel/trace/ftrace.c:1067:43: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:1067:43: sparse: expected struct ftrace_hash [noderef] __rcu *notrace_hash
kernel/trace/ftrace.c:1067:43: sparse: got struct ftrace_hash *
kernel/trace/ftrace.c:1068:43: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:1068:43: sparse: expected struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:1068:43: sparse: got struct ftrace_hash *
kernel/trace/ftrace.c:1300:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:1300:40: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:1300:40: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:1301:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:1301:40: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:1301:40: sparse: got struct ftrace_hash [noderef] __rcu *notrace_hash
kernel/trace/ftrace.c:1302:37: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:1302:37: sparse: expected struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:1302:37: sparse: got struct ftrace_hash *
kernel/trace/ftrace.c:1303:38: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:1303:38: sparse: expected struct ftrace_hash [noderef] __rcu *notrace_hash
kernel/trace/ftrace.c:1303:38: sparse: got struct ftrace_hash *
kernel/trace/ftrace.c:2115:54: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *old_hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:2115:54: sparse: expected struct ftrace_hash *old_hash
kernel/trace/ftrace.c:2115:54: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:1507:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/trace/ftrace.c:1507:9: sparse: struct ftrace_hash [noderef] __rcu *
kernel/trace/ftrace.c:1507:9: sparse: struct ftrace_hash *
kernel/trace/ftrace.c:1523:39: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:1524:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:1525:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:1526:42: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:1697:18: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_ops *ops @@ got struct ftrace_ops [noderef] __rcu *[addressable] [toplevel] ftrace_ops_list @@
kernel/trace/ftrace.c:1698:43: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_ops *ops @@ got struct ftrace_ops [noderef] __rcu *next @@
kernel/trace/ftrace.c:1759:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:1760:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *notrace_hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:2093:50: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:2104:50: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:2587:53: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:2598:36: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@
kernel/trace/ftrace.c:3394:51: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *B @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3395:66: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:3401:52: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *B @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3402:66: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:3415:41: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3416:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *src @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3419:52: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *notrace_hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3423:52: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *src @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3438:39: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3439:42: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3447:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3453:81: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3457:54: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *notrace_hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3459:56: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *new_hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3489:60: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *new_hash1 @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3490:49: sparse: sparse: incorrect type in argument 3 (different address spaces) @@ expected struct ftrace_hash *new_hash2 @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3529:45: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3531:46: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3533:48: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3535:49: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3541:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3542:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3548:34: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *save_filter_hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3549:35: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *save_notrace_hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3551:45: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *[addressable] filter_hash @@
kernel/trace/ftrace.c:3552:46: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash *[addressable] notrace_hash @@
kernel/trace/ftrace.c:3557:53: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *save_filter_hash @@
kernel/trace/ftrace.c:3558:54: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash *save_notrace_hash @@
kernel/trace/ftrace.c:3605:31: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3606:32: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3621:59: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *[addressable] filter_hash @@
kernel/trace/ftrace.c:3622:59: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *[addressable] notrace_hash @@
kernel/trace/ftrace.c:3627:43: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *[addressable] filter_hash @@
kernel/trace/ftrace.c:3628:43: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *[addressable] notrace_hash @@
kernel/trace/ftrace.c:3630:39: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *[addressable] filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3631:40: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *[addressable] notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3673:48: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3674:48: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3675:45: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3676:46: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3962:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3979:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:4665:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:4668:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:5079:27: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5081:27: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5461:19: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5605:19: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5611:34: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *[assigned] old_hash @@
kernel/trace/ftrace.c:5876:27: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5878:27: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5959:50: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@
kernel/trace/ftrace.c:5961:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@
kernel/trace/ftrace.c:5977:50: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:6021:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:6071:19: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *free_hash @@ got struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@
kernel/trace/ftrace.c:6136:50: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:6174:52: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [addressable] [assigned] [toplevel] direct_functions @@
kernel/trace/ftrace.c:6309:48: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [addressable] [assigned] [toplevel] direct_functions @@
>> kernel/trace/ftrace.c:6314:25: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *old_filter_hash @@ got struct ftrace_hash [noderef] __rcu * @@
>> kernel/trace/ftrace.c:6315:30: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *old_direct_functions @@ got struct ftrace_hash [noderef] __rcu *static [addressable] [assigned] [toplevel] direct_functions @@
>> kernel/trace/ftrace.c:6341:45: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *[assigned] new_filter_hash @@
>> kernel/trace/ftrace.c:6346:53: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *old_filter_hash @@
kernel/trace/ftrace.c:6629:35: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *extern [addressable] [toplevel] ftrace_graph_hash @@ got struct ftrace_hash *[assigned] hash @@
kernel/trace/ftrace.c:6631:43: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *extern [addressable] [toplevel] ftrace_graph_notrace_hash @@ got struct ftrace_hash *[assigned] hash @@
kernel/trace/ftrace.c:6700:35: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:6708:35: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:6773:47: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *[addressable] [toplevel] ftrace_graph_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:6774:55: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *[addressable] [toplevel] ftrace_graph_notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:7493:46: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:7494:47: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:7498:44: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:7516:18: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_ops *ops @@ got struct ftrace_ops [noderef] __rcu *[addressable] [toplevel] ftrace_ops_list @@
kernel/trace/ftrace.c:7516:66: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_ops *ops @@ got struct ftrace_ops [noderef] __rcu *next @@
kernel/trace/ftrace.c:7568:59: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:7569:59: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:7958:62: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:7959:62: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:8003:36: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/trace/ftrace.c:8003:36: sparse: struct ftrace_ops [noderef] __rcu *
kernel/trace/ftrace.c:8003:36: sparse: struct ftrace_ops *
kernel/trace/ftrace.c:8779:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:8779:14: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:8779:14: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:8828:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:8828:14: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:8828:14: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:230:20: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:230:20: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:230:20: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:6039:30: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:6048:21: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:6050:17: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3754:48: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3754:48: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:3754:48: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:3755:49: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3755:49: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:3755:49: sparse: got struct ftrace_hash [noderef] __rcu *notrace_hash
vim +6314 kernel/trace/ftrace.c
6291
6292 int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
6293 {
6294 struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions = NULL;
6295 struct ftrace_hash *old_filter_hash = NULL, *new_filter_hash = NULL;
6296 struct ftrace_func_entry *entry;
6297 int i, size, err = -EINVAL;
6298 bool reg;
6299
6300 if (!hash_count(hash))
6301 return -EINVAL;
6302
6303 mutex_lock(&direct_mutex);
6304
6305 /* Make sure requested entries are not already registered. */
6306 size = 1 << hash->size_bits;
6307 for (i = 0; i < size; i++) {
6308 hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
6309 if (__ftrace_lookup_ip(direct_functions, entry->ip))
6310 goto out_unlock;
6311 }
6312 }
6313
> 6314 old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> 6315 old_direct_functions = direct_functions;
6316
6317 /* If there's nothing in filter_hash we need to register the ops. */
6318 reg = hash_count(old_filter_hash) == 0;
6319 if (reg) {
6320 if (ops->func || ops->trampoline)
6321 goto out_unlock;
6322 if (ops->flags & FTRACE_OPS_FL_ENABLED)
6323 goto out_unlock;
6324 }
6325
6326 err = -ENOMEM;
6327 new_filter_hash = hash_add(old_filter_hash, hash);
6328 if (!new_filter_hash)
6329 goto out_unlock;
6330
6331 new_direct_functions = hash_add(old_direct_functions, hash);
6332 if (!new_direct_functions)
6333 goto out_unlock;
6334
6335 rcu_assign_pointer(direct_functions, new_direct_functions);
6336
6337 if (reg) {
6338 ops->func = call_direct_funcs;
6339 ops->flags |= MULTI_FLAGS;
6340 ops->trampoline = FTRACE_REGS_ADDR;
> 6341 ops->local_hash.filter_hash = new_filter_hash;
6342
6343 err = register_ftrace_function_nolock(ops);
6344 if (err) {
6345 /* restore old filter on error */
> 6346 ops->local_hash.filter_hash = old_filter_hash;
6347 old_filter_hash = new_filter_hash;
6348
6349 /* cleanup for possible another register call */
6350 ops->func = NULL;
6351 ops->trampoline = 0;
6352 }
6353 } else {
6354 err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
6355 /*
6356 * new_filter_hash is dup-ed, so we need to release it anyway,
6357 * old_filter_hash either stays on error or is released already
6358 */
6359 old_filter_hash = new_filter_hash;
6360 }
6361
6362 if (err) {
6363 /* reset direct_functions and free the new one */
6364 rcu_assign_pointer(direct_functions, old_direct_functions);
6365 old_direct_functions = new_direct_functions;
6366 }
6367
6368 out_unlock:
6369 mutex_unlock(&direct_mutex);
6370
6371 if (old_direct_functions && old_direct_functions != EMPTY_HASH)
6372 call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
6373 if (old_filter_hash)
6374 free_ftrace_hash(old_filter_hash);
6375
6376 return err;
6377 }
6378
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCHv3 bpf-next 4/8] ftrace: Add update_ftrace_direct_del function
2025-11-20 21:23 [PATCHv3 bpf-next 0/8] ftrace,bpf: Use single direct ops for bpf trampolines Jiri Olsa
` (2 preceding siblings ...)
2025-11-20 21:23 ` [PATCHv3 bpf-next 3/8] ftrace: Add update_ftrace_direct_add function Jiri Olsa
@ 2025-11-20 21:23 ` Jiri Olsa
2025-11-20 22:23 ` bot+bpf-ci
2025-11-20 21:23 ` [PATCHv3 bpf-next 5/8] ftrace: Add update_ftrace_direct_mod function Jiri Olsa
` (3 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2025-11-20 21:23 UTC (permalink / raw)
To: Steven Rostedt, Florent Revest, Mark Rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Menglong Dong, Song Liu
Adding update_ftrace_direct_del function that removes all entries
(ip -> addr) provided in hash argument to direct ftrace ops and
updates its attachments.
The difference to current unregister_ftrace_direct is
- hash argument that allows to unregister multiple ip -> direct
entries at once
- we can call update_ftrace_direct_del multiple times on the
same ftrace_ops object, becase we do not need to unregister
all entries at once, we can do it gradualy with the help of
ftrace_update_ops function
This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
include/linux/ftrace.h | 6 +++
kernel/trace/ftrace.c | 110 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 116 insertions(+)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 9cf4cd56d982..c571deeff840 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -551,6 +551,7 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
+int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
void ftrace_stub_direct_tramp(void);
@@ -583,6 +584,11 @@ static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace
return -ENODEV;
}
+static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+ return -ENODEV;
+}
+
/*
* This must be implemented by the architecture.
* It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 850ff55ff25e..cc730a8fd087 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6376,6 +6376,116 @@ int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
return err;
}
+/**
+ * hash_sub - substracts @b from @a and returns the result
+ * @a: struct ftrace_hash object
+ * @b: struct ftrace_hash object
+ *
+ * Returns struct ftrace_hash object on success, NULL on error.
+ */
+static struct ftrace_hash *hash_sub(struct ftrace_hash *a, struct ftrace_hash *b)
+{
+ struct ftrace_func_entry *entry, *del;
+ struct ftrace_hash *sub;
+ int size, i;
+
+ sub = alloc_and_copy_ftrace_hash(a->size_bits, a);
+ if (!sub)
+ goto error;
+
+ size = 1 << b->size_bits;
+ for (i = 0; i < size; i++) {
+ hlist_for_each_entry(entry, &b->buckets[i], hlist) {
+ del = __ftrace_lookup_ip(sub, entry->ip);
+ if (WARN_ON_ONCE(!del))
+ goto error;
+ remove_hash_entry(sub, del);
+ kfree(del);
+ }
+ }
+ return sub;
+
+ error:
+ free_ftrace_hash(sub);
+ return NULL;
+}
+
+int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
+{
+ struct ftrace_hash *old_direct_functions = NULL, *new_direct_functions = NULL;
+ struct ftrace_hash *old_filter_hash = NULL, *new_filter_hash = NULL;
+ struct ftrace_func_entry *del, *entry;
+ unsigned long size, i;
+ int err = -EINVAL;
+
+ if (!hash_count(hash))
+ return -EINVAL;
+ if (check_direct_multi(ops))
+ return -EINVAL;
+ if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+ return -EINVAL;
+ if (direct_functions == EMPTY_HASH)
+ return -EINVAL;
+
+ mutex_lock(&direct_mutex);
+
+ old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
+ old_direct_functions = direct_functions;
+
+ /* Make sure requested entries are already registered. */
+ size = 1 << hash->size_bits;
+ for (i = 0; i < size; i++) {
+ hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+ del = __ftrace_lookup_ip(direct_functions, entry->ip);
+ if (!del || del->direct != entry->direct)
+ goto out_unlock;
+ }
+ }
+
+ err = -ENOMEM;
+ new_filter_hash = hash_sub(old_filter_hash, hash);
+ if (!new_filter_hash)
+ goto out_unlock;
+
+ new_direct_functions = hash_sub(old_direct_functions, hash);
+ if (!new_direct_functions)
+ goto out_unlock;
+
+ /* If there's nothing left, we need to unregister the ops. */
+ if (ftrace_hash_empty(new_filter_hash)) {
+ err = unregister_ftrace_function(ops);
+ if (!err) {
+ /* cleanup for possible another register call */
+ ops->func = NULL;
+ ops->trampoline = 0;
+ ftrace_free_filter(ops);
+ ops->func_hash->filter_hash = NULL;
+ }
+ } else {
+ err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
+ /*
+ * new_filter_hash is dup-ed, so we need to release it anyway,
+ * old_filter_hash either stays on error or is released already
+ */
+ }
+
+ if (err) {
+ /* reset direct_functions and free the new one */
+ old_direct_functions = new_direct_functions;
+ } else {
+ rcu_assign_pointer(direct_functions, new_direct_functions);
+ }
+
+ out_unlock:
+ mutex_unlock(&direct_mutex);
+
+ if (old_direct_functions && old_direct_functions != EMPTY_HASH)
+ call_rcu_tasks(&old_direct_functions->rcu, register_ftrace_direct_cb);
+ free_ftrace_hash(new_filter_hash);
+
+ return err;
+}
+
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
/**
--
2.51.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCHv3 bpf-next 4/8] ftrace: Add update_ftrace_direct_del function
2025-11-20 21:23 ` [PATCHv3 bpf-next 4/8] ftrace: Add update_ftrace_direct_del function Jiri Olsa
@ 2025-11-20 22:23 ` bot+bpf-ci
2025-11-21 13:52 ` Jiri Olsa
0 siblings, 1 reply; 16+ messages in thread
From: bot+bpf-ci @ 2025-11-20 22:23 UTC (permalink / raw)
To: jolsa, rostedt, revest, mark.rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel, ast,
daniel, andrii, menglong8.dong, song, ast, andrii, daniel,
martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2989 bytes --]
> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index 9cf4cd56d..c571deeff 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
> @@ -551,6 +551,7 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
> int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
>
> int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
> +int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
>
> void ftrace_stub_direct_tramp(void);
>
> @@ -583,6 +584,11 @@ static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace
> return -ENODEV;
> }
>
> +static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> +{
> + return -ENODEV;
> +}
> +
[ ... ]
> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index 850ff55ff..cc730a8fd 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
[ ... ]
> +/**
> + * hash_sub - substracts @b from @a and returns the result
> + * @a: struct ftrace_hash object
> + * @b: struct ftrace_hash object
> + *
> + * Returns struct ftrace_hash object on success, NULL on error.
> + */
> +static struct ftrace_hash *hash_sub(struct ftrace_hash *a, struct ftrace_hash *b)
> +{
> + struct ftrace_func_entry *entry, *del;
> + struct ftrace_hash *sub;
> + int size, i;
> +
> + sub = alloc_and_copy_ftrace_hash(a->size_bits, a);
^^^^^^^^^^^^
Can hash_sub() handle a NULL hash pointer in parameter a? I notice the
parallel function hash_add() safely handles NULL via hash_count() and
alloc_and_copy_ftrace_hash() which checks ftrace_hash_empty().
However, hash_sub() directly dereferences a->size_bits before passing a
to alloc_and_copy_ftrace_hash(). This will crash if a is NULL.
This matters because update_ftrace_direct_del() calls hash_sub() with
old_filter_hash which can be NULL:
old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
...
new_filter_hash = hash_sub(old_filter_hash, hash);
The existing update_ftrace_direct_add() has the same defensive check and
passes the potentially-NULL old_filter_hash to hash_add(), which handles
it correctly.
> + if (!sub)
> + goto error;
> +
> + size = 1 << b->size_bits;
> + for (i = 0; i < size; i++) {
> + hlist_for_each_entry(entry, &b->buckets[i], hlist) {
> + del = __ftrace_lookup_ip(sub, entry->ip);
> + if (WARN_ON_ONCE(!del))
> + goto error;
> + remove_hash_entry(sub, del);
> + kfree(del);
> + }
> + }
> + return sub;
> +
> + error:
> + free_ftrace_hash(sub);
> + return NULL;
> +}
> +
> +int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> +{
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/19552032346
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCHv3 bpf-next 4/8] ftrace: Add update_ftrace_direct_del function
2025-11-20 22:23 ` bot+bpf-ci
@ 2025-11-21 13:52 ` Jiri Olsa
0 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2025-11-21 13:52 UTC (permalink / raw)
To: bot+bpf-ci
Cc: rostedt, revest, mark.rutland, bpf, linux-kernel,
linux-trace-kernel, linux-arm-kernel, ast, daniel, andrii,
menglong8.dong, song, martin.lau, eddyz87, yonghong.song, clm,
ihor.solodrai
On Thu, Nov 20, 2025 at 10:23:46PM +0000, bot+bpf-ci@kernel.org wrote:
> > diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> > index 9cf4cd56d..c571deeff 100644
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
> > @@ -551,6 +551,7 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
> > int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
> >
> > int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
> > +int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
> >
> > void ftrace_stub_direct_tramp(void);
> >
> > @@ -583,6 +584,11 @@ static inline int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace
> > return -ENODEV;
> > }
> >
> > +static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> > +{
> > + return -ENODEV;
> > +}
> > +
>
> [ ... ]
>
> > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> > index 850ff55ff..cc730a8fd 100644
> > --- a/kernel/trace/ftrace.c
> > +++ b/kernel/trace/ftrace.c
>
> [ ... ]
>
> > +/**
> > + * hash_sub - substracts @b from @a and returns the result
> > + * @a: struct ftrace_hash object
> > + * @b: struct ftrace_hash object
> > + *
> > + * Returns struct ftrace_hash object on success, NULL on error.
> > + */
> > +static struct ftrace_hash *hash_sub(struct ftrace_hash *a, struct ftrace_hash *b)
> > +{
> > + struct ftrace_func_entry *entry, *del;
> > + struct ftrace_hash *sub;
> > + int size, i;
> > +
> > + sub = alloc_and_copy_ftrace_hash(a->size_bits, a);
> ^^^^^^^^^^^^
>
> Can hash_sub() handle a NULL hash pointer in parameter a? I notice the
> parallel function hash_add() safely handles NULL via hash_count() and
> alloc_and_copy_ftrace_hash() which checks ftrace_hash_empty().
>
> However, hash_sub() directly dereferences a->size_bits before passing a
> to alloc_and_copy_ftrace_hash(). This will crash if a is NULL.
>
> This matters because update_ftrace_direct_del() calls hash_sub() with
> old_filter_hash which can be NULL:
>
> old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
> ...
> new_filter_hash = hash_sub(old_filter_hash, hash);
>
> The existing update_ftrace_direct_add() has the same defensive check and
> passes the potentially-NULL old_filter_hash to hash_add(), which handles
> it correctly.
so we never call update_ftrace_direct_del without having
update_ftrace_direct_add called, which ensures the existence of filter_hash,
but it's probably good idea to do explicit check for future
thanks,
jirka
>
> > + if (!sub)
> > + goto error;
> > +
> > + size = 1 << b->size_bits;
> > + for (i = 0; i < size; i++) {
> > + hlist_for_each_entry(entry, &b->buckets[i], hlist) {
> > + del = __ftrace_lookup_ip(sub, entry->ip);
> > + if (WARN_ON_ONCE(!del))
> > + goto error;
> > + remove_hash_entry(sub, del);
> > + kfree(del);
> > + }
> > + }
> > + return sub;
> > +
> > + error:
> > + free_ftrace_hash(sub);
> > + return NULL;
> > +}
> > +
> > +int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> > +{
>
> [ ... ]
>
>
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
>
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/19552032346
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCHv3 bpf-next 5/8] ftrace: Add update_ftrace_direct_mod function
2025-11-20 21:23 [PATCHv3 bpf-next 0/8] ftrace,bpf: Use single direct ops for bpf trampolines Jiri Olsa
` (3 preceding siblings ...)
2025-11-20 21:23 ` [PATCHv3 bpf-next 4/8] ftrace: Add update_ftrace_direct_del function Jiri Olsa
@ 2025-11-20 21:23 ` Jiri Olsa
2025-11-20 22:23 ` bot+bpf-ci
2025-11-21 18:19 ` kernel test robot
2025-11-20 21:24 ` [PATCHv3 bpf-next 6/8] bpf: Add trampoline ip hash table Jiri Olsa
` (2 subsequent siblings)
7 siblings, 2 replies; 16+ messages in thread
From: Jiri Olsa @ 2025-11-20 21:23 UTC (permalink / raw)
To: Steven Rostedt, Florent Revest, Mark Rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Menglong Dong, Song Liu
Adding update_ftrace_direct_mod function that modifies all entries
(ip -> direct) provided in hash argument to direct ftrace ops and
updates its attachments.
The difference to current modify_ftrace_direct is:
- hash argument that allows to modify multiple ip -> direct
entries at once
This change will allow us to have simple ftrace_ops for all bpf
direct interface users in following changes.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
include/linux/ftrace.h | 6 ++++
kernel/trace/ftrace.c | 68 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index c571deeff840..4e2c0ed769fc 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -552,6 +552,7 @@ int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash);
int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash);
+int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock);
void ftrace_stub_direct_tramp(void);
@@ -589,6 +590,11 @@ static inline int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace
return -ENODEV;
}
+static inline int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
+{
+ return -ENODEV;
+}
+
/*
* This must be implemented by the architecture.
* It is the way the ftrace direct_ops helper, when called
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index cc730a8fd087..5243aefb6096 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6486,6 +6486,74 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
return err;
}
+int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
+{
+ struct ftrace_hash *orig_hash = ops->func_hash->filter_hash;
+ struct ftrace_func_entry *entry, *tmp;
+ static struct ftrace_ops tmp_ops = {
+ .func = ftrace_stub,
+ .flags = FTRACE_OPS_FL_STUB,
+ };
+ unsigned long size, i;
+ int err;
+
+ if (!hash_count(hash))
+ return -EINVAL;
+ if (check_direct_multi(ops))
+ return -EINVAL;
+ if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+ return -EINVAL;
+ if (direct_functions == EMPTY_HASH)
+ return -EINVAL;
+
+ if (do_direct_lock)
+ mutex_lock(&direct_mutex);
+
+ /* Enable the tmp_ops to have the same functions as the direct ops */
+ ftrace_ops_init(&tmp_ops);
+ tmp_ops.func_hash = ops->func_hash;
+
+ err = register_ftrace_function_nolock(&tmp_ops);
+ if (err)
+ goto unlock;
+
+ /*
+ * Call __ftrace_hash_update_ipmodify() here, so that we can call
+ * ops->ops_func for the ops. This is needed because the above
+ * register_ftrace_function_nolock() worked on tmp_ops.
+ */
+ err = __ftrace_hash_update_ipmodify(ops, orig_hash, orig_hash, true);
+ if (err)
+ goto out;
+
+ /*
+ * Now the ftrace_ops_list_func() is called to do the direct callers.
+ * We can safely change the direct functions attached to each entry.
+ */
+ mutex_lock(&ftrace_lock);
+
+ size = 1 << hash->size_bits;
+ for (i = 0; i < size; i++) {
+ hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
+ tmp = __ftrace_lookup_ip(direct_functions, entry->ip);
+ if (!tmp)
+ continue;
+ tmp->direct = entry->direct;
+ }
+ }
+
+ mutex_unlock(&ftrace_lock);
+
+out:
+ /* Removing the tmp_ops will add the updated direct callers to the functions */
+ unregister_ftrace_function(&tmp_ops);
+
+unlock:
+ if (do_direct_lock)
+ mutex_unlock(&direct_mutex);
+ return err;
+}
+
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
/**
--
2.51.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCHv3 bpf-next 5/8] ftrace: Add update_ftrace_direct_mod function
2025-11-20 21:23 ` [PATCHv3 bpf-next 5/8] ftrace: Add update_ftrace_direct_mod function Jiri Olsa
@ 2025-11-20 22:23 ` bot+bpf-ci
2025-11-21 13:53 ` Jiri Olsa
2025-11-21 18:19 ` kernel test robot
1 sibling, 1 reply; 16+ messages in thread
From: bot+bpf-ci @ 2025-11-20 22:23 UTC (permalink / raw)
To: jolsa, rostedt, revest, mark.rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel, ast,
daniel, andrii, menglong8.dong, song, ast, andrii, daniel,
martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 1662 bytes --]
> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index c571deeff..4e2c0ed76 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
[ ... ]
> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index cc730a8fd..5243aefb6 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
[ ... ]
> @@ -6486,6 +6486,74 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> return err;
> }
>
> +int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
> +{
> + struct ftrace_hash *orig_hash = ops->func_hash->filter_hash;
^^^^^^^^^^^^^^^^
Can this crash if ops->func_hash is NULL? In update_ftrace_direct_add()
and update_ftrace_direct_del(), there's a defensive check:
old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
But update_ftrace_direct_mod() dereferences ops->func_hash before any
validation checks occur. The check_direct_multi(ops) validation happens
later, but the dereference occurs first at function entry.
> + struct ftrace_func_entry *entry, *tmp;
> + static struct ftrace_ops tmp_ops = {
> + .func = ftrace_stub,
> + .flags = FTRACE_OPS_FL_STUB,
> + };
> + unsigned long size, i;
> + int err;
> +
> + if (!hash_count(hash))
> + return -EINVAL;
> + if (check_direct_multi(ops))
> + return -EINVAL;
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/19552032346
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCHv3 bpf-next 5/8] ftrace: Add update_ftrace_direct_mod function
2025-11-20 22:23 ` bot+bpf-ci
@ 2025-11-21 13:53 ` Jiri Olsa
0 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2025-11-21 13:53 UTC (permalink / raw)
To: bot+bpf-ci
Cc: rostedt, revest, mark.rutland, bpf, linux-kernel,
linux-trace-kernel, linux-arm-kernel, ast, daniel, andrii,
menglong8.dong, song, martin.lau, eddyz87, yonghong.song, clm,
ihor.solodrai
On Thu, Nov 20, 2025 at 10:23:47PM +0000, bot+bpf-ci@kernel.org wrote:
> > diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> > index c571deeff..4e2c0ed76 100644
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
>
> [ ... ]
>
> > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> > index cc730a8fd..5243aefb6 100644
> > --- a/kernel/trace/ftrace.c
> > +++ b/kernel/trace/ftrace.c
>
> [ ... ]
>
> > @@ -6486,6 +6486,74 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
> > return err;
> > }
> >
> > +int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
> > +{
> > + struct ftrace_hash *orig_hash = ops->func_hash->filter_hash;
> ^^^^^^^^^^^^^^^^
>
> Can this crash if ops->func_hash is NULL? In update_ftrace_direct_add()
> and update_ftrace_direct_del(), there's a defensive check:
>
> old_filter_hash = ops->func_hash ? ops->func_hash->filter_hash : NULL;
>
> But update_ftrace_direct_mod() dereferences ops->func_hash before any
> validation checks occur. The check_direct_multi(ops) validation happens
> later, but the dereference occurs first at function entry.
update_ftrace_direct_add is called before update_ftrace_direct_mod which
ensures the existence of the filter_hash, but same as for the update_ftrace_direct_del
case in the other reply, it's probably better to add the check for future
thanks,
jirka
>
> > + struct ftrace_func_entry *entry, *tmp;
> > + static struct ftrace_ops tmp_ops = {
> > + .func = ftrace_stub,
> > + .flags = FTRACE_OPS_FL_STUB,
> > + };
> > + unsigned long size, i;
> > + int err;
> > +
> > + if (!hash_count(hash))
> > + return -EINVAL;
> > + if (check_direct_multi(ops))
> > + return -EINVAL;
>
> [ ... ]
>
>
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
>
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/19552032346
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCHv3 bpf-next 5/8] ftrace: Add update_ftrace_direct_mod function
2025-11-20 21:23 ` [PATCHv3 bpf-next 5/8] ftrace: Add update_ftrace_direct_mod function Jiri Olsa
2025-11-20 22:23 ` bot+bpf-ci
@ 2025-11-21 18:19 ` kernel test robot
1 sibling, 0 replies; 16+ messages in thread
From: kernel test robot @ 2025-11-21 18:19 UTC (permalink / raw)
To: Jiri Olsa; +Cc: oe-kbuild-all
Hi Jiri,
kernel test robot noticed the following build warnings:
[auto build test WARNING on bpf-next/master]
url: https://github.com/intel-lab-lkp/linux/commits/Jiri-Olsa/ftrace-Make-alloc_and_copy_ftrace_hash-direct-friendly/20251121-052934
base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link: https://lore.kernel.org/r/20251120212402.466524-6-jolsa%40kernel.org
patch subject: [PATCHv3 bpf-next 5/8] ftrace: Add update_ftrace_direct_mod function
config: s390-randconfig-r132-20251121 (https://download.01.org/0day-ci/archive/20251122/202511220257.fB3eHgIF-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 12.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251122/202511220257.fB3eHgIF-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511220257.fB3eHgIF-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
kernel/trace/ftrace.c:1067:43: sparse: got struct ftrace_hash *
kernel/trace/ftrace.c:1068:43: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:1068:43: sparse: expected struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:1068:43: sparse: got struct ftrace_hash *
kernel/trace/ftrace.c:1300:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:1300:40: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:1300:40: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:1301:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:1301:40: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:1301:40: sparse: got struct ftrace_hash [noderef] __rcu *notrace_hash
kernel/trace/ftrace.c:1302:37: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:1302:37: sparse: expected struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:1302:37: sparse: got struct ftrace_hash *
kernel/trace/ftrace.c:1303:38: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:1303:38: sparse: expected struct ftrace_hash [noderef] __rcu *notrace_hash
kernel/trace/ftrace.c:1303:38: sparse: got struct ftrace_hash *
kernel/trace/ftrace.c:2115:54: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *old_hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:2115:54: sparse: expected struct ftrace_hash *old_hash
kernel/trace/ftrace.c:2115:54: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:1507:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/trace/ftrace.c:1507:9: sparse: struct ftrace_hash [noderef] __rcu *
kernel/trace/ftrace.c:1507:9: sparse: struct ftrace_hash *
kernel/trace/ftrace.c:1523:39: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:1524:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:1525:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:1526:42: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:1697:18: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_ops *ops @@ got struct ftrace_ops [noderef] __rcu *[addressable] [toplevel] ftrace_ops_list @@
kernel/trace/ftrace.c:1698:43: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_ops *ops @@ got struct ftrace_ops [noderef] __rcu *next @@
kernel/trace/ftrace.c:1759:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:1760:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *notrace_hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:2093:50: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:2104:50: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:2587:53: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:2598:36: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@
kernel/trace/ftrace.c:3394:51: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *B @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3395:66: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:3401:52: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *B @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3402:66: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:3415:41: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3416:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *src @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3419:52: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *notrace_hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3423:52: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *src @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3438:39: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3439:42: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3447:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3453:81: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3457:54: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *notrace_hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3459:56: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *new_hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3489:60: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *new_hash1 @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3490:49: sparse: sparse: incorrect type in argument 3 (different address spaces) @@ expected struct ftrace_hash *new_hash2 @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3529:45: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3531:46: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3533:48: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3535:49: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3541:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3542:17: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3548:34: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *save_filter_hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3549:35: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *save_notrace_hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3551:45: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *[addressable] filter_hash @@
kernel/trace/ftrace.c:3552:46: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash *[addressable] notrace_hash @@
kernel/trace/ftrace.c:3557:53: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *save_filter_hash @@
kernel/trace/ftrace.c:3558:54: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash *save_notrace_hash @@
kernel/trace/ftrace.c:3605:31: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3606:32: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3621:59: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *[addressable] filter_hash @@
kernel/trace/ftrace.c:3622:59: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *[addressable] notrace_hash @@
kernel/trace/ftrace.c:3627:43: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *[addressable] filter_hash @@
kernel/trace/ftrace.c:3628:43: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *[addressable] notrace_hash @@
kernel/trace/ftrace.c:3630:39: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *[addressable] filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3631:40: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *[addressable] notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3673:48: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3674:48: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3675:45: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3676:46: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:3962:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3979:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:4665:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:4668:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:5079:27: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5081:27: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5461:19: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5605:19: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5611:34: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *[assigned] old_hash @@
kernel/trace/ftrace.c:5876:27: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5878:27: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:5959:50: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@
kernel/trace/ftrace.c:5961:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@
kernel/trace/ftrace.c:5977:50: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:6021:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:6071:19: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *free_hash @@ got struct ftrace_hash [noderef] __rcu *static [toplevel] direct_functions @@
kernel/trace/ftrace.c:6136:50: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:6174:52: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [addressable] [assigned] [toplevel] direct_functions @@
kernel/trace/ftrace.c:6309:48: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *static [addressable] [assigned] [toplevel] direct_functions @@
kernel/trace/ftrace.c:6314:25: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *old_filter_hash @@ got struct ftrace_hash [noderef] __rcu * @@
kernel/trace/ftrace.c:6315:30: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *old_direct_functions @@ got struct ftrace_hash [noderef] __rcu *static [addressable] [assigned] [toplevel] direct_functions @@
kernel/trace/ftrace.c:6341:45: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *[assigned] new_filter_hash @@
kernel/trace/ftrace.c:6346:53: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *filter_hash @@ got struct ftrace_hash *old_filter_hash @@
kernel/trace/ftrace.c:6427:30: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/trace/ftrace.c:6427:30: sparse: struct ftrace_hash [noderef] __rcu *
kernel/trace/ftrace.c:6427:30: sparse: struct ftrace_hash *
>> kernel/trace/ftrace.c:6491:55: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash *orig_hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:6506:30: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/trace/ftrace.c:6506:30: sparse: struct ftrace_hash [noderef] __rcu *
kernel/trace/ftrace.c:6506:30: sparse: struct ftrace_hash *
kernel/trace/ftrace.c:6807:35: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *extern [addressable] [toplevel] ftrace_graph_hash @@ got struct ftrace_hash *[assigned] hash @@
kernel/trace/ftrace.c:6809:43: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *extern [addressable] [toplevel] ftrace_graph_notrace_hash @@ got struct ftrace_hash *[assigned] hash @@
kernel/trace/ftrace.c:6878:35: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:6886:35: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash **orig_hash @@ got struct ftrace_hash [noderef] __rcu ** @@
kernel/trace/ftrace.c:6951:47: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *[addressable] [toplevel] ftrace_graph_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:6952:55: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct ftrace_hash [noderef] __rcu *[addressable] [toplevel] ftrace_graph_notrace_hash @@ got struct ftrace_hash * @@
kernel/trace/ftrace.c:7671:46: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:7672:47: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:7676:44: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:7694:18: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_ops *ops @@ got struct ftrace_ops [noderef] __rcu *[addressable] [toplevel] ftrace_ops_list @@
kernel/trace/ftrace.c:7694:66: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_ops *ops @@ got struct ftrace_ops [noderef] __rcu *next @@
kernel/trace/ftrace.c:7746:59: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:7747:59: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:8136:62: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:8137:62: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:8181:36: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/trace/ftrace.c:8181:36: sparse: struct ftrace_ops [noderef] __rcu *
kernel/trace/ftrace.c:8181:36: sparse: struct ftrace_ops *
kernel/trace/ftrace.c:8957:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:8957:14: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:8957:14: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:9006:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:9006:14: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:9006:14: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:230:20: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:230:20: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:230:20: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3449:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3483:29: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:6039:30: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:6048:21: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:6050:17: sparse: sparse: dereference of noderef expression
kernel/trace/ftrace.c:3754:48: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *filter_hash @@
kernel/trace/ftrace.c:3754:48: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:3754:48: sparse: got struct ftrace_hash [noderef] __rcu *filter_hash
kernel/trace/ftrace.c:3755:49: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct ftrace_hash *hash @@ got struct ftrace_hash [noderef] __rcu *notrace_hash @@
kernel/trace/ftrace.c:3755:49: sparse: expected struct ftrace_hash *hash
kernel/trace/ftrace.c:3755:49: sparse: got struct ftrace_hash [noderef] __rcu *notrace_hash
vim +6491 kernel/trace/ftrace.c
6488
6489 int update_ftrace_direct_mod(struct ftrace_ops *ops, struct ftrace_hash *hash, bool do_direct_lock)
6490 {
> 6491 struct ftrace_hash *orig_hash = ops->func_hash->filter_hash;
6492 struct ftrace_func_entry *entry, *tmp;
6493 static struct ftrace_ops tmp_ops = {
6494 .func = ftrace_stub,
6495 .flags = FTRACE_OPS_FL_STUB,
6496 };
6497 unsigned long size, i;
6498 int err;
6499
6500 if (!hash_count(hash))
6501 return -EINVAL;
6502 if (check_direct_multi(ops))
6503 return -EINVAL;
6504 if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
6505 return -EINVAL;
6506 if (direct_functions == EMPTY_HASH)
6507 return -EINVAL;
6508
6509 if (do_direct_lock)
6510 mutex_lock(&direct_mutex);
6511
6512 /* Enable the tmp_ops to have the same functions as the direct ops */
6513 ftrace_ops_init(&tmp_ops);
6514 tmp_ops.func_hash = ops->func_hash;
6515
6516 err = register_ftrace_function_nolock(&tmp_ops);
6517 if (err)
6518 goto unlock;
6519
6520 /*
6521 * Call __ftrace_hash_update_ipmodify() here, so that we can call
6522 * ops->ops_func for the ops. This is needed because the above
6523 * register_ftrace_function_nolock() worked on tmp_ops.
6524 */
6525 err = __ftrace_hash_update_ipmodify(ops, orig_hash, orig_hash, true);
6526 if (err)
6527 goto out;
6528
6529 /*
6530 * Now the ftrace_ops_list_func() is called to do the direct callers.
6531 * We can safely change the direct functions attached to each entry.
6532 */
6533 mutex_lock(&ftrace_lock);
6534
6535 size = 1 << hash->size_bits;
6536 for (i = 0; i < size; i++) {
6537 hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
6538 tmp = __ftrace_lookup_ip(direct_functions, entry->ip);
6539 if (!tmp)
6540 continue;
6541 tmp->direct = entry->direct;
6542 }
6543 }
6544
6545 mutex_unlock(&ftrace_lock);
6546
6547 out:
6548 /* Removing the tmp_ops will add the updated direct callers to the functions */
6549 unregister_ftrace_function(&tmp_ops);
6550
6551 unlock:
6552 if (do_direct_lock)
6553 mutex_unlock(&direct_mutex);
6554 return err;
6555 }
6556
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCHv3 bpf-next 6/8] bpf: Add trampoline ip hash table
2025-11-20 21:23 [PATCHv3 bpf-next 0/8] ftrace,bpf: Use single direct ops for bpf trampolines Jiri Olsa
` (4 preceding siblings ...)
2025-11-20 21:23 ` [PATCHv3 bpf-next 5/8] ftrace: Add update_ftrace_direct_mod function Jiri Olsa
@ 2025-11-20 21:24 ` Jiri Olsa
2025-11-20 21:24 ` [PATCHv3 bpf-next 7/8] ftrace: Factor ftrace_ops ops_func interface Jiri Olsa
2025-11-20 21:24 ` [PATCHv3 bpf-next 8/8] bpf, x86: Use single ftrace_ops for direct calls Jiri Olsa
7 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2025-11-20 21:24 UTC (permalink / raw)
To: Steven Rostedt, Florent Revest, Mark Rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Menglong Dong, Song Liu
Following changes need to lookup trampoline based on its ip address,
adding hash table for that.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
include/linux/bpf.h | 7 +++++--
kernel/bpf/trampoline.c | 30 +++++++++++++++++++-----------
2 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 09d5dc541d1c..ad86857a8562 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1295,14 +1295,17 @@ struct bpf_tramp_image {
};
struct bpf_trampoline {
- /* hlist for trampoline_table */
- struct hlist_node hlist;
+ /* hlist for trampoline_key_table */
+ struct hlist_node hlist_key;
+ /* hlist for trampoline_ip_table */
+ struct hlist_node hlist_ip;
struct ftrace_ops *fops;
/* serializes access to fields of this trampoline */
struct mutex mutex;
refcount_t refcnt;
u32 flags;
u64 key;
+ unsigned long ip;
struct {
struct btf_func_model model;
void *addr;
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 04104397c432..f33693061c2e 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -24,9 +24,10 @@ const struct bpf_prog_ops bpf_extension_prog_ops = {
#define TRAMPOLINE_HASH_BITS 10
#define TRAMPOLINE_TABLE_SIZE (1 << TRAMPOLINE_HASH_BITS)
-static struct hlist_head trampoline_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_key_table[TRAMPOLINE_TABLE_SIZE];
+static struct hlist_head trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
-/* serializes access to trampoline_table */
+/* serializes access to trampoline tables */
static DEFINE_MUTEX(trampoline_mutex);
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
@@ -135,15 +136,15 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
PAGE_SIZE, true, ksym->name);
}
-static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
+static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
{
struct bpf_trampoline *tr;
struct hlist_head *head;
int i;
mutex_lock(&trampoline_mutex);
- head = &trampoline_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
- hlist_for_each_entry(tr, head, hlist) {
+ head = &trampoline_key_table[hash_64(key, TRAMPOLINE_HASH_BITS)];
+ hlist_for_each_entry(tr, head, hlist_key) {
if (tr->key == key) {
refcount_inc(&tr->refcnt);
goto out;
@@ -164,8 +165,12 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
#endif
tr->key = key;
- INIT_HLIST_NODE(&tr->hlist);
- hlist_add_head(&tr->hlist, head);
+ tr->ip = ftrace_location(ip);
+ INIT_HLIST_NODE(&tr->hlist_key);
+ INIT_HLIST_NODE(&tr->hlist_ip);
+ hlist_add_head(&tr->hlist_key, head);
+ head = &trampoline_ip_table[hash_64(tr->ip, TRAMPOLINE_HASH_BITS)];
+ hlist_add_head(&tr->hlist_ip, head);
refcount_set(&tr->refcnt, 1);
mutex_init(&tr->mutex);
for (i = 0; i < BPF_TRAMP_MAX; i++)
@@ -801,7 +806,7 @@ void bpf_trampoline_unlink_cgroup_shim(struct bpf_prog *prog)
prog->aux->attach_btf_id);
bpf_lsm_find_cgroup_shim(prog, &bpf_func);
- tr = bpf_trampoline_lookup(key);
+ tr = bpf_trampoline_lookup(key, 0);
if (WARN_ON_ONCE(!tr))
return;
@@ -821,7 +826,7 @@ struct bpf_trampoline *bpf_trampoline_get(u64 key,
{
struct bpf_trampoline *tr;
- tr = bpf_trampoline_lookup(key);
+ tr = bpf_trampoline_lookup(key, tgt_info->tgt_addr);
if (!tr)
return NULL;
@@ -857,7 +862,8 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
* fexit progs. The fentry-only trampoline will be freed via
* multiple rcu callbacks.
*/
- hlist_del(&tr->hlist);
+ hlist_del(&tr->hlist_key);
+ hlist_del(&tr->hlist_ip);
if (tr->fops) {
ftrace_free_filter(tr->fops);
kfree(tr->fops);
@@ -1130,7 +1136,9 @@ static int __init init_trampolines(void)
int i;
for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
- INIT_HLIST_HEAD(&trampoline_table[i]);
+ INIT_HLIST_HEAD(&trampoline_key_table[i]);
+ for (i = 0; i < TRAMPOLINE_TABLE_SIZE; i++)
+ INIT_HLIST_HEAD(&trampoline_ip_table[i]);
return 0;
}
late_initcall(init_trampolines);
--
2.51.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCHv3 bpf-next 7/8] ftrace: Factor ftrace_ops ops_func interface
2025-11-20 21:23 [PATCHv3 bpf-next 0/8] ftrace,bpf: Use single direct ops for bpf trampolines Jiri Olsa
` (5 preceding siblings ...)
2025-11-20 21:24 ` [PATCHv3 bpf-next 6/8] bpf: Add trampoline ip hash table Jiri Olsa
@ 2025-11-20 21:24 ` Jiri Olsa
2025-11-20 21:24 ` [PATCHv3 bpf-next 8/8] bpf, x86: Use single ftrace_ops for direct calls Jiri Olsa
7 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2025-11-20 21:24 UTC (permalink / raw)
To: Steven Rostedt, Florent Revest, Mark Rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Menglong Dong, Song Liu
We are going to remove "ftrace_ops->private == bpf_trampoline" setup
in following changes.
Adding ip argument to ftrace_ops_func_t callback function, so we can
use it to look up the trampoline.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
include/linux/ftrace.h | 2 +-
kernel/bpf/trampoline.c | 3 ++-
kernel/trace/ftrace.c | 6 +++---
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 4e2c0ed769fc..5aa37dec0081 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -402,7 +402,7 @@ enum ftrace_ops_cmd {
* 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);
+typedef int (*ftrace_ops_func_t)(struct ftrace_ops *op, unsigned long ip, enum ftrace_ops_cmd cmd);
#ifdef CONFIG_DYNAMIC_FTRACE
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index f33693061c2e..d8762f7990ed 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -33,7 +33,8 @@ static DEFINE_MUTEX(trampoline_mutex);
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
-static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, enum ftrace_ops_cmd cmd)
+static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
+ enum ftrace_ops_cmd cmd)
{
struct bpf_trampoline *tr = ops->private;
int ret = 0;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 5243aefb6096..b0e4d7a5d47c 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2049,7 +2049,7 @@ static int __ftrace_hash_update_ipmodify(struct ftrace_ops *ops,
*/
if (!ops->ops_func)
return -EBUSY;
- ret = ops->ops_func(ops, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF);
+ ret = ops->ops_func(ops, rec->ip, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF);
if (ret)
return ret;
} else if (is_ipmodify) {
@@ -8976,7 +8976,7 @@ static int prepare_direct_functions_for_ipmodify(struct ftrace_ops *ops)
if (!op->ops_func)
return -EBUSY;
- ret = op->ops_func(op, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_PEER);
+ ret = op->ops_func(op, ip, FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_PEER);
if (ret)
return ret;
}
@@ -9023,7 +9023,7 @@ static void cleanup_direct_functions_after_ipmodify(struct ftrace_ops *ops)
/* The cleanup is optional, ignore any errors */
if (found_op && op->ops_func)
- op->ops_func(op, FTRACE_OPS_CMD_DISABLE_SHARE_IPMODIFY_PEER);
+ op->ops_func(op, ip, FTRACE_OPS_CMD_DISABLE_SHARE_IPMODIFY_PEER);
}
}
mutex_unlock(&direct_mutex);
--
2.51.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCHv3 bpf-next 8/8] bpf, x86: Use single ftrace_ops for direct calls
2025-11-20 21:23 [PATCHv3 bpf-next 0/8] ftrace,bpf: Use single direct ops for bpf trampolines Jiri Olsa
` (6 preceding siblings ...)
2025-11-20 21:24 ` [PATCHv3 bpf-next 7/8] ftrace: Factor ftrace_ops ops_func interface Jiri Olsa
@ 2025-11-20 21:24 ` Jiri Olsa
2025-11-21 18:41 ` kernel test robot
7 siblings, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2025-11-20 21:24 UTC (permalink / raw)
To: Steven Rostedt, Florent Revest, Mark Rutland
Cc: bpf, linux-kernel, linux-trace-kernel, linux-arm-kernel,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Menglong Dong, Song Liu
Using single ftrace_ops for direct calls update instead of allocating
ftrace_ops object for each trampoline.
With single ftrace_ops object we can use update_ftrace_direct_* api
that allows multiple ip sites updates on single ftrace_ops object.
Adding HAVE_SINGLE_FTRACE_DIRECT_OPS config option to be enabled on
each arch that supports this.
At the moment we can enable this only on x86 arch, because arm relies
on ftrace_ops object representing just single trampoline image (stored
in ftrace_ops::direct_call). Ach that do not support this will continue
to use *_ftrace_direct api.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
arch/x86/Kconfig | 1 +
kernel/bpf/trampoline.c | 172 +++++++++++++++++++++++++++++++++++-----
kernel/trace/Kconfig | 3 +
kernel/trace/ftrace.c | 7 +-
4 files changed, 164 insertions(+), 19 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index fa3b616af03a..65a2fc279b46 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -332,6 +332,7 @@ config X86
select SCHED_SMT if SMP
select ARCH_SUPPORTS_SCHED_CLUSTER if SMP
select ARCH_SUPPORTS_SCHED_MC if SMP
+ select HAVE_SINGLE_FTRACE_DIRECT_OPS if X86_64 && DYNAMIC_FTRACE_WITH_DIRECT_CALLS
config INSTRUCTION_DECODER
def_bool y
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index d8762f7990ed..9cc4de215df7 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -33,12 +33,40 @@ static DEFINE_MUTEX(trampoline_mutex);
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+ struct hlist_head *head_ip;
+ struct bpf_trampoline *tr;
+
+ mutex_lock(&trampoline_mutex);
+ head_ip = &trampoline_ip_table[hash_64(ip, TRAMPOLINE_HASH_BITS)];
+ hlist_for_each_entry(tr, head_ip, hlist_ip) {
+ if (tr->ip == ip)
+ goto out;
+ }
+ tr = NULL;
+out:
+ mutex_unlock(&trampoline_mutex);
+ return tr;
+}
+#else
+static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
+{
+ return ops->private;
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+
static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
enum ftrace_ops_cmd cmd)
{
- struct bpf_trampoline *tr = ops->private;
+ struct bpf_trampoline *tr;
int ret = 0;
+ tr = direct_ops_ip_lookup(ops, ip);
+ if (!tr)
+ return -EINVAL;
+
if (cmd == FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF) {
/* This is called inside register_ftrace_direct_multi(), so
* tr->mutex is already locked.
@@ -137,6 +165,126 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
PAGE_SIZE, true, ksym->name);
}
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+/*
+ * We have only single direct_ops which contains all the direct call
+ * sites and is the only global ftrace_ops for all trampolines.
+ *
+ * We use 'update_ftrace_direct_*' api for attachment.
+ */
+struct ftrace_ops direct_ops = {
+ .ops_func = bpf_tramp_ftrace_ops_func,
+};
+
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+ tr->fops = &direct_ops;
+ return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+
+static struct ftrace_hash *hash_from(unsigned long ip, void *addr)
+{
+ struct ftrace_hash *hash;
+
+ ip = ftrace_location(ip);
+ if (!ip)
+ return NULL;
+ hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
+ if (!hash)
+ return NULL;
+ if (!add_hash_entry_direct(hash, ip, (unsigned long) addr)) {
+ free_ftrace_hash(hash);
+ return NULL;
+ }
+ return hash;
+}
+
+static int direct_ops_add(struct ftrace_ops *ops, unsigned long ip, void *addr)
+{
+ struct ftrace_hash *hash = hash_from(ip, addr);
+ int err = -ENOMEM;
+
+ if (hash)
+ err = update_ftrace_direct_add(ops, hash);
+ free_ftrace_hash(hash);
+ return err;
+}
+
+static int direct_ops_del(struct ftrace_ops *ops, unsigned long ip, void *addr)
+{
+ struct ftrace_hash *hash = hash_from(ip, addr);
+ int err = -ENOMEM;
+
+ if (hash)
+ err = update_ftrace_direct_del(ops, hash);
+ free_ftrace_hash(hash);
+ return err;
+}
+
+static int direct_ops_mod(struct ftrace_ops *ops, unsigned long ip, void *addr, bool lock_direct_mutex)
+{
+ struct ftrace_hash *hash = hash_from(ip, addr);
+ int err = -ENOMEM;
+
+ if (hash)
+ err = update_ftrace_direct_mod(ops, hash, lock_direct_mutex);
+ free_ftrace_hash(hash);
+ return err;
+}
+#else
+/*
+ * We allocate ftrace_ops object for each trampoline and it contains
+ * call site specific for that trampoline.
+ *
+ * We use *_ftrace_direct api for attachment.
+ */
+static int direct_ops_alloc(struct bpf_trampoline *tr)
+{
+ tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
+ if (!tr->fops)
+ return -ENOMEM;
+ tr->fops->private = tr;
+ tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
+ return 0;
+}
+
+static void direct_ops_free(struct bpf_trampoline *tr)
+{
+ if (tr->fops) {
+ ftrace_free_filter(tr->fops);
+ kfree(tr->fops);
+ }
+}
+
+static int direct_ops_add(struct ftrace_ops *ops, unsigned long ip, void *addr)
+{
+ int ret;
+
+ ret = ftrace_set_filter_ip(ops, (unsigned long)ip, 0, 1);
+ if (ret)
+ return ret;
+ return register_ftrace_direct(ops, (long)addr);
+}
+
+static int direct_ops_del(struct ftrace_ops *ops, unsigned long ip, void *addr)
+{
+ return unregister_ftrace_direct(ops, (long)addr, false);
+}
+
+static int direct_ops_mod(struct ftrace_ops *ops, unsigned long ip, void *addr, bool lock_direct_mutex)
+{
+ if (lock_direct_mutex)
+ return modify_ftrace_direct(ops, (long)addr);
+ return modify_ftrace_direct_nolock(ops, (long)addr);
+}
+#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
+#else
+static void direct_ops_free(struct bpf_trampoline *tr) { }
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+
static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
{
struct bpf_trampoline *tr;
@@ -155,14 +303,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
if (!tr)
goto out;
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
- tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
- if (!tr->fops) {
+ if (direct_ops_alloc(tr)) {
kfree(tr);
tr = NULL;
goto out;
}
- tr->fops->private = tr;
- tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
#endif
tr->key = key;
@@ -187,7 +332,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
int ret;
if (tr->func.ftrace_managed)
- ret = unregister_ftrace_direct(tr->fops, (long)old_addr, false);
+ ret = direct_ops_del(tr->fops, tr->ip, old_addr);
else
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL);
@@ -201,10 +346,7 @@ static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_ad
int ret;
if (tr->func.ftrace_managed) {
- if (lock_direct_mutex)
- ret = modify_ftrace_direct(tr->fops, (long)new_addr);
- else
- ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
+ ret = direct_ops_mod(tr->fops, tr->ip, new_addr, lock_direct_mutex);
} else {
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, new_addr);
}
@@ -226,10 +368,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
}
if (tr->func.ftrace_managed) {
- ret = ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
- if (ret)
- return ret;
- ret = register_ftrace_direct(tr->fops, (long)new_addr);
+ ret = direct_ops_add(tr->fops, tr->ip, new_addr);
} else {
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr);
}
@@ -865,10 +1004,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
*/
hlist_del(&tr->hlist_key);
hlist_del(&tr->hlist_ip);
- if (tr->fops) {
- ftrace_free_filter(tr->fops);
- kfree(tr->fops);
- }
+ direct_ops_free(tr);
kfree(tr);
out:
mutex_unlock(&trampoline_mutex);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index d2c79da81e4f..4bf5beb04a5b 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -50,6 +50,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
bool
+config HAVE_SINGLE_FTRACE_DIRECT_OPS
+ bool
+
config HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
bool
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index b0e4d7a5d47c..4380839d2422 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2605,8 +2605,13 @@ unsigned long ftrace_find_rec_direct(unsigned long ip)
static void call_direct_funcs(unsigned long ip, unsigned long pip,
struct ftrace_ops *ops, struct ftrace_regs *fregs)
{
- unsigned long addr = READ_ONCE(ops->direct_call);
+ unsigned long addr;
+#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
+ addr = ftrace_find_rec_direct(ip);
+#else
+ addr = READ_ONCE(ops->direct_call);
+#endif
if (!addr)
return;
--
2.51.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCHv3 bpf-next 8/8] bpf, x86: Use single ftrace_ops for direct calls
2025-11-20 21:24 ` [PATCHv3 bpf-next 8/8] bpf, x86: Use single ftrace_ops for direct calls Jiri Olsa
@ 2025-11-21 18:41 ` kernel test robot
0 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2025-11-21 18:41 UTC (permalink / raw)
To: Jiri Olsa; +Cc: oe-kbuild-all
Hi Jiri,
kernel test robot noticed the following build errors:
[auto build test ERROR on bpf-next/master]
url: https://github.com/intel-lab-lkp/linux/commits/Jiri-Olsa/ftrace-Make-alloc_and_copy_ftrace_hash-direct-friendly/20251121-052934
base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link: https://lore.kernel.org/r/20251120212402.466524-9-jolsa%40kernel.org
patch subject: [PATCHv3 bpf-next 8/8] bpf, x86: Use single ftrace_ops for direct calls
config: i386-randconfig-141-20251121 (https://download.01.org/0day-ci/archive/20251122/202511220217.s9169XhB-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251122/202511220217.s9169XhB-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511220217.s9169XhB-lkp@intel.com/
All errors (new ones prefixed by >>):
kernel/bpf/trampoline.c: In function 'unregister_fentry':
>> kernel/bpf/trampoline.c:335:23: error: implicit declaration of function 'direct_ops_del'; did you mean 'direct_ops_free'? [-Wimplicit-function-declaration]
335 | ret = direct_ops_del(tr->fops, tr->ip, old_addr);
| ^~~~~~~~~~~~~~
| direct_ops_free
kernel/bpf/trampoline.c: In function 'modify_fentry':
>> kernel/bpf/trampoline.c:349:23: error: implicit declaration of function 'direct_ops_mod'; did you mean 'direct_ops_free'? [-Wimplicit-function-declaration]
349 | ret = direct_ops_mod(tr->fops, tr->ip, new_addr, lock_direct_mutex);
| ^~~~~~~~~~~~~~
| direct_ops_free
kernel/bpf/trampoline.c: In function 'register_fentry':
>> kernel/bpf/trampoline.c:371:23: error: implicit declaration of function 'direct_ops_add'; did you mean 'direct_ops_free'? [-Wimplicit-function-declaration]
371 | ret = direct_ops_add(tr->fops, tr->ip, new_addr);
| ^~~~~~~~~~~~~~
| direct_ops_free
vim +335 kernel/bpf/trampoline.c
328
329 static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
330 {
331 void *ip = tr->func.addr;
332 int ret;
333
334 if (tr->func.ftrace_managed)
> 335 ret = direct_ops_del(tr->fops, tr->ip, old_addr);
336 else
337 ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL);
338
339 return ret;
340 }
341
342 static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_addr,
343 bool lock_direct_mutex)
344 {
345 void *ip = tr->func.addr;
346 int ret;
347
348 if (tr->func.ftrace_managed) {
> 349 ret = direct_ops_mod(tr->fops, tr->ip, new_addr, lock_direct_mutex);
350 } else {
351 ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, new_addr);
352 }
353 return ret;
354 }
355
356 /* first time registering */
357 static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
358 {
359 void *ip = tr->func.addr;
360 unsigned long faddr;
361 int ret;
362
363 faddr = ftrace_location((unsigned long)ip);
364 if (faddr) {
365 if (!tr->fops)
366 return -ENOTSUPP;
367 tr->func.ftrace_managed = true;
368 }
369
370 if (tr->func.ftrace_managed) {
> 371 ret = direct_ops_add(tr->fops, tr->ip, new_addr);
372 } else {
373 ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr);
374 }
375
376 return ret;
377 }
378
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread