On Fri, 2022-08-26 at 12:30 -0700, Yonghong Song wrote: > > > On 8/25/22 5:37 PM, Kui-Feng Lee wrote: > > Allow creating an iterator that loops through resources of one > > thread/process. > > > > People could only create iterators to loop through all resources of > > files, vma, and tasks in the system, even though they were > > interested > > in only the resources of a specific task or process. Passing the > > additional parameters, people can now create an iterator to go > > through all resources or only the resources of a task. > > > > Signed-off-by: Kui-Feng Lee <kuifeng@xxxxxx> > > Acked-by: Yonghong Song <yhs@xxxxxx> > > --- > > include/linux/bpf.h | 25 +++++++ > > include/uapi/linux/bpf.h | 6 ++ > > kernel/bpf/task_iter.c | 128 ++++++++++++++++++++++++++-- > > ----- > > tools/include/uapi/linux/bpf.h | 6 ++ > > 4 files changed, 141 insertions(+), 24 deletions(-) > > > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > > index 9c1674973e03..31ac2c1181f5 100644 > > --- a/include/linux/bpf.h > > +++ b/include/linux/bpf.h > > @@ -1730,6 +1730,27 @@ int bpf_obj_get_user(const char __user > > *pathname, int flags); > > extern int bpf_iter_ ## target(args); \ > > int __init bpf_iter_ ## target(args) { return 0; } > > > > +/* > > + * The task type of iterators. > > + * > > + * For BPF task iterators, they can be parameterized with various > > + * parameters to visit only some of tasks. > > + * > > + * BPF_TASK_ITER_ALL (default) > > + * Iterate over resources of every task. > > + * > > + * BPF_TASK_ITER_TID > > + * Iterate over resources of a task/tid. > > + * > > + * BPF_TASK_ITER_TGID > > + * Iterate over resources of every task of a process / task > > group. > > + */ > > +enum bpf_iter_task_type { > > + BPF_TASK_ITER_ALL = 0, > > + BPF_TASK_ITER_TID, > > + BPF_TASK_ITER_TGID, > > +}; > > + > > struct bpf_iter_aux_info { > > /* for map_elem iter */ > > struct bpf_map *map; > > @@ -1739,6 +1760,10 @@ struct bpf_iter_aux_info { > > struct cgroup *start; /* starting cgroup */ > > enum bpf_cgroup_iter_order order; > > } cgroup; > > + struct { > > + enum bpf_iter_task_type type; > > + u32 pid; > > + } task; > > }; > > > > typedef int (*bpf_iter_attach_target_t)(struct bpf_prog *prog, > > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > > index 0f61f09f467a..385deab984e1 100644 > > --- a/include/uapi/linux/bpf.h > > +++ b/include/uapi/linux/bpf.h > > @@ -110,6 +110,12 @@ union bpf_iter_link_info { > > __u32 cgroup_fd; > > __u64 cgroup_id; > > } cgroup; > > + /* Parameters of task iterators. */ > > + struct { > > + __u32 tid; > > + __u32 pid; > > + __u32 pid_fd; > > + } task; > > }; > > > > /* BPF syscall commands, see bpf(2) man-page for more details. */ > > diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c > > index 8c921799def4..1200cfde71e3 100644 > > --- a/kernel/bpf/task_iter.c > > +++ b/kernel/bpf/task_iter.c > > @@ -12,6 +12,8 @@ > > > > struct bpf_iter_seq_task_common { > > struct pid_namespace *ns; > > + enum bpf_iter_task_type type; > > + u32 pid; > > }; > > > > struct bpf_iter_seq_task_info { > > @@ -22,24 +24,54 @@ struct bpf_iter_seq_task_info { > > u32 tid; > > }; > > > > -static struct task_struct *task_seq_get_next(struct pid_namespace > > *ns, > > +static bool matched_task(struct task_struct *task, > > + struct bpf_iter_seq_task_common *common, > > + bool skip_if_dup_file) > > +{ > > + /* Should not have the same 'files' if skip_if_dup_file is > > true */ > > + bool diff_files_if = > > + !skip_if_dup_file || > > + (thread_group_leader(task) && > > + task->files != task->group_leader->files); > > Should this be > !skip_if_dup_file || thread_group_leader(task) || > task->files != task->group_leader->files > ? Good catch! This change will be rollbacked by using next_thread(). > > > + /* Should have the given tgid if the type is > > BPF_TASK_ITER_TGI */ > > BPF_TASK_ITER_TGID? > > > + bool have_tgid_if = > > + common->type != BPF_TASK_ITER_TGID || > > + __task_pid_nr_ns(task, PIDTYPE_TGID, > > + common->ns) == common->pid; > > + return diff_files_if && have_tgid_if; > > +} > > + > > + > > +static struct task_struct *task_seq_get_next(struct > > bpf_iter_seq_task_common *common, > > u32 *tid, > > bool > > skip_if_dup_files) > > { > > struct task_struct *task = NULL; > > struct pid *pid; > > > > + if (common->type == BPF_TASK_ITER_TID) { > > + if (*tid && *tid != common->pid) > > + return NULL; > > + rcu_read_lock(); > > + pid = find_pid_ns(common->pid, common->ns); > > + if (pid) { > > + task = get_pid_task(pid, PIDTYPE_PID); > > + *tid = common->pid; > > + } > > + rcu_read_unlock(); > > + return task; > > + } > > + > > rcu_read_lock(); > > retry: > > - pid = find_ge_pid(*tid, ns); > > + pid = find_ge_pid(*tid, common->ns); > > if (pid) { > > - *tid = pid_nr_ns(pid, ns); > > + *tid = pid_nr_ns(pid, common->ns); > > task = get_pid_task(pid, PIDTYPE_PID); > > if (!task) { > > ++*tid; > > goto retry; > > - } else if (skip_if_dup_files && > > !thread_group_leader(task) && > > - task->files == task->group_leader- > > >files) { > > + } else if (!matched_task(task, common, > > skip_if_dup_files)) { > > put_task_struct(task); > > task = NULL; > > ++*tid; > > @@ -56,7 +88,7 @@ static void *task_seq_start(struct seq_file *seq, > > loff_t *pos) > > struct bpf_iter_seq_task_info *info = seq->private; > > struct task_struct *task; > > > > - task = task_seq_get_next(info->common.ns, &info->tid, > > false); > > + task = task_seq_get_next(&info->common, &info->tid, false); > > if (!task) > > return NULL; > > > [...]