diff options
| author | Theodore Ts'o <tytso@mit.edu> | 2013-04-21 16:47:54 -0400 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2013-04-21 16:47:54 -0400 |
| commit | f783f091e49ce4896e6b026af82d76e0537c6089 (patch) | |
| tree | 0ff78a05254d4b996bb027d9fac9969d1d6e0b07 | |
| parent | 13fca323e9a8b63c08de7a4e05d3c702516b535d (diff) | |
jbd2: trace when lock_buffer in do_get_write_access takes a long time
While investigating interactivity problems it was clear that processes
sometimes stall for long periods of times if an attempt is made to
lock a buffer which is undergoing writeback. It would stall in
a trace looking something like
[<ffffffff811a39de>] __lock_buffer+0x2e/0x30
[<ffffffff8123a60f>] do_get_write_access+0x43f/0x4b0
[<ffffffff8123a7cb>] jbd2_journal_get_write_access+0x2b/0x50
[<ffffffff81220f79>] __ext4_journal_get_write_access+0x39/0x80
[<ffffffff811f3198>] ext4_reserve_inode_write+0x78/0xa0
[<ffffffff811f3209>] ext4_mark_inode_dirty+0x49/0x220
[<ffffffff811f57d1>] ext4_dirty_inode+0x41/0x60
[<ffffffff8119ac3e>] __mark_inode_dirty+0x4e/0x2d0
[<ffffffff8118b9b9>] update_time+0x79/0xc0
[<ffffffff8118ba98>] file_update_time+0x98/0x100
[<ffffffff81110ffc>] __generic_file_aio_write+0x17c/0x3b0
[<ffffffff811112aa>] generic_file_aio_write+0x7a/0xf0
[<ffffffff811ea853>] ext4_file_write+0x83/0xd0
[<ffffffff81172b23>] do_sync_write+0xa3/0xe0
[<ffffffff811731ae>] vfs_write+0xae/0x180
[<ffffffff8117361d>] sys_write+0x4d/0x90
[<ffffffff8159d62d>] system_call_fastpath+0x1a/0x1f
[<ffffffffffffffff>] 0xffffffffffffffff
Signed-off-by: Mel Gorman <mgorman@suse.de>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
| -rw-r--r-- | fs/jbd2/transaction.c | 8 | ||||
| -rw-r--r-- | include/trace/events/jbd2.h | 21 |
2 files changed, 29 insertions, 0 deletions
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index a1920da22802..10f524c59ea8 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
| @@ -639,6 +639,7 @@ do_get_write_access(handle_t *handle, struct journal_head *jh, | |||
| 639 | int error; | 639 | int error; |
| 640 | char *frozen_buffer = NULL; | 640 | char *frozen_buffer = NULL; |
| 641 | int need_copy = 0; | 641 | int need_copy = 0; |
| 642 | unsigned long start_lock, time_lock; | ||
| 642 | 643 | ||
| 643 | if (is_handle_aborted(handle)) | 644 | if (is_handle_aborted(handle)) |
| 644 | return -EROFS; | 645 | return -EROFS; |
| @@ -654,9 +655,16 @@ repeat: | |||
| 654 | 655 | ||
| 655 | /* @@@ Need to check for errors here at some point. */ | 656 | /* @@@ Need to check for errors here at some point. */ |
| 656 | 657 | ||
| 658 | start_lock = jiffies; | ||
| 657 | lock_buffer(bh); | 659 | lock_buffer(bh); |
| 658 | jbd_lock_bh_state(bh); | 660 | jbd_lock_bh_state(bh); |
| 659 | 661 | ||
| 662 | /* If it takes too long to lock the buffer, trace it */ | ||
| 663 | time_lock = jbd2_time_diff(start_lock, jiffies); | ||
| 664 | if (time_lock > HZ/10) | ||
| 665 | trace_jbd2_lock_buffer_stall(bh->b_bdev->bd_dev, | ||
| 666 | jiffies_to_msecs(time_lock)); | ||
| 667 | |||
| 660 | /* We now hold the buffer lock so it is safe to query the buffer | 668 | /* We now hold the buffer lock so it is safe to query the buffer |
| 661 | * state. Is the buffer dirty? | 669 | * state. Is the buffer dirty? |
| 662 | * | 670 | * |
diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h index 070df49e4a1d..c1d1f3eb242d 100644 --- a/include/trace/events/jbd2.h +++ b/include/trace/events/jbd2.h | |||
| @@ -358,6 +358,27 @@ TRACE_EVENT(jbd2_write_superblock, | |||
| 358 | MINOR(__entry->dev), __entry->write_op) | 358 | MINOR(__entry->dev), __entry->write_op) |
| 359 | ); | 359 | ); |
| 360 | 360 | ||
| 361 | TRACE_EVENT(jbd2_lock_buffer_stall, | ||
| 362 | |||
| 363 | TP_PROTO(dev_t dev, unsigned long stall_ms), | ||
| 364 | |||
| 365 | TP_ARGS(dev, stall_ms), | ||
| 366 | |||
| 367 | TP_STRUCT__entry( | ||
| 368 | __field( dev_t, dev ) | ||
| 369 | __field(unsigned long, stall_ms ) | ||
| 370 | ), | ||
| 371 | |||
| 372 | TP_fast_assign( | ||
| 373 | __entry->dev = dev; | ||
| 374 | __entry->stall_ms = stall_ms; | ||
| 375 | ), | ||
| 376 | |||
| 377 | TP_printk("dev %d,%d stall_ms %lu", | ||
| 378 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
| 379 | __entry->stall_ms) | ||
| 380 | ); | ||
| 381 | |||
| 361 | #endif /* _TRACE_JBD2_H */ | 382 | #endif /* _TRACE_JBD2_H */ |
| 362 | 383 | ||
| 363 | /* This part must be outside protection */ | 384 | /* This part must be outside protection */ |
