From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753832Ab2GUCWT (ORCPT ); Fri, 20 Jul 2012 22:22:19 -0400 Received: from hrndva-omtalb.mail.rr.com ([71.74.56.122]:28689 "EHLO hrndva-omtalb.mail.rr.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752286Ab2GUCVM (ORCPT ); Fri, 20 Jul 2012 22:21:12 -0400 X-Authority-Analysis: v=2.0 cv=AtpsLZBP c=1 sm=0 a=s5Htg7xnQOKvHEu9STBOug==:17 a=OpT9cpI26MMA:10 a=Ciwy3NGCPMMA:10 a=zWScXzqMWvIA:10 a=5SG0PmZfjMsA:10 a=bbbx4UPp9XUA:10 a=meVymXHHAAAA:8 a=20KFwNOVAAAA:8 a=ywr9Lfw1UOhYjjAWiyIA:9 a=QEXdDO2ut3YA:10 a=jEp0ucaQiEUA:10 a=jeBq3FmKZ4MA:10 a=1sZ5UlT5ZBE_QGE7:21 a=PykllXfriNwsTAQ0:21 a=XhgKmp_9P01-hH-vVGkA:9 a=s5Htg7xnQOKvHEu9STBOug==:117 X-Cloudmark-Score: 0 X-Originating-IP: 72.230.195.127 Message-Id: <20120721022109.652033022@goodmis.org> User-Agent: quilt/0.60-1 Date: Fri, 20 Jul 2012 22:19:54 -0400 From: Steven Rostedt To: linux-kernel@vger.kernel.org Cc: Ingo Molnar , Andrew Morton , Masami Hiramatsu , Frederic Weisbecker , Thomas Gleixner , "H. Peter Anvin" Subject: [PATCH 11/19] ftrace: Add selftest to test function trace recursion protection References: <20120721021943.274162381@goodmis.org> Content-Disposition: inline; filename=0011-ftrace-Add-selftest-to-test-function-trace-recursion.patch Content-Type: multipart/signed; micalg="pgp-sha1"; protocol="application/pgp-signature"; boundary="00GvhwF7k39YY" Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org --00GvhwF7k39YY Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable From: Steven Rostedt Add selftests to test the function tracing recursion protection actually does work. It also tests if a ftrace_ops states it will perform its own protection. Although, even if the ftrace_ops states it will protect itself, the ftrace infrastructure may still provide protection if the arch does not support all features or another ftrace_ops is registered. Signed-off-by: Steven Rostedt --- include/linux/ftrace.h | 6 ++ kernel/trace/ftrace.c | 21 +++++++ kernel/trace/trace_selftest.c | 136 +++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 163 insertions(+) diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 65a14e4..9962e95 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -220,6 +220,10 @@ extern void ftrace_stub(unsigned long a0, unsigned lon= g a1, */ #define register_ftrace_function(ops) ({ 0; }) #define unregister_ftrace_function(ops) ({ 0; }) +static inline int ftrace_nr_registered_ops(void) +{ + return 0; +} static inline void clear_ftrace_function(void) { } static inline void ftrace_kill(void) { } static inline void ftrace_stop(void) { } @@ -275,6 +279,8 @@ extern void unregister_ftrace_function_probe_all(char *= glob); =20 extern int ftrace_text_reserved(void *start, void *end); =20 +extern int ftrace_nr_registered_ops(void); + /* * The dyn_ftrace record's flags field is split into two parts. * the first part which is '0-FTRACE_REF_MAX' is a counter of diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index ad765b4..528d997 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -111,6 +111,27 @@ static void ftrace_ops_no_ops(unsigned long ip, unsign= ed long parent_ip); #define ftrace_ops_list_func ((ftrace_func_t)ftrace_ops_no_ops) #endif =20 +/** + * ftrace_nr_registered_ops - return number of ops registered + * + * Returns the number of ftrace_ops registered and tracing functions + */ +int ftrace_nr_registered_ops(void) +{ + struct ftrace_ops *ops; + int cnt =3D 0; + + mutex_lock(&ftrace_lock); + + for (ops =3D ftrace_ops_list; + ops !=3D &ftrace_list_end; ops =3D ops->next) + cnt++; + + mutex_unlock(&ftrace_lock); + + return cnt; +} + /* * Traverse the ftrace_global_list, invoking all entries. The reason that= we * can use rcu_dereference_raw() is that elements removed from this list diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 1fb6da8..86422f9 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c @@ -406,8 +406,141 @@ int trace_selftest_startup_dynamic_tracing(struct tra= cer *trace, =20 return ret; } + +static int trace_selftest_recursion_cnt; +static void trace_selftest_test_recursion_func(unsigned long ip, + unsigned long pip, + struct ftrace_ops *op, + struct pt_regs *pt_regs) +{ + /* + * This function is registered without the recursion safe flag. + * The ftrace infrastructure should provide the recursion + * protection. If not, this will crash the kernel! + */ + trace_selftest_recursion_cnt++; + DYN_FTRACE_TEST_NAME(); +} + +static void trace_selftest_test_recursion_safe_func(unsigned long ip, + unsigned long pip, + struct ftrace_ops *op, + struct pt_regs *pt_regs) +{ + /* + * We said we would provide our own recursion. By calling + * this function again, we should recurse back into this function + * and count again. But this only happens if the arch supports + * all of ftrace features and nothing else is using the function + * tracing utility. + */ + if (trace_selftest_recursion_cnt++) + return; + DYN_FTRACE_TEST_NAME(); +} + +static struct ftrace_ops test_rec_probe =3D { + .func =3D trace_selftest_test_recursion_func, +}; + +static struct ftrace_ops test_recsafe_probe =3D { + .func =3D trace_selftest_test_recursion_safe_func, + .flags =3D FTRACE_OPS_FL_RECURSION_SAFE, +}; + +static int +trace_selftest_function_recursion(void) +{ + int save_ftrace_enabled =3D ftrace_enabled; + int save_tracer_enabled =3D tracer_enabled; + char *func_name; + int len; + int ret; + int cnt; + + /* The previous test PASSED */ + pr_cont("PASSED\n"); + pr_info("Testing ftrace recursion: "); + + + /* enable tracing, and record the filter function */ + ftrace_enabled =3D 1; + tracer_enabled =3D 1; + + /* Handle PPC64 '.' name */ + func_name =3D "*" __stringify(DYN_FTRACE_TEST_NAME); + len =3D strlen(func_name); + + ret =3D ftrace_set_filter(&test_rec_probe, func_name, len, 1); + if (ret) { + pr_cont("*Could not set filter* "); + goto out; + } + + ret =3D register_ftrace_function(&test_rec_probe); + if (ret) { + pr_cont("*could not register callback* "); + goto out; + } + + DYN_FTRACE_TEST_NAME(); + + unregister_ftrace_function(&test_rec_probe); + + ret =3D -1; + if (trace_selftest_recursion_cnt !=3D 1) { + pr_cont("*callback not called once (%d)* ", + trace_selftest_recursion_cnt); + goto out; + } + + trace_selftest_recursion_cnt =3D 1; + + pr_cont("PASSED\n"); + pr_info("Testing ftrace recursion safe: "); + + ret =3D ftrace_set_filter(&test_recsafe_probe, func_name, len, 1); + if (ret) { + pr_cont("*Could not set filter* "); + goto out; + } + + ret =3D register_ftrace_function(&test_recsafe_probe); + if (ret) { + pr_cont("*could not register callback* "); + goto out; + } + + DYN_FTRACE_TEST_NAME(); + + unregister_ftrace_function(&test_recsafe_probe); + + /* + * If arch supports all ftrace features, and no other task + * was on the list, we should be fine. + */ + if (!ftrace_nr_registered_ops() && !FTRACE_FORCE_LIST_FUNC) + cnt =3D 2; /* Should have recursed */ + else + cnt =3D 1; + + ret =3D -1; + if (trace_selftest_recursion_cnt !=3D cnt) { + pr_cont("*callback not called expected %d times (%d)* ", + cnt, trace_selftest_recursion_cnt); + goto out; + } + + ret =3D 0; +out: + ftrace_enabled =3D save_ftrace_enabled; + tracer_enabled =3D save_tracer_enabled; + + return ret; +} #else # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; }) +# define trace_selftest_function_recursion() ({ 0; }) #endif /* CONFIG_DYNAMIC_FTRACE */ =20 /* @@ -455,7 +588,10 @@ trace_selftest_startup_function(struct tracer *trace, = struct trace_array *tr) =20 ret =3D trace_selftest_startup_dynamic_tracing(trace, tr, DYN_FTRACE_TEST_NAME); + if (ret) + goto out; =20 + ret =3D trace_selftest_function_recursion(); out: ftrace_enabled =3D save_ftrace_enabled; tracer_enabled =3D save_tracer_enabled; --=20 1.7.10.4 --00GvhwF7k39YY Content-Type: application/pgp-signature; name="signature.asc" Content-Description: This is a digitally signed message part -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQChIVAAoJEIy3vGnGbaoAOIUQAK0i5j1Acjgqy94ddKtmgeRi LM0veHF8okx+eBHGxrRGLe43bBJVgmakK/IAj3+ETRAF0dzNrm1j8bXqQmqYiu5F jyHG245MyzLQlqeCQFlLs1fsU8zhfXRfXn0gYYktfzb9WkLApaWmMUInC6lTB38s dbZEFj6azCiDU2CR4+XwhgxO3vbOWErB7uMmytnzFTTHUM/FgNDXUWbbTCgAemZs c9axtZ/uwORsl3RTnsfMfKGSMW9eMKiLhjIv9ccCXx8oxhfk3Fm0KlSLAXLUN2oy BNZaUWQC5Q3X6fAV1ska0x50+e2Hr8rSkHARFja10jZMauci1aoyZ+hhXO5afZKz XHT8j3clKB0ich3RiNH1TnnhEXbD+dMwgXot3xynDFLPrtaKZPSLYNH6nxorWz+l SW/PFy6XDW8MYVTo4QnPEBFKpvO3Y0tD0JAvscYx6LQpy+KhnZ/XQrVQsBYhufHr UGJtbX1GVtTiAH/6j0A/lw8CThtnhvINAGCLx6gVVKtRp7kR5S1NuciFXC7FIvw4 S8dfeI0gFSfwKXNIY+QtlE50CBzIdok2w+LWXFFKmxoLhF1nFy5PwpuBssYFgJTM 5/b3k0BKLnorTWu63wMfC3YnlftTeHD7o1AbnDsbV1HAUxzoEHZAOCR4qC4PPaSv T9DPtSLfLu1avg8aLL9c =YkUo -----END PGP SIGNATURE----- --00GvhwF7k39YY--