diff options
author | Dave Brolley <brolley@redhat.com> | 2009-01-13 16:20:47 -0500 |
---|---|---|
committer | Dave Brolley <brolley@redhat.com> | 2009-01-13 16:20:47 -0500 |
commit | e40ff0adfa7decc9204389af87e1fd2de43f2400 (patch) | |
tree | f75e624a8adce119b6c050812f8928e07b702600 /runtime | |
parent | 21325e0c78f4de1e772813c8f071d909d83e1b58 (diff) | |
parent | e869a84298ccba93b5d244b11657d4183c0eeb64 (diff) | |
download | systemtap-steved-e40ff0adfa7decc9204389af87e1fd2de43f2400.tar.gz systemtap-steved-e40ff0adfa7decc9204389af87e1fd2de43f2400.tar.xz systemtap-steved-e40ff0adfa7decc9204389af87e1fd2de43f2400.zip |
Merge branch 'master' of git://sources.redhat.com/git/systemtap
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/ChangeLog | 8 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.c | 78 |
2 files changed, 75 insertions, 11 deletions
diff --git a/runtime/ChangeLog b/runtime/ChangeLog index bce0ea30..c023fac6 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,11 @@ +2009-01-13 Jim Keniston <jkenisto@us.ibm.com> + + PR 7082. + * uprobes2/uprobes.c: On exec, free up outstanding + uretprobe_instances and tick down the uproc's ref-count + accordingly, so the (old image's) uproc goes away as + desired. + 2009-01-12 Wenji Huang <wenji.huang@oracle.com> * transport/symbols.c (_stp_sort): Adapt it to 2.6.29. diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c index 02496a4e..af187fc9 100644 --- a/runtime/uprobes2/uprobes.c +++ b/runtime/uprobes2/uprobes.c @@ -498,13 +498,24 @@ static bool quiesce_all_threads(struct uprobe_process *uproc, return survivors; } +static void utask_free_uretprobe_instances(struct uprobe_task *utask) +{ + struct uretprobe_instance *ri; + struct hlist_node *r1, *r2; + + hlist_for_each_entry_safe(ri, r1, r2, &utask->uretprobe_instances, + hlist) { + hlist_del(&ri->hlist); + kfree(ri); + uprobe_decref_process(utask->uproc); + } +} + /* Called with utask->uproc write-locked. */ static void uprobe_free_task(struct uprobe_task *utask, bool in_callback) { struct deferred_registration *dr, *d; struct delayed_signal *ds, *ds2; - struct uretprobe_instance *ri; - struct hlist_node *r1, *r2; if (utask->engine && (utask->tsk != current || !in_callback)) { /* @@ -530,12 +541,8 @@ static void uprobe_free_task(struct uprobe_task *utask, bool in_callback) kfree(ds); } - hlist_for_each_entry_safe(ri, r1, r2, &utask->uretprobe_instances, - hlist) { - hlist_del(&ri->hlist); - kfree(ri); - uprobe_decref_process(utask->uproc); - } + utask_free_uretprobe_instances(utask); + kfree(utask); } @@ -873,6 +880,27 @@ static void purge_uprobe(struct uprobe_kimg *uk) uprobe_free_probept(ppt); } +/* TODO: Avoid code duplication with uprobe_validate_vaddr(). */ +static int uprobe_validate_vma(struct task_struct *t, unsigned long vaddr) +{ + struct vm_area_struct *vma; + struct mm_struct *mm; + int ret = 0; + + mm = get_task_mm(t); + if (!mm) + return -EINVAL; + down_read(&mm->mmap_sem); + vma = find_vma(mm, vaddr); + if (!vma || vaddr < vma->vm_start) + ret = -ENOENT; + else if (!(vma->vm_flags & VM_EXEC)) + ret = -EFAULT; + up_read(&mm->mmap_sem); + mmput(mm); + return ret; +} + /* Probed address must be in an executable VM area, outside the SSOL area. */ static int uprobe_validate_vaddr(struct pid *p, unsigned long vaddr, struct uprobe_process *uproc) @@ -2085,9 +2113,9 @@ static u32 uprobe_report_quiesce(enum utrace_resume_action action, /* * uproc's process is exiting or exec-ing, so zap all the (now irrelevant) - * probepoints. Runs with uproc->rwsem write-locked. Caller must ref-count - * uproc before calling this function, to ensure that uproc doesn't get - * freed in the middle of this. + * probepoints and uretprobe_instances. Runs with uproc->rwsem write-locked. + * Caller must ref-count uproc before calling this function, to ensure that + * uproc doesn't get freed in the middle of this. */ static void uprobe_cleanup_process(struct uprobe_process *uproc) { @@ -2096,6 +2124,7 @@ static void uprobe_cleanup_process(struct uprobe_process *uproc) struct hlist_node *pnode1, *pnode2; struct hlist_head *head; struct uprobe_kimg *uk, *unode; + struct uprobe_task *utask; uproc->finished = 1; @@ -2131,6 +2160,16 @@ static void uprobe_cleanup_process(struct uprobe_process *uproc) } } } + + /* + * Free uretprobe_instances. This is a nop on exit, since all + * the uprobe_tasks are already gone. We do this here on exec + * (as opposed to letting uprobe_free_process() take care of it) + * because uprobe_free_process() never gets called if we don't + * tick down the ref count here (PR #7082). + */ + list_for_each_entry(utask, &uproc->thread_list, list) + utask_free_uretprobe_instances(utask); } /* @@ -2280,6 +2319,23 @@ static int uprobe_fork_uproc(struct uprobe_process *parent_uproc, BUG_ON(!parent_uproc->uretprobe_trampoline_addr || IS_ERR(parent_uproc->uretprobe_trampoline_addr)); + ret = uprobe_validate_vma(child_tsk, + (unsigned long) parent_uproc->ssol_area.insn_area); + if (ret) { + int ret2; + printk(KERN_ERR "uprobes: Child %d failed to inherit" + " parent %d's SSOL vma at %p. Error = %d\n", + child_tsk->pid, parent_utask->tsk->pid, + parent_uproc->ssol_area.insn_area, ret); + ret2 = uprobe_validate_vma(parent_utask->tsk, + (unsigned long) parent_uproc->ssol_area.insn_area); + if (ret2 != 0) + printk(KERN_ERR "uprobes: Parent %d's SSOL vma" + " is no longer valid. Error = %d\n", + parent_utask->tsk->pid, ret2); + return ret; + } + if (!try_module_get(THIS_MODULE)) return -ENOSYS; child_pid = get_pid(find_vpid(child_tsk->pid)); |