aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/hw_breakpoint.c56
-rw-r--r--kernel/kgdb.c3
2 files changed, 49 insertions, 10 deletions
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c
index 50dbd5999588..8a5c7d55ac9f 100644
--- a/kernel/hw_breakpoint.c
+++ b/kernel/hw_breakpoint.c
@@ -243,38 +243,70 @@ static void toggle_bp_slot(struct perf_event *bp, bool enable)
243 * ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *)) 243 * ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *))
244 * + max(per_cpu(nr_task_bp_pinned, *))) < HBP_NUM 244 * + max(per_cpu(nr_task_bp_pinned, *))) < HBP_NUM
245 */ 245 */
246int reserve_bp_slot(struct perf_event *bp) 246static int __reserve_bp_slot(struct perf_event *bp)
247{ 247{
248 struct bp_busy_slots slots = {0}; 248 struct bp_busy_slots slots = {0};
249 int ret = 0;
250
251 mutex_lock(&nr_bp_mutex);
252 249
253 fetch_bp_busy_slots(&slots, bp); 250 fetch_bp_busy_slots(&slots, bp);
254 251
255 /* Flexible counters need to keep at least one slot */ 252 /* Flexible counters need to keep at least one slot */
256 if (slots.pinned + (!!slots.flexible) == HBP_NUM) { 253 if (slots.pinned + (!!slots.flexible) == HBP_NUM)
257 ret = -ENOSPC; 254 return -ENOSPC;
258 goto end;
259 }
260 255
261 toggle_bp_slot(bp, true); 256 toggle_bp_slot(bp, true);
262 257
263end: 258 return 0;
259}
260
261int reserve_bp_slot(struct perf_event *bp)
262{
263 int ret;
264
265 mutex_lock(&nr_bp_mutex);
266
267 ret = __reserve_bp_slot(bp);
268
264 mutex_unlock(&nr_bp_mutex); 269 mutex_unlock(&nr_bp_mutex);
265 270
266 return ret; 271 return ret;
267} 272}
268 273
274static void __release_bp_slot(struct perf_event *bp)
275{
276 toggle_bp_slot(bp, false);
277}
278
269void release_bp_slot(struct perf_event *bp) 279void release_bp_slot(struct perf_event *bp)
270{ 280{
271 mutex_lock(&nr_bp_mutex); 281 mutex_lock(&nr_bp_mutex);
272 282
273 toggle_bp_slot(bp, false); 283 __release_bp_slot(bp);
274 284
275 mutex_unlock(&nr_bp_mutex); 285 mutex_unlock(&nr_bp_mutex);
276} 286}
277 287
288/*
289 * Allow the kernel debugger to reserve breakpoint slots without
290 * taking a lock using the dbg_* variant of for the reserve and
291 * release breakpoint slots.
292 */
293int dbg_reserve_bp_slot(struct perf_event *bp)
294{
295 if (mutex_is_locked(&nr_bp_mutex))
296 return -1;
297
298 return __reserve_bp_slot(bp);
299}
300
301int dbg_release_bp_slot(struct perf_event *bp)
302{
303 if (mutex_is_locked(&nr_bp_mutex))
304 return -1;
305
306 __release_bp_slot(bp);
307
308 return 0;
309}
278 310
279int register_perf_hw_breakpoint(struct perf_event *bp) 311int register_perf_hw_breakpoint(struct perf_event *bp)
280{ 312{
@@ -296,6 +328,10 @@ int register_perf_hw_breakpoint(struct perf_event *bp)
296 if (!bp->attr.disabled || !bp->overflow_handler) 328 if (!bp->attr.disabled || !bp->overflow_handler)
297 ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task); 329 ret = arch_validate_hwbkpt_settings(bp, bp->ctx->task);
298 330
331 /* if arch_validate_hwbkpt_settings() fails then release bp slot */
332 if (ret)
333 release_bp_slot(bp);
334
299 return ret; 335 return ret;
300} 336}
301 337
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index 2eb517e23514..c7ade62e4ef0 100644
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -583,6 +583,9 @@ static void kgdb_wait(struct pt_regs *regs)
583 smp_wmb(); 583 smp_wmb();
584 atomic_set(&cpu_in_kgdb[cpu], 1); 584 atomic_set(&cpu_in_kgdb[cpu], 1);
585 585
586 /* Disable any cpu specific hw breakpoints */
587 kgdb_disable_hw_debug(regs);
588
586 /* Wait till primary CPU is done with debugging */ 589 /* Wait till primary CPU is done with debugging */
587 while (atomic_read(&passive_cpu_wait[cpu])) 590 while (atomic_read(&passive_cpu_wait[cpu]))
588 cpu_relax(); 591 cpu_relax();