Thread (15 messages) flat view 15 messages, 3 authors, 2020-09-29

Re: [PATCH v6 bpf-next 6/6] selftests/bpf: add test for bpf_seq_printf_btf helper

From: Alexei Starovoitov <hidden>
Date: 2020-09-25 01:26:28
Also in: bpf, linux-kselftest, lkml
Subsystem: bpf [general] (safe dynamic programs and tools), bpf [iterator], the rest · Maintainers: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Yonghong Song, Linus Torvalds

On Wed, Sep 23, 2020 at 06:46:28PM +0100, Alan Maguire wrote:
Add a test verifying iterating over tasks and displaying BTF
representation of data succeeds.  Note here that we do not display
the task_struct itself, as it will overflow the PAGE_SIZE limit on seq
data; instead we write task->fs (a struct fs_struct).
Yeah. I've tried to print task_struct before reading above comment and
it took me long time to figure out what 'read failed: Argument list too long' means.
How can we improve usability of this helper?

We can bump:
--- a/kernel/bpf/bpf_iter.c
+++ b/kernel/bpf/bpf_iter.c
@@ -88,8 +88,8 @@ static ssize_t bpf_seq_read(struct file *file, char __user *buf, size_t size,
        mutex_lock(&seq->lock);

        if (!seq->buf) {
-               seq->size = PAGE_SIZE;
+               seq->size = PAGE_SIZE * 32;
to whatever number, but printing single task_struct needs ~800 lines and
~18kbytes. Humans can scroll through that much spam, but can we make it less
verbose by default somehow?
May be not in this patch set, but in the follow up?
+SEC("iter/task")
+int dump_task_fs_struct(struct bpf_iter__task *ctx)
+{
+	static const char fs_type[] = "struct fs_struct";
+	struct seq_file *seq = ctx->meta->seq;
+	struct task_struct *task = ctx->task;
+	struct fs_struct *fs = (void *)0;
+	static struct btf_ptr ptr = { };
+	long ret;
+
+	if (task)
+		fs = task->fs;
+
+	ptr.type = fs_type;
+	ptr.ptr = fs;
imo the following is better:
       ptr.type_id = __builtin_btf_type_id(*fs, 1);
       ptr.ptr = fs;
+
+	if (ctx->meta->seq_num == 0)
+		BPF_SEQ_PRINTF(seq, "Raw BTF fs_struct per task\n");
+
+	ret = bpf_seq_printf_btf(seq, &ptr, sizeof(ptr), 0);
+	switch (ret) {
+	case 0:
+		tasks++;
+		break;
+	case -ERANGE:
+		/* NULL task or task->fs, don't count it as an error. */
+		break;
+	default:
+		seq_err = ret;
+		break;
+	}
Please add handling of E2BIG to this switch. Otherwise
printing large amount of tiny structs will overflow PAGE_SIZE and E2BIG
will be send to user space.
Like this:
@@ -40,6 +40,8 @@ int dump_task_fs_struct(struct bpf_iter__task *ctx)
        case -ERANGE:
                /* NULL task or task->fs, don't count it as an error. */
                break;
+       case -E2BIG:
+               return 1;
Also please change bpf_seq_read() like this:
diff --git a/kernel/bpf/bpf_iter.c b/kernel/bpf/bpf_iter.c
index 30833bbf3019..8f10e30ea0b0 100644
--- a/kernel/bpf/bpf_iter.c
+++ b/kernel/bpf/bpf_iter.c
@@ -88,8 +88,8 @@ static ssize_t bpf_seq_read(struct file *file, char __user *buf, size_t size,
        mutex_lock(&seq->lock);

        if (!seq->buf) {
-               seq->size = PAGE_SIZE;
-               seq->buf = kmalloc(seq->size, GFP_KERNEL);
+               seq->size = PAGE_SIZE << 3;
+               seq->buf = kvmalloc(seq->size, GFP_KERNEL);
So users can print task_struct by default.
Hopefully we will figure out how to deal with spam later.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help