diff options
Diffstat (limited to 'kernel/trace/blktrace.c')
| -rw-r--r-- | kernel/trace/blktrace.c | 225 | 
1 files changed, 114 insertions, 111 deletions
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 7b8ec028154..c1bd4ada2a0 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -23,8 +23,10 @@  #include <linux/mutex.h>  #include <linux/slab.h>  #include <linux/debugfs.h> +#include <linux/export.h>  #include <linux/time.h>  #include <linux/uaccess.h> +#include <linux/list.h>  #include <trace/events/block.h> @@ -37,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 @@ -71,7 +76,7 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action,  	bool blk_tracer = blk_tracer_enabled;  	if (blk_tracer) { -		buffer = blk_tr->buffer; +		buffer = blk_tr->trace_buffer.buffer;  		pc = preempt_count();  		event = trace_buffer_lock_reserve(buffer, TRACE_BLK,  						  sizeof(*t) + len, @@ -106,10 +111,18 @@ record_it:   * 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) @@ -138,8 +151,15 @@ void __trace_note_message(struct blk_trace *bt, const char *fmt, ...)  		     !blk_tracer_enabled))  		return; +	/* +	 * If the BLK_TC_NOTIFY action mask isn't set, don't send any note +	 * message to the trace. +	 */ +	if (!(bt->act_mask & BLK_TC_NOTIFY)) +		return; +  	local_irq_save(flags); -	buf = per_cpu_ptr(bt->msg_data, smp_processor_id()); +	buf = this_cpu_ptr(bt->msg_data);  	va_start(args, fmt);  	n = vscnprintf(buf, BLK_TN_MAX_MSG, fmt, args);  	va_end(args); @@ -199,6 +219,8 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,  	what |= MASK_TC_BIT(rw, RAHEAD);  	what |= MASK_TC_BIT(rw, META);  	what |= MASK_TC_BIT(rw, DISCARD); +	what |= MASK_TC_BIT(rw, FLUSH); +	what |= MASK_TC_BIT(rw, FUA);  	pid = tsk->pid;  	if (act_log_check(bt, what, sector, pid)) @@ -208,7 +230,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,  	if (blk_tracer) {  		tracing_record_cmdline(current); -		buffer = blk_tr->buffer; +		buffer = blk_tr->trace_buffer.buffer;  		pc = preempt_count();  		event = trace_buffer_lock_reserve(buffer, TRACE_BLK,  						  sizeof(*t) + pdu_len, @@ -219,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); @@ -301,13 +322,6 @@ int blk_trace_remove(struct request_queue *q)  }  EXPORT_SYMBOL_GPL(blk_trace_remove); -static int blk_dropped_open(struct inode *inode, struct file *filp) -{ -	filp->private_data = inode->i_private; - -	return 0; -} -  static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,  				size_t count, loff_t *ppos)  { @@ -321,18 +335,11 @@ static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,  static const struct file_operations blk_dropped_fops = {  	.owner =	THIS_MODULE, -	.open =		blk_dropped_open, +	.open =		simple_open,  	.read =		blk_dropped_read,  	.llseek =	default_llseek,  }; -static int blk_msg_open(struct inode *inode, struct file *filp) -{ -	filp->private_data = inode->i_private; - -	return 0; -} -  static ssize_t blk_msg_write(struct file *filp, const char __user *buffer,  				size_t count, loff_t *ppos)  { @@ -361,7 +368,7 @@ static ssize_t blk_msg_write(struct file *filp, const char __user *buffer,  static const struct file_operations blk_msg_fops = {  	.owner =	THIS_MODULE, -	.open =		blk_msg_open, +	.open =		simple_open,  	.write =	blk_msg_write,  	.llseek =	noop_llseek,  }; @@ -392,7 +399,7 @@ static int blk_remove_buf_file_callback(struct dentry *dentry)  static struct dentry *blk_create_buf_file_callback(const char *filename,  						   struct dentry *parent, -						   int mode, +						   umode_t mode,  						   struct rchan_buf *buf,  						   int *is_global)  { @@ -481,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, @@ -571,13 +579,12 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,  		.end_lba = cbuts.end_lba,  		.pid = cbuts.pid,  	}; -	memcpy(&buts.name, &cbuts.name, 32);  	ret = do_blk_trace_setup(q, name, dev, bdev, &buts);  	if (ret)  		return ret; -	if (copy_to_user(arg, &buts.name, 32)) { +	if (copy_to_user(arg, &buts.name, ARRAY_SIZE(buts.name))) {  		blk_trace_remove(q);  		return -EFAULT;  	} @@ -605,6 +612,9 @@ 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; @@ -612,6 +622,9 @@ int blk_trace_startstop(struct request_queue *q, int start)  	} 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;  		} @@ -689,6 +702,7 @@ void blk_trace_shutdown(struct request_queue *q)   * blk_add_trace_rq - Add a trace for a request oriented action   * @q:		queue the io is for   * @rq:		the source request + * @nr_bytes:	number of completed bytes   * @what:	the action   *   * Description: @@ -696,61 +710,55 @@ void blk_trace_shutdown(struct request_queue *q)   *   **/  static void blk_add_trace_rq(struct request_queue *q, struct request *rq, -				    u32 what) +			     unsigned int nr_bytes, u32 what)  {  	struct blk_trace *bt = q->blk_trace; -	int rw = rq->cmd_flags & 0x03;  	if (likely(!bt))  		return; -	if (rq->cmd_flags & REQ_DISCARD) -		rw |= REQ_DISCARD; - -	if (rq->cmd_flags & REQ_SECURE) -		rw |= REQ_SECURE; -  	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {  		what |= BLK_TC_ACT(BLK_TC_PC); -		__blk_add_trace(bt, 0, blk_rq_bytes(rq), rw, +		__blk_add_trace(bt, 0, nr_bytes, rq->cmd_flags,  				what, rq->errors, rq->cmd_len, rq->cmd);  	} else  {  		what |= BLK_TC_ACT(BLK_TC_FS); -		__blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), rw, -				what, rq->errors, 0, NULL); +		__blk_add_trace(bt, blk_rq_pos(rq), nr_bytes, +				rq->cmd_flags, what, rq->errors, 0, NULL);  	}  }  static void blk_add_trace_rq_abort(void *ignore,  				   struct request_queue *q, struct request *rq)  { -	blk_add_trace_rq(q, rq, BLK_TA_ABORT); +	blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_ABORT);  }  static void blk_add_trace_rq_insert(void *ignore,  				    struct request_queue *q, struct request *rq)  { -	blk_add_trace_rq(q, rq, BLK_TA_INSERT); +	blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_INSERT);  }  static void blk_add_trace_rq_issue(void *ignore,  				   struct request_queue *q, struct request *rq)  { -	blk_add_trace_rq(q, rq, BLK_TA_ISSUE); +	blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_ISSUE);  }  static void blk_add_trace_rq_requeue(void *ignore,  				     struct request_queue *q,  				     struct request *rq)  { -	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE); +	blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_REQUEUE);  }  static void blk_add_trace_rq_complete(void *ignore,  				      struct request_queue *q, -				      struct request *rq) +				      struct request *rq, +				      unsigned int nr_bytes)  { -	blk_add_trace_rq(q, rq, BLK_TA_COMPLETE); +	blk_add_trace_rq(q, rq, nr_bytes, BLK_TA_COMPLETE);  }  /** @@ -758,53 +766,60 @@ static void blk_add_trace_rq_complete(void *ignore,   * @q:		queue the io is for   * @bio:	the source bio   * @what:	the action + * @error:	error, if any   *   * Description:   *     Records an action against a bio. Will log the bio offset + size.   *   **/  static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, -				     u32 what) +			      u32 what, int error)  {  	struct blk_trace *bt = q->blk_trace;  	if (likely(!bt))  		return; -	__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, -			!bio_flagged(bio, BIO_UPTODATE), 0, NULL); +	if (!error && !bio_flagged(bio, BIO_UPTODATE)) +		error = EIO; + +	__blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, +			bio->bi_rw, what, error, 0, NULL);  }  static void blk_add_trace_bio_bounce(void *ignore,  				     struct request_queue *q, struct bio *bio)  { -	blk_add_trace_bio(q, bio, BLK_TA_BOUNCE); +	blk_add_trace_bio(q, bio, BLK_TA_BOUNCE, 0);  }  static void blk_add_trace_bio_complete(void *ignore, -				       struct request_queue *q, struct bio *bio) +				       struct request_queue *q, struct bio *bio, +				       int error)  { -	blk_add_trace_bio(q, bio, BLK_TA_COMPLETE); +	blk_add_trace_bio(q, bio, BLK_TA_COMPLETE, error);  }  static void blk_add_trace_bio_backmerge(void *ignore,  					struct request_queue *q, +					struct request *rq,  					struct bio *bio)  { -	blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE); +	blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE, 0);  }  static void blk_add_trace_bio_frontmerge(void *ignore,  					 struct request_queue *q, +					 struct request *rq,  					 struct bio *bio)  { -	blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE); +	blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE, 0);  }  static void blk_add_trace_bio_queue(void *ignore,  				    struct request_queue *q, struct bio *bio)  { -	blk_add_trace_bio(q, bio, BLK_TA_QUEUE); +	blk_add_trace_bio(q, bio, BLK_TA_QUEUE, 0);  }  static void blk_add_trace_getrq(void *ignore, @@ -812,7 +827,7 @@ static void blk_add_trace_getrq(void *ignore,  				struct bio *bio, int rw)  {  	if (bio) -		blk_add_trace_bio(q, bio, BLK_TA_GETRQ); +		blk_add_trace_bio(q, bio, BLK_TA_GETRQ, 0);  	else {  		struct blk_trace *bt = q->blk_trace; @@ -827,7 +842,7 @@ static void blk_add_trace_sleeprq(void *ignore,  				  struct bio *bio, int rw)  {  	if (bio) -		blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ); +		blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ, 0);  	else {  		struct blk_trace *bt = q->blk_trace; @@ -845,29 +860,21 @@ static void blk_add_trace_plug(void *ignore, struct request_queue *q)  		__blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL);  } -static void blk_add_trace_unplug_io(void *ignore, struct request_queue *q) +static void blk_add_trace_unplug(void *ignore, struct request_queue *q, +				    unsigned int depth, bool explicit)  {  	struct blk_trace *bt = q->blk_trace;  	if (bt) { -		unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE]; -		__be64 rpdu = cpu_to_be64(pdu); +		__be64 rpdu = cpu_to_be64(depth); +		u32 what; -		__blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_IO, 0, -				sizeof(rpdu), &rpdu); -	} -} - -static void blk_add_trace_unplug_timer(void *ignore, struct request_queue *q) -{ -	struct blk_trace *bt = q->blk_trace; - -	if (bt) { -		unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE]; -		__be64 rpdu = cpu_to_be64(pdu); +		if (explicit) +			what = BLK_TA_UNPLUG_IO; +		else +			what = BLK_TA_UNPLUG_TIMER; -		__blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_TIMER, 0, -				sizeof(rpdu), &rpdu); +		__blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu);  	}  } @@ -880,14 +887,15 @@ static void blk_add_trace_split(void *ignore,  	if (bt) {  		__be64 rpdu = cpu_to_be64(pdu); -		__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, -				BLK_TA_SPLIT, !bio_flagged(bio, BIO_UPTODATE), +		__blk_add_trace(bt, bio->bi_iter.bi_sector, +				bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_SPLIT, +				!bio_flagged(bio, BIO_UPTODATE),  				sizeof(rpdu), &rpdu);  	}  }  /** - * blk_add_trace_remap - Add a trace for a remap operation + * blk_add_trace_bio_remap - Add a trace for a bio-remap operation   * @ignore:	trace callback data parameter (not used)   * @q:		queue the io is for   * @bio:	the source bio @@ -899,9 +907,9 @@ static void blk_add_trace_split(void *ignore,   *     it spans a stripe (or similar). Add a trace for that action.   *   **/ -static void blk_add_trace_remap(void *ignore, -				struct request_queue *q, struct bio *bio, -				dev_t dev, sector_t from) +static void blk_add_trace_bio_remap(void *ignore, +				    struct request_queue *q, struct bio *bio, +				    dev_t dev, sector_t from)  {  	struct blk_trace *bt = q->blk_trace;  	struct blk_io_trace_remap r; @@ -913,9 +921,9 @@ static void blk_add_trace_remap(void *ignore,  	r.device_to   = cpu_to_be32(bio->bi_bdev->bd_dev);  	r.sector_from = cpu_to_be64(from); -	__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, -			BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), -			sizeof(r), &r); +	__blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, +			bio->bi_rw, BLK_TA_REMAP, +			!bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r);  }  /** @@ -1010,13 +1018,11 @@ static void blk_register_tracepoints(void)  	WARN_ON(ret);  	ret = register_trace_block_plug(blk_add_trace_plug, NULL);  	WARN_ON(ret); -	ret = register_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL); -	WARN_ON(ret); -	ret = register_trace_block_unplug_io(blk_add_trace_unplug_io, NULL); +	ret = register_trace_block_unplug(blk_add_trace_unplug, NULL);  	WARN_ON(ret);  	ret = register_trace_block_split(blk_add_trace_split, NULL);  	WARN_ON(ret); -	ret = register_trace_block_remap(blk_add_trace_remap, NULL); +	ret = register_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);  	WARN_ON(ret);  	ret = register_trace_block_rq_remap(blk_add_trace_rq_remap, NULL);  	WARN_ON(ret); @@ -1025,10 +1031,9 @@ static void blk_register_tracepoints(void)  static void blk_unregister_tracepoints(void)  {  	unregister_trace_block_rq_remap(blk_add_trace_rq_remap, NULL); -	unregister_trace_block_remap(blk_add_trace_remap, NULL); +	unregister_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);  	unregister_trace_block_split(blk_add_trace_split, NULL); -	unregister_trace_block_unplug_io(blk_add_trace_unplug_io, NULL); -	unregister_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL); +	unregister_trace_block_unplug(blk_add_trace_unplug, NULL);  	unregister_trace_block_plug(blk_add_trace_plug, NULL);  	unregister_trace_block_sleeprq(blk_add_trace_sleeprq, NULL);  	unregister_trace_block_getrq(blk_add_trace_getrq, NULL); @@ -1060,6 +1065,9 @@ static void fill_rwbs(char *rwbs, const struct blk_io_trace *t)  		goto out;  	} +	if (tc & BLK_TC_FLUSH) +		rwbs[i++] = 'F'; +  	if (tc & BLK_TC_DISCARD)  		rwbs[i++] = 'D';  	else if (tc & BLK_TC_WRITE) @@ -1069,10 +1077,10 @@ static void fill_rwbs(char *rwbs, const struct blk_io_trace *t)  	else  		rwbs[i++] = 'N'; +	if (tc & BLK_TC_FUA) +		rwbs[i++] = 'F';  	if (tc & BLK_TC_AHEAD)  		rwbs[i++] = 'A'; -	if (tc & BLK_TC_BARRIER) -		rwbs[i++] = 'B';  	if (tc & BLK_TC_SYNC)  		rwbs[i++] = 'S';  	if (tc & BLK_TC_META) @@ -1138,7 +1146,7 @@ typedef int (blk_log_action_t) (struct trace_iterator *iter, const char *act);  static int blk_log_action_classic(struct trace_iterator *iter, const char *act)  { -	char rwbs[6]; +	char rwbs[RWBS_LEN];  	unsigned long long ts  = iter->ts;  	unsigned long nsec_rem = do_div(ts, NSEC_PER_SEC);  	unsigned secs	       = (unsigned long)ts; @@ -1154,7 +1162,7 @@ static int blk_log_action_classic(struct trace_iterator *iter, const char *act)  static int blk_log_action(struct trace_iterator *iter, const char *act)  { -	char rwbs[6]; +	char rwbs[RWBS_LEN];  	const struct blk_io_trace *t = te_blk_io_trace(iter->ent);  	fill_rwbs(rwbs, t); @@ -1421,7 +1429,8 @@ static enum print_line_t blk_tracer_print_line(struct trace_iterator *iter)  	return print_one_line(iter, true);  } -static int blk_tracer_set_flag(u32 old_flags, u32 bit, int set) +static int +blk_tracer_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)  {  	/* don't output context-info for blk_classic output */  	if (bit == TRACE_BLK_OPT_CLASSIC) { @@ -1484,6 +1493,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;  } @@ -1567,7 +1579,7 @@ static const struct {  } mask_maps[] = {  	{ BLK_TC_READ,		"read"		},  	{ BLK_TC_WRITE,		"write"		}, -	{ BLK_TC_BARRIER,	"barrier"	}, +	{ BLK_TC_FLUSH,		"flush"		},  	{ BLK_TC_SYNC,		"sync"		},  	{ BLK_TC_QUEUE,		"queue"		},  	{ BLK_TC_REQUEUE,	"requeue"	}, @@ -1579,6 +1591,7 @@ static const struct {  	{ BLK_TC_META,		"meta"		},  	{ BLK_TC_DISCARD,	"discard"	},  	{ BLK_TC_DRV_DATA,	"drv_data"	}, +	{ BLK_TC_FUA,		"fua"		},  };  static int blk_trace_str2mask(const char *str) @@ -1794,6 +1807,9 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)  {  	int i = 0; +	if (rw & REQ_FLUSH) +		rwbs[i++] = 'F'; +  	if (rw & WRITE)  		rwbs[i++] = 'W';  	else if (rw & REQ_DISCARD) @@ -1803,6 +1819,8 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)  	else  		rwbs[i++] = 'N'; +	if (rw & REQ_FUA) +		rwbs[i++] = 'F';  	if (rw & REQ_RAHEAD)  		rwbs[i++] = 'A';  	if (rw & REQ_SYNC) @@ -1814,22 +1832,7 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)  	rwbs[i] = '\0';  } - -void blk_fill_rwbs_rq(char *rwbs, struct request *rq) -{ -	int rw = rq->cmd_flags & 0x03; -	int bytes; - -	if (rq->cmd_flags & REQ_DISCARD) -		rw |= REQ_DISCARD; - -	if (rq->cmd_flags & REQ_SECURE) -		rw |= REQ_SECURE; - -	bytes = blk_rq_bytes(rq); - -	blk_fill_rwbs(rwbs, rw, bytes); -} +EXPORT_SYMBOL_GPL(blk_fill_rwbs);  #endif /* CONFIG_EVENT_TRACING */  | 
