systemtap/systemtap-fix-for-kernels-without-vm_executable.patch
2013-01-12 05:43:52 +00:00

213 lines
7.3 KiB
Diff

From: Josh Stone <jistone@redhat.com>
Date: Fri Oct 12 14:45:55 2012 -0700
Subject: PR14172: Fix for kernels without VM_EXECUTABLE
Git-commit: 529c7eaed7360776b596af31c86d4e4712a1a3db
We were using VM_EXECUTABLE in two ways:
1) In task_finder for locating the process executable among all the
vmas. Since around 2.6.26 there is also mm->exe_file, which will serve
this purpose just fine.
2) In uprobes to avoid relocation offset for semaphores in ET_EXEC
files. This is actually incorrect, but harmless, because the callback
path for ET_EXEC targets already sets relocation=offset=0 anyway. So we
can just remove the special case for VM_EXECUTABLE altogether.
* runtime/task_finder_vma.c (stap_find_exe_file): New, locate the
process executable either by VM_EXECUTABLE or mm->exe_file.
* runtime/linux/task_finder.c (__stp_get_mm_path): Use stap_find_exe_file.
* runtime/linux/task_finder2.c (__stp_get_mm_path): Ditto.
* runtime/linux/uprobes-common.c (stap_uprobe_change_plus): Don't
special case for VM_EXECUTABLE (and add a comment why).
* runtime/linux/uprobes-inode.c (stapiu_change_plus): Ditto.
(stapiu_get_task_inode): Use stap_find_exe_file.
diff --git a/runtime/linux/runtime.h b/runtime/linux/runtime.h
index e167be6..783f199 100644
--- a/runtime/linux/runtime.h
+++ b/runtime/linux/runtime.h
@@ -163,13 +163,13 @@ void *kallsyms_task_work_cancel;
#include "copy.c"
#include "regs.c"
#include "regs-ia64.c"
+#include "sym.c"
#if (defined(CONFIG_UTRACE) || defined(STAPCONF_UTRACE_VIA_TRACEPOINTS))
#define HAVE_TASK_FINDER
#include "task_finder.c"
#endif
-#include "sym.c"
#ifdef STP_PERFMON
#include "perf.c"
#endif
diff --git a/runtime/linux/task_finder.c b/runtime/linux/task_finder.c
index 2b1e22f..d718e80 100644
--- a/runtime/linux/task_finder.c
+++ b/runtime/linux/task_finder.c
@@ -440,7 +440,7 @@ __stp_task_finder_cleanup(void)
static char *
__stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
{
- struct vm_area_struct *vma;
+ struct file *vm_file;
char *rc = NULL;
// The down_read() function can sleep, so we'll call
@@ -451,17 +451,12 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
return ERR_PTR(-ENOENT);
}
- vma = mm->mmap;
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
- break;
- vma = vma->vm_next;
- }
- if (vma) {
+ vm_file = stap_find_exe_file(mm);
+ if (vm_file) {
#ifdef STAPCONF_DPATH_PATH
- rc = d_path(&(vma->vm_file->f_path), buf, buflen);
+ rc = d_path(&(vm_file->f_path), buf, buflen);
#else
- rc = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt,
+ rc = d_path(vm_file->f_dentry, vm_file->f_vfsmnt,
buf, buflen);
#endif
}
diff --git a/runtime/linux/task_finder2.c b/runtime/linux/task_finder2.c
index 680b428..5cee195 100644
--- a/runtime/linux/task_finder2.c
+++ b/runtime/linux/task_finder2.c
@@ -425,7 +425,7 @@ __stp_task_finder_cleanup(void)
static char *
__stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
{
- struct vm_area_struct *vma;
+ struct file *vm_file;
char *rc = NULL;
// The down_read() function can sleep, so we'll call
@@ -436,17 +436,12 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
return ERR_PTR(-ENOENT);
}
- vma = mm->mmap;
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
- break;
- vma = vma->vm_next;
- }
- if (vma) {
+ vm_file = stap_find_exe_file(mm);
+ if (vm_file) {
#ifdef STAPCONF_DPATH_PATH
- rc = d_path(&(vma->vm_file->f_path), buf, buflen);
+ rc = d_path(&(vm_file->f_path), buf, buflen);
#else
- rc = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt,
+ rc = d_path(vm_file->f_dentry, vm_file->f_vfsmnt,
buf, buflen);
#endif
}
diff --git a/runtime/linux/uprobes-common.c b/runtime/linux/uprobes-common.c
index 64b62cc..cdfb5a6 100644
--- a/runtime/linux/uprobes-common.c
+++ b/runtime/linux/uprobes-common.c
@@ -77,13 +77,10 @@ static int stap_uprobe_change_plus (struct task_struct *tsk, unsigned long reloc
sdt_sem_pid = (sups->return_p ? sup->urp.u.pid : sup->up.pid);
if (sups->sdt_sem_offset && (sdt_sem_pid != tsk->tgid || sup->sdt_sem_address == 0)) {
- /* If the probe is in the executable itself, the offset *is* the address. */
- if (vm_flags & VM_EXECUTABLE) {
- sup->sdt_sem_address = relocation + sups->sdt_sem_offset;
- }
- else {
- sup->sdt_sem_address = (relocation - offset) + sups->sdt_sem_offset;
- }
+ /* If the probe is in an ET_EXEC binary, then the sdt_sem_offset already
+ * is a real address. But stap_uprobe_process_found calls us in this
+ * case with relocation=offset=0, so we don't have to worry about it. */
+ sup->sdt_sem_address = (relocation - offset) + sups->sdt_sem_offset;
} /* sdt_sem_offset */
if (slotted_p) {
struct stap_uprobe *sup = & stap_uprobes[i];
diff --git a/runtime/linux/uprobes-inode.c b/runtime/linux/uprobes-inode.c
index 578123c..9d4d867 100644
--- a/runtime/linux/uprobes-inode.c
+++ b/runtime/linux/uprobes-inode.c
@@ -406,9 +406,14 @@ stapiu_change_plus(struct stapiu_target* target, struct task_struct *task,
if (!p->tgid) {
p->tgid = task->tgid;
p->relocation = relocation;
- p->base = relocation;
- if (!(vm_flags & VM_EXECUTABLE))
- p->base -= offset;
+
+ /* The base is used for relocating semaphores. If the
+ * probe is in an ET_EXEC binary, then that offset
+ * already is a real address. But stapiu_process_found
+ * calls us in this case with relocation=offset=0, so
+ * we don't have to worry about it. */
+ p->base = relocation - offset;
+
list_add(&p->target_process, &target->processes);
break;
}
@@ -491,7 +496,7 @@ static struct inode *
stapiu_get_task_inode(struct task_struct *task)
{
struct mm_struct *mm;
- struct vm_area_struct *vma;
+ struct file* vm_file;
struct inode *inode = NULL;
// Grab the inode associated with the task.
@@ -507,15 +512,9 @@ stapiu_get_task_inode(struct task_struct *task)
}
down_read(&mm->mmap_sem);
- vma = mm->mmap;
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file
- && vma->vm_file->f_path.dentry != NULL) {
- inode = vma->vm_file->f_path.dentry->d_inode;
- break;
- }
- vma = vma->vm_next;
- }
+ vm_file = stap_find_exe_file(mm);
+ if (vm_file && vm_file->f_path.dentry)
+ inode = vm_file->f_path.dentry->d_inode;
up_read(&mm->mmap_sem);
return inode;
diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c
index 7c872ba..1c1bfbc 100644
--- a/runtime/task_finder_vma.c
+++ b/runtime/task_finder_vma.c
@@ -371,3 +371,21 @@ stap_drop_vma_maps(struct task_struct *tsk)
write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return 0;
}
+
+/* Find the main executable for this mm.
+ * NB: mmap_sem should be held already. */
+static struct file*
+stap_find_exe_file(struct mm_struct* mm)
+{
+ /* VM_EXECUTABLE was killed in kernel commit e9714acf, but in kernels
+ * that new we can just use mm->exe_file anyway. (PR14172) */
+#ifdef VM_EXECUTABLE
+ struct vm_area_struct *vma;
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
+ return vma->vm_file;
+ return NULL;
+#else
+ return mm->exe_file;
+#endif
+}