2 * ltt/probes/ext4-trace.c
4 * ext4 tracepoint probes.
6 * (C) Copyright 2009 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
7 * Dual LGPL v2.1/GPL v2 license.
10 #include <linux/module.h>
11 #include <linux/writeback.h>
12 #include <linux/debugfs.h>
13 #include <linux/mutex.h>
14 #include <linux/rcupdate.h>
15 #include <trace/events/ext4.h>
17 #include "../ltt-tracer.h"
18 #include "../../fs/ext4/mballoc.h"
20 static struct dentry
*ext4_filter_dentry
, *ext4_filter_dev_dentry
,
21 *ext4_filter_inode_dentry
;
22 static DEFINE_MUTEX(ext4_filter_mutex
);
23 /* Make sure we don't race between module exit and file write */
24 static int module_exits
;
26 struct rcu_dev_filter
{
28 char devname
[NAME_MAX
];
31 static struct rcu_dev_filter
*dev_filter
;
32 /* ~0UL inode_filter enables all inodes */
33 static unsigned long inode_filter
= ~0UL;
36 * Probes are executed in rcu_sched read-side critical section.
39 static int do_dev_filter(const char *dev
)
41 struct rcu_dev_filter
*ldev_filter
= rcu_dereference(dev_filter
);
43 if (unlikely(ldev_filter
))
44 if (unlikely(strcmp(ldev_filter
->devname
, dev
)))
49 static int do_inode_filter(unsigned long ino
)
51 if (unlikely(inode_filter
!= ~0UL))
52 if (unlikely(inode_filter
!= ino
))
58 * Logical AND between dev and inode filter.
60 static int do_filter(const char *dev
, unsigned long ino
)
62 if (unlikely(!do_dev_filter(dev
)))
64 if (unlikely(!do_inode_filter(ino
)))
70 void probe_ext4_free_inode(void *data
, struct inode
*inode
)
72 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
74 trace_mark_tp(ext4
, free_inode
, ext4_free_inode
,
75 probe_ext4_free_inode
,
76 "dev %s ino %lu mode %d uid %lu gid %lu blocks %llu",
77 inode
->i_sb
->s_id
, inode
->i_ino
, inode
->i_mode
,
78 (unsigned long) inode
->i_uid
, (unsigned long) inode
->i_gid
,
79 (unsigned long long) inode
->i_blocks
);
82 void probe_ext4_request_inode(void *data
, struct inode
*dir
, int mode
)
84 if (unlikely(!do_filter(dir
->i_sb
->s_id
, dir
->i_ino
)))
86 trace_mark_tp(ext4
, request_inode
, ext4_request_inode
,
87 probe_ext4_request_inode
,
88 "dev %s dir %lu mode %d",
89 dir
->i_sb
->s_id
, dir
->i_ino
, mode
);
92 void probe_ext4_allocate_inode(void *data
, struct inode
*inode
, struct inode
*dir
, int mode
)
94 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)
95 && !do_filter(dir
->i_sb
->s_id
, dir
->i_ino
)))
97 trace_mark_tp(ext4
, allocate_inode
, ext4_allocate_inode
,
98 probe_ext4_allocate_inode
,
99 "dev %s ino %lu dir %lu mode %d",
100 dir
->i_sb
->s_id
, inode
->i_ino
, dir
->i_ino
, mode
);
103 void probe_ext4_write_begin(void *data
, struct inode
*inode
, loff_t pos
, unsigned int len
,
106 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
108 trace_mark_tp(ext4
, write_begin
, ext4_write_begin
,
109 probe_ext4_write_begin
,
110 "dev %s ino %lu pos %llu len %u flags %u",
111 inode
->i_sb
->s_id
, inode
->i_ino
,
112 (unsigned long long) pos
, len
, flags
);
115 void probe_ext4_ordered_write_end(void *data
, struct inode
*inode
, loff_t pos
,
116 unsigned int len
, unsigned int copied
)
118 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
120 trace_mark_tp(ext4
, ordered_write_end
, ext4_ordered_write_end
,
121 probe_ext4_ordered_write_end
,
122 "dev %s ino %lu pos %llu len %u copied %u",
123 inode
->i_sb
->s_id
, inode
->i_ino
,
124 (unsigned long long) pos
, len
, copied
);
127 void probe_ext4_writeback_write_end(void *data
, struct inode
*inode
, loff_t pos
,
128 unsigned int len
, unsigned int copied
)
130 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
132 trace_mark_tp(ext4
, writeback_write_end
, ext4_writeback_write_end
,
133 probe_ext4_writeback_write_end
,
134 "dev %s ino %lu pos %llu len %u copied %u",
135 inode
->i_sb
->s_id
, inode
->i_ino
,
136 (unsigned long long) pos
, len
, copied
);
139 void probe_ext4_journalled_write_end(void *data
, struct inode
*inode
, loff_t pos
,
140 unsigned int len
, unsigned int copied
)
142 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
144 trace_mark_tp(ext4
, journalled_write_end
, ext4_journalled_write_end
,
145 probe_ext4_journalled_write_end
,
146 "dev %s ino %lu pos %llu len %u copied %u",
147 inode
->i_sb
->s_id
, inode
->i_ino
,
148 (unsigned long long) pos
, len
, copied
);
152 * note : wbc_flags will have to be decoded by userspace.
153 * #1x uses a single byte in the trace. Limits to 8 bits.
155 void probe_ext4_da_writepages(void *data
, struct inode
*inode
,
156 struct writeback_control
*wbc
)
158 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
160 trace_mark_tp(ext4
, da_writepages
, ext4_da_writepages
,
161 probe_ext4_da_writepages
,
162 "dev %s ino %lu nr_to_write %ld "
163 "pages_skipped %ld range_start %llu range_end %llu "
164 "wbc_flags(nonblocking,for_kupdate,"
165 "for_reclaim,range_cyclic) #1x%u",
166 inode
->i_sb
->s_id
, inode
->i_ino
, wbc
->nr_to_write
,
168 (unsigned long long) wbc
->range_start
,
169 (unsigned long long) wbc
->range_end
,
170 (wbc
->nonblocking
<< 3)
171 | (wbc
->for_kupdate
<< 2)
172 | (wbc
->for_reclaim
<< 1)
173 | wbc
->range_cyclic
);
177 * note : wbc_flags will have to be decoded by userspace.
178 * #1x uses a single byte in the trace. Limits to 8 bits.
180 void probe_ext4_da_writepages_result(void *data
, struct inode
*inode
,
181 struct writeback_control
*wbc
,
182 int ret
, int pages_written
)
184 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
186 trace_mark_tp(ext4
, da_writepages_result
, ext4_da_writepages_result
,
187 probe_ext4_da_writepages_result
,
188 "dev %s ino %lu ret %d pages_written %d "
190 "wbc_flags(encountered_congestion,"
191 "more_io,no_nrwrite_index_update) #1x%u",
192 inode
->i_sb
->s_id
, inode
->i_ino
, ret
, pages_written
,
194 (wbc
->encountered_congestion
<< 2)
195 | (wbc
->more_io
<< 1)
196 | wbc
->no_nrwrite_index_update
);
199 void probe_ext4_da_write_begin(void *data
, struct inode
*inode
, loff_t pos
,
200 unsigned int len
, unsigned int flags
)
202 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
204 trace_mark_tp(ext4
, da_write_begin
, ext4_da_write_begin
,
205 probe_ext4_da_write_begin
,
206 "dev %s ino %lu pos %llu len %u flags %u",
207 inode
->i_sb
->s_id
, inode
->i_ino
,
208 (unsigned long long) pos
, len
, flags
);
211 void probe_ext4_da_write_end(void *data
, struct inode
*inode
, loff_t pos
,
212 unsigned int len
, unsigned int copied
)
214 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
216 trace_mark_tp(ext4
, da_write_end
, ext4_da_write_end
,
217 probe_ext4_da_write_end
,
218 "dev %s ino %lu pos %llu len %u copied %u",
219 inode
->i_sb
->s_id
, inode
->i_ino
,
220 (unsigned long long) pos
, len
, copied
);
223 void probe_ext4_discard_blocks(void *data
, struct super_block
*sb
, unsigned long long blk
,
224 unsigned long long count
)
226 if (unlikely(!do_dev_filter(sb
->s_id
)))
228 trace_mark_tp(ext4
, discard_blocks
, ext4_discard_blocks
,
229 probe_ext4_discard_blocks
,
230 "dev %s blk %llu count %llu",
231 sb
->s_id
, blk
, count
);
234 void probe_ext4_mb_new_inode_pa(void *data
, struct ext4_allocation_context
*ac
,
235 struct ext4_prealloc_space
*pa
)
237 if (unlikely(!do_filter(ac
->ac_sb
->s_id
, ac
->ac_inode
->i_ino
)))
239 trace_mark_tp(ext4
, mb_new_inode_pa
, ext4_mb_new_inode_pa
,
240 probe_ext4_mb_new_inode_pa
,
241 "dev %s ino %lu pstart %llu len %u lstart %u",
242 ac
->ac_sb
->s_id
, ac
->ac_inode
->i_ino
, pa
->pa_pstart
,
243 pa
->pa_len
, pa
->pa_lstart
);
246 void probe_ext4_mb_new_group_pa(void *data
, struct ext4_allocation_context
*ac
,
247 struct ext4_prealloc_space
*pa
)
249 if (unlikely(!do_dev_filter(ac
->ac_sb
->s_id
)))
251 trace_mark_tp(ext4
, mb_new_group_pa
, ext4_mb_new_group_pa
,
252 probe_ext4_mb_new_group_pa
,
253 "dev %s pstart %llu len %u lstart %u",
254 ac
->ac_sb
->s_id
, pa
->pa_pstart
,
255 pa
->pa_len
, pa
->pa_lstart
);
258 void probe_ext4_mb_release_inode_pa(void *data
, struct ext4_allocation_context
*ac
,
259 struct ext4_prealloc_space
*pa
,
260 unsigned long long block
,
263 if (unlikely(!do_filter(ac
->ac_sb
->s_id
, ac
->ac_inode
->i_ino
)))
265 trace_mark_tp(ext4
, mb_release_inode_pa
, ext4_mb_release_inode_pa
,
266 probe_ext4_mb_release_inode_pa
,
267 "dev %s ino %lu block %llu count %u",
268 ac
->ac_sb
->s_id
, pa
->pa_inode
->i_ino
, block
, count
);
271 void probe_ext4_mb_release_group_pa(void *data
, struct ext4_allocation_context
*ac
,
272 struct ext4_prealloc_space
*pa
)
274 if (unlikely(!do_dev_filter(ac
->ac_sb
->s_id
)))
276 trace_mark_tp(ext4
, mb_release_group_pa
, ext4_mb_release_group_pa
,
277 probe_ext4_mb_release_group_pa
,
278 "dev %s pstart %llu len %d",
279 ac
->ac_sb
->s_id
, pa
->pa_pstart
, pa
->pa_len
);
282 void probe_ext4_discard_preallocations(void *data
, struct inode
*inode
)
284 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
286 trace_mark_tp(ext4
, discard_preallocations
,
287 ext4_discard_preallocations
,
288 probe_ext4_discard_preallocations
,
290 inode
->i_sb
->s_id
, inode
->i_ino
);
293 void probe_ext4_mb_discard_preallocations(void *data
, struct super_block
*sb
, int needed
)
295 if (unlikely(!do_dev_filter(sb
->s_id
)))
297 trace_mark_tp(ext4
, mb_discard_preallocations
,
298 ext4_mb_discard_preallocations
,
299 probe_ext4_mb_discard_preallocations
,
304 void probe_ext4_request_blocks(void *data
, struct ext4_allocation_request
*ar
)
307 if (unlikely(!do_filter(ar
->inode
->i_sb
->s_id
,
311 if (unlikely(!do_dev_filter(ar
->inode
->i_sb
->s_id
)))
314 trace_mark_tp(ext4
, request_blocks
, ext4_request_blocks
,
315 probe_ext4_request_blocks
,
316 "dev %s flags %u len %u ino %lu "
317 "lblk %llu goal %llu lleft %llu lright %llu "
318 "pleft %llu pright %llu",
319 ar
->inode
->i_sb
->s_id
, ar
->flags
, ar
->len
,
320 ar
->inode
? ar
->inode
->i_ino
: 0,
321 (unsigned long long) ar
->logical
,
322 (unsigned long long) ar
->goal
,
323 (unsigned long long) ar
->lleft
,
324 (unsigned long long) ar
->lright
,
325 (unsigned long long) ar
->pleft
,
326 (unsigned long long) ar
->pright
);
329 void probe_ext4_allocate_blocks(void *data
, struct ext4_allocation_request
*ar
,
330 unsigned long long block
)
333 if (unlikely(!do_filter(ar
->inode
->i_sb
->s_id
,
337 if (unlikely(!do_dev_filter(ar
->inode
->i_sb
->s_id
)))
340 trace_mark_tp(ext4
, allocate_blocks
, ext4_allocate_blocks
,
341 probe_ext4_allocate_blocks
,
342 "dev %s block %llu flags %u len %u ino %lu "
343 "logical %llu goal %llu lleft %llu lright %llu "
344 "pleft %llu pright %llu",
345 ar
->inode
->i_sb
->s_id
, (unsigned long long) block
,
346 ar
->flags
, ar
->len
, ar
->inode
? ar
->inode
->i_ino
: 0,
347 (unsigned long long) ar
->logical
,
348 (unsigned long long) ar
->goal
,
349 (unsigned long long) ar
->lleft
,
350 (unsigned long long) ar
->lright
,
351 (unsigned long long) ar
->pleft
,
352 (unsigned long long) ar
->pright
);
355 void probe_ext4_free_blocks(void *data
, struct inode
*inode
, __u64 block
,
356 unsigned long count
, int metadata
)
358 if (unlikely(!do_filter(inode
->i_sb
->s_id
, inode
->i_ino
)))
360 trace_mark_tp(ext4
, free_blocks
, ext4_free_blocks
,
361 probe_ext4_free_blocks
,
362 "dev %s block %llu count %lu metadata %d ino %lu",
363 inode
->i_sb
->s_id
, (unsigned long long)block
,
364 count
, metadata
, inode
->i_ino
);
367 void probe_ext4_sync_file(void *data
, struct file
*file
, struct dentry
*dentry
,
370 if (unlikely(!do_dev_filter(dentry
->d_inode
->i_sb
->s_id
)))
372 if (unlikely(!do_inode_filter(dentry
->d_inode
->i_ino
)
373 && !do_inode_filter(dentry
->d_parent
->d_inode
->i_ino
)))
375 trace_mark_tp(ext4
, sync_file
, ext4_sync_file
,
376 probe_ext4_sync_file
,
377 "dev %s datasync %d ino %ld parent %ld",
378 dentry
->d_inode
->i_sb
->s_id
, datasync
, dentry
->d_inode
->i_ino
,
379 dentry
->d_parent
->d_inode
->i_ino
);
382 void probe_ext4_sync_fs(void *data
, struct super_block
*sb
, int wait
)
384 if (unlikely(!do_dev_filter(sb
->s_id
)))
386 trace_mark_tp(ext4
, sync_fs
, ext4_sync_fs
,
392 static void free_dev_filter(struct rcu_head
*head
)
394 kfree(container_of(head
, struct rcu_dev_filter
, rcu
));
397 static ssize_t
dev_filter_op_write(struct file
*file
,
398 const char __user
*user_buf
, size_t count
, loff_t
*ppos
)
404 struct rcu_dev_filter
*new, *old
;
406 mutex_lock(&ext4_filter_mutex
);
411 buf_size
= min(count
, sizeof(buf
) - 1);
412 err
= copy_from_user(buf
, user_buf
, buf_size
);
417 if (sscanf(buf
, "%s", name
) != 1) {
424 /* Empty string or * means all active */
425 if (name
[0] == '\0' || (name
[0] == '*' && name
[1] == '\0')) {
428 new = kmalloc(sizeof(*new), GFP_KERNEL
);
429 strcpy(new->devname
, name
);
432 rcu_assign_pointer(dev_filter
, new);
434 call_rcu_sched(&old
->rcu
, free_dev_filter
);
436 mutex_unlock(&ext4_filter_mutex
);
440 mutex_unlock(&ext4_filter_mutex
);
444 static ssize_t
dev_filter_op_read(struct file
*filp
, char __user
*buffer
,
445 size_t count
, loff_t
*ppos
)
450 mutex_lock(&ext4_filter_mutex
);
454 devname
= dev_filter
->devname
;
455 bcount
= simple_read_from_buffer(buffer
, count
, ppos
,
456 devname
, strlen(devname
));
457 mutex_unlock(&ext4_filter_mutex
);
461 static struct file_operations ext4_dev_file_operations
= {
462 .write
= dev_filter_op_write
,
463 .read
= dev_filter_op_read
,
466 static ssize_t
inode_filter_op_write(struct file
*file
,
467 const char __user
*user_buf
, size_t count
, loff_t
*ppos
)
473 unsigned long inode_num
;
475 mutex_lock(&ext4_filter_mutex
);
480 buf_size
= min(count
, sizeof(buf
) - 1);
481 err
= copy_from_user(buf
, user_buf
, buf_size
);
486 if (sscanf(buf
, "%s", name
) != 1) {
491 /* Empty string or * means all active */
492 if (name
[0] == '\0' || (name
[0] == '*' && name
[1] == '\0')) {
495 if (sscanf(buf
, "%lu", &inode_num
) != 1) {
499 inode_filter
= inode_num
;
502 mutex_unlock(&ext4_filter_mutex
);
506 mutex_unlock(&ext4_filter_mutex
);
510 static ssize_t
inode_filter_op_read(struct file
*filp
, char __user
*buffer
,
511 size_t count
, loff_t
*ppos
)
514 char inode_str
[NAME_MAX
];
516 mutex_lock(&ext4_filter_mutex
);
517 if (inode_filter
== ~0UL)
518 strcpy(inode_str
, "*");
520 bcount
= snprintf(inode_str
, sizeof(inode_str
), "%lu",
522 if (bcount
== sizeof(inode_str
))
527 bcount
= simple_read_from_buffer(buffer
, count
, ppos
,
528 inode_str
, strlen(inode_str
));
530 mutex_unlock(&ext4_filter_mutex
);
534 static struct file_operations ext4_inode_file_operations
= {
535 .write
= inode_filter_op_write
,
536 .read
= inode_filter_op_read
,
539 static void release_filter_dev(void)
541 struct rcu_dev_filter
*old
;
543 mutex_lock(&ext4_filter_mutex
);
546 rcu_assign_pointer(dev_filter
, NULL
);
548 call_rcu_sched(&old
->rcu
, free_dev_filter
);
549 mutex_unlock(&ext4_filter_mutex
);
552 static int __init
filter_init(void)
554 struct dentry
*filter_root_dentry
;
557 filter_root_dentry
= get_filter_root();
558 if (!filter_root_dentry
) {
563 ext4_filter_dentry
= debugfs_create_dir("ext4", filter_root_dentry
);
565 if (IS_ERR(ext4_filter_dentry
) || !ext4_filter_dentry
) {
566 printk(KERN_ERR
"Failed to create ext4 filter file\n");
571 ext4_filter_dev_dentry
= debugfs_create_file("dev", S_IWUSR
,
572 ext4_filter_dentry
, NULL
, &ext4_dev_file_operations
);
573 if (IS_ERR(ext4_filter_dev_dentry
) || !ext4_filter_dev_dentry
) {
574 printk(KERN_ERR
"Failed to create ext4 dev filter file\n");
576 goto release_filter_dentry
;
579 ext4_filter_inode_dentry
= debugfs_create_file("inode", S_IWUSR
,
580 ext4_filter_dentry
, NULL
, &ext4_inode_file_operations
);
581 if (IS_ERR(ext4_filter_inode_dentry
) || !ext4_filter_inode_dentry
) {
582 printk(KERN_ERR
"Failed to create ext4 inode filter file\n");
584 goto release_filter_dev_dentry
;
589 release_filter_dev_dentry
:
590 debugfs_remove(ext4_filter_dev_dentry
);
591 release_filter_dentry
:
592 debugfs_remove(ext4_filter_dentry
);
593 release_filter_dev();
598 static void __exit
filter_exit(void)
600 debugfs_remove(ext4_filter_dev_dentry
);
601 debugfs_remove(ext4_filter_inode_dentry
);
602 debugfs_remove(ext4_filter_dentry
);
603 release_filter_dev();
606 module_init(filter_init
);
607 module_exit(filter_exit
);
609 MODULE_LICENSE("GPL and additional rights");
610 MODULE_AUTHOR("Mathieu Desnoyers");
611 MODULE_DESCRIPTION("ext4 Tracepoint Probes");