aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-12-31 12:00:06 -0500
committerOleg Nesterov <oleg@redhat.com>2013-02-08 11:47:12 -0500
commita6cb3f6d51253e9cf21a38b17c025018117809d7 (patch)
treef0ffafefd93cb97f550b0149b14e56a68c778576 /kernel/events
parent5a2df662aafdabffb2cf3adb780a5adf66dfb3bc (diff)
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>
Diffstat (limited to 'kernel/events')
-rw-r--r--kernel/events/uprobes.c37
1 files changed, 21 insertions, 16 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 16e54d63a9fd..8d9c5bcb110e 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1176,30 +1176,26 @@ static unsigned long xol_take_insn_slot(struct xol_area *area)
1176} 1176}
1177 1177
1178/* 1178/*
1179 * xol_get_insn_slot - If was not allocated a slot, then 1179 * xol_get_insn_slot - allocate a slot for xol.
1180 * allocate a slot.
1181 * Returns the allocated slot address or 0. 1180 * Returns the allocated slot address or 0.
1182 */ 1181 */
1183static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot_addr) 1182static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
1184{ 1183{
1185 struct xol_area *area; 1184 struct xol_area *area;
1186 unsigned long offset; 1185 unsigned long offset;
1186 unsigned long xol_vaddr;
1187 void *vaddr; 1187 void *vaddr;
1188 1188
1189 area = get_xol_area(); 1189 area = get_xol_area();
1190 if (!area) 1190 if (!area)
1191 return 0; 1191 return 0;
1192 1192
1193 current->utask->xol_vaddr = xol_take_insn_slot(area); 1193 xol_vaddr = xol_take_insn_slot(area);
1194 /* 1194 if (unlikely(!xol_vaddr))
1195 * Initialize the slot if xol_vaddr points to valid
1196 * instruction slot.
1197 */
1198 if (unlikely(!current->utask->xol_vaddr))
1199 return 0; 1195 return 0;
1200 1196
1201 current->utask->vaddr = slot_addr; 1197 /* Initialize the slot */
1202 offset = current->utask->xol_vaddr & ~PAGE_MASK; 1198 offset = xol_vaddr & ~PAGE_MASK;
1203 vaddr = kmap_atomic(area->page); 1199 vaddr = kmap_atomic(area->page);
1204 memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES); 1200 memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
1205 kunmap_atomic(vaddr); 1201 kunmap_atomic(vaddr);
@@ -1209,7 +1205,7 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot
1209 */ 1205 */
1210 flush_dcache_page(area->page); 1206 flush_dcache_page(area->page);
1211 1207
1212 return current->utask->xol_vaddr; 1208 return xol_vaddr;
1213} 1209}
1214 1210
1215/* 1211/*
@@ -1306,12 +1302,21 @@ static struct uprobe_task *get_utask(void)
1306 1302
1307/* Prepare to single-step probed instruction out of line. */ 1303/* Prepare to single-step probed instruction out of line. */
1308static int 1304static int
1309pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long vaddr) 1305pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long bp_vaddr)
1310{ 1306{
1311 if (xol_get_insn_slot(uprobe, vaddr) && !arch_uprobe_pre_xol(&uprobe->arch, regs)) 1307 struct uprobe_task *utask;
1312 return 0; 1308 unsigned long xol_vaddr;
1309
1310 utask = current->utask;
1311
1312 xol_vaddr = xol_get_insn_slot(uprobe);
1313 if (!xol_vaddr)
1314 return -ENOMEM;
1315
1316 utask->xol_vaddr = xol_vaddr;
1317 utask->vaddr = bp_vaddr;
1313 1318
1314 return -EFAULT; 1319 return arch_uprobe_pre_xol(&uprobe->arch, regs);
1315} 1320}
1316 1321
1317/* 1322/*