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