@ -44,23 +44,17 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
return 0 ;
}
static int perf_trace_event_init ( struct ftrace_event_call * tp_event ,
struct perf_event * p_event )
static int perf_trace_event_reg ( struct ftrace_event_call * tp_event ,
struct perf_event * p_event )
{
struct hlist_head __percpu * list ;
int ret ;
int ret = - ENOMEM ;
int cpu ;
ret = perf_trace_event_perm ( tp_event , p_event ) ;
if ( ret )
return ret ;
p_event - > tp_event = tp_event ;
if ( tp_event - > perf_refcount + + > 0 )
return 0 ;
ret = - ENOMEM ;
list = alloc_percpu ( struct hlist_head ) ;
if ( ! list )
goto fail ;
@ -83,7 +77,7 @@ static int perf_trace_event_init(struct ftrace_event_call *tp_event,
}
}
ret = tp_event - > class - > reg ( tp_event , TRACE_REG_PERF_REGISTER ) ;
ret = tp_event - > class - > reg ( tp_event , TRACE_REG_PERF_REGISTER , NULL ) ;
if ( ret )
goto fail ;
@ -108,6 +102,69 @@ fail:
return ret ;
}
static void perf_trace_event_unreg ( struct perf_event * p_event )
{
struct ftrace_event_call * tp_event = p_event - > tp_event ;
int i ;
if ( - - tp_event - > perf_refcount > 0 )
goto out ;
tp_event - > class - > reg ( tp_event , TRACE_REG_PERF_UNREGISTER , NULL ) ;
/*
* Ensure our callback won ' t be called anymore . The buffers
* will be freed after that .
*/
tracepoint_synchronize_unregister ( ) ;
free_percpu ( tp_event - > perf_events ) ;
tp_event - > perf_events = NULL ;
if ( ! - - total_ref_count ) {
for ( i = 0 ; i < PERF_NR_CONTEXTS ; i + + ) {
free_percpu ( perf_trace_buf [ i ] ) ;
perf_trace_buf [ i ] = NULL ;
}
}
out :
module_put ( tp_event - > mod ) ;
}
static int perf_trace_event_open ( struct perf_event * p_event )
{
struct ftrace_event_call * tp_event = p_event - > tp_event ;
return tp_event - > class - > reg ( tp_event , TRACE_REG_PERF_OPEN , p_event ) ;
}
static void perf_trace_event_close ( struct perf_event * p_event )
{
struct ftrace_event_call * tp_event = p_event - > tp_event ;
tp_event - > class - > reg ( tp_event , TRACE_REG_PERF_CLOSE , p_event ) ;
}
static int perf_trace_event_init ( struct ftrace_event_call * tp_event ,
struct perf_event * p_event )
{
int ret ;
ret = perf_trace_event_perm ( tp_event , p_event ) ;
if ( ret )
return ret ;
ret = perf_trace_event_reg ( tp_event , p_event ) ;
if ( ret )
return ret ;
ret = perf_trace_event_open ( p_event ) ;
if ( ret ) {
perf_trace_event_unreg ( p_event ) ;
return ret ;
}
return 0 ;
}
int perf_trace_init ( struct perf_event * p_event )
{
struct ftrace_event_call * tp_event ;
@ -130,6 +187,14 @@ int perf_trace_init(struct perf_event *p_event)
return ret ;
}
void perf_trace_destroy ( struct perf_event * p_event )
{
mutex_lock ( & event_mutex ) ;
perf_trace_event_close ( p_event ) ;
perf_trace_event_unreg ( p_event ) ;
mutex_unlock ( & event_mutex ) ;
}
int perf_trace_add ( struct perf_event * p_event , int flags )
{
struct ftrace_event_call * tp_event = p_event - > tp_event ;
@ -154,37 +219,6 @@ void perf_trace_del(struct perf_event *p_event, int flags)
hlist_del_rcu ( & p_event - > hlist_entry ) ;
}
void perf_trace_destroy ( struct perf_event * p_event )
{
struct ftrace_event_call * tp_event = p_event - > tp_event ;
int i ;
mutex_lock ( & event_mutex ) ;
if ( - - tp_event - > perf_refcount > 0 )
goto out ;
tp_event - > class - > reg ( tp_event , TRACE_REG_PERF_UNREGISTER ) ;
/*
* Ensure our callback won ' t be called anymore . The buffers
* will be freed after that .
*/
tracepoint_synchronize_unregister ( ) ;
free_percpu ( tp_event - > perf_events ) ;
tp_event - > perf_events = NULL ;
if ( ! - - total_ref_count ) {
for ( i = 0 ; i < PERF_NR_CONTEXTS ; i + + ) {
free_percpu ( perf_trace_buf [ i ] ) ;
perf_trace_buf [ i ] = NULL ;
}
}
out :
module_put ( tp_event - > mod ) ;
mutex_unlock ( & event_mutex ) ;
}
__kprobes void * perf_trace_buf_prepare ( int size , unsigned short type ,
struct pt_regs * regs , int * rctxp )
{