From: Peter Zijlstra peterz@infradead.org
[ Upstream commit 68b1eddd421d2b16c6655eceb48918a1e896bbbc ]
It turns out that static_call_set_init() does not preserve the other flags; IOW. it clears TAIL if it was set.
Fixes: 9183c3f9ed710 ("static_call: Add inline static call infrastructure") Reported-by: Sumit Garg sumit.garg@linaro.org Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Acked-by: Jarkko Sakkinen jarkko@kernel.org Tested-by: Sumit Garg sumit.garg@linaro.org Link: https://lkml.kernel.org/r/20210318113610.519406371@infradead.org Signed-off-by: Sasha Levin sashal@kernel.org --- kernel/static_call.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/kernel/static_call.c b/kernel/static_call.c index 5d53c354fbe7..49efbdc5b480 100644 --- a/kernel/static_call.c +++ b/kernel/static_call.c @@ -35,27 +35,30 @@ static inline void *static_call_addr(struct static_call_site *site) return (void *)((long)site->addr + (long)&site->addr); }
+static inline unsigned long __static_call_key(const struct static_call_site *site) +{ + return (long)site->key + (long)&site->key; +}
static inline struct static_call_key *static_call_key(const struct static_call_site *site) { - return (struct static_call_key *) - (((long)site->key + (long)&site->key) & ~STATIC_CALL_SITE_FLAGS); + return (void *)(__static_call_key(site) & ~STATIC_CALL_SITE_FLAGS); }
/* These assume the key is word-aligned. */ static inline bool static_call_is_init(struct static_call_site *site) { - return ((long)site->key + (long)&site->key) & STATIC_CALL_SITE_INIT; + return __static_call_key(site) & STATIC_CALL_SITE_INIT; }
static inline bool static_call_is_tail(struct static_call_site *site) { - return ((long)site->key + (long)&site->key) & STATIC_CALL_SITE_TAIL; + return __static_call_key(site) & STATIC_CALL_SITE_TAIL; }
static inline void static_call_set_init(struct static_call_site *site) { - site->key = ((long)static_call_key(site) | STATIC_CALL_SITE_INIT) - + site->key = (__static_call_key(site) | STATIC_CALL_SITE_INIT) - (long)&site->key; }
@@ -199,7 +202,7 @@ void __static_call_update(struct static_call_key *key, void *tramp, void *func) }
arch_static_call_transform(site_addr, NULL, func, - static_call_is_tail(site)); + static_call_is_tail(site)); } }
@@ -358,7 +361,7 @@ static int static_call_add_module(struct module *mod) struct static_call_site *site;
for (site = start; site != stop; site++) { - unsigned long s_key = (long)site->key + (long)&site->key; + unsigned long s_key = __static_call_key(site); unsigned long addr = s_key & ~STATIC_CALL_SITE_FLAGS; unsigned long key;