uprobes: Do not play with utask in xol_get_insn_slot()
pre_ssout()->xol_get_insn_slot() path is confusing and buggy. This patch cleanups the code, the next one fixes the bug. Change xol_get_insn_slot() to only allocate the slot and do nothing more, move the initialization of utask->xol_vaddr/vaddr into pre_ssout(). Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Anton Arapov <anton@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
This commit is contained in:
parent
5a2df662aa
commit
a6cb3f6d51
|
@ -1176,30 +1176,26 @@ static unsigned long xol_take_insn_slot(struct xol_area *area)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xol_get_insn_slot - If was not allocated a slot, then
|
* xol_get_insn_slot - allocate a slot for xol.
|
||||||
* allocate a slot.
|
|
||||||
* Returns the allocated slot address or 0.
|
* Returns the allocated slot address or 0.
|
||||||
*/
|
*/
|
||||||
static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot_addr)
|
static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
|
||||||
{
|
{
|
||||||
struct xol_area *area;
|
struct xol_area *area;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
|
unsigned long xol_vaddr;
|
||||||
void *vaddr;
|
void *vaddr;
|
||||||
|
|
||||||
area = get_xol_area();
|
area = get_xol_area();
|
||||||
if (!area)
|
if (!area)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
current->utask->xol_vaddr = xol_take_insn_slot(area);
|
xol_vaddr = xol_take_insn_slot(area);
|
||||||
/*
|
if (unlikely(!xol_vaddr))
|
||||||
* Initialize the slot if xol_vaddr points to valid
|
|
||||||
* instruction slot.
|
|
||||||
*/
|
|
||||||
if (unlikely(!current->utask->xol_vaddr))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
current->utask->vaddr = slot_addr;
|
/* Initialize the slot */
|
||||||
offset = current->utask->xol_vaddr & ~PAGE_MASK;
|
offset = xol_vaddr & ~PAGE_MASK;
|
||||||
vaddr = kmap_atomic(area->page);
|
vaddr = kmap_atomic(area->page);
|
||||||
memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
|
memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
|
||||||
kunmap_atomic(vaddr);
|
kunmap_atomic(vaddr);
|
||||||
|
@ -1209,7 +1205,7 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot
|
||||||
*/
|
*/
|
||||||
flush_dcache_page(area->page);
|
flush_dcache_page(area->page);
|
||||||
|
|
||||||
return current->utask->xol_vaddr;
|
return xol_vaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1306,12 +1302,21 @@ static struct uprobe_task *get_utask(void)
|
||||||
|
|
||||||
/* Prepare to single-step probed instruction out of line. */
|
/* Prepare to single-step probed instruction out of line. */
|
||||||
static int
|
static int
|
||||||
pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long vaddr)
|
pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long bp_vaddr)
|
||||||
{
|
{
|
||||||
if (xol_get_insn_slot(uprobe, vaddr) && !arch_uprobe_pre_xol(&uprobe->arch, regs))
|
struct uprobe_task *utask;
|
||||||
return 0;
|
unsigned long xol_vaddr;
|
||||||
|
|
||||||
return -EFAULT;
|
utask = current->utask;
|
||||||
|
|
||||||
|
xol_vaddr = xol_get_insn_slot(uprobe);
|
||||||
|
if (!xol_vaddr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
utask->xol_vaddr = xol_vaddr;
|
||||||
|
utask->vaddr = bp_vaddr;
|
||||||
|
|
||||||
|
return arch_uprobe_pre_xol(&uprobe->arch, regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue