Messages in this thread | | | Date | Fri, 1 Jun 2012 20:31:13 +0200 | From | Oleg Nesterov <> | Subject | Re: [PATCH 1/3] uprobes: install_breakpoint() should fail if is_swbp_insn() == T |
| |
On 06/01, Oleg Nesterov wrote: > > But. What do you think about the pseudo-code below? Only to illustrate > the approach, the code is not complete. > > In the "likely" case we do vma_prio_tree_foreach() twice, this is > better than the current quadratic behaviour.
See the "full" version. Untested of course, most probably has bugs, but hopefully close enough.
What do you think?
Oleg.
struct map_info { struct map_info *next; struct mm_struct *mm; loff_t vaddr; };
static inline struct map_info *free_map_info(struct map_info *info) { struct map_info *next = info->next; kfree(info); return next; }
static struct map_info * build_map_info(struct address_space *mapping, loff_t offset, bool is_register) { unsigned long pgoff = offset >> PAGE_SHIFT; struct prio_tree_iter iter; struct vm_area_struct *vma; struct map_info *curr = NULL; struct map_info *prev = NULL; struct map_info *info; int more = 0;
again: mutex_lock(&mapping->i_mmap_mutex); vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { if (!valid_vma(vma, is_register)) continue;
if (!prev) { more++; continue; }
if (!atomic_inc_not_zero(&vma->vm_mm->mm_users)) continue;
info = prev; prev = prev->next; info->next = curr; curr = info;
info->mm = vma->vm_mm; info->vaddr = vma_address(vma, offset); } mutex_unlock(&mapping->i_mmap_mutex);
if (!more) goto out;
prev = curr; while (curr) { mmput(curr->mm); curr = curr->next; }
while (more--) { info = kmalloc(sizeof(struct map_info), GFP_KERNEL); if (!info) { curr = ERR_PTR(-ENOMEM); goto out; } info->next = prev; prev = info; }
goto again; out: while (prev) prev = free_map_info(prev); return curr; }
static int register_for_each_vma(struct uprobe *uprobe, bool is_register) { struct map_info *info; int err = 0;
info = build_map_info(uprobe->inode->i_mapping, uprobe->offset, is_register); if (IS_ERR(info)) return PTR_ERR(info);
while (info) { struct mm_struct *mm = info->mm; struct vm_area_struct *vma; loff_t vaddr;
if (err) goto free;
down_write(&mm->mmap_sem); vma = find_vma(mm, (unsigned long)info->vaddr); if (!vma || !valid_vma(vma, is_register)) goto unlock;
vaddr = vma_address(vma, uprobe->offset); if (vma->vm_file->f_mapping->host != uprobe->inode || vaddr != info->vaddr) goto unlock;
if (is_register) { err = install_breakpoint(uprobe, mm, vma, info->vaddr); if (err == -EEXIST) err = 0; } else { remove_breakpoint(uprobe, mm, info->vaddr); } unlock: up_write(&mm->mmap_sem); free: mmput(mm); info = free_map_info(info); }
return err; }
| |