On Wed, 24 Mar 2021 at 15:01, Peter Zijlstra peterz@infradead.org wrote:
One last try, I'll leave it alone now, I promise :-)
This looks like it does what you suggested, thanks! :-)
I'll still need to think about it, because of the potential problem with modify-signal-races and what the user's synchronization story would look like then.
--- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -778,6 +778,9 @@ struct perf_event { void *security; #endif struct list_head sb_list;
unsigned long si_uattr;
unsigned long si_data;
#endif /* CONFIG_PERF_EVENTS */ };
--- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5652,13 +5652,17 @@ static long _perf_ioctl(struct perf_even return perf_event_query_prog_array(event, (void __user *)arg);
case PERF_EVENT_IOC_MODIFY_ATTRIBUTES: {
struct perf_event_attr __user *uattr; struct perf_event_attr new_attr;
int err = perf_copy_attr((struct perf_event_attr __user *)arg,
&new_attr);
int err;
uattr = (struct perf_event_attr __user *)arg;
err = perf_copy_attr(uattr, &new_attr); if (err) return err;
event->si_uattr = (unsigned long)uattr;
return perf_event_modify_attr(event, &new_attr); } default:
@@ -6399,7 +6403,12 @@ static void perf_sigtrap(struct perf_eve clear_siginfo(&info); info.si_signo = SIGTRAP; info.si_code = TRAP_PERF;
info.si_errno = event->attr.type;
info.si_addr = (void *)event->si_data;
info.si_perf = event->si_uattr;
if (event->parent)
info.si_perf = event->parent->si_uattr;
force_sig_info(&info);
}
@@ -6414,8 +6423,8 @@ static void perf_pending_event_disable(s WRITE_ONCE(event->pending_disable, -1);
if (event->attr.sigtrap) {
atomic_set(&event->event_limit, 1); /* rearm event */ perf_sigtrap(event);
atomic_set_release(&event->event_limit, 1); /* rearm event */ return; }
@@ -9121,6 +9130,7 @@ static int __perf_event_overflow(struct if (events && atomic_dec_and_test(&event->event_limit)) { ret = 1; event->pending_kill = POLL_HUP;
event->si_data = data->addr; perf_event_disable_inatomic(event); }
@@ -12011,6 +12021,8 @@ SYSCALL_DEFINE5(perf_event_open, goto err_task; }
event->si_uattr = (unsigned long)attr_uptr;
if (is_sampling_event(event)) { if (event->pmu->capabilities & PERF_PMU_CAP_NO_INTERRUPT) { err = -EOPNOTSUPP;