diff options
author | Jan Kara <jack@suse.cz> | 2013-06-04 12:12:57 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-06-04 12:12:57 -0400 |
commit | 76c39904561004ac8675f858a290129e439d5168 (patch) | |
tree | 46b2c2800ffbad5dd2ebd4ceb66893414630df2b | |
parent | 2f387f849b6a5be5b4b914c43a8af0406279db11 (diff) |
jbd2: cleanup needed free block estimates when starting a transaction
__jbd2_log_space_left() and jbd_space_needed() were kind of odd.
jbd_space_needed() accounted also credits needed for currently
committing transaction while it didn't account for credits needed for
control blocks. __jbd2_log_space_left() then accounted for control
blocks as a fraction of free space. Since results of these two
functions are always only compared against each other, this works
correct but is somewhat strange. Move the estimates so that
jbd_space_needed() returns number of blocks needed for a transaction
including control blocks and __jbd2_log_space_left() returns free
space in the journal (with the committing transaction already
subtracted). Rename functions to jbd2_log_space_left() and
jbd2_space_needed() while we are changing them.
Reviewed-by: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | fs/jbd2/checkpoint.c | 8 | ||||
-rw-r--r-- | fs/jbd2/journal.c | 29 | ||||
-rw-r--r-- | fs/jbd2/transaction.c | 9 | ||||
-rw-r--r-- | include/linux/jbd2.h | 32 |
4 files changed, 35 insertions, 43 deletions
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 65ec076e41f2..a572383bcf99 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c | |||
@@ -120,8 +120,8 @@ void __jbd2_log_wait_for_space(journal_t *journal) | |||
120 | int nblocks, space_left; | 120 | int nblocks, space_left; |
121 | /* assert_spin_locked(&journal->j_state_lock); */ | 121 | /* assert_spin_locked(&journal->j_state_lock); */ |
122 | 122 | ||
123 | nblocks = jbd_space_needed(journal); | 123 | nblocks = jbd2_space_needed(journal); |
124 | while (__jbd2_log_space_left(journal) < nblocks) { | 124 | while (jbd2_log_space_left(journal) < nblocks) { |
125 | if (journal->j_flags & JBD2_ABORT) | 125 | if (journal->j_flags & JBD2_ABORT) |
126 | return; | 126 | return; |
127 | write_unlock(&journal->j_state_lock); | 127 | write_unlock(&journal->j_state_lock); |
@@ -140,8 +140,8 @@ void __jbd2_log_wait_for_space(journal_t *journal) | |||
140 | */ | 140 | */ |
141 | write_lock(&journal->j_state_lock); | 141 | write_lock(&journal->j_state_lock); |
142 | spin_lock(&journal->j_list_lock); | 142 | spin_lock(&journal->j_list_lock); |
143 | nblocks = jbd_space_needed(journal); | 143 | nblocks = jbd2_space_needed(journal); |
144 | space_left = __jbd2_log_space_left(journal); | 144 | space_left = jbd2_log_space_left(journal); |
145 | if (space_left < nblocks) { | 145 | if (space_left < nblocks) { |
146 | int chkpt = journal->j_checkpoint_transactions != NULL; | 146 | int chkpt = journal->j_checkpoint_transactions != NULL; |
147 | tid_t tid = 0; | 147 | tid_t tid = 0; |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 5ef0712e2f7a..8e5486d62e89 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -478,35 +478,6 @@ repeat: | |||
478 | */ | 478 | */ |
479 | 479 | ||
480 | /* | 480 | /* |
481 | * __jbd2_log_space_left: Return the number of free blocks left in the journal. | ||
482 | * | ||
483 | * Called with the journal already locked. | ||
484 | * | ||
485 | * Called under j_state_lock | ||
486 | */ | ||
487 | |||
488 | int __jbd2_log_space_left(journal_t *journal) | ||
489 | { | ||
490 | int left = journal->j_free; | ||
491 | |||
492 | /* assert_spin_locked(&journal->j_state_lock); */ | ||
493 | |||
494 | /* | ||
495 | * Be pessimistic here about the number of those free blocks which | ||
496 | * might be required for log descriptor control blocks. | ||
497 | */ | ||
498 | |||
499 | #define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */ | ||
500 | |||
501 | left -= MIN_LOG_RESERVED_BLOCKS; | ||
502 | |||
503 | if (left <= 0) | ||
504 | return 0; | ||
505 | left -= (left >> 3); | ||
506 | return left; | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * Called with j_state_lock locked for writing. | 481 | * Called with j_state_lock locked for writing. |
511 | * Returns true if a transaction commit was started. | 482 | * Returns true if a transaction commit was started. |
512 | */ | 483 | */ |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 60361c634b5d..f9cd43190b43 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -283,12 +283,12 @@ repeat: | |||
283 | * reduce the free space arbitrarily. Be careful to account for | 283 | * reduce the free space arbitrarily. Be careful to account for |
284 | * those buffers when checkpointing. | 284 | * those buffers when checkpointing. |
285 | */ | 285 | */ |
286 | if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) { | 286 | if (jbd2_log_space_left(journal) < jbd2_space_needed(journal)) { |
287 | jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); | 287 | jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); |
288 | atomic_sub(nblocks, &transaction->t_outstanding_credits); | 288 | atomic_sub(nblocks, &transaction->t_outstanding_credits); |
289 | read_unlock(&journal->j_state_lock); | 289 | read_unlock(&journal->j_state_lock); |
290 | write_lock(&journal->j_state_lock); | 290 | write_lock(&journal->j_state_lock); |
291 | if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) | 291 | if (jbd2_log_space_left(journal) < jbd2_space_needed(journal)) |
292 | __jbd2_log_wait_for_space(journal); | 292 | __jbd2_log_wait_for_space(journal); |
293 | write_unlock(&journal->j_state_lock); | 293 | write_unlock(&journal->j_state_lock); |
294 | goto repeat; | 294 | goto repeat; |
@@ -306,7 +306,7 @@ repeat: | |||
306 | jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", | 306 | jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", |
307 | handle, nblocks, | 307 | handle, nblocks, |
308 | atomic_read(&transaction->t_outstanding_credits), | 308 | atomic_read(&transaction->t_outstanding_credits), |
309 | __jbd2_log_space_left(journal)); | 309 | jbd2_log_space_left(journal)); |
310 | read_unlock(&journal->j_state_lock); | 310 | read_unlock(&journal->j_state_lock); |
311 | 311 | ||
312 | lock_map_acquire(&handle->h_lockdep_map); | 312 | lock_map_acquire(&handle->h_lockdep_map); |
@@ -441,7 +441,8 @@ int jbd2_journal_extend(handle_t *handle, int nblocks) | |||
441 | goto unlock; | 441 | goto unlock; |
442 | } | 442 | } |
443 | 443 | ||
444 | if (wanted > __jbd2_log_space_left(journal)) { | 444 | if (wanted + (wanted >> JBD2_CONTROL_BLOCKS_SHIFT) > |
445 | jbd2_log_space_left(journal)) { | ||
445 | jbd_debug(3, "denied handle %p %d blocks: " | 446 | jbd_debug(3, "denied handle %p %d blocks: " |
446 | "insufficient log space\n", handle, nblocks); | 447 | "insufficient log space\n", handle, nblocks); |
447 | goto unlock; | 448 | goto unlock; |
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index e33e84b3d5c8..7a1f6cd864c8 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h | |||
@@ -1220,7 +1220,6 @@ extern void jbd2_clear_buffer_revoked_flags(journal_t *journal); | |||
1220 | * transitions on demand. | 1220 | * transitions on demand. |
1221 | */ | 1221 | */ |
1222 | 1222 | ||
1223 | int __jbd2_log_space_left(journal_t *); /* Called with journal locked */ | ||
1224 | int jbd2_log_start_commit(journal_t *journal, tid_t tid); | 1223 | int jbd2_log_start_commit(journal_t *journal, tid_t tid); |
1225 | int __jbd2_log_start_commit(journal_t *journal, tid_t tid); | 1224 | int __jbd2_log_start_commit(journal_t *journal, tid_t tid); |
1226 | int jbd2_journal_start_commit(journal_t *journal, tid_t *tid); | 1225 | int jbd2_journal_start_commit(journal_t *journal, tid_t *tid); |
@@ -1291,16 +1290,37 @@ extern int jbd2_journal_blocks_per_page(struct inode *inode); | |||
1291 | extern size_t journal_tag_bytes(journal_t *journal); | 1290 | extern size_t journal_tag_bytes(journal_t *journal); |
1292 | 1291 | ||
1293 | /* | 1292 | /* |
1293 | * We reserve t_outstanding_credits >> JBD2_CONTROL_BLOCKS_SHIFT for | ||
1294 | * transaction control blocks. | ||
1295 | */ | ||
1296 | #define JBD2_CONTROL_BLOCKS_SHIFT 5 | ||
1297 | |||
1298 | /* | ||
1294 | * Return the minimum number of blocks which must be free in the journal | 1299 | * Return the minimum number of blocks which must be free in the journal |
1295 | * before a new transaction may be started. Must be called under j_state_lock. | 1300 | * before a new transaction may be started. Must be called under j_state_lock. |
1296 | */ | 1301 | */ |
1297 | static inline int jbd_space_needed(journal_t *journal) | 1302 | static inline int jbd2_space_needed(journal_t *journal) |
1298 | { | 1303 | { |
1299 | int nblocks = journal->j_max_transaction_buffers; | 1304 | int nblocks = journal->j_max_transaction_buffers; |
1300 | if (journal->j_committing_transaction) | 1305 | return nblocks + (nblocks >> JBD2_CONTROL_BLOCKS_SHIFT); |
1301 | nblocks += atomic_read(&journal->j_committing_transaction-> | 1306 | } |
1302 | t_outstanding_credits); | 1307 | |
1303 | return nblocks; | 1308 | /* |
1309 | * Return number of free blocks in the log. Must be called under j_state_lock. | ||
1310 | */ | ||
1311 | static inline unsigned long jbd2_log_space_left(journal_t *journal) | ||
1312 | { | ||
1313 | /* Allow for rounding errors */ | ||
1314 | unsigned long free = journal->j_free - 32; | ||
1315 | |||
1316 | if (journal->j_committing_transaction) { | ||
1317 | unsigned long committing = atomic_read(&journal-> | ||
1318 | j_committing_transaction->t_outstanding_credits); | ||
1319 | |||
1320 | /* Transaction + control blocks */ | ||
1321 | free -= committing + (committing >> JBD2_CONTROL_BLOCKS_SHIFT); | ||
1322 | } | ||
1323 | return free; | ||
1304 | } | 1324 | } |
1305 | 1325 | ||
1306 | /* | 1326 | /* |