diff --git a/.bcc.metadata b/.bcc.metadata
index 82927a1..e3a63ae 100644
--- a/.bcc.metadata
+++ b/.bcc.metadata
@@ -1 +1 @@
-87f0836bc2a1d7a795a44622d14930e6d4f6d627 SOURCES/bcc-0.20.0.tar.gz
+896d0249470dedfabfcc9a4c8b4089a55b793277 SOURCES/bcc-0.24.0.tar.gz
diff --git a/.gitignore b/.gitignore
index c5b3e19..277ef94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/bcc-0.20.0.tar.gz
+SOURCES/bcc-0.24.0.tar.gz
diff --git a/SOURCES/bcc-0.20.0-Define-KERNEL_VERSION.patch b/SOURCES/bcc-0.20.0-Define-KERNEL_VERSION.patch
deleted file mode 100644
index 959eae5..0000000
--- a/SOURCES/bcc-0.20.0-Define-KERNEL_VERSION.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From 6516fb0d00208f05b29f320176204957b02b23e3 Mon Sep 17 00:00:00 2001
-From: Jerome Marchand <jmarchan@redhat.com>
-Date: Mon, 26 Jul 2021 12:05:57 +0200
-Subject: [PATCH] Define KERNEL_VERSION
-
-The libbpf version on RHEL9 doesn't define it.
----
- libbpf-tools/biolatency.bpf.c | 2 ++
- libbpf-tools/biosnoop.bpf.c   | 2 ++
- libbpf-tools/bitesize.bpf.c   | 2 ++
- 3 files changed, 6 insertions(+)
-
-diff --git a/libbpf-tools/biolatency.bpf.c b/libbpf-tools/biolatency.bpf.c
-index 8d8fe584..8e6e81e2 100644
---- a/libbpf-tools/biolatency.bpf.c
-+++ b/libbpf-tools/biolatency.bpf.c
-@@ -9,6 +9,8 @@
- 
- #define MAX_ENTRIES	10240
- 
-+#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
-+
- extern int LINUX_KERNEL_VERSION __kconfig;
- 
- const volatile bool targ_per_disk = false;
-diff --git a/libbpf-tools/biosnoop.bpf.c b/libbpf-tools/biosnoop.bpf.c
-index 76697967..7b7cb1a4 100644
---- a/libbpf-tools/biosnoop.bpf.c
-+++ b/libbpf-tools/biosnoop.bpf.c
-@@ -11,6 +11,8 @@
- const volatile bool targ_queued = false;
- const volatile dev_t targ_dev = -1;
- 
-+#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
-+
- extern __u32 LINUX_KERNEL_VERSION __kconfig;
- 
- struct piddata {
-diff --git a/libbpf-tools/bitesize.bpf.c b/libbpf-tools/bitesize.bpf.c
-index 7b4d3f9d..5e7d9d97 100644
---- a/libbpf-tools/bitesize.bpf.c
-+++ b/libbpf-tools/bitesize.bpf.c
-@@ -10,6 +10,8 @@
- const volatile char targ_comm[TASK_COMM_LEN] = {};
- const volatile dev_t targ_dev = -1;
- 
-+#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
-+
- extern __u32 LINUX_KERNEL_VERSION __kconfig;
- 
- struct {
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-Fix-a-llvm-compilation-error.patch b/SOURCES/bcc-0.20.0-Fix-a-llvm-compilation-error.patch
deleted file mode 100644
index 5c15817..0000000
--- a/SOURCES/bcc-0.20.0-Fix-a-llvm-compilation-error.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From e2a4a556755d3c5ae7538ba9bcb731f93b9f81c9 Mon Sep 17 00:00:00 2001
-From: Yonghong Song <yhs@fb.com>
-Date: Tue, 25 May 2021 19:58:00 -0700
-Subject: [PATCH] Fix a llvm compilation error
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Current llvm trunk (https://github.com/llvm/llvm-project)
-will cause the following compilation errors:
-  /home/yhs/work/bcc/src/cc/bcc_debug.cc: In member function ‘void ebpf::SourceDebugger::dump()’:
-  /home/yhs/work/bcc/src/cc/bcc_debug.cc:135:75: error: no matching function for call to
-     ‘llvm::MCContext::MCContext(llvm::Triple&, std::unique_ptr<llvm::MCAsmInfo>::pointer,
-      std::unique_ptr<llvm::MCRegisterInfo>::pointer, llvm::MCObjectFileInfo*,
-      std::unique_ptr<llvm::MCSubtargetInfo>::pointer, std::nullptr_t)’
-     MCContext Ctx(TheTriple, MAI.get(), MRI.get(), &MOFI, STI.get(), nullptr);
-                                                                             ^
-     ......
-
-This is because upstream patch https://reviews.llvm.org/D101921
-refactored MCObjectFileInfo initialization and changed MCContext
-constructor signature.
-
-This patch fixed the issue by following the new code patterns
-in https://reviews.llvm.org/D101921.
----
- src/cc/bcc_debug.cc | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/cc/bcc_debug.cc b/src/cc/bcc_debug.cc
-index 775c9141..97d6d95b 100644
---- a/src/cc/bcc_debug.cc
-+++ b/src/cc/bcc_debug.cc
-@@ -132,7 +132,8 @@ void SourceDebugger::dump() {
-       T->createMCSubtargetInfo(TripleStr, "", ""));
-   MCObjectFileInfo MOFI;
- #if LLVM_MAJOR_VERSION >= 13
--  MCContext Ctx(TheTriple, MAI.get(), MRI.get(), &MOFI, STI.get(), nullptr);
-+  MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), nullptr);
-+  Ctx.setObjectFileInfo(&MOFI);
-   MOFI.initMCObjectFileInfo(Ctx, false, false);
- #else
-   MCContext Ctx(MAI.get(), MRI.get(), &MOFI, nullptr);
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-Fix-mdflush-on-RHEL9.patch b/SOURCES/bcc-0.20.0-Fix-mdflush-on-RHEL9.patch
deleted file mode 100644
index b6b9e07..0000000
--- a/SOURCES/bcc-0.20.0-Fix-mdflush-on-RHEL9.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 8032bb4053ff8803371b038fc696b9fa682027f2 Mon Sep 17 00:00:00 2001
-From: Jerome Marchand <jmarchan@redhat.com>
-Date: Thu, 7 Oct 2021 17:31:53 +0200
-Subject: [PATCH] Fix mdflush on RHEL9
-
-Since kernel commit 309dca309fc ("block: store a block_device pointer
-in struct bio") struct bio points again to a block_device and not to a
-gendisk directly. However mdflush is looking at the presence or not of
-the bio_dev macro to check whether to get the gendisk directly from
-the bio or not, which doesn't work anymore since the bio_dev macro
-still exists. Since we don't have to deal other ekrnel kernel version
-but our own, just use the definition that we use in our kernels.
----
- tools/mdflush.py | 11 -----------
- 1 file changed, 11 deletions(-)
-
-diff --git a/tools/mdflush.py b/tools/mdflush.py
-index 2abe15cf..df0f13c1 100755
---- a/tools/mdflush.py
-+++ b/tools/mdflush.py
-@@ -35,18 +35,7 @@ int kprobe__md_flush_request(struct pt_regs *ctx, void *mddev, struct bio *bio)
-     u32 pid = bpf_get_current_pid_tgid();
-     data.pid = pid;
-     bpf_get_current_comm(&data.comm, sizeof(data.comm));
--/*
-- * The following deals with a kernel version change (in mainline 4.14, although
-- * it may be backported to earlier kernels) with how the disk name is accessed.
-- * We handle both pre- and post-change versions here. Please avoid kernel
-- * version tests like this as much as possible: they inflate the code, test,
-- * and maintenance burden.
-- */
--#ifdef bio_dev
--    struct gendisk *bi_disk = bio->bi_disk;
--#else
-     struct gendisk *bi_disk = bio->bi_bdev->bd_disk;
--#endif
-     bpf_probe_read_kernel(&data.disk, sizeof(data.disk), bi_disk->disk_name);
-     events.perf_submit(ctx, &data, sizeof(data));
-     return 0;
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-Handle-renaming-of-task_struct_-state-field-on-RHEL-.patch b/SOURCES/bcc-0.20.0-Handle-renaming-of-task_struct_-state-field-on-RHEL-.patch
deleted file mode 100644
index 6a35839..0000000
--- a/SOURCES/bcc-0.20.0-Handle-renaming-of-task_struct_-state-field-on-RHEL-.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-From 019615235458a9486d883a675a3ea16014ee597f Mon Sep 17 00:00:00 2001
-From: Jerome Marchand <jmarchan@redhat.com>
-Date: Thu, 14 Oct 2021 12:01:01 +0200
-Subject: [PATCH] Handle renaming of task_struct_>state field on RHEL 9
-
-There has been some cleanup of task_struct's state field and to catch
-any place that has been missed in the conversion, it has been renamed
-__state.
----
- tools/offcputime.py  | 4 ++--
- tools/offwaketime.py | 4 ++--
- tools/runqlat.py     | 4 ++--
- tools/runqslower.py  | 4 ++--
- 4 files changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/tools/offcputime.py b/tools/offcputime.py
-index 128c6496..b93e78d2 100755
---- a/tools/offcputime.py
-+++ b/tools/offcputime.py
-@@ -205,10 +205,10 @@ thread_context = ""
-     thread_context = "all threads"
-     thread_filter = '1'
- if args.state == 0:
--    state_filter = 'prev->state == 0'
-+    state_filter = 'prev->__state == 0'
- elif args.state:
-     # these states are sometimes bitmask checked
--    state_filter = 'prev->state & %d' % args.state
-+    state_filter = 'prev->__state & %d' % args.state
- else:
-     state_filter = '1'
- bpf_text = bpf_text.replace('THREAD_FILTER', thread_filter)
-diff --git a/tools/offwaketime.py b/tools/offwaketime.py
-index 753eee97..722c0381 100755
---- a/tools/offwaketime.py
-+++ b/tools/offwaketime.py
-@@ -254,10 +254,10 @@ int oncpu(struct pt_regs *ctx, struct task_struct *p) {
- else:
-     thread_filter = '1'
- if args.state == 0:
--    state_filter = 'p->state == 0'
-+    state_filter = 'p->__state == 0'
- elif args.state:
-     # these states are sometimes bitmask checked
--    state_filter = 'p->state & %d' % args.state
-+    state_filter = 'p->__state & %d' % args.state
- else:
-     state_filter = '1'
- bpf_text = bpf_text.replace('THREAD_FILTER', thread_filter)
-diff --git a/tools/runqlat.py b/tools/runqlat.py
-index b13ff2d1..8e443c3c 100755
---- a/tools/runqlat.py
-+++ b/tools/runqlat.py
-@@ -116,7 +116,7 @@ int trace_run(struct pt_regs *ctx, struct task_struct *prev)
-     u32 pid, tgid;
- 
-     // ivcsw: treat like an enqueue event and store timestamp
--    if (prev->state == TASK_RUNNING) {
-+    if (prev->__state == TASK_RUNNING) {
-         tgid = prev->tgid;
-         pid = prev->pid;
-         if (!(FILTER || pid == 0)) {
-@@ -170,7 +170,7 @@ RAW_TRACEPOINT_PROBE(sched_switch)
-     u32 pid, tgid;
- 
-     // ivcsw: treat like an enqueue event and store timestamp
--    if (prev->state == TASK_RUNNING) {
-+    if (prev->__state == TASK_RUNNING) {
-         tgid = prev->tgid;
-         pid = prev->pid;
-         if (!(FILTER || pid == 0)) {
-diff --git a/tools/runqslower.py b/tools/runqslower.py
-index 6df98d9f..ba71e5d3 100755
---- a/tools/runqslower.py
-+++ b/tools/runqslower.py
-@@ -112,7 +112,7 @@ int trace_run(struct pt_regs *ctx, struct task_struct *prev)
-     u32 pid, tgid;
- 
-     // ivcsw: treat like an enqueue event and store timestamp
--    if (prev->state == TASK_RUNNING) {
-+    if (prev->__state == TASK_RUNNING) {
-         tgid = prev->tgid;
-         pid = prev->pid;
-         u64 ts = bpf_ktime_get_ns();
-@@ -178,7 +178,7 @@ RAW_TRACEPOINT_PROBE(sched_switch)
-     long state;
- 
-     // ivcsw: treat like an enqueue event and store timestamp
--    bpf_probe_read_kernel(&state, sizeof(long), (const void *)&prev->state);
-+    bpf_probe_read_kernel(&state, sizeof(long), (const void *)&prev->__state);
-     if (state == TASK_RUNNING) {
-         bpf_probe_read_kernel(&tgid, sizeof(prev->tgid), &prev->tgid);
-         bpf_probe_read_kernel(&pid, sizeof(prev->pid), &prev->pid);
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-Remove-APInt-APSInt-toString-std-string-variants.patch b/SOURCES/bcc-0.20.0-Remove-APInt-APSInt-toString-std-string-variants.patch
deleted file mode 100644
index 182209e..0000000
--- a/SOURCES/bcc-0.20.0-Remove-APInt-APSInt-toString-std-string-variants.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From fd0585d5d8a1a47912ae7a70721d3cab0c7d06f8 Mon Sep 17 00:00:00 2001
-From: Khem Raj <raj.khem@gmail.com>
-Date: Mon, 14 Jun 2021 12:49:43 -0700
-Subject: [PATCH] Remove APInt/APSInt toString() std::string variants
-
-clang 13+ has removed this in favour of a pair of llvm::toString
-() helpers inside StringExtras.h to improve compile speed by avoiding
-hits on <string> header
-
-Signed-off-by: Khem Raj <raj.khem@gmail.com>
----
- src/cc/json_map_decl_visitor.cc | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/src/cc/json_map_decl_visitor.cc b/src/cc/json_map_decl_visitor.cc
-index eff4d067..53896199 100644
---- a/src/cc/json_map_decl_visitor.cc
-+++ b/src/cc/json_map_decl_visitor.cc
-@@ -20,6 +20,7 @@
- #include <clang/AST/ASTContext.h>
- #include <clang/AST/RecordLayout.h>
- #include <clang/AST/RecursiveASTVisitor.h>
-+#include <llvm/ADT/StringExtras.h>
- #include "common.h"
- #include "table_desc.h"
- 
-@@ -79,7 +80,11 @@ void BMapDeclVisitor::genJSONForField(FieldDecl *F) {
-   result_ += "[";
-   TraverseDecl(F);
-   if (const ConstantArrayType *T = dyn_cast<ConstantArrayType>(F->getType()))
-+#if LLVM_MAJOR_VERSION >= 13
-+    result_ += ", [" + toString(T->getSize(), 10, false) + "]";
-+#else
-     result_ += ", [" + T->getSize().toString(10, false) + "]";
-+#endif
-   if (F->isBitField())
-     result_ += ", " + to_string(F->getBitWidthValue(C));
-   result_ += "], ";
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-Revert-libbpf-tools-remove-unecessary-custom-NULL-de.patch b/SOURCES/bcc-0.20.0-Revert-libbpf-tools-remove-unecessary-custom-NULL-de.patch
deleted file mode 100644
index 47cccef..0000000
--- a/SOURCES/bcc-0.20.0-Revert-libbpf-tools-remove-unecessary-custom-NULL-de.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From aaa39601b756074e9ba8b9a607102a1ae0cb4c94 Mon Sep 17 00:00:00 2001
-From: Jerome Marchand <jmarchan@redhat.com>
-Date: Mon, 26 Jul 2021 14:45:37 +0200
-Subject: [PATCH] Revert "libbpf-tools: remove unecessary custom NULL
- definitions"
-
-Libbpf on RHEL does not define NULL
-This reverts commit a9f461d74a84be2f96fd35c02cf98c7251bd4166.
----
- libbpf-tools/biostacks.bpf.c | 1 +
- libbpf-tools/xfsslower.bpf.c | 2 ++
- 2 files changed, 3 insertions(+)
-
-diff --git a/libbpf-tools/biostacks.bpf.c b/libbpf-tools/biostacks.bpf.c
-index f02a1ac5..6ed0bda6 100644
---- a/libbpf-tools/biostacks.bpf.c
-+++ b/libbpf-tools/biostacks.bpf.c
-@@ -9,6 +9,7 @@
- #include "maps.bpf.h"
- 
- #define MAX_ENTRIES	10240
-+#define NULL		0
- 
- const volatile bool targ_ms = false;
- const volatile dev_t targ_dev = -1;
-diff --git a/libbpf-tools/xfsslower.bpf.c b/libbpf-tools/xfsslower.bpf.c
-index 05962f46..2b1c6e4b 100644
---- a/libbpf-tools/xfsslower.bpf.c
-+++ b/libbpf-tools/xfsslower.bpf.c
-@@ -6,6 +6,8 @@
- #include <bpf/bpf_tracing.h>
- #include "xfsslower.h"
- 
-+#define NULL	0
-+
- const volatile pid_t targ_tgid = 0;
- const volatile __u64 min_lat = 0;
- 
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-Update-cpudist.py.patch b/SOURCES/bcc-0.20.0-Update-cpudist.py.patch
deleted file mode 100644
index 492c72f..0000000
--- a/SOURCES/bcc-0.20.0-Update-cpudist.py.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From ad56e8a5a722df2ac2a5b3ea0822fd78f9a6fe51 Mon Sep 17 00:00:00 2001
-From: Nick-nizhen <74173686+Nick-nizhen@users.noreply.github.com>
-Date: Thu, 27 May 2021 13:21:59 +0800
-Subject: [PATCH] Update cpudist.py
-
-When calculating the ONCPU  time, prev has left the CPU already. It is not necessary to judge whether the process state is TASK_RUNNING or not.
----
- tools/cpudist.py | 14 ++++----------
- 1 file changed, 4 insertions(+), 10 deletions(-)
-
-diff --git a/tools/cpudist.py b/tools/cpudist.py
-index eb04f590..b5a6a978 100755
---- a/tools/cpudist.py
-+++ b/tools/cpudist.py
-@@ -100,19 +100,13 @@ int sched_switch(struct pt_regs *ctx, struct task_struct *prev)
-     u64 pid_tgid = bpf_get_current_pid_tgid();
-     u32 tgid = pid_tgid >> 32, pid = pid_tgid;
- 
-+    u32 prev_pid = prev->pid;
-+    u32 prev_tgid = prev->tgid;
- #ifdef ONCPU
--    if (prev->state == TASK_RUNNING) {
-+    update_hist(prev_tgid, prev_pid, ts);
- #else
--    if (1) {
-+    store_start(prev_tgid, prev_pid, ts);
- #endif
--        u32 prev_pid = prev->pid;
--        u32 prev_tgid = prev->tgid;
--#ifdef ONCPU
--        update_hist(prev_tgid, prev_pid, ts);
--#else
--        store_start(prev_tgid, prev_pid, ts);
--#endif
--    }
- 
- BAIL:
- #ifdef ONCPU
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-biolatpcts-Build-fixes-on-recent-kernels.patch b/SOURCES/bcc-0.20.0-biolatpcts-Build-fixes-on-recent-kernels.patch
deleted file mode 100644
index 7eb8da6..0000000
--- a/SOURCES/bcc-0.20.0-biolatpcts-Build-fixes-on-recent-kernels.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-From 11614bcacdecd4d1f7015bb0f0311bb709207991 Mon Sep 17 00:00:00 2001
-From: Tejun Heo <tj@kernel.org>
-Date: Thu, 27 Jan 2022 06:25:31 -1000
-Subject: [PATCH] biolatpcts: Build fixes on recent kernels
-
-* `struct request` definition recently moved from blkdev.h to blk-mq.h
-  breaking both tools/biolatpcts and examples/tracing/biolatpcts. Fix them
-  by also including blk-mq.h.
-
-* blk_account_io_done() got split into two parts - inline condition checks
-  and the actual accounting with the latter now done in
-  __blk_account_io_done(). The kprobe attachment needs to be conditionalized
-  to work across the change. tools/biolatpcts was already updated but
-  examples/tracing/biolatpcts wasn't. Fix it.
-
-Signed-off-by: Tejun Heo <tj@kernel.org>
----
- examples/tracing/biolatpcts.py | 6 +++++-
- tools/biolatpcts.py            | 1 +
- 2 files changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/examples/tracing/biolatpcts.py b/examples/tracing/biolatpcts.py
-index c9bb834e..68a59516 100755
---- a/examples/tracing/biolatpcts.py
-+++ b/examples/tracing/biolatpcts.py
-@@ -11,6 +11,7 @@ from time import sleep
- 
- bpf_source = """
- #include <linux/blk_types.h>
-+#include <linux/blk-mq.h>
- #include <linux/blkdev.h>
- #include <linux/time64.h>
- 
-@@ -45,7 +46,10 @@ void kprobe_blk_account_io_done(struct pt_regs *ctx, struct request *rq, u64 now
- """
- 
- bpf = BPF(text=bpf_source)
--bpf.attach_kprobe(event='blk_account_io_done', fn_name='kprobe_blk_account_io_done')
-+if BPF.get_kprobe_functions(b'__blk_account_io_done'):
-+    bpf.attach_kprobe(event="__blk_account_io_done", fn_name="kprobe_blk_account_io_done")
-+else:
-+    bpf.attach_kprobe(event="blk_account_io_done", fn_name="kprobe_blk_account_io_done")
- 
- cur_lat_100ms = bpf['lat_100ms']
- cur_lat_1ms = bpf['lat_1ms']
-diff --git a/tools/biolatpcts.py b/tools/biolatpcts.py
-index a2f59592..0f334419 100755
---- a/tools/biolatpcts.py
-+++ b/tools/biolatpcts.py
-@@ -56,6 +56,7 @@ parser.add_argument('--verbose', '-v', action='count', default = 0)
- bpf_source = """
- #include <linux/blk_types.h>
- #include <linux/blkdev.h>
-+#include <linux/blk-mq.h>
- #include <linux/time64.h>
- 
- BPF_PERCPU_ARRAY(rwdf_100ms, u64, 400);
--- 
-2.35.1
-
diff --git a/SOURCES/bcc-0.20.0-libbpf-tool-don-t-ignore-LDFLAGS.patch b/SOURCES/bcc-0.20.0-libbpf-tool-don-t-ignore-LDFLAGS.patch
deleted file mode 100644
index 6f73a5c..0000000
--- a/SOURCES/bcc-0.20.0-libbpf-tool-don-t-ignore-LDFLAGS.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 657f1b2049f2c7751a9d2a13abb42c409da1bb6f Mon Sep 17 00:00:00 2001
-From: Jerome Marchand <jmarchan@redhat.com>
-Date: Wed, 2 Jun 2021 14:23:20 +0200
-Subject: [PATCH] libbpf-tool: don't ignore LDFLAGS
-
----
- libbpf-tools/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/libbpf-tools/Makefile b/libbpf-tools/Makefile
-index 92dcf5a5..54288380 100644
---- a/libbpf-tools/Makefile
-+++ b/libbpf-tools/Makefile
-@@ -77,7 +77,7 @@ endif
- 
- $(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(COMMON_OBJ) | $(OUTPUT)
- 	$(call msg,BINARY,$@)
--	$(Q)$(CC) $(CFLAGS) $^ -lelf -lz -o $@
-+	$(Q)$(CC) $(CFLAGS) $^ $(LDFLAGS) -lelf -lz -o $@
- 
- $(patsubst %,$(OUTPUT)/%.o,$(APPS)): %.o: %.skel.h
- 
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-libbpf-tools-readahead-don-t-mark-struct-hist-as-sta.patch b/SOURCES/bcc-0.20.0-libbpf-tools-readahead-don-t-mark-struct-hist-as-sta.patch
deleted file mode 100644
index 204865b..0000000
--- a/SOURCES/bcc-0.20.0-libbpf-tools-readahead-don-t-mark-struct-hist-as-sta.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 4e2851687904cff7ab4f8faa862b9046e5aaab09 Mon Sep 17 00:00:00 2001
-From: Jerome Marchand <jmarchan@redhat.com>
-Date: Fri, 30 Jul 2021 18:15:05 +0200
-Subject: [PATCH] libbpf-tools: readahead: don't mark struct hist as static
-
-Libbpf readahead tool does not compile with bpftool v5.14. Since
-commit 31332ccb756 ("bpftool: Stop emitting static variables in BPF
-skeleton"), bpftool gen skeleton does not include static variable into
-the skeleton file anymore.
-
-Fixes the following compilation error:
-readahead.c: In function 'main':
-readahead.c:153:26: error: 'struct readahead_bpf__bss' has no member named 'hist'
-  153 |         histp = &obj->bss->hist;
-      |                          ^~
----
- libbpf-tools/readahead.bpf.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/libbpf-tools/readahead.bpf.c b/libbpf-tools/readahead.bpf.c
-index ba22e534..cfead704 100644
---- a/libbpf-tools/readahead.bpf.c
-+++ b/libbpf-tools/readahead.bpf.c
-@@ -24,7 +24,7 @@ struct {
- 	__uint(map_flags, BPF_F_NO_PREALLOC);
- } birth SEC(".maps");
- 
--static struct hist hist;
-+struct hist hist = {};
- 
- SEC("fentry/do_page_cache_ra")
- int BPF_PROG(do_page_cache_ra)
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-sync-with-latest-libbpf-repo-3529.patch b/SOURCES/bcc-0.20.0-sync-with-latest-libbpf-repo-3529.patch
deleted file mode 100644
index 10765ef..0000000
--- a/SOURCES/bcc-0.20.0-sync-with-latest-libbpf-repo-3529.patch
+++ /dev/null
@@ -1,408 +0,0 @@
-From 0c12dfe26a362db181e6172cb56a39cd002a6892 Mon Sep 17 00:00:00 2001
-From: yonghong-song <yhs@fb.com>
-Date: Sun, 18 Jul 2021 15:05:34 -0700
-Subject: [PATCH] sync with latest libbpf repo (#3529)
-
-sync with latest libbpf repo which is upto commit
-  21f90f61b084 sync: latest libbpf changes from kernel
-
-Signed-off-by: Yonghong Song <yhs@fb.com>
----
- docs/kernel-versions.md           |   8 ++
- introspection/bps.c               |   1 +
- src/cc/compat/linux/virtual_bpf.h | 167 ++++++++++++++++++++++++++++--
- src/cc/export/helpers.h           |  17 +++
- src/cc/libbpf.c                   |   8 ++
- 5 files changed, 190 insertions(+), 11 deletions(-)
-
-diff --git a/docs/kernel-versions.md b/docs/kernel-versions.md
-index 9192aa43..33318624 100644
---- a/docs/kernel-versions.md
-+++ b/docs/kernel-versions.md
-@@ -208,6 +208,7 @@ Helper | Kernel version | License | Commit |
- -------|----------------|---------|--------|
- `BPF_FUNC_bind()` | 4.17 |  | [`d74bad4e74ee`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=d74bad4e74ee373787a9ae24197c17b7cdc428d5) |
- `BPF_FUNC_bprm_opts_set()` | 5.11 |  | [`3f6719c7b62f`](https://github.com/torvalds/linux/commit/3f6719c7b62f0327c9091e26d0da10e65668229e)
-+`BPF_FUNC_btf_find_by_name_kind()` | 5.14 |  | [`3d78417b60fb`](https://github.com/torvalds/linux/commit/3d78417b60fba249cc555468cb72d96f5cde2964)
- `BPF_FUNC_check_mtu()` | 5.12 |  | [`34b2021cc616`](https://github.com/torvalds/linux/commit/34b2021cc61642d61c3cf943d9e71925b827941b)
- `BPF_FUNC_clone_redirect()` | 4.2 |  | [`3896d655f4d4`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=3896d655f4d491c67d669a15f275a39f713410f8)
- `BPF_FUNC_copy_from_user()` | 5.10 |  | [`07be4c4a3e7a`](https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit?id=07be4c4a3e7a0db148e44b16c5190e753d1c8569)
-@@ -226,6 +227,7 @@ Helper | Kernel version | License | Commit |
- `BPF_FUNC_get_current_task()` | 4.8 | GPL | [`606274c5abd8`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=606274c5abd8e245add01bc7145a8cbb92b69ba8)
- `BPF_FUNC_get_current_task_btf()` | 5.11 | GPL | [`3ca1032ab7ab`](https://github.com/torvalds/linux/commit/3ca1032ab7ab010eccb107aa515598788f7d93bb)
- `BPF_FUNC_get_current_uid_gid()` | 4.2 |  | [`ffeedafbf023`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ffeedafbf0236f03aeb2e8db273b3e5ae5f5bc89)
-+`BPF_FUNC_get_func_ip()` | 5.15 |  | [`5d8b583d04ae`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=5d8b583d04aedb3bd5f6d227a334c210c7d735f9)
- `BPF_FUNC_get_hash_recalc()` | 4.8 |  | [`13c5c240f789`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=13c5c240f789bbd2bcacb14a23771491485ae61f)
- `BPF_FUNC_get_listener_sock()` | 5.1 |  | [`dbafd7ddd623`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/dbafd7ddd62369b2f3926ab847cbf8fc40e800b7)
- `BPF_FUNC_get_local_storage()` | 4.19 |  | [`cd3394317653`](https://github.com/torvalds/linux/commit/cd3394317653837e2eb5c5d0904a8996102af9fc)
-@@ -352,6 +354,8 @@ Helper | Kernel version | License | Commit |
- `BPF_FUNC_store_hdr_opt()` | 5.10 |  | [`0813a841566f`](https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit?id=0813a841566f0962a5551be7749b43c45f0022a0)
- `BPF_FUNC_strtol()` | 5.2 |  | [`d7a4cb9b6705`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/d7a4cb9b6705a89937d12c8158a35a3145dc967a)
- `BPF_FUNC_strtoul()` | 5.2 |  | [`d7a4cb9b6705`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/d7a4cb9b6705a89937d12c8158a35a3145dc967a)
-+`BPF_FUNC_sys_bpf()` | 5.14 |  | [`79a7f8bdb159`](https://github.com/torvalds/linux/commit/79a7f8bdb159d9914b58740f3d31d602a6e4aca8)
-+`BPF_FUNC_sys_close()` | 5.14 |  | [`3abea089246f`](https://github.com/torvalds/linux/commit/3abea089246f76c1517b054ddb5946f3f1dbd2c0)
- `BPF_FUNC_sysctl_get_current_value()` | 5.2 |  | [`1d11b3016cec`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/1d11b3016cec4ed9770b98e82a61708c8f4926e7)
- `BPF_FUNC_sysctl_get_name()` | 5.2 |  | [`808649fb787d`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/808649fb787d918a48a360a668ee4ee9023f0c11)
- `BPF_FUNC_sysctl_get_new_value()` | 5.2 |  | [`4e63acdff864`](https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/4e63acdff864654cee0ac5aaeda3913798ee78f6)
-@@ -364,6 +368,10 @@ Helper | Kernel version | License | Commit |
- `BPF_FUNC_tcp_send_ack()` | 5.5 | | [`206057fe020a`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=206057fe020ac5c037d5e2dd6562a9bd216ec765)
- `BPF_FUNC_tcp_sock()` | 5.1 |  | [`655a51e536c0`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=655a51e536c09d15ffa3603b1b6fce2b45b85a1f)
- `BPF_FUNC_this_cpu_ptr()` | 5.10 |  | [`63d9b80dcf2c`](https://github.com/torvalds/linux/commit/63d9b80dcf2c67bc5ade61cbbaa09d7af21f43f1) |
-+`BPF_FUNC_timer_init()` | 5.15 |  | [`b00628b1c7d5`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=b00628b1c7d595ae5b544e059c27b1f5828314b4)
-+`BPF_FUNC_timer_set_callback()` | 5.15 |  | [`b00628b1c7d5`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=b00628b1c7d595ae5b544e059c27b1f5828314b4)
-+`BPF_FUNC_timer_start()` | 5.15 |  | [`b00628b1c7d5`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=b00628b1c7d595ae5b544e059c27b1f5828314b4)
-+`BPF_FUNC_timer_cancel()` | 5.15 |  | [`b00628b1c7d5`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=b00628b1c7d595ae5b544e059c27b1f5828314b4)
- `BPF_FUNC_trace_printk()` | 4.1 | GPL | [`9c959c863f82`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=9c959c863f8217a2ff3d7c296e8223654d240569)
- `BPF_FUNC_xdp_adjust_head()` | 4.10 |  | [`17bedab27231`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=17bedab2723145d17b14084430743549e6943d03)
- `BPF_FUNC_xdp_adjust_meta()` | 4.15 |  | [`de8f3a83b0a0`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=de8f3a83b0a0fddb2cf56e7a718127e9619ea3da)
-diff --git a/introspection/bps.c b/introspection/bps.c
-index e92da3f6..25a88cbd 100644
---- a/introspection/bps.c
-+++ b/introspection/bps.c
-@@ -47,6 +47,7 @@ static const char * const prog_type_strings[] = {
-   [BPF_PROG_TYPE_EXT] = "ext",
-   [BPF_PROG_TYPE_LSM] = "lsm",
-   [BPF_PROG_TYPE_SK_LOOKUP] = "sk_lookup",
-+  [BPF_PROG_TYPE_SYSCALL] = "syscall",
- };
- 
- static const char * const map_type_strings[] = {
-diff --git a/src/cc/compat/linux/virtual_bpf.h b/src/cc/compat/linux/virtual_bpf.h
-index 3490bc14..bf4bc3a6 100644
---- a/src/cc/compat/linux/virtual_bpf.h
-+++ b/src/cc/compat/linux/virtual_bpf.h
-@@ -325,9 +325,6 @@ union bpf_iter_link_info {
-  *		**BPF_PROG_TYPE_SK_LOOKUP**
-  *			*data_in* and *data_out* must be NULL.
-  *
-- *		**BPF_PROG_TYPE_XDP**
-- *			*ctx_in* and *ctx_out* must be NULL.
-- *
-  *		**BPF_PROG_TYPE_RAW_TRACEPOINT**,
-  *		**BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE**
-  *
-@@ -528,6 +525,15 @@ union bpf_iter_link_info {
-  *		Look up an element with the given *key* in the map referred to
-  *		by the file descriptor *fd*, and if found, delete the element.
-  *
-+ *		For **BPF_MAP_TYPE_QUEUE** and **BPF_MAP_TYPE_STACK** map
-+ *		types, the *flags* argument needs to be set to 0, but for other
-+ *		map types, it may be specified as:
-+ *
-+ *		**BPF_F_LOCK**
-+ *			Look up and delete the value of a spin-locked map
-+ *			without returning the lock. This must be specified if
-+ *			the elements contain a spinlock.
-+ *
-  *		The **BPF_MAP_TYPE_QUEUE** and **BPF_MAP_TYPE_STACK** map types
-  *		implement this command as a "pop" operation, deleting the top
-  *		element rather than one corresponding to *key*.
-@@ -537,6 +543,10 @@ union bpf_iter_link_info {
-  *		This command is only valid for the following map types:
-  *		* **BPF_MAP_TYPE_QUEUE**
-  *		* **BPF_MAP_TYPE_STACK**
-+ *		* **BPF_MAP_TYPE_HASH**
-+ *		* **BPF_MAP_TYPE_PERCPU_HASH**
-+ *		* **BPF_MAP_TYPE_LRU_HASH**
-+ *		* **BPF_MAP_TYPE_LRU_PERCPU_HASH**
-  *
-  *	Return
-  *		Returns zero on success. On error, -1 is returned and *errno*
-@@ -838,6 +848,7 @@ enum bpf_cmd {
- 	BPF_PROG_ATTACH,
- 	BPF_PROG_DETACH,
- 	BPF_PROG_TEST_RUN,
-+	BPF_PROG_RUN = BPF_PROG_TEST_RUN,
- 	BPF_PROG_GET_NEXT_ID,
- 	BPF_MAP_GET_NEXT_ID,
- 	BPF_PROG_GET_FD_BY_ID,
-@@ -938,6 +949,7 @@ enum bpf_prog_type {
- 	BPF_PROG_TYPE_EXT,
- 	BPF_PROG_TYPE_LSM,
- 	BPF_PROG_TYPE_SK_LOOKUP,
-+	BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
- };
- 
- enum bpf_attach_type {
-@@ -980,6 +992,8 @@ enum bpf_attach_type {
- 	BPF_SK_LOOKUP,
- 	BPF_XDP,
- 	BPF_SK_SKB_VERDICT,
-+	BPF_SK_REUSEPORT_SELECT,
-+	BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
- 	__MAX_BPF_ATTACH_TYPE
- };
- 
-@@ -1098,8 +1112,8 @@ enum bpf_link_type {
- /* When BPF ldimm64's insn[0].src_reg != 0 then this can have
-  * the following extensions:
-  *
-- * insn[0].src_reg:  BPF_PSEUDO_MAP_FD
-- * insn[0].imm:      map fd
-+ * insn[0].src_reg:  BPF_PSEUDO_MAP_[FD|IDX]
-+ * insn[0].imm:      map fd or fd_idx
-  * insn[1].imm:      0
-  * insn[0].off:      0
-  * insn[1].off:      0
-@@ -1107,15 +1121,19 @@ enum bpf_link_type {
-  * verifier type:    CONST_PTR_TO_MAP
-  */
- #define BPF_PSEUDO_MAP_FD	1
--/* insn[0].src_reg:  BPF_PSEUDO_MAP_VALUE
-- * insn[0].imm:      map fd
-+#define BPF_PSEUDO_MAP_IDX	5
-+
-+/* insn[0].src_reg:  BPF_PSEUDO_MAP_[IDX_]VALUE
-+ * insn[0].imm:      map fd or fd_idx
-  * insn[1].imm:      offset into value
-  * insn[0].off:      0
-  * insn[1].off:      0
-  * ldimm64 rewrite:  address of map[0]+offset
-  * verifier type:    PTR_TO_MAP_VALUE
-  */
--#define BPF_PSEUDO_MAP_VALUE	2
-+#define BPF_PSEUDO_MAP_VALUE		2
-+#define BPF_PSEUDO_MAP_IDX_VALUE	6
-+
- /* insn[0].src_reg:  BPF_PSEUDO_BTF_ID
-  * insn[0].imm:      kernel btd id of VAR
-  * insn[1].imm:      0
-@@ -1315,6 +1333,8 @@ union bpf_attr {
- 			/* or valid module BTF object fd or 0 to attach to vmlinux */
- 			__u32		attach_btf_obj_fd;
- 		};
-+		__u32		:32;		/* pad */
-+		__aligned_u64	fd_array;	/* array of FDs */
- 	};
- 
- 	struct { /* anonymous struct used by BPF_OBJ_* commands */
-@@ -2535,8 +2555,12 @@ union bpf_attr {
-  * 		The lower two bits of *flags* are used as the return code if
-  * 		the map lookup fails. This is so that the return value can be
-  * 		one of the XDP program return codes up to **XDP_TX**, as chosen
-- * 		by the caller. Any higher bits in the *flags* argument must be
-- * 		unset.
-+ * 		by the caller. The higher bits of *flags* can be set to
-+ * 		BPF_F_BROADCAST or BPF_F_EXCLUDE_INGRESS as defined below.
-+ *
-+ * 		With BPF_F_BROADCAST the packet will be broadcasted to all the
-+ * 		interfaces in the map, with BPF_F_EXCLUDE_INGRESS the ingress
-+ * 		interface will be excluded when do broadcasting.
-  *
-  * 		See also **bpf_redirect**\ (), which only supports redirecting
-  * 		to an ifindex, but doesn't require a map to do so.
-@@ -3223,7 +3247,7 @@ union bpf_attr {
-  * long bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags)
-  *	Description
-  *		Select a **SO_REUSEPORT** socket from a
-- *		**BPF_MAP_TYPE_REUSEPORT_ARRAY** *map*.
-+ *		**BPF_MAP_TYPE_REUSEPORT_SOCKARRAY** *map*.
-  *		It checks the selected socket is matching the incoming
-  *		request in the socket buffer.
-  *	Return
-@@ -4736,6 +4760,94 @@ union bpf_attr {
-  *		be zero-terminated except when **str_size** is 0.
-  *
-  *		Or **-EBUSY** if the per-CPU memory copy buffer is busy.
-+ *
-+ * long bpf_sys_bpf(u32 cmd, void *attr, u32 attr_size)
-+ * 	Description
-+ * 		Execute bpf syscall with given arguments.
-+ * 	Return
-+ * 		A syscall result.
-+ *
-+ * long bpf_btf_find_by_name_kind(char *name, int name_sz, u32 kind, int flags)
-+ * 	Description
-+ * 		Find BTF type with given name and kind in vmlinux BTF or in module's BTFs.
-+ * 	Return
-+ * 		Returns btf_id and btf_obj_fd in lower and upper 32 bits.
-+ *
-+ * long bpf_sys_close(u32 fd)
-+ * 	Description
-+ * 		Execute close syscall for given FD.
-+ * 	Return
-+ * 		A syscall result.
-+ *
-+ * long bpf_timer_init(struct bpf_timer *timer, struct bpf_map *map, u64 flags)
-+ *	Description
-+ *		Initialize the timer.
-+ *		First 4 bits of *flags* specify clockid.
-+ *		Only CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_BOOTTIME are allowed.
-+ *		All other bits of *flags* are reserved.
-+ *		The verifier will reject the program if *timer* is not from
-+ *		the same *map*.
-+ *	Return
-+ *		0 on success.
-+ *		**-EBUSY** if *timer* is already initialized.
-+ *		**-EINVAL** if invalid *flags* are passed.
-+ *		**-EPERM** if *timer* is in a map that doesn't have any user references.
-+ *		The user space should either hold a file descriptor to a map with timers
-+ *		or pin such map in bpffs. When map is unpinned or file descriptor is
-+ *		closed all timers in the map will be cancelled and freed.
-+ *
-+ * long bpf_timer_set_callback(struct bpf_timer *timer, void *callback_fn)
-+ *	Description
-+ *		Configure the timer to call *callback_fn* static function.
-+ *	Return
-+ *		0 on success.
-+ *		**-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.
-+ *		**-EPERM** if *timer* is in a map that doesn't have any user references.
-+ *		The user space should either hold a file descriptor to a map with timers
-+ *		or pin such map in bpffs. When map is unpinned or file descriptor is
-+ *		closed all timers in the map will be cancelled and freed.
-+ *
-+ * long bpf_timer_start(struct bpf_timer *timer, u64 nsecs, u64 flags)
-+ *	Description
-+ *		Set timer expiration N nanoseconds from the current time. The
-+ *		configured callback will be invoked in soft irq context on some cpu
-+ *		and will not repeat unless another bpf_timer_start() is made.
-+ *		In such case the next invocation can migrate to a different cpu.
-+ *		Since struct bpf_timer is a field inside map element the map
-+ *		owns the timer. The bpf_timer_set_callback() will increment refcnt
-+ *		of BPF program to make sure that callback_fn code stays valid.
-+ *		When user space reference to a map reaches zero all timers
-+ *		in a map are cancelled and corresponding program's refcnts are
-+ *		decremented. This is done to make sure that Ctrl-C of a user
-+ *		process doesn't leave any timers running. If map is pinned in
-+ *		bpffs the callback_fn can re-arm itself indefinitely.
-+ *		bpf_map_update/delete_elem() helpers and user space sys_bpf commands
-+ *		cancel and free the timer in the given map element.
-+ *		The map can contain timers that invoke callback_fn-s from different
-+ *		programs. The same callback_fn can serve different timers from
-+ *		different maps if key/value layout matches across maps.
-+ *		Every bpf_timer_set_callback() can have different callback_fn.
-+ *
-+ *	Return
-+ *		0 on success.
-+ *		**-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier
-+ *		or invalid *flags* are passed.
-+ *
-+ * long bpf_timer_cancel(struct bpf_timer *timer)
-+ *	Description
-+ *		Cancel the timer and wait for callback_fn to finish if it was running.
-+ *	Return
-+ *		0 if the timer was not active.
-+ *		1 if the timer was active.
-+ *		**-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.
-+ *		**-EDEADLK** if callback_fn tried to call bpf_timer_cancel() on its
-+ *		own timer which would have led to a deadlock otherwise.
-+ *
-+ * u64 bpf_get_func_ip(void *ctx)
-+ * 	Description
-+ * 		Get address of the traced function (for tracing and kprobe programs).
-+ * 	Return
-+ * 		Address of the traced function.
-  */
- #define __BPF_FUNC_MAPPER(FN)		\
- 	FN(unspec),			\
-@@ -4904,6 +5016,14 @@ union bpf_attr {
- 	FN(check_mtu),			\
- 	FN(for_each_map_elem),		\
- 	FN(snprintf),			\
-+	FN(sys_bpf),			\
-+	FN(btf_find_by_name_kind),	\
-+	FN(sys_close),			\
-+	FN(timer_init),			\
-+	FN(timer_set_callback),		\
-+	FN(timer_start),		\
-+	FN(timer_cancel),		\
-+	FN(get_func_ip),		\
- 	/* */
- 
- /* integer value in 'imm' field of BPF_CALL instruction selects which helper
-@@ -5081,6 +5201,12 @@ enum {
- 	BPF_F_BPRM_SECUREEXEC	= (1ULL << 0),
- };
- 
-+/* Flags for bpf_redirect_map helper */
-+enum {
-+	BPF_F_BROADCAST		= (1ULL << 3),
-+	BPF_F_EXCLUDE_INGRESS	= (1ULL << 4),
-+};
-+
- #define __bpf_md_ptr(type, name)	\
- union {					\
- 	type name;			\
-@@ -5365,6 +5491,20 @@ struct sk_reuseport_md {
- 	__u32 ip_protocol;	/* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */
- 	__u32 bind_inany;	/* Is sock bound to an INANY address? */
- 	__u32 hash;		/* A hash of the packet 4 tuples */
-+	/* When reuse->migrating_sk is NULL, it is selecting a sk for the
-+	 * new incoming connection request (e.g. selecting a listen sk for
-+	 * the received SYN in the TCP case).  reuse->sk is one of the sk
-+	 * in the reuseport group. The bpf prog can use reuse->sk to learn
-+	 * the local listening ip/port without looking into the skb.
-+	 *
-+	 * When reuse->migrating_sk is not NULL, reuse->sk is closed and
-+	 * reuse->migrating_sk is the socket that needs to be migrated
-+	 * to another listening socket.  migrating_sk could be a fullsock
-+	 * sk that is fully established or a reqsk that is in-the-middle
-+	 * of 3-way handshake.
-+	 */
-+	__bpf_md_ptr(struct bpf_sock *, sk);
-+	__bpf_md_ptr(struct bpf_sock *, migrating_sk);
- };
- 
- #define BPF_TAG_SIZE	8
-@@ -6010,6 +6150,11 @@ struct bpf_spin_lock {
- 	__u32	val;
- };
- 
-+struct bpf_timer {
-+	__u64 :64;
-+	__u64 :64;
-+} __attribute__((aligned(8)));
-+
- struct bpf_sysctl {
- 	__u32	write;		/* Sysctl is being read (= 0) or written (= 1).
- 				 * Allows 1,2,4-byte read, but no write.
-diff --git a/src/cc/export/helpers.h b/src/cc/export/helpers.h
-index e9137f7f..a4e9b705 100644
---- a/src/cc/export/helpers.h
-+++ b/src/cc/export/helpers.h
-@@ -847,6 +847,23 @@ static long (*bpf_snprintf)(char *str, __u32 str_size, const char *fmt,
-                             __u64 *data, __u32 data_len) =
-   (void *)BPF_FUNC_snprintf;
- 
-+static long (*bpf_sys_bpf)(__u32 cmd, void *attr, __u32 attr_size) =
-+  (void *)BPF_FUNC_sys_bpf;
-+static long (*bpf_btf_find_by_name_kind)(char *name, int name_sz, __u32 kind, int flags) =
-+  (void *)BPF_FUNC_btf_find_by_name_kind;
-+static long (*bpf_sys_close)(__u32 fd) = (void *)BPF_FUNC_sys_close;
-+
-+struct bpf_timer;
-+static long (*bpf_timer_init)(struct bpf_timer *timer, void *map, __u64 flags) =
-+  (void *)BPF_FUNC_timer_init;
-+static long (*bpf_timer_set_callback)(struct bpf_timer *timer, void *callback_fn) =
-+  (void *)BPF_FUNC_timer_set_callback;
-+static long (*bpf_timer_start)(struct bpf_timer *timer, __u64 nsecs, __u64 flags) =
-+  (void *)BPF_FUNC_timer_start;
-+static long (*bpf_timer_cancel)(struct bpf_timer *timer) = (void *)BPF_FUNC_timer_cancel;
-+
-+static __u64 (*bpf_get_func_ip)(void *ctx) = (void *)BPF_FUNC_get_func_ip;
-+
- /* llvm builtin functions that eBPF C program may use to
-  * emit BPF_LD_ABS and BPF_LD_IND instructions
-  */
-diff --git a/src/cc/libbpf.c b/src/cc/libbpf.c
-index b83d68fd..f3608cfe 100644
---- a/src/cc/libbpf.c
-+++ b/src/cc/libbpf.c
-@@ -270,6 +270,14 @@ static struct bpf_helper helpers[] = {
-   {"check_mtu", "5.12"},
-   {"for_each_map_elem", "5.13"},
-   {"snprintf", "5.13"},
-+  {"sys_bpf", "5.14"},
-+  {"btf_find_by_name_kind", "5.14"},
-+  {"sys_close", "5.14"},
-+  {"timer_init", "5.15"},
-+  {"timer_set_callback", "5.15"},
-+  {"timer_start", "5.15"},
-+  {"timer_cancel", "5.15"},
-+  {"get_func_ip", "5.15"},
- };
- 
- static uint64_t ptr_to_u64(void *ptr)
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-threadsnoop-look-for-pthread_create-in-libc-too.patch b/SOURCES/bcc-0.20.0-threadsnoop-look-for-pthread_create-in-libc-too.patch
deleted file mode 100644
index 2170eb8..0000000
--- a/SOURCES/bcc-0.20.0-threadsnoop-look-for-pthread_create-in-libc-too.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 460a71ab24ad511318342077ac9ef57df543375f Mon Sep 17 00:00:00 2001
-From: Jerome Marchand <jmarchan@redhat.com>
-Date: Thu, 16 Sep 2021 14:44:23 +0200
-Subject: [PATCH] threadsnoop: look for pthread_create in libc too
-
-Since glibc 2.34, pthread features are integrated in libc directly.
-Look for pthread_create there too when it is not found in libpthread.
-
-Fixes #3623
----
- tools/threadsnoop.py | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/tools/threadsnoop.py b/tools/threadsnoop.py
-index 04c5e680..471b0c3c 100755
---- a/tools/threadsnoop.py
-+++ b/tools/threadsnoop.py
-@@ -38,7 +38,12 @@ void do_entry(struct pt_regs *ctx) {
-     events.perf_submit(ctx, &data, sizeof(data));
- };
- """)
--b.attach_uprobe(name="pthread", sym="pthread_create", fn_name="do_entry")
-+
-+# Since version 2.34, pthread features are integrated in libc
-+try:
-+    b.attach_uprobe(name="pthread", sym="pthread_create", fn_name="do_entry")
-+except Exception:
-+    b.attach_uprobe(name="c", sym="pthread_create", fn_name="do_entry")
- 
- print("%-10s %-6s %-16s %s" % ("TIME(ms)", "PID", "COMM", "FUNC"))
- 
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.20.0-tools-Fix-BCC-bio-tools-with-recent-kernel-change.patch b/SOURCES/bcc-0.20.0-tools-Fix-BCC-bio-tools-with-recent-kernel-change.patch
deleted file mode 100644
index 428499d..0000000
--- a/SOURCES/bcc-0.20.0-tools-Fix-BCC-bio-tools-with-recent-kernel-change.patch
+++ /dev/null
@@ -1,119 +0,0 @@
-From 59a4e7ea490f78ba289c1ba461bfe1fce9e7ef19 Mon Sep 17 00:00:00 2001
-From: Hengqi Chen <chenhengqi@outlook.com>
-Date: Sat, 11 Dec 2021 17:36:17 +0800
-Subject: [PATCH] tools: Fix BCC bio tools with recent kernel change
-
-Several BCC bio tools are broken due to kernel change ([0]).
-blk_account_io_{start, done} were renamed to __blk_account_io_{start, done},
-and the symbols gone from /proc/kallsyms. Fix them by checking symbol existence.
-
-  [0]: https://github.com/torvalds/linux/commit/be6bfe36db1795babe9d92178a47b2e02193cb0f
-
-Signed-off-by: Hengqi Chen <chenhengqi@outlook.com>
----
- tools/biolatency.py | 12 ++++++++----
- tools/biolatpcts.py |  5 ++++-
- tools/biosnoop.py   | 11 ++++++++---
- tools/biotop.py     | 11 ++++++++---
- 4 files changed, 28 insertions(+), 11 deletions(-)
-
-diff --git a/tools/biolatency.py b/tools/biolatency.py
-index 0599609b..2e75a5de 100755
---- a/tools/biolatency.py
-+++ b/tools/biolatency.py
-@@ -168,13 +168,18 @@ bpf_text = bpf_text.replace("STORE", store_str)
- # load BPF program
- b = BPF(text=bpf_text)
- if args.queued:
--    b.attach_kprobe(event="blk_account_io_start", fn_name="trace_req_start")
-+    if BPF.get_kprobe_functions(b'__blk_account_io_start'):
-+        b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_req_start")
-+    else:
-+        b.attach_kprobe(event="blk_account_io_start", fn_name="trace_req_start")
- else:
-     if BPF.get_kprobe_functions(b'blk_start_request'):
-         b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start")
-     b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start")
--b.attach_kprobe(event="blk_account_io_done",
--    fn_name="trace_req_done")
-+if BPF.get_kprobe_functions(b'__blk_account_io_done'):
-+    b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_done")
-+else:
-+    b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_done")
- 
- if not args.json:
-     print("Tracing block device I/O... Hit Ctrl-C to end.")
-@@ -277,4 +282,3 @@ dist = b.get_table("dist")
-     countdown -= 1
-     if exiting or countdown == 0:
-         exit()
--
-diff --git a/tools/biolatpcts.py b/tools/biolatpcts.py
-index 5ab8aa5f..a2f59592 100755
---- a/tools/biolatpcts.py
-+++ b/tools/biolatpcts.py
-@@ -142,7 +142,10 @@ bpf_source = bpf_source.replace('__MAJOR__', str(major))
- bpf_source = bpf_source.replace('__MINOR__', str(minor))
- 
- bpf = BPF(text=bpf_source)
--bpf.attach_kprobe(event="blk_account_io_done", fn_name="kprobe_blk_account_io_done")
-+if BPF.get_kprobe_functions(b'__blk_account_io_done'):
-+    bpf.attach_kprobe(event="__blk_account_io_done", fn_name="kprobe_blk_account_io_done")
-+else:
-+    bpf.attach_kprobe(event="blk_account_io_done", fn_name="kprobe_blk_account_io_done")
- 
- # times are in usecs
- MSEC = 1000
-diff --git a/tools/biosnoop.py b/tools/biosnoop.py
-index 333949b5..2b954ac9 100755
---- a/tools/biosnoop.py
-+++ b/tools/biosnoop.py
-@@ -163,12 +163,17 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req)
- 
- # initialize BPF
- b = BPF(text=bpf_text)
--b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start")
-+if BPF.get_kprobe_functions(b'__blk_account_io_start'):
-+    b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start")
-+else:
-+    b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start")
- if BPF.get_kprobe_functions(b'blk_start_request'):
-     b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start")
- b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start")
--b.attach_kprobe(event="blk_account_io_done",
--    fn_name="trace_req_completion")
-+if BPF.get_kprobe_functions(b'__blk_account_io_done'):
-+    b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_completion")
-+else:
-+    b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_completion")
- 
- # header
- print("%-11s %-14s %-6s %-7s %-1s %-10s %-7s" % ("TIME(s)", "COMM", "PID",
-diff --git a/tools/biotop.py b/tools/biotop.py
-index 596f0076..0ebfef0e 100755
---- a/tools/biotop.py
-+++ b/tools/biotop.py
-@@ -180,12 +180,17 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req)
-     exit()
- 
- b = BPF(text=bpf_text)
--b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start")
-+if BPF.get_kprobe_functions(b'__blk_account_io_start'):
-+    b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start")
-+else:
-+    b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start")
- if BPF.get_kprobe_functions(b'blk_start_request'):
-     b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start")
- b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start")
--b.attach_kprobe(event="blk_account_io_done",
--    fn_name="trace_req_completion")
-+if BPF.get_kprobe_functions(b'__blk_account_io_done'):
-+    b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_completion")
-+else:
-+    b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_completion")
- 
- print('Tracing... Output every %d secs. Hit Ctrl-C to end' % interval)
- 
--- 
-2.35.1
-
diff --git a/SOURCES/bcc-0.20.0-tools-include-blk-mq.h-in-bio-tools.patch b/SOURCES/bcc-0.20.0-tools-include-blk-mq.h-in-bio-tools.patch
deleted file mode 100644
index 03e703f..0000000
--- a/SOURCES/bcc-0.20.0-tools-include-blk-mq.h-in-bio-tools.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-From ee81072e75bcc796b1154c315e2eb0371928a922 Mon Sep 17 00:00:00 2001
-From: Jerome Marchand <jmarchan@redhat.com>
-Date: Wed, 23 Feb 2022 16:04:30 +0100
-Subject: [PATCH] tools: include blk-mq.h in bio tools
-
-Kernel commit 24b83deb29b ("block: move struct request to blk-mq.h")
-has moved struct request  from blkdev.h to blk-mq.h. It results in
-several bio tools to fail with errors of the following type:
-
-error: incomplete definition of type 'struct request'
-
-Since blk-mq.h had always included blkdev.h. it is safe to simply
-replace the inclusion of blkdev.h by blk-mq-h. It works on both older
-and newer kernel.
-
-Fixes: #3869
-
-Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
----
- tools/biolatency.py | 2 +-
- tools/biosnoop.py   | 2 +-
- tools/biotop.py     | 2 +-
- 3 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/tools/biolatency.py b/tools/biolatency.py
-index f4e2c9ea..427cee47 100755
---- a/tools/biolatency.py
-+++ b/tools/biolatency.py
-@@ -64,7 +64,7 @@ debug = 0
- # define BPF program
- bpf_text = """
- #include <uapi/linux/ptrace.h>
--#include <linux/blkdev.h>
-+#include <linux/blk-mq.h>
- 
- typedef struct disk_key {
-     char disk[DISK_NAME_LEN];
-diff --git a/tools/biosnoop.py b/tools/biosnoop.py
-index 2b954ac9..ae38e384 100755
---- a/tools/biosnoop.py
-+++ b/tools/biosnoop.py
-@@ -37,7 +37,7 @@ debug = 0
- # define BPF program
- bpf_text="""
- #include <uapi/linux/ptrace.h>
--#include <linux/blkdev.h>
-+#include <linux/blk-mq.h>
- 
- // for saving the timestamp and __data_len of each request
- struct start_req_t {
-diff --git a/tools/biotop.py b/tools/biotop.py
-index eac4dab9..b3e3ea00 100755
---- a/tools/biotop.py
-+++ b/tools/biotop.py
-@@ -54,7 +54,7 @@ diskstats = "/proc/diskstats"
- # load BPF program
- bpf_text = """
- #include <uapi/linux/ptrace.h>
--#include <linux/blkdev.h>
-+#include <linux/blk-mq.h>
- 
- // for saving the timestamp and __data_len of each request
- struct start_req_t {
--- 
-2.35.1
-
diff --git a/SOURCES/bcc-0.20.0-tools-readahead-compatible-with-kernel-version-5.10-.patch b/SOURCES/bcc-0.20.0-tools-readahead-compatible-with-kernel-version-5.10-.patch
deleted file mode 100644
index b658d56..0000000
--- a/SOURCES/bcc-0.20.0-tools-readahead-compatible-with-kernel-version-5.10-.patch
+++ /dev/null
@@ -1,109 +0,0 @@
-From 6c9d91c2196e69682a611dbfc10a0731f86deada Mon Sep 17 00:00:00 2001
-From: zcy <zcy.chenyue.zhou@gmail.com>
-Date: Fri, 25 Jun 2021 10:16:53 +0800
-Subject: [PATCH] tools/readahead compatible with kernel version >= 5.10
- (#3507)
-
-After kernel version 5.10, __do_page_cache_readahead() was renamed to do_page_cache_ra(),
-let us try both in readahead.py.
----
- tools/readahead.py          | 12 ++++++++----
- tools/readahead_example.txt | 22 +++++++++++-----------
- 2 files changed, 19 insertions(+), 15 deletions(-)
-
-diff --git a/tools/readahead.py b/tools/readahead.py
-index 14182d5a..b338261f 100755
---- a/tools/readahead.py
-+++ b/tools/readahead.py
-@@ -20,7 +20,7 @@ import argparse
- 
- # arguments
- examples = """examples:
--    ./readahead -d 20       # monitor for 10 seconds and generate stats 
-+    ./readahead -d 20       # monitor for 20 seconds and generate stats
- """
- 
- parser = argparse.ArgumentParser(
-@@ -95,15 +95,19 @@ int entry_mark_page_accessed(struct pt_regs *ctx) {
- """
- 
- b = BPF(text=program)
--b.attach_kprobe(event="__do_page_cache_readahead", fn_name="entry__do_page_cache_readahead")
--b.attach_kretprobe(event="__do_page_cache_readahead", fn_name="exit__do_page_cache_readahead")
-+if BPF.get_kprobe_functions(b"__do_page_cache_readahead"):
-+    ra_event = "__do_page_cache_readahead"
-+else:
-+    ra_event = "do_page_cache_ra"
-+b.attach_kprobe(event=ra_event, fn_name="entry__do_page_cache_readahead")
-+b.attach_kretprobe(event=ra_event, fn_name="exit__do_page_cache_readahead")
- b.attach_kretprobe(event="__page_cache_alloc", fn_name="exit__page_cache_alloc")
- b.attach_kprobe(event="mark_page_accessed", fn_name="entry_mark_page_accessed")
- 
- # header
- print("Tracing... Hit Ctrl-C to end.")
- 
--# print 
-+# print
- def print_stats():
-     print()
-     print("Read-ahead unused pages: %d" % (b["pages"][ct.c_ulong(0)].value))
-diff --git a/tools/readahead_example.txt b/tools/readahead_example.txt
-index 079dbaae..6d675c13 100644
---- a/tools/readahead_example.txt
-+++ b/tools/readahead_example.txt
-@@ -2,20 +2,20 @@ Demonstration of readahead, the Linux eBPF/bcc version
- 
- Read-ahead mechanism is used by operation sytems to optimize sequential operations
- by reading ahead some pages to avoid more expensive filesystem operations. This tool
--shows the performance of the read-ahead caching on the system under a given load to 
-+shows the performance of the read-ahead caching on the system under a given load to
- investigate any caching issues. It shows a count for unused pages in the cache and
- also prints a histogram showing how long they have remianed there.
- 
- Usage Scenario
- ==============
- 
--Consider that you are developing a React Native application which performs aggressive 
-+Consider that you are developing a React Native application which performs aggressive
- reads while re-encoding a video in local-storage. Usually such an app would be multi-
--layered and have transitional library dependencies. The actual read may be performed 
--by some unknown native library which may or may not be using hints to the OS, such as  
--madvise(p, LEN, MADV_SEQUENTIAL). If high IOPS is observed in such an app, running 
--readahead may pin the issue much faster in this case as the developer digs deeper 
--into what may be causing this. 
-+layered and have transitional library dependencies. The actual read may be performed
-+by some unknown native library which may or may not be using hints to the OS, such as
-+madvise(p, LEN, MADV_SEQUENTIAL). If high IOPS is observed in such an app, running
-+readahead may pin the issue much faster in this case as the developer digs deeper
-+into what may be causing this.
- 
- An example where such an issue can surface is: https://github.com/boltdb/bolt/issues/691
- 
-@@ -40,7 +40,7 @@ Read-ahead unused pages: 6765
-       2048 -> 4095       : 439      |****                                    |
-       4096 -> 8191       : 188      |*                                       |
- 
--In the example above, we recorded system-wide stats for 30 seconds. We can observe that 
-+In the example above, we recorded system-wide stats for 30 seconds. We can observe that
- while most of the pages stayed in the readahead cache for quite less time, after 30
- seconds 6765 pages still remained in the cache, yet unaccessed.
- 
-@@ -49,12 +49,12 @@ Note on Kprobes Usage
- 
- This tool uses Kprobes on the following kernel functions:
- 
--__do_page_cache_readahead()
-+__do_page_cache_readahead()/do_page_cache_ra() (After kernel version 5.10 (include), __do_page_cache_readahead was renamed to do_page_cache_ra)
- __page_cache_alloc()
- mark_page_accessed()
- 
--Since the tool uses Kprobes, depending on your linux kernel's compilation, these 
--functions may be inlined and hence not available for Kprobes. To see whether you have 
-+Since the tool uses Kprobes, depending on your linux kernel's compilation, these
-+functions may be inlined and hence not available for Kprobes. To see whether you have
- the functions available, check vmlinux source and binary to confirm whether inlining is
- happening or not. You can also check /proc/kallsyms on the host and verify if the target
- functions are present there before using this tool.
--- 
-2.31.1
-
diff --git a/SOURCES/bcc-0.24.0-C9S-Fix-mdflush.patch b/SOURCES/bcc-0.24.0-C9S-Fix-mdflush.patch
new file mode 100644
index 0000000..716789e
--- /dev/null
+++ b/SOURCES/bcc-0.24.0-C9S-Fix-mdflush.patch
@@ -0,0 +1,44 @@
+From 5e7543d35596fabd9e5b02b58f8910bf572ca2fa Mon Sep 17 00:00:00 2001
+From: Jerome Marchand <jmarchan@redhat.com>
+Date: Thu, 7 Oct 2021 17:31:53 +0200
+Subject: [PATCH] C9S: Fix mdflush
+
+Since kernel commit 309dca309fc ("block: store a block_device pointer
+in struct bio") struct bio points again to a block_device and not to a
+gendisk directly. However mdflush is looking at the presence or not of
+the bio_dev macro to check whether to get the gendisk directly from
+the bio or not, which doesn't work anymore since the bio_dev macro
+still exists. Since we don't have to deal other ekrnel kernel version
+but our own, just use the definition that we use in our kernels.
+
+Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
+---
+ tools/mdflush.py | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+diff --git a/tools/mdflush.py b/tools/mdflush.py
+index 8a23520b..3581d1bf 100755
+--- a/tools/mdflush.py
++++ b/tools/mdflush.py
+@@ -35,18 +35,7 @@ int kprobe__md_flush_request(struct pt_regs *ctx, void *mddev, struct bio *bio)
+     u32 pid = bpf_get_current_pid_tgid() >> 32;
+     data.pid = pid;
+     bpf_get_current_comm(&data.comm, sizeof(data.comm));
+-/*
+- * The following deals with a kernel version change (in mainline 4.14, although
+- * it may be backported to earlier kernels) with how the disk name is accessed.
+- * We handle both pre- and post-change versions here. Please avoid kernel
+- * version tests like this as much as possible: they inflate the code, test,
+- * and maintenance burden.
+- */
+-#ifdef bio_dev
+-    struct gendisk *bi_disk = bio->bi_disk;
+-#else
+     struct gendisk *bi_disk = bio->bi_bdev->bd_disk;
+-#endif
+     bpf_probe_read_kernel(&data.disk, sizeof(data.disk), bi_disk->disk_name);
+     events.perf_submit(ctx, &data, sizeof(data));
+     return 0;
+-- 
+2.35.1
+
diff --git a/SOURCES/bcc-0.24.0-C9S-libpbf-version-fixes.patch b/SOURCES/bcc-0.24.0-C9S-libpbf-version-fixes.patch
new file mode 100644
index 0000000..3c42a52
--- /dev/null
+++ b/SOURCES/bcc-0.24.0-C9S-libpbf-version-fixes.patch
@@ -0,0 +1,297 @@
+From a81f219d7f2bfc70dba1eb12208e3e6ab7c81b50 Mon Sep 17 00:00:00 2001
+From: Jerome Marchand <jmarchan@redhat.com>
+Date: Thu, 24 Mar 2022 16:08:17 +0100
+Subject: [PATCH] C9S: libpbf version fixes
+
+Revert "bcc: Replace deprecated libbpf APIs" since the libbpf version
+provided in C9S doesn't provide the new APIs.
+
+Remove BPF_MAP_TYPE_BLOOM_FILTER from bps since the libbpf version in
+C9S, doesn't provide bloom filter map.
+
+Add definition of struct bpf_core_relo.
+---
+ introspection/bps.c |  1 -
+ src/cc/bcc_btf.cc   | 73 +++++++++++++++++++++++++++++++++++++++-
+ src/cc/libbpf.c     | 82 ++++++---------------------------------------
+ 3 files changed, 83 insertions(+), 73 deletions(-)
+
+diff --git a/introspection/bps.c b/introspection/bps.c
+index 232b23d4..6ec02e6c 100644
+--- a/introspection/bps.c
++++ b/introspection/bps.c
+@@ -80,7 +80,6 @@ static const char * const map_type_strings[] = {
+   [BPF_MAP_TYPE_RINGBUF] = "ringbuf",
+   [BPF_MAP_TYPE_INODE_STORAGE] = "inode_storage",
+   [BPF_MAP_TYPE_TASK_STORAGE] = "task_storage",
+-  [BPF_MAP_TYPE_BLOOM_FILTER] = "bloom_filter",
+ };
+ 
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+diff --git a/src/cc/bcc_btf.cc b/src/cc/bcc_btf.cc
+index 7f551ae8..c78ba823 100644
+--- a/src/cc/bcc_btf.cc
++++ b/src/cc/bcc_btf.cc
+@@ -170,6 +170,77 @@ static int btf_ext_setup_line_info(struct btf_ext *btf_ext)
+         return btf_ext_setup_info(btf_ext, &param);
+ }
+ 
++/* bpf_core_relo_kind encodes which aspect of captured field/type/enum value
++ * has to be adjusted by relocations.
++ */
++enum bpf_core_relo_kind {
++	BPF_FIELD_BYTE_OFFSET = 0,	/* field byte offset */
++	BPF_FIELD_BYTE_SIZE = 1,	/* field size in bytes */
++	BPF_FIELD_EXISTS = 2,		/* field existence in target kernel */
++	BPF_FIELD_SIGNED = 3,		/* field signedness (0 - unsigned, 1 - signed) */
++	BPF_FIELD_LSHIFT_U64 = 4,	/* bitfield-specific left bitshift */
++	BPF_FIELD_RSHIFT_U64 = 5,	/* bitfield-specific right bitshift */
++	BPF_TYPE_ID_LOCAL = 6,		/* type ID in local BPF object */
++	BPF_TYPE_ID_TARGET = 7,		/* type ID in target kernel */
++	BPF_TYPE_EXISTS = 8,		/* type existence in target kernel */
++	BPF_TYPE_SIZE = 9,		/* type size in bytes */
++	BPF_ENUMVAL_EXISTS = 10,	/* enum value existence in target kernel */
++	BPF_ENUMVAL_VALUE = 11,		/* enum value integer value */
++};
++
++/* The minimum bpf_core_relo checked by the loader
++ *
++ * CO-RE relocation captures the following data:
++ * - insn_off - instruction offset (in bytes) within a BPF program that needs
++ *   its insn->imm field to be relocated with actual field info;
++ * - type_id - BTF type ID of the "root" (containing) entity of a relocatable
++ *   type or field;
++ * - access_str_off - offset into corresponding .BTF string section. String
++ *   interpretation depends on specific relocation kind:
++ *     - for field-based relocations, string encodes an accessed field using
++ *     a sequence of field and array indices, separated by colon (:). It's
++ *     conceptually very close to LLVM's getelementptr ([0]) instruction's
++ *     arguments for identifying offset to a field.
++ *     - for type-based relocations, strings is expected to be just "0";
++ *     - for enum value-based relocations, string contains an index of enum
++ *     value within its enum type;
++ *
++ * Example to provide a better feel.
++ *
++ *   struct sample {
++ *       int a;
++ *       struct {
++ *           int b[10];
++ *       };
++ *   };
++ *
++ *   struct sample *s = ...;
++ *   int x = &s->a;     // encoded as "0:0" (a is field #0)
++ *   int y = &s->b[5];  // encoded as "0:1:0:5" (anon struct is field #1, 
++ *                      // b is field #0 inside anon struct, accessing elem #5)
++ *   int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
++ *
++ * type_id for all relocs in this example  will capture BTF type id of
++ * `struct sample`.
++ *
++ * Such relocation is emitted when using __builtin_preserve_access_index()
++ * Clang built-in, passing expression that captures field address, e.g.:
++ *
++ * bpf_probe_read(&dst, sizeof(dst),
++ *		  __builtin_preserve_access_index(&src->a.b.c));
++ *
++ * In this case Clang will emit field relocation recording necessary data to
++ * be able to find offset of embedded `a.b.c` field within `src` struct.
++ *
++ *   [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
++ */
++struct bpf_core_relo {
++	__u32   insn_off;
++	__u32   type_id;
++	__u32   access_str_off;
++	enum bpf_core_relo_kind kind;
++};
++
+ static int btf_ext_setup_core_relos(struct btf_ext *btf_ext)
+ {
+         struct btf_ext_sec_setup_param param = {
+@@ -597,7 +668,7 @@ int BTF::load(uint8_t *btf_sec, uintptr_t btf_sec_size,
+     return -1;
+   }
+ 
+-  if (btf__load_into_kernel(btf)) {
++  if (btf__load(btf)) {
+     btf__free(btf);
+     warning("Loading .BTF section failed\n");
+     return -1;
+diff --git a/src/cc/libbpf.c b/src/cc/libbpf.c
+index e6403299..68af4b35 100644
+--- a/src/cc/libbpf.c
++++ b/src/cc/libbpf.c
+@@ -297,25 +297,6 @@ static uint64_t ptr_to_u64(void *ptr)
+   return (uint64_t) (unsigned long) ptr;
+ }
+ 
+-static int libbpf_bpf_map_create(struct bpf_create_map_attr *create_attr)
+-{
+-  LIBBPF_OPTS(bpf_map_create_opts, p);
+-
+-  p.map_flags = create_attr->map_flags;
+-  p.numa_node = create_attr->numa_node;
+-  p.btf_fd = create_attr->btf_fd;
+-  p.btf_key_type_id = create_attr->btf_key_type_id;
+-  p.btf_value_type_id = create_attr->btf_value_type_id;
+-  p.map_ifindex = create_attr->map_ifindex;
+-  if (create_attr->map_type == BPF_MAP_TYPE_STRUCT_OPS)
+-    p.btf_vmlinux_value_type_id = create_attr->btf_vmlinux_value_type_id;
+-  else
+-    p.inner_map_fd = create_attr->inner_map_fd;
+-
+-  return bpf_map_create(create_attr->map_type, create_attr->name, create_attr->key_size,
+-                        create_attr->value_size, create_attr->max_entries, &p);
+-}
+-
+ int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit)
+ {
+   unsigned name_len = attr->name ? strlen(attr->name) : 0;
+@@ -323,7 +304,7 @@ int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit)
+ 
+   memcpy(map_name, attr->name, min(name_len, BPF_OBJ_NAME_LEN - 1));
+   attr->name = map_name;
+-  int ret = libbpf_bpf_map_create(attr);
++  int ret = bpf_create_map_xattr(attr);
+ 
+   if (ret < 0 && errno == EPERM) {
+     if (!allow_rlimit)
+@@ -335,7 +316,7 @@ int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit)
+       rl.rlim_max = RLIM_INFINITY;
+       rl.rlim_cur = rl.rlim_max;
+       if (setrlimit(RLIMIT_MEMLOCK, &rl) == 0)
+-        ret = libbpf_bpf_map_create(attr);
++        ret = bpf_create_map_xattr(attr);
+     }
+   }
+ 
+@@ -345,12 +326,12 @@ int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit)
+     attr->btf_fd = 0;
+     attr->btf_key_type_id = 0;
+     attr->btf_value_type_id = 0;
+-    ret = libbpf_bpf_map_create(attr);
++    ret = bpf_create_map_xattr(attr);
+   }
+ 
+   if (ret < 0 && name_len && (errno == E2BIG || errno == EINVAL)) {
+     map_name[0] = '\0';
+-    ret = libbpf_bpf_map_create(attr);
++    ret = bpf_create_map_xattr(attr);
+   }
+ 
+   if (ret < 0 && errno == EPERM) {
+@@ -363,7 +344,7 @@ int bcc_create_map_xattr(struct bpf_create_map_attr *attr, bool allow_rlimit)
+       rl.rlim_max = RLIM_INFINITY;
+       rl.rlim_cur = rl.rlim_max;
+       if (setrlimit(RLIMIT_MEMLOCK, &rl) == 0)
+-        ret = libbpf_bpf_map_create(attr);
++        ret = bpf_create_map_xattr(attr);
+     }
+   }
+   return ret;
+@@ -627,47 +608,6 @@ int bpf_prog_get_tag(int fd, unsigned long long *ptag)
+   return 0;
+ }
+ 
+-static int libbpf_bpf_prog_load(const struct bpf_load_program_attr *load_attr,
+-                                char *log_buf, size_t log_buf_sz)
+-{
+-  LIBBPF_OPTS(bpf_prog_load_opts, p);
+-
+-  if (!load_attr || !log_buf != !log_buf_sz) {
+-    errno = EINVAL;
+-    return -EINVAL;
+-  }
+-
+-  p.expected_attach_type = load_attr->expected_attach_type;
+-  switch (load_attr->prog_type) {
+-  case BPF_PROG_TYPE_STRUCT_OPS:
+-  case BPF_PROG_TYPE_LSM:
+-    p.attach_btf_id = load_attr->attach_btf_id;
+-    break;
+-  case BPF_PROG_TYPE_TRACING:
+-  case BPF_PROG_TYPE_EXT:
+-    p.attach_btf_id = load_attr->attach_btf_id;
+-    p.attach_prog_fd = load_attr->attach_prog_fd;
+-    break;
+-  default:
+-    p.prog_ifindex = load_attr->prog_ifindex;
+-    p.kern_version = load_attr->kern_version;
+-  }
+-  p.log_level = load_attr->log_level;
+-  p.log_buf = log_buf;
+-  p.log_size = log_buf_sz;
+-  p.prog_btf_fd = load_attr->prog_btf_fd;
+-  p.func_info_rec_size = load_attr->func_info_rec_size;
+-  p.func_info_cnt = load_attr->func_info_cnt;
+-  p.func_info = load_attr->func_info;
+-  p.line_info_rec_size = load_attr->line_info_rec_size;
+-  p.line_info_cnt = load_attr->line_info_cnt;
+-  p.line_info = load_attr->line_info;
+-  p.prog_flags = load_attr->prog_flags;
+-
+-  return bpf_prog_load(load_attr->prog_type, load_attr->name, load_attr->license,
+-                       load_attr->insns, load_attr->insns_cnt, &p);
+-}
+-
+ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len,
+                         char *log_buf, unsigned log_buf_size, bool allow_rlimit)
+ {
+@@ -750,7 +690,7 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len,
+     attr->name = prog_name;
+   }
+ 
+-  ret = libbpf_bpf_prog_load(attr, attr_log_buf, attr_log_buf_size);
++  ret = bpf_load_program_xattr(attr, attr_log_buf, attr_log_buf_size);
+ 
+   // func_info/line_info may not be supported in old kernels.
+   if (ret < 0 && attr->func_info && errno == EINVAL) {
+@@ -761,14 +701,14 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len,
+     attr->line_info = NULL;
+     attr->line_info_cnt = 0;
+     attr->line_info_rec_size = 0;
+-    ret = libbpf_bpf_prog_load(attr, attr_log_buf, attr_log_buf_size);
++    ret = bpf_load_program_xattr(attr, attr_log_buf, attr_log_buf_size);
+   }
+ 
+   // BPF object name is not supported on older Kernels.
+   // If we failed due to this, clear the name and try again.
+   if (ret < 0 && name_len && (errno == E2BIG || errno == EINVAL)) {
+     prog_name[0] = '\0';
+-    ret = libbpf_bpf_prog_load(attr, attr_log_buf, attr_log_buf_size);
++    ret = bpf_load_program_xattr(attr, attr_log_buf, attr_log_buf_size);
+   }
+ 
+   if (ret < 0 && errno == EPERM) {
+@@ -787,7 +727,7 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len,
+       rl.rlim_max = RLIM_INFINITY;
+       rl.rlim_cur = rl.rlim_max;
+       if (setrlimit(RLIMIT_MEMLOCK, &rl) == 0)
+-        ret = libbpf_bpf_prog_load(attr, attr_log_buf, attr_log_buf_size);
++        ret = bpf_load_program_xattr(attr, attr_log_buf, attr_log_buf_size);
+     }
+   }
+ 
+@@ -805,7 +745,7 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len,
+       // If logging is not already enabled, enable it and do the syscall again.
+       if (attr->log_level == 0) {
+         attr->log_level = 1;
+-        ret = libbpf_bpf_prog_load(attr, log_buf, log_buf_size);
++        ret = bpf_load_program_xattr(attr, log_buf, log_buf_size);
+       }
+       // Print the log message and return.
+       bpf_print_hints(ret, log_buf);
+@@ -829,7 +769,7 @@ int bcc_prog_load_xattr(struct bpf_load_program_attr *attr, int prog_len,
+         goto return_result;
+       }
+       tmp_log_buf[0] = 0;
+-      ret = libbpf_bpf_prog_load(attr, tmp_log_buf, tmp_log_buf_size);
++      ret = bpf_load_program_xattr(attr, tmp_log_buf, tmp_log_buf_size);
+       if (ret < 0 && errno == ENOSPC) {
+         // Temporary buffer size is not enough. Double it and try again.
+         free(tmp_log_buf);
+-- 
+2.36.1
+
diff --git a/SOURCES/bcc-0.24.0-Revert-libbpf-1.0-changes.patch b/SOURCES/bcc-0.24.0-Revert-libbpf-1.0-changes.patch
new file mode 100644
index 0000000..8d86dd9
--- /dev/null
+++ b/SOURCES/bcc-0.24.0-Revert-libbpf-1.0-changes.patch
@@ -0,0 +1,2331 @@
+From 09cee55c78fe5c165c7d7c21f596c23831f844e1 Mon Sep 17 00:00:00 2001
+From: Jerome Marchand <jmarchan@redhat.com>
+Date: Tue, 19 Apr 2022 18:02:13 +0200
+Subject: [PATCH] Revert libbpf 1.0 changes
+
+Revert "libbpf-tools: remove now unnecessary bump_memlock_rlimit()"
+
+This reverts commit 5d8f5c45b16c389bb342d2b80c9f5e13e4f3b112.
+
+Revert "libbpf-tools: update vfsstat for libbpf 1.0"
+
+This reverts commit f083d3dc37372e555133519cb417f893c431eef0.
+
+Revert "libbpf-tools: update tcprtt for libbpf 1.0"
+
+This reverts commit a5b6c3cb2d20718ef002e7447046fad877590b91.
+
+Revert "libbpf-tools: update tcpconnlat for libbpf 1.0"
+
+This reverts commit aae06012af8cc8c2b592340f8783a2873aad2023.
+
+Revert "libbpf-tools: update tcpconnect for libbpf 1.0"
+
+This reverts commit 4051a9e83cb68733af20ce263fcc41c8aadc2622.
+
+Revert "libbpf-tools: update syscount for libbpf 1.0"
+
+This reverts commit d2dc7bcd0d94ef54e336119a2a79113b87839820.
+
+Revert "libbpf-tools: update statsnoop for libbpf 1.0"
+
+This reverts commit 0e348e5ed66aabd0cd5c0c75932f245bd1385b3b.
+
+Revert "libbpf-tools: update solisten for libbpf 1.0"
+
+This reverts commit 60dd074e26e762727e685334999bec5851adaef9.
+
+Revert "libbpf-tools: update softirqs for libbpf 1.0"
+
+This reverts commit 92806a435c2e1b248acdb9d0dc5b3eedc86994b0.
+
+Revert "libbpf-tools: update runqslower for libbpf 1.0"
+
+This reverts commit e6477620ccfc9abe10f7e630e65381204daa5ba8.
+
+Revert "libbpf-tools: update runqlen for libbpf 1.0"
+
+This reverts commit a7f0148372018140940d66f8faf53cb5add1e858.
+
+Revert "libbpf-tools: update runqlat for libbpf 1.0"
+
+This reverts commit 865f990b7139dca166a43bbc8159f6acd4bfbee6.
+
+Revert "libbpf-tools: update readahead for libbpf 1.0"
+
+This reverts commit 3c5dae6380dcc2034a8746c648e3bb24ea61f886.
+
+Revert "libbpf-tools: update opensnoop for libbpf 1.0"
+
+This reverts commit 34a680ba8da7e61befad67ebccb69c5041e9e288.
+
+Revert "libbpf-tools: update offcputime for libbpf 1.0"
+
+This reverts commit 5ef6d9922841d7cfde1994c25ccbac53858ed99f.
+
+Revert "libbpf-tools: update numamove for libbpf 1.0"
+
+This reverts commit 824ffd2a1fbb527f5fd25e2caa4b43fbf1ee858b.
+
+Revert "libbpf-tools: update mountsnoop for libbpf 1.0"
+
+This reverts commit 08301e93e5cea8575d5dc4b66fb7a76cebd5969b.
+
+Revert "libbpf-tools: update llcstat for libbpf 1.0"
+
+This reverts commit dbee9ea8ede33166fa70ecc33af7d7721ef26280.
+
+Revert "libbpf-tools: update hardirqs for libbpf 1.0"
+
+This reverts commit 8fcf08c81d30d80f89f995f79ef3246ce99c72dd.
+
+Revert "libbpf-tools: update gethostlatency for libbpf 1.0"
+
+This reverts commit 54a239abd21df9d6fc5d8db7ae7a26c5d8db2440.
+
+Revert "libbpf-tools: update funclatency for libbpf 1.0"
+
+This reverts commit d7b3ed3a8b2169087534738670d108489711f2d1.
+
+Revert "libbpf-tools: update fsslower for libbpf 1.0"
+
+This reverts commit 511ab72f046848d6df3f7c6ec0411b1609e165fb.
+
+Revert "libbpf-tools: update fsdist for libbpf 1.0"
+
+This reverts commit 21586658c86e1a20e9195d8715d37d714be93bb6.
+
+Revert "libbpf-tools: update filetop for libbpf 1.0"
+
+This reverts commit e6d151227f56433a317790d56ba7875ccae00448.
+
+Revert "libbpf-tools: update filelife for libbpf 1.0"
+
+This reverts commit 4ca8dd95efb7c4f149b889b700beeda036ebe822.
+
+Revert "libbpf-tools: update exitsnoop for libbpf 1.0"
+
+This reverts commit 0a035be644cf818354f3faab25a74e005a66d954.
+
+Revert "libbpf-tools: update execsnoop for libbpf 1.0"
+
+This reverts commit 7da38aabbefa41b8553e9fdec7744a5e423b5119.
+
+Revert "libbpf-tools: update cpudist for libbpf 1.0"
+
+This reverts commit dab1d09ef49e74c4c95f933e97e16dfc074338c2.
+
+Revert "libbpf-tools: update drsnoop for libbpf 1.0"
+
+This reverts commit 9cfdf5e04b32ca079a634ff60de7c08e3c41ccf5.
+
+Revert "libbpf-tools: fix cpufreq.bpf.c and update cpufreq for libbpf 1.0"
+
+This reverts commit f2006eaa5901d6ccf51d24b18c644f2fb1d41757.
+
+Revert "libbpf-tools: update cachestat for libbpf 1.0"
+
+This reverts commit 4970d23f9ff308c5860612ad6395d7692b05104e.
+
+Revert "libbpf-tools: update bitesize for libbpf 1.0"
+
+This reverts commit 7bea6c4ad9a460fc34eb618e488e44ca014e8ac7.
+
+Revert "libbpf-tools: update biostacks for libbpf 1.0"
+
+This reverts commit 49bb367628500104411d42851194162bec5d1f4c.
+
+Revert "libbpf-tools: update biosnoop for libbpf 1.0"
+
+This reverts commit 519ed8cf9c0daff75ecb3f435a3efec2087945a6.
+
+Revert "libbpf-tools: update biopattern for libbpf 1.0"
+
+This reverts commit c5b17e65a6e59fae1223bf493648050643ad9179.
+
+Revert "libbpf-tools: update biolatency for libbpf 1.0"
+
+This reverts commit 24d723699fbeeb8686acabc09ecefcceb749b9e0.
+
+Revert "libbpf-tools: update bindsnoop for libbpf 1.0"
+
+This reverts commit 7f2f4c4123a55438754b1a29f7ad3d3cfdbc7373.
+
+Revert "libbpf-tools: update ksnoop for libbpf 1.0"
+
+This reverts commit 18dc2ac7d84a854e2f5ac9ce1b532a0c59acf49e.
+
+Revert "libbpf-tools: update bashreadline for libbpf 1.0"
+
+This reverts commit 2cf0ba491d16386529c50ff0a9ec3eb9f86a2493.
+
+Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
+---
+ libbpf-tools/bashreadline.c   | 24 ++++++++-----
+ libbpf-tools/bindsnoop.c      | 21 +++++++----
+ libbpf-tools/biolatency.c     | 28 +++++++++------
+ libbpf-tools/biopattern.c     |  7 +++-
+ libbpf-tools/biosnoop.c       | 67 +++++++++++++++++++++--------------
+ libbpf-tools/biostacks.c      | 39 ++++++++++++--------
+ libbpf-tools/bitesize.c       |  7 +++-
+ libbpf-tools/cachestat.c      |  7 +++-
+ libbpf-tools/cpudist.c        |  7 +++-
+ libbpf-tools/cpufreq.bpf.c    | 11 ------
+ libbpf-tools/cpufreq.c        | 15 +++++---
+ libbpf-tools/drsnoop.c        | 21 +++++++----
+ libbpf-tools/execsnoop.c      | 22 ++++++++----
+ libbpf-tools/exitsnoop.c      | 20 +++++++----
+ libbpf-tools/filelife.c       | 21 +++++++----
+ libbpf-tools/filetop.c        |  6 +++-
+ libbpf-tools/fsdist.c         | 38 +++++++++++++-------
+ libbpf-tools/fsslower.c       | 46 ++++++++++++++++--------
+ libbpf-tools/funclatency.c    | 32 ++++++++++-------
+ libbpf-tools/gethostlatency.c | 49 +++++++++++++++----------
+ libbpf-tools/hardirqs.c       | 34 +++++++++++-------
+ libbpf-tools/ksnoop.c         | 65 ++++++++++++++++-----------------
+ libbpf-tools/llcstat.bpf.c    |  4 +--
+ libbpf-tools/llcstat.c        | 13 +++++--
+ libbpf-tools/mountsnoop.c     | 20 +++++++----
+ libbpf-tools/numamove.c       | 16 ++++++---
+ libbpf-tools/offcputime.c     |  7 +++-
+ libbpf-tools/opensnoop.c      | 21 +++++++----
+ libbpf-tools/readahead.c      |  7 +++-
+ libbpf-tools/runqlat.c        |  7 +++-
+ libbpf-tools/runqlen.c        | 13 +++++--
+ libbpf-tools/runqslower.c     | 22 ++++++++----
+ libbpf-tools/softirqs.c       |  7 +++-
+ libbpf-tools/solisten.c       | 20 +++++++----
+ libbpf-tools/statsnoop.c      | 20 +++++++----
+ libbpf-tools/syscount.c       | 18 ++++++----
+ libbpf-tools/tcpconnect.c     | 25 ++++++++-----
+ libbpf-tools/tcpconnlat.c     | 24 +++++++++----
+ libbpf-tools/tcprtt.c         |  7 +++-
+ libbpf-tools/trace_helpers.c  | 22 ++++++++----
+ libbpf-tools/trace_helpers.h  |  1 +
+ libbpf-tools/vfsstat.c        |  8 ++++-
+ 42 files changed, 576 insertions(+), 293 deletions(-)
+
+diff --git a/libbpf-tools/bashreadline.c b/libbpf-tools/bashreadline.c
+index 2fcb2e2c..ab3b955e 100644
+--- a/libbpf-tools/bashreadline.c
++++ b/libbpf-tools/bashreadline.c
+@@ -149,6 +149,7 @@ int main(int argc, char **argv)
+ 		.doc = argp_program_doc,
+ 	};
+ 	struct bashreadline_bpf *obj = NULL;
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	char *readline_so_path;
+ 	off_t func_off;
+@@ -165,7 +166,11 @@ int main(int argc, char **argv)
+ 		return 1;
+ 	}
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		goto cleanup;
++	}
+ 	libbpf_set_print(libbpf_print_fn);
+ 
+ 	obj = bashreadline_bpf__open_and_load();
+@@ -182,16 +187,17 @@ int main(int argc, char **argv)
+ 
+ 	obj->links.printret = bpf_program__attach_uprobe(obj->progs.printret, true, -1,
+ 							 readline_so_path, func_off);
+-	if (!obj->links.printret) {
+-		err = -errno;
++	err = libbpf_get_error(obj->links.printret);
++	if (err) {
+ 		warn("failed to attach readline: %d\n", err);
+ 		goto cleanup;
+ 	}
+ 
+-	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
++	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
+ 		warn("failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -205,8 +211,8 @@ int main(int argc, char **argv)
+ 	printf("%-9s %-7s %s\n", "TIME", "PID", "COMMAND");
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			warn("error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			warn("error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		err = 0;
+diff --git a/libbpf-tools/bindsnoop.c b/libbpf-tools/bindsnoop.c
+index 5d87d484..c75b57e0 100644
+--- a/libbpf-tools/bindsnoop.c
++++ b/libbpf-tools/bindsnoop.c
+@@ -174,6 +174,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct bindsnoop_bpf *obj;
+ 	int err, port_map_fd;
+@@ -184,7 +185,11 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
+ 	libbpf_set_print(libbpf_print_fn);
+ 
+ 	obj = bindsnoop_bpf__open();
+@@ -219,10 +224,12 @@ int main(int argc, char **argv)
+ 		goto cleanup;
+ 	}
+ 
+-	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
++	pb = perf_buffer__new(bpf_map__fd(obj->maps.events),
++			      PERF_BUFFER_PAGES, &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
+ 		warn("failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -240,8 +247,8 @@ int main(int argc, char **argv)
+ 
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			warn("error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			warn("error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/biolatency.c b/libbpf-tools/biolatency.c
+index 51afa509..f2cf5ffd 100644
+--- a/libbpf-tools/biolatency.c
++++ b/libbpf-tools/biolatency.c
+@@ -255,9 +255,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = biolatency_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -308,22 +313,25 @@ int main(int argc, char **argv)
+ 	}
+ 
+ 	if (env.queued) {
+-		obj->links.block_rq_insert = bpf_program__attach(obj->progs.block_rq_insert);
+-		if (!obj->links.block_rq_insert) {
+-			err = -errno;
++		obj->links.block_rq_insert =
++			bpf_program__attach(obj->progs.block_rq_insert);
++		err = libbpf_get_error(obj->links.block_rq_insert);
++		if (err) {
+ 			fprintf(stderr, "failed to attach: %s\n", strerror(-err));
+ 			goto cleanup;
+ 		}
+ 	}
+-	obj->links.block_rq_issue = bpf_program__attach(obj->progs.block_rq_issue);
+-	if (!obj->links.block_rq_issue) {
+-		err = -errno;
++	obj->links.block_rq_issue =
++		bpf_program__attach(obj->progs.block_rq_issue);
++	err = libbpf_get_error(obj->links.block_rq_issue);
++	if (err) {
+ 		fprintf(stderr, "failed to attach: %s\n", strerror(-err));
+ 		goto cleanup;
+ 	}
+-	obj->links.block_rq_complete = bpf_program__attach(obj->progs.block_rq_complete);
+-	if (!obj->links.block_rq_complete) {
+-		err = -errno;
++	obj->links.block_rq_complete =
++		bpf_program__attach(obj->progs.block_rq_complete);
++	err = libbpf_get_error(obj->links.block_rq_complete);
++	if (err) {
+ 		fprintf(stderr, "failed to attach: %s\n", strerror(-err));
+ 		goto cleanup;
+ 	}
+diff --git a/libbpf-tools/biopattern.c b/libbpf-tools/biopattern.c
+index 92324702..2cc0d9a3 100644
+--- a/libbpf-tools/biopattern.c
++++ b/libbpf-tools/biopattern.c
+@@ -172,9 +172,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = biopattern_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+diff --git a/libbpf-tools/biosnoop.c b/libbpf-tools/biosnoop.c
+index f0f665a6..618af38e 100644
+--- a/libbpf-tools/biosnoop.c
++++ b/libbpf-tools/biosnoop.c
+@@ -190,6 +190,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct ksyms *ksyms = NULL;
+ 	struct biosnoop_bpf *obj;
+@@ -202,9 +203,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = biosnoop_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -251,55 +257,64 @@ int main(int argc, char **argv)
+ 		}
+ 	}
+ 
+-	obj->links.blk_account_io_start = bpf_program__attach(obj->progs.blk_account_io_start);
+-	if (!obj->links.blk_account_io_start) {
+-		err = -errno;
++	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);
++	if (err) {
+ 		fprintf(stderr, "failed to attach blk_account_io_start: %s\n",
+-			strerror(-err));
++			strerror(err));
+ 		goto cleanup;
+ 	}
+ 	ksyms = ksyms__load();
+ 	if (!ksyms) {
+-		err = -ENOMEM;
+ 		fprintf(stderr, "failed to load kallsyms\n");
+ 		goto cleanup;
+ 	}
+ 	if (ksyms__get_symbol(ksyms, "blk_account_io_merge_bio")) {
+ 		obj->links.blk_account_io_merge_bio =
+ 			bpf_program__attach(obj->progs.blk_account_io_merge_bio);
+-		if (!obj->links.blk_account_io_merge_bio) {
+-			err = -errno;
+-			fprintf(stderr, "failed to attach blk_account_io_merge_bio: %s\n",
+-				strerror(-err));
++		err = libbpf_get_error(obj->links.blk_account_io_merge_bio);
++		if (err) {
++			fprintf(stderr, "failed to attach "
++				"blk_account_io_merge_bio: %s\n",
++				strerror(err));
+ 			goto cleanup;
+ 		}
+ 	}
+ 	if (env.queued) {
+ 		obj->links.block_rq_insert =
+ 			bpf_program__attach(obj->progs.block_rq_insert);
+-		if (!obj->links.block_rq_insert) {
+-			err = -errno;
+-			fprintf(stderr, "failed to attach block_rq_insert: %s\n", strerror(-err));
++		err = libbpf_get_error(obj->links.block_rq_insert);
++		if (err) {
++			fprintf(stderr, "failed to attach block_rq_insert: %s\n",
++				strerror(err));
+ 			goto cleanup;
+ 		}
+ 	}
+-	obj->links.block_rq_issue = bpf_program__attach(obj->progs.block_rq_issue);
+-	if (!obj->links.block_rq_issue) {
+-		err = -errno;
+-		fprintf(stderr, "failed to attach block_rq_issue: %s\n", strerror(-err));
++	obj->links.block_rq_issue =
++		bpf_program__attach(obj->progs.block_rq_issue);
++	err = libbpf_get_error(obj->links.block_rq_issue);
++	if (err) {
++		fprintf(stderr, "failed to attach block_rq_issue: %s\n",
++			strerror(err));
+ 		goto cleanup;
+ 	}
+-	obj->links.block_rq_complete = bpf_program__attach(obj->progs.block_rq_complete);
+-	if (!obj->links.block_rq_complete) {
+-		err = -errno;
+-		fprintf(stderr, "failed to attach block_rq_complete: %s\n", strerror(-err));
++	obj->links.block_rq_complete =
++		bpf_program__attach(obj->progs.block_rq_complete);
++	err = libbpf_get_error(obj->links.block_rq_complete);
++	if (err) {
++		fprintf(stderr, "failed to attach block_rq_complete: %s\n",
++			strerror(err));
+ 		goto cleanup;
+ 	}
+ 
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
+ 	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++			&pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
++		pb = NULL;
+ 		fprintf(stderr, "failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -323,8 +338,8 @@ int main(int argc, char **argv)
+ 	/* main: poll */
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		if (env.duration && get_ktime_ns() > time_end)
+diff --git a/libbpf-tools/biostacks.c b/libbpf-tools/biostacks.c
+index 260bc235..c98fd532 100644
+--- a/libbpf-tools/biostacks.c
++++ b/libbpf-tools/biostacks.c
+@@ -145,9 +145,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = biostacks_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -179,10 +184,12 @@ int main(int argc, char **argv)
+ 		goto cleanup;
+ 	}
+ 
+-	obj->links.blk_account_io_start = bpf_program__attach(obj->progs.blk_account_io_start);
+-	if (!obj->links.blk_account_io_start) {
+-		err = -errno;
+-		fprintf(stderr, "failed to attach blk_account_io_start: %s\n", strerror(-err));
++	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);
++	if (err) {
++		fprintf(stderr, "failed to attach blk_account_io_start: %s\n",
++			strerror(err));
+ 		goto cleanup;
+ 	}
+ 	ksyms = ksyms__load();
+@@ -192,19 +199,23 @@ int main(int argc, char **argv)
+ 	}
+ 	if (ksyms__get_symbol(ksyms, "blk_account_io_merge_bio")) {
+ 		obj->links.blk_account_io_merge_bio =
+-			bpf_program__attach(obj->progs.blk_account_io_merge_bio);
+-		if (!obj->links.blk_account_io_merge_bio) {
+-			err = -errno;
+-			fprintf(stderr, "failed to attach blk_account_io_merge_bio: %s\n",
+-				strerror(-err));
++			bpf_program__attach(obj->
++					progs.blk_account_io_merge_bio);
++		err = libbpf_get_error(obj->
++				links.blk_account_io_merge_bio);
++		if (err) {
++			fprintf(stderr, "failed to attach "
++				"blk_account_io_merge_bio: %s\n",
++				strerror(err));
+ 			goto cleanup;
+ 		}
+ 	}
+-	obj->links.blk_account_io_done = bpf_program__attach(obj->progs.blk_account_io_done);
+-	if (!obj->links.blk_account_io_done) {
+-		err = -errno;
++	obj->links.blk_account_io_done =
++		bpf_program__attach(obj->progs.blk_account_io_done);
++	err = libbpf_get_error(obj->links.blk_account_io_done);
++	if (err) {
+ 		fprintf(stderr, "failed to attach blk_account_io_done: %s\n",
+-			strerror(-err));
++			strerror(err));
+ 		goto cleanup;
+ 	}
+ 
+diff --git a/libbpf-tools/bitesize.c b/libbpf-tools/bitesize.c
+index 4c371508..41b1a7db 100644
+--- a/libbpf-tools/bitesize.c
++++ b/libbpf-tools/bitesize.c
+@@ -167,9 +167,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = bitesize_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+diff --git a/libbpf-tools/cachestat.c b/libbpf-tools/cachestat.c
+index 05785251..abc81878 100644
+--- a/libbpf-tools/cachestat.c
++++ b/libbpf-tools/cachestat.c
+@@ -139,9 +139,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = cachestat_bpf__open_and_load();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open and/or load BPF object\n");
+diff --git a/libbpf-tools/cpudist.c b/libbpf-tools/cpudist.c
+index f76d8a67..035100ea 100644
+--- a/libbpf-tools/cpudist.c
++++ b/libbpf-tools/cpudist.c
+@@ -197,9 +197,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = cpudist_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+diff --git a/libbpf-tools/cpufreq.bpf.c b/libbpf-tools/cpufreq.bpf.c
+index 88a1bd25..697620ba 100644
+--- a/libbpf-tools/cpufreq.bpf.c
++++ b/libbpf-tools/cpufreq.bpf.c
+@@ -17,21 +17,11 @@ struct {
+ 	__type(value, struct hist);
+ } hists SEC(".maps");
+ 
+-#define clamp_umax(VAR, UMAX)						\
+-	asm volatile (							\
+-		"if %0 <= %[max] goto +1\n"				\
+-		"%0 = %[max]\n"						\
+-		: "+r"(VAR)						\
+-		: [max]"i"(UMAX)					\
+-	)
+-
+ SEC("tp_btf/cpu_frequency")
+ int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id)
+ {
+ 	if (cpu_id >= MAX_CPU_NR)
+ 		return 0;
+-
+-	clamp_umax(cpu_id, MAX_CPU_NR - 1);
+ 	freqs_mhz[cpu_id] = state / 1000;
+ 	return 0;
+ }
+@@ -46,7 +36,6 @@ int do_sample(struct bpf_perf_event_data *ctx)
+ 
+ 	if (cpu >= MAX_CPU_NR)
+ 		return 0;
+-	clamp_umax(cpu, MAX_CPU_NR - 1);
+ 	freq_mhz = freqs_mhz[cpu];
+ 	if (!freq_mhz)
+ 		return 0;
+diff --git a/libbpf-tools/cpufreq.c b/libbpf-tools/cpufreq.c
+index c5839560..65876587 100644
+--- a/libbpf-tools/cpufreq.c
++++ b/libbpf-tools/cpufreq.c
+@@ -102,8 +102,10 @@ static int open_and_attach_perf_event(int freq, struct bpf_program *prog,
+ 			return -1;
+ 		}
+ 		links[i] = bpf_program__attach_perf_event(prog, fd);
+-		if (!links[i]) {
+-			fprintf(stderr, "failed to attach perf event on cpu: %d\n", i);
++		if (libbpf_get_error(links[i])) {
++			fprintf(stderr, "failed to attach perf event on cpu: "
++				"%d\n", i);
++			links[i] = NULL;
+ 			close(fd);
+ 			return -1;
+ 		}
+@@ -173,7 +175,7 @@ static void print_linear_hists(struct bpf_map *hists,
+ 
+ 	printf("\n");
+ 	print_linear_hist(bss->syswide.slots, MAX_SLOTS, 0, HIST_STEP_SIZE,
+-			  "syswide");
++			"syswide");
+ }
+ 
+ int main(int argc, char **argv)
+@@ -191,9 +193,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	nr_cpus = libbpf_num_possible_cpus();
+ 	if (nr_cpus < 0) {
+ 		fprintf(stderr, "failed to get # of possible cpus: '%s'!\n",
+diff --git a/libbpf-tools/drsnoop.c b/libbpf-tools/drsnoop.c
+index 705db9a4..89285871 100644
+--- a/libbpf-tools/drsnoop.c
++++ b/libbpf-tools/drsnoop.c
+@@ -146,6 +146,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct ksyms *ksyms = NULL;
+ 	const struct ksym *ksym;
+@@ -157,9 +158,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = drsnoop_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -207,10 +213,13 @@ int main(int argc, char **argv)
+ 		printf(" %8s", "FREE(KB)");
+ 	printf("\n");
+ 
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
+ 	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++			      &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
++		pb = NULL;
+ 		fprintf(stderr, "failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -228,8 +237,8 @@ int main(int argc, char **argv)
+ 	/* main: poll */
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		if (env.duration && get_ktime_ns() > time_end)
+diff --git a/libbpf-tools/execsnoop.c b/libbpf-tools/execsnoop.c
+index 38294816..1fd573da 100644
+--- a/libbpf-tools/execsnoop.c
++++ b/libbpf-tools/execsnoop.c
+@@ -263,6 +263,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct execsnoop_bpf *obj;
+ 	int err;
+@@ -271,9 +272,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = execsnoop_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -311,10 +317,12 @@ int main(int argc, char **argv)
+ 	printf("%-16s %-6s %-6s %3s %s\n", "PCOMM", "PID", "PPID", "RET", "ARGS");
+ 
+ 	/* setup event callbacks */
+-	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
++	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
++		pb = NULL;
+ 		fprintf(stderr, "failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -328,8 +336,8 @@ int main(int argc, char **argv)
+ 	/* main: poll */
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/exitsnoop.c b/libbpf-tools/exitsnoop.c
+index bca9d4d3..410e00da 100644
+--- a/libbpf-tools/exitsnoop.c
++++ b/libbpf-tools/exitsnoop.c
+@@ -152,6 +152,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct exitsnoop_bpf *obj;
+ 	int err;
+@@ -160,7 +161,11 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
+ 	libbpf_set_print(libbpf_print_fn);
+ 
+ 	obj = exitsnoop_bpf__open();
+@@ -185,10 +190,11 @@ int main(int argc, char **argv)
+ 		goto cleanup;
+ 	}
+ 
+-	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
++	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
+ 		warn("failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -206,8 +212,8 @@ int main(int argc, char **argv)
+ 
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			warn("error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			warn("error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/filelife.c b/libbpf-tools/filelife.c
+index ba6b9440..1f94039e 100644
+--- a/libbpf-tools/filelife.c
++++ b/libbpf-tools/filelife.c
+@@ -110,6 +110,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct filelife_bpf *obj;
+ 	int err;
+@@ -118,9 +119,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = filelife_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -145,10 +151,13 @@ int main(int argc, char **argv)
+ 	printf("Tracing the lifespan of short-lived files ... Hit Ctrl-C to end.\n");
+ 	printf("%-8s %-6s %-16s %-7s %s\n", "TIME", "PID", "COMM", "AGE(s)", "FILE");
+ 
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
+ 	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++			      &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
++		pb = NULL;
+ 		fprintf(stderr, "failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -161,8 +170,8 @@ int main(int argc, char **argv)
+ 
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/filetop.c b/libbpf-tools/filetop.c
+index 70240d85..f1f7ba96 100644
+--- a/libbpf-tools/filetop.c
++++ b/libbpf-tools/filetop.c
+@@ -268,7 +268,11 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
+ 	libbpf_set_print(libbpf_print_fn);
+ 
+ 	obj = filetop_bpf__open();
+diff --git a/libbpf-tools/fsdist.c b/libbpf-tools/fsdist.c
+index f411d162..782a0e6a 100644
+--- a/libbpf-tools/fsdist.c
++++ b/libbpf-tools/fsdist.c
+@@ -299,44 +299,53 @@ static int attach_kprobes(struct fsdist_bpf *obj)
+ 
+ 	/* READ */
+ 	obj->links.file_read_entry = bpf_program__attach_kprobe(obj->progs.file_read_entry, false, cfg->op_funcs[READ]);
+-	if (!obj->links.file_read_entry)
++	err = libbpf_get_error(obj->links.file_read_entry);
++	if (err)
+ 		goto errout;
+ 	obj->links.file_read_exit = bpf_program__attach_kprobe(obj->progs.file_read_exit, true, cfg->op_funcs[READ]);
+-	if (!obj->links.file_read_exit)
++	err = libbpf_get_error(obj->links.file_read_exit);
++	if (err)
+ 		goto errout;
+ 	/* WRITE */
+ 	obj->links.file_write_entry = bpf_program__attach_kprobe(obj->progs.file_write_entry, false, cfg->op_funcs[WRITE]);
+-	if (!obj->links.file_write_entry)
++	err = libbpf_get_error(obj->links.file_write_entry);
++	if (err)
+ 		goto errout;
+ 	obj->links.file_write_exit = bpf_program__attach_kprobe(obj->progs.file_write_exit, true, cfg->op_funcs[WRITE]);
+-	if (!obj->links.file_write_exit)
++	err = libbpf_get_error(obj->links.file_write_exit);
++	if (err)
+ 		goto errout;
+ 	/* OPEN */
+ 	obj->links.file_open_entry = bpf_program__attach_kprobe(obj->progs.file_open_entry, false, cfg->op_funcs[OPEN]);
+-	if (!obj->links.file_open_entry)
++	err = libbpf_get_error(obj->links.file_open_entry);
++	if (err)
+ 		goto errout;
+ 	obj->links.file_open_exit = bpf_program__attach_kprobe(obj->progs.file_open_exit, true, cfg->op_funcs[OPEN]);
+-	if (!obj->links.file_open_exit)
++	err = libbpf_get_error(obj->links.file_open_exit);
++	if (err)
+ 		goto errout;
+ 	/* FSYNC */
+ 	obj->links.file_sync_entry = bpf_program__attach_kprobe(obj->progs.file_sync_entry, false, cfg->op_funcs[FSYNC]);
+-	if (!obj->links.file_sync_entry)
++	err = libbpf_get_error(obj->links.file_sync_entry);
++	if (err)
+ 		goto errout;
+ 	obj->links.file_sync_exit = bpf_program__attach_kprobe(obj->progs.file_sync_exit, true, cfg->op_funcs[FSYNC]);
+-	if (!obj->links.file_sync_exit)
++	err = libbpf_get_error(obj->links.file_sync_exit);
++	if (err)
+ 		goto errout;
+ 	/* GETATTR */
+ 	if (!cfg->op_funcs[GETATTR])
+ 		return 0;
+ 	obj->links.getattr_entry = bpf_program__attach_kprobe(obj->progs.getattr_entry, false, cfg->op_funcs[GETATTR]);
+-	if (!obj->links.getattr_entry)
++	err = libbpf_get_error(obj->links.getattr_entry);
++	if (err)
+ 		goto errout;
+ 	obj->links.getattr_exit = bpf_program__attach_kprobe(obj->progs.getattr_exit, true, cfg->op_funcs[GETATTR]);
+-	if (!obj->links.getattr_exit)
++	err = libbpf_get_error(obj->links.getattr_exit);
++	if (err)
+ 		goto errout;
+ 	return 0;
+ errout:
+-	err = -errno;
+ 	warn("failed to attach kprobe: %ld\n", err);
+ 	return err;
+ }
+@@ -364,9 +373,14 @@ int main(int argc, char **argv)
+ 		return 1;
+ 	}
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	skel = fsdist_bpf__open();
+ 	if (!skel) {
+ 		warn("failed to open BPF object\n");
+diff --git a/libbpf-tools/fsslower.c b/libbpf-tools/fsslower.c
+index e96c9efa..2975b493 100644
+--- a/libbpf-tools/fsslower.c
++++ b/libbpf-tools/fsslower.c
+@@ -256,36 +256,43 @@ static int attach_kprobes(struct fsslower_bpf *obj)
+ 
+ 	/* READ */
+ 	obj->links.file_read_entry = bpf_program__attach_kprobe(obj->progs.file_read_entry, false, cfg->op_funcs[READ]);
+-	if (!obj->links.file_read_entry)
++	err = libbpf_get_error(obj->links.file_read_entry);
++	if (err)
+ 		goto errout;
+ 	obj->links.file_read_exit = bpf_program__attach_kprobe(obj->progs.file_read_exit, true, cfg->op_funcs[READ]);
+-	if (!obj->links.file_read_exit)
++	err = libbpf_get_error(obj->links.file_read_exit);
++	if (err)
+ 		goto errout;
+ 	/* WRITE */
+ 	obj->links.file_write_entry = bpf_program__attach_kprobe(obj->progs.file_write_entry, false, cfg->op_funcs[WRITE]);
+-	if (!obj->links.file_write_entry)
++	err = libbpf_get_error(obj->links.file_write_entry);
++	if (err)
+ 		goto errout;
+ 	obj->links.file_write_exit = bpf_program__attach_kprobe(obj->progs.file_write_exit, true, cfg->op_funcs[WRITE]);
+-	if (!obj->links.file_write_exit)
++	err = libbpf_get_error(obj->links.file_write_exit);
++	if (err)
+ 		goto errout;
+ 	/* OPEN */
+ 	obj->links.file_open_entry = bpf_program__attach_kprobe(obj->progs.file_open_entry, false, cfg->op_funcs[OPEN]);
+-	if (!obj->links.file_open_entry)
++	err = libbpf_get_error(obj->links.file_open_entry);
++	if (err)
+ 		goto errout;
+ 	obj->links.file_open_exit = bpf_program__attach_kprobe(obj->progs.file_open_exit, true, cfg->op_funcs[OPEN]);
+-	if (!obj->links.file_open_exit)
++	err = libbpf_get_error(obj->links.file_open_exit);
++	if (err)
+ 		goto errout;
+ 	/* FSYNC */
+ 	obj->links.file_sync_entry = bpf_program__attach_kprobe(obj->progs.file_sync_entry, false, cfg->op_funcs[FSYNC]);
+-	if (!obj->links.file_sync_entry)
++	err = libbpf_get_error(obj->links.file_sync_entry);
++	if (err)
+ 		goto errout;
+ 	obj->links.file_sync_exit = bpf_program__attach_kprobe(obj->progs.file_sync_exit, true, cfg->op_funcs[FSYNC]);
+-	if (!obj->links.file_sync_exit)
++	err = libbpf_get_error(obj->links.file_sync_exit);
++	if (err)
+ 		goto errout;
+ 	return 0;
+ 
+ errout:
+-	err = -errno;
+ 	warn("failed to attach kprobe: %ld\n", err);
+ 	return err;
+ }
+@@ -354,6 +361,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct fsslower_bpf *skel;
+ 	__u64 time_end = 0;
+@@ -369,9 +377,14 @@ int main(int argc, char **argv)
+ 		return 1;
+ 	}
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	skel = fsslower_bpf__open();
+ 	if (!skel) {
+ 		warn("failed to open BPF object\n");
+@@ -415,10 +428,13 @@ int main(int argc, char **argv)
+ 		goto cleanup;
+ 	}
+ 
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
+ 	pb = perf_buffer__new(bpf_map__fd(skel->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++			      &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
++		pb = NULL;
+ 		warn("failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -437,8 +453,8 @@ int main(int argc, char **argv)
+ 	/* main: poll */
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		if (duration && get_ktime_ns() > time_end)
+diff --git a/libbpf-tools/funclatency.c b/libbpf-tools/funclatency.c
+index 3ea0fec3..b079292e 100644
+--- a/libbpf-tools/funclatency.c
++++ b/libbpf-tools/funclatency.c
+@@ -185,18 +185,20 @@ static int attach_kprobes(struct funclatency_bpf *obj)
+ {
+ 	long err;
+ 
+-	obj->links.dummy_kprobe = bpf_program__attach_kprobe(obj->progs.dummy_kprobe, false,
+-							     env.funcname);
+-	if (!obj->links.dummy_kprobe) {
+-		err = -errno;
++	obj->links.dummy_kprobe =
++		bpf_program__attach_kprobe(obj->progs.dummy_kprobe, false,
++					   env.funcname);
++	err = libbpf_get_error(obj->links.dummy_kprobe);
++	if (err) {
+ 		warn("failed to attach kprobe: %ld\n", err);
+ 		return -1;
+ 	}
+ 
+-	obj->links.dummy_kretprobe = bpf_program__attach_kprobe(obj->progs.dummy_kretprobe, true,
+-								env.funcname);
+-	if (!obj->links.dummy_kretprobe) {
+-		err = -errno;
++	obj->links.dummy_kretprobe =
++		bpf_program__attach_kprobe(obj->progs.dummy_kretprobe, true,
++					   env.funcname);
++	err = libbpf_get_error(obj->links.dummy_kretprobe);
++	if (err) {
+ 		warn("failed to attach kretprobe: %ld\n", err);
+ 		return -1;
+ 	}
+@@ -237,8 +239,8 @@ static int attach_uprobes(struct funclatency_bpf *obj)
+ 	obj->links.dummy_kprobe =
+ 		bpf_program__attach_uprobe(obj->progs.dummy_kprobe, false,
+ 					   env.pid ?: -1, bin_path, func_off);
+-	if (!obj->links.dummy_kprobe) {
+-		err = -errno;
++	err = libbpf_get_error(obj->links.dummy_kprobe);
++	if (err) {
+ 		warn("Failed to attach uprobe: %ld\n", err);
+ 		goto out_binary;
+ 	}
+@@ -246,8 +248,8 @@ static int attach_uprobes(struct funclatency_bpf *obj)
+ 	obj->links.dummy_kretprobe =
+ 		bpf_program__attach_uprobe(obj->progs.dummy_kretprobe, true,
+ 					   env.pid ?: -1, bin_path, func_off);
+-	if (!obj->links.dummy_kretprobe) {
+-		err = -errno;
++	err = libbpf_get_error(obj->links.dummy_kretprobe);
++	if (err) {
+ 		warn("Failed to attach uretprobe: %ld\n", err);
+ 		goto out_binary;
+ 	}
+@@ -296,7 +298,11 @@ int main(int argc, char **argv)
+ 
+ 	sigaction(SIGINT, &sigact, 0);
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
+ 	libbpf_set_print(libbpf_print_fn);
+ 
+ 	obj = funclatency_bpf__open();
+diff --git a/libbpf-tools/gethostlatency.c b/libbpf-tools/gethostlatency.c
+index 9b3ebc28..12076e6a 100644
+--- a/libbpf-tools/gethostlatency.c
++++ b/libbpf-tools/gethostlatency.c
+@@ -164,14 +164,16 @@ static int attach_uprobes(struct gethostlatency_bpf *obj, struct bpf_link *links
+ 	}
+ 	links[0] = bpf_program__attach_uprobe(obj->progs.handle_entry, false,
+ 					      target_pid ?: -1, libc_path, func_off);
+-	if (!links[0]) {
+-		warn("failed to attach getaddrinfo: %d\n", -errno);
++	err = libbpf_get_error(links[0]);
++	if (err) {
++		warn("failed to attach getaddrinfo: %d\n", err);
+ 		return -1;
+ 	}
+ 	links[1] = bpf_program__attach_uprobe(obj->progs.handle_return, true,
+ 					      target_pid ?: -1, libc_path, func_off);
+-	if (!links[1]) {
+-		warn("failed to attach getaddrinfo: %d\n", -errno);
++	err = libbpf_get_error(links[1]);
++	if (err) {
++		warn("failed to attach getaddrinfo: %d\n", err);
+ 		return -1;
+ 	}
+ 
+@@ -182,14 +184,16 @@ static int attach_uprobes(struct gethostlatency_bpf *obj, struct bpf_link *links
+ 	}
+ 	links[2] = bpf_program__attach_uprobe(obj->progs.handle_entry, false,
+ 					      target_pid ?: -1, libc_path, func_off);
+-	if (!links[2]) {
+-		warn("failed to attach gethostbyname: %d\n", -errno);
++	err = libbpf_get_error(links[2]);
++	if (err) {
++		warn("failed to attach gethostbyname: %d\n", err);
+ 		return -1;
+ 	}
+ 	links[3] = bpf_program__attach_uprobe(obj->progs.handle_return, true,
+ 					      target_pid ?: -1, libc_path, func_off);
+-	if (!links[3]) {
+-		warn("failed to attach gethostbyname: %d\n", -errno);
++	err = libbpf_get_error(links[3]);
++	if (err) {
++		warn("failed to attach gethostbyname: %d\n", err);
+ 		return -1;
+ 	}
+ 
+@@ -200,14 +204,16 @@ static int attach_uprobes(struct gethostlatency_bpf *obj, struct bpf_link *links
+ 	}
+ 	links[4] = bpf_program__attach_uprobe(obj->progs.handle_entry, false,
+ 					      target_pid ?: -1, libc_path, func_off);
+-	if (!links[4]) {
+-		warn("failed to attach gethostbyname2: %d\n", -errno);
++	err = libbpf_get_error(links[4]);
++	if (err) {
++		warn("failed to attach gethostbyname2: %d\n", err);
+ 		return -1;
+ 	}
+ 	links[5] = bpf_program__attach_uprobe(obj->progs.handle_return, true,
+ 					      target_pid ?: -1, libc_path, func_off);
+-	if (!links[5]) {
+-		warn("failed to attach gethostbyname2: %d\n", -errno);
++	err = libbpf_get_error(links[5]);
++	if (err) {
++		warn("failed to attach gethostbyname2: %d\n", err);
+ 		return -1;
+ 	}
+ 
+@@ -221,6 +227,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct bpf_link *links[6] = {};
+ 	struct gethostlatency_bpf *obj;
+@@ -230,7 +237,11 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
+ 	libbpf_set_print(libbpf_print_fn);
+ 
+ 	obj = gethostlatency_bpf__open();
+@@ -251,10 +262,12 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		goto cleanup;
+ 
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
+ 	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++			&pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
+ 		warn("failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -270,8 +283,8 @@ int main(int argc, char **argv)
+ 
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			warn("error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			warn("error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/hardirqs.c b/libbpf-tools/hardirqs.c
+index a2475ef1..759b3949 100644
+--- a/libbpf-tools/hardirqs.c
++++ b/libbpf-tools/hardirqs.c
+@@ -185,9 +185,14 @@ int main(int argc, char **argv)
+ 		return 1;
+ 	}
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = hardirqs_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -207,27 +212,30 @@ int main(int argc, char **argv)
+ 	}
+ 
+ 	if (env.count) {
+-		obj->links.handle__irq_handler = bpf_program__attach(obj->progs.handle__irq_handler);
+-		if (!obj->links.handle__irq_handler) {
+-			err = -errno;
++		obj->links.handle__irq_handler =
++			bpf_program__attach(obj->progs.handle__irq_handler);
++		err = libbpf_get_error(obj->links.handle__irq_handler);
++		if (err) {
+ 			fprintf(stderr,
+ 				"failed to attach irq/irq_handler_entry: %s\n",
+-				strerror(-err));
++				strerror(err));
+ 		}
+ 	} else {
+-		obj->links.irq_handler_entry = bpf_program__attach(obj->progs.irq_handler_entry);
+-		if (!obj->links.irq_handler_entry) {
+-			err = -errno;
++		obj->links.irq_handler_entry =
++			bpf_program__attach(obj->progs.irq_handler_entry);
++		err = libbpf_get_error(obj->links.irq_handler_entry);
++		if (err) {
+ 			fprintf(stderr,
+ 				"failed to attach irq_handler_entry: %s\n",
+-				strerror(-err));
++				strerror(err));
+ 		}
+-		obj->links.irq_handler_exit_exit = bpf_program__attach(obj->progs.irq_handler_exit_exit);
+-		if (!obj->links.irq_handler_exit_exit) {
+-			err = -errno;
++		obj->links.irq_handler_exit_exit =
++			bpf_program__attach(obj->progs.irq_handler_exit_exit);
++		err = libbpf_get_error(obj->links.irq_handler_exit_exit);
++		if (err) {
+ 			fprintf(stderr,
+ 				"failed to attach irq_handler_exit: %s\n",
+-				strerror(-err));
++				strerror(err));
+ 		}
+ 	}
+ 
+diff --git a/libbpf-tools/ksnoop.c b/libbpf-tools/ksnoop.c
+index a6ea6107..a5f59a0f 100644
+--- a/libbpf-tools/ksnoop.c
++++ b/libbpf-tools/ksnoop.c
+@@ -38,6 +38,7 @@ static bool verbose = false;
+ static __u32 filter_pid;
+ static bool stack_mode;
+ 
++#define libbpf_errstr(val)	strerror(-libbpf_get_error(val))
+ 
+ static void __p(enum log_level level, char *level_str, char *fmt, ...)
+ {
+@@ -222,12 +223,14 @@ static int get_func_btf(struct btf *btf, struct func *func)
+ 		return -ENOENT;
+ 	}
+ 	type = btf__type_by_id(btf, func->id);
+-	if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC) {
++	if (libbpf_get_error(type) ||
++	    BTF_INFO_KIND(type->info) != BTF_KIND_FUNC) {
+ 		p_err("Error looking up function type via id '%d'", func->id);
+ 		return -EINVAL;
+ 	}
+ 	type = btf__type_by_id(btf, type->type);
+-	if (!type || BTF_INFO_KIND(type->info) != BTF_KIND_FUNC_PROTO) {
++	if (libbpf_get_error(type) ||
++	    BTF_INFO_KIND(type->info) != BTF_KIND_FUNC_PROTO) {
+ 		p_err("Error looking up function proto type via id '%d'",
+ 		      func->id);
+ 		return -EINVAL;
+@@ -341,16 +344,15 @@ static int trace_to_value(struct btf *btf, struct func *func, char *argname,
+ static struct btf *get_btf(const char *name)
+ {
+ 	struct btf *mod_btf;
+-	int err;
+ 
+ 	p_debug("getting BTF for %s",
+ 		name && strlen(name) > 0 ? name : "vmlinux");
+ 
+ 	if (!vmlinux_btf) {
+ 		vmlinux_btf = btf__load_vmlinux_btf();
+-		if (!vmlinux_btf) {
+-			err = -errno;
+-			p_err("No BTF, cannot determine type info: %s", strerror(-err));
++		if (libbpf_get_error(vmlinux_btf)) {
++			p_err("No BTF, cannot determine type info: %s",
++			      libbpf_errstr(vmlinux_btf));
+ 			return NULL;
+ 		}
+ 	}
+@@ -358,9 +360,9 @@ static struct btf *get_btf(const char *name)
+ 		return vmlinux_btf;
+ 
+ 	mod_btf = btf__load_module_btf(name, vmlinux_btf);
+-	if (!mod_btf) {
+-		err = -errno;
+-		p_err("No BTF for module '%s': %s", name, strerror(-err));
++	if (libbpf_get_error(mod_btf)) {
++		p_err("No BTF for module '%s': %s",
++		      name, libbpf_errstr(mod_btf));
+ 		return NULL;
+ 	}
+ 	return mod_btf;
+@@ -394,11 +396,11 @@ static char *type_id_to_str(struct btf *btf, __s32 type_id, char *str)
+ 	default:
+ 		do {
+ 			type = btf__type_by_id(btf, type_id);
+-			if (!type) {
++
++			if (libbpf_get_error(type)) {
+ 				name = "?";
+ 				break;
+ 			}
+-
+ 			switch (BTF_INFO_KIND(type->info)) {
+ 			case BTF_KIND_CONST:
+ 			case BTF_KIND_VOLATILE:
+@@ -553,17 +555,16 @@ static int parse_trace(char *str, struct trace *trace)
+ 		return ret;
+ 	}
+ 	trace->btf = get_btf(func->mod);
+-	if (!trace->btf) {
+-		ret = -errno;
++	if (libbpf_get_error(trace->btf)) {
+ 		p_err("could not get BTF for '%s': %s",
+ 		      strlen(func->mod) ? func->mod : "vmlinux",
+-		      strerror(-ret));
++		      libbpf_errstr(trace->btf));
+ 		return -ENOENT;
+ 	}
+ 	trace->dump = btf_dump__new(trace->btf, NULL, &opts, trace_printf);
+-	if (!trace->dump) {
+-		ret = -errno;
+-		p_err("could not create BTF dump : %n", strerror(-ret));
++	if (libbpf_get_error(trace->dump)) {
++		p_err("could not create BTF dump : %n",
++		      libbpf_errstr(trace->btf));
+ 		return -EINVAL;
+ 	}
+ 
+@@ -823,20 +824,20 @@ static int attach_traces(struct ksnoop_bpf *skel, struct trace *traces,
+ 			bpf_program__attach_kprobe(skel->progs.kprobe_entry,
+ 						   false,
+ 						   traces[i].func.name);
+-		if (!traces[i].links[0]) {
+-			ret = -errno;
++		ret = libbpf_get_error(traces[i].links[0]);
++		if (ret) {
+ 			p_err("Could not attach kprobe to '%s': %s",
+ 			      traces[i].func.name, strerror(-ret));
+ 				return ret;
+-		}
++			}
+ 		p_debug("Attached kprobe for '%s'", traces[i].func.name);
+ 
+ 		traces[i].links[1] =
+ 			bpf_program__attach_kprobe(skel->progs.kprobe_return,
+ 						   true,
+ 						   traces[i].func.name);
+-		if (!traces[i].links[1]) {
+-			ret = -errno;
++		ret = libbpf_get_error(traces[i].links[1]);
++		if (ret) {
+ 			p_err("Could not attach kretprobe to '%s': %s",
+ 			      traces[i].func.name, strerror(-ret));
+ 			return ret;
+@@ -848,6 +849,7 @@ static int attach_traces(struct ksnoop_bpf *skel, struct trace *traces,
+ 
+ static int cmd_trace(int argc, char **argv)
+ {
++	struct perf_buffer_opts pb_opts = {};
+ 	struct bpf_map *perf_map, *func_map;
+ 	struct perf_buffer *pb = NULL;
+ 	struct ksnoop_bpf *skel;
+@@ -860,8 +862,7 @@ static int cmd_trace(int argc, char **argv)
+ 
+ 	skel = ksnoop_bpf__open_and_load();
+ 	if (!skel) {
+-		ret = -errno;
+-		p_err("Could not load ksnoop BPF: %s", strerror(-ret));
++		p_err("Could not load ksnoop BPF: %s", libbpf_errstr(skel));
+ 		return 1;
+ 	}
+ 
+@@ -886,11 +887,12 @@ static int cmd_trace(int argc, char **argv)
+ 		goto cleanup;
+ 	}
+ 
+-	pb = perf_buffer__new(bpf_map__fd(perf_map), pages,
+-			      trace_handler, lost_handler, NULL, NULL);
+-	if (!pb) {
+-		ret = -errno;
+-		p_err("Could not create perf buffer: %s", strerror(-ret));
++	pb_opts.sample_cb = trace_handler;
++	pb_opts.lost_cb = lost_handler;
++	pb = perf_buffer__new(bpf_map__fd(perf_map), pages, &pb_opts);
++	if (libbpf_get_error(pb)) {
++		p_err("Could not create perf buffer: %s",
++		      libbpf_errstr(pb));
+ 		goto cleanup;
+ 	}
+ 
+@@ -904,8 +906,8 @@ static int cmd_trace(int argc, char **argv)
+ 
+ 	while (!exiting) {
+ 		ret = perf_buffer__poll(pb, 1);
+-		if (ret < 0 && ret != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-ret));
++		if (ret < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset ret to return 0 if exiting */
+@@ -1005,7 +1007,6 @@ int main(int argc, char *argv[])
+ 	if (argc < 0)
+ 		usage();
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
+ 	return cmd_select(argc, argv);
+diff --git a/libbpf-tools/llcstat.bpf.c b/libbpf-tools/llcstat.bpf.c
+index a36fc2df..fbd5b6c4 100644
+--- a/libbpf-tools/llcstat.bpf.c
++++ b/libbpf-tools/llcstat.bpf.c
+@@ -36,13 +36,13 @@ int trace_event(__u64 sample_period, bool miss)
+ 	return 0;
+ }
+ 
+-SEC("perf_event")
++SEC("perf_event/1")
+ int on_cache_miss(struct bpf_perf_event_data *ctx)
+ {
+ 	return trace_event(ctx->sample_period, true);
+ }
+ 
+-SEC("perf_event")
++SEC("perf_event/2")
+ int on_cache_ref(struct bpf_perf_event_data *ctx)
+ {
+ 	return trace_event(ctx->sample_period, false);
+diff --git a/libbpf-tools/llcstat.c b/libbpf-tools/llcstat.c
+index be437bc2..150dd38b 100644
+--- a/libbpf-tools/llcstat.c
++++ b/libbpf-tools/llcstat.c
+@@ -106,8 +106,10 @@ static int open_and_attach_perf_event(__u64 config, int period,
+ 			return -1;
+ 		}
+ 		links[i] = bpf_program__attach_perf_event(prog, fd);
+-		if (!links[i]) {
+-			fprintf(stderr, "failed to attach perf event on cpu: %d\n", i);
++		if (libbpf_get_error(links[i])) {
++			fprintf(stderr, "failed to attach perf event on cpu: "
++				"%d\n", i);
++			links[i] = NULL;
+ 			close(fd);
+ 			return -1;
+ 		}
+@@ -182,9 +184,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	nr_cpus = libbpf_num_possible_cpus();
+ 	if (nr_cpus < 0) {
+ 		fprintf(stderr, "failed to get # of possible cpus: '%s'!\n",
+diff --git a/libbpf-tools/mountsnoop.c b/libbpf-tools/mountsnoop.c
+index ac2acc45..0955f59e 100644
+--- a/libbpf-tools/mountsnoop.c
++++ b/libbpf-tools/mountsnoop.c
+@@ -249,6 +249,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct mountsnoop_bpf *obj;
+ 	int err;
+@@ -257,7 +258,11 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
+ 	libbpf_set_print(libbpf_print_fn);
+ 
+ 	obj = mountsnoop_bpf__open();
+@@ -280,10 +285,11 @@ int main(int argc, char **argv)
+ 		goto cleanup;
+ 	}
+ 
+-	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
++	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
+ 		warn("failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -302,8 +308,8 @@ int main(int argc, char **argv)
+ 
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/numamove.c b/libbpf-tools/numamove.c
+index 0747f841..66a53ed6 100644
+--- a/libbpf-tools/numamove.c
++++ b/libbpf-tools/numamove.c
+@@ -80,9 +80,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = numamove_bpf__open_and_load();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open and/or load BPF object\n");
+@@ -102,15 +107,18 @@ int main(int argc, char **argv)
+ 
+ 	signal(SIGINT, sig_handler);
+ 
+-	printf("%-10s %18s %18s\n", "TIME", "NUMA_migrations", "NUMA_migrations_ms");
++	printf("%-10s %18s %18s\n", "TIME", "NUMA_migrations",
++		"NUMA_migrations_ms");
+ 	while (!exiting) {
+ 		sleep(1);
+ 		time(&t);
+ 		tm = localtime(&t);
+ 		strftime(ts, sizeof(ts), "%H:%M:%S", tm);
+ 		printf("%-10s %18lld %18lld\n", ts,
+-			__atomic_exchange_n(&obj->bss->num, 0, __ATOMIC_RELAXED),
+-			__atomic_exchange_n(&obj->bss->latency, 0, __ATOMIC_RELAXED));
++			__atomic_exchange_n(&obj->bss->num, 0,
++					__ATOMIC_RELAXED),
++			__atomic_exchange_n(&obj->bss->latency, 0,
++					__ATOMIC_RELAXED));
+ 	}
+ 
+ cleanup:
+diff --git a/libbpf-tools/offcputime.c b/libbpf-tools/offcputime.c
+index 37a8ec2c..0582b158 100644
+--- a/libbpf-tools/offcputime.c
++++ b/libbpf-tools/offcputime.c
+@@ -279,9 +279,14 @@ int main(int argc, char **argv)
+ 		return 1;
+ 	}
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = offcputime_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+diff --git a/libbpf-tools/opensnoop.c b/libbpf-tools/opensnoop.c
+index 557a63cd..5cdac0e5 100644
+--- a/libbpf-tools/opensnoop.c
++++ b/libbpf-tools/opensnoop.c
+@@ -219,6 +219,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct opensnoop_bpf *obj;
+ 	__u64 time_end = 0;
+@@ -228,9 +229,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = opensnoop_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -276,10 +282,13 @@ int main(int argc, char **argv)
+ 	printf("%s\n", "PATH");
+ 
+ 	/* setup event callbacks */
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
+ 	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++			      &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
++		pb = NULL;
+ 		fprintf(stderr, "failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -297,8 +306,8 @@ int main(int argc, char **argv)
+ 	/* main: poll */
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		if (env.duration && get_ktime_ns() > time_end)
+diff --git a/libbpf-tools/readahead.c b/libbpf-tools/readahead.c
+index 17079389..77986011 100644
+--- a/libbpf-tools/readahead.c
++++ b/libbpf-tools/readahead.c
+@@ -109,9 +109,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = readahead_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+diff --git a/libbpf-tools/runqlat.c b/libbpf-tools/runqlat.c
+index 5a60b874..249bf794 100644
+--- a/libbpf-tools/runqlat.c
++++ b/libbpf-tools/runqlat.c
+@@ -193,9 +193,14 @@ int main(int argc, char **argv)
+ 		return 1;
+ 	}
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = runqlat_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+diff --git a/libbpf-tools/runqlen.c b/libbpf-tools/runqlen.c
+index 9cbbc739..2f6c5789 100644
+--- a/libbpf-tools/runqlen.c
++++ b/libbpf-tools/runqlen.c
+@@ -145,8 +145,10 @@ static int open_and_attach_perf_event(int freq, struct bpf_program *prog,
+ 			return -1;
+ 		}
+ 		links[i] = bpf_program__attach_perf_event(prog, fd);
+-		if (!links[i]) {
+-			fprintf(stderr, "failed to attach perf event on cpu: %d\n", i);
++		if (libbpf_get_error(links[i])) {
++			fprintf(stderr, "failed to attach perf event on cpu: "
++				"%d\n", i);
++			links[i] = NULL;
+ 			close(fd);
+ 			return -1;
+ 		}
+@@ -229,9 +231,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	nr_cpus = libbpf_num_possible_cpus();
+ 	if (nr_cpus < 0) {
+ 		printf("failed to get # of possible cpus: '%s'!\n",
+diff --git a/libbpf-tools/runqslower.c b/libbpf-tools/runqslower.c
+index b038173e..b21894ca 100644
+--- a/libbpf-tools/runqslower.c
++++ b/libbpf-tools/runqslower.c
+@@ -145,6 +145,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct runqslower_bpf *obj;
+ 	int err;
+@@ -153,9 +154,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = runqslower_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -185,10 +191,12 @@ int main(int argc, char **argv)
+ 	else
+ 		printf("%-8s %-16s %-6s %14s\n", "TIME", "COMM", "TID", "LAT(us)");
+ 
+-	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), 64,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
++	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), 64, &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
++		pb = NULL;
+ 		fprintf(stderr, "failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -201,8 +209,8 @@ int main(int argc, char **argv)
+ 
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, 100);
+-		if (err < 0 && err != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/softirqs.c b/libbpf-tools/softirqs.c
+index 34cfdb77..f1678d4c 100644
+--- a/libbpf-tools/softirqs.c
++++ b/libbpf-tools/softirqs.c
+@@ -195,9 +195,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = softirqs_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+diff --git a/libbpf-tools/solisten.c b/libbpf-tools/solisten.c
+index adaa668d..e5812f0c 100644
+--- a/libbpf-tools/solisten.c
++++ b/libbpf-tools/solisten.c
+@@ -137,6 +137,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct solisten_bpf *obj;
+ 	int err;
+@@ -145,7 +146,11 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
+ 	libbpf_set_print(libbpf_print_fn);
+ 
+ 	obj = solisten_bpf__open();
+@@ -175,10 +180,11 @@ int main(int argc, char **argv)
+ 		goto cleanup;
+ 	}
+ 
+-	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
++	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES, &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
+ 		warn("failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -196,8 +202,8 @@ int main(int argc, char **argv)
+ 
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			warn("error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			warn("error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/statsnoop.c b/libbpf-tools/statsnoop.c
+index 3f8f5c58..76779da6 100644
+--- a/libbpf-tools/statsnoop.c
++++ b/libbpf-tools/statsnoop.c
+@@ -127,6 +127,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct statsnoop_bpf *obj;
+ 	int err;
+@@ -135,9 +136,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %d\n", err);
++		return 1;
++	}
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++
+ 	obj = statsnoop_bpf__open();
+ 	if (!obj) {
+ 		warn("failed to open BPF object\n");
+@@ -159,10 +165,12 @@ int main(int argc, char **argv)
+ 		goto cleanup;
+ 	}
+ 
++	pb_opts.sample_cb = handle_event;
++	pb_opts.lost_cb = handle_lost_events;
+ 	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++			      &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
+ 		warn("failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -180,8 +188,8 @@ int main(int argc, char **argv)
+ 
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			warn("error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			warn("error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/syscount.c b/libbpf-tools/syscount.c
+index 2d687573..35c0e095 100644
+--- a/libbpf-tools/syscount.c
++++ b/libbpf-tools/syscount.c
+@@ -390,9 +390,14 @@ int main(int argc, char **argv)
+ 		goto free_names;
+ 	}
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %s\n", strerror(errno));
++		goto free_names;
++	}
++
+ 	obj = syscount_bpf__open();
+ 	if (!obj) {
+ 		warn("failed to open BPF object\n");
+@@ -418,15 +423,16 @@ int main(int argc, char **argv)
+ 	}
+ 
+ 	obj->links.sys_exit = bpf_program__attach(obj->progs.sys_exit);
+-	if (!obj->links.sys_exit) {
+-		err = -errno;
+-		warn("failed to attach sys_exit program: %s\n", strerror(-err));
++	err = libbpf_get_error(obj->links.sys_exit);
++	if (err) {
++		warn("failed to attach sys_exit program: %s\n",
++		     strerror(-err));
+ 		goto cleanup_obj;
+ 	}
+ 	if (env.latency) {
+ 		obj->links.sys_enter = bpf_program__attach(obj->progs.sys_enter);
+-		if (!obj->links.sys_enter) {
+-			err = -errno;
++		err = libbpf_get_error(obj->links.sys_enter);
++		if (err) {
+ 			warn("failed to attach sys_enter programs: %s\n",
+ 			     strerror(-err));
+ 			goto cleanup_obj;
+diff --git a/libbpf-tools/tcpconnect.c b/libbpf-tools/tcpconnect.c
+index 101cf72b..82b2bebb 100644
+--- a/libbpf-tools/tcpconnect.c
++++ b/libbpf-tools/tcpconnect.c
+@@ -324,13 +324,17 @@ static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt)
+ 
+ static void print_events(int perf_map_fd)
+ {
+-	struct perf_buffer *pb;
++	struct perf_buffer_opts pb_opts = {
++		.sample_cb = handle_event,
++		.lost_cb = handle_lost_events,
++	};
++	struct perf_buffer *pb = NULL;
+ 	int err;
+ 
+-	pb = perf_buffer__new(perf_map_fd, 128,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		err = -errno;
++	pb = perf_buffer__new(perf_map_fd, 128, &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
++		pb = NULL;
+ 		warn("failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+@@ -338,8 +342,8 @@ static void print_events(int perf_map_fd)
+ 	print_events_header();
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, 100);
+-		if (err < 0 && err != -EINTR) {
+-			warn("error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			warn("error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+@@ -365,9 +369,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		warn("failed to increase rlimit: %s\n", strerror(errno));
++		return 1;
++	}
++
+ 	obj = tcpconnect_bpf__open();
+ 	if (!obj) {
+ 		warn("failed to open BPF object\n");
+diff --git a/libbpf-tools/tcpconnlat.c b/libbpf-tools/tcpconnlat.c
+index 8eae76ae..3cab2115 100644
+--- a/libbpf-tools/tcpconnlat.c
++++ b/libbpf-tools/tcpconnlat.c
+@@ -161,6 +161,7 @@ int main(int argc, char **argv)
+ 		.parser = parse_arg,
+ 		.doc = argp_program_doc,
+ 	};
++	struct perf_buffer_opts pb_opts;
+ 	struct perf_buffer *pb = NULL;
+ 	struct tcpconnlat_bpf *obj;
+ 	int err;
+@@ -169,9 +170,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = tcpconnlat_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+@@ -193,10 +199,15 @@ int main(int argc, char **argv)
+ 		goto cleanup;
+ 	}
+ 
++	pb_opts.sample_cb = handle_event;
++
++	pb_opts.lost_cb = handle_lost_events;
+ 	pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
+-			      handle_event, handle_lost_events, NULL, NULL);
+-	if (!pb) {
+-		fprintf(stderr, "failed to open perf buffer: %d\n", errno);
++			      &pb_opts);
++	err = libbpf_get_error(pb);
++	if (err) {
++		pb = NULL;
++		fprintf(stderr, "failed to open perf buffer: %d\n", err);
+ 		goto cleanup;
+ 	}
+ 
+@@ -211,6 +222,7 @@ int main(int argc, char **argv)
+ 			"PID", "COMM", "IP", "SADDR", "DADDR", "DPORT", "LAT(ms)");
+ 	}
+ 
++
+ 	if (signal(SIGINT, sig_int) == SIG_ERR) {
+ 		fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
+ 		err = 1;
+@@ -220,8 +232,8 @@ int main(int argc, char **argv)
+ 	/* main: poll */
+ 	while (!exiting) {
+ 		err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
+-		if (err < 0 && err != -EINTR) {
+-			fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
++		if (err < 0 && errno != EINTR) {
++			fprintf(stderr, "error polling perf buffer: %s\n", strerror(errno));
+ 			goto cleanup;
+ 		}
+ 		/* reset err to return 0 if exiting */
+diff --git a/libbpf-tools/tcprtt.c b/libbpf-tools/tcprtt.c
+index bed6efa7..bdff55bb 100644
+--- a/libbpf-tools/tcprtt.c
++++ b/libbpf-tools/tcprtt.c
+@@ -225,9 +225,14 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %d\n", err);
++		return 1;
++	}
++
+ 	obj = tcprtt_bpf__open();
+ 	if (!obj) {
+ 		fprintf(stderr, "failed to open BPF object\n");
+diff --git a/libbpf-tools/trace_helpers.c b/libbpf-tools/trace_helpers.c
+index 322b3c4f..f37015e7 100644
+--- a/libbpf-tools/trace_helpers.c
++++ b/libbpf-tools/trace_helpers.c
+@@ -967,6 +967,16 @@ unsigned long long get_ktime_ns(void)
+ 	return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
+ }
+ 
++int bump_memlock_rlimit(void)
++{
++	struct rlimit rlim_new = {
++		.rlim_cur	= RLIM_INFINITY,
++		.rlim_max	= RLIM_INFINITY,
++	};
++
++	return setrlimit(RLIMIT_MEMLOCK, &rlim_new);
++}
++
+ bool is_kernel_module(const char *name)
+ {
+ 	bool found = false;
+@@ -997,22 +1007,20 @@ bool fentry_exists(const char *name, const char *mod)
+ 	const struct btf_type *type;
+ 	const struct btf_enum *e;
+ 	char sysfs_mod[80];
+-	int id = -1, i, err;
++	int id = -1, i;
+ 
+ 	base = btf__parse(sysfs_vmlinux, NULL);
+-	if (!base) {
+-		err = -errno;
++	if (libbpf_get_error(base)) {
+ 		fprintf(stderr, "failed to parse vmlinux BTF at '%s': %s\n",
+-			sysfs_vmlinux, strerror(-err));
++			sysfs_vmlinux, strerror(-libbpf_get_error(base)));
+ 		goto err_out;
+ 	}
+ 	if (mod && module_btf_exists(mod)) {
+ 		snprintf(sysfs_mod, sizeof(sysfs_mod), "/sys/kernel/btf/%s", mod);
+ 		btf = btf__parse_split(sysfs_mod, base);
+-		if (!btf) {
+-			err = -errno;
++		if (libbpf_get_error(btf)) {
+ 			fprintf(stderr, "failed to load BTF from %s: %s\n",
+-				sysfs_mod, strerror(-err));
++				sysfs_mod, strerror(-libbpf_get_error(btf)));
+ 			btf = base;
+ 			base = NULL;
+ 		}
+diff --git a/libbpf-tools/trace_helpers.h b/libbpf-tools/trace_helpers.h
+index 98fd640f..61cbe433 100644
+--- a/libbpf-tools/trace_helpers.h
++++ b/libbpf-tools/trace_helpers.h
+@@ -58,6 +58,7 @@ void print_linear_hist(unsigned int *vals, int vals_size, unsigned int base,
+ 		unsigned int step, const char *val_type);
+ 
+ unsigned long long get_ktime_ns(void);
++int bump_memlock_rlimit(void);
+ 
+ bool is_kernel_module(const char *name);
+ 
+diff --git a/libbpf-tools/vfsstat.c b/libbpf-tools/vfsstat.c
+index 5519c366..3a8a51d8 100644
+--- a/libbpf-tools/vfsstat.c
++++ b/libbpf-tools/vfsstat.c
+@@ -150,9 +150,15 @@ int main(int argc, char **argv)
+ 	if (err)
+ 		return err;
+ 
+-	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+ 	libbpf_set_print(libbpf_print_fn);
+ 
++	err = bump_memlock_rlimit();
++	if (err) {
++		fprintf(stderr, "failed to increase rlimit: %s\n",
++				strerror(errno));
++		return 1;
++	}
++
+ 	skel = vfsstat_bpf__open();
+ 	if (!skel) {
+ 		fprintf(stderr, "failed to open BPF skelect\n");
+-- 
+2.35.1
+
diff --git a/SOURCES/bcc-0.24.0-biolatency-biolatpcts-biosnoop-biotop-Build-fix-for-.patch b/SOURCES/bcc-0.24.0-biolatency-biolatpcts-biosnoop-biotop-Build-fix-for-.patch
new file mode 100644
index 0000000..da15c6e
--- /dev/null
+++ b/SOURCES/bcc-0.24.0-biolatency-biolatpcts-biosnoop-biotop-Build-fix-for-.patch
@@ -0,0 +1,125 @@
+From 879792d2d47c1308e884fb59d92fe535f7bb8d71 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Thu, 10 Mar 2022 08:37:21 -1000
+Subject: [PATCH 1/2] biolatency, biolatpcts, biosnoop, biotop: Build fix for
+ v5.17+
+
+During 5.17 dev cycle, the kernel dropped request->rq_disk. It can now be
+accessed through request->q->disk. Fix the python ones in tools/. There are
+more usages in other places which need to be fixed too.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
+---
+ tools/biolatency.py |  8 ++++++--
+ tools/biolatpcts.py | 11 ++++++++---
+ tools/biosnoop.py   |  6 +++++-
+ tools/biotop.py     |  9 +++++++--
+ 4 files changed, 26 insertions(+), 8 deletions(-)
+
+diff --git a/tools/biolatency.py b/tools/biolatency.py
+index 427cee47..10c852ac 100755
+--- a/tools/biolatency.py
++++ b/tools/biolatency.py
+@@ -128,12 +128,16 @@ storage_str = ""
+ store_str = ""
+ if args.disks:
+     storage_str += "BPF_HISTOGRAM(dist, disk_key_t);"
+-    store_str += """
++    disks_str = """
+     disk_key_t key = {.slot = bpf_log2l(delta)};
+-    void *__tmp = (void *)req->rq_disk->disk_name;
++    void *__tmp = (void *)req->__RQ_DISK__->disk_name;
+     bpf_probe_read(&key.disk, sizeof(key.disk), __tmp);
+     dist.atomic_increment(key);
+     """
++    if BPF.kernel_struct_has_field(b'request', b'rq_disk'):
++        store_str += disks_str.replace('__RQ_DISK__', 'rq_disk')
++    else:
++        store_str += disks_str.replace('__RQ_DISK__', 'q->disk')
+ elif args.flags:
+     storage_str += "BPF_HISTOGRAM(dist, flag_key_t);"
+     store_str += """
+diff --git a/tools/biolatpcts.py b/tools/biolatpcts.py
+index 0f334419..ea8b1ce6 100755
+--- a/tools/biolatpcts.py
++++ b/tools/biolatpcts.py
+@@ -72,9 +72,9 @@ void kprobe_blk_account_io_done(struct pt_regs *ctx, struct request *rq, u64 now
+         if (!rq->__START_TIME_FIELD__)
+                 return;
+ 
+-        if (!rq->rq_disk ||
+-            rq->rq_disk->major != __MAJOR__ ||
+-            rq->rq_disk->first_minor != __MINOR__)
++        if (!rq->__RQ_DISK__ ||
++            rq->__RQ_DISK__->major != __MAJOR__ ||
++            rq->__RQ_DISK__->first_minor != __MINOR__)
+                 return;
+ 
+         cmd_flags = rq->cmd_flags;
+@@ -142,6 +142,11 @@ bpf_source = bpf_source.replace('__START_TIME_FIELD__', start_time_field)
+ bpf_source = bpf_source.replace('__MAJOR__', str(major))
+ bpf_source = bpf_source.replace('__MINOR__', str(minor))
+ 
++if BPF.kernel_struct_has_field(b'request', b'rq_disk'):
++    bpf_source = bpf_source.replace('__RQ_DISK__', 'rq_disk')
++else:
++    bpf_source = bpf_source.replace('__RQ_DISK__', 'q->disk')
++
+ bpf = BPF(text=bpf_source)
+ if BPF.get_kprobe_functions(b'__blk_account_io_done'):
+     bpf.attach_kprobe(event="__blk_account_io_done", fn_name="kprobe_blk_account_io_done")
+diff --git a/tools/biosnoop.py b/tools/biosnoop.py
+index ae38e384..a2b636aa 100755
+--- a/tools/biosnoop.py
++++ b/tools/biosnoop.py
+@@ -125,7 +125,7 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req)
+         data.pid = valp->pid;
+         data.sector = req->__sector;
+         bpf_probe_read_kernel(&data.name, sizeof(data.name), valp->name);
+-        struct gendisk *rq_disk = req->rq_disk;
++        struct gendisk *rq_disk = req->__RQ_DISK__;
+         bpf_probe_read_kernel(&data.disk_name, sizeof(data.disk_name),
+                        rq_disk->disk_name);
+     }
+@@ -156,6 +156,10 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req)
+     bpf_text = bpf_text.replace('##QUEUE##', '1')
+ else:
+     bpf_text = bpf_text.replace('##QUEUE##', '0')
++if BPF.kernel_struct_has_field(b'request', b'rq_disk'):
++    bpf_text = bpf_text.replace('__RQ_DISK__', 'rq_disk')
++else:
++    bpf_text = bpf_text.replace('__RQ_DISK__', 'q->disk')
+ if debug or args.ebpf:
+     print(bpf_text)
+     if args.ebpf:
+diff --git a/tools/biotop.py b/tools/biotop.py
+index b3e3ea00..882835f6 100755
+--- a/tools/biotop.py
++++ b/tools/biotop.py
+@@ -129,8 +129,8 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req)
+ 
+     // setup info_t key
+     struct info_t info = {};
+-    info.major = req->rq_disk->major;
+-    info.minor = req->rq_disk->first_minor;
++    info.major = req->__RQ_DISK__->major;
++    info.minor = req->__RQ_DISK__->first_minor;
+ /*
+  * The following deals with a kernel version change (in mainline 4.7, although
+  * it may be backported to earlier kernels) with how block request write flags
+@@ -174,6 +174,11 @@ int trace_req_completion(struct pt_regs *ctx, struct request *req)
+     print(bpf_text)
+     exit()
+ 
++if BPF.kernel_struct_has_field(b'request', b'rq_disk'):
++    bpf_text = bpf_text.replace('__RQ_DISK__', 'rq_disk')
++else:
++    bpf_text = bpf_text.replace('__RQ_DISK__', 'q->disk')
++
+ b = BPF(text=bpf_text)
+ if BPF.get_kprobe_functions(b'__blk_account_io_start'):
+     b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start")
+-- 
+2.35.1
+
diff --git a/SOURCES/bcc-0.24.0-biolatpcts-Build-fixes-on-recent-kernels.patch b/SOURCES/bcc-0.24.0-biolatpcts-Build-fixes-on-recent-kernels.patch
new file mode 100644
index 0000000..e190cd5
--- /dev/null
+++ b/SOURCES/bcc-0.24.0-biolatpcts-Build-fixes-on-recent-kernels.patch
@@ -0,0 +1,60 @@
+From 2ada4cee035c4d07391faa870a5df1874d657b65 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Thu, 27 Jan 2022 06:25:31 -1000
+Subject: [PATCH 2/3] biolatpcts: Build fixes on recent kernels
+
+* `struct request` definition recently moved from blkdev.h to blk-mq.h
+  breaking both tools/biolatpcts and examples/tracing/biolatpcts. Fix them
+  by also including blk-mq.h.
+
+* blk_account_io_done() got split into two parts - inline condition checks
+  and the actual accounting with the latter now done in
+  __blk_account_io_done(). The kprobe attachment needs to be conditionalized
+  to work across the change. tools/biolatpcts was already updated but
+  examples/tracing/biolatpcts wasn't. Fix it.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+---
+ examples/tracing/biolatpcts.py | 6 +++++-
+ tools/biolatpcts.py            | 1 +
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/examples/tracing/biolatpcts.py b/examples/tracing/biolatpcts.py
+index c9bb834e..68a59516 100755
+--- a/examples/tracing/biolatpcts.py
++++ b/examples/tracing/biolatpcts.py
+@@ -11,6 +11,7 @@ from time import sleep
+ 
+ bpf_source = """
+ #include <linux/blk_types.h>
++#include <linux/blk-mq.h>
+ #include <linux/blkdev.h>
+ #include <linux/time64.h>
+ 
+@@ -45,7 +46,10 @@ void kprobe_blk_account_io_done(struct pt_regs *ctx, struct request *rq, u64 now
+ """
+ 
+ bpf = BPF(text=bpf_source)
+-bpf.attach_kprobe(event='blk_account_io_done', fn_name='kprobe_blk_account_io_done')
++if BPF.get_kprobe_functions(b'__blk_account_io_done'):
++    bpf.attach_kprobe(event="__blk_account_io_done", fn_name="kprobe_blk_account_io_done")
++else:
++    bpf.attach_kprobe(event="blk_account_io_done", fn_name="kprobe_blk_account_io_done")
+ 
+ cur_lat_100ms = bpf['lat_100ms']
+ cur_lat_1ms = bpf['lat_1ms']
+diff --git a/tools/biolatpcts.py b/tools/biolatpcts.py
+index a2f59592..0f334419 100755
+--- a/tools/biolatpcts.py
++++ b/tools/biolatpcts.py
+@@ -56,6 +56,7 @@ parser.add_argument('--verbose', '-v', action='count', default = 0)
+ bpf_source = """
+ #include <linux/blk_types.h>
+ #include <linux/blkdev.h>
++#include <linux/blk-mq.h>
+ #include <linux/time64.h>
+ 
+ BPF_PERCPU_ARRAY(rwdf_100ms, u64, 400);
+-- 
+2.35.1
+
diff --git a/SOURCES/bcc-0.24.0-libbpf-tools-Allow-to-use-different-cflags-for-bpf-t.patch b/SOURCES/bcc-0.24.0-libbpf-tools-Allow-to-use-different-cflags-for-bpf-t.patch
new file mode 100644
index 0000000..5d40363
--- /dev/null
+++ b/SOURCES/bcc-0.24.0-libbpf-tools-Allow-to-use-different-cflags-for-bpf-t.patch
@@ -0,0 +1,49 @@
+From a6a5dba23d19f6a900b0359a7390df4a6b9a42f4 Mon Sep 17 00:00:00 2001
+From: Jerome Marchand <jmarchan@redhat.com>
+Date: Tue, 15 Mar 2022 17:59:24 +0100
+Subject: [PATCH 1/3] libbpf-tools: Allow to use different cflags for bpf
+ targets
+
+commit 531b698cdc20 ("libbpf-tools: Enable compilation warnings for
+BPF programs") applies CFLAGS to all targets. However, some of the c
+flags typically used by distribution are not available to the bpf
+target. Add a new BPFCFLAGS macro to take care of that.
+
+Fixes the following compilation error on fedora:
+
+  BPF      bashreadline.bpf.o
+clang-13: warning: optimization flag '-ffat-lto-objects' is not supported [-Wignored-optimization-argument]
+clang-13: warning: argument unused during compilation: '-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1' [-Wunused-command-line-argument]
+clang-13: warning: argument unused during compilation: '-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1' [-Wunused-command-line-argument]
+clang-13: warning: argument unused during compilation: '-fstack-clash-protection' [-Wunused-command-line-argument]
+error: option 'cf-protection=return' cannot be specified on this target
+error: option 'cf-protection=branch' cannot be specified on this target
+2 errors generated.
+---
+ libbpf-tools/Makefile | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/libbpf-tools/Makefile b/libbpf-tools/Makefile
+index 6bf1ed08..39af95ec 100644
+--- a/libbpf-tools/Makefile
++++ b/libbpf-tools/Makefile
+@@ -7,6 +7,7 @@ LIBBPF_SRC := $(abspath ../src/cc/libbpf/src)
+ LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a)
+ INCLUDES := -I$(OUTPUT) -I../src/cc/libbpf/include/uapi
+ CFLAGS := -g -O2 -Wall
++BPFCFLAGS := -g -O2 -Wall
+ INSTALL ?= install
+ prefix ?= /usr/local
+ ARCH := $(shell uname -m | sed 's/x86_64/x86/' | sed 's/aarch64/arm64/' | sed 's/ppc64le/powerpc/' | sed 's/mips.*/mips/')
+@@ -106,7 +107,7 @@ $(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT)
+ 
+ $(OUTPUT)/%.bpf.o: %.bpf.c $(LIBBPF_OBJ) $(wildcard %.h) $(ARCH)/vmlinux.h | $(OUTPUT)
+ 	$(call msg,BPF,$@)
+-	$(Q)$(CLANG) $(CFLAGS) -target bpf -D__TARGET_ARCH_$(ARCH)	      \
++	$(Q)$(CLANG) $(BPFCFLAGS) -target bpf -D__TARGET_ARCH_$(ARCH)	      \
+ 		     -I$(ARCH)/ $(INCLUDES) -c $(filter %.c,$^) -o $@ &&      \
+ 	$(LLVM_STRIP) -g $@
+ 
+-- 
+2.35.1
+
diff --git a/SOURCES/bcc-0.24.0-libbpf-tools-Fix-dropped-request-rq_disk-for-kernel-.patch b/SOURCES/bcc-0.24.0-libbpf-tools-Fix-dropped-request-rq_disk-for-kernel-.patch
new file mode 100644
index 0000000..8134d1f
--- /dev/null
+++ b/SOURCES/bcc-0.24.0-libbpf-tools-Fix-dropped-request-rq_disk-for-kernel-.patch
@@ -0,0 +1,158 @@
+From 50480835adf15a389267393674504551b68987a2 Mon Sep 17 00:00:00 2001
+From: xingfeng2510 <xingfeng25100@163.com>
+Date: Wed, 30 Mar 2022 16:10:51 +0800
+Subject: [PATCH 2/2] libbpf-tools: Fix dropped request->rq_disk for kernel
+ 5.17+
+
+Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
+---
+ libbpf-tools/biolatency.bpf.c | 20 ++++++++++++++++++--
+ libbpf-tools/biosnoop.bpf.c   | 12 +++++++++++-
+ libbpf-tools/biostacks.bpf.c  | 12 +++++++++++-
+ libbpf-tools/bitesize.bpf.c   | 12 +++++++++++-
+ 4 files changed, 51 insertions(+), 5 deletions(-)
+
+diff --git a/libbpf-tools/biolatency.bpf.c b/libbpf-tools/biolatency.bpf.c
+index 648dda78..8f325046 100644
+--- a/libbpf-tools/biolatency.bpf.c
++++ b/libbpf-tools/biolatency.bpf.c
+@@ -19,6 +19,10 @@ const volatile bool targ_ms = false;
+ const volatile bool filter_dev = false;
+ const volatile __u32 targ_dev = 0;
+ 
++struct request_queue___x {
++	struct gendisk *disk;
++} __attribute__((preserve_access_index));
++
+ struct {
+ 	__uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
+ 	__type(key, u32);
+@@ -53,9 +57,15 @@ int trace_rq_start(struct request *rq, int issue)
+ 	u64 ts = bpf_ktime_get_ns();
+ 
+ 	if (filter_dev) {
+-		struct gendisk *disk = BPF_CORE_READ(rq, rq_disk);
++		struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q);
++		struct gendisk *disk;
+ 		u32 dev;
+ 
++		if (bpf_core_field_exists(q->disk))
++			disk = BPF_CORE_READ(q, disk);
++		else
++			disk = BPF_CORE_READ(rq, rq_disk);
++
+ 		dev = disk ? MKDEV(BPF_CORE_READ(disk, major),
+ 				BPF_CORE_READ(disk, first_minor)) : 0;
+ 		if (targ_dev != dev)
+@@ -119,7 +129,13 @@ int BPF_PROG(block_rq_complete, struct request *rq, int error,
+ 		goto cleanup;
+ 
+ 	if (targ_per_disk) {
+-		struct gendisk *disk = BPF_CORE_READ(rq, rq_disk);
++		struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q);
++		struct gendisk *disk;
++
++		if (bpf_core_field_exists(q->disk))
++			disk = BPF_CORE_READ(q, disk);
++		else
++			disk = BPF_CORE_READ(rq, rq_disk);
+ 
+ 		hkey.dev = disk ? MKDEV(BPF_CORE_READ(disk, major),
+ 					BPF_CORE_READ(disk, first_minor)) : 0;
+diff --git a/libbpf-tools/biosnoop.bpf.c b/libbpf-tools/biosnoop.bpf.c
+index 54226e43..05903473 100644
+--- a/libbpf-tools/biosnoop.bpf.c
++++ b/libbpf-tools/biosnoop.bpf.c
+@@ -15,6 +15,10 @@ const volatile __u32 targ_dev = 0;
+ 
+ extern __u32 LINUX_KERNEL_VERSION __kconfig;
+ 
++struct request_queue___x {
++	struct gendisk *disk;
++} __attribute__((preserve_access_index));
++
+ struct {
+ 	__uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
+ 	__type(key, u32);
+@@ -92,7 +96,13 @@ int trace_rq_start(struct request *rq, bool insert)
+ 
+ 	stagep = bpf_map_lookup_elem(&start, &rq);
+ 	if (!stagep) {
+-		struct gendisk *disk = BPF_CORE_READ(rq, rq_disk);
++		struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q);
++		struct gendisk *disk;
++
++		if (bpf_core_field_exists(q->disk))
++			disk = BPF_CORE_READ(q, disk);
++		else
++			disk = BPF_CORE_READ(rq, rq_disk);
+ 
+ 		stage.dev = disk ? MKDEV(BPF_CORE_READ(disk, major),
+ 				BPF_CORE_READ(disk, first_minor)) : 0;
+diff --git a/libbpf-tools/biostacks.bpf.c b/libbpf-tools/biostacks.bpf.c
+index 01993737..c13975fa 100644
+--- a/libbpf-tools/biostacks.bpf.c
++++ b/libbpf-tools/biostacks.bpf.c
+@@ -14,6 +14,10 @@ const volatile bool targ_ms = false;
+ const volatile bool filter_dev = false;
+ const volatile __u32 targ_dev = -1;
+ 
++struct request_queue___x {
++	struct gendisk *disk;
++} __attribute__((preserve_access_index));
++
+ struct internal_rqinfo {
+ 	u64 start_ts;
+ 	struct rqinfo rqinfo;
+@@ -41,9 +45,15 @@ static __always_inline
+ int trace_start(void *ctx, struct request *rq, bool merge_bio)
+ {
+ 	struct internal_rqinfo *i_rqinfop = NULL, i_rqinfo = {};
+-	struct gendisk *disk = BPF_CORE_READ(rq, rq_disk);
++	struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q);
++	struct gendisk *disk;
+ 	u32 dev;
+ 
++	if (bpf_core_field_exists(q->disk))
++		disk = BPF_CORE_READ(q, disk);
++	else
++		disk = BPF_CORE_READ(rq, rq_disk);
++
+ 	dev = disk ? MKDEV(BPF_CORE_READ(disk, major),
+ 			BPF_CORE_READ(disk, first_minor)) : 0;
+ 	if (filter_dev && targ_dev != dev)
+diff --git a/libbpf-tools/bitesize.bpf.c b/libbpf-tools/bitesize.bpf.c
+index 80672c9b..5066ca33 100644
+--- a/libbpf-tools/bitesize.bpf.c
++++ b/libbpf-tools/bitesize.bpf.c
+@@ -13,6 +13,10 @@ const volatile __u32 targ_dev = 0;
+ 
+ extern __u32 LINUX_KERNEL_VERSION __kconfig;
+ 
++struct request_queue___x {
++	struct gendisk *disk;
++} __attribute__((preserve_access_index));
++
+ struct {
+ 	__uint(type, BPF_MAP_TYPE_HASH);
+ 	__uint(max_entries, 10240);
+@@ -41,9 +45,15 @@ static int trace_rq_issue(struct request *rq)
+ 	u64 slot;
+ 
+ 	if (filter_dev) {
+-		struct gendisk *disk = BPF_CORE_READ(rq, rq_disk);
++		struct request_queue___x *q = (void *)BPF_CORE_READ(rq, q);
++		struct gendisk *disk;
+ 		u32 dev;
+ 
++		if (bpf_core_field_exists(q->disk))
++			disk = BPF_CORE_READ(q, disk);
++		else
++			disk = BPF_CORE_READ(rq, rq_disk);
++
+ 		dev = disk ? MKDEV(BPF_CORE_READ(disk, major),
+ 				BPF_CORE_READ(disk, first_minor)) : 0;
+ 		if (targ_dev != dev)
+-- 
+2.35.1
+
diff --git a/SOURCES/bcc-0.24.0-tools-include-blk-mq.h-in-bio-tools.patch b/SOURCES/bcc-0.24.0-tools-include-blk-mq.h-in-bio-tools.patch
new file mode 100644
index 0000000..1f7ce06
--- /dev/null
+++ b/SOURCES/bcc-0.24.0-tools-include-blk-mq.h-in-bio-tools.patch
@@ -0,0 +1,66 @@
+From 1eafb1f5aa0d3a9f60f89aad0ea55ae93899baff Mon Sep 17 00:00:00 2001
+From: Jerome Marchand <jmarchan@redhat.com>
+Date: Wed, 23 Feb 2022 16:04:30 +0100
+Subject: [PATCH 3/3] tools: include blk-mq.h in bio tools
+
+Kernel commit 24b83deb29b ("block: move struct request to blk-mq.h")
+has moved struct request  from blkdev.h to blk-mq.h. It results in
+several bio tools to fail with errors of the following type:
+
+error: incomplete definition of type 'struct request'
+
+Since blk-mq.h had always included blkdev.h. it is safe to simply
+replace the inclusion of blkdev.h by blk-mq-h. It works on both older
+and newer kernel.
+
+Fixes: #3869
+
+Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
+---
+ tools/biolatency.py | 2 +-
+ tools/biosnoop.py   | 2 +-
+ tools/biotop.py     | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/tools/biolatency.py b/tools/biolatency.py
+index f4e2c9ea..427cee47 100755
+--- a/tools/biolatency.py
++++ b/tools/biolatency.py
+@@ -64,7 +64,7 @@ debug = 0
+ # define BPF program
+ bpf_text = """
+ #include <uapi/linux/ptrace.h>
+-#include <linux/blkdev.h>
++#include <linux/blk-mq.h>
+ 
+ typedef struct disk_key {
+     char disk[DISK_NAME_LEN];
+diff --git a/tools/biosnoop.py b/tools/biosnoop.py
+index 2b954ac9..ae38e384 100755
+--- a/tools/biosnoop.py
++++ b/tools/biosnoop.py
+@@ -37,7 +37,7 @@ debug = 0
+ # define BPF program
+ bpf_text="""
+ #include <uapi/linux/ptrace.h>
+-#include <linux/blkdev.h>
++#include <linux/blk-mq.h>
+ 
+ // for saving the timestamp and __data_len of each request
+ struct start_req_t {
+diff --git a/tools/biotop.py b/tools/biotop.py
+index eac4dab9..b3e3ea00 100755
+--- a/tools/biotop.py
++++ b/tools/biotop.py
+@@ -54,7 +54,7 @@ diskstats = "/proc/diskstats"
+ # load BPF program
+ bpf_text = """
+ #include <uapi/linux/ptrace.h>
+-#include <linux/blkdev.h>
++#include <linux/blk-mq.h>
+ 
+ // for saving the timestamp and __data_len of each request
+ struct start_req_t {
+-- 
+2.35.1
+
diff --git a/SOURCES/bcc-0.24.0-tools-mdflush-include-blkdev.h-instead-of-genhd.h.patch b/SOURCES/bcc-0.24.0-tools-mdflush-include-blkdev.h-instead-of-genhd.h.patch
new file mode 100644
index 0000000..18edfb4
--- /dev/null
+++ b/SOURCES/bcc-0.24.0-tools-mdflush-include-blkdev.h-instead-of-genhd.h.patch
@@ -0,0 +1,30 @@
+From 93a464e2ef05b7ef78b5679e366b89fcddf6a575 Mon Sep 17 00:00:00 2001
+From: Jerome Marchand <jmarchan@redhat.com>
+Date: Mon, 1 Aug 2022 11:45:41 +0200
+Subject: [PATCH] tools/mdflush: include blkdev.h instead of genhd.h
+
+In recent kernels, i.e. since commit 322cbb50de71 ("block: remove
+genhd.h"), genhd.h header has been removed and its content moved to
+blkdev.h. Since genhd.h has been included in blkdev.h since forever,
+including blkdev instead of genhd in the mdflush tool works for both
+older and newer kernel.
+---
+ tools/mdflush.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/mdflush.py b/tools/mdflush.py
+index 3581d1bf..6741d563 100755
+--- a/tools/mdflush.py
++++ b/tools/mdflush.py
+@@ -19,7 +19,7 @@ from time import strftime
+ b = BPF(text="""
+ #include <uapi/linux/ptrace.h>
+ #include <linux/sched.h>
+-#include <linux/genhd.h>
++#include <linux/blkdev.h>
+ #include <linux/bio.h>
+ 
+ struct data_t {
+-- 
+2.37.1
+
diff --git a/SPECS/bcc.spec b/SPECS/bcc.spec
index ada1d4e..42396df 100644
--- a/SPECS/bcc.spec
+++ b/SPECS/bcc.spec
@@ -22,31 +22,23 @@
 %global with_llvm_shared 1
 %endif
 
-# Force out of source build
-%undefine __cmake_in_source_build
 
 Name:           bcc
-Version:        0.20.0
-Release:        10%{?dist}
+Version:        0.24.0
+Release:        4%{?dist}
 Summary:        BPF Compiler Collection (BCC)
 License:        ASL 2.0
 URL:            https://github.com/iovisor/bcc
 Source0:        %{url}/archive/v%{version}/%{name}-%{version}.tar.gz
-Patch0:         %{name}-%{version}-libbpf-tool-don-t-ignore-LDFLAGS.patch
-Patch1:         %{name}-%{version}-libbpf-tools-readahead-don-t-mark-struct-hist-as-sta.patch
-Patch2:         %{name}-%{version}-Define-KERNEL_VERSION.patch
-Patch3:         %{name}-%{version}-Revert-libbpf-tools-remove-unecessary-custom-NULL-de.patch
-Patch4:         %{name}-%{version}-sync-with-latest-libbpf-repo-3529.patch
-Patch5:         %{name}-%{version}-threadsnoop-look-for-pthread_create-in-libc-too.patch
-Patch6:         %{name}-%{version}-Update-cpudist.py.patch
-Patch7:         %{name}-%{version}-tools-readahead-compatible-with-kernel-version-5.10-.patch
-Patch8:         %{name}-%{version}-Fix-mdflush-on-RHEL9.patch
-Patch9:         %{name}-%{version}-Handle-renaming-of-task_struct_-state-field-on-RHEL-.patch
-Patch10:        %{name}-%{version}-Fix-a-llvm-compilation-error.patch
-Patch11:        %{name}-%{version}-Remove-APInt-APSInt-toString-std-string-variants.patch
-Patch12:        %{name}-%{version}-tools-Fix-BCC-bio-tools-with-recent-kernel-change.patch
-Patch13:        %{name}-%{version}-biolatpcts-Build-fixes-on-recent-kernels.patch
-Patch14:        %{name}-%{version}-tools-include-blk-mq.h-in-bio-tools.patch
+Patch0:         %{name}-%{version}-libbpf-tools-Allow-to-use-different-cflags-for-bpf-t.patch
+Patch1:         %{name}-%{version}-biolatpcts-Build-fixes-on-recent-kernels.patch
+Patch2:         %{name}-%{version}-tools-include-blk-mq.h-in-bio-tools.patch
+Patch3:         %{name}-%{version}-C9S-libpbf-version-fixes.patch
+Patch4:         %{name}-%{version}-Revert-libbpf-1.0-changes.patch
+Patch5:         %{name}-%{version}-C9S-Fix-mdflush.patch
+Patch6:         %{name}-%{version}-biolatency-biolatpcts-biosnoop-biotop-Build-fix-for-.patch
+Patch7:         %{name}-%{version}-libbpf-tools-Fix-dropped-request-rq_disk-for-kernel-.patch
+Patch8:         %{name}-%{version}-tools-mdflush-include-blkdev.h-instead-of-genhd.h.patch
 
 # Arches will be included as upstream support is added and dependencies are
 # satisfied in the respective arches
@@ -58,6 +50,7 @@ BuildRequires:  flex
 BuildRequires:  libxml2-devel
 BuildRequires:  python3-devel
 BuildRequires:  elfutils-libelf-devel
+BuildRequires:  elfutils-debuginfod-client-devel
 BuildRequires:  llvm-devel
 BuildRequires:  clang-devel
 %if %{with llvm_static}
@@ -67,9 +60,9 @@ BuildRequires:  ncurses-devel
 %if %{with lua}
 BuildRequires:  pkgconfig(luajit)
 %endif
-BuildRequires:  libbpf-devel >= 0.0.5-3, libbpf-static >= 0.0.5-3
+BuildRequires:  libbpf-devel >= 0.6.0, libbpf-static >= 0.6.0
 
-Requires:       libbpf >= 0.0.5-3
+Requires:       libbpf >= 0.6.0
 Requires:       tar
 Recommends:     kernel-devel
 
@@ -88,6 +81,7 @@ performance analysis and network traffic control.
 %package devel
 Summary:        Shared library for BPF Compiler Collection (BCC)
 Requires:       %{name}%{?_isa} = %{version}-%{release}
+Suggests:       elfutils-debuginfod-client
 
 %description devel
 The %{name}-devel package contains libraries and header files for developing
@@ -135,7 +129,6 @@ Command line tools for BPF Compiler Collection (BCC)
 %if %{with libbpf_tools}
 %package -n libbpf-tools
 Summary:        Command line libbpf tools for BPF Compiler Collection (BCC)
-BuildRequires:  libbpf-devel >= 0.0.5-3, libbpf-static >= 0.0.5-3
 BuildRequires:  bpftool
 
 %description -n libbpf-tools
@@ -147,11 +140,10 @@ Command line libbpf tools for BPF Compiler Collection (BCC)
 
 
 %build
-%cmake . \
-        -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-        -DREVISION_LAST=%{version} -DREVISION=%{version} -DPYTHON_CMD=python3 \
-        -DCMAKE_USE_LIBBPF_PACKAGE:BOOL=TRUE \
-        %{?with_llvm_shared:-DENABLE_LLVM_SHARED=1}
+%cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+       -DREVISION_LAST=%{version} -DREVISION=%{version} -DPYTHON_CMD=python3 \
+       -DCMAKE_USE_LIBBPF_PACKAGE:BOOL=TRUE \
+       %{?with_llvm_shared:-DENABLE_LLVM_SHARED=1}
 %cmake_build
 
 # It was discussed and agreed to package libbpf-tools with
@@ -163,7 +155,17 @@ Command line libbpf tools for BPF Compiler Collection (BCC)
 pushd libbpf-tools;
 make BPFTOOL=bpftool LIBBPF_OBJ=%{_libdir}/libbpf.a CFLAGS="%{optflags}" LDFLAGS="%{build_ldflags}"
 make DESTDIR=./tmp-install prefix= install
-(cd tmp-install/bin; for file in *; do mv $file bpf-$file; done;)
+(
+    cd tmp-install/bin
+    for file in *; do
+        mv $file bpf-$file
+    done
+    # now fix the broken symlinks
+    for file in `find . -type l`; do
+        dest=$(readlink "$file")
+        ln -s -f bpf-$dest $file
+    done
+)
 popd
 %endif
 
@@ -197,7 +199,10 @@ rm -rf %{buildroot}%{_datadir}/%{name}/tools/old/
 
 %if %{with libbpf_tools}
 mkdir -p %{buildroot}/%{_sbindir}
-install libbpf-tools/tmp-install/bin/* %{buildroot}/%{_sbindir}
+# We cannot use `install` because some of the tools are symlinks and `install`
+# follows those. Since all the tools already have the correct permissions set,
+# we just need to copy them to the right place while preserving those
+cp -a libbpf-tools/tmp-install/bin/* %{buildroot}/%{_sbindir}/
 %endif
 
 %ldconfig_scriptlets
@@ -257,6 +262,19 @@ install libbpf-tools/tmp-install/bin/* %{buildroot}/%{_sbindir}
 %endif
 
 %changelog
+* Tue Aug 23 2022 Jerome Marchand <jmarchan@redhat.com> - 0.24.1-4
+- Fix mdflush tool (rhbz#2108001)
+
+* Fri Jul 01 2022 Jerome Marchand <jmarchan@redhat.com> - 0.24.1-3
+- Rebuild for libbpf 0.6.0
+
+* Wed May 18 2022 Jerome Marchand <jmarchan@redhat.com> - 0.24.1-2
+- Rebuild (previous build failed with UNKNOWN_KOJI_ERROR)
+
+* Thu Mar 24 2022 Jerome Marchand <jmarchan@redhat.com> - 0.24.0-1
+- Rebase to v0.24.0
+- Fix cmake build
+
 * Fri Feb 25 2022 Jerome Marchand <jmarchan@redhat.com> - 0.20.0-10
 - Remove deprecated python_provides macro (needed for gating)