add patch fix-fsync-error-handling-after-filesystem-abort
[ext4-patch-queue.git] / cleanup-needed-free-block-estimates-when-starting-a-transaction
blobf98674b623261f3a030b5678b9ac9c506b14d624
1 jbd2: cleanup needed free block estimates when starting a transaction
3 From: Jan Kara <jack@suse.cz>
5 __jbd2_log_space_left() and jbd_space_needed() were kind of odd.
6 jbd_space_needed() accounted also credits needed for currently
7 committing transaction while it didn't account for credits needed for
8 control blocks.  __jbd2_log_space_left() then accounted for control
9 blocks as a fraction of free space.  Since results of these two
10 functions are always only compared against each other, this works
11 correct but is somewhat strange.  Move the estimates so that
12 jbd_space_needed() returns number of blocks needed for a transaction
13 including control blocks and __jbd2_log_space_left() returns free
14 space in the journal (with the committing transaction already
15 subtracted).  Rename functions to jbd2_log_space_left() and
16 jbd2_space_needed() while we are changing them.
18 Reviewed-by: Zheng Liu <wenqing.lz@taobao.com>
19 Signed-off-by: Jan Kara <jack@suse.cz>
20 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
21 ---
22  fs/jbd2/checkpoint.c  |  8 ++++----
23  fs/jbd2/journal.c     | 29 -----------------------------
24  fs/jbd2/transaction.c |  9 +++++----
25  include/linux/jbd2.h  | 32 ++++++++++++++++++++++++++------
26  4 files changed, 35 insertions(+), 43 deletions(-)
28 diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
29 index 65ec076..a572383 100644
30 --- a/fs/jbd2/checkpoint.c
31 +++ b/fs/jbd2/checkpoint.c
32 @@ -120,8 +120,8 @@ void __jbd2_log_wait_for_space(journal_t *journal)
33         int nblocks, space_left;
34         /* assert_spin_locked(&journal->j_state_lock); */
36 -       nblocks = jbd_space_needed(journal);
37 -       while (__jbd2_log_space_left(journal) < nblocks) {
38 +       nblocks = jbd2_space_needed(journal);
39 +       while (jbd2_log_space_left(journal) < nblocks) {
40                 if (journal->j_flags & JBD2_ABORT)
41                         return;
42                 write_unlock(&journal->j_state_lock);
43 @@ -140,8 +140,8 @@ void __jbd2_log_wait_for_space(journal_t *journal)
44                  */
45                 write_lock(&journal->j_state_lock);
46                 spin_lock(&journal->j_list_lock);
47 -               nblocks = jbd_space_needed(journal);
48 -               space_left = __jbd2_log_space_left(journal);
49 +               nblocks = jbd2_space_needed(journal);
50 +               space_left = jbd2_log_space_left(journal);
51                 if (space_left < nblocks) {
52                         int chkpt = journal->j_checkpoint_transactions != NULL;
53                         tid_t tid = 0;
54 diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
55 index e812030..b8827f8 100644
56 --- a/fs/jbd2/journal.c
57 +++ b/fs/jbd2/journal.c
58 @@ -478,35 +478,6 @@ repeat:
59   */
61  /*
62 - * __jbd2_log_space_left: Return the number of free blocks left in the journal.
63 - *
64 - * Called with the journal already locked.
65 - *
66 - * Called under j_state_lock
67 - */
69 -int __jbd2_log_space_left(journal_t *journal)
71 -       int left = journal->j_free;
73 -       /* assert_spin_locked(&journal->j_state_lock); */
75 -       /*
76 -        * Be pessimistic here about the number of those free blocks which
77 -        * might be required for log descriptor control blocks.
78 -        */
80 -#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */
82 -       left -= MIN_LOG_RESERVED_BLOCKS;
84 -       if (left <= 0)
85 -               return 0;
86 -       left -= (left >> 3);
87 -       return left;
90 -/*
91   * Called with j_state_lock locked for writing.
92   * Returns true if a transaction commit was started.
93   */
94 diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
95 index b62b252..dd89ad2 100644
96 --- a/fs/jbd2/transaction.c
97 +++ b/fs/jbd2/transaction.c
98 @@ -283,12 +283,12 @@ repeat:
99          * reduce the free space arbitrarily.  Be careful to account for
100          * those buffers when checkpointing.
101          */
102 -       if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) {
103 +       if (jbd2_log_space_left(journal) < jbd2_space_needed(journal)) {
104                 jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle);
105                 atomic_sub(nblocks, &transaction->t_outstanding_credits);
106                 read_unlock(&journal->j_state_lock);
107                 write_lock(&journal->j_state_lock);
108 -               if (__jbd2_log_space_left(journal) < jbd_space_needed(journal))
109 +               if (jbd2_log_space_left(journal) < jbd2_space_needed(journal))
110                         __jbd2_log_wait_for_space(journal);
111                 write_unlock(&journal->j_state_lock);
112                 goto repeat;
113 @@ -306,7 +306,7 @@ repeat:
114         jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n",
115                   handle, nblocks,
116                   atomic_read(&transaction->t_outstanding_credits),
117 -                 __jbd2_log_space_left(journal));
118 +                 jbd2_log_space_left(journal));
119         read_unlock(&journal->j_state_lock);
121         lock_map_acquire(&handle->h_lockdep_map);
122 @@ -441,7 +441,8 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
123                 goto unlock;
124         }
126 -       if (wanted > __jbd2_log_space_left(journal)) {
127 +       if (wanted + (wanted >> JBD2_CONTROL_BLOCKS_SHIFT) >
128 +           jbd2_log_space_left(journal)) {
129                 jbd_debug(3, "denied handle %p %d blocks: "
130                           "insufficient log space\n", handle, nblocks);
131                 goto unlock;
132 diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
133 index a687c8d..7835719 100644
134 --- a/include/linux/jbd2.h
135 +++ b/include/linux/jbd2.h
136 @@ -1220,7 +1220,6 @@ extern void       jbd2_clear_buffer_revoked_flags(journal_t *journal);
137   * transitions on demand.
138   */
140 -int __jbd2_log_space_left(journal_t *); /* Called with journal locked */
141  int jbd2_log_start_commit(journal_t *journal, tid_t tid);
142  int __jbd2_log_start_commit(journal_t *journal, tid_t tid);
143  int jbd2_journal_start_commit(journal_t *journal, tid_t *tid);
144 @@ -1291,16 +1290,37 @@ extern int jbd2_journal_blocks_per_page(struct inode *inode);
145  extern size_t journal_tag_bytes(journal_t *journal);
147  /*
148 + * We reserve t_outstanding_credits >> JBD2_CONTROL_BLOCKS_SHIFT for
149 + * transaction control blocks.
150 + */
151 +#define JBD2_CONTROL_BLOCKS_SHIFT 5
154   * Return the minimum number of blocks which must be free in the journal
155   * before a new transaction may be started.  Must be called under j_state_lock.
156   */
157 -static inline int jbd_space_needed(journal_t *journal)
158 +static inline int jbd2_space_needed(journal_t *journal)
160         int nblocks = journal->j_max_transaction_buffers;
161 -       if (journal->j_committing_transaction)
162 -               nblocks += atomic_read(&journal->j_committing_transaction->
163 -                                      t_outstanding_credits);
164 -       return nblocks;
165 +       return nblocks + (nblocks >> JBD2_CONTROL_BLOCKS_SHIFT);
169 + * Return number of free blocks in the log. Must be called under j_state_lock.
170 + */
171 +static inline unsigned long jbd2_log_space_left(journal_t *journal)
173 +       /* Allow for rounding errors */
174 +       unsigned long free = journal->j_free - 32;
176 +       if (journal->j_committing_transaction) {
177 +               unsigned long committing = atomic_read(&journal->
178 +                       j_committing_transaction->t_outstanding_credits);
180 +               /* Transaction + control blocks */
181 +               free -= committing + (committing >> JBD2_CONTROL_BLOCKS_SHIFT);
182 +       }
183 +       return free;
186  /*
187 -- 
188 1.8.1.4