1#ifndef BLKTRACE_H
2#define BLKTRACE_H
3
4#include <linux/blkdev.h>
5#include <linux/relay.h>
6
7/*
8 * Trace categories
9 */
10enum blktrace_cat {
11	BLK_TC_READ	= 1 << 0,	/* reads */
12	BLK_TC_WRITE	= 1 << 1,	/* writes */
13	BLK_TC_BARRIER	= 1 << 2,	/* barrier */
14	BLK_TC_SYNC	= 1 << 3,	/* sync IO */
15	BLK_TC_QUEUE	= 1 << 4,	/* queueing/merging */
16	BLK_TC_REQUEUE	= 1 << 5,	/* requeueing */
17	BLK_TC_ISSUE	= 1 << 6,	/* issue */
18	BLK_TC_COMPLETE	= 1 << 7,	/* completions */
19	BLK_TC_FS	= 1 << 8,	/* fs requests */
20	BLK_TC_PC	= 1 << 9,	/* pc requests */
21	BLK_TC_NOTIFY	= 1 << 10,	/* special message */
22	BLK_TC_AHEAD	= 1 << 11,	/* readahead */
23	BLK_TC_META	= 1 << 12,	/* metadata */
24
25	BLK_TC_END	= 1 << 15,	/* only 16-bits, reminder */
26};
27
28#define BLK_TC_SHIFT		(16)
29#define BLK_TC_ACT(act)		((act) << BLK_TC_SHIFT)
30
31/*
32 * Basic trace actions
33 */
34enum blktrace_act {
35	__BLK_TA_QUEUE = 1,		/* queued */
36	__BLK_TA_BACKMERGE,		/* back merged to existing rq */
37	__BLK_TA_FRONTMERGE,		/* front merge to existing rq */
38	__BLK_TA_GETRQ,			/* allocated new request */
39	__BLK_TA_SLEEPRQ,		/* sleeping on rq allocation */
40	__BLK_TA_REQUEUE,		/* request requeued */
41	__BLK_TA_ISSUE,			/* sent to driver */
42	__BLK_TA_COMPLETE,		/* completed by driver */
43	__BLK_TA_PLUG,			/* queue was plugged */
44	__BLK_TA_UNPLUG_IO,		/* queue was unplugged by io */
45	__BLK_TA_UNPLUG_TIMER,		/* queue was unplugged by timer */
46	__BLK_TA_INSERT,		/* insert request */
47	__BLK_TA_SPLIT,			/* bio was split */
48	__BLK_TA_BOUNCE,		/* bio was bounced */
49	__BLK_TA_REMAP,			/* bio was remapped */
50};
51
52/*
53 * Notify events.
54 */
55enum blktrace_notify {
56	__BLK_TN_PROCESS = 0,		/* establish pid/name mapping */
57	__BLK_TN_TIMESTAMP,		/* include system clock */
58};
59
60
61/*
62 * Trace actions in full. Additionally, read or write is masked
63 */
64#define BLK_TA_QUEUE		(__BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_QUEUE))
65#define BLK_TA_BACKMERGE	(__BLK_TA_BACKMERGE | BLK_TC_ACT(BLK_TC_QUEUE))
66#define BLK_TA_FRONTMERGE	(__BLK_TA_FRONTMERGE | BLK_TC_ACT(BLK_TC_QUEUE))
67#define	BLK_TA_GETRQ		(__BLK_TA_GETRQ | BLK_TC_ACT(BLK_TC_QUEUE))
68#define	BLK_TA_SLEEPRQ		(__BLK_TA_SLEEPRQ | BLK_TC_ACT(BLK_TC_QUEUE))
69#define	BLK_TA_REQUEUE		(__BLK_TA_REQUEUE | BLK_TC_ACT(BLK_TC_REQUEUE))
70#define BLK_TA_ISSUE		(__BLK_TA_ISSUE | BLK_TC_ACT(BLK_TC_ISSUE))
71#define BLK_TA_COMPLETE		(__BLK_TA_COMPLETE| BLK_TC_ACT(BLK_TC_COMPLETE))
72#define BLK_TA_PLUG		(__BLK_TA_PLUG | BLK_TC_ACT(BLK_TC_QUEUE))
73#define BLK_TA_UNPLUG_IO	(__BLK_TA_UNPLUG_IO | BLK_TC_ACT(BLK_TC_QUEUE))
74#define BLK_TA_UNPLUG_TIMER	(__BLK_TA_UNPLUG_TIMER | BLK_TC_ACT(BLK_TC_QUEUE))
75#define BLK_TA_INSERT		(__BLK_TA_INSERT | BLK_TC_ACT(BLK_TC_QUEUE))
76#define BLK_TA_SPLIT		(__BLK_TA_SPLIT)
77#define BLK_TA_BOUNCE		(__BLK_TA_BOUNCE)
78#define BLK_TA_REMAP		(__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE))
79
80#define BLK_TN_PROCESS		(__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY))
81#define BLK_TN_TIMESTAMP	(__BLK_TN_TIMESTAMP | BLK_TC_ACT(BLK_TC_NOTIFY))
82
83#define BLK_IO_TRACE_MAGIC	0x65617400
84#define BLK_IO_TRACE_VERSION	0x07
85
86/*
87 * The trace itself
88 */
89struct blk_io_trace {
90	u32 magic;		/* MAGIC << 8 | version */
91	u32 sequence;		/* event number */
92	u64 time;		/* in microseconds */
93	u64 sector;		/* disk offset */
94	u32 bytes;		/* transfer length */
95	u32 action;		/* what happened */
96	u32 pid;		/* who did it */
97	u32 device;		/* device number */
98	u32 cpu;		/* on what cpu did it happen */
99	u16 error;		/* completion error */
100	u16 pdu_len;		/* length of data after this trace */
101};
102
103/*
104 * The remap event
105 */
106struct blk_io_trace_remap {
107	__be32 device;
108	u32 __pad;
109	__be64 sector;
110};
111
112enum {
113	Blktrace_setup = 1,
114	Blktrace_running,
115	Blktrace_stopped,
116};
117
118struct blk_trace {
119	int trace_state;
120	struct rchan *rchan;
121	unsigned long *sequence;
122	u16 act_mask;
123	u64 start_lba;
124	u64 end_lba;
125	u32 pid;
126	u32 dev;
127	struct dentry *dir;
128	struct dentry *dropped_file;
129	atomic_t dropped;
130};
131
132/*
133 * User setup structure passed with BLKTRACESTART
134 */
135struct blk_user_trace_setup {
136	char name[BDEVNAME_SIZE];	/* output */
137	u16 act_mask;			/* input */
138	u32 buf_size;			/* input */
139	u32 buf_nr;			/* input */
140	u64 start_lba;
141	u64 end_lba;
142	u32 pid;
143};
144
145#if defined(CONFIG_BLK_DEV_IO_TRACE)
146extern int blk_trace_ioctl(struct block_device *, unsigned, char __user *);
147extern void blk_trace_shutdown(request_queue_t *);
148extern void __blk_add_trace(struct blk_trace *, sector_t, int, int, u32, int, int, void *);
149
150/**
151 * blk_add_trace_rq - Add a trace for a request oriented action
152 * @q:		queue the io is for
153 * @rq:		the source request
154 * @what:	the action
155 *
156 * Description:
157 *     Records an action against a request. Will log the bio offset + size.
158 *
159 **/
160static inline void blk_add_trace_rq(struct request_queue *q, struct request *rq,
161				    u32 what)
162{
163	struct blk_trace *bt = q->blk_trace;
164	int rw = rq->cmd_flags & 0x03;
165
166	if (likely(!bt))
167		return;
168
169	if (blk_pc_request(rq)) {
170		what |= BLK_TC_ACT(BLK_TC_PC);
171		__blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors, sizeof(rq->cmd), rq->cmd);
172	} else  {
173		what |= BLK_TC_ACT(BLK_TC_FS);
174		__blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, rw, what, rq->errors, 0, NULL);
175	}
176}
177
178/**
179 * blk_add_trace_bio - Add a trace for a bio oriented action
180 * @q:		queue the io is for
181 * @bio:	the source bio
182 * @what:	the action
183 *
184 * Description:
185 *     Records an action against a bio. Will log the bio offset + size.
186 *
187 **/
188static inline void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
189				     u32 what)
190{
191	struct blk_trace *bt = q->blk_trace;
192
193	if (likely(!bt))
194		return;
195
196	__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, !bio_flagged(bio, BIO_UPTODATE), 0, NULL);
197}
198
199/**
200 * blk_add_trace_generic - Add a trace for a generic action
201 * @q:		queue the io is for
202 * @bio:	the source bio
203 * @rw:		the data direction
204 * @what:	the action
205 *
206 * Description:
207 *     Records a simple trace
208 *
209 **/
210static inline void blk_add_trace_generic(struct request_queue *q,
211					 struct bio *bio, int rw, u32 what)
212{
213	struct blk_trace *bt = q->blk_trace;
214
215	if (likely(!bt))
216		return;
217
218	if (bio)
219		blk_add_trace_bio(q, bio, what);
220	else
221		__blk_add_trace(bt, 0, 0, rw, what, 0, 0, NULL);
222}
223
224/**
225 * blk_add_trace_pdu_int - Add a trace for a bio with an integer payload
226 * @q:		queue the io is for
227 * @what:	the action
228 * @bio:	the source bio
229 * @pdu:	the integer payload
230 *
231 * Description:
232 *     Adds a trace with some integer payload. This might be an unplug
233 *     option given as the action, with the depth at unplug time given
234 *     as the payload
235 *
236 **/
237static inline void blk_add_trace_pdu_int(struct request_queue *q, u32 what,
238					 struct bio *bio, unsigned int pdu)
239{
240	struct blk_trace *bt = q->blk_trace;
241	__be64 rpdu = cpu_to_be64(pdu);
242
243	if (likely(!bt))
244		return;
245
246	if (bio)
247		__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, !bio_flagged(bio, BIO_UPTODATE), sizeof(rpdu), &rpdu);
248	else
249		__blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu);
250}
251
252/**
253 * blk_add_trace_remap - Add a trace for a remap operation
254 * @q:		queue the io is for
255 * @bio:	the source bio
256 * @dev:	target device
257 * @from:	source sector
258 * @to:		target sector
259 *
260 * Description:
261 *     Device mapper or raid target sometimes need to split a bio because
262 *     it spans a stripe (or similar). Add a trace for that action.
263 *
264 **/
265static inline void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
266				       dev_t dev, sector_t from, sector_t to)
267{
268	struct blk_trace *bt = q->blk_trace;
269	struct blk_io_trace_remap r;
270
271	if (likely(!bt))
272		return;
273
274	r.device = cpu_to_be32(dev);
275	r.sector = cpu_to_be64(to);
276
277	__blk_add_trace(bt, from, bio->bi_size, bio->bi_rw, BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r);
278}
279
280#else /* !CONFIG_BLK_DEV_IO_TRACE */
281#define blk_trace_ioctl(bdev, cmd, arg)		(-ENOTTY)
282#define blk_trace_shutdown(q)			do { } while (0)
283#define blk_add_trace_rq(q, rq, what)		do { } while (0)
284#define blk_add_trace_bio(q, rq, what)		do { } while (0)
285#define blk_add_trace_generic(q, rq, rw, what)	do { } while (0)
286#define blk_add_trace_pdu_int(q, what, bio, pdu)	do { } while (0)
287#define blk_add_trace_remap(q, bio, dev, f, t)	do {} while (0)
288#endif /* CONFIG_BLK_DEV_IO_TRACE */
289
290#endif
291