diff --git a/.bcc.metadata b/.bcc.metadata new file mode 100644 index 0000000..0e97130 --- /dev/null +++ b/.bcc.metadata @@ -0,0 +1 @@ +70e35f9ad5989dfeab4c0e87b98602e78493a730 SOURCES/bcc-0.10.0.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f367d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/bcc-0.10.0.tar.gz diff --git a/SOURCES/Fix-tools-for-RHEL-7.patch b/SOURCES/Fix-tools-for-RHEL-7.patch new file mode 100644 index 0000000..f6c8362 --- /dev/null +++ b/SOURCES/Fix-tools-for-RHEL-7.patch @@ -0,0 +1,594 @@ +From 5848b9fe9ad49151492cb2652a06921fa4b49031 Mon Sep 17 00:00:00 2001 +From: Jerome Marchand +Date: Thu, 16 Aug 2018 14:58:56 +0200 +Subject: [PATCH] Fix tools for RHEL 7 + +There some differences on RHEL 7 that make some tools fail. This patch +fixes the following: + - missing /sys/kernel/debug/kprobes/blacklist file + - missing __vfs_read() function + - aio_read/write methods replaced by read/write_iter in file_operations + - changes in mnt_namespace structure + - change in finish_task_switch() argument list + - changes in sock_common struct + - missing TCP_NEW_SYN_RECV TCP state + - mm_page_alloc tracepoint returns page struct instead of PFN + - iocb argument removed from tcp_sendmsg() +--- + src/python/bcc/__init__.py | 7 +++++-- + tools/btrfsdist.py | 13 +++++++------ + tools/btrfsslower.py | 13 +++++++------ + tools/cpudist.py | 4 +++- + tools/ext4dist.py | 11 ++++++----- + tools/ext4slower.py | 13 +++++++------ + tools/fileslower.py | 13 +++++++++---- + tools/memleak.py | 12 ++++++++++-- + tools/mountsnoop.py | 9 ++++----- + tools/nfsslower.py | 1 + + tools/offcputime.py | 4 +++- + tools/offwaketime.py | 4 +++- + tools/oomkill.py | 8 ++++---- + tools/runqlat.py | 2 +- + tools/runqslower.py | 2 +- + tools/solisten.py | 2 +- + tools/tcpsubnet.py | 4 ++-- + tools/tcptracer.py | 9 ++++----- + tools/xfsdist.py | 8 ++++---- + tools/xfsslower.py | 11 ++++++----- + 20 files changed, 88 insertions(+), 62 deletions(-) + +diff --git a/src/python/bcc/__init__.py b/src/python/bcc/__init__.py +index bff5f282..19933cf7 100644 +--- a/src/python/bcc/__init__.py ++++ b/src/python/bcc/__init__.py +@@ -525,8 +525,11 @@ DEBUG_BTF = 0x20 + + @staticmethod + def get_kprobe_functions(event_re): +- with open("%s/../kprobes/blacklist" % TRACEFS, "rb") as blacklist_f: +- blacklist = set([line.rstrip().split()[1] for line in blacklist_f]) ++ try: ++ with open("%s/../kprobes/blacklist" % TRACEFS, "rb") as blacklist_f: ++ blacklist = set([line.rstrip().split()[1] for line in blacklist_f]) ++ except: ++ blacklist = set() + fns = [] + + in_init_section = 0 +diff --git a/tools/btrfsdist.py b/tools/btrfsdist.py +index 4659ab46..3326b67a 100755 +--- a/tools/btrfsdist.py ++++ b/tools/btrfsdist.py +@@ -60,6 +60,7 @@ debug = 0 + bpf_text = """ + #include + #include ++#include + #include + + #define OP_NAME_LEN 8 +@@ -81,7 +82,7 @@ int trace_entry(struct pt_regs *ctx) + return 0; + } + +-// The current btrfs (Linux 4.5) uses generic_file_read_iter() instead of it's ++// btrfs uses generic_file_aio_read() instead of it's + // own read function. So we need to trace that and then filter on btrfs, which + // I do by checking file->f_op. + int trace_read_entry(struct pt_regs *ctx, struct kiocb *iocb) +@@ -193,13 +194,13 @@ bpf_text = bpf_text.replace('FACTOR', str(factor)) + # load BPF program + b = BPF(text=bpf_text) + +-# Common file functions. See earlier comment about generic_file_read_iter(). +-b.attach_kprobe(event="generic_file_read_iter", fn_name="trace_read_entry") +-b.attach_kprobe(event="btrfs_file_write_iter", fn_name="trace_entry") ++# Common file functions. See earlier comment about generic_file_aio_read(). ++b.attach_kprobe(event="generic_file_aio_read", fn_name="trace_read_entry") ++b.attach_kprobe(event="btrfs_file_aio_write", fn_name="trace_entry") + b.attach_kprobe(event="generic_file_open", fn_name="trace_open_entry") + b.attach_kprobe(event="btrfs_sync_file", fn_name="trace_entry") +-b.attach_kretprobe(event="generic_file_read_iter", fn_name="trace_read_return") +-b.attach_kretprobe(event="btrfs_file_write_iter", fn_name="trace_write_return") ++b.attach_kretprobe(event="generic_file_aio_read", fn_name="trace_read_return") ++b.attach_kretprobe(event="btrfs_file_aio_write", fn_name="trace_write_return") + b.attach_kretprobe(event="generic_file_open", fn_name="trace_open_return") + b.attach_kretprobe(event="btrfs_sync_file", fn_name="trace_fsync_return") + +diff --git a/tools/btrfsslower.py b/tools/btrfsslower.py +index bacbc06a..b650cea0 100755 +--- a/tools/btrfsslower.py ++++ b/tools/btrfsslower.py +@@ -62,6 +62,7 @@ debug = 0 + bpf_text = """ + #include + #include ++#include + #include + #include + +@@ -96,7 +97,7 @@ BPF_PERF_OUTPUT(events); + // Store timestamp and size on entry + // + +-// The current btrfs (Linux 4.5) uses generic_file_read_iter() instead of it's ++// btrfs uses generic_file_aio_read() instead of it's + // own read function. So we need to trace that and then filter on btrfs, which + // I do by checking file->f_op. + int trace_read_entry(struct pt_regs *ctx, struct kiocb *iocb) +@@ -123,7 +124,7 @@ int trace_read_entry(struct pt_regs *ctx, struct kiocb *iocb) + return 0; + } + +-// btrfs_file_write_iter(): ++// btrfs_file_aio_write(): + int trace_write_entry(struct pt_regs *ctx, struct kiocb *iocb) + { + u64 id = bpf_get_current_pid_tgid(); +@@ -313,12 +314,12 @@ int trace_fsync_return(struct pt_regs *ctx) + b = BPF(text=bpf_text) + + # Common file functions. See earlier comment about generic_*(). +-b.attach_kprobe(event="generic_file_read_iter", fn_name="trace_read_entry") +-b.attach_kprobe(event="btrfs_file_write_iter", fn_name="trace_write_entry") ++b.attach_kprobe(event="generic_file_aio_read", fn_name="trace_read_entry") ++b.attach_kprobe(event="btrfs_file_aio_write", fn_name="trace_write_entry") + b.attach_kprobe(event="generic_file_open", fn_name="trace_open_entry") + b.attach_kprobe(event="btrfs_sync_file", fn_name="trace_fsync_entry") +-b.attach_kretprobe(event="generic_file_read_iter", fn_name="trace_read_return") +-b.attach_kretprobe(event="btrfs_file_write_iter", fn_name="trace_write_return") ++b.attach_kretprobe(event="generic_file_aio_read", fn_name="trace_read_return") ++b.attach_kretprobe(event="btrfs_file_aio_write", fn_name="trace_write_return") + b.attach_kretprobe(event="generic_file_open", fn_name="trace_open_return") + b.attach_kretprobe(event="btrfs_sync_file", fn_name="trace_fsync_return") + +diff --git a/tools/cpudist.py b/tools/cpudist.py +index 4d7c9eb4..ddb675e2 100755 +--- a/tools/cpudist.py ++++ b/tools/cpudist.py +@@ -94,7 +94,9 @@ static inline void update_hist(u32 tgid, u32 pid, u64 ts) + STORE + } + +-int sched_switch(struct pt_regs *ctx, struct task_struct *prev) ++struct rq; ++ ++int sched_switch(struct pt_regs *ctx, struct rq *rq, struct task_struct *prev) + { + u64 ts = bpf_ktime_get_ns(); + u64 pid_tgid = bpf_get_current_pid_tgid(); +diff --git a/tools/ext4dist.py b/tools/ext4dist.py +index 384a4c14..559e4a5f 100755 +--- a/tools/ext4dist.py ++++ b/tools/ext4dist.py +@@ -60,6 +60,7 @@ debug = 0 + bpf_text = """ + #include + #include ++#include + #include + + #define OP_NAME_LEN 8 +@@ -136,18 +137,18 @@ int trace_fsync_return(struct pt_regs *ctx) + """ + + # Starting from Linux 4.10 ext4_file_operations.read_iter has been changed from +-# using generic_file_read_iter() to its own ext4_file_read_iter(). ++# using generic_file_aio_read() to its own ext4_file_read_iter(). + # + # To detect the proper function to trace check if ext4_file_read_iter() is + # defined in /proc/kallsyms, if it's defined attach to that function, otherwise +-# use generic_file_read_iter() and inside the trace hook filter on ext4 read ++# use generic_file_aio_read() and inside the trace hook filter on ext4 read + # events (checking if file->f_op == ext4_file_operations). + if BPF.get_kprobe_functions(b'ext4_file_read_iter'): + ext4_read_fn = 'ext4_file_read_iter' + ext4_trace_read_fn = 'trace_entry' + ext4_trace_read_code = '' + else: +- ext4_read_fn = 'generic_file_read_iter' ++ ext4_read_fn = 'generic_file_aio_read' + ext4_trace_read_fn = 'trace_read_entry' + ext4_file_ops_addr = '' + with open(kallsyms) as syms: +@@ -194,11 +195,11 @@ bpf_text = bpf_text.replace('FACTOR', str(factor)) + b = BPF(text=bpf_text) + + b.attach_kprobe(event=ext4_read_fn, fn_name=ext4_trace_read_fn) +-b.attach_kprobe(event="ext4_file_write_iter", fn_name="trace_entry") ++b.attach_kprobe(event="ext4_file_write", fn_name="trace_entry") + b.attach_kprobe(event="ext4_file_open", fn_name="trace_entry") + b.attach_kprobe(event="ext4_sync_file", fn_name="trace_entry") + b.attach_kretprobe(event=ext4_read_fn, fn_name='trace_read_return') +-b.attach_kretprobe(event="ext4_file_write_iter", fn_name="trace_write_return") ++b.attach_kretprobe(event="ext4_file_write", fn_name="trace_write_return") + b.attach_kretprobe(event="ext4_file_open", fn_name="trace_open_return") + b.attach_kretprobe(event="ext4_sync_file", fn_name="trace_fsync_return") + +diff --git a/tools/ext4slower.py b/tools/ext4slower.py +index 0524f22e..d5fbb661 100755 +--- a/tools/ext4slower.py ++++ b/tools/ext4slower.py +@@ -63,6 +63,7 @@ debug = 0 + bpf_text = """ + #include + #include ++#include + #include + #include + +@@ -97,7 +98,7 @@ BPF_PERF_OUTPUT(events); + // Store timestamp and size on entry + // + +-// The current ext4 (Linux 4.5) uses generic_file_read_iter(), instead of it's ++// ext4 uses generic_file_aio_read(), instead of it's + // own function, for reads. So we need to trace that and then filter on ext4, + // which I do by checking file->f_op. + // The new Linux version (since form 4.10) uses ext4_file_read_iter(), And if the 'CONFIG_FS_DAX' +@@ -127,7 +128,7 @@ int trace_read_entry(struct pt_regs *ctx, struct kiocb *iocb) + return 0; + } + +-// ext4_file_write_iter(): ++// ext4_file_write(): + int trace_write_entry(struct pt_regs *ctx, struct kiocb *iocb) + { + u64 id = bpf_get_current_pid_tgid(); +@@ -314,15 +315,15 @@ b = BPF(text=bpf_text) + if BPF.get_kprobe_functions(b'ext4_file_read_iter'): + b.attach_kprobe(event="ext4_file_read_iter", fn_name="trace_read_entry") + else: +- b.attach_kprobe(event="generic_file_read_iter", fn_name="trace_read_entry") +-b.attach_kprobe(event="ext4_file_write_iter", fn_name="trace_write_entry") ++ b.attach_kprobe(event="generic_file_aio_read", fn_name="trace_read_entry") ++b.attach_kprobe(event="ext4_file_write", fn_name="trace_write_entry") + b.attach_kprobe(event="ext4_file_open", fn_name="trace_open_entry") + b.attach_kprobe(event="ext4_sync_file", fn_name="trace_fsync_entry") + if BPF.get_kprobe_functions(b'ext4_file_read_iter'): + b.attach_kretprobe(event="ext4_file_read_iter", fn_name="trace_read_return") + else: +- b.attach_kretprobe(event="generic_file_read_iter", fn_name="trace_read_return") +-b.attach_kretprobe(event="ext4_file_write_iter", fn_name="trace_write_return") ++ b.attach_kretprobe(event="generic_file_aio_read", fn_name="trace_read_return") ++b.attach_kretprobe(event="ext4_file_write", fn_name="trace_write_return") + b.attach_kretprobe(event="ext4_file_open", fn_name="trace_open_return") + b.attach_kretprobe(event="ext4_sync_file", fn_name="trace_fsync_return") + +diff --git a/tools/fileslower.py b/tools/fileslower.py +index 31e3adf9..05582c9e 100755 +--- a/tools/fileslower.py ++++ b/tools/fileslower.py +@@ -123,7 +123,7 @@ int trace_read_entry(struct pt_regs *ctx, struct file *file, + char __user *buf, size_t count) + { + // skip non-sync I/O; see kernel code for __vfs_read() +- if (!(file->f_op->read_iter)) ++ if (!(file->f_op->aio_read)) + return 0; + return trace_rw_entry(ctx, file, buf, count); + } +@@ -132,7 +132,7 @@ int trace_write_entry(struct pt_regs *ctx, struct file *file, + char __user *buf, size_t count) + { + // skip non-sync I/O; see kernel code for __vfs_write() +- if (!(file->f_op->write_iter)) ++ if (!(file->f_op->aio_write)) + return 0; + return trace_rw_entry(ctx, file, buf, count); + } +@@ -199,8 +199,13 @@ b = BPF(text=bpf_text) + # do_sync_read/do_sync_write), but those became static. So trace these from + # the parent functions, at the cost of more overhead, instead. + # Ultimately, we should be using [V]FS tracepoints. +-b.attach_kprobe(event="__vfs_read", fn_name="trace_read_entry") +-b.attach_kretprobe(event="__vfs_read", fn_name="trace_read_return") ++try: ++ b.attach_kprobe(event="__vfs_read", fn_name="trace_read_entry") ++ b.attach_kretprobe(event="__vfs_read", fn_name="trace_read_return") ++except: ++ # older kernels don't have __vfs_read so try vfs_read instead ++ b.attach_kprobe(event="vfs_read", fn_name="trace_read_entry") ++ b.attach_kretprobe(event="vfs_read", fn_name="trace_read_return") + try: + b.attach_kprobe(event="__vfs_write", fn_name="trace_write_entry") + b.attach_kretprobe(event="__vfs_write", fn_name="trace_write_return") +diff --git a/tools/memleak.py b/tools/memleak.py +index fd08bc4d..db8b927a 100755 +--- a/tools/memleak.py ++++ b/tools/memleak.py +@@ -357,13 +357,21 @@ TRACEPOINT_PROBE(kmem, kmem_cache_free) { + return gen_free_enter((struct pt_regs *)args, (void *)args->ptr); + } + ++/* ++ * Upstream reads the PFN here, but on RHEL7 kernel this is not available ++ * and the address of the pages struct is returned instead. This value is ++ * used as the key in a hash to identify each allocation. No other allocation ++ * should return an address belonging to mem_map, so there's no risk of ++ * colision ++ */ ++ + TRACEPOINT_PROBE(kmem, mm_page_alloc) { + gen_alloc_enter((struct pt_regs *)args, PAGE_SIZE << args->order); +- return gen_alloc_exit2((struct pt_regs *)args, args->pfn); ++ return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->page); + } + + TRACEPOINT_PROBE(kmem, mm_page_free) { +- return gen_free_enter((struct pt_regs *)args, (void *)args->pfn); ++ return gen_free_enter((struct pt_regs *)args, (void *)args->page); + } + """ + +diff --git a/tools/mountsnoop.py b/tools/mountsnoop.py +index eefb4ec7..5f3678b3 100755 +--- a/tools/mountsnoop.py ++++ b/tools/mountsnoop.py +@@ -24,7 +24,6 @@ bpf_text = r""" + #include + + #include +-#include + + /* + * XXX: struct mnt_namespace is defined in fs/mount.h, which is private to the +@@ -34,7 +33,7 @@ bpf_text = r""" + */ + struct mnt_namespace { + atomic_t count; +- struct ns_common ns; ++ unsigned int proc_inum; + }; + + /* +@@ -69,7 +68,7 @@ struct data_t { + union { + /* EVENT_MOUNT, EVENT_UMOUNT */ + struct { +- /* current->nsproxy->mnt_ns->ns.inum */ ++ /* current->nsproxy->proc_inum */ + unsigned int mnt_ns; + char comm[TASK_COMM_LEN]; + unsigned long flags; +@@ -106,7 +105,7 @@ int syscall__mount(struct pt_regs *ctx, char __user *source, + task = (struct task_struct *)bpf_get_current_task(); + nsproxy = task->nsproxy; + mnt_ns = nsproxy->mnt_ns; +- event.enter.mnt_ns = mnt_ns->ns.inum; ++ event.enter.mnt_ns = mnt_ns->proc_inum; + events.perf_submit(ctx, &event, sizeof(event)); + + event.type = EVENT_MOUNT_SOURCE; +@@ -161,7 +160,7 @@ int syscall__umount(struct pt_regs *ctx, char __user *target, int flags) + task = (struct task_struct *)bpf_get_current_task(); + nsproxy = task->nsproxy; + mnt_ns = nsproxy->mnt_ns; +- event.enter.mnt_ns = mnt_ns->ns.inum; ++ event.enter.mnt_ns = mnt_ns->proc_inum; + events.perf_submit(ctx, &event, sizeof(event)); + + event.type = EVENT_UMOUNT_TARGET; +diff --git a/tools/nfsslower.py b/tools/nfsslower.py +index 36918ca0..9c6d8f6c 100755 +--- a/tools/nfsslower.py ++++ b/tools/nfsslower.py +@@ -64,6 +64,7 @@ bpf_text = """ + + #include + #include ++#include + #include + #include + +diff --git a/tools/offcputime.py b/tools/offcputime.py +index ac3b7281..ea36b264 100755 +--- a/tools/offcputime.py ++++ b/tools/offcputime.py +@@ -128,7 +128,9 @@ BPF_HASH(counts, struct key_t); + BPF_HASH(start, u32); + BPF_STACK_TRACE(stack_traces, STACK_STORAGE_SIZE); + +-int oncpu(struct pt_regs *ctx, struct task_struct *prev) { ++struct rq; ++ ++int oncpu(struct pt_regs *ctx, struct rq *rq, struct task_struct *prev) { + u32 pid = prev->pid; + u32 tgid = prev->tgid; + u64 ts, *tsp; +diff --git a/tools/offwaketime.py b/tools/offwaketime.py +index 4a1cebab..baa28801 100755 +--- a/tools/offwaketime.py ++++ b/tools/offwaketime.py +@@ -163,7 +163,9 @@ int waker(struct pt_regs *ctx, struct task_struct *p) { + return 0; + } + +-int oncpu(struct pt_regs *ctx, struct task_struct *p) { ++struct rq; ++ ++int oncpu(struct pt_regs *ctx, struct rq *rq, struct task_struct *p) { + // PID and TGID of the previous Process (Process going into waiting) + u32 pid = p->pid; + u32 tgid = p->tgid; +diff --git a/tools/oomkill.py b/tools/oomkill.py +index 4f3b6ce7..546c2dc6 100755 +--- a/tools/oomkill.py ++++ b/tools/oomkill.py +@@ -35,15 +35,15 @@ struct data_t { + + BPF_PERF_OUTPUT(events); + +-void kprobe__oom_kill_process(struct pt_regs *ctx, struct oom_control *oc, const char *message) ++void kprobe__oom_kill_process(struct pt_regs *ctx, struct task_struct *p, ++ gfp_t gfp_mask, int order, unsigned int points, ++ unsigned long totalpages, struct mem_cgroup *memcg) + { +- unsigned long totalpages; +- struct task_struct *p = oc->chosen; + struct data_t data = {}; + u32 pid = bpf_get_current_pid_tgid(); + data.fpid = pid; + data.tpid = p->pid; +- data.pages = oc->totalpages; ++ data.pages = totalpages; + bpf_get_current_comm(&data.fcomm, sizeof(data.fcomm)); + bpf_probe_read(&data.tcomm, sizeof(data.tcomm), p->comm); + events.perf_submit(ctx, &data, sizeof(data)); +diff --git a/tools/runqlat.py b/tools/runqlat.py +index 9fd40642..0c9bb1c4 100755 +--- a/tools/runqlat.py ++++ b/tools/runqlat.py +@@ -111,7 +111,7 @@ int trace_ttwu_do_wakeup(struct pt_regs *ctx, struct rq *rq, struct task_struct + } + + // calculate latency +-int trace_run(struct pt_regs *ctx, struct task_struct *prev) ++int trace_run(struct pt_regs *ctx, struct rq *rq, struct task_struct *prev) + { + u32 pid, tgid; + +diff --git a/tools/runqslower.py b/tools/runqslower.py +index 1d48be8a..16a5a4c2 100755 +--- a/tools/runqslower.py ++++ b/tools/runqslower.py +@@ -97,7 +97,7 @@ int trace_ttwu_do_wakeup(struct pt_regs *ctx, struct rq *rq, struct task_struct + } + + // calculate latency +-int trace_run(struct pt_regs *ctx, struct task_struct *prev) ++int trace_run(struct pt_regs *ctx, struct rq *rq, struct task_struct *prev) + { + u32 pid, tgid; + +diff --git a/tools/solisten.py b/tools/solisten.py +index f2a0a342..16872212 100755 +--- a/tools/solisten.py ++++ b/tools/solisten.py +@@ -100,7 +100,7 @@ int kprobe__inet_listen(struct pt_regs *ctx, struct socket *sock, int backlog) + + // Get network namespace id, if kernel supports it + #ifdef CONFIG_NET_NS +- evt.netns = sk->__sk_common.skc_net.net->ns.inum; ++ evt.netns = sk->__sk_common.skc_net->proc_inum; + #else + evt.netns = 0; + #endif +diff --git a/tools/tcpsubnet.py b/tools/tcpsubnet.py +index 5f2a8062..1ba275bc 100755 +--- a/tools/tcpsubnet.py ++++ b/tools/tcpsubnet.py +@@ -110,8 +110,8 @@ struct index_key_t { + + BPF_HASH(ipv4_send_bytes, struct index_key_t); + +-int kprobe__tcp_sendmsg(struct pt_regs *ctx, struct sock *sk, +- struct msghdr *msg, size_t size) ++int kprobe__tcp_sendmsg(struct pt_regs *ctx, struct kiocb *iocb, ++ struct sock *sk, struct msghdr *msg, size_t size) + { + u16 family = sk->__sk_common.skc_family; + +diff --git a/tools/tcptracer.py b/tools/tcptracer.py +index e61fe9ba..f00f0d19 100755 +--- a/tools/tcptracer.py ++++ b/tools/tcptracer.py +@@ -115,7 +115,7 @@ static int read_ipv4_tuple(struct ipv4_tuple_t *tuple, struct sock *skp) + u16 sport = sockp->inet_sport; + u16 dport = skp->__sk_common.skc_dport; + #ifdef CONFIG_NET_NS +- net_ns_inum = skp->__sk_common.skc_net.net->ns.inum; ++ net_ns_inum = skp->__sk_common.skc_net->proc_inum; + #endif + + ##FILTER_NETNS## +@@ -142,7 +142,7 @@ static int read_ipv6_tuple(struct ipv6_tuple_t *tuple, struct sock *skp) + u16 sport = sockp->inet_sport; + u16 dport = skp->__sk_common.skc_dport; + #ifdef CONFIG_NET_NS +- net_ns_inum = skp->__sk_common.skc_net.net->ns.inum; ++ net_ns_inum = skp->__sk_common.skc_net->proc_inum; + #endif + bpf_probe_read(&saddr, sizeof(saddr), + skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); +@@ -360,8 +360,7 @@ int trace_close_entry(struct pt_regs *ctx, struct sock *skp) + // Don't generate close events for connections that were never + // established in the first place. + if (oldstate == TCP_SYN_SENT || +- oldstate == TCP_SYN_RECV || +- oldstate == TCP_NEW_SYN_RECV) ++ oldstate == TCP_SYN_RECV ) + return 0; + + u8 ipver = 0; +@@ -432,7 +431,7 @@ int trace_accept_return(struct pt_regs *ctx) + + // Get network namespace id, if kernel supports it + #ifdef CONFIG_NET_NS +- net_ns_inum = newsk->__sk_common.skc_net.net->ns.inum; ++ net_ns_inum = newsk->__sk_common.skc_net->proc_inum; + #endif + + ##FILTER_NETNS## +diff --git a/tools/xfsdist.py b/tools/xfsdist.py +index f409f90d..2976f9e2 100755 +--- a/tools/xfsdist.py ++++ b/tools/xfsdist.py +@@ -137,12 +137,12 @@ bpf_text = bpf_text.replace('FACTOR', str(factor)) + b = BPF(text=bpf_text) + + # common file functions +-b.attach_kprobe(event="xfs_file_read_iter", fn_name="trace_entry") +-b.attach_kprobe(event="xfs_file_write_iter", fn_name="trace_entry") ++b.attach_kprobe(event="xfs_file_aio_read", fn_name="trace_entry") ++b.attach_kprobe(event="xfs_file_aio_write", fn_name="trace_entry") + b.attach_kprobe(event="xfs_file_open", fn_name="trace_entry") + b.attach_kprobe(event="xfs_file_fsync", fn_name="trace_entry") +-b.attach_kretprobe(event="xfs_file_read_iter", fn_name="trace_read_return") +-b.attach_kretprobe(event="xfs_file_write_iter", fn_name="trace_write_return") ++b.attach_kretprobe(event="xfs_file_aio_read", fn_name="trace_read_return") ++b.attach_kretprobe(event="xfs_file_aio_write", fn_name="trace_write_return") + b.attach_kretprobe(event="xfs_file_open", fn_name="trace_open_return") + b.attach_kretprobe(event="xfs_file_fsync", fn_name="trace_fsync_return") + +diff --git a/tools/xfsslower.py b/tools/xfsslower.py +index 9fa12566..0ef50f6e 100755 +--- a/tools/xfsslower.py ++++ b/tools/xfsslower.py +@@ -59,6 +59,7 @@ debug = 0 + bpf_text = """ + #include + #include ++#include + #include + #include + +@@ -93,7 +94,7 @@ BPF_PERF_OUTPUT(events); + // Store timestamp and size on entry + // + +-// xfs_file_read_iter(), xfs_file_write_iter(): ++// xfs_file_aio_read(), xfs_file_aio_write(): + int trace_rw_entry(struct pt_regs *ctx, struct kiocb *iocb) + { + u64 id = bpf_get_current_pid_tgid(); +@@ -264,12 +265,12 @@ int trace_fsync_return(struct pt_regs *ctx) + b = BPF(text=bpf_text) + + # common file functions +-b.attach_kprobe(event="xfs_file_read_iter", fn_name="trace_rw_entry") +-b.attach_kprobe(event="xfs_file_write_iter", fn_name="trace_rw_entry") ++b.attach_kprobe(event="xfs_file_aio_read", fn_name="trace_rw_entry") ++b.attach_kprobe(event="xfs_file_aio_write", fn_name="trace_rw_entry") + b.attach_kprobe(event="xfs_file_open", fn_name="trace_open_entry") + b.attach_kprobe(event="xfs_file_fsync", fn_name="trace_fsync_entry") +-b.attach_kretprobe(event="xfs_file_read_iter", fn_name="trace_read_return") +-b.attach_kretprobe(event="xfs_file_write_iter", fn_name="trace_write_return") ++b.attach_kretprobe(event="xfs_file_aio_read", fn_name="trace_read_return") ++b.attach_kretprobe(event="xfs_file_aio_write", fn_name="trace_write_return") + b.attach_kretprobe(event="xfs_file_open", fn_name="trace_open_return") + b.attach_kretprobe(event="xfs_file_fsync", fn_name="trace_fsync_return") + +-- +2.20.1 + diff --git a/SOURCES/bcc-0.10.0-tools-fix-vfscount-output-when-no-duration-is-specif.patch b/SOURCES/bcc-0.10.0-tools-fix-vfscount-output-when-no-duration-is-specif.patch new file mode 100644 index 0000000..84be464 --- /dev/null +++ b/SOURCES/bcc-0.10.0-tools-fix-vfscount-output-when-no-duration-is-specif.patch @@ -0,0 +1,62 @@ +From 0206fc4e3568eab6cacfc1d5916258a9ba764f5d Mon Sep 17 00:00:00 2001 +From: Jerome Marchand +Date: Mon, 5 Aug 2019 15:29:22 +0200 +Subject: [PATCH] tools: fix vfscount output when no duration is specified + +Since commit a2e71a9eb71a ("vfscount.py: add args time (#2344)"), +vfscount does not show any output when it is interrupted by a key +press, which is the only way out when no time limit is specified. I +assume the exit() that has been added in the keyboard interrupt +handler is there so that no output is displayed when the program has +been interrupted early when a time limit has been specified. But since +the tool still invite the user to use Ctrl-C to end the tracing in +that case, it seems more consistent to show an output in that case +too. + +This patch removes the exit() and the tools always show a result at +the end. It also adds the duration argument to the synopsis and the +option section in the man page. +--- + man/man8/vfscount.8 | 6 +++++- + tools/vfscount.py | 1 - + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/man/man8/vfscount.8 b/man/man8/vfscount.8 +index fbf0e89e..febbc9e6 100644 +--- a/man/man8/vfscount.8 ++++ b/man/man8/vfscount.8 +@@ -2,7 +2,7 @@ + .SH NAME + vfscount \- Count VFS calls ("vfs_*"). Uses Linux eBPF/bcc. + .SH SYNOPSIS +-.B vfscount ++.B vfscount [duration] + .SH DESCRIPTION + This counts VFS calls. This can be useful for general workload + characterization of these operations. +@@ -14,6 +14,10 @@ Edit the script to customize which functions to trace. + Since this uses BPF, only the root user can use this tool. + .SH REQUIREMENTS + CONFIG_BPF and bcc. ++.SH OPTIONS ++.TP ++duration ++duration of the trace in seconds. + .SH EXAMPLES + .TP + Count some VFS calls until Ctrl-C is hit: +diff --git a/tools/vfscount.py b/tools/vfscount.py +index b7c18efd..303d3fde 100755 +--- a/tools/vfscount.py ++++ b/tools/vfscount.py +@@ -54,7 +54,6 @@ print("Tracing... Ctrl-C to end.") + sleep(interval) + except KeyboardInterrupt: + pass +- exit() + + print("\n%-16s %-26s %8s" % ("ADDR", "FUNC", "COUNT")) + counts = b.get_table("counts") +-- +2.20.1 + diff --git a/SOURCES/link-against-libLLVM.so-instead-of-static-libs.patch b/SOURCES/link-against-libLLVM.so-instead-of-static-libs.patch new file mode 100644 index 0000000..fe40e27 --- /dev/null +++ b/SOURCES/link-against-libLLVM.so-instead-of-static-libs.patch @@ -0,0 +1,30 @@ +From ddbdaef40b7db8259f7728a64839b9ff38fbfd76 Mon Sep 17 00:00:00 2001 +From: Jerome Marchand +Date: Fri, 15 Jun 2018 11:41:47 +0200 +Subject: [PATCH] Link against libLLVM.so instead of static libs + +--- + src/cc/CMakeLists.txt | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/cc/CMakeLists.txt b/src/cc/CMakeLists.txt +index 8ddfd8f..0c3d7df 100644 +--- a/src/cc/CMakeLists.txt ++++ b/src/cc/CMakeLists.txt +@@ -62,11 +62,11 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${llvm_lib_exclude_f + # bcc_common_libs_for_a for archive libraries + # bcc_common_libs_for_s for shared libraries + set(bcc_common_libs_for_a b_frontend clang_frontend bpf-static +- -Wl,--whole-archive ${clang_libs} ${llvm_libs} -Wl,--no-whole-archive ++ -Wl,--whole-archive ${clang_libs} libLLVM-7-rhel.so -Wl,--no-whole-archive + ${LIBELF_LIBRARIES}) + set(bcc_common_libs_for_s ${bcc_common_libs_for_a}) + set(bcc_common_libs_for_lua b_frontend clang_frontend bpf-static +- ${clang_libs} ${llvm_libs} ${LIBELF_LIBRARIES}) ++ ${clang_libs} libLLVM-7-rhel.so ${LIBELF_LIBRARIES}) + + if(ENABLE_CPP_API) + add_subdirectory(api) +-- +2.17.1 + diff --git a/SPECS/bcc.spec b/SPECS/bcc.spec new file mode 100644 index 0000000..b7aa384 --- /dev/null +++ b/SPECS/bcc.spec @@ -0,0 +1,279 @@ +# luajit is not available for some architectures and not at all on RHEL7 +%if 0%{?rhel} <= 7 +%bcond_with lua +%else +%ifarch ppc64 ppc64le s390x +%bcond_with lua +%else +%bcond_without lua +%endif +%endif + +Name: bcc +Version: 0.10.0 +Release: 1%{?dist} +Summary: BPF Compiler Collection (BCC) +License: ASL 2.0 +URL: https://github.com/iovisor/bcc +# Generate source tarball until upstream bug is fixed +# See https://github.com/iovisor/bcc/issues/2261 +# To generate the tarball, use the following commands +# git clone -b "v0.10.0" --single-branch --depth 1 url bcc-0.10.0 +# pushd bcc-0.10.0 +# git submodule update --init +# popd +# tar zcvf bcc-0.10.0.tar.gz bcc-0.10.0/ +#Source0: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz +Source0: %{name}-%{version}.tar.gz +Patch0: link-against-libLLVM.so-instead-of-static-libs.patch +Patch1: Fix-tools-for-RHEL-7.patch +Patch2: %{name}-%{version}-tools-fix-vfscount-output-when-no-duration-is-specif.patch + +# Arches will be included as upstream support is added and dependencies are +# satisfied in the respective arches +ExcludeArch: i686 ppc s390 + +BuildRequires: bison, cmake >= 2.8.7, flex, libxml2-devel +BuildRequires: python-devel +BuildRequires: elfutils-libelf-devel +BuildRequires: ncurses-devel +%if %{with lua} +BuildRequires: pkgconfig(luajit) +%endif +BuildRequires: llvm-private-devel >= 6.0.1-0.3 + +Requires: %{name}-tools = %{version}-%{release} +Requires: llvm-private >= 6.0.1-0.3 + +%description +BCC is a toolkit for creating efficient kernel tracing and manipulation +programs, and includes several useful tools and examples. It makes use of +extended BPF (Berkeley Packet Filters), formally known as eBPF, a new feature +that was first added to Linux 3.15. BCC makes BPF programs easier to write, +with kernel instrumentation in C (and includes a C wrapper around LLVM), and +front-ends in Python and lua. It is suited for many tasks, including +performance analysis and network traffic control. + + +%package devel +Summary: Shared library for BPF Compiler Collection (BCC) +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for developing +application that use BPF Compiler Collection (BCC). + + +%package doc +Summary: Examples for BPF Compiler Collection (BCC) +BuildArch: noarch + +%description doc +Examples for BPF Compiler Collection (BCC) + + +%package -n python-%{name} +Summary: Python bindings for BPF Compiler Collection (BCC) +Requires: %{name}%{?_isa} = %{version}-%{release} +%{?python_provide:%python_provide python-%{srcname}} + +%description -n python-%{name} +Python bindings for BPF Compiler Collection (BCC) + + +%if %{with lua} +%package lua +Summary: Standalone tool to run BCC tracers written in Lua +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description lua +Standalone tool to run BCC tracers written in Lua +%endif + + +%package tools +Summary: Command line tools for BPF Compiler Collection (BCC) +Requires: python-%{name} = %{version}-%{release} +Requires: python-netaddr +Requires: kernel-devel + +%description tools +Command line tools for BPF Compiler Collection (BCC) + +%prep +%autosetup -p1 + +%build +%cmake . \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo\ + -DCMAKE_CXX_FLAGS='-std=c++11 -I/usr/include/llvm-private/'\ + -DREVISION_LAST=%{version} -DREVISION=%{version}\ + -DCMAKE_LIBRARY_PATH=/usr/lib64/clang-private/\ + -DCMAKE_INSTALL_RPATH=/usr/lib64/clang-private/ +%make_build + +%install +%make_install + +# Move man pages to the right location +mkdir -p %{buildroot}%{_mandir} +mv %{buildroot}%{_datadir}/%{name}/man/* %{buildroot}%{_mandir}/ +# Avoid conflict with other manpages +# https://bugzilla.redhat.com/show_bug.cgi?id=1517408 +for i in `find %{buildroot}%{_mandir} -name "*.gz"`; do + tname=$(basename $i) + rename $tname %{name}-$tname $i +done +# Fix the symlink too +for i in `find %{buildroot}%{_mandir} -lname \*.gz` ; do + target=`readlink $i`; + ln -sf bcc-$target $i; +done +mkdir -p %{buildroot}%{_docdir}/%{name} +mv %{buildroot}%{_datadir}/%{name}/examples %{buildroot}%{_docdir}/%{name}/ + +# We cannot run the test suit since it requires root and it makes changes to +# the machine (e.g, IP address) +#%check + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%doc README.md +%license LICENSE.txt +%{_libdir}/lib%{name}.so.* +%{_libdir}/libbcc_bpf.so.* + +%files devel +%{_libdir}/lib%{name}.so +%{_libdir}/libbcc_bpf.so +%{_libdir}/pkgconfig/lib%{name}.pc +%{_includedir}/%{name}/ + +%files -n python-%{name} +%{python_sitelib}/%{name}* + +%files doc +%dir %{_docdir}/%{name} +%doc %{_docdir}/%{name}/examples/ + +%files tools +%dir %{_datadir}/%{name} +%dir %{_datadir}/%{name}/tools +%dir %{_datadir}/%{name}/introspection +%{_datadir}/%{name}/tools/* +%{_datadir}/%{name}/introspection/* +%exclude %{_datadir}/%{name}/tools/old/ +# inject relies on BPF_KPROBE_OVERRIDE which is absent on RHEL 7 +%exclude %{_datadir}/%{name}/tools/inject +%exclude %{_datadir}/%{name}/tools/doc/inject_example.txt +%exclude %{_mandir}/man8/inject.8 +# ZFS isn't available on RHEL +%exclude %{_datadir}/%{name}/tools/zfs* +%exclude %{_datadir}/%{name}/tools/doc/zfs* +%exclude %{_mandir}/man8/zfs* +# criticalstat relies on CONFIG_PREEMPTIRQ_EVENTS which is absent on RHEL 7 +%exclude %{_datadir}/%{name}/tools/criticalstat +%exclude %{_datadir}/%{name}/tools/doc/criticalstat_example.txt +%exclude %{_mandir}/man8/criticalstat.8 +# tcpstates relies on sock:inet_sock_set_state which is absent on RHEL 7 +%exclude %{_datadir}/%{name}/tools/tcpstates +%exclude %{_datadir}/%{name}/tools/doc/tcpstates_example.txt +%exclude %{_mandir}/man8/tcpstates.8 +%{_mandir}/man8/* + +%if %{with lua} +%files lua +%{_bindir}/bcc-lua +%endif + + +%changelog +* Tue Aug 06 2019 Jerome Marchand - 0.10.0-1 +- Rebase on bcc-0.10.0 +- Fix regression of vfscount +- Drop tools that relies on features unavailable on RHEL 7 + +* Mon Jan 28 2019 Jerome Marchand - 0.8.0-1 +- Rebase on bcc-8.0.0 +- Update libLLVM.so name for 7.0 + +* Fri Sep 21 2018 Jerome Marchand - 0.6.1-2 +- Set a minimal version for llvm-private(-devel) + +* Thu Aug 16 2018 Jerome Marchand - 0.6.1-1 +- Rebase on v0.6.1 +- Fix tcpsubnet +- Reinstate llcstat tool +- Remove inject tool +- Add NSS support to sslsniff +- Fixes miscellaneous error uncovered by covscan + +* Wed Jul 04 2018 Jerome Marchand - 0.6.0-3 +- Fix tools on RHEL 7 +- Remove llcstat and ZFS tools. + +* Tue Jun 26 2018 Jerome Marchand - 0.6.0-2 +- Add llvm-private requirement +- Fix manpages symlinks + +* Tue Jun 19 2018 Jerome Marchand - 0.6.0-1 +- Rebase on bcc-0.6.0 + +* Thu Jun 07 2018 Jerome Marchand - 0.5.0-6 +- Enables build on RHEL 7 + +* Thu May 24 2018 Jerome Marchand - 0.5.0-5 +- Enables build on ppc64(le) and s390x arches + +* Thu Apr 05 2018 Rafael Santos - 0.5.0-4 +- Resolves #1555627 - fix compilation error with latest llvm/clang + +* Wed Feb 07 2018 Fedora Release Engineering - 0.5.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Fri Feb 02 2018 Igor Gnatenko - 0.5.0-2 +- Switch to %%ldconfig_scriptlets + +* Wed Jan 03 2018 Rafael Santos - 0.5.0-1 +- Rebase to new released version + +* Thu Nov 16 2017 Rafael Santos - 0.4.0-4 +- Resolves #1517408 - avoid conflict with other manpages + +* Thu Nov 02 2017 Rafael Santos - 0.4.0-3 +- Use weak deps to not require lua subpkg on ppc64(le) + +* Wed Nov 01 2017 Igor Gnatenko - 0.4.0-2 +- Rebuild for LLVM5 + +* Wed Nov 01 2017 Rafael Fonseca - 0.4.0-1 +- Resolves #1460482 - rebase to new release +- Resolves #1505506 - add support for LLVM 5.0 +- Resolves #1460482 - BPF module compilation issue +- Partially address #1479990 - location of man pages +- Enable ppc64(le) support without lua +- Soname versioning for libbpf by ignatenkobrain + +* Wed Aug 02 2017 Fedora Release Engineering - 0.3.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 0.3.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Thu Mar 30 2017 Igor Gnatenko - 0.3.0-2 +- Rebuild for LLVM4 +- Trivial fixes in spec + +* Fri Mar 10 2017 Rafael Fonseca - 0.3.0-1 +- Rebase to new release. + +* Fri Feb 10 2017 Fedora Release Engineering - 0.2.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Tue Jan 10 2017 Rafael Fonseca - 0.2.0-2 +- Fix typo + +* Tue Nov 29 2016 Rafael Fonseca - 0.2.0-1 +- Initial import