This v2 addresses the TODO in trace_fprobe to handle comma-separated
symbol lists and the '!' prefix. Tokens starting with '!' are collected
as "nofilter", and the others as "filter", then passed to
register_fprobe() accordingly. Empty tokens are rejected and errors are
reported with trace_probe_log_err().

Questions for maintainers (to confirm my understanding):
  * Parsing location: Masami suggested doing the parsing in the parse
    stage (e.g., via parse_symbol_and_return()). v2 keeps the logic in
    __register_trace_fprobe(), but I can move the call into the parsing
    path in v3 if that is the preferred place. Is that correct?
  * Documentation: I plan to update the user-facing docs for fprobe
    syntax. Is Documentation/trace/ the right place (e.g., 
    Documentation/trace/fprobetrace.rst)?

Link: 
https://lore.kernel.org/linux-trace-kernel/[email protected]/
Signed-off-by: Ryan Chung <[email protected]>
---

Changes in v2:
  * Classify '!' tokens as nofilter, others as filter; pass both to
    register_fprobe().
  * Reject empty tokens; log errors with trace_probe_log_*().
  * Use __free(kfree) for temporary buffers.
  * Keep subject and style per "Submitting patches" (tabs, wrapping).
  * No manual dedup (leave to ftrace).

 kernel/trace/trace_fprobe.c | 48 +++++++++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c
index b36ade43d4b3..d731d9754a39 100644
--- a/kernel/trace/trace_fprobe.c
+++ b/kernel/trace/trace_fprobe.c
@@ -815,6 +815,11 @@ static int trace_fprobe_verify_target(struct trace_fprobe 
*tf)
 static int __register_trace_fprobe(struct trace_fprobe *tf)
 {
        int i, ret;
+       const char *p, *q;
+       size_t spec_len, flen = 0, nflen = 0, tlen;
+       bool have_f = false, have_nf = false;
+       char *filter __free(kfree) = NULL;
+       char *nofilter __free(kfree) = NULL;
 
        /* Should we need new LOCKDOWN flag for fprobe? */
        ret = security_locked_down(LOCKDOWN_KPROBES);
@@ -835,8 +840,47 @@ static int __register_trace_fprobe(struct trace_fprobe *tf)
        if (trace_fprobe_is_tracepoint(tf))
                return __regsiter_tracepoint_fprobe(tf);
 
-       /* TODO: handle filter, nofilter or symbol list */
-       return register_fprobe(&tf->fp, tf->symbol, NULL);
+       spec_len = strlen(tf->symbol);
+       filter = kzalloc(spec_len + 1, GFP_KERNEL);
+       nofilter = kzalloc(spec_len + 1, GFP_KERNEL);
+       if (!filter || !nofilter)
+               return -ENOMEM;
+
+       p = tf->symbol;
+       for (p = tf->symbol; p; p = q ? q + 1 : NULL) {
+               q = strchr(p, ',');
+               tlen = q ? (size_t)(q-p) : strlen(p);
+
+               /* reject empty token */
+               if (!tlen) {
+                       trace_probe_log_set_index(1);
+                       trace_probe_log_err(0, BAD_TP_NAME);
+                       return -EINVAL;
+               }
+
+               if (*p == '!') {
+                       if (tlen == 1) {
+                               trace_probe_log_set_index(1);
+                               trace_probe_log_err(0, BAD_TP_NAME);
+                               return -EINVAL;
+                       }
+                       if (have_nf)
+                               nofilter[nflen++] = ',';
+                       memcpy(nofilter + nflen, p + 1, tlen - 1);
+                       nflen += tlen - 1;
+                       have_nf = true;
+               } else {
+                       if (have_f)
+                               filter[flen++] = ',';
+                       memcpy(filter + flen, p, tlen);
+                       flen += tlen;
+                       have_f = true;
+               }
+       }
+
+       return register_fprobe(&tf->fp,
+                       have_f ? filter : NULL,
+                       have_nf ? nofilter : NULL);
 }
 
 /* Internal unregister function - just handle fprobe and flags */
-- 
2.43.0


Reply via email to