Support tracing of processes under cgroup path
authorChethan Suresh <Chethan.Suresh@sony.com>
Fri, 10 Dec 2021 04:47:59 +0000 (10:17 +0530)
committeryonghong-song <ys114321@gmail.com>
Sat, 11 Dec 2021 18:56:08 +0000 (10:56 -0800)
- Using bpf_current_task_under_cgroup() we can check whether the probe
  is being run in the context of a given subset of the cgroup2 hierarchy.
- Support cgroup path '-c' args to get the cgroup2 path
  and filter based on the cgroup2 path fd using bpf_current_task_under_cgroup()

Signed-off-by: Chethan Suresh <Chethan.Suresh@sony.com>
libbpf-tools/biolatency.bpf.c
libbpf-tools/biolatency.c
libbpf-tools/biosnoop.bpf.c
libbpf-tools/biosnoop.c

index 8d8fe584d431d33002457b4aae88f4c06f1f58d0..91e21c3ebaa3ea1e4080cf2ed790e0c30faeb70e 100644 (file)
 
 extern int LINUX_KERNEL_VERSION __kconfig;
 
+const volatile bool filter_cg = false;
 const volatile bool targ_per_disk = false;
 const volatile bool targ_per_flag = false;
 const volatile bool targ_queued = false;
 const volatile bool targ_ms = false;
 const volatile dev_t targ_dev = -1;
 
+struct {
+       __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
+       __type(key, u32);
+       __type(value, u32);
+       __uint(max_entries, 1);
+} cgroup_map SEC(".maps");
+
 struct {
        __uint(type, BPF_MAP_TYPE_HASH);
        __uint(max_entries, MAX_ENTRIES);
@@ -59,6 +67,9 @@ int trace_rq_start(struct request *rq, int issue)
 SEC("tp_btf/block_rq_insert")
 int block_rq_insert(u64 *ctx)
 {
+       if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
+               return 0;
+
        /**
         * commit a54895fa (v5.11-rc1) changed tracepoint argument list
         * from TP_PROTO(struct request_queue *q, struct request *rq)
@@ -73,6 +84,9 @@ int block_rq_insert(u64 *ctx)
 SEC("tp_btf/block_rq_issue")
 int block_rq_issue(u64 *ctx)
 {
+       if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
+               return 0;
+
        /**
         * commit a54895fa (v5.11-rc1) changed tracepoint argument list
         * from TP_PROTO(struct request_queue *q, struct request *rq)
@@ -88,6 +102,9 @@ SEC("tp_btf/block_rq_complete")
 int BPF_PROG(block_rq_complete, struct request *rq, int error,
        unsigned int nr_bytes)
 {
+       if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
+               return 0;
+
        u64 slot, *tsp, ts = bpf_ktime_get_ns();
        struct hist_key hkey = {};
        struct hist *histp;
index a09ebf29e3b3eccb84ae49d2aed1d20612d7c953..ab309a67e24997333d608950a5688b3873829a6a 100644 (file)
@@ -7,6 +7,7 @@
 #include <signal.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <time.h>
 #include <bpf/libbpf.h>
 #include <sys/resource.h>
@@ -28,6 +29,8 @@ static struct env {
        bool per_flag;
        bool milliseconds;
        bool verbose;
+       char *cgroupspath;
+       bool cg;
 } env = {
        .interval = 99999999,
        .times = 99999999,
@@ -41,7 +44,7 @@ const char *argp_program_bug_address =
 const char argp_program_doc[] =
 "Summarize block device I/O latency as a histogram.\n"
 "\n"
-"USAGE: biolatency [--help] [-T] [-m] [-Q] [-D] [-F] [-d DISK] [interval] [count]\n"
+"USAGE: biolatency [--help] [-T] [-m] [-Q] [-D] [-F] [-d DISK] [-c CG] [interval] [count]\n"
 "\n"
 "EXAMPLES:\n"
 "    biolatency              # summarize block I/O latency as a histogram\n"
@@ -50,7 +53,8 @@ const char argp_program_doc[] =
 "    biolatency -Q           # include OS queued time in I/O time\n"
 "    biolatency -D           # show each disk device separately\n"
 "    biolatency -F           # show I/O flags separately\n"
-"    biolatency -d sdc       # Trace sdc only\n";
+"    biolatency -d sdc       # Trace sdc only\n"
+"    biolatency -c CG        # Trace process under cgroupsPath CG\n";
 
 static const struct argp_option opts[] = {
        { "timestamp", 'T', NULL, 0, "Include timestamp on output" },
@@ -60,6 +64,7 @@ static const struct argp_option opts[] = {
        { "flag", 'F', NULL, 0, "Print a histogram per set of I/O flags" },
        { "disk",  'd', "DISK",  0, "Trace this disk only" },
        { "verbose", 'v', NULL, 0, "Verbose debug output" },
+       { "cgroup", 'c', "/sys/fs/cgroup/unified", 0, "Trace process in cgroup path"},
        { NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
        {},
 };
@@ -90,6 +95,10 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
        case 'T':
                env.timestamp = true;
                break;
+       case 'c':
+               env.cgroupspath = arg;
+               env.cg = true;
+               break;
        case 'd':
                env.disk = arg;
                if (strlen(arg) + 1 > DISK_NAME_LEN) {
@@ -240,6 +249,8 @@ int main(int argc, char **argv)
        char ts[32];
        time_t t;
        int err;
+       int idx, cg_map_fd;
+       int cgfd = -1;
 
        err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
        if (err)
@@ -278,6 +289,7 @@ int main(int argc, char **argv)
        obj->rodata->targ_per_flag = env.per_flag;
        obj->rodata->targ_ms = env.milliseconds;
        obj->rodata->targ_queued = env.queued;
+       obj->rodata->filter_cg = env.cg;
 
        err = biolatency_bpf__load(obj);
        if (err) {
@@ -285,6 +297,21 @@ int main(int argc, char **argv)
                goto cleanup;
        }
 
+       /* update cgroup path fd to map */
+       if (env.cg) {
+               idx = 0;
+               cg_map_fd = bpf_map__fd(obj->maps.cgroup_map);
+               cgfd = open(env.cgroupspath, O_RDONLY);
+               if (cgfd < 0) {
+                       fprintf(stderr, "Failed opening Cgroup path: %s", env.cgroupspath);
+                       goto cleanup;
+               }
+               if (bpf_map_update_elem(cg_map_fd, &idx, &cgfd, BPF_ANY)) {
+                       fprintf(stderr, "Failed adding target cgroup to map");
+                       goto cleanup;
+               }
+       }
+
        if (env.queued) {
                obj->links.block_rq_insert =
                        bpf_program__attach(obj->progs.block_rq_insert);
@@ -336,6 +363,8 @@ int main(int argc, char **argv)
 cleanup:
        biolatency_bpf__destroy(obj);
        partitions__free(partitions);
+       if (cgfd > 0)
+               close(cgfd);
 
        return err != 0;
 }
index 1c340357fb30815c30616b739b55c5e1347916e4..3fb7403f9d727d9d88aea0a6f70b66e052d62287 100644 (file)
@@ -8,11 +8,19 @@
 
 #define MAX_ENTRIES    10240
 
+const volatile bool filter_cg = false;
 const volatile bool targ_queued = false;
 const volatile dev_t targ_dev = -1;
 
 extern __u32 LINUX_KERNEL_VERSION __kconfig;
 
+struct {
+       __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
+       __type(key, u32);
+       __type(value, u32);
+       __uint(max_entries, 1);
+} cgroup_map SEC(".maps");
+
 struct piddata {
        char comm[TASK_COMM_LEN];
        u32 pid;
@@ -60,12 +68,18 @@ int trace_pid(struct request *rq)
 SEC("fentry/blk_account_io_start")
 int BPF_PROG(blk_account_io_start, struct request *rq)
 {
+       if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
+               return 0;
+
        return trace_pid(rq);
 }
 
 SEC("kprobe/blk_account_io_merge_bio")
 int BPF_KPROBE(blk_account_io_merge_bio, struct request *rq)
 {
+       if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
+               return 0;
+
        return trace_pid(rq);
 }
 
@@ -97,6 +111,9 @@ int trace_rq_start(struct request *rq, bool insert)
 SEC("tp_btf/block_rq_insert")
 int BPF_PROG(block_rq_insert)
 {
+       if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
+               return 0;
+
        /**
         * commit a54895fa (v5.11-rc1) changed tracepoint argument list
         * from TP_PROTO(struct request_queue *q, struct request *rq)
@@ -111,6 +128,9 @@ int BPF_PROG(block_rq_insert)
 SEC("tp_btf/block_rq_issue")
 int BPF_PROG(block_rq_issue)
 {
+       if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
+               return 0;
+
        /**
         * commit a54895fa (v5.11-rc1) changed tracepoint argument list
         * from TP_PROTO(struct request_queue *q, struct request *rq)
@@ -126,6 +146,9 @@ SEC("tp_btf/block_rq_complete")
 int BPF_PROG(block_rq_complete, struct request *rq, int error,
             unsigned int nr_bytes)
 {
+       if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
+               return 0;
+
        u64 ts = bpf_ktime_get_ns();
        struct piddata *piddatap;
        struct event event = {};
index e0f00693a48638724284b0078887208e30024439..bbca68ce0ccebba31efd088d7e96162c58458f60 100644 (file)
@@ -11,6 +11,7 @@
 #include <bpf/libbpf.h>
 #include <sys/resource.h>
 #include <bpf/bpf.h>
+#include <fcntl.h>
 #include "blk_types.h"
 #include "biosnoop.h"
 #include "biosnoop.skel.h"
@@ -27,6 +28,8 @@ static struct env {
        bool timestamp;
        bool queued;
        bool verbose;
+       char *cgroupspath;
+       bool cg;
 } env = {};
 
 static volatile __u64 start_ts;
@@ -37,18 +40,20 @@ const char *argp_program_bug_address =
 const char argp_program_doc[] =
 "Trace block I/O.\n"
 "\n"
-"USAGE: biosnoop [--help] [-d DISK] [-Q]\n"
+"USAGE: biosnoop [--help] [-d DISK] [-c CG] [-Q]\n"
 "\n"
 "EXAMPLES:\n"
 "    biosnoop              # trace all block I/O\n"
 "    biosnoop -Q           # include OS queued time in I/O time\n"
 "    biosnoop 10           # trace for 10 seconds only\n"
-"    biosnoop -d sdc       # trace sdc only\n";
+"    biosnoop -d sdc       # trace sdc only\n"
+"    biosnoop -c CG        # Trace process under cgroupsPath CG\n";
 
 static const struct argp_option opts[] = {
        { "queued", 'Q', NULL, 0, "Include OS queued time in I/O time" },
        { "disk",  'd', "DISK",  0, "Trace this disk only" },
        { "verbose", 'v', NULL, 0, "Verbose debug output" },
+       { "cgroup", 'c', "/sys/fs/cgroup/unified/CG", 0, "Trace process in cgroup path"},
        { NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
        {},
 };
@@ -67,6 +72,10 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
        case 'Q':
                env.queued = true;
                break;
+       case 'c':
+               env.cg = true;
+               env.cgroupspath = arg;
+               break;
        case 'd':
                env.disk = arg;
                if (strlen(arg) + 1 > DISK_NAME_LEN) {
@@ -188,6 +197,8 @@ int main(int argc, char **argv)
        struct biosnoop_bpf *obj;
        __u64 time_end = 0;
        int err;
+       int idx, cg_map_fd;
+       int cgfd = -1;
 
        err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
        if (err)
@@ -222,6 +233,7 @@ int main(int argc, char **argv)
                }
        }
        obj->rodata->targ_queued = env.queued;
+       obj->rodata->filter_cg = env.cg;
 
        err = biosnoop_bpf__load(obj);
        if (err) {
@@ -229,6 +241,21 @@ int main(int argc, char **argv)
                goto cleanup;
        }
 
+       /* update cgroup path fd to map */
+       if (env.cg) {
+               idx = 0;
+               cg_map_fd = bpf_map__fd(obj->maps.cgroup_map);
+               cgfd = open(env.cgroupspath, O_RDONLY);
+               if (cgfd < 0) {
+                       fprintf(stderr, "Failed opening Cgroup path: %s\n", env.cgroupspath);
+                       goto cleanup;
+               }
+               if (bpf_map_update_elem(cg_map_fd, &idx, &cgfd, BPF_ANY)) {
+                       fprintf(stderr, "Failed adding target cgroup to map\n");
+                       goto cleanup;
+               }
+       }
+
        obj->links.blk_account_io_start =
                bpf_program__attach(obj->progs.blk_account_io_start);
        err = libbpf_get_error(obj->links.blk_account_io_start);
@@ -325,6 +352,8 @@ cleanup:
        biosnoop_bpf__destroy(obj);
        ksyms__free(ksyms);
        partitions__free(partitions);
+       if (cgfd > 0)
+               close(cgfd);
 
        return err != 0;
 }