88#include <linux/fprobe.h>
99#include <linux/kallsyms.h>
1010#include <linux/kprobes.h>
11+ #include <linux/rethook.h>
1112#include <linux/slab.h>
1213#include <linux/sort.h>
1314
15+ #include "trace.h"
16+
17+ struct fprobe_rethook_node {
18+ struct rethook_node node ;
19+ unsigned long entry_ip ;
20+ };
21+
1422static void fprobe_handler (unsigned long ip , unsigned long parent_ip ,
1523 struct ftrace_ops * ops , struct ftrace_regs * fregs )
1624{
25+ struct fprobe_rethook_node * fpr ;
26+ struct rethook_node * rh ;
1727 struct fprobe * fp ;
1828 int bit ;
1929
@@ -30,10 +40,37 @@ static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
3040 if (fp -> entry_handler )
3141 fp -> entry_handler (fp , ip , ftrace_get_regs (fregs ));
3242
43+ if (fp -> exit_handler ) {
44+ rh = rethook_try_get (fp -> rethook );
45+ if (!rh ) {
46+ fp -> nmissed ++ ;
47+ goto out ;
48+ }
49+ fpr = container_of (rh , struct fprobe_rethook_node , node );
50+ fpr -> entry_ip = ip ;
51+ rethook_hook (rh , ftrace_get_regs (fregs ), true);
52+ }
53+
54+ out :
3355 ftrace_test_recursion_unlock (bit );
3456}
3557NOKPROBE_SYMBOL (fprobe_handler );
3658
59+ static void fprobe_exit_handler (struct rethook_node * rh , void * data ,
60+ struct pt_regs * regs )
61+ {
62+ struct fprobe * fp = (struct fprobe * )data ;
63+ struct fprobe_rethook_node * fpr ;
64+
65+ if (!fp || fprobe_disabled (fp ))
66+ return ;
67+
68+ fpr = container_of (rh , struct fprobe_rethook_node , node );
69+
70+ fp -> exit_handler (fp , fpr -> entry_ip , regs );
71+ }
72+ NOKPROBE_SYMBOL (fprobe_exit_handler );
73+
3774/* Convert ftrace location address from symbols */
3875static unsigned long * get_ftrace_locations (const char * * syms , int num )
3976{
@@ -77,6 +114,48 @@ static void fprobe_init(struct fprobe *fp)
77114 fp -> ops .flags |= FTRACE_OPS_FL_SAVE_REGS ;
78115}
79116
117+ static int fprobe_init_rethook (struct fprobe * fp , int num )
118+ {
119+ int i , size ;
120+
121+ if (num < 0 )
122+ return - EINVAL ;
123+
124+ if (!fp -> exit_handler ) {
125+ fp -> rethook = NULL ;
126+ return 0 ;
127+ }
128+
129+ /* Initialize rethook if needed */
130+ size = num * num_possible_cpus () * 2 ;
131+ if (size < 0 )
132+ return - E2BIG ;
133+
134+ fp -> rethook = rethook_alloc ((void * )fp , fprobe_exit_handler );
135+ for (i = 0 ; i < size ; i ++ ) {
136+ struct rethook_node * node ;
137+
138+ node = kzalloc (sizeof (struct fprobe_rethook_node ), GFP_KERNEL );
139+ if (!node ) {
140+ rethook_free (fp -> rethook );
141+ fp -> rethook = NULL ;
142+ return - ENOMEM ;
143+ }
144+ rethook_add_node (fp -> rethook , node );
145+ }
146+ return 0 ;
147+ }
148+
149+ static void fprobe_fail_cleanup (struct fprobe * fp )
150+ {
151+ if (fp -> rethook ) {
152+ /* Don't need to cleanup rethook->handler because this is not used. */
153+ rethook_free (fp -> rethook );
154+ fp -> rethook = NULL ;
155+ }
156+ ftrace_free_filter (& fp -> ops );
157+ }
158+
80159/**
81160 * register_fprobe() - Register fprobe to ftrace by pattern.
82161 * @fp: A fprobe data structure to be registered.
@@ -90,6 +169,7 @@ static void fprobe_init(struct fprobe *fp)
90169 */
91170int register_fprobe (struct fprobe * fp , const char * filter , const char * notfilter )
92171{
172+ struct ftrace_hash * hash ;
93173 unsigned char * str ;
94174 int ret , len ;
95175
@@ -114,10 +194,21 @@ int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter
114194 goto out ;
115195 }
116196
117- ret = register_ftrace_function (& fp -> ops );
197+ /* TODO:
198+ * correctly calculate the total number of filtered symbols
199+ * from both filter and notfilter.
200+ */
201+ hash = fp -> ops .local_hash .filter_hash ;
202+ if (WARN_ON_ONCE (!hash ))
203+ goto out ;
204+
205+ ret = fprobe_init_rethook (fp , (int )hash -> count );
206+ if (!ret )
207+ ret = register_ftrace_function (& fp -> ops );
208+
118209out :
119210 if (ret )
120- ftrace_free_filter ( & fp -> ops );
211+ fprobe_fail_cleanup ( fp );
121212 return ret ;
122213}
123214EXPORT_SYMBOL_GPL (register_fprobe );
@@ -145,12 +236,15 @@ int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num)
145236 fprobe_init (fp );
146237
147238 ret = ftrace_set_filter_ips (& fp -> ops , addrs , num , 0 , 0 );
239+ if (ret )
240+ return ret ;
241+
242+ ret = fprobe_init_rethook (fp , num );
148243 if (!ret )
149244 ret = register_ftrace_function (& fp -> ops );
150245
151246 if (ret )
152- ftrace_free_filter (& fp -> ops );
153-
247+ fprobe_fail_cleanup (fp );
154248 return ret ;
155249}
156250EXPORT_SYMBOL_GPL (register_fprobe_ips );
@@ -201,10 +295,20 @@ int unregister_fprobe(struct fprobe *fp)
201295 if (!fp || fp -> ops .func != fprobe_handler )
202296 return - EINVAL ;
203297
298+ /*
299+ * rethook_free() starts disabling the rethook, but the rethook handlers
300+ * may be running on other processors at this point. To make sure that all
301+ * current running handlers are finished, call unregister_ftrace_function()
302+ * after this.
303+ */
304+ if (fp -> rethook )
305+ rethook_free (fp -> rethook );
306+
204307 ret = unregister_ftrace_function (& fp -> ops );
308+ if (ret < 0 )
309+ return ret ;
205310
206- if (!ret )
207- ftrace_free_filter (& fp -> ops );
311+ ftrace_free_filter (& fp -> ops );
208312
209313 return ret ;
210314}
0 commit comments