Skip to content

Commit

Permalink
blktrace: Send BLK_TN_PROCESS events to all running traces
Browse files Browse the repository at this point in the history
Currently each task sends BLK_TN_PROCESS event to the first traced
device it interacts with after a new trace is started. When there are
several traced devices and the task accesses more devices, this logic
can result in BLK_TN_PROCESS being sent several times to some devices
while it is never sent to other devices. Thus blkparse doesn't display
command name when parsing some blktrace files.

Fix the problem by sending BLK_TN_PROCESS event to all traced devices
when a task interacts with any of them.

Signed-off-by: Jan Kara <[email protected]>
Review-by: Jeff Moyer <[email protected]>
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
jankara authored and axboe committed Nov 8, 2013
1 parent 5e01dc7 commit a404d55
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 6 deletions.
2 changes: 2 additions & 0 deletions include/linux/blktrace_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <linux/relay.h>
#include <linux/compat.h>
#include <uapi/linux/blktrace_api.h>
#include <linux/list.h>

#if defined(CONFIG_BLK_DEV_IO_TRACE)

Expand All @@ -23,6 +24,7 @@ struct blk_trace {
struct dentry *dir;
struct dentry *dropped_file;
struct dentry *msg_file;
struct list_head running_list;
atomic_t dropped;
};

Expand Down
33 changes: 27 additions & 6 deletions kernel/trace/blktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/export.h>
#include <linux/time.h>
#include <linux/uaccess.h>
#include <linux/list.h>

#include <trace/events/block.h>

Expand All @@ -38,6 +39,9 @@ static unsigned int blktrace_seq __read_mostly = 1;
static struct trace_array *blk_tr;
static bool blk_tracer_enabled __read_mostly;

static LIST_HEAD(running_trace_list);
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(running_trace_lock);

/* Select an alternative, minimalistic output than the original one */
#define TRACE_BLK_OPT_CLASSIC 0x1

Expand Down Expand Up @@ -107,10 +111,18 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action,
* Send out a notify for this process, if we haven't done so since a trace
* started
*/
static void trace_note_tsk(struct blk_trace *bt, struct task_struct *tsk)
static void trace_note_tsk(struct task_struct *tsk)
{
unsigned long flags;
struct blk_trace *bt;

tsk->btrace_seq = blktrace_seq;
trace_note(bt, tsk->pid, BLK_TN_PROCESS, tsk->comm, sizeof(tsk->comm));
spin_lock_irqsave(&running_trace_lock, flags);
list_for_each_entry(bt, &running_trace_list, running_list) {
trace_note(bt, tsk->pid, BLK_TN_PROCESS, tsk->comm,
sizeof(tsk->comm));
}
spin_unlock_irqrestore(&running_trace_lock, flags);
}

static void trace_note_time(struct blk_trace *bt)
Expand Down Expand Up @@ -229,16 +241,15 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
goto record_it;
}

if (unlikely(tsk->btrace_seq != blktrace_seq))
trace_note_tsk(tsk);

/*
* A word about the locking here - we disable interrupts to reserve
* some space in the relay per-cpu buffer, to prevent an irq
* from coming in and stepping on our toes.
*/
local_irq_save(flags);

if (unlikely(tsk->btrace_seq != blktrace_seq))
trace_note_tsk(bt, tsk);

t = relay_reserve(bt->rchan, sizeof(*t) + pdu_len);
if (t) {
sequence = per_cpu_ptr(bt->sequence, cpu);
Expand Down Expand Up @@ -477,6 +488,7 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
bt->dir = dir;
bt->dev = dev;
atomic_set(&bt->dropped, 0);
INIT_LIST_HEAD(&bt->running_list);

ret = -EIO;
bt->dropped_file = debugfs_create_file("dropped", 0444, dir, bt,
Expand Down Expand Up @@ -601,13 +613,19 @@ int blk_trace_startstop(struct request_queue *q, int start)
blktrace_seq++;
smp_mb();
bt->trace_state = Blktrace_running;
spin_lock_irq(&running_trace_lock);
list_add(&bt->running_list, &running_trace_list);
spin_unlock_irq(&running_trace_lock);

trace_note_time(bt);
ret = 0;
}
} else {
if (bt->trace_state == Blktrace_running) {
bt->trace_state = Blktrace_stopped;
spin_lock_irq(&running_trace_lock);
list_del_init(&bt->running_list);
spin_unlock_irq(&running_trace_lock);
relay_flush(bt->rchan);
ret = 0;
}
Expand Down Expand Up @@ -1472,6 +1490,9 @@ static int blk_trace_remove_queue(struct request_queue *q)
if (atomic_dec_and_test(&blk_probes_ref))
blk_unregister_tracepoints();

spin_lock_irq(&running_trace_lock);
list_del(&bt->running_list);
spin_unlock_irq(&running_trace_lock);
blk_trace_free(bt);
return 0;
}
Expand Down

0 comments on commit a404d55

Please sign in to comment.