From patchwork Tue Mar 30 00:51:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171315 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B37E0C433E5 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8D025619AB for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229479AbhC3AxO (ORCPT ); Mon, 29 Mar 2021 20:53:14 -0400 Received: from mail.kernel.org ([198.145.29.99]:57618 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229483AbhC3Aws (ORCPT ); Mon, 29 Mar 2021 20:52:48 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 871F66024A; Tue, 30 Mar 2021 00:52:48 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ch-003TdS-GZ; Mon, 29 Mar 2021 20:52:47 -0400 Message-ID: <20210330005247.397966909@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik , "Tzvetomir Stoyanov (VMware)" Subject: [PATCH 01/13 v2] libtracefs: An API to set the filtering of functions References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Sameeruddin shaik This new API will write the function filters into the set_ftrace_filter file. tracefs_function_filter() https://bugzilla.kernel.org/show_bug.cgi?id=210643 Link: https://lore.kernel.org/linux-trace-devel/1616171938-18914-1-git-send-email-sameeruddin.shaik8@gmail.com Link: https://lore.kernel.org/linux-trace-devel/20210323013224.729594322@goodmis.org Acked-by: "Tzvetomir Stoyanov (VMware)" Signed-off-by: Sameeruddin shaik Signed-off-by: Steven Rostedt (VMware) --- include/tracefs.h | 3 +- src/tracefs-tools.c | 111 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/include/tracefs.h b/include/tracefs.h index 05bd0ef4d404..9477fdb14c5a 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -145,5 +145,6 @@ bool tracefs_option_is_enabled(struct tracefs_instance *instance, enum tracefs_o int tracefs_option_enable(struct tracefs_instance *instance, enum tracefs_option_id id); int tracefs_option_diasble(struct tracefs_instance *instance, enum tracefs_option_id id); const char *tracefs_option_name(enum tracefs_option_id id); - +int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, + const char *module, bool reset, const char ***errs); #endif /* _TRACE_FS_H */ diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index e2dfc7b8acff..4f8bcdc299df 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -18,6 +18,7 @@ #include "tracefs-local.h" #define TRACE_CTRL "tracing_on" +#define TRACE_FILTER "set_ftrace_filter" static const char * const options_map[] = { "unknown", @@ -387,3 +388,113 @@ void tracefs_option_clear(struct tracefs_options_mask *options, enum tracefs_opt if (options && id > TRACEFS_OPTION_INVALID) options->mask &= ~(1ULL << (id - 1)); } + +static int controlled_write(const char *filter_path, const char **filters, + const char *module, bool reset, const char ***errs) +{ + int flags = reset ? O_TRUNC : O_APPEND; + const char **temp = NULL; + const char **e = NULL; + char *each_str = NULL; + int write_size = 0; + int size = 0; + int fd = -1; + int ret = 0; + int j = 0; + int i; + + fd = open(filter_path, O_WRONLY | flags); + if (fd < 0) + return 1; + + for (i = 0; filters[i]; i++) { + if (module) + write_size = asprintf(&each_str, "%s:mod:%s ", filters[i], module); + else + write_size = asprintf(&each_str, "%s ", filters[i]); + if (write_size < 0) { + ret = 1; + goto error; + } + size = write(fd, each_str, write_size); + /* compare written bytes*/ + if (size < write_size) { + if (errs) { + temp = realloc(e, (j + 1) * (sizeof(char *))); + if (!temp) { + free(e); + ret = 1; + goto error; + } else + e = temp; + + e[j++] = filters[i]; + ret -= 1; + } + } + free(each_str); + each_str = NULL; + } + if (errs) { + temp = realloc(e, (j + 1) * (sizeof(char *))); + if (!temp) { + free(e); + ret = 1; + goto error; + } else + e = temp; + e[j] = NULL; + *errs = e; + } + error: + if (each_str) + free(each_str); + close(fd); + return ret; +} + +/** + * tracefs_function_filter - write to set_ftrace_filter file to trace + * particular functions + * @instance: ftrace instance, can be NULL for top tracing instance + * @filters: An array of function names ending with a NULL pointer + * @module: Module to be traced + * @reset: set to true to reset the file before applying the filter + * @errs: A pointer to array of constant strings that will be allocated + * on negative return of this function, pointing to the filters that + * failed.May be NULL, in which case this field will be ignored. + * + * The @filters is an array of strings, where each string will be used + * to set a function or functions to be traced. + * + * If @reset is true, then all functions in the filter are cleared + * before adding functions from @filters. Otherwise, the functions set + * by @filters will be appended to the filter file + * + * returns -x on filter errors (where x is number of failed filter + * srtings) and if @errs is not NULL will be an allocated string array + * pointing to the strings in @filters that failed and must be freed + * with free(). + * + * returns 1 on general errors not realted to setting the filter. + * @errs is not set even if supplied. + * + * return 0 on success and @errs is not set. + */ +int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, + const char *module, bool reset, const char ***errs) +{ + char *ftrace_filter_path; + int ret = 0; + + if (!filters) + return 1; + + ftrace_filter_path = tracefs_instance_get_file(instance, TRACE_FILTER); + if (!ftrace_filter_path) + return 1; + + ret = controlled_write(ftrace_filter_path, filters, module, reset, errs); + tracefs_put_tracing_file(ftrace_filter_path); + return ret; +} From patchwork Tue Mar 30 00:51:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171321 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1811C433E8 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B829261987 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229655AbhC3AxN (ORCPT ); Mon, 29 Mar 2021 20:53:13 -0400 Received: from mail.kernel.org ([198.145.29.99]:57628 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229555AbhC3Aws (ORCPT ); Mon, 29 Mar 2021 20:52:48 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 9BC1F61996; Tue, 30 Mar 2021 00:52:48 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ch-003Tdx-LN; Mon, 29 Mar 2021 20:52:47 -0400 Message-ID: <20210330005247.542845271@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:25 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 02/13 v2] libtracefs: Document function_filter API References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: Sameeruddin shaik Added documentation for the below API: tracefs_function_filter() Link: https://lore.kernel.org/linux-trace-devel/1616719420-6747-1-git-send-email-sameeruddin.shaik8@gmail.com Signed-off-by: Sameeruddin shaik [ Cleaned up some white space issues - S.R ] Signed-off-by: Steven Rostedt (VMware) --- Documentation/libtracefs-function-filter.txt | 120 +++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 Documentation/libtracefs-function-filter.txt diff --git a/Documentation/libtracefs-function-filter.txt b/Documentation/libtracefs-function-filter.txt new file mode 100644 index 000000000000..9351788dd1a1 --- /dev/null +++ b/Documentation/libtracefs-function-filter.txt @@ -0,0 +1,120 @@ +libtracefs(3) +============= + +NAME +---- +tracefs_function_filter - Function to limit kernel functions that are traced + +SYNOPSIS +-------- +[verse] +-- +*#include * + +int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, const char *module, bool reset, const char ***errs); +-- + +DESCRIPTION +----------- +This function can be used to limit the Linux kernel functions that were +traced by the function and function-graph tracers + +It will take +_instance_ , that can be NULL for the top level tracing. +_filters_, which is an array of the strings that represent a list of filters that should +be applied to define what functions are to be traced and The array must end +with a NULL pointer. +_module_ , name of the module to be traced. +_reset_ if set will clear the current set of filters and then apply the +filter list, otherwise the list of filters are added to the current set of +filters, +_errs_, is a pointer to an array of strings, which will be allocated if +any of filters fail to match any available function, If _errs_ is NULL, it will +be ignored. + +returns 0 on success, 1 or -x (where x is an integer) on error. + +RETURN VALUE +------------ +return 0 on success, if there is error, it will return 1 for general errors or +negative number -x(x denotes number of failed filters), if there are any failed filters. + +In case of negative return value, errs have to be checked and must be freed +using the free() + +EXAMPLE +------- +[source,c] +-- +#include + +#define INST "dummy" + +const char *filters[] = { "run_init_process", "try_to_run_init_process", "dummy1", NULL }; + +int main(int argc, char *argv[]) +{ + struct tracefs_instance *inst = tracefs_instance_create(INST); + const char **errs = NULL; + bool reset = 1; + int ret; + int i = 0; + + if (!inst) { + /* Error creating new trace instance*/ + } + + ret = tracefs_function_filter(inst, filters, NULL, reset, &errs); + + if (ret < 0 && errs) { + while (errs[i]) + printf("%s\n", errs[i++]); + } + + tracefs_instance_free(inst); + tracefs_instance_destroy(inst); + free(errs); + return 0; +} +-- + +FILES +----- +[verse] +-- +*tracefs.h* + Header file to include in order to have access to the library APIs. +*-ltracefs* + Linker switch to add when building a program that uses the library. +-- + +SEE ALSO +-------- +_libtracefs(3)_, +_libtraceevent(3)_, +_trace-cmd(1)_ + +AUTHOR +------ +[verse] +-- +*Steven Rostedt* +*Tzvetomir Stoyanov* +*sameeruddin shaik* +-- +REPORTING BUGS +-------------- +Report bugs to + +LICENSE +------- +libtracefs is Free Software licensed under the GNU LGPL 2.1 + +RESOURCES +--------- +https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ + +COPYING +------- +Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under +the terms of the GNU Public License (GPL). From patchwork Tue Mar 30 00:51:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171325 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0BAA3C433E6 for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D2B59619A5 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229689AbhC3AxM (ORCPT ); Mon, 29 Mar 2021 20:53:12 -0400 Received: from mail.kernel.org ([198.145.29.99]:57642 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229655AbhC3Awt (ORCPT ); Mon, 29 Mar 2021 20:52:49 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id B88F461997; Tue, 30 Mar 2021 00:52:48 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ch-003TeR-Ps; Mon, 29 Mar 2021 20:52:47 -0400 Message-ID: <20210330005247.685321870@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:26 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 03/13 v2] libtracefs: Fix notations of tracefs_function_filter() and module parameter References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" Highlight the function name and encapsulate each '*' with a "pass:[*]" to not have the creation of the man pages interpret them as bold annotations. Also remove the tracefs_instance_free(), as tracefs_instance_destroy() is called and that frees the instance. The description in the man page for tracefs_function_filter() left out that NULL is a suitable value for the modules parameter, meaning that all functions will be examined for a match of one of the filters. Signed-off-by: Steven Rostedt (VMware) --- Documentation/libtracefs-function-filter.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/libtracefs-function-filter.txt b/Documentation/libtracefs-function-filter.txt index 9351788dd1a1..c0c89f372c21 100644 --- a/Documentation/libtracefs-function-filter.txt +++ b/Documentation/libtracefs-function-filter.txt @@ -11,7 +11,7 @@ SYNOPSIS -- *#include * -int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, const char *module, bool reset, const char ***errs); +int *tracefs_function_filter*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]pass:[*]_filters_, const char pass:[*]_module_, bool _reset_, const char pass:[*]pass:[*]pass:[*]_errs_); -- DESCRIPTION @@ -24,7 +24,7 @@ _instance_ , that can be NULL for the top level tracing. _filters_, which is an array of the strings that represent a list of filters that should be applied to define what functions are to be traced and The array must end with a NULL pointer. -_module_ , name of the module to be traced. +_module_ , name of the module to be traced (or NULL for all functions), _reset_ if set will clear the current set of filters and then apply the filter list, otherwise the list of filters are added to the current set of filters, @@ -61,7 +61,7 @@ int main(int argc, char *argv[]) int i = 0; if (!inst) { - /* Error creating new trace instance*/ + /* Error creating new trace instance */ } ret = tracefs_function_filter(inst, filters, NULL, reset, &errs); @@ -71,7 +71,6 @@ int main(int argc, char *argv[]) printf("%s\n", errs[i++]); } - tracefs_instance_free(inst); tracefs_instance_destroy(inst); free(errs); return 0; From patchwork Tue Mar 30 00:51:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171311 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 84A64C433E3 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4F7B461987 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229709AbhC3AxL (ORCPT ); Mon, 29 Mar 2021 20:53:11 -0400 Received: from mail.kernel.org ([198.145.29.99]:57658 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229689AbhC3Awt (ORCPT ); Mon, 29 Mar 2021 20:52:49 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id E0C6861999; Tue, 30 Mar 2021 00:52:48 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ch-003Tev-U8; Mon, 29 Mar 2021 20:52:47 -0400 Message-ID: <20210330005247.820340155@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:27 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 04/13 v2] libtracefs: Move opening of file out of controlled_write() References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" In order to try multiple methods of writing to the filter file, the opening of the filter file needs to be in the tracefs_function_filter() call, and allow that to be passed to multiple ways of writing to the filter. Link: https://lore.kernel.org/linux-trace-devel/20210323013224.877520803@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-tools.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index 4f8bcdc299df..02e43168a810 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -389,24 +389,18 @@ void tracefs_option_clear(struct tracefs_options_mask *options, enum tracefs_opt options->mask &= ~(1ULL << (id - 1)); } -static int controlled_write(const char *filter_path, const char **filters, - const char *module, bool reset, const char ***errs) +static int controlled_write(int fd, const char **filters, + const char *module, const char ***errs) { - int flags = reset ? O_TRUNC : O_APPEND; const char **temp = NULL; const char **e = NULL; char *each_str = NULL; int write_size = 0; int size = 0; - int fd = -1; int ret = 0; int j = 0; int i; - fd = open(filter_path, O_WRONLY | flags); - if (fd < 0) - return 1; - for (i = 0; filters[i]; i++) { if (module) write_size = asprintf(&each_str, "%s:mod:%s ", filters[i], module); @@ -449,7 +443,6 @@ static int controlled_write(const char *filter_path, const char **filters, error: if (each_str) free(each_str); - close(fd); return ret; } @@ -486,6 +479,8 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt { char *ftrace_filter_path; int ret = 0; + int flags; + int fd; if (!filters) return 1; @@ -494,7 +489,16 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt if (!ftrace_filter_path) return 1; - ret = controlled_write(ftrace_filter_path, filters, module, reset, errs); + flags = reset ? O_TRUNC : O_APPEND; + + fd = open(ftrace_filter_path, O_WRONLY | flags); tracefs_put_tracing_file(ftrace_filter_path); + if (fd < 0) + return 1; + + ret = controlled_write(fd, filters, module, errs); + + close(fd); + return ret; } From patchwork Tue Mar 30 00:51:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171309 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 061D6C433C1 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AA50161987 for ; Tue, 30 Mar 2021 00:53:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229762AbhC3AxL (ORCPT ); Mon, 29 Mar 2021 20:53:11 -0400 Received: from mail.kernel.org ([198.145.29.99]:57672 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229709AbhC3Awt (ORCPT ); Mon, 29 Mar 2021 20:52:49 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 0B49A61987; Tue, 30 Mar 2021 00:52:49 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ci-003TfP-2c; Mon, 29 Mar 2021 20:52:48 -0400 Message-ID: <20210330005247.960629718@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:28 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 05/13 v2] libtracefs: Add add_errors() helper function for control_write() References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" Move the code that manages errors out of control_write() as this will be used by other methods in setting the filters. Link: https://lore.kernel.org/linux-trace-devel/20210323013225.012918584@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-tools.c | 61 ++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index 02e43168a810..1348542a3419 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -389,16 +389,40 @@ void tracefs_option_clear(struct tracefs_options_mask *options, enum tracefs_opt options->mask &= ~(1ULL << (id - 1)); } +static void add_errors(const char ***errs, const char *filter, int ret) +{ + const char **e; + + if (!errs) + return; + + /* Negative is passed in */ + ret = -ret; + e = *errs; + + /* If this previously failed to allocate stop processing */ + if (!e && ret) + return; + + /* Add 2, one for the new entry, and one for NULL */ + e = realloc(e, sizeof(*e) * (ret + 2)); + if (!e) { + free(*errs); + *errs = NULL; + return; + } + e[ret] = filter; + e[ret + 1] = NULL; + *errs = e; +} + static int controlled_write(int fd, const char **filters, const char *module, const char ***errs) { - const char **temp = NULL; - const char **e = NULL; char *each_str = NULL; int write_size = 0; int size = 0; int ret = 0; - int j = 0; int i; for (i = 0; filters[i]; i++) { @@ -412,34 +436,11 @@ static int controlled_write(int fd, const char **filters, } size = write(fd, each_str, write_size); /* compare written bytes*/ - if (size < write_size) { - if (errs) { - temp = realloc(e, (j + 1) * (sizeof(char *))); - if (!temp) { - free(e); - ret = 1; - goto error; - } else - e = temp; - - e[j++] = filters[i]; - ret -= 1; - } - } + if (size < write_size) + add_errors(errs, filters[i], ret--); free(each_str); each_str = NULL; } - if (errs) { - temp = realloc(e, (j + 1) * (sizeof(char *))); - if (!temp) { - free(e); - ret = 1; - goto error; - } else - e = temp; - e[j] = NULL; - *errs = e; - } error: if (each_str) free(each_str); @@ -496,6 +497,10 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt if (fd < 0) return 1; + /* Make sure errs is NULL to start with, realloc() depends on it. */ + if (errs) + *errs = NULL; + ret = controlled_write(fd, filters, module, errs); close(fd); From patchwork Tue Mar 30 00:51:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171313 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C3DCC433E1 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 31109619A0 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230223AbhC3AxL (ORCPT ); Mon, 29 Mar 2021 20:53:11 -0400 Received: from mail.kernel.org ([198.145.29.99]:57686 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229750AbhC3Awt (ORCPT ); Mon, 29 Mar 2021 20:52:49 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 2D74A619A0; Tue, 30 Mar 2021 00:52:49 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ci-003Tft-71; Mon, 29 Mar 2021 20:52:48 -0400 Message-ID: <20210330005248.103947204@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:29 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 06/13 v2] libtracefs: Add checking of available_filter_functions to tracefs_function_filter() References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" Instead of modifying the set_ftrace_filter file with a filter that possibly does not match anything, check the available_filter_functions file first to make sure that each filter will match something. Then if "reset" is enabled, it wont clear the filter file and not set any filtering, which could cause issues if the application is not expecting all functions to be enabled. Link: https://lore.kernel.org/linux-trace-devel/20210323013225.156539389@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-tools.c | 183 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 178 insertions(+), 5 deletions(-) diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index 1348542a3419..db12f759be1b 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -416,6 +417,112 @@ static void add_errors(const char ***errs, const char *filter, int ret) *errs = e; } +struct func_filter { + const char *filter; + regex_t re; + bool set; +}; + +/* + * Convert a glob into a regular expression. + */ +static char *make_regex(const char *glob) +{ + char *str; + int cnt = 0; + int i, j; + + for (i = 0; glob[i]; i++) { + if (glob[i] == '*'|| glob[i] == '.') + cnt++; + } + + /* '^' + ('*'->'.*' or '.' -> '\.') + '$' + '\0' */ + str = malloc(i + cnt + 3); + if (!str) + return NULL; + + str[0] = '^'; + for (i = 0, j = 1; glob[i]; i++, j++) { + if (glob[i] == '*') + str[j++] = '.'; + /* Dots can be part of a function name */ + if (glob[i] == '.') + str[j++] = '\\'; + str[j] = glob[i]; + } + str[j++] = '$'; + str[j] = '\0'; + return str; +} + +static bool match(const char *str, struct func_filter *func_filter) +{ + return regexec(&func_filter->re, str, 0, NULL, 0) == 0; +} + +static int check_available_filters(struct func_filter *func_filters, + const char *module, const char ***errs) +{ + char *line = NULL; + size_t size = 0; + char *path; + FILE *fp; + int ret = 1; + int mlen; + int i; + + path = tracefs_get_tracing_file("available_filter_functions"); + if (!path) + return 1; + + fp = fopen(path, "r"); + tracefs_put_tracing_file(path); + + if (!fp) + return 1; + + if (module) + mlen = strlen(module); + + while (getline(&line, &size, fp) >= 0) { + char *saveptr = NULL; + char *tok, *mtok; + int len = strlen(line); + + if (line[len - 1] == '\n') + line[len - 1] = '\0'; + tok = strtok_r(line, " ", &saveptr); + if (!tok) + goto next; + if (module) { + mtok = strtok_r(NULL, " ", &saveptr); + if (!mtok) + goto next; + if ((strncmp(mtok + 1, module, mlen) != 0) || + (mtok[mlen + 1] != ']')) + goto next; + } + for (i = 0; func_filters[i].filter; i++) { + if (match(tok, &func_filters[i])) + func_filters[i].set = true; + } + next: + free(line); + line = NULL; + len = 0; + } + fclose(fp); + + ret = 0; + for (i = 0; func_filters[i].filter; i++) { + if (!func_filters[i].set) + add_errors(errs, func_filters[i].filter, ret--); + } + + return ret; +} + static int controlled_write(int fd, const char **filters, const char *module, const char ***errs) { @@ -447,6 +554,62 @@ static int controlled_write(int fd, const char **filters, return ret; } +static int init_func_filter(struct func_filter *func_filter, const char *filter) +{ + char *str; + int ret; + + str = make_regex(filter); + if (!str) + return -1; + + ret = regcomp(&func_filter->re, str, REG_ICASE|REG_NOSUB); + free(str); + + if (ret < 0) + return -1; + + func_filter->filter = filter; + return 0; +} + +static void free_func_filters(struct func_filter *func_filters) +{ + int i; + + if (!func_filters) + return; + + for (i = 0; func_filters[i].filter; i++) { + regfree(&func_filters[i].re); + } +} + +static struct func_filter *make_func_filters(const char **filters) +{ + struct func_filter *func_filters = NULL; + int i; + + for (i = 0; filters[i]; i++) + ; + + if (!i) + return NULL; + + func_filters = calloc(i + 1, sizeof(*func_filters)); + if (!func_filters) + return NULL; + + for (i = 0; filters[i]; i++) { + if (init_func_filter(&func_filters[i], filters[i]) < 0) + goto out_err; + } + return func_filters; + out_err: + free_func_filters(func_filters); + return NULL; +} + /** * tracefs_function_filter - write to set_ftrace_filter file to trace * particular functions @@ -478,14 +641,28 @@ static int controlled_write(int fd, const char **filters, int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, const char *module, bool reset, const char ***errs) { + struct func_filter *func_filters; char *ftrace_filter_path; - int ret = 0; int flags; + int ret; int fd; if (!filters) return 1; + func_filters = make_func_filters(filters); + if (!func_filters) + return 1; + + /* Make sure errs is NULL to start with, realloc() depends on it. */ + if (errs) + *errs = NULL; + + ret = check_available_filters(func_filters, module, errs); + free_func_filters(func_filters); + if (ret) + return ret; + ftrace_filter_path = tracefs_instance_get_file(instance, TRACE_FILTER); if (!ftrace_filter_path) return 1; @@ -497,10 +674,6 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt if (fd < 0) return 1; - /* Make sure errs is NULL to start with, realloc() depends on it. */ - if (errs) - *errs = NULL; - ret = controlled_write(fd, filters, module, errs); close(fd); From patchwork Tue Mar 30 00:51:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171307 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D05AC433E0 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DD28861988 for ; Tue, 30 Mar 2021 00:53:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229750AbhC3AxL (ORCPT ); Mon, 29 Mar 2021 20:53:11 -0400 Received: from mail.kernel.org ([198.145.29.99]:57658 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229762AbhC3Awt (ORCPT ); Mon, 29 Mar 2021 20:52:49 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 50217619A5; Tue, 30 Mar 2021 00:52:49 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ci-003TgN-Bo; Mon, 29 Mar 2021 20:52:48 -0400 Message-ID: <20210330005248.243416850@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:30 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 07/13 v2] libtracefs: Add write_filter() helper function References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" Wrap the writing of the filter into the filter file in a helper function such that it can be used in more places. Link: https://lore.kernel.org/linux-trace-devel/20210323013225.303716095@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-tools.c | 58 ++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index db12f759be1b..470502b07f7d 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -461,6 +461,33 @@ static bool match(const char *str, struct func_filter *func_filter) return regexec(&func_filter->re, str, 0, NULL, 0) == 0; } +/* + * Return 0 on success, -1 error writing, 1 on other errors. + */ +static int write_filter(int fd, const char *filter, const char *module) +{ + char *each_str = NULL; + int write_size; + int size; + + if (module) + write_size = asprintf(&each_str, "%s:mod:%s ", filter, module); + else + write_size = asprintf(&each_str, "%s ", filter); + + if (write_size < 0) + return 1; + + size = write(fd, each_str, write_size); + free(each_str); + + /* compare written bytes*/ + if (size < write_size) + return -1; + + return 0; +} + static int check_available_filters(struct func_filter *func_filters, const char *module, const char ***errs) { @@ -526,31 +553,24 @@ static int check_available_filters(struct func_filter *func_filters, static int controlled_write(int fd, const char **filters, const char *module, const char ***errs) { - char *each_str = NULL; - int write_size = 0; - int size = 0; int ret = 0; int i; for (i = 0; filters[i]; i++) { - if (module) - write_size = asprintf(&each_str, "%s:mod:%s ", filters[i], module); - else - write_size = asprintf(&each_str, "%s ", filters[i]); - if (write_size < 0) { - ret = 1; - goto error; - } - size = write(fd, each_str, write_size); - /* compare written bytes*/ - if (size < write_size) + int r; + + r = write_filter(fd, filters[i], module); + if (r < 0) { add_errors(errs, filters[i], ret--); - free(each_str); - each_str = NULL; + } else if (r > 0) { + /* Not filter error */ + if (errs) { + free(*errs); + *errs = NULL; + } + return 1; + } } - error: - if (each_str) - free(each_str); return ret; } From patchwork Tue Mar 30 00:51:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171331 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 68E53C433ED for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4A47D60C3E for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229842AbhC3AxO (ORCPT ); Mon, 29 Mar 2021 20:53:14 -0400 Received: from mail.kernel.org ([198.145.29.99]:57672 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229763AbhC3Awt (ORCPT ); Mon, 29 Mar 2021 20:52:49 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 7EC636024A; Tue, 30 Mar 2021 00:52:49 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ci-003Tgr-GN; Mon, 29 Mar 2021 20:52:48 -0400 Message-ID: <20210330005248.391852830@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:31 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 08/13 v2] libtracefs: Allow for setting filters with regex expressions References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" All for full "regex(3)" processing of setting functions in the set_ftrace_filter file. Check if the filter passed in is just a glob expression that the kernel can process, or if it is a regex that should look at the available_filter_functions list instead. If it is a regex, it will read the available_filter_functions and write in each function as it finds it. Link: https://lore.kernel.org/linux-trace-devel/20210323013225.451281989@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- Documentation/libtracefs-function-filter.txt | 10 ++ src/tracefs-tools.c | 139 ++++++++++++++++--- 2 files changed, 128 insertions(+), 21 deletions(-) diff --git a/Documentation/libtracefs-function-filter.txt b/Documentation/libtracefs-function-filter.txt index c0c89f372c21..88aa3b923d54 100644 --- a/Documentation/libtracefs-function-filter.txt +++ b/Documentation/libtracefs-function-filter.txt @@ -32,6 +32,16 @@ _errs_, is a pointer to an array of strings, which will be allocated if any of filters fail to match any available function, If _errs_ is NULL, it will be ignored. +A filter in the array of _filters_ may be either a straight match of a +function, a glob or regex(3). a glob is where '*' matches zero or more +characters, '?' will match zero or one character, and '.' only matches a +period. If the filter is determined to be a regex (where it contains +anything other than alpha numeric characters, or '.', '*', '?') the filter +will be processed as a regex(3) following the rules of regex(3), and '.' is +not a period, but will match any one character. To force a regular +expression, either prefix the filter with a '^' or append it with a '$' as +all filters will act as complete matches of functions anyway. + returns 0 on success, 1 or -x (where x is an integer) on error. RETURN VALUE diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index 470502b07f7d..d1a448459c6f 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -18,8 +18,9 @@ #include "tracefs.h" #include "tracefs-local.h" -#define TRACE_CTRL "tracing_on" -#define TRACE_FILTER "set_ftrace_filter" +#define TRACE_CTRL "tracing_on" +#define TRACE_FILTER "set_ftrace_filter" +#define TRACE_FILTER_LIST "available_filter_functions" static const char * const options_map[] = { "unknown", @@ -421,8 +422,53 @@ struct func_filter { const char *filter; regex_t re; bool set; + bool is_regex; }; +static bool is_regex(const char *str) +{ + int i; + + for (i = 0; str[i]; i++) { + switch (str[i]) { + case 'a' ... 'z': + case 'A'...'Z': + case '_': + case '0'...'9': + case '*': + case '.': + /* Dots can be part of a function name */ + case '?': + continue; + default: + return true; + } + } + return false; +} + +static char *update_regex(const char *reg) +{ + int len = strlen(reg); + char *str; + + if (reg[0] == '^' && reg[len - 1] == '$') + return strdup(reg); + + str = malloc(len + 3); + if (reg[0] == '^') { + strcpy(str, reg); + } else { + str[0] = '^'; + strcpy(str + 1, reg); + len++; /* add ^ */ + } + if (str[len - 1] != '$') + str[len++]= '$'; + str[len] = '\0'; + return str; +} + /* * Convert a glob into a regular expression. */ @@ -488,8 +534,13 @@ static int write_filter(int fd, const char *filter, const char *module) return 0; } -static int check_available_filters(struct func_filter *func_filters, - const char *module, const char ***errs) +enum match_type { + FILTER_CHECK, + FILTER_WRITE, +}; + +static int match_filters(int fd, struct func_filter *func_filters, + const char *module, enum match_type type) { char *line = NULL; size_t size = 0; @@ -499,7 +550,7 @@ static int check_available_filters(struct func_filter *func_filters, int mlen; int i; - path = tracefs_get_tracing_file("available_filter_functions"); + path = tracefs_get_tracing_file(TRACE_FILTER_LIST); if (!path) return 1; @@ -530,39 +581,76 @@ static int check_available_filters(struct func_filter *func_filters, (mtok[mlen + 1] != ']')) goto next; } - for (i = 0; func_filters[i].filter; i++) { - if (match(tok, &func_filters[i])) - func_filters[i].set = true; + switch (type) { + case FILTER_CHECK: + /* Check, checks a list of filters */ + for (i = 0; func_filters[i].filter; i++) { + if (match(tok, &func_filters[i])) + func_filters[i].set = true; + } + break; + case FILTER_WRITE: + /* Writes only have one filter */ + if (match(tok, func_filters)) { + ret = write_filter(fd, tok, module); + if (ret) + goto out; + } + break; } next: free(line); line = NULL; len = 0; } + out: + free(line); fclose(fp); + return ret; +} + +static int check_available_filters(struct func_filter *func_filters, + const char *module, const char ***errs) +{ + int ret; + int i; + + ret = match_filters(-1, func_filters, module, FILTER_CHECK); + /* Return here if success or non filter error */ + if (ret >= 0) + return ret; + + /* Failed on filter, set the errors */ ret = 0; for (i = 0; func_filters[i].filter; i++) { if (!func_filters[i].set) add_errors(errs, func_filters[i].filter, ret--); } - return ret; } -static int controlled_write(int fd, const char **filters, +static int set_regex_filter(int fd, struct func_filter *func_filter, + const char *module) +{ + return match_filters(fd, func_filter, module, FILTER_WRITE); +} + +static int controlled_write(int fd, struct func_filter *func_filters, const char *module, const char ***errs) { int ret = 0; int i; - for (i = 0; filters[i]; i++) { + for (i = 0; func_filters[i].filter; i++) { + const char *filter = func_filters[i].filter; int r; - r = write_filter(fd, filters[i], module); - if (r < 0) { - add_errors(errs, filters[i], ret--); - } else if (r > 0) { + if (func_filters[i].is_regex) + r = set_regex_filter(fd, &func_filters[i], module); + else + r = write_filter(fd, filter, module); + if (r > 0) { /* Not filter error */ if (errs) { free(*errs); @@ -570,6 +658,8 @@ static int controlled_write(int fd, const char **filters, } return 1; } + if (r < 0) + add_errors(errs, filter, ret--); } return ret; } @@ -579,7 +669,11 @@ static int init_func_filter(struct func_filter *func_filter, const char *filter) char *str; int ret; - str = make_regex(filter); + if (!(func_filter->is_regex = is_regex(filter))) + str = make_regex(filter); + else + str = update_regex(filter); + if (!str) return -1; @@ -679,24 +773,27 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt *errs = NULL; ret = check_available_filters(func_filters, module, errs); - free_func_filters(func_filters); if (ret) - return ret; + goto out_free; + ret = 1; ftrace_filter_path = tracefs_instance_get_file(instance, TRACE_FILTER); if (!ftrace_filter_path) - return 1; + goto out_free; flags = reset ? O_TRUNC : O_APPEND; fd = open(ftrace_filter_path, O_WRONLY | flags); tracefs_put_tracing_file(ftrace_filter_path); if (fd < 0) - return 1; + goto out_free; - ret = controlled_write(fd, filters, module, errs); + ret = controlled_write(fd, func_filters, module, errs); close(fd); + out_free: + free_func_filters(func_filters); + return ret; } From patchwork Tue Mar 30 00:51:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171319 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 93D75C433E2 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 780DA619A6 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229483AbhC3AxO (ORCPT ); Mon, 29 Mar 2021 20:53:14 -0400 Received: from mail.kernel.org ([198.145.29.99]:57686 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229842AbhC3Awt (ORCPT ); Mon, 29 Mar 2021 20:52:49 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 990CB61996; Tue, 30 Mar 2021 00:52:49 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ci-003ThN-Ld; Mon, 29 Mar 2021 20:52:48 -0400 Message-ID: <20210330005248.543285809@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:32 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 09/13 v2] libtracefs: Add indexing to set functions in tracefs_function_filter() References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" Starting in Linux kernel 5.1, it is possible to write the index of the available_filter_functions (where the first function is 1), which is a much faster way to set functions than with the glob expressions. By finding the matches of the available_filter_functions and using the index of the function, this can make the function call of tracefs_function_filter() return much faster. Link: https://lore.kernel.org/linux-trace-devel/20210323013225.595028176@goodmis.org Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-tools.c | 123 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 7 deletions(-) diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index d1a448459c6f..8f2130948fe0 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -418,6 +418,12 @@ static void add_errors(const char ***errs, const char *filter, int ret) *errs = e; } +struct func_list { + struct func_list *next; + unsigned int start; + unsigned int end; +}; + struct func_filter { const char *filter; regex_t re; @@ -534,18 +540,54 @@ static int write_filter(int fd, const char *filter, const char *module) return 0; } +static int add_func(struct func_list ***next_func_ptr, unsigned int index) +{ + struct func_list **next_func = *next_func_ptr; + struct func_list *func_list = *next_func; + + if (!func_list) { + func_list = calloc(1, sizeof(*func_list)); + if (!func_list) + return -1; + func_list->start = index; + func_list->end = index; + *next_func = func_list; + return 0; + } + + if (index == func_list->end + 1) { + func_list->end = index; + return 0; + } + *next_func_ptr = &func_list->next; + return add_func(next_func_ptr, index); +} + +static void free_func_list(struct func_list *func_list) +{ + struct func_list *f; + + while (func_list) { + f = func_list; + func_list = f->next; + free(f); + } +} + enum match_type { FILTER_CHECK, FILTER_WRITE, }; static int match_filters(int fd, struct func_filter *func_filters, - const char *module, enum match_type type) + const char *module, struct func_list **func_list, + enum match_type type) { char *line = NULL; size_t size = 0; char *path; FILE *fp; + int index = 0; int ret = 1; int mlen; int i; @@ -567,12 +609,16 @@ static int match_filters(int fd, struct func_filter *func_filters, char *saveptr = NULL; char *tok, *mtok; int len = strlen(line); + bool first = true; if (line[len - 1] == '\n') line[len - 1] = '\0'; tok = strtok_r(line, " ", &saveptr); if (!tok) goto next; + + index++; + if (module) { mtok = strtok_r(NULL, " ", &saveptr); if (!mtok) @@ -585,8 +631,23 @@ static int match_filters(int fd, struct func_filter *func_filters, case FILTER_CHECK: /* Check, checks a list of filters */ for (i = 0; func_filters[i].filter; i++) { - if (match(tok, &func_filters[i])) + /* + * If a match was found, still need to + * check if other filters would match + * to make sure that all filters have a + * match, as some filters may overlap. + */ + if (!first && func_filters[i].set) + continue; + if (match(tok, &func_filters[i])) { func_filters[i].set = true; + if (first) { + first = false; + ret = add_func(&func_list, index); + if (ret) + goto out; + } + } } break; case FILTER_WRITE: @@ -611,12 +672,13 @@ static int match_filters(int fd, struct func_filter *func_filters, } static int check_available_filters(struct func_filter *func_filters, - const char *module, const char ***errs) + const char *module, const char ***errs, + struct func_list **func_list) { int ret; int i; - ret = match_filters(-1, func_filters, module, FILTER_CHECK); + ret = match_filters(-1, func_filters, module, func_list, FILTER_CHECK); /* Return here if success or non filter error */ if (ret >= 0) return ret; @@ -633,7 +695,7 @@ static int check_available_filters(struct func_filter *func_filters, static int set_regex_filter(int fd, struct func_filter *func_filter, const char *module) { - return match_filters(fd, func_filter, module, FILTER_WRITE); + return match_filters(fd, func_filter, module, NULL, FILTER_WRITE); } static int controlled_write(int fd, struct func_filter *func_filters, @@ -724,6 +786,49 @@ static struct func_filter *make_func_filters(const char **filters) return NULL; } +static int write_number(int fd, unsigned int start, unsigned int end) +{ + char buf[64]; + unsigned int i; + int n, ret; + + for (i = start; i <= end; i++) { + n = snprintf(buf, 64, "%d ", i); + ret = write(fd, buf, n); + if (ret < 0) + return ret; + } + + return 0; +} + +/* + * This will try to write the first number, if that fails, it + * will assume that it is not supported and return 1. + * If the first write succeeds, but a following write fails, then + * the kernel does support this, but something else went wrong, + * in this case, return -1. + */ +static int write_func_list(int fd, struct func_list *list) +{ + int ret; + + if (!list) + return 0; + + ret = write_number(fd, list->start, list->end); + if (ret) + return 1; // try a different way + list = list->next; + while (list) { + ret = write_number(fd, list->start, list->end); + if (ret) + return -1; + list = list->next; + } + return 0; +} + /** * tracefs_function_filter - write to set_ftrace_filter file to trace * particular functions @@ -756,6 +861,7 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt const char *module, bool reset, const char ***errs) { struct func_filter *func_filters; + struct func_list *func_list = NULL; char *ftrace_filter_path; int flags; int ret; @@ -772,7 +878,7 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt if (errs) *errs = NULL; - ret = check_available_filters(func_filters, module, errs); + ret = check_available_filters(func_filters, module, errs, &func_list); if (ret) goto out_free; @@ -788,11 +894,14 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt if (fd < 0) goto out_free; - ret = controlled_write(fd, func_filters, module, errs); + ret = write_func_list(fd, func_list); + if (ret > 0) + ret = controlled_write(fd, func_filters, module, errs); close(fd); out_free: + free_func_list(func_list); free_func_filters(func_filters); return ret; From patchwork Tue Mar 30 00:51:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171333 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7BCB5C433EC for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 613906024A for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230089AbhC3AxP (ORCPT ); Mon, 29 Mar 2021 20:53:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:57658 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229861AbhC3Awu (ORCPT ); Mon, 29 Mar 2021 20:52:50 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id C128661988; Tue, 30 Mar 2021 00:52:49 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ci-003Thr-QD; Mon, 29 Mar 2021 20:52:48 -0400 Message-ID: <20210330005248.694899644@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:33 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 10/13 v2] libtracefs: Pass in reset via flags to tracefs_function_filter() References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" Instead of having a separate boolean to tell tracefs_function_filter() to reset the file upon opening, make it a flag instead. This way other booleans can be passed into the function without having to extend the parameters. Signed-off-by: Steven Rostedt (VMware) --- Documentation/libtracefs-function-filter.txt | 26 ++++++++++++++------ include/tracefs.h | 10 +++++++- src/tracefs-tools.c | 19 ++++++++------ 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Documentation/libtracefs-function-filter.txt b/Documentation/libtracefs-function-filter.txt index 88aa3b923d54..5b55a72727c8 100644 --- a/Documentation/libtracefs-function-filter.txt +++ b/Documentation/libtracefs-function-filter.txt @@ -11,7 +11,7 @@ SYNOPSIS -- *#include * -int *tracefs_function_filter*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]pass:[*]_filters_, const char pass:[*]_module_, bool _reset_, const char pass:[*]pass:[*]pass:[*]_errs_); +int *tracefs_function_filter*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]pass:[*]_filters_, const char pass:[*]_module_, int _flags_, const char pass:[*]pass:[*]pass:[*]_errs_); -- DESCRIPTION @@ -25,18 +25,17 @@ _filters_, which is an array of the strings that represent a list of filters tha be applied to define what functions are to be traced and The array must end with a NULL pointer. _module_ , name of the module to be traced (or NULL for all functions), -_reset_ if set will clear the current set of filters and then apply the -filter list, otherwise the list of filters are added to the current set of -filters, +_flags_ which holds control knobs on how the filters will be handled (see *FLAGS*) +section below, _errs_, is a pointer to an array of strings, which will be allocated if any of filters fail to match any available function, If _errs_ is NULL, it will be ignored. A filter in the array of _filters_ may be either a straight match of a -function, a glob or regex(3). a glob is where '*' matches zero or more +function, a glob or regex(3). a glob is where 'pass:[*]' matches zero or more characters, '?' will match zero or one character, and '.' only matches a period. If the filter is determined to be a regex (where it contains -anything other than alpha numeric characters, or '.', '*', '?') the filter +anything other than alpha numeric characters, or '.', 'pass:[*]', '?') the filter will be processed as a regex(3) following the rules of regex(3), and '.' is not a period, but will match any one character. To force a regular expression, either prefix the filter with a '^' or append it with a '$' as @@ -44,6 +43,17 @@ all filters will act as complete matches of functions anyway. returns 0 on success, 1 or -x (where x is an integer) on error. +FLAGS +----- + +The _flags_ parameter may have the following set, or be zero. + +*TRACEFS_FL_RESET* : +If _flags_ contains *TRACEFS_FL_RESET*, then it will clear the filters that +are currently set before applying the list of filters from _filters_. Otherwise, +the list of filters from _filters_ will be added to the current set of filters +already enabled. + RETURN VALUE ------------ return 0 on success, if there is error, it will return 1 for general errors or @@ -66,7 +76,7 @@ int main(int argc, char *argv[]) { struct tracefs_instance *inst = tracefs_instance_create(INST); const char **errs = NULL; - bool reset = 1; + int flags = TRACEFS_FL_RESET; int ret; int i = 0; @@ -74,7 +84,7 @@ int main(int argc, char *argv[]) /* Error creating new trace instance */ } - ret = tracefs_function_filter(inst, filters, NULL, reset, &errs); + ret = tracefs_function_filter(inst, filters, NULL, flags, &errs); if (ret < 0 && errs) { while (errs[i]) diff --git a/include/tracefs.h b/include/tracefs.h index 9477fdb14c5a..5193d46f41f5 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -145,6 +145,14 @@ bool tracefs_option_is_enabled(struct tracefs_instance *instance, enum tracefs_o int tracefs_option_enable(struct tracefs_instance *instance, enum tracefs_option_id id); int tracefs_option_diasble(struct tracefs_instance *instance, enum tracefs_option_id id); const char *tracefs_option_name(enum tracefs_option_id id); + +/* + * RESET - Reset on opening filter file (O_TRUNC) + */ +enum { + TRACEFS_FL_RESET = (1 << 0), +}; + int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, - const char *module, bool reset, const char ***errs); + const char *module, unsigned int flags, const char ***errs); #endif /* _TRACE_FS_H */ diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index 8f2130948fe0..6d03b4856a63 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -835,7 +835,7 @@ static int write_func_list(int fd, struct func_list *list) * @instance: ftrace instance, can be NULL for top tracing instance * @filters: An array of function names ending with a NULL pointer * @module: Module to be traced - * @reset: set to true to reset the file before applying the filter + * @flags: flags on modifying the filter file * @errs: A pointer to array of constant strings that will be allocated * on negative return of this function, pointing to the filters that * failed.May be NULL, in which case this field will be ignored. @@ -843,9 +843,11 @@ static int write_func_list(int fd, struct func_list *list) * The @filters is an array of strings, where each string will be used * to set a function or functions to be traced. * - * If @reset is true, then all functions in the filter are cleared - * before adding functions from @filters. Otherwise, the functions set - * by @filters will be appended to the filter file + * @flags: + * TRACEFS_FL_RESET - will clear the functions in the filter file + * before applying the @filters. This flag is ignored + * if this function is called again when the previous + * call had TRACEFS_FL_CONTINUE set. * * returns -x on filter errors (where x is number of failed filter * srtings) and if @errs is not NULL will be an allocated string array @@ -858,12 +860,13 @@ static int write_func_list(int fd, struct func_list *list) * return 0 on success and @errs is not set. */ int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, - const char *module, bool reset, const char ***errs) + const char *module, unsigned int flags, const char ***errs) { struct func_filter *func_filters; struct func_list *func_list = NULL; char *ftrace_filter_path; - int flags; + bool reset = flags & TRACEFS_FL_RESET; + int open_flags; int ret; int fd; @@ -887,9 +890,9 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt if (!ftrace_filter_path) goto out_free; - flags = reset ? O_TRUNC : O_APPEND; + open_flags = reset ? O_TRUNC : O_APPEND; - fd = open(ftrace_filter_path, O_WRONLY | flags); + fd = open(ftrace_filter_path, O_WRONLY | open_flags); tracefs_put_tracing_file(ftrace_filter_path); if (fd < 0) goto out_free; From patchwork Tue Mar 30 00:51:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171323 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 244A8C433E9 for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F0DC8619A6 for ; Tue, 30 Mar 2021 00:53:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230100AbhC3AxP (ORCPT ); Mon, 29 Mar 2021 20:53:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:57672 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230089AbhC3Awu (ORCPT ); Mon, 29 Mar 2021 20:52:50 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id E679F61987; Tue, 30 Mar 2021 00:52:49 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2ci-003TiL-Us; Mon, 29 Mar 2021 20:52:48 -0400 Message-ID: <20210330005248.836930575@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:34 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 11/13 v2] libtracefs: Add pthread_mutex_lock() around tracefs_function_filter() References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" In order to make tracefs_function_filter() thread safe, add a pthread mutex around the entire function to only let one thread access it at a time. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-tools.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index 6d03b4856a63..7e191e207867 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "tracefs.h" @@ -22,6 +23,8 @@ #define TRACE_FILTER "set_ftrace_filter" #define TRACE_FILTER_LIST "available_filter_functions" +static pthread_mutex_t filter_lock = PTHREAD_MUTEX_INITIALIZER; + static const char * const options_map[] = { "unknown", "annotate", @@ -867,15 +870,16 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt char *ftrace_filter_path; bool reset = flags & TRACEFS_FL_RESET; int open_flags; - int ret; + int ret = 1; int fd; + pthread_mutex_lock(&filter_lock); if (!filters) - return 1; + goto out; func_filters = make_func_filters(filters); if (!func_filters) - return 1; + goto out; /* Make sure errs is NULL to start with, realloc() depends on it. */ if (errs) @@ -906,6 +910,8 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt out_free: free_func_list(func_list); free_func_filters(func_filters); + out: + pthread_mutex_unlock(&filter_lock); return ret; } From patchwork Tue Mar 30 00:51:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171327 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3BAABC433EB for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 16BD56024A for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230209AbhC3AxP (ORCPT ); Mon, 29 Mar 2021 20:53:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:57760 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230100AbhC3Awu (ORCPT ); Mon, 29 Mar 2021 20:52:50 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 13B1D61997; Tue, 30 Mar 2021 00:52:50 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2cj-003Tip-3B; Mon, 29 Mar 2021 20:52:49 -0400 Message-ID: <20210330005248.979418078@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:35 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 12/13 v2] libtracefs: Move struct tracefs_instance to tracefs-local.h References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" In order to have direct access to the tracefs_instance structure for all of the libtracefs internal code, move it to the tracefs-local.h file, then other parts of libtracefs code can use it to store internal data. Signed-off-by: Steven Rostedt (VMware) --- include/tracefs-local.h | 6 ++++++ src/tracefs-instance.c | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/tracefs-local.h b/include/tracefs-local.h index 187870e7c491..9c18218cd916 100644 --- a/include/tracefs-local.h +++ b/include/tracefs-local.h @@ -14,6 +14,12 @@ #define BUILD_BUG_ON(cond) \ do { if (!(1/!(cond))) { } } while (0) +struct tracefs_instance { + char *trace_dir; + char *name; + int flags; +}; + /* Can be overridden */ void warning(const char *fmt, ...); diff --git a/src/tracefs-instance.c b/src/tracefs-instance.c index 0df313c8e8c6..a02c839f2079 100644 --- a/src/tracefs-instance.c +++ b/src/tracefs-instance.c @@ -19,11 +19,6 @@ #include "tracefs-local.h" #define FLAG_INSTANCE_NEWLY_CREATED (1 << 0) -struct tracefs_instance { - char *trace_dir; - char *name; - int flags; -}; /** * instance_alloc - allocate a new ftrace instance From patchwork Tue Mar 30 00:51:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171329 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4B1BEC433EA for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2FE2D6044F for ; Tue, 30 Mar 2021 00:53:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229763AbhC3AxP (ORCPT ); Mon, 29 Mar 2021 20:53:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:57764 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230209AbhC3Awu (ORCPT ); Mon, 29 Mar 2021 20:52:50 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 443876024A; Tue, 30 Mar 2021 00:52:50 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94) (envelope-from ) id 1lR2cj-003TjJ-7h; Mon, 29 Mar 2021 20:52:49 -0400 Message-ID: <20210330005249.118764252@goodmis.org> User-Agent: quilt/0.66 Date: Mon, 29 Mar 2021 20:51:36 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [PATCH 13/13 v2] libtracefs: Add CONTINUE to tracefs_function_filter() References: <20210330005123.151740983@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" Add the TRACEFS_FL_CONTINUE flag to the tracefs_function_filter() API that will allow it to return without closing the set_ftrace_filter file. When the set_ftrace_filter file is closed, all the changes to it take place, but not before hand. In the case that multiple modules need to be set in one activation, the tracefs_function_filter() would need to be called multiple times without closing the file descriptor. Note, the next call to tracefs_function_filter() after it was called with the CONTINUE flag set, the RESET flag is ignored, as the RESET flag only takes effect on opening the file. The next call to tracefs_function_filter() after it was called with the CONTINUE flag (on the same instance) does not reopen the file, and thus will not reset the file. If the file is opened, calling tracefs_function_filter() with no filters and the continue flag not set, will simply close the set_ftrace_filter file. Signed-off-by: Steven Rostedt (VMware) --- Documentation/libtracefs-function-filter.txt | 32 +++++++++++++--- include/tracefs-local.h | 1 + include/tracefs.h | 2 + src/tracefs-instance.c | 2 + src/tracefs-tools.c | 39 ++++++++++++++++---- 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/Documentation/libtracefs-function-filter.txt b/Documentation/libtracefs-function-filter.txt index 5b55a72727c8..1ac8a06961bf 100644 --- a/Documentation/libtracefs-function-filter.txt +++ b/Documentation/libtracefs-function-filter.txt @@ -52,7 +52,20 @@ The _flags_ parameter may have the following set, or be zero. If _flags_ contains *TRACEFS_FL_RESET*, then it will clear the filters that are currently set before applying the list of filters from _filters_. Otherwise, the list of filters from _filters_ will be added to the current set of filters -already enabled. +already enabled. This flag is ignored if a previous call to +tracefs_function_filter() had the same _instance_ and the +*TRACEFS_FL_CONTINUE* flag was set. + +*TRACEFS_FL_CONTINUE* : +If _flags_ contains *TRACEFS_FL_CONTINUE*, then the filters will not take +effect after a successful call to tracefs_function_filter(). This allows for +multiple calls to tracefs_function_filter() to update the filter function. +It can be called multiple times and add more filters. A call without this +flag set will commit the changes before returning (if the filters passed in +successfully matched). A tracefs_function_filter() call after one that had +the *TRACEFS_FL_CONTINUE* flag set for the same instance will ignore the +*TRACEFS_FL_RESET* flag, as the reset flag is only applicable for the first +filters to be added before committing. RETURN VALUE ------------ @@ -70,13 +83,13 @@ EXAMPLE #define INST "dummy" -const char *filters[] = { "run_init_process", "try_to_run_init_process", "dummy1", NULL }; +static const char *filters[] = { "run_init_process", "try_to_run_init_process", "dummy1", NULL }; +static const char *all[] = { "*", NULL }; int main(int argc, char *argv[]) { struct tracefs_instance *inst = tracefs_instance_create(INST); const char **errs = NULL; - int flags = TRACEFS_FL_RESET; int ret; int i = 0; @@ -84,15 +97,24 @@ int main(int argc, char *argv[]) /* Error creating new trace instance */ } - ret = tracefs_function_filter(inst, filters, NULL, flags, &errs); + ret = tracefs_function_filter(inst, filters, NULL, + TRACEFS_FL_RESET | TRACEF_FL_CONTINUE, + &errs); if (ret < 0 && errs) { while (errs[i]) printf("%s\n", errs[i++]); } + free(errs); + + ret = tracefs_function_filter(inst, all, "ext4", 0, &errs); + if (ret < 0) { + printf("Failed to set filters for ext4\n"); + /* Force the function to commit previous filters */ + tracefs_function_filter(inst, NULL, NULL, 0, &errs); + } tracefs_instance_destroy(inst); - free(errs); return 0; } -- diff --git a/include/tracefs-local.h b/include/tracefs-local.h index 9c18218cd916..73ec113fdb20 100644 --- a/include/tracefs-local.h +++ b/include/tracefs-local.h @@ -18,6 +18,7 @@ struct tracefs_instance { char *trace_dir; char *name; int flags; + int ftrace_filter_fd; }; /* Can be overridden */ diff --git a/include/tracefs.h b/include/tracefs.h index 5193d46f41f5..f4775e938f69 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -148,9 +148,11 @@ const char *tracefs_option_name(enum tracefs_option_id id); /* * RESET - Reset on opening filter file (O_TRUNC) + * CONTINUE - Do not close filter file on return. */ enum { TRACEFS_FL_RESET = (1 << 0), + TRACEFS_FL_CONTINUE = (1 << 1), }; int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, diff --git a/src/tracefs-instance.c b/src/tracefs-instance.c index a02c839f2079..bf2fabf111ea 100644 --- a/src/tracefs-instance.c +++ b/src/tracefs-instance.c @@ -43,6 +43,8 @@ static struct tracefs_instance *instance_alloc(const char *trace_dir, const char goto error; } + instance->ftrace_filter_fd = -1; + return instance; error: diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index 7e191e207867..862db5caa20e 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -23,6 +23,8 @@ #define TRACE_FILTER "set_ftrace_filter" #define TRACE_FILTER_LIST "available_filter_functions" +/* File descriptor for Top level set_ftrace_filter */ +static int ftrace_filter_fd = -1; static pthread_mutex_t filter_lock = PTHREAD_MUTEX_INITIALIZER; static const char * const options_map[] = { @@ -851,6 +853,12 @@ static int write_func_list(int fd, struct func_list *list) * before applying the @filters. This flag is ignored * if this function is called again when the previous * call had TRACEFS_FL_CONTINUE set. + * TRACEFS_FL_CONTINUE - will keep the filter file open on return. + * The filter is updated on closing of the filter file. + * With this flag set, the file is not closed, and more filters + * may be added before they take effect. The last call of this + * function must be called without this flag for the filter + * to take effect. * * returns -x on filter errors (where x is number of failed filter * srtings) and if @errs is not NULL will be an allocated string array @@ -869,13 +877,26 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt struct func_list *func_list = NULL; char *ftrace_filter_path; bool reset = flags & TRACEFS_FL_RESET; + bool cont = flags & TRACEFS_FL_CONTINUE; int open_flags; int ret = 1; - int fd; + int *fd; pthread_mutex_lock(&filter_lock); - if (!filters) + if (instance) + fd = &instance->ftrace_filter_fd; + else + fd = &ftrace_filter_fd; + + if (!filters) { + /* OK to call without filters if this is closing the opened file */ + if (!cont && *fd >= 0) { + ret = 0; + close(*fd); + *fd = -1; + } goto out; + } func_filters = make_func_filters(filters); if (!func_filters) @@ -896,16 +917,20 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt open_flags = reset ? O_TRUNC : O_APPEND; - fd = open(ftrace_filter_path, O_WRONLY | open_flags); + if (*fd < 0) + *fd = open(ftrace_filter_path, O_WRONLY | open_flags); tracefs_put_tracing_file(ftrace_filter_path); - if (fd < 0) + if (*fd < 0) goto out_free; - ret = write_func_list(fd, func_list); + ret = write_func_list(*fd, func_list); if (ret > 0) - ret = controlled_write(fd, func_filters, module, errs); + ret = controlled_write(*fd, func_filters, module, errs); - close(fd); + if (!cont) { + close(*fd); + *fd = -1; + } out_free: free_func_list(func_list); From patchwork Tue Mar 30 01:03:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 12171343 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.2 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_SANE_2 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F2E1DC433C1 for ; Tue, 30 Mar 2021 01:03:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A63D361999 for ; Tue, 30 Mar 2021 01:03:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230220AbhC3BDE (ORCPT ); Mon, 29 Mar 2021 21:03:04 -0400 Received: from mail.kernel.org ([198.145.29.99]:58946 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229555AbhC3BDE (ORCPT ); Mon, 29 Mar 2021 21:03:04 -0400 Received: from oasis.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id AB9B861996; Tue, 30 Mar 2021 01:03:03 +0000 (UTC) Date: Mon, 29 Mar 2021 21:03:02 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Sameeruddin shaik Subject: [RFC][PATCH 14/13 v2] libtracefs: Just past one filter in for tracefs_function_filter() Message-ID: <20210329210302.0f7910e3@oasis.local.home> In-Reply-To: <20210330005123.151740983@goodmis.org> References: <20210330005123.151740983@goodmis.org> X-Mailer: Claws Mail 3.17.3 (GTK+ 2.24.33; x86_64-pc-linux-gnu) MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org From: "Steven Rostedt (VMware)" [ Now that we have a way to call tracefs_function_filter() more than once without committing the filter, I think it now makes sense to go back to Tzvetomir's original proposal of calling this function once per filter and not pass in an array. This greatly simplifies the code, and makes the errs parameter obsolete. I played a little with this interface, and I think it makes a lot of sense. Comments? ] With the new CONTINUE flag, it is inconsistent to have an array of filters but only one module. Change the API to pass in a single filter, and remove the errs parameter. Also change the return value to be 0 on success, 1 if it failed before starting to write to the filter file, and -1 if it failed after starting to write to the filter file. Also, set errno appropriately, where if the filter fails EINVAL is set. Signed-off-by: Steven Rostedt (VMware) --- Documentation/libtracefs-function-filter.txt | 105 ++++++---- include/tracefs.h | 4 +- src/tracefs-tools.c | 208 +++++-------------- 3 files changed, 109 insertions(+), 208 deletions(-) diff --git a/Documentation/libtracefs-function-filter.txt b/Documentation/libtracefs-function-filter.txt index 1ac8a06..5631ff7 100644 --- a/Documentation/libtracefs-function-filter.txt +++ b/Documentation/libtracefs-function-filter.txt @@ -11,37 +11,31 @@ SYNOPSIS -- *#include * -int *tracefs_function_filter*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]pass:[*]_filters_, const char pass:[*]_module_, int _flags_, const char pass:[*]pass:[*]pass:[*]_errs_); +int *tracefs_function_filter*(struct tracefs_instance pass:[*]_instance_, const char pass:[*]_filter_, const char pass:[*]_module_, int _flags_); -- DESCRIPTION ----------- -This function can be used to limit the Linux kernel functions that were +This function can be used to limit the Linux kernel functions that would be traced by the function and function-graph tracers -It will take -_instance_ , that can be NULL for the top level tracing. -_filters_, which is an array of the strings that represent a list of filters that should -be applied to define what functions are to be traced and The array must end -with a NULL pointer. -_module_ , name of the module to be traced (or NULL for all functions), +It will take an +_instance_ , that can be NULL for the top level tracing, +_filter_, a string that represents a filter that should +be applied to define what functions are to be traced, +_module_, to limit the filtering on a specific module (or NULL to filter on all functions), _flags_ which holds control knobs on how the filters will be handled (see *FLAGS*) -section below, -_errs_, is a pointer to an array of strings, which will be allocated if -any of filters fail to match any available function, If _errs_ is NULL, it will -be ignored. +section below. -A filter in the array of _filters_ may be either a straight match of a -function, a glob or regex(3). a glob is where 'pass:[*]' matches zero or more +The _filter may be either a straight match of a +function, a glob or regex(3). A glob is where 'pass:[*]' matches zero or more characters, '?' will match zero or one character, and '.' only matches a -period. If the filter is determined to be a regex (where it contains -anything other than alpha numeric characters, or '.', 'pass:[*]', '?') the filter +period. If the _filter_ is determined to be a regex (where it contains +anything other than alpha numeric characters, or '.', 'pass:[*]', '?') the _filter_ will be processed as a regex(3) following the rules of regex(3), and '.' is not a period, but will match any one character. To force a regular -expression, either prefix the filter with a '^' or append it with a '$' as -all filters will act as complete matches of functions anyway. - -returns 0 on success, 1 or -x (where x is an integer) on error. +expression, either prefix _filter_ with a '^' or append it with a '$' as +the _filter_ does complete matches of the functions anyway. FLAGS ----- @@ -50,18 +44,19 @@ The _flags_ parameter may have the following set, or be zero. *TRACEFS_FL_RESET* : If _flags_ contains *TRACEFS_FL_RESET*, then it will clear the filters that -are currently set before applying the list of filters from _filters_. Otherwise, -the list of filters from _filters_ will be added to the current set of filters -already enabled. This flag is ignored if a previous call to -tracefs_function_filter() had the same _instance_ and the +are currently set before applying _filter_. Otherwise, _filter_ is added to +the current set of filters already enabled. This flag is ignored if a +previous call to tracefs_function_filter() had the same _instance_ and the *TRACEFS_FL_CONTINUE* flag was set. *TRACEFS_FL_CONTINUE* : -If _flags_ contains *TRACEFS_FL_CONTINUE*, then the filters will not take +If _flags_ contains *TRACEFS_FL_CONTINUE*, then _filter_ will not take effect after a successful call to tracefs_function_filter(). This allows for -multiple calls to tracefs_function_filter() to update the filter function. -It can be called multiple times and add more filters. A call without this -flag set will commit the changes before returning (if the filters passed in +multiple calls to tracefs_function_filter() to update the filter function +and then a single call (one without the *TRACEFS_FL_CONTINUE* flag set) to +commit all the filters. +It can be called multiple times to add more filters. A call without this +flag set will commit the changes before returning (if the _filter_ passed in successfully matched). A tracefs_function_filter() call after one that had the *TRACEFS_FL_CONTINUE* flag set for the same instance will ignore the *TRACEFS_FL_RESET* flag, as the reset flag is only applicable for the first @@ -69,49 +64,67 @@ filters to be added before committing. RETURN VALUE ------------ -return 0 on success, if there is error, it will return 1 for general errors or -negative number -x(x denotes number of failed filters), if there are any failed filters. +Returns 0 on success. If the there is an error but the filtering was not +started, then 1 is returned. If filtering was started but an error occurs, +then -1 is returned. The state of the filtering may be in an unknown state. + +If *TRACEFS_FL_CONTINUE* was set, and 0 or -1 was returned, then another call +to tracefs_function_filter() must be done without *TRACEFS_FL_CONTINUE* set +in order to commit (and close) the filtering. + +ERRORS +------ -In case of negative return value, errs have to be checked and must be freed -using the free() +*tracefs_function_filter*() can fail with the following errors: + +*EINVAL* The filter is invalid or did not match any functions. + +Other errors may also happen caused by internal system calls. EXAMPLE ------- [source,c] -- +#include +#include #include #define INST "dummy" static const char *filters[] = { "run_init_process", "try_to_run_init_process", "dummy1", NULL }; -static const char *all[] = { "*", NULL }; int main(int argc, char *argv[]) { struct tracefs_instance *inst = tracefs_instance_create(INST); - const char **errs = NULL; int ret; - int i = 0; + int i; if (!inst) { /* Error creating new trace instance */ } - ret = tracefs_function_filter(inst, filters, NULL, - TRACEFS_FL_RESET | TRACEF_FL_CONTINUE, - &errs); - - if (ret < 0 && errs) { - while (errs[i]) - printf("%s\n", errs[i++]); + for (i = 0; filters[i]; i++) { + /* + * Note, only the first call does something + * with TRACEFS_FL_RESET. It is ignored in the following + * calls. + */ + ret = tracefs_function_filter(inst, filters[i], NULL, + TRACEFS_FL_RESET | TRACEFS_FL_CONTINUE); + + if (ret) { + if (errno == EINVAL) + printf("Filter %s did not match\n", filters[i]); + else + printf("Failed writing %s\n", filters[i]); + } } - free(errs); - ret = tracefs_function_filter(inst, all, "ext4", 0, &errs); - if (ret < 0) { + ret = tracefs_function_filter(inst, "*", "ext4", 0); + if (ret) { printf("Failed to set filters for ext4\n"); /* Force the function to commit previous filters */ - tracefs_function_filter(inst, NULL, NULL, 0, &errs); + tracefs_function_filter(inst, NULL, NULL, 0); } tracefs_instance_destroy(inst); diff --git a/include/tracefs.h b/include/tracefs.h index f4775e9..0d98c10 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -155,6 +155,6 @@ enum { TRACEFS_FL_CONTINUE = (1 << 1), }; -int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, - const char *module, unsigned int flags, const char ***errs); +int tracefs_function_filter(struct tracefs_instance *instance, const char *filter, + const char *module, unsigned int flags); #endif /* _TRACE_FS_H */ diff --git a/src/tracefs-tools.c b/src/tracefs-tools.c index 862db5c..165a9db 100644 --- a/src/tracefs-tools.c +++ b/src/tracefs-tools.c @@ -396,33 +396,6 @@ void tracefs_option_clear(struct tracefs_options_mask *options, enum tracefs_opt options->mask &= ~(1ULL << (id - 1)); } -static void add_errors(const char ***errs, const char *filter, int ret) -{ - const char **e; - - if (!errs) - return; - - /* Negative is passed in */ - ret = -ret; - e = *errs; - - /* If this previously failed to allocate stop processing */ - if (!e && ret) - return; - - /* Add 2, one for the new entry, and one for NULL */ - e = realloc(e, sizeof(*e) * (ret + 2)); - if (!e) { - free(*errs); - *errs = NULL; - return; - } - e[ret] = filter; - e[ret + 1] = NULL; - *errs = e; -} - struct func_list { struct func_list *next; unsigned int start; @@ -584,7 +557,7 @@ enum match_type { FILTER_WRITE, }; -static int match_filters(int fd, struct func_filter *func_filters, +static int match_filters(int fd, struct func_filter *func_filter, const char *module, struct func_list **func_list, enum match_type type) { @@ -595,7 +568,6 @@ static int match_filters(int fd, struct func_filter *func_filters, int index = 0; int ret = 1; int mlen; - int i; path = tracefs_get_tracing_file(TRACE_FILTER_LIST); if (!path) @@ -614,7 +586,6 @@ static int match_filters(int fd, struct func_filter *func_filters, char *saveptr = NULL; char *tok, *mtok; int len = strlen(line); - bool first = true; if (line[len - 1] == '\n') line[len - 1] = '\0'; @@ -634,30 +605,16 @@ static int match_filters(int fd, struct func_filter *func_filters, } switch (type) { case FILTER_CHECK: - /* Check, checks a list of filters */ - for (i = 0; func_filters[i].filter; i++) { - /* - * If a match was found, still need to - * check if other filters would match - * to make sure that all filters have a - * match, as some filters may overlap. - */ - if (!first && func_filters[i].set) - continue; - if (match(tok, &func_filters[i])) { - func_filters[i].set = true; - if (first) { - first = false; - ret = add_func(&func_list, index); - if (ret) - goto out; - } - } + if (match(tok, func_filter)) { + func_filter->set = true; + ret = add_func(&func_list, index); + if (ret) + goto out; } break; case FILTER_WRITE: /* Writes only have one filter */ - if (match(tok, func_filters)) { + if (match(tok, func_filter)) { ret = write_filter(fd, tok, module); if (ret) goto out; @@ -676,25 +633,11 @@ static int match_filters(int fd, struct func_filter *func_filters, return ret; } -static int check_available_filters(struct func_filter *func_filters, - const char *module, const char ***errs, +static int check_available_filters(struct func_filter *func_filter, + const char *module, struct func_list **func_list) { - int ret; - int i; - - ret = match_filters(-1, func_filters, module, func_list, FILTER_CHECK); - /* Return here if success or non filter error */ - if (ret >= 0) - return ret; - - /* Failed on filter, set the errors */ - ret = 0; - for (i = 0; func_filters[i].filter; i++) { - if (!func_filters[i].set) - add_errors(errs, func_filters[i].filter, ret--); - } - return ret; + return match_filters(-1, func_filter, module, func_list, FILTER_CHECK); } static int set_regex_filter(int fd, struct func_filter *func_filter, @@ -703,31 +646,17 @@ static int set_regex_filter(int fd, struct func_filter *func_filter, return match_filters(fd, func_filter, module, NULL, FILTER_WRITE); } -static int controlled_write(int fd, struct func_filter *func_filters, - const char *module, const char ***errs) +static int controlled_write(int fd, struct func_filter *func_filter, + const char *module) { - int ret = 0; - int i; + const char *filter = func_filter->filter; + int ret; + + if (func_filter->is_regex) + ret = set_regex_filter(fd, func_filter, module); + else + ret = write_filter(fd, filter, module); - for (i = 0; func_filters[i].filter; i++) { - const char *filter = func_filters[i].filter; - int r; - - if (func_filters[i].is_regex) - r = set_regex_filter(fd, &func_filters[i], module); - else - r = write_filter(fd, filter, module); - if (r > 0) { - /* Not filter error */ - if (errs) { - free(*errs); - *errs = NULL; - } - return 1; - } - if (r < 0) - add_errors(errs, filter, ret--); - } return ret; } @@ -754,43 +683,6 @@ static int init_func_filter(struct func_filter *func_filter, const char *filter) return 0; } -static void free_func_filters(struct func_filter *func_filters) -{ - int i; - - if (!func_filters) - return; - - for (i = 0; func_filters[i].filter; i++) { - regfree(&func_filters[i].re); - } -} - -static struct func_filter *make_func_filters(const char **filters) -{ - struct func_filter *func_filters = NULL; - int i; - - for (i = 0; filters[i]; i++) - ; - - if (!i) - return NULL; - - func_filters = calloc(i + 1, sizeof(*func_filters)); - if (!func_filters) - return NULL; - - for (i = 0; filters[i]; i++) { - if (init_func_filter(&func_filters[i], filters[i]) < 0) - goto out_err; - } - return func_filters; - out_err: - free_func_filters(func_filters); - return NULL; -} - static int write_number(int fd, unsigned int start, unsigned int end) { char buf[64]; @@ -835,22 +727,19 @@ static int write_func_list(int fd, struct func_list *list) } /** - * tracefs_function_filter - write to set_ftrace_filter file to trace - * particular functions - * @instance: ftrace instance, can be NULL for top tracing instance - * @filters: An array of function names ending with a NULL pointer - * @module: Module to be traced + * tracefs_function_filter - filter the functions that are traced + * @instance: ftrace instance, can be NULL for top tracing instance. + * @filter: The filter to filter what functions are to be traced + * @module: Module to be traced or NULL if all functions are to be examined. * @flags: flags on modifying the filter file - * @errs: A pointer to array of constant strings that will be allocated - * on negative return of this function, pointing to the filters that - * failed.May be NULL, in which case this field will be ignored. * - * The @filters is an array of strings, where each string will be used - * to set a function or functions to be traced. + * @filter may be a full function name, a glob, or a regex. It will be + * considered a regex, if there's any characters that are not normally in + * function names or "*" or "?" for a glob. * * @flags: * TRACEFS_FL_RESET - will clear the functions in the filter file - * before applying the @filters. This flag is ignored + * before applying the @filter. This flag is ignored * if this function is called again when the previous * call had TRACEFS_FL_CONTINUE set. * TRACEFS_FL_CONTINUE - will keep the filter file open on return. @@ -860,20 +749,16 @@ static int write_func_list(int fd, struct func_list *list) * function must be called without this flag for the filter * to take effect. * - * returns -x on filter errors (where x is number of failed filter - * srtings) and if @errs is not NULL will be an allocated string array - * pointing to the strings in @filters that failed and must be freed - * with free(). - * - * returns 1 on general errors not realted to setting the filter. - * @errs is not set even if supplied. - * - * return 0 on success and @errs is not set. + * Returns 0 on success, 1 if there was an error but the filtering has not + * yet started, -1 if there was an error but the filtering has started. + * If -1 is returned and TRACEFS_FL_CONTINUE was set, then this function + * needs to be called again without the TRACEFS_FL_CONTINUE flag to commit + * the changes and close the filter file. */ -int tracefs_function_filter(struct tracefs_instance *instance, const char **filters, - const char *module, unsigned int flags, const char ***errs) +int tracefs_function_filter(struct tracefs_instance *instance, const char *filter, + const char *module, unsigned int flags) { - struct func_filter *func_filters; + struct func_filter func_filter; struct func_list *func_list = NULL; char *ftrace_filter_path; bool reset = flags & TRACEFS_FL_RESET; @@ -888,9 +773,16 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt else fd = &ftrace_filter_fd; - if (!filters) { + /* + * Set EINVAL on no matching filter. But errno may still be modified + * on another type of failure (allocation or opening a file). + */ + errno = EINVAL; + + if (!filter) { /* OK to call without filters if this is closing the opened file */ if (!cont && *fd >= 0) { + errno = 0; ret = 0; close(*fd); *fd = -1; @@ -898,15 +790,10 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt goto out; } - func_filters = make_func_filters(filters); - if (!func_filters) + if (init_func_filter(&func_filter, filter) < 0) goto out; - /* Make sure errs is NULL to start with, realloc() depends on it. */ - if (errs) - *errs = NULL; - - ret = check_available_filters(func_filters, module, errs, &func_list); + ret = check_available_filters(&func_filter, module, &func_list); if (ret) goto out_free; @@ -923,9 +810,11 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt if (*fd < 0) goto out_free; + errno = 0; + ret = write_func_list(*fd, func_list); if (ret > 0) - ret = controlled_write(*fd, func_filters, module, errs); + ret = controlled_write(*fd, &func_filter, module); if (!cont) { close(*fd); @@ -934,7 +823,6 @@ int tracefs_function_filter(struct tracefs_instance *instance, const char **filt out_free: free_func_list(func_list); - free_func_filters(func_filters); out: pthread_mutex_unlock(&filter_lock);