Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
4 : : *
5 : : */
6 : : #include <linux/kernel.h>
7 : : #include <linux/blkdev.h>
8 : : #include <linux/blktrace_api.h>
9 : : #include <linux/percpu.h>
10 : : #include <linux/init.h>
11 : : #include <linux/mutex.h>
12 : : #include <linux/slab.h>
13 : : #include <linux/debugfs.h>
14 : : #include <linux/export.h>
15 : : #include <linux/time.h>
16 : : #include <linux/uaccess.h>
17 : : #include <linux/list.h>
18 : : #include <linux/blk-cgroup.h>
19 : :
20 : : #include "../../block/blk.h"
21 : :
22 : : #include <trace/events/block.h>
23 : :
24 : : #include "trace_output.h"
25 : :
26 : : #ifdef CONFIG_BLK_DEV_IO_TRACE
27 : :
28 : : static unsigned int blktrace_seq __read_mostly = 1;
29 : :
30 : : static struct trace_array *blk_tr;
31 : : static bool blk_tracer_enabled __read_mostly;
32 : :
33 : : static LIST_HEAD(running_trace_list);
34 : : static __cacheline_aligned_in_smp DEFINE_SPINLOCK(running_trace_lock);
35 : :
36 : : /* Select an alternative, minimalistic output than the original one */
37 : : #define TRACE_BLK_OPT_CLASSIC 0x1
38 : : #define TRACE_BLK_OPT_CGROUP 0x2
39 : : #define TRACE_BLK_OPT_CGNAME 0x4
40 : :
41 : : static struct tracer_opt blk_tracer_opts[] = {
42 : : /* Default disable the minimalistic output */
43 : : { TRACER_OPT(blk_classic, TRACE_BLK_OPT_CLASSIC) },
44 : : #ifdef CONFIG_BLK_CGROUP
45 : : { TRACER_OPT(blk_cgroup, TRACE_BLK_OPT_CGROUP) },
46 : : { TRACER_OPT(blk_cgname, TRACE_BLK_OPT_CGNAME) },
47 : : #endif
48 : : { }
49 : : };
50 : :
51 : : static struct tracer_flags blk_tracer_flags = {
52 : : .val = 0,
53 : : .opts = blk_tracer_opts,
54 : : };
55 : :
56 : : /* Global reference count of probes */
57 : : static DEFINE_MUTEX(blk_probe_mutex);
58 : : static int blk_probes_ref;
59 : :
60 : : static void blk_register_tracepoints(void);
61 : : static void blk_unregister_tracepoints(void);
62 : :
63 : : /*
64 : : * Send out a notify message.
65 : : */
66 : : static void trace_note(struct blk_trace *bt, pid_t pid, int action,
67 : : const void *data, size_t len, u64 cgid)
68 : : {
69 : : struct blk_io_trace *t;
70 : : struct ring_buffer_event *event = NULL;
71 : : struct trace_buffer *buffer = NULL;
72 : : int pc = 0;
73 : : int cpu = smp_processor_id();
74 : : bool blk_tracer = blk_tracer_enabled;
75 : : ssize_t cgid_len = cgid ? sizeof(cgid) : 0;
76 : :
77 : : if (blk_tracer) {
78 : : buffer = blk_tr->array_buffer.buffer;
79 : : pc = preempt_count();
80 : : event = trace_buffer_lock_reserve(buffer, TRACE_BLK,
81 : : sizeof(*t) + len + cgid_len,
82 : : 0, pc);
83 : : if (!event)
84 : : return;
85 : : t = ring_buffer_event_data(event);
86 : : goto record_it;
87 : : }
88 : :
89 : : if (!bt->rchan)
90 : : return;
91 : :
92 : : t = relay_reserve(bt->rchan, sizeof(*t) + len + cgid_len);
93 : : if (t) {
94 : : t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION;
95 : : t->time = ktime_to_ns(ktime_get());
96 : : record_it:
97 : : t->device = bt->dev;
98 : : t->action = action | (cgid ? __BLK_TN_CGROUP : 0);
99 : : t->pid = pid;
100 : : t->cpu = cpu;
101 : : t->pdu_len = len + cgid_len;
102 : : if (cgid_len)
103 : : memcpy((void *)t + sizeof(*t), &cgid, cgid_len);
104 : : memcpy((void *) t + sizeof(*t) + cgid_len, data, len);
105 : :
106 : : if (blk_tracer)
107 : : trace_buffer_unlock_commit(blk_tr, buffer, event, 0, pc);
108 : : }
109 : : }
110 : :
111 : : /*
112 : : * Send out a notify for this process, if we haven't done so since a trace
113 : : * started
114 : : */
115 : 0 : static void trace_note_tsk(struct task_struct *tsk)
116 : : {
117 : 0 : unsigned long flags;
118 : 0 : struct blk_trace *bt;
119 : :
120 : 0 : tsk->btrace_seq = blktrace_seq;
121 : 0 : spin_lock_irqsave(&running_trace_lock, flags);
122 [ # # ]: 0 : list_for_each_entry(bt, &running_trace_list, running_list) {
123 : 0 : trace_note(bt, tsk->pid, BLK_TN_PROCESS, tsk->comm,
124 : : sizeof(tsk->comm), 0);
125 : : }
126 : 0 : spin_unlock_irqrestore(&running_trace_lock, flags);
127 : 0 : }
128 : :
129 : 0 : static void trace_note_time(struct blk_trace *bt)
130 : : {
131 : 0 : struct timespec64 now;
132 : 0 : unsigned long flags;
133 : 0 : u32 words[2];
134 : :
135 : : /* need to check user space to see if this breaks in y2038 or y2106 */
136 : 0 : ktime_get_real_ts64(&now);
137 : 0 : words[0] = (u32)now.tv_sec;
138 : 0 : words[1] = now.tv_nsec;
139 : :
140 : 0 : local_irq_save(flags);
141 : 0 : trace_note(bt, 0, BLK_TN_TIMESTAMP, words, sizeof(words), 0);
142 : 0 : local_irq_restore(flags);
143 : 0 : }
144 : :
145 : 0 : void __trace_note_message(struct blk_trace *bt, struct blkcg *blkcg,
146 : : const char *fmt, ...)
147 : : {
148 : 0 : int n;
149 : 0 : va_list args;
150 : 0 : unsigned long flags;
151 : 0 : char *buf;
152 : :
153 [ # # # # ]: 0 : if (unlikely(bt->trace_state != Blktrace_running &&
154 : : !blk_tracer_enabled))
155 : 0 : return;
156 : :
157 : : /*
158 : : * If the BLK_TC_NOTIFY action mask isn't set, don't send any note
159 : : * message to the trace.
160 : : */
161 [ # # ]: 0 : if (!(bt->act_mask & BLK_TC_NOTIFY))
162 : : return;
163 : :
164 : 0 : local_irq_save(flags);
165 : 0 : buf = this_cpu_ptr(bt->msg_data);
166 : 0 : va_start(args, fmt);
167 : 0 : n = vscnprintf(buf, BLK_TN_MAX_MSG, fmt, args);
168 : 0 : va_end(args);
169 : :
170 : 0 : if (!(blk_tracer_flags.val & TRACE_BLK_OPT_CGROUP))
171 : : blkcg = NULL;
172 : : #ifdef CONFIG_BLK_CGROUP
173 : : trace_note(bt, 0, BLK_TN_MESSAGE, buf, n,
174 : : blkcg ? cgroup_id(blkcg->css.cgroup) : 1);
175 : : #else
176 : 0 : trace_note(bt, 0, BLK_TN_MESSAGE, buf, n, 0);
177 : : #endif
178 : 0 : local_irq_restore(flags);
179 : : }
180 : : EXPORT_SYMBOL_GPL(__trace_note_message);
181 : :
182 : 0 : static int act_log_check(struct blk_trace *bt, u32 what, sector_t sector,
183 : : pid_t pid)
184 : : {
185 : 0 : if (((bt->act_mask << BLK_TC_SHIFT) & what) == 0)
186 : : return 1;
187 [ # # # # : 0 : if (sector && (sector < bt->start_lba || sector > bt->end_lba))
# # ]
188 : : return 1;
189 [ # # # # ]: 0 : if (bt->pid && pid != bt->pid)
190 : : return 1;
191 : :
192 : : return 0;
193 : : }
194 : :
195 : : /*
196 : : * Data direction bit lookup
197 : : */
198 : : static const u32 ddir_act[2] = { BLK_TC_ACT(BLK_TC_READ),
199 : : BLK_TC_ACT(BLK_TC_WRITE) };
200 : :
201 : : #define BLK_TC_RAHEAD BLK_TC_AHEAD
202 : : #define BLK_TC_PREFLUSH BLK_TC_FLUSH
203 : :
204 : : /* The ilog2() calls fall out because they're constant */
205 : : #define MASK_TC_BIT(rw, __name) ((rw & REQ_ ## __name) << \
206 : : (ilog2(BLK_TC_ ## __name) + BLK_TC_SHIFT - __REQ_ ## __name))
207 : :
208 : : /*
209 : : * The worker for the various blk_add_trace*() types. Fills out a
210 : : * blk_io_trace structure and places it in a per-cpu subbuffer.
211 : : */
212 : 0 : static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
213 : : int op, int op_flags, u32 what, int error, int pdu_len,
214 : : void *pdu_data, u64 cgid)
215 : : {
216 [ # # ]: 0 : struct task_struct *tsk = current;
217 : 0 : struct ring_buffer_event *event = NULL;
218 : 0 : struct trace_buffer *buffer = NULL;
219 : 0 : struct blk_io_trace *t;
220 : 0 : unsigned long flags = 0;
221 : 0 : unsigned long *sequence;
222 : 0 : pid_t pid;
223 : 0 : int cpu, pc = 0;
224 : 0 : bool blk_tracer = blk_tracer_enabled;
225 [ # # ]: 0 : ssize_t cgid_len = cgid ? sizeof(cgid) : 0;
226 : :
227 [ # # # # ]: 0 : if (unlikely(bt->trace_state != Blktrace_running && !blk_tracer))
228 : : return;
229 : :
230 [ # # ]: 0 : what |= ddir_act[op_is_write(op) ? WRITE : READ];
231 : 0 : what |= MASK_TC_BIT(op_flags, SYNC);
232 : 0 : what |= MASK_TC_BIT(op_flags, RAHEAD);
233 : 0 : what |= MASK_TC_BIT(op_flags, META);
234 : 0 : what |= MASK_TC_BIT(op_flags, PREFLUSH);
235 : 0 : what |= MASK_TC_BIT(op_flags, FUA);
236 [ # # ]: 0 : if (op == REQ_OP_DISCARD || op == REQ_OP_SECURE_ERASE)
237 : 0 : what |= BLK_TC_ACT(BLK_TC_DISCARD);
238 [ # # ]: 0 : if (op == REQ_OP_FLUSH)
239 : 0 : what |= BLK_TC_ACT(BLK_TC_FLUSH);
240 [ # # ]: 0 : if (cgid)
241 : 0 : what |= __BLK_TA_CGROUP;
242 : :
243 : 0 : pid = tsk->pid;
244 [ # # ]: 0 : if (act_log_check(bt, what, sector, pid))
245 : : return;
246 : 0 : cpu = raw_smp_processor_id();
247 : :
248 [ # # ]: 0 : if (blk_tracer) {
249 : 0 : tracing_record_cmdline(current);
250 : :
251 : 0 : buffer = blk_tr->array_buffer.buffer;
252 : 0 : pc = preempt_count();
253 : 0 : event = trace_buffer_lock_reserve(buffer, TRACE_BLK,
254 : 0 : sizeof(*t) + pdu_len + cgid_len,
255 : : 0, pc);
256 [ # # ]: 0 : if (!event)
257 : : return;
258 : 0 : t = ring_buffer_event_data(event);
259 : 0 : goto record_it;
260 : : }
261 : :
262 [ # # ]: 0 : if (unlikely(tsk->btrace_seq != blktrace_seq))
263 : 0 : trace_note_tsk(tsk);
264 : :
265 : : /*
266 : : * A word about the locking here - we disable interrupts to reserve
267 : : * some space in the relay per-cpu buffer, to prevent an irq
268 : : * from coming in and stepping on our toes.
269 : : */
270 : 0 : local_irq_save(flags);
271 : 0 : t = relay_reserve(bt->rchan, sizeof(*t) + pdu_len + cgid_len);
272 [ # # ]: 0 : if (t) {
273 : 0 : sequence = per_cpu_ptr(bt->sequence, cpu);
274 : :
275 : 0 : t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION;
276 : 0 : t->sequence = ++(*sequence);
277 : 0 : t->time = ktime_to_ns(ktime_get());
278 : 0 : record_it:
279 : : /*
280 : : * These two are not needed in ftrace as they are in the
281 : : * generic trace_entry, filled by tracing_generic_entry_update,
282 : : * but for the trace_event->bin() synthesizer benefit we do it
283 : : * here too.
284 : : */
285 : 0 : t->cpu = cpu;
286 : 0 : t->pid = pid;
287 : :
288 : 0 : t->sector = sector;
289 : 0 : t->bytes = bytes;
290 : 0 : t->action = what;
291 : 0 : t->device = bt->dev;
292 : 0 : t->error = error;
293 : 0 : t->pdu_len = pdu_len + cgid_len;
294 : :
295 [ # # ]: 0 : if (cgid_len)
296 : 0 : memcpy((void *)t + sizeof(*t), &cgid, cgid_len);
297 [ # # ]: 0 : if (pdu_len)
298 : 0 : memcpy((void *)t + sizeof(*t) + cgid_len, pdu_data, pdu_len);
299 : :
300 [ # # ]: 0 : if (blk_tracer) {
301 : 0 : trace_buffer_unlock_commit(blk_tr, buffer, event, 0, pc);
302 : 0 : return;
303 : : }
304 : : }
305 : :
306 : 0 : local_irq_restore(flags);
307 : : }
308 : :
309 : 0 : static void blk_trace_free(struct blk_trace *bt)
310 : : {
311 : 0 : debugfs_remove(bt->msg_file);
312 : 0 : debugfs_remove(bt->dropped_file);
313 : 0 : relay_close(bt->rchan);
314 : 0 : debugfs_remove(bt->dir);
315 : 0 : free_percpu(bt->sequence);
316 : 0 : free_percpu(bt->msg_data);
317 : 0 : kfree(bt);
318 : 0 : }
319 : :
320 : 0 : static void get_probe_ref(void)
321 : : {
322 : 0 : mutex_lock(&blk_probe_mutex);
323 [ # # ]: 0 : if (++blk_probes_ref == 1)
324 : 0 : blk_register_tracepoints();
325 : 0 : mutex_unlock(&blk_probe_mutex);
326 : 0 : }
327 : :
328 : 0 : static void put_probe_ref(void)
329 : : {
330 : 0 : mutex_lock(&blk_probe_mutex);
331 [ # # ]: 0 : if (!--blk_probes_ref)
332 : 0 : blk_unregister_tracepoints();
333 : 0 : mutex_unlock(&blk_probe_mutex);
334 : 0 : }
335 : :
336 : 0 : static void blk_trace_cleanup(struct blk_trace *bt)
337 : : {
338 : 0 : synchronize_rcu();
339 : 0 : blk_trace_free(bt);
340 : 0 : put_probe_ref();
341 : 0 : }
342 : :
343 : 0 : static int __blk_trace_remove(struct request_queue *q)
344 : : {
345 : 0 : struct blk_trace *bt;
346 : :
347 : 0 : bt = xchg(&q->blk_trace, NULL);
348 [ # # ]: 0 : if (!bt)
349 : : return -EINVAL;
350 : :
351 [ # # ]: 0 : if (bt->trace_state != Blktrace_running)
352 : 0 : blk_trace_cleanup(bt);
353 : :
354 : : return 0;
355 : : }
356 : :
357 : 0 : int blk_trace_remove(struct request_queue *q)
358 : : {
359 : 0 : int ret;
360 : :
361 : 0 : mutex_lock(&q->blk_trace_mutex);
362 : 0 : ret = __blk_trace_remove(q);
363 : 0 : mutex_unlock(&q->blk_trace_mutex);
364 : :
365 : 0 : return ret;
366 : : }
367 : : EXPORT_SYMBOL_GPL(blk_trace_remove);
368 : :
369 : 0 : static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,
370 : : size_t count, loff_t *ppos)
371 : : {
372 : 0 : struct blk_trace *bt = filp->private_data;
373 : 0 : char buf[16];
374 : :
375 : 0 : snprintf(buf, sizeof(buf), "%u\n", atomic_read(&bt->dropped));
376 : :
377 : 0 : return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
378 : : }
379 : :
380 : : static const struct file_operations blk_dropped_fops = {
381 : : .owner = THIS_MODULE,
382 : : .open = simple_open,
383 : : .read = blk_dropped_read,
384 : : .llseek = default_llseek,
385 : : };
386 : :
387 : 0 : static ssize_t blk_msg_write(struct file *filp, const char __user *buffer,
388 : : size_t count, loff_t *ppos)
389 : : {
390 : 0 : char *msg;
391 : 0 : struct blk_trace *bt;
392 : :
393 [ # # ]: 0 : if (count >= BLK_TN_MAX_MSG)
394 : : return -EINVAL;
395 : :
396 : 0 : msg = memdup_user_nul(buffer, count);
397 [ # # ]: 0 : if (IS_ERR(msg))
398 : 0 : return PTR_ERR(msg);
399 : :
400 : 0 : bt = filp->private_data;
401 : 0 : __trace_note_message(bt, NULL, "%s", msg);
402 : 0 : kfree(msg);
403 : :
404 : 0 : return count;
405 : : }
406 : :
407 : : static const struct file_operations blk_msg_fops = {
408 : : .owner = THIS_MODULE,
409 : : .open = simple_open,
410 : : .write = blk_msg_write,
411 : : .llseek = noop_llseek,
412 : : };
413 : :
414 : : /*
415 : : * Keep track of how many times we encountered a full subbuffer, to aid
416 : : * the user space app in telling how many lost events there were.
417 : : */
418 : 0 : static int blk_subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
419 : : void *prev_subbuf, size_t prev_padding)
420 : : {
421 : 0 : struct blk_trace *bt;
422 : :
423 [ # # ]: 0 : if (!relay_buf_full(buf))
424 : : return 1;
425 : :
426 : 0 : bt = buf->chan->private_data;
427 : 0 : atomic_inc(&bt->dropped);
428 : 0 : return 0;
429 : : }
430 : :
431 : 0 : static int blk_remove_buf_file_callback(struct dentry *dentry)
432 : : {
433 : 0 : debugfs_remove(dentry);
434 : :
435 : 0 : return 0;
436 : : }
437 : :
438 : 0 : static struct dentry *blk_create_buf_file_callback(const char *filename,
439 : : struct dentry *parent,
440 : : umode_t mode,
441 : : struct rchan_buf *buf,
442 : : int *is_global)
443 : : {
444 : 0 : return debugfs_create_file(filename, mode, parent, buf,
445 : : &relay_file_operations);
446 : : }
447 : :
448 : : static struct rchan_callbacks blk_relay_callbacks = {
449 : : .subbuf_start = blk_subbuf_start_callback,
450 : : .create_buf_file = blk_create_buf_file_callback,
451 : : .remove_buf_file = blk_remove_buf_file_callback,
452 : : };
453 : :
454 : 0 : static void blk_trace_setup_lba(struct blk_trace *bt,
455 : : struct block_device *bdev)
456 : : {
457 : 0 : struct hd_struct *part = NULL;
458 : :
459 : 0 : if (bdev)
460 : 0 : part = bdev->bd_part;
461 : :
462 [ # # # # ]: 0 : if (part) {
463 : 0 : bt->start_lba = part->start_sect;
464 : 0 : bt->end_lba = part->start_sect + part->nr_sects;
465 : : } else {
466 : 0 : bt->start_lba = 0;
467 : 0 : bt->end_lba = -1ULL;
468 : : }
469 : : }
470 : :
471 : : /*
472 : : * Setup everything required to start tracing
473 : : */
474 : 0 : static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
475 : : struct block_device *bdev,
476 : : struct blk_user_trace_setup *buts)
477 : : {
478 : 0 : struct blk_trace *bt = NULL;
479 : 0 : struct dentry *dir = NULL;
480 : 0 : int ret;
481 : :
482 [ # # # # ]: 0 : if (!buts->buf_size || !buts->buf_nr)
483 : : return -EINVAL;
484 : :
485 [ # # ]: 0 : if (!blk_debugfs_root)
486 : : return -ENOENT;
487 : :
488 : 0 : strncpy(buts->name, name, BLKTRACE_BDEV_SIZE);
489 : 0 : buts->name[BLKTRACE_BDEV_SIZE - 1] = '\0';
490 : :
491 : : /*
492 : : * some device names have larger paths - convert the slashes
493 : : * to underscores for this to work as expected
494 : : */
495 : 0 : strreplace(buts->name, '/', '_');
496 : :
497 : 0 : bt = kzalloc(sizeof(*bt), GFP_KERNEL);
498 [ # # ]: 0 : if (!bt)
499 : : return -ENOMEM;
500 : :
501 : 0 : ret = -ENOMEM;
502 : 0 : bt->sequence = alloc_percpu(unsigned long);
503 [ # # ]: 0 : if (!bt->sequence)
504 : 0 : goto err;
505 : :
506 : 0 : bt->msg_data = __alloc_percpu(BLK_TN_MAX_MSG, __alignof__(char));
507 [ # # ]: 0 : if (!bt->msg_data)
508 : 0 : goto err;
509 : :
510 : 0 : ret = -ENOENT;
511 : :
512 : 0 : dir = debugfs_lookup(buts->name, blk_debugfs_root);
513 [ # # ]: 0 : if (!dir)
514 : 0 : bt->dir = dir = debugfs_create_dir(buts->name, blk_debugfs_root);
515 : :
516 : 0 : bt->dev = dev;
517 : 0 : atomic_set(&bt->dropped, 0);
518 : 0 : INIT_LIST_HEAD(&bt->running_list);
519 : :
520 : 0 : ret = -EIO;
521 : 0 : bt->dropped_file = debugfs_create_file("dropped", 0444, dir, bt,
522 : : &blk_dropped_fops);
523 : :
524 : 0 : bt->msg_file = debugfs_create_file("msg", 0222, dir, bt, &blk_msg_fops);
525 : :
526 : 0 : bt->rchan = relay_open("trace", dir, buts->buf_size,
527 : 0 : buts->buf_nr, &blk_relay_callbacks, bt);
528 [ # # ]: 0 : if (!bt->rchan)
529 : 0 : goto err;
530 : :
531 : 0 : bt->act_mask = buts->act_mask;
532 [ # # ]: 0 : if (!bt->act_mask)
533 : 0 : bt->act_mask = (u16) -1;
534 : :
535 [ # # ]: 0 : blk_trace_setup_lba(bt, bdev);
536 : :
537 : : /* overwrite with user settings */
538 [ # # ]: 0 : if (buts->start_lba)
539 : 0 : bt->start_lba = buts->start_lba;
540 [ # # ]: 0 : if (buts->end_lba)
541 : 0 : bt->end_lba = buts->end_lba;
542 : :
543 : 0 : bt->pid = buts->pid;
544 : 0 : bt->trace_state = Blktrace_setup;
545 : :
546 : 0 : ret = -EBUSY;
547 [ # # ]: 0 : if (cmpxchg(&q->blk_trace, NULL, bt))
548 : 0 : goto err;
549 : :
550 : 0 : get_probe_ref();
551 : :
552 : 0 : ret = 0;
553 : 0 : err:
554 [ # # # # ]: 0 : if (dir && !bt->dir)
555 : 0 : dput(dir);
556 [ # # ]: 0 : if (ret)
557 : 0 : blk_trace_free(bt);
558 : : return ret;
559 : : }
560 : :
561 : 0 : static int __blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
562 : : struct block_device *bdev, char __user *arg)
563 : : {
564 : 0 : struct blk_user_trace_setup buts;
565 : 0 : int ret;
566 : :
567 : 0 : ret = copy_from_user(&buts, arg, sizeof(buts));
568 [ # # ]: 0 : if (ret)
569 : : return -EFAULT;
570 : :
571 : 0 : ret = do_blk_trace_setup(q, name, dev, bdev, &buts);
572 [ # # ]: 0 : if (ret)
573 : : return ret;
574 : :
575 [ # # ]: 0 : if (copy_to_user(arg, &buts, sizeof(buts))) {
576 : 0 : __blk_trace_remove(q);
577 : 0 : return -EFAULT;
578 : : }
579 : : return 0;
580 : : }
581 : :
582 : 0 : int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
583 : : struct block_device *bdev,
584 : : char __user *arg)
585 : : {
586 : 0 : int ret;
587 : :
588 : 0 : mutex_lock(&q->blk_trace_mutex);
589 : 0 : ret = __blk_trace_setup(q, name, dev, bdev, arg);
590 : 0 : mutex_unlock(&q->blk_trace_mutex);
591 : :
592 : 0 : return ret;
593 : : }
594 : : EXPORT_SYMBOL_GPL(blk_trace_setup);
595 : :
596 : : #if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
597 : 0 : static int compat_blk_trace_setup(struct request_queue *q, char *name,
598 : : dev_t dev, struct block_device *bdev,
599 : : char __user *arg)
600 : : {
601 : 0 : struct blk_user_trace_setup buts;
602 : 0 : struct compat_blk_user_trace_setup cbuts;
603 : 0 : int ret;
604 : :
605 [ # # ]: 0 : if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
606 : : return -EFAULT;
607 : :
608 : 0 : buts = (struct blk_user_trace_setup) {
609 : 0 : .act_mask = cbuts.act_mask,
610 : 0 : .buf_size = cbuts.buf_size,
611 : 0 : .buf_nr = cbuts.buf_nr,
612 : 0 : .start_lba = cbuts.start_lba,
613 : 0 : .end_lba = cbuts.end_lba,
614 : 0 : .pid = cbuts.pid,
615 : : };
616 : :
617 : 0 : ret = do_blk_trace_setup(q, name, dev, bdev, &buts);
618 [ # # ]: 0 : if (ret)
619 : : return ret;
620 : :
621 [ # # ]: 0 : if (copy_to_user(arg, &buts.name, ARRAY_SIZE(buts.name))) {
622 : 0 : __blk_trace_remove(q);
623 : 0 : return -EFAULT;
624 : : }
625 : :
626 : : return 0;
627 : : }
628 : : #endif
629 : :
630 : : static int __blk_trace_startstop(struct request_queue *q, int start)
631 : : {
632 : : int ret;
633 : : struct blk_trace *bt;
634 : :
635 : : bt = rcu_dereference_protected(q->blk_trace,
636 : : lockdep_is_held(&q->blk_trace_mutex));
637 : : if (bt == NULL)
638 : : return -EINVAL;
639 : :
640 : : /*
641 : : * For starting a trace, we can transition from a setup or stopped
642 : : * trace. For stopping a trace, the state must be running
643 : : */
644 : : ret = -EINVAL;
645 : : if (start) {
646 : : if (bt->trace_state == Blktrace_setup ||
647 : : bt->trace_state == Blktrace_stopped) {
648 : : blktrace_seq++;
649 : : smp_mb();
650 : : bt->trace_state = Blktrace_running;
651 : : spin_lock_irq(&running_trace_lock);
652 : : list_add(&bt->running_list, &running_trace_list);
653 : : spin_unlock_irq(&running_trace_lock);
654 : :
655 : : trace_note_time(bt);
656 : : ret = 0;
657 : : }
658 : : } else {
659 : : if (bt->trace_state == Blktrace_running) {
660 : : bt->trace_state = Blktrace_stopped;
661 : : spin_lock_irq(&running_trace_lock);
662 : : list_del_init(&bt->running_list);
663 : : spin_unlock_irq(&running_trace_lock);
664 : : relay_flush(bt->rchan);
665 : : ret = 0;
666 : : }
667 : : }
668 : :
669 : : return ret;
670 : : }
671 : :
672 : 0 : int blk_trace_startstop(struct request_queue *q, int start)
673 : : {
674 : 0 : int ret;
675 : :
676 : 0 : mutex_lock(&q->blk_trace_mutex);
677 : 0 : ret = __blk_trace_startstop(q, start);
678 : 0 : mutex_unlock(&q->blk_trace_mutex);
679 : :
680 : 0 : return ret;
681 : : }
682 : : EXPORT_SYMBOL_GPL(blk_trace_startstop);
683 : :
684 : : /*
685 : : * When reading or writing the blktrace sysfs files, the references to the
686 : : * opened sysfs or device files should prevent the underlying block device
687 : : * from being removed. So no further delete protection is really needed.
688 : : */
689 : :
690 : : /**
691 : : * blk_trace_ioctl: - handle the ioctls associated with tracing
692 : : * @bdev: the block device
693 : : * @cmd: the ioctl cmd
694 : : * @arg: the argument data, if any
695 : : *
696 : : **/
697 : 0 : int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
698 : : {
699 : 0 : struct request_queue *q;
700 : 0 : int ret, start = 0;
701 : 0 : char b[BDEVNAME_SIZE];
702 : :
703 [ # # ]: 0 : q = bdev_get_queue(bdev);
704 [ # # ]: 0 : if (!q)
705 : : return -ENXIO;
706 : :
707 : 0 : mutex_lock(&q->blk_trace_mutex);
708 : :
709 [ # # # # : 0 : switch (cmd) {
# # ]
710 : 0 : case BLKTRACESETUP:
711 : 0 : bdevname(bdev, b);
712 : 0 : ret = __blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
713 : 0 : break;
714 : : #if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
715 : 0 : case BLKTRACESETUP32:
716 : 0 : bdevname(bdev, b);
717 : 0 : ret = compat_blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
718 : 0 : break;
719 : : #endif
720 : 0 : case BLKTRACESTART:
721 : 0 : start = 1;
722 : : /* fall through */
723 : 0 : case BLKTRACESTOP:
724 : 0 : ret = __blk_trace_startstop(q, start);
725 : 0 : break;
726 : 0 : case BLKTRACETEARDOWN:
727 : 0 : ret = __blk_trace_remove(q);
728 : 0 : break;
729 : : default:
730 : : ret = -ENOTTY;
731 : : break;
732 : : }
733 : :
734 : 0 : mutex_unlock(&q->blk_trace_mutex);
735 : 0 : return ret;
736 : : }
737 : :
738 : : /**
739 : : * blk_trace_shutdown: - stop and cleanup trace structures
740 : : * @q: the request queue associated with the device
741 : : *
742 : : **/
743 : 0 : void blk_trace_shutdown(struct request_queue *q)
744 : : {
745 : 0 : mutex_lock(&q->blk_trace_mutex);
746 [ # # ]: 0 : if (rcu_dereference_protected(q->blk_trace,
747 : : lockdep_is_held(&q->blk_trace_mutex))) {
748 : 0 : __blk_trace_startstop(q, 0);
749 : 0 : __blk_trace_remove(q);
750 : : }
751 : :
752 : 0 : mutex_unlock(&q->blk_trace_mutex);
753 : 0 : }
754 : :
755 : : #ifdef CONFIG_BLK_CGROUP
756 : : static u64 blk_trace_bio_get_cgid(struct request_queue *q, struct bio *bio)
757 : : {
758 : : struct blk_trace *bt;
759 : :
760 : : /* We don't use the 'bt' value here except as an optimization... */
761 : : bt = rcu_dereference_protected(q->blk_trace, 1);
762 : : if (!bt || !(blk_tracer_flags.val & TRACE_BLK_OPT_CGROUP))
763 : : return 0;
764 : :
765 : : if (!bio->bi_blkg)
766 : : return 0;
767 : : return cgroup_id(bio_blkcg(bio)->css.cgroup);
768 : : }
769 : : #else
770 : 0 : u64 blk_trace_bio_get_cgid(struct request_queue *q, struct bio *bio)
771 : : {
772 : 0 : return 0;
773 : : }
774 : : #endif
775 : :
776 : : static u64
777 : 0 : blk_trace_request_get_cgid(struct request_queue *q, struct request *rq)
778 : : {
779 : 0 : if (!rq->bio)
780 : : return 0;
781 : : /* Use the first bio */
782 : : return blk_trace_bio_get_cgid(q, rq->bio);
783 : : }
784 : :
785 : : /*
786 : : * blktrace probes
787 : : */
788 : :
789 : : /**
790 : : * blk_add_trace_rq - Add a trace for a request oriented action
791 : : * @rq: the source request
792 : : * @error: return status to log
793 : : * @nr_bytes: number of completed bytes
794 : : * @what: the action
795 : : * @cgid: the cgroup info
796 : : *
797 : : * Description:
798 : : * Records an action against a request. Will log the bio offset + size.
799 : : *
800 : : **/
801 : 0 : static void blk_add_trace_rq(struct request *rq, int error,
802 : : unsigned int nr_bytes, u32 what, u64 cgid)
803 : : {
804 : 0 : struct blk_trace *bt;
805 : :
806 : 0 : rcu_read_lock();
807 [ # # ]: 0 : bt = rcu_dereference(rq->q->blk_trace);
808 [ # # ]: 0 : if (likely(!bt)) {
809 : 0 : rcu_read_unlock();
810 : 0 : return;
811 : : }
812 : :
813 [ # # # # ]: 0 : if (blk_rq_is_passthrough(rq))
814 : 0 : what |= BLK_TC_ACT(BLK_TC_PC);
815 : : else
816 : 0 : what |= BLK_TC_ACT(BLK_TC_FS);
817 : :
818 [ # # ]: 0 : __blk_add_trace(bt, blk_rq_trace_sector(rq), nr_bytes, req_op(rq),
819 : : rq->cmd_flags, what, error, 0, NULL, cgid);
820 : 0 : rcu_read_unlock();
821 : : }
822 : :
823 : 0 : static void blk_add_trace_rq_insert(void *ignore,
824 : : struct request_queue *q, struct request *rq)
825 : : {
826 : 0 : blk_add_trace_rq(rq, 0, blk_rq_bytes(rq), BLK_TA_INSERT,
827 : : blk_trace_request_get_cgid(q, rq));
828 : 0 : }
829 : :
830 : 0 : static void blk_add_trace_rq_issue(void *ignore,
831 : : struct request_queue *q, struct request *rq)
832 : : {
833 : 0 : blk_add_trace_rq(rq, 0, blk_rq_bytes(rq), BLK_TA_ISSUE,
834 : : blk_trace_request_get_cgid(q, rq));
835 : 0 : }
836 : :
837 : 0 : static void blk_add_trace_rq_requeue(void *ignore,
838 : : struct request_queue *q,
839 : : struct request *rq)
840 : : {
841 : 0 : blk_add_trace_rq(rq, 0, blk_rq_bytes(rq), BLK_TA_REQUEUE,
842 : : blk_trace_request_get_cgid(q, rq));
843 : 0 : }
844 : :
845 : 0 : static void blk_add_trace_rq_complete(void *ignore, struct request *rq,
846 : : int error, unsigned int nr_bytes)
847 : : {
848 : 0 : blk_add_trace_rq(rq, error, nr_bytes, BLK_TA_COMPLETE,
849 : : blk_trace_request_get_cgid(rq->q, rq));
850 : 0 : }
851 : :
852 : : /**
853 : : * blk_add_trace_bio - Add a trace for a bio oriented action
854 : : * @q: queue the io is for
855 : : * @bio: the source bio
856 : : * @what: the action
857 : : * @error: error, if any
858 : : *
859 : : * Description:
860 : : * Records an action against a bio. Will log the bio offset + size.
861 : : *
862 : : **/
863 : 0 : static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
864 : : u32 what, int error)
865 : : {
866 : 0 : struct blk_trace *bt;
867 : :
868 : 0 : rcu_read_lock();
869 [ # # ]: 0 : bt = rcu_dereference(q->blk_trace);
870 [ # # ]: 0 : if (likely(!bt)) {
871 : 0 : rcu_read_unlock();
872 : 0 : return;
873 : : }
874 : :
875 : 0 : __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
876 : 0 : bio_op(bio), bio->bi_opf, what, error, 0, NULL,
877 : : blk_trace_bio_get_cgid(q, bio));
878 : 0 : rcu_read_unlock();
879 : : }
880 : :
881 : 0 : static void blk_add_trace_bio_bounce(void *ignore,
882 : : struct request_queue *q, struct bio *bio)
883 : : {
884 : 0 : blk_add_trace_bio(q, bio, BLK_TA_BOUNCE, 0);
885 : 0 : }
886 : :
887 : 0 : static void blk_add_trace_bio_complete(void *ignore,
888 : : struct request_queue *q, struct bio *bio,
889 : : int error)
890 : : {
891 : 0 : blk_add_trace_bio(q, bio, BLK_TA_COMPLETE, error);
892 : 0 : }
893 : :
894 : 0 : static void blk_add_trace_bio_backmerge(void *ignore,
895 : : struct request_queue *q,
896 : : struct request *rq,
897 : : struct bio *bio)
898 : : {
899 : 0 : blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE, 0);
900 : 0 : }
901 : :
902 : 0 : static void blk_add_trace_bio_frontmerge(void *ignore,
903 : : struct request_queue *q,
904 : : struct request *rq,
905 : : struct bio *bio)
906 : : {
907 : 0 : blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE, 0);
908 : 0 : }
909 : :
910 : 0 : static void blk_add_trace_bio_queue(void *ignore,
911 : : struct request_queue *q, struct bio *bio)
912 : : {
913 : 0 : blk_add_trace_bio(q, bio, BLK_TA_QUEUE, 0);
914 : 0 : }
915 : :
916 : 0 : static void blk_add_trace_getrq(void *ignore,
917 : : struct request_queue *q,
918 : : struct bio *bio, int rw)
919 : : {
920 [ # # ]: 0 : if (bio)
921 : 0 : blk_add_trace_bio(q, bio, BLK_TA_GETRQ, 0);
922 : : else {
923 : 0 : struct blk_trace *bt;
924 : :
925 : 0 : rcu_read_lock();
926 [ # # ]: 0 : bt = rcu_dereference(q->blk_trace);
927 [ # # ]: 0 : if (bt)
928 : 0 : __blk_add_trace(bt, 0, 0, rw, 0, BLK_TA_GETRQ, 0, 0,
929 : : NULL, 0);
930 : 0 : rcu_read_unlock();
931 : : }
932 : 0 : }
933 : :
934 : :
935 : 0 : static void blk_add_trace_sleeprq(void *ignore,
936 : : struct request_queue *q,
937 : : struct bio *bio, int rw)
938 : : {
939 [ # # ]: 0 : if (bio)
940 : 0 : blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ, 0);
941 : : else {
942 : 0 : struct blk_trace *bt;
943 : :
944 : 0 : rcu_read_lock();
945 [ # # ]: 0 : bt = rcu_dereference(q->blk_trace);
946 [ # # ]: 0 : if (bt)
947 : 0 : __blk_add_trace(bt, 0, 0, rw, 0, BLK_TA_SLEEPRQ,
948 : : 0, 0, NULL, 0);
949 : 0 : rcu_read_unlock();
950 : : }
951 : 0 : }
952 : :
953 : 0 : static void blk_add_trace_plug(void *ignore, struct request_queue *q)
954 : : {
955 : 0 : struct blk_trace *bt;
956 : :
957 : 0 : rcu_read_lock();
958 [ # # ]: 0 : bt = rcu_dereference(q->blk_trace);
959 [ # # ]: 0 : if (bt)
960 : 0 : __blk_add_trace(bt, 0, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL, 0);
961 : 0 : rcu_read_unlock();
962 : 0 : }
963 : :
964 : 0 : static void blk_add_trace_unplug(void *ignore, struct request_queue *q,
965 : : unsigned int depth, bool explicit)
966 : : {
967 : 0 : struct blk_trace *bt;
968 : :
969 : 0 : rcu_read_lock();
970 [ # # ]: 0 : bt = rcu_dereference(q->blk_trace);
971 [ # # ]: 0 : if (bt) {
972 : 0 : __be64 rpdu = cpu_to_be64(depth);
973 : 0 : u32 what;
974 : :
975 [ # # ]: 0 : if (explicit)
976 : : what = BLK_TA_UNPLUG_IO;
977 : : else
978 : 0 : what = BLK_TA_UNPLUG_TIMER;
979 : :
980 : 0 : __blk_add_trace(bt, 0, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu, 0);
981 : : }
982 : 0 : rcu_read_unlock();
983 : 0 : }
984 : :
985 : 0 : static void blk_add_trace_split(void *ignore,
986 : : struct request_queue *q, struct bio *bio,
987 : : unsigned int pdu)
988 : : {
989 : 0 : struct blk_trace *bt;
990 : :
991 : 0 : rcu_read_lock();
992 [ # # ]: 0 : bt = rcu_dereference(q->blk_trace);
993 [ # # ]: 0 : if (bt) {
994 : 0 : __be64 rpdu = cpu_to_be64(pdu);
995 : :
996 : 0 : __blk_add_trace(bt, bio->bi_iter.bi_sector,
997 : 0 : bio->bi_iter.bi_size, bio_op(bio), bio->bi_opf,
998 : 0 : BLK_TA_SPLIT, bio->bi_status, sizeof(rpdu),
999 : : &rpdu, blk_trace_bio_get_cgid(q, bio));
1000 : : }
1001 : 0 : rcu_read_unlock();
1002 : 0 : }
1003 : :
1004 : : /**
1005 : : * blk_add_trace_bio_remap - Add a trace for a bio-remap operation
1006 : : * @ignore: trace callback data parameter (not used)
1007 : : * @q: queue the io is for
1008 : : * @bio: the source bio
1009 : : * @dev: target device
1010 : : * @from: source sector
1011 : : *
1012 : : * Description:
1013 : : * Device mapper or raid target sometimes need to split a bio because
1014 : : * it spans a stripe (or similar). Add a trace for that action.
1015 : : *
1016 : : **/
1017 : 0 : static void blk_add_trace_bio_remap(void *ignore,
1018 : : struct request_queue *q, struct bio *bio,
1019 : : dev_t dev, sector_t from)
1020 : : {
1021 : 0 : struct blk_trace *bt;
1022 : 0 : struct blk_io_trace_remap r;
1023 : :
1024 : 0 : rcu_read_lock();
1025 [ # # ]: 0 : bt = rcu_dereference(q->blk_trace);
1026 [ # # ]: 0 : if (likely(!bt)) {
1027 : 0 : rcu_read_unlock();
1028 : 0 : return;
1029 : : }
1030 : :
1031 : 0 : r.device_from = cpu_to_be32(dev);
1032 : 0 : r.device_to = cpu_to_be32(bio_dev(bio));
1033 : 0 : r.sector_from = cpu_to_be64(from);
1034 : :
1035 : 0 : __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
1036 : 0 : bio_op(bio), bio->bi_opf, BLK_TA_REMAP, bio->bi_status,
1037 : : sizeof(r), &r, blk_trace_bio_get_cgid(q, bio));
1038 : 0 : rcu_read_unlock();
1039 : : }
1040 : :
1041 : : /**
1042 : : * blk_add_trace_rq_remap - Add a trace for a request-remap operation
1043 : : * @ignore: trace callback data parameter (not used)
1044 : : * @q: queue the io is for
1045 : : * @rq: the source request
1046 : : * @dev: target device
1047 : : * @from: source sector
1048 : : *
1049 : : * Description:
1050 : : * Device mapper remaps request to other devices.
1051 : : * Add a trace for that action.
1052 : : *
1053 : : **/
1054 : 0 : static void blk_add_trace_rq_remap(void *ignore,
1055 : : struct request_queue *q,
1056 : : struct request *rq, dev_t dev,
1057 : : sector_t from)
1058 : : {
1059 : 0 : struct blk_trace *bt;
1060 : 0 : struct blk_io_trace_remap r;
1061 : :
1062 : 0 : rcu_read_lock();
1063 [ # # ]: 0 : bt = rcu_dereference(q->blk_trace);
1064 [ # # ]: 0 : if (likely(!bt)) {
1065 : 0 : rcu_read_unlock();
1066 : 0 : return;
1067 : : }
1068 : :
1069 : 0 : r.device_from = cpu_to_be32(dev);
1070 : 0 : r.device_to = cpu_to_be32(disk_devt(rq->rq_disk));
1071 : 0 : r.sector_from = cpu_to_be64(from);
1072 : :
1073 : 0 : __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq),
1074 : 0 : rq_data_dir(rq), 0, BLK_TA_REMAP, 0,
1075 : : sizeof(r), &r, blk_trace_request_get_cgid(q, rq));
1076 : 0 : rcu_read_unlock();
1077 : : }
1078 : :
1079 : : /**
1080 : : * blk_add_driver_data - Add binary message with driver-specific data
1081 : : * @q: queue the io is for
1082 : : * @rq: io request
1083 : : * @data: driver-specific data
1084 : : * @len: length of driver-specific data
1085 : : *
1086 : : * Description:
1087 : : * Some drivers might want to write driver-specific data per request.
1088 : : *
1089 : : **/
1090 : 0 : void blk_add_driver_data(struct request_queue *q,
1091 : : struct request *rq,
1092 : : void *data, size_t len)
1093 : : {
1094 : 0 : struct blk_trace *bt;
1095 : :
1096 : 0 : rcu_read_lock();
1097 [ # # ]: 0 : bt = rcu_dereference(q->blk_trace);
1098 [ # # ]: 0 : if (likely(!bt)) {
1099 : 0 : rcu_read_unlock();
1100 : 0 : return;
1101 : : }
1102 : :
1103 [ # # ]: 0 : __blk_add_trace(bt, blk_rq_trace_sector(rq), blk_rq_bytes(rq), 0, 0,
1104 : : BLK_TA_DRV_DATA, 0, len, data,
1105 : : blk_trace_request_get_cgid(q, rq));
1106 : 0 : rcu_read_unlock();
1107 : : }
1108 : : EXPORT_SYMBOL_GPL(blk_add_driver_data);
1109 : :
1110 : 0 : static void blk_register_tracepoints(void)
1111 : : {
1112 : 0 : int ret;
1113 : :
1114 : 0 : ret = register_trace_block_rq_insert(blk_add_trace_rq_insert, NULL);
1115 [ # # ]: 0 : WARN_ON(ret);
1116 : 0 : ret = register_trace_block_rq_issue(blk_add_trace_rq_issue, NULL);
1117 [ # # ]: 0 : WARN_ON(ret);
1118 : 0 : ret = register_trace_block_rq_requeue(blk_add_trace_rq_requeue, NULL);
1119 [ # # ]: 0 : WARN_ON(ret);
1120 : 0 : ret = register_trace_block_rq_complete(blk_add_trace_rq_complete, NULL);
1121 [ # # ]: 0 : WARN_ON(ret);
1122 : 0 : ret = register_trace_block_bio_bounce(blk_add_trace_bio_bounce, NULL);
1123 [ # # ]: 0 : WARN_ON(ret);
1124 : 0 : ret = register_trace_block_bio_complete(blk_add_trace_bio_complete, NULL);
1125 [ # # ]: 0 : WARN_ON(ret);
1126 : 0 : ret = register_trace_block_bio_backmerge(blk_add_trace_bio_backmerge, NULL);
1127 [ # # ]: 0 : WARN_ON(ret);
1128 : 0 : ret = register_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge, NULL);
1129 [ # # ]: 0 : WARN_ON(ret);
1130 : 0 : ret = register_trace_block_bio_queue(blk_add_trace_bio_queue, NULL);
1131 [ # # ]: 0 : WARN_ON(ret);
1132 : 0 : ret = register_trace_block_getrq(blk_add_trace_getrq, NULL);
1133 [ # # ]: 0 : WARN_ON(ret);
1134 : 0 : ret = register_trace_block_sleeprq(blk_add_trace_sleeprq, NULL);
1135 [ # # ]: 0 : WARN_ON(ret);
1136 : 0 : ret = register_trace_block_plug(blk_add_trace_plug, NULL);
1137 [ # # ]: 0 : WARN_ON(ret);
1138 : 0 : ret = register_trace_block_unplug(blk_add_trace_unplug, NULL);
1139 [ # # ]: 0 : WARN_ON(ret);
1140 : 0 : ret = register_trace_block_split(blk_add_trace_split, NULL);
1141 [ # # ]: 0 : WARN_ON(ret);
1142 : 0 : ret = register_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);
1143 [ # # ]: 0 : WARN_ON(ret);
1144 : 0 : ret = register_trace_block_rq_remap(blk_add_trace_rq_remap, NULL);
1145 [ # # ]: 0 : WARN_ON(ret);
1146 : 0 : }
1147 : :
1148 : 0 : static void blk_unregister_tracepoints(void)
1149 : : {
1150 : 0 : unregister_trace_block_rq_remap(blk_add_trace_rq_remap, NULL);
1151 : 0 : unregister_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);
1152 : 0 : unregister_trace_block_split(blk_add_trace_split, NULL);
1153 : 0 : unregister_trace_block_unplug(blk_add_trace_unplug, NULL);
1154 : 0 : unregister_trace_block_plug(blk_add_trace_plug, NULL);
1155 : 0 : unregister_trace_block_sleeprq(blk_add_trace_sleeprq, NULL);
1156 : 0 : unregister_trace_block_getrq(blk_add_trace_getrq, NULL);
1157 : 0 : unregister_trace_block_bio_queue(blk_add_trace_bio_queue, NULL);
1158 : 0 : unregister_trace_block_bio_frontmerge(blk_add_trace_bio_frontmerge, NULL);
1159 : 0 : unregister_trace_block_bio_backmerge(blk_add_trace_bio_backmerge, NULL);
1160 : 0 : unregister_trace_block_bio_complete(blk_add_trace_bio_complete, NULL);
1161 : 0 : unregister_trace_block_bio_bounce(blk_add_trace_bio_bounce, NULL);
1162 : 0 : unregister_trace_block_rq_complete(blk_add_trace_rq_complete, NULL);
1163 : 0 : unregister_trace_block_rq_requeue(blk_add_trace_rq_requeue, NULL);
1164 : 0 : unregister_trace_block_rq_issue(blk_add_trace_rq_issue, NULL);
1165 : 0 : unregister_trace_block_rq_insert(blk_add_trace_rq_insert, NULL);
1166 : :
1167 : 0 : tracepoint_synchronize_unregister();
1168 : 0 : }
1169 : :
1170 : : /*
1171 : : * struct blk_io_tracer formatting routines
1172 : : */
1173 : :
1174 : : static void fill_rwbs(char *rwbs, const struct blk_io_trace *t)
1175 : : {
1176 : : int i = 0;
1177 : : int tc = t->action >> BLK_TC_SHIFT;
1178 : :
1179 : : if ((t->action & ~__BLK_TN_CGROUP) == BLK_TN_MESSAGE) {
1180 : : rwbs[i++] = 'N';
1181 : : goto out;
1182 : : }
1183 : :
1184 : : if (tc & BLK_TC_FLUSH)
1185 : : rwbs[i++] = 'F';
1186 : :
1187 : : if (tc & BLK_TC_DISCARD)
1188 : : rwbs[i++] = 'D';
1189 : : else if (tc & BLK_TC_WRITE)
1190 : : rwbs[i++] = 'W';
1191 : : else if (t->bytes)
1192 : : rwbs[i++] = 'R';
1193 : : else
1194 : : rwbs[i++] = 'N';
1195 : :
1196 : : if (tc & BLK_TC_FUA)
1197 : : rwbs[i++] = 'F';
1198 : : if (tc & BLK_TC_AHEAD)
1199 : : rwbs[i++] = 'A';
1200 : : if (tc & BLK_TC_SYNC)
1201 : : rwbs[i++] = 'S';
1202 : : if (tc & BLK_TC_META)
1203 : : rwbs[i++] = 'M';
1204 : : out:
1205 : : rwbs[i] = '\0';
1206 : : }
1207 : :
1208 : : static inline
1209 : 0 : const struct blk_io_trace *te_blk_io_trace(const struct trace_entry *ent)
1210 : : {
1211 : 0 : return (const struct blk_io_trace *)ent;
1212 : : }
1213 : :
1214 : 0 : static inline const void *pdu_start(const struct trace_entry *ent, bool has_cg)
1215 : : {
1216 : 0 : return (void *)(te_blk_io_trace(ent) + 1) + (has_cg ? sizeof(u64) : 0);
1217 : : }
1218 : :
1219 : 0 : static inline u64 t_cgid(const struct trace_entry *ent)
1220 : : {
1221 : 0 : return *(u64 *)(te_blk_io_trace(ent) + 1);
1222 : : }
1223 : :
1224 : 0 : static inline int pdu_real_len(const struct trace_entry *ent, bool has_cg)
1225 : : {
1226 [ # # ]: 0 : return te_blk_io_trace(ent)->pdu_len - (has_cg ? sizeof(u64) : 0);
1227 : : }
1228 : :
1229 : 0 : static inline u32 t_action(const struct trace_entry *ent)
1230 : : {
1231 : 0 : return te_blk_io_trace(ent)->action;
1232 : : }
1233 : :
1234 : 0 : static inline u32 t_bytes(const struct trace_entry *ent)
1235 : : {
1236 : 0 : return te_blk_io_trace(ent)->bytes;
1237 : : }
1238 : :
1239 : 0 : static inline u32 t_sec(const struct trace_entry *ent)
1240 : : {
1241 : 0 : return te_blk_io_trace(ent)->bytes >> 9;
1242 : : }
1243 : :
1244 : 0 : static inline unsigned long long t_sector(const struct trace_entry *ent)
1245 : : {
1246 : 0 : return te_blk_io_trace(ent)->sector;
1247 : : }
1248 : :
1249 : 0 : static inline __u16 t_error(const struct trace_entry *ent)
1250 : : {
1251 : 0 : return te_blk_io_trace(ent)->error;
1252 : : }
1253 : :
1254 : 0 : static __u64 get_pdu_int(const struct trace_entry *ent, bool has_cg)
1255 : : {
1256 : 0 : const __u64 *val = pdu_start(ent, has_cg);
1257 : 0 : return be64_to_cpu(*val);
1258 : : }
1259 : :
1260 : 0 : static void get_pdu_remap(const struct trace_entry *ent,
1261 : : struct blk_io_trace_remap *r, bool has_cg)
1262 : : {
1263 : 0 : const struct blk_io_trace_remap *__r = pdu_start(ent, has_cg);
1264 : 0 : __u64 sector_from = __r->sector_from;
1265 : :
1266 : 0 : r->device_from = be32_to_cpu(__r->device_from);
1267 : 0 : r->device_to = be32_to_cpu(__r->device_to);
1268 : 0 : r->sector_from = be64_to_cpu(sector_from);
1269 : : }
1270 : :
1271 : : typedef void (blk_log_action_t) (struct trace_iterator *iter, const char *act,
1272 : : bool has_cg);
1273 : :
1274 : 0 : static void blk_log_action_classic(struct trace_iterator *iter, const char *act,
1275 : : bool has_cg)
1276 : : {
1277 : 0 : char rwbs[RWBS_LEN];
1278 : 0 : unsigned long long ts = iter->ts;
1279 : 0 : unsigned long nsec_rem = do_div(ts, NSEC_PER_SEC);
1280 : 0 : unsigned secs = (unsigned long)ts;
1281 : 0 : const struct blk_io_trace *t = te_blk_io_trace(iter->ent);
1282 : :
1283 : 0 : fill_rwbs(rwbs, t);
1284 : :
1285 : 0 : trace_seq_printf(&iter->seq,
1286 : : "%3d,%-3d %2d %5d.%09lu %5u %2s %3s ",
1287 : 0 : MAJOR(t->device), MINOR(t->device), iter->cpu,
1288 : 0 : secs, nsec_rem, iter->ent->pid, act, rwbs);
1289 : 0 : }
1290 : :
1291 : 0 : static void blk_log_action(struct trace_iterator *iter, const char *act,
1292 : : bool has_cg)
1293 : : {
1294 : 0 : char rwbs[RWBS_LEN];
1295 : 0 : const struct blk_io_trace *t = te_blk_io_trace(iter->ent);
1296 : :
1297 : 0 : fill_rwbs(rwbs, t);
1298 [ # # ]: 0 : if (has_cg) {
1299 : 0 : u64 id = t_cgid(iter->ent);
1300 : :
1301 [ # # ]: 0 : if (blk_tracer_flags.val & TRACE_BLK_OPT_CGNAME) {
1302 : 0 : char blkcg_name_buf[NAME_MAX + 1] = "<...>";
1303 : :
1304 : 0 : cgroup_path_from_kernfs_id(id, blkcg_name_buf,
1305 : : sizeof(blkcg_name_buf));
1306 : 0 : trace_seq_printf(&iter->seq, "%3d,%-3d %s %2s %3s ",
1307 : 0 : MAJOR(t->device), MINOR(t->device),
1308 : : blkcg_name_buf, act, rwbs);
1309 : : } else {
1310 : : /*
1311 : : * The cgid portion used to be "INO,GEN". Userland
1312 : : * builds a FILEID_INO32_GEN fid out of them and
1313 : : * opens the cgroup using open_by_handle_at(2).
1314 : : * While 32bit ino setups are still the same, 64bit
1315 : : * ones now use the 64bit ino as the whole ID and
1316 : : * no longer use generation.
1317 : : *
1318 : : * Regarldess of the content, always output
1319 : : * "LOW32,HIGH32" so that FILEID_INO32_GEN fid can
1320 : : * be mapped back to @id on both 64 and 32bit ino
1321 : : * setups. See __kernfs_fh_to_dentry().
1322 : : */
1323 : 0 : trace_seq_printf(&iter->seq,
1324 : : "%3d,%-3d %llx,%-llx %2s %3s ",
1325 : 0 : MAJOR(t->device), MINOR(t->device),
1326 : : id & U32_MAX, id >> 32, act, rwbs);
1327 : : }
1328 : : } else
1329 : 0 : trace_seq_printf(&iter->seq, "%3d,%-3d %2s %3s ",
1330 : 0 : MAJOR(t->device), MINOR(t->device), act, rwbs);
1331 : 0 : }
1332 : :
1333 : 0 : static void blk_log_dump_pdu(struct trace_seq *s,
1334 : : const struct trace_entry *ent, bool has_cg)
1335 : : {
1336 : 0 : const unsigned char *pdu_buf;
1337 : 0 : int pdu_len;
1338 : 0 : int i, end;
1339 : :
1340 [ # # ]: 0 : pdu_buf = pdu_start(ent, has_cg);
1341 [ # # ]: 0 : pdu_len = pdu_real_len(ent, has_cg);
1342 : :
1343 [ # # ]: 0 : if (!pdu_len)
1344 : : return;
1345 : :
1346 : : /* find the last zero that needs to be printed */
1347 [ # # ]: 0 : for (end = pdu_len - 1; end >= 0; end--)
1348 [ # # ]: 0 : if (pdu_buf[end])
1349 : : break;
1350 : 0 : end++;
1351 : :
1352 : 0 : trace_seq_putc(s, '(');
1353 : :
1354 [ # # ]: 0 : for (i = 0; i < pdu_len; i++) {
1355 : :
1356 : 0 : trace_seq_printf(s, "%s%02x",
1357 [ # # ]: 0 : i == 0 ? "" : " ", pdu_buf[i]);
1358 : :
1359 : : /*
1360 : : * stop when the rest is just zeroes and indicate so
1361 : : * with a ".." appended
1362 : : */
1363 [ # # # # ]: 0 : if (i == end && end != pdu_len - 1) {
1364 : 0 : trace_seq_puts(s, " ..) ");
1365 : 0 : return;
1366 : : }
1367 : : }
1368 : :
1369 : 0 : trace_seq_puts(s, ") ");
1370 : : }
1371 : :
1372 : 0 : static void blk_log_generic(struct trace_seq *s, const struct trace_entry *ent, bool has_cg)
1373 : : {
1374 : 0 : char cmd[TASK_COMM_LEN];
1375 : :
1376 : 0 : trace_find_cmdline(ent->pid, cmd);
1377 : :
1378 [ # # ]: 0 : if (t_action(ent) & BLK_TC_ACT(BLK_TC_PC)) {
1379 : 0 : trace_seq_printf(s, "%u ", t_bytes(ent));
1380 : 0 : blk_log_dump_pdu(s, ent, has_cg);
1381 : 0 : trace_seq_printf(s, "[%s]\n", cmd);
1382 : : } else {
1383 [ # # ]: 0 : if (t_sec(ent))
1384 : 0 : trace_seq_printf(s, "%llu + %u [%s]\n",
1385 : : t_sector(ent), t_sec(ent), cmd);
1386 : : else
1387 : 0 : trace_seq_printf(s, "[%s]\n", cmd);
1388 : : }
1389 : 0 : }
1390 : :
1391 : 0 : static void blk_log_with_error(struct trace_seq *s,
1392 : : const struct trace_entry *ent, bool has_cg)
1393 : : {
1394 [ # # ]: 0 : if (t_action(ent) & BLK_TC_ACT(BLK_TC_PC)) {
1395 : 0 : blk_log_dump_pdu(s, ent, has_cg);
1396 : 0 : trace_seq_printf(s, "[%d]\n", t_error(ent));
1397 : : } else {
1398 [ # # ]: 0 : if (t_sec(ent))
1399 : 0 : trace_seq_printf(s, "%llu + %u [%d]\n",
1400 : : t_sector(ent),
1401 : : t_sec(ent), t_error(ent));
1402 : : else
1403 : 0 : trace_seq_printf(s, "%llu [%d]\n",
1404 : : t_sector(ent), t_error(ent));
1405 : : }
1406 : 0 : }
1407 : :
1408 : 0 : static void blk_log_remap(struct trace_seq *s, const struct trace_entry *ent, bool has_cg)
1409 : : {
1410 : 0 : struct blk_io_trace_remap r = { .device_from = 0, };
1411 : :
1412 [ # # ]: 0 : get_pdu_remap(ent, &r, has_cg);
1413 : 0 : trace_seq_printf(s, "%llu + %u <- (%d,%d) %llu\n",
1414 : : t_sector(ent), t_sec(ent),
1415 : 0 : MAJOR(r.device_from), MINOR(r.device_from),
1416 : : (unsigned long long)r.sector_from);
1417 : 0 : }
1418 : :
1419 : 0 : static void blk_log_plug(struct trace_seq *s, const struct trace_entry *ent, bool has_cg)
1420 : : {
1421 : 0 : char cmd[TASK_COMM_LEN];
1422 : :
1423 : 0 : trace_find_cmdline(ent->pid, cmd);
1424 : :
1425 : 0 : trace_seq_printf(s, "[%s]\n", cmd);
1426 : 0 : }
1427 : :
1428 : 0 : static void blk_log_unplug(struct trace_seq *s, const struct trace_entry *ent, bool has_cg)
1429 : : {
1430 : 0 : char cmd[TASK_COMM_LEN];
1431 : :
1432 : 0 : trace_find_cmdline(ent->pid, cmd);
1433 : :
1434 [ # # ]: 0 : trace_seq_printf(s, "[%s] %llu\n", cmd, get_pdu_int(ent, has_cg));
1435 : 0 : }
1436 : :
1437 : 0 : static void blk_log_split(struct trace_seq *s, const struct trace_entry *ent, bool has_cg)
1438 : : {
1439 : 0 : char cmd[TASK_COMM_LEN];
1440 : :
1441 : 0 : trace_find_cmdline(ent->pid, cmd);
1442 : :
1443 [ # # ]: 0 : trace_seq_printf(s, "%llu / %llu [%s]\n", t_sector(ent),
1444 : : get_pdu_int(ent, has_cg), cmd);
1445 : 0 : }
1446 : :
1447 : 0 : static void blk_log_msg(struct trace_seq *s, const struct trace_entry *ent,
1448 : : bool has_cg)
1449 : : {
1450 : :
1451 [ # # ]: 0 : trace_seq_putmem(s, pdu_start(ent, has_cg),
1452 : : pdu_real_len(ent, has_cg));
1453 : 0 : trace_seq_putc(s, '\n');
1454 : 0 : }
1455 : :
1456 : : /*
1457 : : * struct tracer operations
1458 : : */
1459 : :
1460 : 0 : static void blk_tracer_print_header(struct seq_file *m)
1461 : : {
1462 [ # # ]: 0 : if (!(blk_tracer_flags.val & TRACE_BLK_OPT_CLASSIC))
1463 : : return;
1464 : 0 : seq_puts(m, "# DEV CPU TIMESTAMP PID ACT FLG\n"
1465 : : "# | | | | | |\n");
1466 : : }
1467 : :
1468 : 0 : static void blk_tracer_start(struct trace_array *tr)
1469 : : {
1470 : 0 : blk_tracer_enabled = true;
1471 : 0 : }
1472 : :
1473 : 0 : static int blk_tracer_init(struct trace_array *tr)
1474 : : {
1475 : 0 : blk_tr = tr;
1476 : 0 : blk_tracer_start(tr);
1477 : 0 : return 0;
1478 : : }
1479 : :
1480 : 0 : static void blk_tracer_stop(struct trace_array *tr)
1481 : : {
1482 : 0 : blk_tracer_enabled = false;
1483 : 0 : }
1484 : :
1485 : 0 : static void blk_tracer_reset(struct trace_array *tr)
1486 : : {
1487 : 0 : blk_tracer_stop(tr);
1488 : 0 : }
1489 : :
1490 : : static const struct {
1491 : : const char *act[2];
1492 : : void (*print)(struct trace_seq *s, const struct trace_entry *ent,
1493 : : bool has_cg);
1494 : : } what2act[] = {
1495 : : [__BLK_TA_QUEUE] = {{ "Q", "queue" }, blk_log_generic },
1496 : : [__BLK_TA_BACKMERGE] = {{ "M", "backmerge" }, blk_log_generic },
1497 : : [__BLK_TA_FRONTMERGE] = {{ "F", "frontmerge" }, blk_log_generic },
1498 : : [__BLK_TA_GETRQ] = {{ "G", "getrq" }, blk_log_generic },
1499 : : [__BLK_TA_SLEEPRQ] = {{ "S", "sleeprq" }, blk_log_generic },
1500 : : [__BLK_TA_REQUEUE] = {{ "R", "requeue" }, blk_log_with_error },
1501 : : [__BLK_TA_ISSUE] = {{ "D", "issue" }, blk_log_generic },
1502 : : [__BLK_TA_COMPLETE] = {{ "C", "complete" }, blk_log_with_error },
1503 : : [__BLK_TA_PLUG] = {{ "P", "plug" }, blk_log_plug },
1504 : : [__BLK_TA_UNPLUG_IO] = {{ "U", "unplug_io" }, blk_log_unplug },
1505 : : [__BLK_TA_UNPLUG_TIMER] = {{ "UT", "unplug_timer" }, blk_log_unplug },
1506 : : [__BLK_TA_INSERT] = {{ "I", "insert" }, blk_log_generic },
1507 : : [__BLK_TA_SPLIT] = {{ "X", "split" }, blk_log_split },
1508 : : [__BLK_TA_BOUNCE] = {{ "B", "bounce" }, blk_log_generic },
1509 : : [__BLK_TA_REMAP] = {{ "A", "remap" }, blk_log_remap },
1510 : : };
1511 : :
1512 : 0 : static enum print_line_t print_one_line(struct trace_iterator *iter,
1513 : : bool classic)
1514 : : {
1515 : 0 : struct trace_array *tr = iter->tr;
1516 : 0 : struct trace_seq *s = &iter->seq;
1517 : 0 : const struct blk_io_trace *t;
1518 : 0 : u16 what;
1519 : 0 : bool long_act;
1520 : 0 : blk_log_action_t *log_action;
1521 : 0 : bool has_cg;
1522 : :
1523 : 0 : t = te_blk_io_trace(iter->ent);
1524 : 0 : what = (t->action & ((1 << BLK_TC_SHIFT) - 1)) & ~__BLK_TA_CGROUP;
1525 : 0 : long_act = !!(tr->trace_flags & TRACE_ITER_VERBOSE);
1526 [ # # ]: 0 : log_action = classic ? &blk_log_action_classic : &blk_log_action;
1527 : 0 : has_cg = t->action & __BLK_TA_CGROUP;
1528 : :
1529 [ # # ]: 0 : if ((t->action & ~__BLK_TN_CGROUP) == BLK_TN_MESSAGE) {
1530 [ # # ]: 0 : log_action(iter, long_act ? "message" : "m", has_cg);
1531 : 0 : blk_log_msg(s, iter->ent, has_cg);
1532 : 0 : return trace_handle_return(s);
1533 : : }
1534 : :
1535 [ # # ]: 0 : if (unlikely(what == 0 || what >= ARRAY_SIZE(what2act)))
1536 : 0 : trace_seq_printf(s, "Unknown action %x\n", what);
1537 : : else {
1538 : 0 : log_action(iter, what2act[what].act[long_act], has_cg);
1539 : 0 : what2act[what].print(s, iter->ent, has_cg);
1540 : : }
1541 : :
1542 : 0 : return trace_handle_return(s);
1543 : : }
1544 : :
1545 : 0 : static enum print_line_t blk_trace_event_print(struct trace_iterator *iter,
1546 : : int flags, struct trace_event *event)
1547 : : {
1548 : 0 : return print_one_line(iter, false);
1549 : : }
1550 : :
1551 : 0 : static void blk_trace_synthesize_old_trace(struct trace_iterator *iter)
1552 : : {
1553 : 0 : struct trace_seq *s = &iter->seq;
1554 : 0 : struct blk_io_trace *t = (struct blk_io_trace *)iter->ent;
1555 : 0 : const int offset = offsetof(struct blk_io_trace, sector);
1556 : 0 : struct blk_io_trace old = {
1557 : : .magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION,
1558 : 0 : .time = iter->ts,
1559 : : };
1560 : :
1561 : 0 : trace_seq_putmem(s, &old, offset);
1562 : 0 : trace_seq_putmem(s, &t->sector,
1563 : 0 : sizeof(old) - offset + t->pdu_len);
1564 : 0 : }
1565 : :
1566 : : static enum print_line_t
1567 : 0 : blk_trace_event_print_binary(struct trace_iterator *iter, int flags,
1568 : : struct trace_event *event)
1569 : : {
1570 : 0 : blk_trace_synthesize_old_trace(iter);
1571 : :
1572 : 0 : return trace_handle_return(&iter->seq);
1573 : : }
1574 : :
1575 : 0 : static enum print_line_t blk_tracer_print_line(struct trace_iterator *iter)
1576 : : {
1577 [ # # ]: 0 : if (!(blk_tracer_flags.val & TRACE_BLK_OPT_CLASSIC))
1578 : : return TRACE_TYPE_UNHANDLED;
1579 : :
1580 : 0 : return print_one_line(iter, true);
1581 : : }
1582 : :
1583 : : static int
1584 : 0 : blk_tracer_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
1585 : : {
1586 : : /* don't output context-info for blk_classic output */
1587 [ # # ]: 0 : if (bit == TRACE_BLK_OPT_CLASSIC) {
1588 [ # # ]: 0 : if (set)
1589 : 0 : tr->trace_flags &= ~TRACE_ITER_CONTEXT_INFO;
1590 : : else
1591 : 0 : tr->trace_flags |= TRACE_ITER_CONTEXT_INFO;
1592 : : }
1593 : 0 : return 0;
1594 : : }
1595 : :
1596 : : static struct tracer blk_tracer __read_mostly = {
1597 : : .name = "blk",
1598 : : .init = blk_tracer_init,
1599 : : .reset = blk_tracer_reset,
1600 : : .start = blk_tracer_start,
1601 : : .stop = blk_tracer_stop,
1602 : : .print_header = blk_tracer_print_header,
1603 : : .print_line = blk_tracer_print_line,
1604 : : .flags = &blk_tracer_flags,
1605 : : .set_flag = blk_tracer_set_flag,
1606 : : };
1607 : :
1608 : : static struct trace_event_functions trace_blk_event_funcs = {
1609 : : .trace = blk_trace_event_print,
1610 : : .binary = blk_trace_event_print_binary,
1611 : : };
1612 : :
1613 : : static struct trace_event trace_blk_event = {
1614 : : .type = TRACE_BLK,
1615 : : .funcs = &trace_blk_event_funcs,
1616 : : };
1617 : :
1618 : 30 : static int __init init_blk_tracer(void)
1619 : : {
1620 [ - + ]: 30 : if (!register_trace_event(&trace_blk_event)) {
1621 : 0 : pr_warn("Warning: could not register block events\n");
1622 : 0 : return 1;
1623 : : }
1624 : :
1625 [ - + ]: 30 : if (register_tracer(&blk_tracer) != 0) {
1626 : 0 : pr_warn("Warning: could not register the block tracer\n");
1627 : 0 : unregister_trace_event(&trace_blk_event);
1628 : 0 : return 1;
1629 : : }
1630 : :
1631 : : return 0;
1632 : : }
1633 : :
1634 : : device_initcall(init_blk_tracer);
1635 : :
1636 : 0 : static int blk_trace_remove_queue(struct request_queue *q)
1637 : : {
1638 : 0 : struct blk_trace *bt;
1639 : :
1640 : 0 : bt = xchg(&q->blk_trace, NULL);
1641 [ # # ]: 0 : if (bt == NULL)
1642 : : return -EINVAL;
1643 : :
1644 : 0 : put_probe_ref();
1645 : 0 : synchronize_rcu();
1646 : 0 : blk_trace_free(bt);
1647 : 0 : return 0;
1648 : : }
1649 : :
1650 : : /*
1651 : : * Setup everything required to start tracing
1652 : : */
1653 : 0 : static int blk_trace_setup_queue(struct request_queue *q,
1654 : : struct block_device *bdev)
1655 : : {
1656 : 0 : struct blk_trace *bt = NULL;
1657 : 0 : int ret = -ENOMEM;
1658 : :
1659 : 0 : bt = kzalloc(sizeof(*bt), GFP_KERNEL);
1660 [ # # ]: 0 : if (!bt)
1661 : : return -ENOMEM;
1662 : :
1663 : 0 : bt->msg_data = __alloc_percpu(BLK_TN_MAX_MSG, __alignof__(char));
1664 [ # # ]: 0 : if (!bt->msg_data)
1665 : 0 : goto free_bt;
1666 : :
1667 : 0 : bt->dev = bdev->bd_dev;
1668 : 0 : bt->act_mask = (u16)-1;
1669 : :
1670 [ # # ]: 0 : blk_trace_setup_lba(bt, bdev);
1671 : :
1672 : 0 : ret = -EBUSY;
1673 [ # # ]: 0 : if (cmpxchg(&q->blk_trace, NULL, bt))
1674 : 0 : goto free_bt;
1675 : :
1676 : 0 : get_probe_ref();
1677 : 0 : return 0;
1678 : :
1679 : 0 : free_bt:
1680 : 0 : blk_trace_free(bt);
1681 : 0 : return ret;
1682 : : }
1683 : :
1684 : : /*
1685 : : * sysfs interface to enable and configure tracing
1686 : : */
1687 : :
1688 : : static ssize_t sysfs_blk_trace_attr_show(struct device *dev,
1689 : : struct device_attribute *attr,
1690 : : char *buf);
1691 : : static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
1692 : : struct device_attribute *attr,
1693 : : const char *buf, size_t count);
1694 : : #define BLK_TRACE_DEVICE_ATTR(_name) \
1695 : : DEVICE_ATTR(_name, S_IRUGO | S_IWUSR, \
1696 : : sysfs_blk_trace_attr_show, \
1697 : : sysfs_blk_trace_attr_store)
1698 : :
1699 : : static BLK_TRACE_DEVICE_ATTR(enable);
1700 : : static BLK_TRACE_DEVICE_ATTR(act_mask);
1701 : : static BLK_TRACE_DEVICE_ATTR(pid);
1702 : : static BLK_TRACE_DEVICE_ATTR(start_lba);
1703 : : static BLK_TRACE_DEVICE_ATTR(end_lba);
1704 : :
1705 : : static struct attribute *blk_trace_attrs[] = {
1706 : : &dev_attr_enable.attr,
1707 : : &dev_attr_act_mask.attr,
1708 : : &dev_attr_pid.attr,
1709 : : &dev_attr_start_lba.attr,
1710 : : &dev_attr_end_lba.attr,
1711 : : NULL
1712 : : };
1713 : :
1714 : : struct attribute_group blk_trace_attr_group = {
1715 : : .name = "trace",
1716 : : .attrs = blk_trace_attrs,
1717 : : };
1718 : :
1719 : : static const struct {
1720 : : int mask;
1721 : : const char *str;
1722 : : } mask_maps[] = {
1723 : : { BLK_TC_READ, "read" },
1724 : : { BLK_TC_WRITE, "write" },
1725 : : { BLK_TC_FLUSH, "flush" },
1726 : : { BLK_TC_SYNC, "sync" },
1727 : : { BLK_TC_QUEUE, "queue" },
1728 : : { BLK_TC_REQUEUE, "requeue" },
1729 : : { BLK_TC_ISSUE, "issue" },
1730 : : { BLK_TC_COMPLETE, "complete" },
1731 : : { BLK_TC_FS, "fs" },
1732 : : { BLK_TC_PC, "pc" },
1733 : : { BLK_TC_NOTIFY, "notify" },
1734 : : { BLK_TC_AHEAD, "ahead" },
1735 : : { BLK_TC_META, "meta" },
1736 : : { BLK_TC_DISCARD, "discard" },
1737 : : { BLK_TC_DRV_DATA, "drv_data" },
1738 : : { BLK_TC_FUA, "fua" },
1739 : : };
1740 : :
1741 : 0 : static int blk_trace_str2mask(const char *str)
1742 : : {
1743 : 0 : int i;
1744 : 0 : int mask = 0;
1745 : 0 : char *buf, *s, *token;
1746 : :
1747 : 0 : buf = kstrdup(str, GFP_KERNEL);
1748 [ # # ]: 0 : if (buf == NULL)
1749 : : return -ENOMEM;
1750 : 0 : s = strstrip(buf);
1751 : :
1752 : 0 : while (1) {
1753 : 0 : token = strsep(&s, ",");
1754 [ # # ]: 0 : if (token == NULL)
1755 : : break;
1756 : :
1757 [ # # ]: 0 : if (*token == '\0')
1758 : 0 : continue;
1759 : :
1760 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(mask_maps); i++) {
1761 [ # # ]: 0 : if (strcasecmp(token, mask_maps[i].str) == 0) {
1762 : 0 : mask |= mask_maps[i].mask;
1763 : 0 : break;
1764 : : }
1765 : : }
1766 [ # # ]: 0 : if (i == ARRAY_SIZE(mask_maps)) {
1767 : : mask = -EINVAL;
1768 : : break;
1769 : : }
1770 : : }
1771 : 0 : kfree(buf);
1772 : :
1773 : 0 : return mask;
1774 : : }
1775 : :
1776 : 0 : static ssize_t blk_trace_mask2str(char *buf, int mask)
1777 : : {
1778 : 0 : int i;
1779 : 0 : char *p = buf;
1780 : :
1781 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(mask_maps); i++) {
1782 [ # # ]: 0 : if (mask & mask_maps[i].mask) {
1783 [ # # ]: 0 : p += sprintf(p, "%s%s",
1784 : : (p == buf) ? "" : ",", mask_maps[i].str);
1785 : : }
1786 : : }
1787 : 0 : *p++ = '\n';
1788 : :
1789 : 0 : return p - buf;
1790 : : }
1791 : :
1792 : 0 : static struct request_queue *blk_trace_get_queue(struct block_device *bdev)
1793 : : {
1794 : 0 : if (bdev->bd_disk == NULL)
1795 : : return NULL;
1796 : :
1797 [ # # # # ]: 0 : return bdev_get_queue(bdev);
1798 : : }
1799 : :
1800 : 0 : static ssize_t sysfs_blk_trace_attr_show(struct device *dev,
1801 : : struct device_attribute *attr,
1802 : : char *buf)
1803 : : {
1804 : 0 : struct hd_struct *p = dev_to_part(dev);
1805 : 0 : struct request_queue *q;
1806 : 0 : struct block_device *bdev;
1807 : 0 : struct blk_trace *bt;
1808 : 0 : ssize_t ret = -ENXIO;
1809 : :
1810 : 0 : bdev = bdget(part_devt(p));
1811 [ # # ]: 0 : if (bdev == NULL)
1812 : 0 : goto out;
1813 : :
1814 [ # # ]: 0 : q = blk_trace_get_queue(bdev);
1815 [ # # ]: 0 : if (q == NULL)
1816 : 0 : goto out_bdput;
1817 : :
1818 : 0 : mutex_lock(&q->blk_trace_mutex);
1819 : :
1820 : 0 : bt = rcu_dereference_protected(q->blk_trace,
1821 : : lockdep_is_held(&q->blk_trace_mutex));
1822 [ # # ]: 0 : if (attr == &dev_attr_enable) {
1823 : 0 : ret = sprintf(buf, "%u\n", !!bt);
1824 : 0 : goto out_unlock_bdev;
1825 : : }
1826 : :
1827 [ # # ]: 0 : if (bt == NULL)
1828 : 0 : ret = sprintf(buf, "disabled\n");
1829 [ # # ]: 0 : else if (attr == &dev_attr_act_mask)
1830 : 0 : ret = blk_trace_mask2str(buf, bt->act_mask);
1831 [ # # ]: 0 : else if (attr == &dev_attr_pid)
1832 : 0 : ret = sprintf(buf, "%u\n", bt->pid);
1833 [ # # ]: 0 : else if (attr == &dev_attr_start_lba)
1834 : 0 : ret = sprintf(buf, "%llu\n", bt->start_lba);
1835 [ # # ]: 0 : else if (attr == &dev_attr_end_lba)
1836 : 0 : ret = sprintf(buf, "%llu\n", bt->end_lba);
1837 : :
1838 : 0 : out_unlock_bdev:
1839 : 0 : mutex_unlock(&q->blk_trace_mutex);
1840 : 0 : out_bdput:
1841 : 0 : bdput(bdev);
1842 : 0 : out:
1843 : 0 : return ret;
1844 : : }
1845 : :
1846 : 0 : static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
1847 : : struct device_attribute *attr,
1848 : : const char *buf, size_t count)
1849 : : {
1850 : 0 : struct block_device *bdev;
1851 : 0 : struct request_queue *q;
1852 : 0 : struct hd_struct *p;
1853 : 0 : struct blk_trace *bt;
1854 : 0 : u64 value;
1855 : 0 : ssize_t ret = -EINVAL;
1856 : :
1857 [ # # ]: 0 : if (count == 0)
1858 : 0 : goto out;
1859 : :
1860 [ # # ]: 0 : if (attr == &dev_attr_act_mask) {
1861 [ # # ]: 0 : if (kstrtoull(buf, 0, &value)) {
1862 : : /* Assume it is a list of trace category names */
1863 : 0 : ret = blk_trace_str2mask(buf);
1864 [ # # ]: 0 : if (ret < 0)
1865 : 0 : goto out;
1866 : 0 : value = ret;
1867 : : }
1868 [ # # ]: 0 : } else if (kstrtoull(buf, 0, &value))
1869 : 0 : goto out;
1870 : :
1871 : 0 : ret = -ENXIO;
1872 : :
1873 : 0 : p = dev_to_part(dev);
1874 : 0 : bdev = bdget(part_devt(p));
1875 [ # # ]: 0 : if (bdev == NULL)
1876 : 0 : goto out;
1877 : :
1878 [ # # ]: 0 : q = blk_trace_get_queue(bdev);
1879 [ # # ]: 0 : if (q == NULL)
1880 : 0 : goto out_bdput;
1881 : :
1882 : 0 : mutex_lock(&q->blk_trace_mutex);
1883 : :
1884 : 0 : bt = rcu_dereference_protected(q->blk_trace,
1885 : : lockdep_is_held(&q->blk_trace_mutex));
1886 [ # # ]: 0 : if (attr == &dev_attr_enable) {
1887 [ # # ]: 0 : if (!!value == !!bt) {
1888 : 0 : ret = 0;
1889 : 0 : goto out_unlock_bdev;
1890 : : }
1891 [ # # ]: 0 : if (value)
1892 : 0 : ret = blk_trace_setup_queue(q, bdev);
1893 : : else
1894 : 0 : ret = blk_trace_remove_queue(q);
1895 : 0 : goto out_unlock_bdev;
1896 : : }
1897 : :
1898 : 0 : ret = 0;
1899 [ # # ]: 0 : if (bt == NULL) {
1900 : 0 : ret = blk_trace_setup_queue(q, bdev);
1901 : 0 : bt = rcu_dereference_protected(q->blk_trace,
1902 : : lockdep_is_held(&q->blk_trace_mutex));
1903 : : }
1904 : :
1905 [ # # ]: 0 : if (ret == 0) {
1906 [ # # ]: 0 : if (attr == &dev_attr_act_mask)
1907 : 0 : bt->act_mask = value;
1908 [ # # ]: 0 : else if (attr == &dev_attr_pid)
1909 : 0 : bt->pid = value;
1910 [ # # ]: 0 : else if (attr == &dev_attr_start_lba)
1911 : 0 : bt->start_lba = value;
1912 [ # # ]: 0 : else if (attr == &dev_attr_end_lba)
1913 : 0 : bt->end_lba = value;
1914 : : }
1915 : :
1916 : 0 : out_unlock_bdev:
1917 : 0 : mutex_unlock(&q->blk_trace_mutex);
1918 : 0 : out_bdput:
1919 : 0 : bdput(bdev);
1920 : 0 : out:
1921 [ # # ]: 0 : return ret ? ret : count;
1922 : : }
1923 : :
1924 : 360 : int blk_trace_init_sysfs(struct device *dev)
1925 : : {
1926 : 360 : return sysfs_create_group(&dev->kobj, &blk_trace_attr_group);
1927 : : }
1928 : :
1929 : 0 : void blk_trace_remove_sysfs(struct device *dev)
1930 : : {
1931 : 0 : sysfs_remove_group(&dev->kobj, &blk_trace_attr_group);
1932 : 0 : }
1933 : :
1934 : : #endif /* CONFIG_BLK_DEV_IO_TRACE */
1935 : :
1936 : : #ifdef CONFIG_EVENT_TRACING
1937 : :
1938 : 0 : void blk_fill_rwbs(char *rwbs, unsigned int op, int bytes)
1939 : : {
1940 : 0 : int i = 0;
1941 : :
1942 [ # # ]: 0 : if (op & REQ_PREFLUSH)
1943 : 0 : rwbs[i++] = 'F';
1944 : :
1945 [ # # # # : 0 : switch (op & REQ_OP_MASK) {
# # ]
1946 : 0 : case REQ_OP_WRITE:
1947 : : case REQ_OP_WRITE_SAME:
1948 : 0 : rwbs[i++] = 'W';
1949 : 0 : break;
1950 : 0 : case REQ_OP_DISCARD:
1951 : 0 : rwbs[i++] = 'D';
1952 : 0 : break;
1953 : 0 : case REQ_OP_SECURE_ERASE:
1954 : 0 : rwbs[i++] = 'D';
1955 : 0 : rwbs[i++] = 'E';
1956 : 0 : break;
1957 : 0 : case REQ_OP_FLUSH:
1958 : 0 : rwbs[i++] = 'F';
1959 : 0 : break;
1960 : 0 : case REQ_OP_READ:
1961 : 0 : rwbs[i++] = 'R';
1962 : 0 : break;
1963 : 0 : default:
1964 : 0 : rwbs[i++] = 'N';
1965 : : }
1966 : :
1967 [ # # ]: 0 : if (op & REQ_FUA)
1968 : 0 : rwbs[i++] = 'F';
1969 [ # # ]: 0 : if (op & REQ_RAHEAD)
1970 : 0 : rwbs[i++] = 'A';
1971 [ # # ]: 0 : if (op & REQ_SYNC)
1972 : 0 : rwbs[i++] = 'S';
1973 [ # # ]: 0 : if (op & REQ_META)
1974 : 0 : rwbs[i++] = 'M';
1975 : :
1976 : 0 : rwbs[i] = '\0';
1977 : 0 : }
1978 : : EXPORT_SYMBOL_GPL(blk_fill_rwbs);
1979 : :
1980 : : #endif /* CONFIG_EVENT_TRACING */
1981 : :
|