From ccc041248568286cdb55afb4ceac7e8d35f76246 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Wed, 22 May 2013 19:25:48 -0400 Subject: [PATCH] dtrace: fixes for tracepoint cleanup Various fixes to handle tracepoint cleanup. It is important to note that it is most common that USDT providers will be cleaned up (asynchronously) when the process/task they relate to is already gone. We therefore cannot use a (pid, addr) pair to identify the tracepoint for removal. The new implementation stores the (inode, offset) pair calculated right before registering the uprobe, so that we can use that same pair again when unregistering. Signed-off-by: Kris Van Hees --- include/linux/dtrace_os.h | 9 ++++-- kernel/dtrace/dtrace_os.c | 62 +++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h index b7a6bb4f8558..7f5430e30af0 100644 --- a/include/linux/dtrace_os.h +++ b/include/linux/dtrace_os.h @@ -7,6 +7,7 @@ typedef uint32_t dtrace_id_t; #ifndef HEADERS_CHECK +#include #include #define DTRACE_IDNONE 0 @@ -79,14 +80,18 @@ extern void unregister_pid_provider(pid_t); extern void dtrace_task_init(struct task_struct *tsk); extern void dtrace_task_cleanup(struct task_struct *tsk); -typedef struct uprobe_consumer fasttrap_machtp_t; +typedef struct fasttrap_machtp { + struct inode *fmtp_ino; + loff_t fmtp_off; + struct uprobe_consumer fmtp_cns; +} fasttrap_machtp_t; extern void (*dtrace_helpers_cleanup)(struct task_struct *); extern void (*dtrace_fasttrap_probes_cleanup)(struct task_struct *); extern void (*dtrace_tracepoint_hit)(fasttrap_machtp_t *, struct pt_regs *); extern int dtrace_tracepoint_enable(pid_t, uintptr_t, fasttrap_machtp_t *); -extern int dtrace_tracepoint_disable(pid_t, uintptr_t, fasttrap_machtp_t *); +extern int dtrace_tracepoint_disable(pid_t, fasttrap_machtp_t *); #endif diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c index a7adcfd5e0a0..823960c37cbb 100644 --- a/kernel/dtrace/dtrace_os.c +++ b/kernel/dtrace/dtrace_os.c @@ -978,12 +978,15 @@ void dtrace_task_cleanup(struct task_struct *tsk) static int handler(struct uprobe_consumer *self, struct pt_regs *regs) { + fasttrap_machtp_t *mtp = container_of(self, fasttrap_machtp_t, + fmtp_cns); + pr_info("USDT-HANDLER: Called for PC %lx\n", GET_IP(regs)); read_lock(&this_cpu_core->cpu_ft_lock); if (dtrace_tracepoint_hit == NULL) pr_warn("Fasttrap probes, but no handler\n"); else - (*dtrace_tracepoint_hit)(self, regs); + (*dtrace_tracepoint_hit)(mtp, regs); read_unlock(&this_cpu_core->cpu_ft_lock); return 0; @@ -998,6 +1001,9 @@ int dtrace_tracepoint_enable(pid_t pid, uintptr_t addr, loff_t off; int rc = 0; + mtp->fmtp_ino = NULL; + mtp->fmtp_off = 0; + p = find_task_by_vpid(pid); if (!p) { pr_warn("PID %d not found\n", pid); @@ -1016,59 +1022,53 @@ pr_info("DEBUG: PID %d: vma 0x%p, mapping 0x%p, inode 0x%p, offset 0x%llx\n", pi if (((uintptr_t)ino & 0xffff880000000000ULL) == 0xffff880000000000ULL) { pr_info("DEBUG: Registering uprobe...\n"); - mtp->handler = handler; - rc = uprobe_register(ino, off, mtp); + mtp->fmtp_cns.handler = handler; + + rc = uprobe_register(ino, off, &mtp->fmtp_cns); /* * If successful, increment the count of the number of * tracepoints active in the victim process. */ - if (rc == 0) + if (rc == 0) { + mtp->fmtp_ino = ino; + mtp->fmtp_off = off; + p->dtrace_tp_count++; + } } return rc; } EXPORT_SYMBOL(dtrace_tracepoint_enable); -int dtrace_tracepoint_disable(pid_t pid, uintptr_t addr, - fasttrap_machtp_t *mtp) +int dtrace_tracepoint_disable(pid_t pid, fasttrap_machtp_t *mtp) { struct task_struct *p; - struct inode *ino; - struct vm_area_struct *vma; - loff_t off; - if (!mtp || !mtp->handler) { - pr_warn("DTRACE: No handler for tracepoint\n"); + if (!mtp || !mtp->fmtp_ino) { + pr_warn("DTRACE: Tracepoint was never enabled\n"); return -ENOENT; } - p = find_task_by_vpid(pid); - if (!p) { - pr_warn("PID %d not found\n", pid); - return -ESRCH; + if (!mtp->fmtp_cns.handler) { + pr_warn("DTRACE: No handler for tracepoint\n"); + return -ENOENT; } - vma = p->mm->mmap; - if (vma->vm_file == NULL) { - pr_warn("DTRACE: vma->vm_file is NULL\n"); - return -ESRCH; - } +pr_info("DEBUG: Unregistering uprobe...\n"); + uprobe_unregister(mtp->fmtp_ino, mtp->fmtp_off, &mtp->fmtp_cns); - ino = vma->vm_file->f_mapping->host; - off = ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (addr - vma->vm_start); -pr_info("DEBUG: PID %d: vma 0x%p, mapping 0x%p, inode 0x%p, offset 0x%llx\n", pid, vma, vma->vm_file->f_mapping, ino, off); + mtp->fmtp_ino = NULL; + mtp->fmtp_off = 0; - if (((uintptr_t)ino & 0xffff880000000000ULL) == 0xffff880000000000ULL) { -pr_info("DEBUG: Registering uprobe...\n"); - uprobe_unregister(ino, off, mtp); - /* - * Decrement the count of the number of tracepoints active in - * the victim process. - */ + /* + * Decrement the count of the number of tracepoints active in + * the victim process (if it still exists). + */ + p = find_task_by_vpid(pid); + if (p) p->dtrace_tp_count--; - } return 0; } -- 2.50.1