Skip to content

Commit 2b26f0a

Browse files
melverPeter Zijlstra
authored andcommitted
perf: Support only inheriting events if cloned with CLONE_THREAD
Adds bit perf_event_attr::inherit_thread, to restricting inheriting events only if the child was cloned with CLONE_THREAD. This option supports the case where an event is supposed to be process-wide only (including subthreads), but should not propagate beyond the current process's shared environment. Suggested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Marco Elver <elver@google.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/lkml/YBvj6eJR%2FDY2TsEB@hirez.programming.kicks-ass.net/
1 parent 47f661e commit 2b26f0a

File tree

4 files changed

+20
-11
lines changed

4 files changed

+20
-11
lines changed

include/linux/perf_event.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ extern void __perf_event_task_sched_in(struct task_struct *prev,
958958
struct task_struct *task);
959959
extern void __perf_event_task_sched_out(struct task_struct *prev,
960960
struct task_struct *next);
961-
extern int perf_event_init_task(struct task_struct *child);
961+
extern int perf_event_init_task(struct task_struct *child, u64 clone_flags);
962962
extern void perf_event_exit_task(struct task_struct *child);
963963
extern void perf_event_free_task(struct task_struct *task);
964964
extern void perf_event_delayed_put(struct task_struct *task);
@@ -1449,7 +1449,8 @@ perf_event_task_sched_in(struct task_struct *prev,
14491449
static inline void
14501450
perf_event_task_sched_out(struct task_struct *prev,
14511451
struct task_struct *next) { }
1452-
static inline int perf_event_init_task(struct task_struct *child) { return 0; }
1452+
static inline int perf_event_init_task(struct task_struct *child,
1453+
u64 clone_flags) { return 0; }
14531454
static inline void perf_event_exit_task(struct task_struct *child) { }
14541455
static inline void perf_event_free_task(struct task_struct *task) { }
14551456
static inline void perf_event_delayed_put(struct task_struct *task) { }

include/uapi/linux/perf_event.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ struct perf_event_attr {
389389
cgroup : 1, /* include cgroup events */
390390
text_poke : 1, /* include text poke events */
391391
build_id : 1, /* use build id in mmap2 events */
392-
__reserved_1 : 29;
392+
inherit_thread : 1, /* children only inherit if cloned with CLONE_THREAD */
393+
__reserved_1 : 28;
393394

394395
union {
395396
__u32 wakeup_events; /* wakeup every n events */

kernel/events/core.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11653,6 +11653,9 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
1165311653
(attr->sample_type & PERF_SAMPLE_WEIGHT_STRUCT))
1165411654
return -EINVAL;
1165511655

11656+
if (!attr->inherit && attr->inherit_thread)
11657+
return -EINVAL;
11658+
1165611659
out:
1165711660
return ret;
1165811661

@@ -12873,12 +12876,13 @@ static int
1287312876
inherit_task_group(struct perf_event *event, struct task_struct *parent,
1287412877
struct perf_event_context *parent_ctx,
1287512878
struct task_struct *child, int ctxn,
12876-
int *inherited_all)
12879+
u64 clone_flags, int *inherited_all)
1287712880
{
1287812881
int ret;
1287912882
struct perf_event_context *child_ctx;
1288012883

12881-
if (!event->attr.inherit) {
12884+
if (!event->attr.inherit ||
12885+
(event->attr.inherit_thread && !(clone_flags & CLONE_THREAD))) {
1288212886
*inherited_all = 0;
1288312887
return 0;
1288412888
}
@@ -12910,7 +12914,8 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent,
1291012914
/*
1291112915
* Initialize the perf_event context in task_struct
1291212916
*/
12913-
static int perf_event_init_context(struct task_struct *child, int ctxn)
12917+
static int perf_event_init_context(struct task_struct *child, int ctxn,
12918+
u64 clone_flags)
1291412919
{
1291512920
struct perf_event_context *child_ctx, *parent_ctx;
1291612921
struct perf_event_context *cloned_ctx;
@@ -12950,7 +12955,8 @@ static int perf_event_init_context(struct task_struct *child, int ctxn)
1295012955
*/
1295112956
perf_event_groups_for_each(event, &parent_ctx->pinned_groups) {
1295212957
ret = inherit_task_group(event, parent, parent_ctx,
12953-
child, ctxn, &inherited_all);
12958+
child, ctxn, clone_flags,
12959+
&inherited_all);
1295412960
if (ret)
1295512961
goto out_unlock;
1295612962
}
@@ -12966,7 +12972,8 @@ static int perf_event_init_context(struct task_struct *child, int ctxn)
1296612972

1296712973
perf_event_groups_for_each(event, &parent_ctx->flexible_groups) {
1296812974
ret = inherit_task_group(event, parent, parent_ctx,
12969-
child, ctxn, &inherited_all);
12975+
child, ctxn, clone_flags,
12976+
&inherited_all);
1297012977
if (ret)
1297112978
goto out_unlock;
1297212979
}
@@ -13008,7 +13015,7 @@ static int perf_event_init_context(struct task_struct *child, int ctxn)
1300813015
/*
1300913016
* Initialize the perf_event context in task_struct
1301013017
*/
13011-
int perf_event_init_task(struct task_struct *child)
13018+
int perf_event_init_task(struct task_struct *child, u64 clone_flags)
1301213019
{
1301313020
int ctxn, ret;
1301413021

@@ -13017,7 +13024,7 @@ int perf_event_init_task(struct task_struct *child)
1301713024
INIT_LIST_HEAD(&child->perf_event_list);
1301813025

1301913026
for_each_task_context_nr(ctxn) {
13020-
ret = perf_event_init_context(child, ctxn);
13027+
ret = perf_event_init_context(child, ctxn, clone_flags);
1302113028
if (ret) {
1302213029
perf_event_free_task(child);
1302313030
return ret;

kernel/fork.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2078,7 +2078,7 @@ static __latent_entropy struct task_struct *copy_process(
20782078
if (retval)
20792079
goto bad_fork_cleanup_policy;
20802080

2081-
retval = perf_event_init_task(p);
2081+
retval = perf_event_init_task(p, clone_flags);
20822082
if (retval)
20832083
goto bad_fork_cleanup_policy;
20842084
retval = audit_alloc(p);

0 commit comments

Comments
 (0)