uprobes/tracing: uprobe_perf_open() forgets to handle the error from uprobe_apply()
cover uprobes/tracing: uprobe_perf_open() forgets to handle the error from uprobe_apply()
Hello,
Steven, I am going to ask Ingo to pull this fix along with other pending uprobes changes, but please let me know if you want to take this patch.
Oleg.
kernel/trace/trace_uprobe.c | 46 +++++++++++++++++++++++------------------- 1 files changed, 25 insertions(+), 21 deletions(-)
PATCH 1/1 uprobes/tracing: uprobe_perf_open() forgets to handle the error from uprobe_apply()
uprobe_perf_open()->uprobe_apply() can fail, but this error is wrongly ignored. Change uprobe_perf_open() to do uprobe_perf_close() and return the error code in this case.
Change uprobe_perf_close() to propogate the error from uprobe_apply() as well, although it should not fail.
The patch looks more complicated because it moves uprobe_perf_close() up to make it visible to uprobe_perf_open().
--- kernel/trace/trace_uprobe.c | 46 +++++++++++++++++++++++------------------- 1 files changed, 25 insertions(+), 21 deletions(-)
kernel/trace/trace_uprobe.c +25 -21
@@ -1003,56 +1003,60 @@ uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event)return __uprobe_perf_filter (&tu->filter, event->hw.tp_target->mm); } -static int uprobe_perf_open (struct trace_uprobe *tu,struct perf_event *event) +static int uprobe_perf_close (struct trace_uprobe *tu,struct perf_event *event) {bool done;write_lock (&tu->filter.rwlock);if (event->hw.tp_target) { -/* -* event->parent != NULL means copy_process(), we can avoid -* uprobe_apply(). current->mm must be probed and we can rely -* on dup_mmap() which preserves the already installed bp's. -* -* attr.enable_on_exec means that exec/mmap will install the -* breakpoints we need. -*/ +list_del (&event->hw.tp_list); done = tu->filter.nr_systemwide || - event->parent || event->attr.enable_on_exec || + (event->hw.tp_target->flags &PF_EXITING ) ||uprobe_filter_event (tu, event); -list_add (&event->hw.tp_list, &tu->filter.perf_events); }else { + tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; - tu->filter.nr_systemwide++; }write_unlock (&tu->filter.rwlock);if (!done) -uprobe_apply (tu->inode, tu->offset, &tu->consumer, true); +return uprobe_apply (tu->inode, tu->offset, &tu->consumer, false);return 0 ; } -static int uprobe_perf_close (struct trace_uprobe *tu,struct perf_event *event) +static int uprobe_perf_open (struct trace_uprobe *tu,struct perf_event *event) {bool done; +int err;write_lock (&tu->filter.rwlock);if (event->hw.tp_target) { -list_del (&event->hw.tp_list); +/* +* event->parent != NULL means copy_process(), we can avoid +* uprobe_apply(). current->mm must be probed and we can rely +* on dup_mmap() which preserves the already installed bp's. +* +* attr.enable_on_exec means that exec/mmap will install the +* breakpoints we need. +*/ done = tu->filter.nr_systemwide || - (event->hw.tp_target->flags &PF_EXITING ) || + event->parent || event->attr.enable_on_exec ||uprobe_filter_event (tu, event); +list_add (&event->hw.tp_list, &tu->filter.perf_events); }else { - tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; + tu->filter.nr_systemwide++; }write_unlock (&tu->filter.rwlock); -if (!done) -uprobe_apply (tu->inode, tu->offset, &tu->consumer, false); - -return 0 ; + err =0 ; +if (!done) { + err =uprobe_apply (tu->inode, tu->offset, &tu->consumer, true); +if (err) +uprobe_perf_close (tu, event); + } +return err; } static bool uprobe_perf_filter(struct uprobe_consumer *uc,
Signature · 1 line
1.5.5.1
Steven Rostedt
maintainerQuoted 20 lines · On Wed, 23 Apr 2014 18:58:30 +0200 Oleg Nesterov <[email protected]> wrote:
uprobe_perf_open()->uprobe_apply() can fail, but this error is wrongly ignored. Change
uprobe_perf_open()to douprobe_perf_close()and return the error code in this case.Change
uprobe_perf_close()to propogate the error fromuprobe_apply()as well, although it should not fail.The patch looks more complicated because it moves
uprobe_perf_close()up to make it visible touprobe_perf_open().Signed-off-by Oleg Nesterov <[email protected]>--- kernel/trace/trace_uprobe.c | 46 +++++++++++++++++++++++------------------- 1 files changed, 25 insertions(+), 21 deletions(-)kernel/trace/trace_uprobe.c +0
-0
kernel/trace/trace_uprobe.c uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) · line 1006
Quoted 5 lines
kernel/trace/trace_uprobe.c +1
-1@@ -1003,56 +1003,60 @@ uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event)return __uprobe_perf_filter (&tu->filter, event->hw.tp_target->mm); } -static int uprobe_perf_open (struct trace_uprobe *tu,struct perf_event *event) +static int uprobe_perf_close (struct trace_uprobe *tu,struct perf_event *event)
Egad, this confused the heck out of me. I didn't notice the swap in functions and was wondering what you were doing. I didn't realize this is what you meant by moving the uprobe_perf_close() up. I was thinking you moved the call up or something, not the function itself physically in the file.
/me tries to continue dazed and confused.
Quoted 63 lines
kernel/trace/trace_uprobe.c +17
-17{bool done;write_lock (&tu->filter.rwlock);if (event->hw.tp_target) { -/* -* event->parent != NULL means copy_process(), we can avoid -* uprobe_apply(). current->mm must be probed and we can rely -* on dup_mmap() which preserves the already installed bp's. -* -* attr.enable_on_exec means that exec/mmap will install the -* breakpoints we need. -*/ +list_del (&event->hw.tp_list); done = tu->filter.nr_systemwide || - event->parent || event->attr.enable_on_exec || + (event->hw.tp_target->flags &PF_EXITING ) ||uprobe_filter_event (tu, event); -list_add (&event->hw.tp_list, &tu->filter.perf_events); }else { + tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; - tu->filter.nr_systemwide++; }write_unlock (&tu->filter.rwlock);if (!done) -uprobe_apply (tu->inode, tu->offset, &tu->consumer, true); +return uprobe_apply (tu->inode, tu->offset, &tu->consumer, false);return 0 ; } -static int uprobe_perf_close (struct trace_uprobe *tu,struct perf_event *event) +static int uprobe_perf_open (struct trace_uprobe *tu,struct perf_event *event) {bool done; +int err;write_lock (&tu->filter.rwlock);if (event->hw.tp_target) { -list_del (&event->hw.tp_list); +/* +* event->parent != NULL means copy_process(), we can avoid +* uprobe_apply(). current->mm must be probed and we can rely +* on dup_mmap() which preserves the already installed bp's. +* +* attr.enable_on_exec means that exec/mmap will install the +* breakpoints we need. +*/ done = tu->filter.nr_systemwide || - (event->hw.tp_target->flags &PF_EXITING ) || + event->parent || event->attr.enable_on_exec ||uprobe_filter_event (tu, event); +list_add (&event->hw.tp_list, &tu->filter.perf_events); }else { - tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; + tu->filter.nr_systemwide++; }write_unlock (&tu->filter.rwlock); -if (!done)
kernel/trace/trace_uprobe.c uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) · line 1059
Quoted 10 lines
kernel/trace/trace_uprobe.c +7
-3-uprobe_apply (tu->inode, tu->offset, &tu->consumer, false); - -return 0 ; + err =0 ; +if (!done) { + err =uprobe_apply (tu->inode, tu->offset, &tu->consumer, true); +if (err) +uprobe_perf_close (tu, event); + } +return err;
You can add by Acked-by, but next time, please make this into two patches. One to do the move, the other to do the change.
Thanks!
-- Steve
Quoted 3 lines
kernel/trace/trace_uprobe.c +0
-0} static bool uprobe_perf_filter(struct uprobe_consumer *uc,
v2 cover uprobes/tracing: uprobe_perf_open()->uprobe_apply() fix
Quoted 6 lines · Steven Rostedt
Egad, this confused the heck out of me. I didn't notice the swap in functions and was wondering what you were doing. I didn't realize this is what you meant by moving the
uprobe_perf_close()up. I was thinking you moved the call up or something, not the function itself physically in the file.
...
Quoted 3 lines
You can add by Acked-by, but next time, please make this into two patches. One to do the move, the other to do the change.
OK...
I tried to lessen the number of patches I have ;) But I agree, this simple fix looks too complicated without preparation which only moves the code.
Let me split it then. Result is the same do I preserved the acks, this is what I am going to add to my tree.
Thanks!
Oleg.
PATCH v2 1/2 uprobes/tracing: Make uprobe_perf_close() visible to uprobe_perf_open()
Preparation. Move uprobe_perf_close() up before uprobe_perf_open() to avoid the forward declaration in the next patch and make it readable.
--- kernel/trace/trace_uprobe.c | 36 ++++++++++++++++++------------------ 1 files changed, 18 insertions(+), 18 deletions(-)
kernel/trace/trace_uprobe.c +18 -18
@@ -1003,54 +1003,54 @@ uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event)return __uprobe_perf_filter (&tu->filter, event->hw.tp_target->mm); } -static int uprobe_perf_open (struct trace_uprobe *tu,struct perf_event *event) +static int uprobe_perf_close (struct trace_uprobe *tu,struct perf_event *event) {bool done;write_lock (&tu->filter.rwlock);if (event->hw.tp_target) { -/* -* event->parent != NULL means copy_process(), we can avoid -* uprobe_apply(). current->mm must be probed and we can rely -* on dup_mmap() which preserves the already installed bp's. -* -* attr.enable_on_exec means that exec/mmap will install the -* breakpoints we need. -*/ +list_del (&event->hw.tp_list); done = tu->filter.nr_systemwide || - event->parent || event->attr.enable_on_exec || + (event->hw.tp_target->flags &PF_EXITING ) ||uprobe_filter_event (tu, event); -list_add (&event->hw.tp_list, &tu->filter.perf_events); }else { + tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; - tu->filter.nr_systemwide++; }write_unlock (&tu->filter.rwlock);if (!done) -uprobe_apply (tu->inode, tu->offset, &tu->consumer, true); +uprobe_apply (tu->inode, tu->offset, &tu->consumer, false);return 0 ; } -static int uprobe_perf_close (struct trace_uprobe *tu,struct perf_event *event) +static int uprobe_perf_open (struct trace_uprobe *tu,struct perf_event *event) {bool done;write_lock (&tu->filter.rwlock);if (event->hw.tp_target) { -list_del (&event->hw.tp_list); +/* +* event->parent != NULL means copy_process(), we can avoid +* uprobe_apply(). current->mm must be probed and we can rely +* on dup_mmap() which preserves the already installed bp's. +* +* attr.enable_on_exec means that exec/mmap will install the +* breakpoints we need. +*/ done = tu->filter.nr_systemwide || - (event->hw.tp_target->flags &PF_EXITING ) || + event->parent || event->attr.enable_on_exec ||uprobe_filter_event (tu, event); +list_add (&event->hw.tp_list, &tu->filter.perf_events); }else { - tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; + tu->filter.nr_systemwide++; }write_unlock (&tu->filter.rwlock);if (!done) -uprobe_apply (tu->inode, tu->offset, &tu->consumer, false); +uprobe_apply (tu->inode, tu->offset, &tu->consumer, true);return 0 ; }
Signature · 1 line
1.5.5.1
PATCH v2 2/2 uprobes/tracing: Fix uprobe_perf_open() on uprobe_apply() failure
In reply to Oleg Nesterovuprobe_perf_open()->uprobe_apply() can fail, but this error is wrongly ignored. Change uprobe_perf_open() to do uprobe_perf_close() and return the error code in this case.
Change uprobe_perf_close() to propogate the error from uprobe_apply() as well, although it should not fail.
--- kernel/trace/trace_uprobe.c | 14 +++++++++----- 1 files changed, 9 insertions(+), 5 deletions(-)
kernel/trace/trace_uprobe.c +9 -5
@@ -1020,7 +1020,7 @@ static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event)write_unlock (&tu->filter.rwlock);if (!done) -uprobe_apply (tu->inode, tu->offset, &tu->consumer, false); +return uprobe_apply (tu->inode, tu->offset, &tu->consumer, false);return 0 ; }
@@ -1028,6 +1028,7 @@ static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event)static int uprobe_perf_open (struct trace_uprobe *tu,struct perf_event *event) {bool done; +int err;write_lock (&tu->filter.rwlock);if (event->hw.tp_target) {
@@ -1049,10 +1050,13 @@ static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event) }write_unlock (&tu->filter.rwlock); -if (!done) -uprobe_apply (tu->inode, tu->offset, &tu->consumer, true); - -return 0 ; + err =0 ; +if (!done) { + err =uprobe_apply (tu->inode, tu->offset, &tu->consumer, true); +if (err) +uprobe_perf_close (tu, event); + } +return err; } static bool uprobe_perf_filter(struct uprobe_consumer *uc,
Signature · 1 line
1.5.5.1
Steven Rostedt
maintainerRe: [PATCH v2 0/2] uprobes/tracing: uprobe_perf_open()->uprobe_apply() fix
In reply to Oleg NesterovQuoted 9 lines · On Thu, 24 Apr 2014 13:54:58 +0200 Oleg Nesterov <[email protected]> wrote:
Quoted 6 lines · Steven Rostedt
Egad, this confused the heck out of me. I didn't notice the swap in functions and was wondering what you were doing. I didn't realize this is what you meant by moving the
uprobe_perf_close()up. I was thinking you moved the call up or something, not the function itself physically in the file....
Quoted 1 line
Quoted 7 lines
Quoted 2 lines
You can add by Acked-by, but next time, please make this into two patches. One to do the move, the other to do the change.
OK...
I tried to lessen the number of patches I have ;) But I agree, this simple fix looks too complicated without preparation which only moves the code.
Yeah, sometimes a simple fix just seems wrong to break into two. But if it helps in code review, it's definitely worth it.
Quoted 3 lines
Let me split it then. Result is the same do I preserved the acks, this is what I am going to add to my tree.
They look good (and much easier to review).
-- Steve
(with 2 nits that you can ignore)
kernel/trace/trace_uprobe.c uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) · line 1019
Quoted 10 lines
kernel/trace/trace_uprobe.c +2
-3done = tu->filter.nr_systemwide || - event->parent || event->attr.enable_on_exec || + (event->hw.tp_target->flags &PF_EXITING ) ||uprobe_filter_event (tu, event); -list_add (&event->hw.tp_list, &tu->filter.perf_events); }else { + tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; - tu->filter.nr_systemwide++; }
Nit: I think 2 lines can be made into
done = --tu->filter.nr_systemwide;
<snipped>
kernel/trace/trace_uprobe.c uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) · line 1050
Quoted 10 lines
kernel/trace/trace_uprobe.c +3
-2done = tu->filter.nr_systemwide || - (event->hw.tp_target->flags &PF_EXITING ) || + event->parent || event->attr.enable_on_exec ||uprobe_filter_event (tu, event); +list_add (&event->hw.tp_list, &tu->filter.perf_events); }else { - tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; + tu->filter.nr_systemwide++; }
Nit: Similarly lines can be made into
done = tu->filter.nr_systemwide++;
Signature · 2 lines
Thanks and Regards Srikar Dronamraju
Quoted 2 lines · Srikar Dronamraju
Thanks, included!
Quoted 7 lines
kernel/trace/trace_uprobe.c uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) · line 1019
Quoted 4 lines
kernel/trace/trace_uprobe.c +1
-1+ tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; - tu->filter.nr_systemwide++; }Nit: I think 2 lines can be made into
done = --tu->filter.nr_systemwide;
...
Quoted 7 lines
kernel/trace/trace_uprobe.c uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) · line 1050
Quoted 4 lines
kernel/trace/trace_uprobe.c +1
-1- tu->filter.nr_systemwide--; done = tu->filter.nr_systemwide; + tu->filter.nr_systemwide++; }Nit: Similarly lines can be made into
done = tu->filter.nr_systemwide++;
Yes, perhaps, but this has nothing to do with this patch, it does not change this code.
And can't resist... you know, initially I wrote this code this way, but then I decided to make it more straightforward to avoid the potential nits from reviewers ;)
Oleg.