@@ -396,6 +396,7 @@ enum handler_id {
396
396
enum action_id {
397
397
ACTION_SAVE = 1 ,
398
398
ACTION_TRACE ,
399
+ ACTION_SNAPSHOT ,
399
400
};
400
401
401
402
struct action_data {
@@ -454,6 +455,83 @@ struct action_data {
454
455
};
455
456
};
456
457
458
+ struct track_data {
459
+ u64 track_val ;
460
+ bool updated ;
461
+
462
+ unsigned int key_len ;
463
+ void * key ;
464
+ struct tracing_map_elt elt ;
465
+
466
+ struct action_data * action_data ;
467
+ struct hist_trigger_data * hist_data ;
468
+ };
469
+
470
+ struct hist_elt_data {
471
+ char * comm ;
472
+ u64 * var_ref_vals ;
473
+ char * field_var_str [SYNTH_FIELDS_MAX ];
474
+ };
475
+
476
+ struct snapshot_context {
477
+ struct tracing_map_elt * elt ;
478
+ void * key ;
479
+ };
480
+
481
+ static void track_data_free (struct track_data * track_data )
482
+ {
483
+ struct hist_elt_data * elt_data ;
484
+
485
+ if (!track_data )
486
+ return ;
487
+
488
+ kfree (track_data -> key );
489
+
490
+ elt_data = track_data -> elt .private_data ;
491
+ if (elt_data ) {
492
+ kfree (elt_data -> comm );
493
+ kfree (elt_data );
494
+ }
495
+
496
+ kfree (track_data );
497
+ }
498
+
499
+ static struct track_data * track_data_alloc (unsigned int key_len ,
500
+ struct action_data * action_data ,
501
+ struct hist_trigger_data * hist_data )
502
+ {
503
+ struct track_data * data = kzalloc (sizeof (* data ), GFP_KERNEL );
504
+ struct hist_elt_data * elt_data ;
505
+
506
+ if (!data )
507
+ return ERR_PTR (- ENOMEM );
508
+
509
+ data -> key = kzalloc (key_len , GFP_KERNEL );
510
+ if (!data -> key ) {
511
+ track_data_free (data );
512
+ return ERR_PTR (- ENOMEM );
513
+ }
514
+
515
+ data -> key_len = key_len ;
516
+ data -> action_data = action_data ;
517
+ data -> hist_data = hist_data ;
518
+
519
+ elt_data = kzalloc (sizeof (* elt_data ), GFP_KERNEL );
520
+ if (!elt_data ) {
521
+ track_data_free (data );
522
+ return ERR_PTR (- ENOMEM );
523
+ }
524
+ data -> elt .private_data = elt_data ;
525
+
526
+ elt_data -> comm = kzalloc (TASK_COMM_LEN , GFP_KERNEL );
527
+ if (!elt_data -> comm ) {
528
+ track_data_free (data );
529
+ return ERR_PTR (- ENOMEM );
530
+ }
531
+
532
+ return data ;
533
+ }
534
+
457
535
static char last_hist_cmd [MAX_FILTER_STR_VAL ];
458
536
static char hist_err_str [MAX_FILTER_STR_VAL ];
459
537
@@ -1726,12 +1804,6 @@ static struct hist_field *find_event_var(struct hist_trigger_data *hist_data,
1726
1804
return hist_field ;
1727
1805
}
1728
1806
1729
- struct hist_elt_data {
1730
- char * comm ;
1731
- u64 * var_ref_vals ;
1732
- char * field_var_str [SYNTH_FIELDS_MAX ];
1733
- };
1734
-
1735
1807
static u64 hist_field_var_ref (struct hist_field * hist_field ,
1736
1808
struct tracing_map_elt * elt ,
1737
1809
struct ring_buffer_event * rbe ,
@@ -3452,6 +3524,112 @@ static bool check_track_val(struct tracing_map_elt *elt,
3452
3524
return data -> track_data .check_val (track_val , var_val );
3453
3525
}
3454
3526
3527
+ #ifdef CONFIG_TRACER_SNAPSHOT
3528
+ static bool cond_snapshot_update (struct trace_array * tr , void * cond_data )
3529
+ {
3530
+ /* called with tr->max_lock held */
3531
+ struct track_data * track_data = tr -> cond_snapshot -> cond_data ;
3532
+ struct hist_elt_data * elt_data , * track_elt_data ;
3533
+ struct snapshot_context * context = cond_data ;
3534
+ u64 track_val ;
3535
+
3536
+ if (!track_data )
3537
+ return false;
3538
+
3539
+ track_val = get_track_val (track_data -> hist_data , context -> elt ,
3540
+ track_data -> action_data );
3541
+
3542
+ track_data -> track_val = track_val ;
3543
+ memcpy (track_data -> key , context -> key , track_data -> key_len );
3544
+
3545
+ elt_data = context -> elt -> private_data ;
3546
+ track_elt_data = track_data -> elt .private_data ;
3547
+ if (elt_data -> comm )
3548
+ memcpy (track_elt_data -> comm , elt_data -> comm , TASK_COMM_LEN );
3549
+
3550
+ track_data -> updated = true;
3551
+
3552
+ return true;
3553
+ }
3554
+
3555
+ static void save_track_data_snapshot (struct hist_trigger_data * hist_data ,
3556
+ struct tracing_map_elt * elt , void * rec ,
3557
+ struct ring_buffer_event * rbe , void * key ,
3558
+ struct action_data * data ,
3559
+ u64 * var_ref_vals )
3560
+ {
3561
+ struct trace_event_file * file = hist_data -> event_file ;
3562
+ struct snapshot_context context ;
3563
+
3564
+ context .elt = elt ;
3565
+ context .key = key ;
3566
+
3567
+ tracing_snapshot_cond (file -> tr , & context );
3568
+ }
3569
+
3570
+ static void hist_trigger_print_key (struct seq_file * m ,
3571
+ struct hist_trigger_data * hist_data ,
3572
+ void * key ,
3573
+ struct tracing_map_elt * elt );
3574
+
3575
+ static struct action_data * snapshot_action (struct hist_trigger_data * hist_data )
3576
+ {
3577
+ unsigned int i ;
3578
+
3579
+ if (!hist_data -> n_actions )
3580
+ return NULL ;
3581
+
3582
+ for (i = 0 ; i < hist_data -> n_actions ; i ++ ) {
3583
+ struct action_data * data = hist_data -> actions [i ];
3584
+
3585
+ if (data -> action == ACTION_SNAPSHOT )
3586
+ return data ;
3587
+ }
3588
+
3589
+ return NULL ;
3590
+ }
3591
+
3592
+ static void track_data_snapshot_print (struct seq_file * m ,
3593
+ struct hist_trigger_data * hist_data )
3594
+ {
3595
+ struct trace_event_file * file = hist_data -> event_file ;
3596
+ struct track_data * track_data ;
3597
+ struct action_data * action ;
3598
+
3599
+ track_data = tracing_cond_snapshot_data (file -> tr );
3600
+ if (!track_data )
3601
+ return ;
3602
+
3603
+ if (!track_data -> updated )
3604
+ return ;
3605
+
3606
+ action = snapshot_action (hist_data );
3607
+ if (!action )
3608
+ return ;
3609
+
3610
+ seq_puts (m , "\nSnapshot taken (see tracing/snapshot). Details:\n" );
3611
+ seq_printf (m , "\ttriggering value { %s(%s) }: %10llu" ,
3612
+ action -> handler == HANDLER_ONMAX ? "onmax" : "onchange" ,
3613
+ action -> track_data .var_str , track_data -> track_val );
3614
+
3615
+ seq_puts (m , "\ttriggered by event with key: " );
3616
+ hist_trigger_print_key (m , hist_data , track_data -> key , & track_data -> elt );
3617
+ seq_putc (m , '\n' );
3618
+ }
3619
+ #else
3620
+ static bool cond_snapshot_update (struct trace_array * tr , void * cond_data )
3621
+ {
3622
+ return false;
3623
+ }
3624
+ static void save_track_data_snapshot (struct hist_trigger_data * hist_data ,
3625
+ struct tracing_map_elt * elt , void * rec ,
3626
+ struct ring_buffer_event * rbe , void * key ,
3627
+ struct action_data * data ,
3628
+ u64 * var_ref_vals ) {}
3629
+ static void track_data_snapshot_print (struct seq_file * m ,
3630
+ struct hist_trigger_data * hist_data ) {}
3631
+ #endif /* CONFIG_TRACER_SNAPSHOT */
3632
+
3455
3633
static void track_data_print (struct seq_file * m ,
3456
3634
struct hist_trigger_data * hist_data ,
3457
3635
struct tracing_map_elt * elt ,
@@ -3463,6 +3641,9 @@ static void track_data_print(struct seq_file *m,
3463
3641
if (data -> handler == HANDLER_ONMAX )
3464
3642
seq_printf (m , "\n\tmax: %10llu" , track_val );
3465
3643
3644
+ if (data -> action == ACTION_SNAPSHOT )
3645
+ return ;
3646
+
3466
3647
for (i = 0 ; i < hist_data -> n_save_vars ; i ++ ) {
3467
3648
struct hist_field * save_val = hist_data -> save_vars [i ]-> val ;
3468
3649
struct hist_field * save_var = hist_data -> save_vars [i ]-> var ;
@@ -3513,9 +3694,21 @@ static void action_data_destroy(struct action_data *data)
3513
3694
static void track_data_destroy (struct hist_trigger_data * hist_data ,
3514
3695
struct action_data * data )
3515
3696
{
3697
+ struct trace_event_file * file = hist_data -> event_file ;
3698
+
3516
3699
destroy_hist_field (data -> track_data .track_var , 0 );
3517
3700
destroy_hist_field (data -> track_data .var_ref , 0 );
3518
3701
3702
+ if (data -> action == ACTION_SNAPSHOT ) {
3703
+ struct track_data * track_data ;
3704
+
3705
+ track_data = tracing_cond_snapshot_data (file -> tr );
3706
+ if (track_data && track_data -> hist_data == hist_data ) {
3707
+ tracing_snapshot_cond_disable (file -> tr );
3708
+ track_data_free (track_data );
3709
+ }
3710
+ }
3711
+
3519
3712
kfree (data -> track_data .var_str );
3520
3713
3521
3714
action_data_destroy (data );
@@ -3646,6 +3839,26 @@ static int action_parse(char *str, struct action_data *data,
3646
3839
data -> track_data .save_data = save_track_data_vars ;
3647
3840
data -> fn = ontrack_action ;
3648
3841
data -> action = ACTION_SAVE ;
3842
+ } else if (str_has_prefix (action_name , "snapshot" )) {
3843
+ char * params = strsep (& str , ")" );
3844
+
3845
+ if (!str ) {
3846
+ hist_err ("action parsing: No closing paren found: %s" , params );
3847
+ ret = - EINVAL ;
3848
+ goto out ;
3849
+ }
3850
+
3851
+ if (handler == HANDLER_ONMAX )
3852
+ data -> track_data .check_val = check_track_val_max ;
3853
+ else {
3854
+ hist_err ("action parsing: Handler doesn't support action: " , action_name );
3855
+ ret = - EINVAL ;
3856
+ goto out ;
3857
+ }
3858
+
3859
+ data -> track_data .save_data = save_track_data_snapshot ;
3860
+ data -> fn = ontrack_action ;
3861
+ data -> action = ACTION_SNAPSHOT ;
3649
3862
} else {
3650
3863
char * params = strsep (& str , ")" );
3651
3864
@@ -3942,6 +4155,8 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
3942
4155
static int action_create (struct hist_trigger_data * hist_data ,
3943
4156
struct action_data * data )
3944
4157
{
4158
+ struct trace_event_file * file = hist_data -> event_file ;
4159
+ struct track_data * track_data ;
3945
4160
struct field_var * field_var ;
3946
4161
unsigned int i ;
3947
4162
char * param ;
@@ -3950,6 +4165,21 @@ static int action_create(struct hist_trigger_data *hist_data,
3950
4165
if (data -> action == ACTION_TRACE )
3951
4166
return trace_action_create (hist_data , data );
3952
4167
4168
+ if (data -> action == ACTION_SNAPSHOT ) {
4169
+ track_data = track_data_alloc (hist_data -> key_size , data , hist_data );
4170
+ if (IS_ERR (track_data )) {
4171
+ ret = PTR_ERR (track_data );
4172
+ goto out ;
4173
+ }
4174
+
4175
+ ret = tracing_snapshot_cond_enable (file -> tr , track_data ,
4176
+ cond_snapshot_update );
4177
+ if (ret )
4178
+ track_data_free (track_data );
4179
+
4180
+ goto out ;
4181
+ }
4182
+
3953
4183
if (data -> action == ACTION_SAVE ) {
3954
4184
if (hist_data -> n_save_vars ) {
3955
4185
ret = - EEXIST ;
@@ -4552,6 +4782,9 @@ static void print_actions(struct seq_file *m,
4552
4782
for (i = 0 ; i < hist_data -> n_actions ; i ++ ) {
4553
4783
struct action_data * data = hist_data -> actions [i ];
4554
4784
4785
+ if (data -> action == ACTION_SNAPSHOT )
4786
+ continue ;
4787
+
4555
4788
if (data -> handler == HANDLER_ONMAX )
4556
4789
track_data_print (m , hist_data , elt , data );
4557
4790
}
@@ -4946,10 +5179,10 @@ static void hist_trigger_stacktrace_print(struct seq_file *m,
4946
5179
}
4947
5180
}
4948
5181
4949
- static void
4950
- hist_trigger_entry_print ( struct seq_file * m ,
4951
- struct hist_trigger_data * hist_data , void * key ,
4952
- struct tracing_map_elt * elt )
5182
+ static void hist_trigger_print_key ( struct seq_file * m ,
5183
+ struct hist_trigger_data * hist_data ,
5184
+ void * key ,
5185
+ struct tracing_map_elt * elt )
4953
5186
{
4954
5187
struct hist_field * key_field ;
4955
5188
char str [KSYM_SYMBOL_LEN ];
@@ -5025,6 +5258,17 @@ hist_trigger_entry_print(struct seq_file *m,
5025
5258
seq_puts (m , " " );
5026
5259
5027
5260
seq_puts (m , "}" );
5261
+ }
5262
+
5263
+ static void hist_trigger_entry_print (struct seq_file * m ,
5264
+ struct hist_trigger_data * hist_data ,
5265
+ void * key ,
5266
+ struct tracing_map_elt * elt )
5267
+ {
5268
+ const char * field_name ;
5269
+ unsigned int i ;
5270
+
5271
+ hist_trigger_print_key (m , hist_data , key , elt );
5028
5272
5029
5273
seq_printf (m , " hitcount: %10llu" ,
5030
5274
tracing_map_read_sum (elt , HITCOUNT_IDX ));
@@ -5091,6 +5335,8 @@ static void hist_trigger_show(struct seq_file *m,
5091
5335
if (n_entries < 0 )
5092
5336
n_entries = 0 ;
5093
5337
5338
+ track_data_snapshot_print (m , hist_data );
5339
+
5094
5340
seq_printf (m , "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n" ,
5095
5341
(u64 )atomic64_read (& hist_data -> map -> hits ),
5096
5342
n_entries , (u64 )atomic64_read (& hist_data -> map -> drops ));
0 commit comments