Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+29
+8
fs/jbd2/transaction.c
··· 639 639 int error; 640 640 char *frozen_buffer = NULL; 641 641 int need_copy = 0; 642 + unsigned long start_lock, time_lock; 642 643 643 644 if (is_handle_aborted(handle)) 644 645 return -EROFS; ··· 655 654 656 655 /* @@@ Need to check for errors here at some point. */ 657 656 657 + start_lock = jiffies; 658 658 lock_buffer(bh); 659 659 jbd_lock_bh_state(bh); 660 + 661 + /* If it takes too long to lock the buffer, trace it */ 662 + time_lock = jbd2_time_diff(start_lock, jiffies); 663 + if (time_lock > HZ/10) 664 + trace_jbd2_lock_buffer_stall(bh->b_bdev->bd_dev, 665 + jiffies_to_msecs(time_lock)); 660 666 661 667 /* We now hold the buffer lock so it is safe to query the buffer 662 668 * state. Is the buffer dirty?
+21
include/trace/events/jbd2.h
··· 358 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 382 #endif /* _TRACE_JBD2_H */ 362 383 363 384 /* This part must be outside protection */