Skip to content

Commit ff89510

Browse files
committed
tracing: Save off entry when peeking at next entry
In order to have the iterator read the buffer even when it's still updating, it requires that the ring buffer iterator saves each event in a separate location outside the ring buffer such that its use is immutable. There's one use case that saves off the event returned from the ring buffer interator and calls it again to look at the next event, before going back to use the first event. As the ring buffer iterator will only have a single copy, this use case will no longer be supported. Instead, have the one use case create its own buffer to store the first event when looking at the next event. This way, when looking at the first event again, it wont be corrupted by the second read. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 8c77f0b commit ff89510

File tree

3 files changed

+47
-10
lines changed

3 files changed

+47
-10
lines changed

include/linux/trace_events.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ struct trace_iterator {
8585
struct mutex mutex;
8686
struct ring_buffer_iter **buffer_iter;
8787
unsigned long iter_flags;
88+
void *temp; /* temp holder */
89+
unsigned int temp_size;
8890

8991
/* trace_seq for __print_flags() and __print_symbolic() etc. */
9092
struct trace_seq tmp_seq;

kernel/trace/trace.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3466,7 +3466,31 @@ __find_next_entry(struct trace_iterator *iter, int *ent_cpu,
34663466
struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
34673467
int *ent_cpu, u64 *ent_ts)
34683468
{
3469-
return __find_next_entry(iter, ent_cpu, NULL, ent_ts);
3469+
/* __find_next_entry will reset ent_size */
3470+
int ent_size = iter->ent_size;
3471+
struct trace_entry *entry;
3472+
3473+
/*
3474+
* The __find_next_entry() may call peek_next_entry(), which may
3475+
* call ring_buffer_peek() that may make the contents of iter->ent
3476+
* undefined. Need to copy iter->ent now.
3477+
*/
3478+
if (iter->ent && iter->ent != iter->temp) {
3479+
if (!iter->temp || iter->temp_size < iter->ent_size) {
3480+
kfree(iter->temp);
3481+
iter->temp = kmalloc(iter->ent_size, GFP_KERNEL);
3482+
if (!iter->temp)
3483+
return NULL;
3484+
}
3485+
memcpy(iter->temp, iter->ent, iter->ent_size);
3486+
iter->temp_size = iter->ent_size;
3487+
iter->ent = iter->temp;
3488+
}
3489+
entry = __find_next_entry(iter, ent_cpu, NULL, ent_ts);
3490+
/* Put back the original ent_size */
3491+
iter->ent_size = ent_size;
3492+
3493+
return entry;
34703494
}
34713495

34723496
/* Find the next real entry, and increment the iterator to the next entry */
@@ -4197,6 +4221,18 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
41974221
if (!iter->buffer_iter)
41984222
goto release;
41994223

4224+
/*
4225+
* trace_find_next_entry() may need to save off iter->ent.
4226+
* It will place it into the iter->temp buffer. As most
4227+
* events are less than 128, allocate a buffer of that size.
4228+
* If one is greater, then trace_find_next_entry() will
4229+
* allocate a new buffer to adjust for the bigger iter->ent.
4230+
* It's not critical if it fails to get allocated here.
4231+
*/
4232+
iter->temp = kmalloc(128, GFP_KERNEL);
4233+
if (iter->temp)
4234+
iter->temp_size = 128;
4235+
42004236
/*
42014237
* We make a copy of the current tracer to avoid concurrent
42024238
* changes on it while we are reading.
@@ -4269,6 +4305,7 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
42694305
fail:
42704306
mutex_unlock(&trace_types_lock);
42714307
kfree(iter->trace);
4308+
kfree(iter->temp);
42724309
kfree(iter->buffer_iter);
42734310
release:
42744311
seq_release_private(inode, file);
@@ -4344,6 +4381,7 @@ static int tracing_release(struct inode *inode, struct file *file)
43444381

43454382
mutex_destroy(&iter->mutex);
43464383
free_cpumask_var(iter->started);
4384+
kfree(iter->temp);
43474385
kfree(iter->trace);
43484386
kfree(iter->buffer_iter);
43494387
seq_release_private(inode, file);

kernel/trace/trace_output.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -617,22 +617,19 @@ int trace_print_context(struct trace_iterator *iter)
617617

618618
int trace_print_lat_context(struct trace_iterator *iter)
619619
{
620+
struct trace_entry *entry, *next_entry;
620621
struct trace_array *tr = iter->tr;
621-
/* trace_find_next_entry will reset ent_size */
622-
int ent_size = iter->ent_size;
623622
struct trace_seq *s = &iter->seq;
624-
u64 next_ts;
625-
struct trace_entry *entry = iter->ent,
626-
*next_entry = trace_find_next_entry(iter, NULL,
627-
&next_ts);
628623
unsigned long verbose = (tr->trace_flags & TRACE_ITER_VERBOSE);
624+
u64 next_ts;
629625

630-
/* Restore the original ent_size */
631-
iter->ent_size = ent_size;
632-
626+
next_entry = trace_find_next_entry(iter, NULL, &next_ts);
633627
if (!next_entry)
634628
next_ts = iter->ts;
635629

630+
/* trace_find_next_entry() may change iter->ent */
631+
entry = iter->ent;
632+
636633
if (verbose) {
637634
char comm[TASK_COMM_LEN];
638635

0 commit comments

Comments
 (0)