@@ -894,7 +894,7 @@ int __trace_bputs(unsigned long ip, const char *str)
894
894
EXPORT_SYMBOL_GPL (__trace_bputs );
895
895
896
896
#ifdef CONFIG_TRACER_SNAPSHOT
897
- void tracing_snapshot_instance (struct trace_array * tr )
897
+ void tracing_snapshot_instance_cond (struct trace_array * tr , void * cond_data )
898
898
{
899
899
struct tracer * tracer = tr -> current_trace ;
900
900
unsigned long flags ;
@@ -920,10 +920,15 @@ void tracing_snapshot_instance(struct trace_array *tr)
920
920
}
921
921
922
922
local_irq_save (flags );
923
- update_max_tr (tr , current , smp_processor_id ());
923
+ update_max_tr (tr , current , smp_processor_id (), cond_data );
924
924
local_irq_restore (flags );
925
925
}
926
926
927
+ void tracing_snapshot_instance (struct trace_array * tr )
928
+ {
929
+ tracing_snapshot_instance_cond (tr , NULL );
930
+ }
931
+
927
932
/**
928
933
* tracing_snapshot - take a snapshot of the current buffer.
929
934
*
@@ -946,6 +951,54 @@ void tracing_snapshot(void)
946
951
}
947
952
EXPORT_SYMBOL_GPL (tracing_snapshot );
948
953
954
+ /**
955
+ * tracing_snapshot_cond - conditionally take a snapshot of the current buffer.
956
+ * @tr: The tracing instance to snapshot
957
+ * @cond_data: The data to be tested conditionally, and possibly saved
958
+ *
959
+ * This is the same as tracing_snapshot() except that the snapshot is
960
+ * conditional - the snapshot will only happen if the
961
+ * cond_snapshot.update() implementation receiving the cond_data
962
+ * returns true, which means that the trace array's cond_snapshot
963
+ * update() operation used the cond_data to determine whether the
964
+ * snapshot should be taken, and if it was, presumably saved it along
965
+ * with the snapshot.
966
+ */
967
+ void tracing_snapshot_cond (struct trace_array * tr , void * cond_data )
968
+ {
969
+ tracing_snapshot_instance_cond (tr , cond_data );
970
+ }
971
+ EXPORT_SYMBOL_GPL (tracing_snapshot_cond );
972
+
973
+ /**
974
+ * tracing_snapshot_cond_data - get the user data associated with a snapshot
975
+ * @tr: The tracing instance
976
+ *
977
+ * When the user enables a conditional snapshot using
978
+ * tracing_snapshot_cond_enable(), the user-defined cond_data is saved
979
+ * with the snapshot. This accessor is used to retrieve it.
980
+ *
981
+ * Should not be called from cond_snapshot.update(), since it takes
982
+ * the tr->max_lock lock, which the code calling
983
+ * cond_snapshot.update() has already done.
984
+ *
985
+ * Returns the cond_data associated with the trace array's snapshot.
986
+ */
987
+ void * tracing_cond_snapshot_data (struct trace_array * tr )
988
+ {
989
+ void * cond_data = NULL ;
990
+
991
+ arch_spin_lock (& tr -> max_lock );
992
+
993
+ if (tr -> cond_snapshot )
994
+ cond_data = tr -> cond_snapshot -> cond_data ;
995
+
996
+ arch_spin_unlock (& tr -> max_lock );
997
+
998
+ return cond_data ;
999
+ }
1000
+ EXPORT_SYMBOL_GPL (tracing_cond_snapshot_data );
1001
+
949
1002
static int resize_buffer_duplicate_size (struct trace_buffer * trace_buf ,
950
1003
struct trace_buffer * size_buf , int cpu_id );
951
1004
static void set_buffer_entries (struct trace_buffer * buf , unsigned long val );
@@ -1025,12 +1078,103 @@ void tracing_snapshot_alloc(void)
1025
1078
tracing_snapshot ();
1026
1079
}
1027
1080
EXPORT_SYMBOL_GPL (tracing_snapshot_alloc );
1081
+
1082
+ /**
1083
+ * tracing_snapshot_cond_enable - enable conditional snapshot for an instance
1084
+ * @tr: The tracing instance
1085
+ * @cond_data: User data to associate with the snapshot
1086
+ * @update: Implementation of the cond_snapshot update function
1087
+ *
1088
+ * Check whether the conditional snapshot for the given instance has
1089
+ * already been enabled, or if the current tracer is already using a
1090
+ * snapshot; if so, return -EBUSY, else create a cond_snapshot and
1091
+ * save the cond_data and update function inside.
1092
+ *
1093
+ * Returns 0 if successful, error otherwise.
1094
+ */
1095
+ int tracing_snapshot_cond_enable (struct trace_array * tr , void * cond_data ,
1096
+ cond_update_fn_t update )
1097
+ {
1098
+ struct cond_snapshot * cond_snapshot ;
1099
+ int ret = 0 ;
1100
+
1101
+ cond_snapshot = kzalloc (sizeof (* cond_snapshot ), GFP_KERNEL );
1102
+ if (!cond_snapshot )
1103
+ return - ENOMEM ;
1104
+
1105
+ cond_snapshot -> cond_data = cond_data ;
1106
+ cond_snapshot -> update = update ;
1107
+
1108
+ mutex_lock (& trace_types_lock );
1109
+
1110
+ ret = tracing_alloc_snapshot_instance (tr );
1111
+ if (ret )
1112
+ goto fail_unlock ;
1113
+
1114
+ if (tr -> current_trace -> use_max_tr ) {
1115
+ ret = - EBUSY ;
1116
+ goto fail_unlock ;
1117
+ }
1118
+
1119
+ if (tr -> cond_snapshot ) {
1120
+ ret = - EBUSY ;
1121
+ goto fail_unlock ;
1122
+ }
1123
+
1124
+ arch_spin_lock (& tr -> max_lock );
1125
+ tr -> cond_snapshot = cond_snapshot ;
1126
+ arch_spin_unlock (& tr -> max_lock );
1127
+
1128
+ mutex_unlock (& trace_types_lock );
1129
+
1130
+ return ret ;
1131
+
1132
+ fail_unlock :
1133
+ mutex_unlock (& trace_types_lock );
1134
+ kfree (cond_snapshot );
1135
+ return ret ;
1136
+ }
1137
+ EXPORT_SYMBOL_GPL (tracing_snapshot_cond_enable );
1138
+
1139
+ /**
1140
+ * tracing_snapshot_cond_disable - disable conditional snapshot for an instance
1141
+ * @tr: The tracing instance
1142
+ *
1143
+ * Check whether the conditional snapshot for the given instance is
1144
+ * enabled; if so, free the cond_snapshot associated with it,
1145
+ * otherwise return -EINVAL.
1146
+ *
1147
+ * Returns 0 if successful, error otherwise.
1148
+ */
1149
+ int tracing_snapshot_cond_disable (struct trace_array * tr )
1150
+ {
1151
+ int ret = 0 ;
1152
+
1153
+ arch_spin_lock (& tr -> max_lock );
1154
+
1155
+ if (!tr -> cond_snapshot )
1156
+ ret = - EINVAL ;
1157
+ else {
1158
+ kfree (tr -> cond_snapshot );
1159
+ tr -> cond_snapshot = NULL ;
1160
+ }
1161
+
1162
+ arch_spin_unlock (& tr -> max_lock );
1163
+
1164
+ return ret ;
1165
+ }
1166
+ EXPORT_SYMBOL_GPL (tracing_snapshot_cond_disable );
1028
1167
#else
1029
1168
void tracing_snapshot (void )
1030
1169
{
1031
1170
WARN_ONCE (1 , "Snapshot feature not enabled, but internal snapshot used" );
1032
1171
}
1033
1172
EXPORT_SYMBOL_GPL (tracing_snapshot );
1173
+ void tracing_snapshot_cond (struct trace_array * tr , void * cond_data )
1174
+ {
1175
+ WARN_ONCE (1 , "Snapshot feature not enabled, but internal conditional snapshot used" );
1176
+ }
1177
+ EXPORT_SYMBOL_GPL (tracing_snapshot_cond );
1034
1178
int tracing_alloc_snapshot (void )
1035
1179
{
1036
1180
WARN_ONCE (1 , "Snapshot feature not enabled, but snapshot allocation used" );
@@ -1043,6 +1187,21 @@ void tracing_snapshot_alloc(void)
1043
1187
tracing_snapshot ();
1044
1188
}
1045
1189
EXPORT_SYMBOL_GPL (tracing_snapshot_alloc );
1190
+ void * tracing_cond_snapshot_data (struct trace_array * tr )
1191
+ {
1192
+ return NULL ;
1193
+ }
1194
+ EXPORT_SYMBOL_GPL (tracing_cond_snapshot_data );
1195
+ int tracing_snapshot_cond_enable (struct trace_array * tr , void * cond_data , cond_update_fn_t update )
1196
+ {
1197
+ return - ENODEV ;
1198
+ }
1199
+ EXPORT_SYMBOL_GPL (tracing_snapshot_cond_enable );
1200
+ int tracing_snapshot_cond_disable (struct trace_array * tr )
1201
+ {
1202
+ return false;
1203
+ }
1204
+ EXPORT_SYMBOL_GPL (tracing_snapshot_cond_disable );
1046
1205
#endif /* CONFIG_TRACER_SNAPSHOT */
1047
1206
1048
1207
void tracer_tracing_off (struct trace_array * tr )
@@ -1354,12 +1513,14 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
1354
1513
* @tr: tracer
1355
1514
* @tsk: the task with the latency
1356
1515
* @cpu: The cpu that initiated the trace.
1516
+ * @cond_data: User data associated with a conditional snapshot
1357
1517
*
1358
1518
* Flip the buffers between the @tr and the max_tr and record information
1359
1519
* about which task was the cause of this latency.
1360
1520
*/
1361
1521
void
1362
- update_max_tr (struct trace_array * tr , struct task_struct * tsk , int cpu )
1522
+ update_max_tr (struct trace_array * tr , struct task_struct * tsk , int cpu ,
1523
+ void * cond_data )
1363
1524
{
1364
1525
if (tr -> stop_count )
1365
1526
return ;
@@ -1380,9 +1541,15 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
1380
1541
else
1381
1542
ring_buffer_record_off (tr -> max_buffer .buffer );
1382
1543
1544
+ #ifdef CONFIG_TRACER_SNAPSHOT
1545
+ if (tr -> cond_snapshot && !tr -> cond_snapshot -> update (tr , cond_data ))
1546
+ goto out_unlock ;
1547
+ #endif
1383
1548
swap (tr -> trace_buffer .buffer , tr -> max_buffer .buffer );
1384
1549
1385
1550
__update_max_tr (tr , tsk , cpu );
1551
+
1552
+ out_unlock :
1386
1553
arch_spin_unlock (& tr -> max_lock );
1387
1554
}
1388
1555
@@ -5396,6 +5563,16 @@ static int tracing_set_tracer(struct trace_array *tr, const char *buf)
5396
5563
if (t == tr -> current_trace )
5397
5564
goto out ;
5398
5565
5566
+ #ifdef CONFIG_TRACER_SNAPSHOT
5567
+ if (t -> use_max_tr ) {
5568
+ arch_spin_lock (& tr -> max_lock );
5569
+ if (tr -> cond_snapshot )
5570
+ ret = - EBUSY ;
5571
+ arch_spin_unlock (& tr -> max_lock );
5572
+ if (ret )
5573
+ goto out ;
5574
+ }
5575
+ #endif
5399
5576
/* Some tracers won't work on kernel command line */
5400
5577
if (system_state < SYSTEM_RUNNING && t -> noboot ) {
5401
5578
pr_warn ("Tracer '%s' is not allowed on command line, ignored\n" ,
@@ -6477,6 +6654,13 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
6477
6654
goto out ;
6478
6655
}
6479
6656
6657
+ arch_spin_lock (& tr -> max_lock );
6658
+ if (tr -> cond_snapshot )
6659
+ ret = - EBUSY ;
6660
+ arch_spin_unlock (& tr -> max_lock );
6661
+ if (ret )
6662
+ goto out ;
6663
+
6480
6664
switch (val ) {
6481
6665
case 0 :
6482
6666
if (iter -> cpu_file != RING_BUFFER_ALL_CPUS ) {
@@ -6502,7 +6686,7 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
6502
6686
local_irq_disable ();
6503
6687
/* Now, we're going to swap */
6504
6688
if (iter -> cpu_file == RING_BUFFER_ALL_CPUS )
6505
- update_max_tr (tr , current , smp_processor_id ());
6689
+ update_max_tr (tr , current , smp_processor_id (), NULL );
6506
6690
else
6507
6691
update_max_tr_single (tr , current , iter -> cpu_file );
6508
6692
local_irq_enable ();
0 commit comments