Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b061610 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'perf-fixes-for-linus' of...

Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  perf tools: Makefile: Use gcc to determine ARCH
  perf events, x86: Fix Intel Nehalem and Westmere last level cache event definitions
  hw_breakpoints, powerpc: Fix CONFIG_HAVE_HW_BREAKPOINT off-case in ptrace_set_debugreg()
  sh, hw_breakpoints: Fix racy access to ptrace breakpoints
  arm, hw_breakpoints: Fix racy access to ptrace breakpoints
  powerpc, hw_breakpoints: Fix racy access to ptrace breakpoints
  x86, hw_breakpoints: Fix racy access to ptrace breakpoints
  ptrace: Prepare to fix racy accesses on task breakpoints
parents c2bf807e 174a7b1f
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -767,12 +767,20 @@ long arch_ptrace(struct task_struct *child, long request,

#ifdef CONFIG_HAVE_HW_BREAKPOINT
		case PTRACE_GETHBPREGS:
			if (ptrace_get_breakpoints(child) < 0)
				return -ESRCH;

			ret = ptrace_gethbpregs(child, addr,
						(unsigned long __user *)data);
			ptrace_put_breakpoints(child);
			break;
		case PTRACE_SETHBPREGS:
			if (ptrace_get_breakpoints(child) < 0)
				return -ESRCH;

			ret = ptrace_sethbpregs(child, addr,
						(unsigned long __user *)data);
			ptrace_put_breakpoints(child);
			break;
#endif

+11 −1
Original line number Diff line number Diff line
@@ -933,12 +933,16 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
	if (data && !(data & DABR_TRANSLATION))
		return -EIO;
#ifdef CONFIG_HAVE_HW_BREAKPOINT
	if (ptrace_get_breakpoints(task) < 0)
		return -ESRCH;

	bp = thread->ptrace_bps[0];
	if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) {
		if (bp) {
			unregister_hw_breakpoint(bp);
			thread->ptrace_bps[0] = NULL;
		}
		ptrace_put_breakpoints(task);
		return 0;
	}
	if (bp) {
@@ -948,9 +952,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
					(DABR_DATA_WRITE | DABR_DATA_READ),
							&attr.bp_type);
		ret =  modify_user_hw_breakpoint(bp, &attr);
		if (ret)
		if (ret) {
			ptrace_put_breakpoints(task);
			return ret;
		}
		thread->ptrace_bps[0] = bp;
		ptrace_put_breakpoints(task);
		thread->dabr = data;
		return 0;
	}
@@ -965,9 +972,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
							ptrace_triggered, task);
	if (IS_ERR(bp)) {
		thread->ptrace_bps[0] = NULL;
		ptrace_put_breakpoints(task);
		return PTR_ERR(bp);
	}

	ptrace_put_breakpoints(task);

#endif /* CONFIG_HAVE_HW_BREAKPOINT */

	/* Move contents to the DABR register */
+4 −0
Original line number Diff line number Diff line
@@ -117,7 +117,11 @@ void user_enable_single_step(struct task_struct *child)

	set_tsk_thread_flag(child, TIF_SINGLESTEP);

	if (ptrace_get_breakpoints(child) < 0)
		return;

	set_single_step(child, pc);
	ptrace_put_breakpoints(child);
}

void user_disable_single_step(struct task_struct *child)
+52 −35
Original line number Diff line number Diff line
@@ -184,26 +184,23 @@ static __initconst const u64 snb_hw_cache_event_ids
	},
 },
 [ C(LL  ) ] = {
	/*
	 * TBD: Need Off-core Response Performance Monitoring support
	 */
	[ C(OP_READ) ] = {
		/* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */
		/* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
		[ C(RESULT_ACCESS) ] = 0x01b7,
		/* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01bb,
		/* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01b7,
	},
	[ C(OP_WRITE) ] = {
		/* OFFCORE_RESPONSE_0.ANY_RFO.LOCAL_CACHE */
		/* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
		[ C(RESULT_ACCESS) ] = 0x01b7,
		/* OFFCORE_RESPONSE_1.ANY_RFO.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01bb,
		/* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01b7,
	},
	[ C(OP_PREFETCH) ] = {
		/* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */
		/* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
		[ C(RESULT_ACCESS) ] = 0x01b7,
		/* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01bb,
		/* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01b7,
	},
 },
 [ C(DTLB) ] = {
@@ -285,26 +282,26 @@ static __initconst const u64 westmere_hw_cache_event_ids
 },
 [ C(LL  ) ] = {
	[ C(OP_READ) ] = {
		/* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */
		/* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
		[ C(RESULT_ACCESS) ] = 0x01b7,
		/* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01bb,
		/* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01b7,
	},
	/*
	 * Use RFO, not WRITEBACK, because a write miss would typically occur
	 * on RFO.
	 */
	[ C(OP_WRITE) ] = {
		/* OFFCORE_RESPONSE_1.ANY_RFO.LOCAL_CACHE */
		[ C(RESULT_ACCESS) ] = 0x01bb,
		/* OFFCORE_RESPONSE_0.ANY_RFO.ANY_LLC_MISS */
		/* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
		[ C(RESULT_ACCESS) ] = 0x01b7,
		/* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01b7,
	},
	[ C(OP_PREFETCH) ] = {
		/* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */
		/* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
		[ C(RESULT_ACCESS) ] = 0x01b7,
		/* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01bb,
		/* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
		[ C(RESULT_MISS)   ] = 0x01b7,
	},
 },
 [ C(DTLB) ] = {
@@ -352,16 +349,36 @@ static __initconst const u64 westmere_hw_cache_event_ids
};

/*
 * OFFCORE_RESPONSE MSR bits (subset), See IA32 SDM Vol 3 30.6.1.3
 * Nehalem/Westmere MSR_OFFCORE_RESPONSE bits;
 * See IA32 SDM Vol 3B 30.6.1.3
 */

#define DMND_DATA_RD     (1 << 0)
#define DMND_RFO         (1 << 1)
#define DMND_WB          (1 << 3)
#define PF_DATA_RD       (1 << 4)
#define PF_DATA_RFO      (1 << 5)
#define RESP_UNCORE_HIT  (1 << 8)
#define RESP_MISS        (0xf600) /* non uncore hit */
#define NHM_DMND_DATA_RD	(1 << 0)
#define NHM_DMND_RFO		(1 << 1)
#define NHM_DMND_IFETCH		(1 << 2)
#define NHM_DMND_WB		(1 << 3)
#define NHM_PF_DATA_RD		(1 << 4)
#define NHM_PF_DATA_RFO		(1 << 5)
#define NHM_PF_IFETCH		(1 << 6)
#define NHM_OFFCORE_OTHER	(1 << 7)
#define NHM_UNCORE_HIT		(1 << 8)
#define NHM_OTHER_CORE_HIT_SNP	(1 << 9)
#define NHM_OTHER_CORE_HITM	(1 << 10)
        			/* reserved */
#define NHM_REMOTE_CACHE_FWD	(1 << 12)
#define NHM_REMOTE_DRAM		(1 << 13)
#define NHM_LOCAL_DRAM		(1 << 14)
#define NHM_NON_DRAM		(1 << 15)

#define NHM_ALL_DRAM		(NHM_REMOTE_DRAM|NHM_LOCAL_DRAM)

#define NHM_DMND_READ		(NHM_DMND_DATA_RD)
#define NHM_DMND_WRITE		(NHM_DMND_RFO|NHM_DMND_WB)
#define NHM_DMND_PREFETCH	(NHM_PF_DATA_RD|NHM_PF_DATA_RFO)

#define NHM_L3_HIT	(NHM_UNCORE_HIT|NHM_OTHER_CORE_HIT_SNP|NHM_OTHER_CORE_HITM)
#define NHM_L3_MISS	(NHM_NON_DRAM|NHM_ALL_DRAM|NHM_REMOTE_CACHE_FWD)
#define NHM_L3_ACCESS	(NHM_L3_HIT|NHM_L3_MISS)

static __initconst const u64 nehalem_hw_cache_extra_regs
				[PERF_COUNT_HW_CACHE_MAX]
@@ -370,16 +387,16 @@ static __initconst const u64 nehalem_hw_cache_extra_regs
{
 [ C(LL  ) ] = {
	[ C(OP_READ) ] = {
		[ C(RESULT_ACCESS) ] = DMND_DATA_RD|RESP_UNCORE_HIT,
		[ C(RESULT_MISS)   ] = DMND_DATA_RD|RESP_MISS,
		[ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_L3_ACCESS,
		[ C(RESULT_MISS)   ] = NHM_DMND_READ|NHM_L3_MISS,
	},
	[ C(OP_WRITE) ] = {
		[ C(RESULT_ACCESS) ] = DMND_RFO|DMND_WB|RESP_UNCORE_HIT,
		[ C(RESULT_MISS)   ] = DMND_RFO|DMND_WB|RESP_MISS,
		[ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_L3_ACCESS,
		[ C(RESULT_MISS)   ] = NHM_DMND_WRITE|NHM_L3_MISS,
	},
	[ C(OP_PREFETCH) ] = {
		[ C(RESULT_ACCESS) ] = PF_DATA_RD|PF_DATA_RFO|RESP_UNCORE_HIT,
		[ C(RESULT_MISS)   ] = PF_DATA_RD|PF_DATA_RFO|RESP_MISS,
		[ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_L3_ACCESS,
		[ C(RESULT_MISS)   ] = NHM_DMND_PREFETCH|NHM_L3_MISS,
	},
 }
};
+26 −10
Original line number Diff line number Diff line
@@ -608,6 +608,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
	unsigned len, type;
	struct perf_event *bp;

	if (ptrace_get_breakpoints(tsk) < 0)
		return -ESRCH;

	data &= ~DR_CONTROL_RESERVED;
	old_dr7 = ptrace_get_dr7(thread->ptrace_bps);
restore:
@@ -655,6 +658,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
		}
		goto restore;
	}

	ptrace_put_breakpoints(tsk);

	return ((orig_ret < 0) ? orig_ret : rc);
}

@@ -668,10 +674,17 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)

	if (n < HBP_NUM) {
		struct perf_event *bp;

		if (ptrace_get_breakpoints(tsk) < 0)
			return -ESRCH;

		bp = thread->ptrace_bps[n];
		if (!bp)
			return 0;
			val = 0;
		else
			val = bp->hw.info.address;

		ptrace_put_breakpoints(tsk);
	} else if (n == 6) {
		val = thread->debugreg6;
	 } else if (n == 7) {
@@ -686,6 +699,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
	struct perf_event *bp;
	struct thread_struct *t = &tsk->thread;
	struct perf_event_attr attr;
	int err = 0;

	if (ptrace_get_breakpoints(tsk) < 0)
		return -ESRCH;

	if (!t->ptrace_bps[nr]) {
		ptrace_breakpoint_init(&attr);
@@ -709,24 +726,23 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
		 * writing for the user. And anyway this is the previous
		 * behaviour.
		 */
		if (IS_ERR(bp))
			return PTR_ERR(bp);
		if (IS_ERR(bp)) {
			err = PTR_ERR(bp);
			goto put;
		}

		t->ptrace_bps[nr] = bp;
	} else {
		int err;

		bp = t->ptrace_bps[nr];

		attr = bp->attr;
		attr.bp_addr = addr;
		err = modify_user_hw_breakpoint(bp, &attr);
		if (err)
			return err;
	}


	return 0;
put:
	ptrace_put_breakpoints(tsk);
	return err;
}

/*
Loading