From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
Date: Fri, 22 Apr 2022 14:07:34 +0800
Subject: bpf: selftests: adapt bpf_iter_task_vma to get_inode_dev()
Patch-mainline: Never, work-around for SUSE-specific patch
References: bsc#927455 bsc#1198585
We carry two patches to allow differentiating btrfs subvolumes through dev_t,
namely:
patches.suse/vfs-add-super_operations-get_inode_dev
patches.suse/btrfs-provide-super_operations-get_inode_dev
Which cause the BPF iterator task_vma test to fail when running on btrfs
because /proc/[PID]/maps exported dev_t (obtained through get_inode_dev()) is
different from what the BPF program gets with file->f_inode->i_sb->s_dev for
files in subvolumes.
This patch workaround the difference by treating inodes associated with btrfs
differently (determined through struct super_operations*), replicating
btrfs_get_inode_dev() with BPF helpers.
In order to replicate btrfs_get_inode_dev(), definition of btrfs-related
structs is needed, this is solved by hacking the build system to generate
header file from btrfs BTF instead of vmlinux, which shouldn't make much
difference for testing.
Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
---
tools/testing/selftests/bpf/Makefile | 15 ++++++++++++++-
tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c | 13 ++++++++++++-
2 files changed, 26 insertions(+), 2 deletions(-)
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -138,6 +138,14 @@ VMLINUX_BTF ?= $(abspath $(firstword $(w
ifeq ($(VMLINUX_BTF),)
$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)")
endif
+BTRFS_BTF_PATHS ?= $(if $(O),$(O)/fs/btrfs/btrfs.ko) \
+ $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/fs/btrfs/btrfs.ko) \
+ ../../../../fs/btrfs/btrfs.ko \
+ /sys/kernel/btf/btrfs
+BTRFS_BTF ?= $(abspath $(firstword $(wildcard $(BTRFS_BTF_PATHS))))
+ifeq ($(BTRFS_BTF),)
+$(error Cannot find a btrfs.ko for BTRFS_BTF at any of "$(BTRFS_BTF_PATHS)")
+endif
# Define simple and short `make test_progs`, `make test_sysctl`, etc targets
# to build individual tests.
@@ -242,7 +250,12 @@ endif
$(INCLUDE_DIR)/vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR)
ifeq ($(VMLINUX_H),)
$(call msg,GEN,,$@)
- $(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@
+ # This is a lie, we're dumping BTF of the btrfs modules because we need
+ # definition of btrfs-related definitions (see bsc#1198585). But since
+ # the header file generated also contains vmlinux definiton (more
+ # specifically, it is a superset of vmlinux definition), it can be used
+ # in places where vmlinux.h is expected.
+ $(Q)$(BPFTOOL) btf dump --base-btf $(VMLINUX_BTF) file $(BTRFS_BTF) format c > $@
else
$(call msg,CP,,$@)
$(Q)cp "$(VMLINUX_H)" $@
--- a/tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c
+++ b/tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */
#include "bpf_iter.h"
+#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
char _license[] SEC("license") = "GPL";
@@ -17,6 +18,9 @@ char _license[] SEC("license") = "GPL";
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
+/* libbpf will fill-in the address of the symbol */
+extern const void btrfs_super_ops __ksym;
+
#define D_PATH_BUF_SIZE 1024
char d_path_buf[D_PATH_BUF_SIZE] = {};
__u32 pid = 0;
@@ -42,7 +46,14 @@ SEC("iter/task_vma") int proc_maps(struc
BPF_SEQ_PRINTF(seq, "%08llx-%08llx %s ", vma->vm_start, vma->vm_end, perm_str);
if (file) {
- __u32 dev = file->f_inode->i_sb->s_dev;
+ __u32 dev;
+ if (file->f_inode->i_sb->s_op == &btrfs_super_ops) {
+ /* BTRFS is treated specially, see bsc#1198585 */
+ struct btrfs_inode *inode = container_of(file->f_inode, struct btrfs_inode, vfs_inode);
+ dev = BPF_CORE_READ(inode, root, anon_dev);
+ } else {
+ dev = file->f_inode->i_sb->s_dev;
+ }
bpf_d_path(&file->f_path, d_path_buf, D_PATH_BUF_SIZE);