uprobes: Introduce MMF_RECALC_UPROBES
Add the new MMF_RECALC_UPROBES flag, it means that MMF_HAS_UPROBES can be false positive after remove_breakpoint() or uprobe_munmap(). It is also set by uprobe_dup_mmap(), this is not optimal but simple. We could add the new hook, uprobe_dup_vma(), to set MMF_HAS_UPROBES only if the new mm actually has uprobes, but I don't think this makes sense. The next patch will use this flag to clear MMF_HAS_UPROBES. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
This commit is contained in:
parent
6f47caa0e1
commit
9f68f672c4
|
@ -446,7 +446,8 @@ extern int get_dumpable(struct mm_struct *mm);
|
|||
#define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */
|
||||
#define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */
|
||||
|
||||
#define MMF_HAS_UPROBES 19 /* might have uprobes */
|
||||
#define MMF_HAS_UPROBES 19 /* has uprobes */
|
||||
#define MMF_RECALC_UPROBES 20 /* MMF_HAS_UPROBES can be wrong */
|
||||
|
||||
#define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK)
|
||||
|
||||
|
|
|
@ -684,7 +684,9 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
|
|||
set_bit(MMF_HAS_UPROBES, &mm->flags);
|
||||
|
||||
ret = set_swbp(&uprobe->arch, mm, vaddr);
|
||||
if (ret && first_uprobe)
|
||||
if (!ret)
|
||||
clear_bit(MMF_RECALC_UPROBES, &mm->flags);
|
||||
else if (first_uprobe)
|
||||
clear_bit(MMF_HAS_UPROBES, &mm->flags);
|
||||
|
||||
return ret;
|
||||
|
@ -693,6 +695,11 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
|
|||
static void
|
||||
remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr)
|
||||
{
|
||||
/* can happen if uprobe_register() fails */
|
||||
if (!test_bit(MMF_HAS_UPROBES, &mm->flags))
|
||||
return;
|
||||
|
||||
set_bit(MMF_RECALC_UPROBES, &mm->flags);
|
||||
set_orig_insn(&uprobe->arch, mm, vaddr);
|
||||
}
|
||||
|
||||
|
@ -1026,6 +1033,25 @@ int uprobe_mmap(struct vm_area_struct *vma)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
vma_has_uprobes(struct vm_area_struct *vma, unsigned long start, unsigned long end)
|
||||
{
|
||||
loff_t min, max;
|
||||
struct inode *inode;
|
||||
struct rb_node *n;
|
||||
|
||||
inode = vma->vm_file->f_mapping->host;
|
||||
|
||||
min = vaddr_to_offset(vma, start);
|
||||
max = min + (end - start) - 1;
|
||||
|
||||
spin_lock(&uprobes_treelock);
|
||||
n = find_node_in_range(inode, min, max);
|
||||
spin_unlock(&uprobes_treelock);
|
||||
|
||||
return !!n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called in context of a munmap of a vma.
|
||||
*/
|
||||
|
@ -1037,10 +1063,12 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon
|
|||
if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */
|
||||
return;
|
||||
|
||||
if (!test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags))
|
||||
if (!test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags) ||
|
||||
test_bit(MMF_RECALC_UPROBES, &vma->vm_mm->flags))
|
||||
return;
|
||||
|
||||
/* TODO: unmapping uprobe(s) will need more work */
|
||||
if (vma_has_uprobes(vma, start, end))
|
||||
set_bit(MMF_RECALC_UPROBES, &vma->vm_mm->flags);
|
||||
}
|
||||
|
||||
/* Slot allocation for XOL */
|
||||
|
@ -1146,8 +1174,11 @@ void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
|
|||
{
|
||||
newmm->uprobes_state.xol_area = NULL;
|
||||
|
||||
if (test_bit(MMF_HAS_UPROBES, &oldmm->flags))
|
||||
if (test_bit(MMF_HAS_UPROBES, &oldmm->flags)) {
|
||||
set_bit(MMF_HAS_UPROBES, &newmm->flags);
|
||||
/* unconditionally, dup_mmap() skips VM_DONTCOPY vmas */
|
||||
set_bit(MMF_RECALC_UPROBES, &newmm->flags);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue