FAILED: patch "[PATCH] rethook: Use __rcu pointer for rethook::handler" failed to apply to 6.6-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x a1461f1fd6cfdc4b8917c9d4a91e92605d1f28dc
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2023120320-obtuse-gap-3bfa@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
a1461f1fd6cf ("rethook: Use __rcu pointer for rethook::handler") 4bbd93455659 ("kprobes: kretprobe scalability improvement")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From a1461f1fd6cfdc4b8917c9d4a91e92605d1f28dc Mon Sep 17 00:00:00 2001
From: "Masami Hiramatsu (Google)" <[email protected]>
Date: Fri, 1 Dec 2023 14:53:56 +0900
Subject: [PATCH] rethook: Use __rcu pointer for rethook::handler
Since the rethook::handler is an RCU-maganged pointer so that it will notice readers the rethook is stopped (unregistered) or not, it should be an __rcu pointer and use appropriate functions to be accessed. This will use appropriate memory barrier when accessing it. OTOH, rethook::data is never changed, so we don't need to check it in get_kretprobe().
NOTE: To avoid sparse warning, rethook::handler is defined by a raw function pointer type with __rcu instead of rethook_handler_t.
include/linux/kprobes.h +2 -4
@@ -197,10 +197,8 @@ extern int arch_trampoline_kprobe(struct kprobe *p);#ifdef CONFIG_KRETPROBE_ON_RETHOOK static nokprobe_inline struct kretprobe *get_kretprobe(struct kretprobe_instance *ri) { -RCU_LOCKDEP_WARN (!rcu_read_lock_any_held (), -"Kretprobe is accessed from instance under preemptive context" ); - -return (struct kretprobe *)READ_ONCE (ri->node.rethook->data); +/* rethook::data is non-changed field, so that you can access it freely. */ +return (struct kretprobe *)ri->node.rethook->data; }static nokprobe_inline unsigned long get_kretprobe_retaddr (struct kretprobe_instance *ri) {
include/linux/rethook.h +6 -1
@@ -28,7 +28,12 @@ typedef void (*rethook_handler_t) (struct rethook_node *, void *, unsigned long,*/ struct rethook {void *data; -rethook_handler_t handler; +/* +* To avoid sparse warnings, this uses a raw function pointer with +* __rcu, instead of rethook_handler_t. But this must be same as +* rethook_handler_t. +*/ +void (__rcu *handler) (struct rethook_node *,void *,unsigned long ,struct pt_regs *);struct objpool_head pool;struct rcu_head rcu; };
kernel/trace/rethook.c +14 -9
@@ -48,7 +48,7 @@ static void rethook_free_rcu(struct rcu_head *head)*/ void rethook_stop (struct rethook *rh) { -WRITE_ONCE (rh->handler,NULL ); +rcu_assign_pointer (rh->handler,NULL ); }/**
@@ -63,7 +63,7 @@ void rethook_stop(struct rethook *rh)*/ void rethook_free (struct rethook *rh) { -WRITE_ONCE (rh->handler,NULL ); +rethook_stop (rh);call_rcu (&rh->rcu, rethook_free_rcu); }
@@ -82,6 +82,12 @@ static int rethook_fini_pool(struct objpool_head *head, void *context)return 0 ; } +static inline rethook_handler_t rethook_get_handler (struct rethook *rh) +{ +return (rethook_handler_t )rcu_dereference_check (rh->handler, +rcu_read_lock_any_held ()); +} +/** * rethook_alloc() - Allocate struct rethook. * @data: a data to pass the @handler when hooking the return.
@@ -107,7 +113,7 @@ struct rethook *rethook_alloc(void *data, rethook_handler_t handler,return ERR_PTR (-ENOMEM ); rh->data = data; - rh->handler = handler; +rcu_assign_pointer (rh->handler, handler);/* initialize the objpool for rethook nodes */ if (objpool_init(&rh->pool, num, size, GFP_KERNEL, rh,
@@ -135,9 +141,10 @@ static void free_rethook_node_rcu(struct rcu_head *head)*/ void rethook_recycle (struct rethook_node *node) { -lockdep_assert_preemption_disabled (); +rethook_handler_t handler; -if (likely (READ_ONCE (node->rethook->handler))) + handler =rethook_get_handler (node->rethook); +if (likely (handler))objpool_push (node, &node->rethook->pool);else call_rcu (&node->rcu, free_rethook_node_rcu);
@@ -153,9 +160,7 @@ NOKPROBE_SYMBOL(rethook_recycle);*/ struct rethook_node *rethook_try_get (struct rethook *rh) { -rethook_handler_t handler =READ_ONCE (rh->handler); - -lockdep_assert_preemption_disabled (); +rethook_handler_t handler =rethook_get_handler (rh);/* Check whether @rh is going to be freed. */ if (unlikely (!handler))
@@ -300,7 +305,7 @@ unsigned long rethook_trampoline_handler(struct pt_regs *regs, rhn = container_of(first, struct rethook_node, llist);if (WARN_ON_ONCE (rhn->frame != frame))break ; - handler =READ_ONCE (rhn->rethook->handler); + handler =rethook_get_handler (rhn->rethook);if (handler)handler (rhn, rhn->rethook->data, correct_ret_addr, regs);
[email protected]
maintainerPATCH 1/1 rethook: Use __rcu pointer for rethook::handler
From: "Masami Hiramatsu (Google)" <[email protected]>
Since the rethook::handler is an RCU-maganged pointer so that it will notice readers the rethook is stopped (unregistered) or not, it should be an __rcu pointer and use appropriate functions to be accessed. This will use appropriate memory barrier when accessing it. OTOH, rethook::data is never changed, so we don't need to check it in get_kretprobe().
NOTE: To avoid sparse warning, rethook::handler is defined by a raw function pointer type with __rcu instead of rethook_handler_t.
--- include/linux/kprobes.h | 6 ++---- include/linux/rethook.h | 7 ++++++- kernel/trace/rethook.c | 23 ++++++++++++++--------- 3 files changed, 22 insertions(+), 14 deletions(-)
include/linux/kprobes.h +2 -4
@@ -202,10 +202,8 @@ extern int arch_trampoline_kprobe(struct kprobe *p);#ifdef CONFIG_KRETPROBE_ON_RETHOOK static nokprobe_inline struct kretprobe *get_kretprobe(struct kretprobe_instance *ri) { -RCU_LOCKDEP_WARN (!rcu_read_lock_any_held (), -"Kretprobe is accessed from instance under preemptive context" ); - -return (struct kretprobe *)READ_ONCE (ri->node.rethook->data); +/* rethook::data is non-changed field, so that you can access it freely. */ +return (struct kretprobe *)ri->node.rethook->data; }static nokprobe_inline unsigned long get_kretprobe_retaddr (struct kretprobe_instance *ri) {
include/linux/rethook.h +6 -1
@@ -29,7 +29,12 @@ typedef void (*rethook_handler_t) (struct rethook_node *, void *, unsigned long,*/ struct rethook {void *data; -rethook_handler_t handler; +/* +* To avoid sparse warnings, this uses a raw function pointer with +* __rcu, instead of rethook_handler_t. But this must be same as +* rethook_handler_t. +*/ +void (__rcu *handler) (struct rethook_node *,void *,unsigned long ,struct pt_regs *);struct freelist_head pool;refcount_t ref;struct rcu_head rcu;
kernel/trace/rethook.c +14 -9
@@ -63,7 +63,7 @@ static void rethook_free_rcu(struct rcu_head *head)*/ void rethook_stop (struct rethook *rh) { -WRITE_ONCE (rh->handler,NULL ); +rcu_assign_pointer (rh->handler,NULL ); }/**
@@ -78,11 +78,17 @@ void rethook_stop(struct rethook *rh)*/ void rethook_free (struct rethook *rh) { -WRITE_ONCE (rh->handler,NULL ); +rethook_stop (rh);call_rcu (&rh->rcu, rethook_free_rcu); } +static inline rethook_handler_t rethook_get_handler (struct rethook *rh) +{ +return (rethook_handler_t )rcu_dereference_check (rh->handler, +rcu_read_lock_any_held ()); +} +/** * rethook_alloc() - Allocate struct rethook. * @data: a data to pass the @handler when hooking the return.
@@ -102,7 +108,7 @@ struct rethook *rethook_alloc(void *data, rethook_handler_t handler) } rh->data = data; - rh->handler = handler; +rcu_assign_pointer (rh->handler, handler); rh->pool.head =NULL ;refcount_set (&rh->ref,1 );
@@ -142,9 +148,10 @@ static void free_rethook_node_rcu(struct rcu_head *head)*/ void rethook_recycle (struct rethook_node *node) { -lockdep_assert_preemption_disabled (); +rethook_handler_t handler; -if (likely (READ_ONCE (node->rethook->handler))) + handler =rethook_get_handler (node->rethook); +if (likely (handler))freelist_add (&node->freelist, &node->rethook->pool);else call_rcu (&node->rcu, free_rethook_node_rcu);
@@ -160,11 +167,9 @@ NOKPROBE_SYMBOL(rethook_recycle);*/ struct rethook_node *rethook_try_get (struct rethook *rh) { -rethook_handler_t handler =READ_ONCE (rh->handler); +rethook_handler_t handler =rethook_get_handler (rh);struct freelist_node *fn; -lockdep_assert_preemption_disabled (); -/* Check whether @rh is going to be freed. */ if (unlikely (!handler))return NULL ;
@@ -312,7 +317,7 @@ unsigned long rethook_trampoline_handler(struct pt_regs *regs, rhn = container_of(first, struct rethook_node, llist);if (WARN_ON_ONCE (rhn->frame != frame))break ; - handler =READ_ONCE (rhn->rethook->handler); + handler =rethook_get_handler (rhn->rethook);if (handler)handler (rhn, rhn->rethook->data, correct_ret_addr, regs);
Signature · 1 line
2.43.0.rc2.451.g8631bc7472-goog