Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 191276
b: refs/heads/master
c: feef47d
h: refs/heads/master
v: v3
  • Loading branch information
Frederic Weisbecker committed May 1, 2010
1 parent 37b7ab2 commit 807c28b
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 32 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f93a20541134fa767e8dc4eb32e956d30b9f6b92
refs/heads/master: feef47d0cb530e8419dfa0b48141b538b89b1b1a
5 changes: 5 additions & 0 deletions trunk/arch/sh/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ struct pmu;
/* Maximum number of UBC channels */
#define HBP_NUM 2

static inline int hw_breakpoint_slots(int type)
{
return HBP_NUM;
}

/* arch/sh/kernel/hw_breakpoint.c */
extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
Expand Down
5 changes: 5 additions & 0 deletions trunk/arch/x86/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ struct arch_hw_breakpoint {
/* Total number of available HW breakpoint registers */
#define HBP_NUM 4

static inline int hw_breakpoint_slots(int type)
{
return HBP_NUM;
}

struct perf_event;
struct pmu;

Expand Down
10 changes: 10 additions & 0 deletions trunk/include/linux/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ enum {
HW_BREAKPOINT_INVALID = HW_BREAKPOINT_RW | HW_BREAKPOINT_X,
};

enum bp_type_idx {
TYPE_INST = 0,
#ifdef CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
TYPE_DATA = 0,
#else
TYPE_DATA = 1,
#endif
TYPE_MAX
};

#ifdef __KERNEL__

#include <linux/perf_event.h>
Expand Down
53 changes: 41 additions & 12 deletions trunk/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,12 @@
#include <linux/percpu.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/smp.h>

#include <linux/hw_breakpoint.h>

enum bp_type_idx {
TYPE_INST = 0,
#ifdef CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
TYPE_DATA = 0,
#else
TYPE_DATA = 1,
#endif
TYPE_MAX
};

/*
* Constraints data
Expand All @@ -63,11 +55,15 @@ enum bp_type_idx {
static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned[TYPE_MAX]);

/* Number of pinned task breakpoints in a cpu */
static DEFINE_PER_CPU(unsigned int, nr_task_bp_pinned[TYPE_MAX][HBP_NUM]);
static DEFINE_PER_CPU(unsigned int, *nr_task_bp_pinned[TYPE_MAX]);

/* Number of non-pinned cpu/task breakpoints in a cpu */
static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]);

static int nr_slots[TYPE_MAX];

static int constraints_initialized;

/* Gather the number of total pinned and un-pinned bp in a cpuset */
struct bp_busy_slots {
unsigned int pinned;
Expand Down Expand Up @@ -99,7 +95,7 @@ static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type)
int i;
unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu);

for (i = HBP_NUM -1; i >= 0; i--) {
for (i = nr_slots[type] - 1; i >= 0; i--) {
if (tsk_pinned[i] > 0)
return i + 1;
}
Expand Down Expand Up @@ -292,6 +288,10 @@ static int __reserve_bp_slot(struct perf_event *bp)
enum bp_type_idx type;
int weight;

/* We couldn't initialize breakpoint constraints on boot */
if (!constraints_initialized)
return -ENOMEM;

/* Basic checks */
if (bp->attr.bp_type == HW_BREAKPOINT_EMPTY ||
bp->attr.bp_type == HW_BREAKPOINT_INVALID)
Expand All @@ -304,7 +304,7 @@ static int __reserve_bp_slot(struct perf_event *bp)
fetch_this_slot(&slots, weight);

/* Flexible counters need to keep at least one slot */
if (slots.pinned + (!!slots.flexible) > HBP_NUM)
if (slots.pinned + (!!slots.flexible) > nr_slots[type])
return -ENOSPC;

toggle_bp_slot(bp, true, type, weight);
Expand Down Expand Up @@ -551,7 +551,36 @@ static struct notifier_block hw_breakpoint_exceptions_nb = {

static int __init init_hw_breakpoint(void)
{
unsigned int **task_bp_pinned;
int cpu, err_cpu;
int i;

for (i = 0; i < TYPE_MAX; i++)
nr_slots[i] = hw_breakpoint_slots(i);

for_each_possible_cpu(cpu) {
for (i = 0; i < TYPE_MAX; i++) {
task_bp_pinned = &per_cpu(nr_task_bp_pinned[i], cpu);
*task_bp_pinned = kzalloc(sizeof(int) * nr_slots[i],
GFP_KERNEL);
if (!*task_bp_pinned)
goto err_alloc;
}
}

constraints_initialized = 1;

return register_die_notifier(&hw_breakpoint_exceptions_nb);

err_alloc:
for_each_possible_cpu(err_cpu) {
if (err_cpu == cpu)
break;
for (i = 0; i < TYPE_MAX; i++)
kfree(per_cpu(nr_task_bp_pinned[i], cpu));
}

return -ENOMEM;
}
core_initcall(init_hw_breakpoint);

Expand Down
26 changes: 7 additions & 19 deletions trunk/kernel/trace/trace_ksym.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@

#include <asm/atomic.h>

/*
* For now, let us restrict the no. of symbols traced simultaneously to number
* of available hardware breakpoint registers.
*/
#define KSYM_TRACER_MAX HBP_NUM

#define KSYM_TRACER_OP_LEN 3 /* rw- */

struct trace_ksym {
Expand All @@ -53,7 +47,6 @@ struct trace_ksym {

static struct trace_array *ksym_trace_array;

static unsigned int ksym_filter_entry_count;
static unsigned int ksym_tracing_enabled;

static HLIST_HEAD(ksym_filter_head);
Expand Down Expand Up @@ -181,13 +174,6 @@ int process_new_ksym_entry(char *ksymname, int op, unsigned long addr)
struct trace_ksym *entry;
int ret = -ENOMEM;

if (ksym_filter_entry_count >= KSYM_TRACER_MAX) {
printk(KERN_ERR "ksym_tracer: Maximum limit:(%d) reached. No"
" new requests for tracing can be accepted now.\n",
KSYM_TRACER_MAX);
return -ENOSPC;
}

entry = kzalloc(sizeof(struct trace_ksym), GFP_KERNEL);
if (!entry)
return -ENOMEM;
Expand All @@ -203,13 +189,17 @@ int process_new_ksym_entry(char *ksymname, int op, unsigned long addr)

if (IS_ERR(entry->ksym_hbp)) {
ret = PTR_ERR(entry->ksym_hbp);
printk(KERN_INFO "ksym_tracer request failed. Try again"
" later!!\n");
if (ret == -ENOSPC) {
printk(KERN_ERR "ksym_tracer: Maximum limit reached."
" No new requests for tracing can be accepted now.\n");
} else {
printk(KERN_INFO "ksym_tracer request failed. Try again"
" later!!\n");
}
goto err;
}

hlist_add_head_rcu(&(entry->ksym_hlist), &ksym_filter_head);
ksym_filter_entry_count++;

return 0;

Expand Down Expand Up @@ -265,7 +255,6 @@ static void __ksym_trace_reset(void)
hlist_for_each_entry_safe(entry, node, node1, &ksym_filter_head,
ksym_hlist) {
unregister_wide_hw_breakpoint(entry->ksym_hbp);
ksym_filter_entry_count--;
hlist_del_rcu(&(entry->ksym_hlist));
synchronize_rcu();
kfree(entry);
Expand Down Expand Up @@ -338,7 +327,6 @@ static ssize_t ksym_trace_filter_write(struct file *file,
goto out_unlock;
}
/* Error or "symbol:---" case: drop it */
ksym_filter_entry_count--;
hlist_del_rcu(&(entry->ksym_hlist));
synchronize_rcu();
kfree(entry);
Expand Down

0 comments on commit 807c28b

Please sign in to comment.