]> sourceware.org Git - systemtap.git/commitdiff
PR 7082: patch for uprobes2 (kernel > 2.6.26)
authorJim Keniston <jkenisto@us.ibm.com>
Tue, 13 Jan 2009 21:14:43 +0000 (13:14 -0800)
committerJim Keniston <jkenisto@us.ibm.com>
Tue, 13 Jan 2009 21:14:43 +0000 (13:14 -0800)
runtime/ChangeLog
runtime/uprobes2/uprobes.c

index bce0ea300853622336bc6e5ca000aef1b5e104b4..c023fac69939ad8a42adbd3e3e7f420ff4d16be1 100644 (file)
@@ -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. 
index 02496a4e21c02ebe20d25ff953de3fd05e63658a..af187fc998994e3952ebf3fdd1cc6c5d7d80e786 100644 (file)
@@ -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));
This page took 0.037531 seconds and 5 git commands to generate.