1 jbd: fix assertion failure in journal_next_log_block
2 From: Josef Bacik <jbacik@redhat.com>
4 Fix assertion failure in journal_next_log_block
6 The way jbd tries to determine if there is enough space left on the journal in
7 order to start a new transaction is looking at the space left in the journal and
8 the space needed for the committing transaction, which is 1/4 of the journal +
9 the number of t_outstanding_credits for that transaction. In this case its
10 assumed that t_outstanding_credits accurately represents the number of credits
11 waiting to be written to the journal, but this sometimes isn't the case. The
12 transaction has two counters for buffers, t_outstanding_credits which is used in
13 conjunction with handles that are added to the transaction, and t_nr_buffers
14 which is only incremented/decremented when buffers are added/removed from the
15 transaction and are actually destined to be journaled. Normally these two
16 counters are the same, however there are cases where the committing transaction
17 can have buffers moved to the next running transaction, for example any buffers
18 on the committing transactions t_reserved list would be moved to the next
19 (running) transaction, and if it had been dirtied in the process it would
20 immediately make it onto the t_updates list, which would increment t_nr_buffers
21 but not t_outstanding_credits. So you get into this situation where
22 t_nr_buffers (the actual number of buffers that are on the transaction) is
23 greater than the number of buffers accounted for via t_outstanding_credits.
24 This presents a problem since as we loop through writting buffers to the
25 journal, we decrement t_outstanding_credits, and if t_nr_buffers is more than
26 t_outstanding_credits then we end up with a negative number for
27 t_outstanding_credits, which means we start saying we need less than 1/4 of the
28 journal for our committing transaction and allow more transactions than we can
29 handle to start, and then bam we fail because journal_next_log_block doesn't
30 have enough free blocks in order to handle the request. This has been tested
31 and fixes the issue (which could not be reproduced by me but several other
32 people could get it to reproduce using postmark), and although I couldn't
33 reproduce the assertion, I could very easily reproduce the situation where
34 t_outstanding_credits was < than t_nr_buffers.
37 Signed-off-by: Josef Bacik <jbacik@redhat.com>
38 Signed-off-by: Mingming Cao <cmm@us.ibm.com>
42 fs/jbd/commit.c | 7 -------
43 fs/jbd2/commit.c | 9 +--------
44 include/linux/jbd.h | 3 +--
45 include/linux/jbd2.h | 3 +--
46 4 files changed, 3 insertions(+), 19 deletions(-)
48 Index: linux-2.6.24/fs/jbd/commit.c
49 ===================================================================
50 --- linux-2.6.24.orig/fs/jbd/commit.c 2008-01-31 16:31:37.000000000 -0800
51 +++ linux-2.6.24/fs/jbd/commit.c 2008-01-31 16:33:21.000000000 -0800
52 @@ -559,13 +559,6 @@ void journal_commit_transaction(journal_
57 - * start_this_handle() uses t_outstanding_credits to determine
58 - * the free space in the log, but this counter is changed
59 - * by journal_next_log_block() also.
61 - commit_transaction->t_outstanding_credits--;
63 /* Bump b_count to prevent truncate from stumbling over
64 the shadowed buffer! @@@ This can go if we ever get
65 rid of the BJ_IO/BJ_Shadow pairing of buffers. */
66 Index: linux-2.6.24/fs/jbd2/commit.c
67 ===================================================================
68 --- linux-2.6.24.orig/fs/jbd2/commit.c 2008-01-31 16:31:37.000000000 -0800
69 +++ linux-2.6.24/fs/jbd2/commit.c 2008-01-31 16:33:21.000000000 -0800
70 @@ -580,7 +580,7 @@ void jbd2_journal_commit_transaction(jou
71 stats.u.run.rs_logging = jiffies;
72 stats.u.run.rs_flushing = jbd2_time_diff(stats.u.run.rs_flushing,
73 stats.u.run.rs_logging);
74 - stats.u.run.rs_blocks = commit_transaction->t_outstanding_credits;
75 + stats.u.run.rs_blocks = commit_transaction->t_nr_buffers;
76 stats.u.run.rs_blocks_logged = 0;
79 @@ -655,13 +655,6 @@ void jbd2_journal_commit_transaction(jou
84 - * start_this_handle() uses t_outstanding_credits to determine
85 - * the free space in the log, but this counter is changed
86 - * by jbd2_journal_next_log_block() also.
88 - commit_transaction->t_outstanding_credits--;
90 /* Bump b_count to prevent truncate from stumbling over
91 the shadowed buffer! @@@ This can go if we ever get
92 rid of the BJ_IO/BJ_Shadow pairing of buffers. */
93 Index: linux-2.6.24/include/linux/jbd.h
94 ===================================================================
95 --- linux-2.6.24.orig/include/linux/jbd.h 2008-01-31 16:31:37.000000000 -0800
96 +++ linux-2.6.24/include/linux/jbd.h 2008-01-31 16:33:37.000000000 -0800
97 @@ -1055,8 +1055,7 @@ static inline int jbd_space_needed(journ
99 int nblocks = journal->j_max_transaction_buffers;
100 if (journal->j_committing_transaction)
101 - nblocks += journal->j_committing_transaction->
102 - t_outstanding_credits;
103 + nblocks += journal->j_committing_transaction->t_nr_buffers;
107 Index: linux-2.6.24/include/linux/jbd2.h
108 ===================================================================
109 --- linux-2.6.24.orig/include/linux/jbd2.h 2008-01-31 16:31:37.000000000 -0800
110 +++ linux-2.6.24/include/linux/jbd2.h 2008-01-31 16:33:55.000000000 -0800
111 @@ -1167,8 +1167,7 @@ static inline int jbd_space_needed(journ
113 int nblocks = journal->j_max_transaction_buffers;
114 if (journal->j_committing_transaction)
115 - nblocks += journal->j_committing_transaction->
116 - t_outstanding_credits;
117 + nblocks += journal->j_committing_transaction->t_nr_buffers;