aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2013-04-21 16:47:54 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-04-21 16:47:54 -0400
commitf783f091e49ce4896e6b026af82d76e0537c6089 (patch)
tree0ff78a05254d4b996bb027d9fac9969d1d6e0b07
parent13fca323e9a8b63c08de7a4e05d3c702516b535d (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.c8
-rw-r--r--include/trace/events/jbd2.h21
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
361TRACE_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 */