Use glob_match() to support flexible glob wildcards (*,?)
and character classes ([) for ftrace.
Since the full glob matching is slower than the current
partial matching routines(*pat, pat*, *pat*), this leaves
those routines and just add MATCH_GLOB for complex glob
expression.
e.g.
----
[root@localhost tracing]# echo 'sched*group' > set_ftrace_filter
[root@localhost tracing]# cat set_ftrace_filter
sched_free_group
sched_change_group
sched_create_group
sched_online_group
sched_destroy_group
sched_offline_group
[root@localhost tracing]# echo '[Ss]y[Ss]_*' > set_ftrace_filter
[root@localhost tracing]# head set_ftrace_filter
sys_arch_prctl
sys_rt_sigreturn
sys_ioperm
SyS_iopl
sys_modify_ldt
SyS_mmap
SyS_set_thread_area
SyS_get_thread_area
SyS_set_tid_address
sys_fork
----
Link: http://lkml.kernel.org/r/147566869501.29136.6462645009894738056.stgit@devbox
Acked-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
 
 ==, !=, ~
 
-The glob (~) only accepts a wild card character (*) at the start and or
-end of the string. For example:
+The glob (~) accepts a wild card character (*,?) and character classes
+([). For example:
 
   prev_comm ~ "*sh"
   prev_comm ~ "sh*"
   prev_comm ~ "*sh*"
-
-But does not allow for it to be within the string:
-
-  prev_comm ~ "ba*sh"   <-- is invalid
+  prev_comm ~ "ba*sh"
 
 5.2 Setting filters
 -------------------
 
 sys_nanosleep
 
 
-Perhaps this is not enough. The filters also allow simple wild
-cards. Only the following are currently available
+Perhaps this is not enough. The filters also allow glob(7) matching.
 
   <match>*  - will match functions that begin with <match>
   *<match>  - will match functions that end with <match>
   *<match>* - will match functions that have <match> in it
-
-These are the only wild cards which are supported.
-
-  <match>*<match> will not work.
+  <match1>*<match2> - will match functions that begin with
+                      <match1> and end with <match2>
 
 Note: It is better to use quotes to enclose the wild cards,
       otherwise the shell may expand the parameters into names
 
 
 config EVENT_TRACING
        select CONTEXT_SWITCH_TRACER
+        select GLOB
        bool
 
 config CONTEXT_SWITCH_TRACER
        select KALLSYMS
        select GENERIC_TRACER
        select CONTEXT_SWITCH_TRACER
+        select GLOB
        help
          Enable the kernel to trace every kernel function. This is done
          by using a compiler feature to insert a small, 5-byte No-Operation
 
                    memcmp(str + slen - g->len, g->search, g->len) == 0)
                        matched = 1;
                break;
+       case MATCH_GLOB:
+               if (glob_match(g->search, str))
+                       matched = 1;
+               break;
        }
 
        return matched;
 
        "\n  available_filter_functions - list of functions that can be filtered on\n"
        "  set_ftrace_filter\t- echo function name in here to only trace these\n"
        "\t\t\t  functions\n"
-       "\t     accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
+       "\t     accepts: func_full_name or glob-matching-pattern\n"
        "\t     modules: Can select a group via module\n"
        "\t      Format: :mod:<module-name>\n"
        "\t     example: echo :mod:ext3 > set_ftrace_filter\n"
 
 #include <linux/trace_events.h>
 #include <linux/compiler.h>
 #include <linux/trace_seq.h>
+#include <linux/glob.h>
 
 #ifdef CONFIG_FTRACE_SYSCALLS
 #include <asm/unistd.h>                /* For NR_SYSCALLS           */
        MATCH_FRONT_ONLY,
        MATCH_MIDDLE_ONLY,
        MATCH_END_ONLY,
+       MATCH_GLOB,
 };
 
 struct regex {
 
        return 0;
 }
 
+static int regex_match_glob(char *str, struct regex *r, int len __maybe_unused)
+{
+       if (glob_match(r->pattern, str))
+               return 1;
+       return 0;
+}
 /**
  * filter_parse_regex - parse a basic regex
  * @buff:   the raw regex
                        if (!i) {
                                *search = buff + 1;
                                type = MATCH_END_ONLY;
-                       } else {
+                       } else if (i == len - 1) {
                                if (type == MATCH_END_ONLY)
                                        type = MATCH_MIDDLE_ONLY;
                                else
                                        type = MATCH_FRONT_ONLY;
                                buff[i] = 0;
                                break;
+                       } else {        /* pattern continues, use full glob */
+                               type = MATCH_GLOB;
+                               break;
                        }
+               } else if (strchr("[?\\", buff[i])) {
+                       type = MATCH_GLOB;
+                       break;
                }
        }
 
        case MATCH_END_ONLY:
                r->match = regex_match_end;
                break;
+       case MATCH_GLOB:
+               r->match = regex_match_glob;
+               break;
        }
 
        pred->not ^= not;