diff options
Diffstat (limited to 'fs/jbd/commit.c')
-rw-r--r-- | fs/jbd/commit.c | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 5a8ca61498ca..f943b9b3f208 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
@@ -36,7 +36,7 @@ static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) | |||
36 | 36 | ||
37 | /* | 37 | /* |
38 | * When an ext3-ordered file is truncated, it is possible that many pages are | 38 | * When an ext3-ordered file is truncated, it is possible that many pages are |
39 | * not sucessfully freed, because they are attached to a committing transaction. | 39 | * not successfully freed, because they are attached to a committing transaction. |
40 | * After the transaction commits, these pages are left on the LRU, with no | 40 | * After the transaction commits, these pages are left on the LRU, with no |
41 | * ->mapping, and with attached buffers. These pages are trivially reclaimable | 41 | * ->mapping, and with attached buffers. These pages are trivially reclaimable |
42 | * by the VM, but their apparent absence upsets the VM accounting, and it makes | 42 | * by the VM, but their apparent absence upsets the VM accounting, and it makes |
@@ -45,8 +45,8 @@ static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) | |||
45 | * So here, we have a buffer which has just come off the forget list. Look to | 45 | * So here, we have a buffer which has just come off the forget list. Look to |
46 | * see if we can strip all buffers from the backing page. | 46 | * see if we can strip all buffers from the backing page. |
47 | * | 47 | * |
48 | * Called under lock_journal(), and possibly under journal_datalist_lock. The | 48 | * Called under journal->j_list_lock. The caller provided us with a ref |
49 | * caller provided us with a ref against the buffer, and we drop that here. | 49 | * against the buffer, and we drop that here. |
50 | */ | 50 | */ |
51 | static void release_buffer_page(struct buffer_head *bh) | 51 | static void release_buffer_page(struct buffer_head *bh) |
52 | { | 52 | { |
@@ -78,6 +78,19 @@ nope: | |||
78 | } | 78 | } |
79 | 79 | ||
80 | /* | 80 | /* |
81 | * Decrement reference counter for data buffer. If it has been marked | ||
82 | * 'BH_Freed', release it and the page to which it belongs if possible. | ||
83 | */ | ||
84 | static void release_data_buffer(struct buffer_head *bh) | ||
85 | { | ||
86 | if (buffer_freed(bh)) { | ||
87 | clear_buffer_freed(bh); | ||
88 | release_buffer_page(bh); | ||
89 | } else | ||
90 | put_bh(bh); | ||
91 | } | ||
92 | |||
93 | /* | ||
81 | * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is | 94 | * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is |
82 | * held. For ranking reasons we must trylock. If we lose, schedule away and | 95 | * held. For ranking reasons we must trylock. If we lose, schedule away and |
83 | * return 0. j_list_lock is dropped in this case. | 96 | * return 0. j_list_lock is dropped in this case. |
@@ -231,7 +244,7 @@ write_out_data: | |||
231 | if (locked) | 244 | if (locked) |
232 | unlock_buffer(bh); | 245 | unlock_buffer(bh); |
233 | BUFFER_TRACE(bh, "already cleaned up"); | 246 | BUFFER_TRACE(bh, "already cleaned up"); |
234 | put_bh(bh); | 247 | release_data_buffer(bh); |
235 | continue; | 248 | continue; |
236 | } | 249 | } |
237 | if (locked && test_clear_buffer_dirty(bh)) { | 250 | if (locked && test_clear_buffer_dirty(bh)) { |
@@ -258,10 +271,10 @@ write_out_data: | |||
258 | if (locked) | 271 | if (locked) |
259 | unlock_buffer(bh); | 272 | unlock_buffer(bh); |
260 | journal_remove_journal_head(bh); | 273 | journal_remove_journal_head(bh); |
261 | /* Once for our safety reference, once for | 274 | /* One for our safety reference, other for |
262 | * journal_remove_journal_head() */ | 275 | * journal_remove_journal_head() */ |
263 | put_bh(bh); | 276 | put_bh(bh); |
264 | put_bh(bh); | 277 | release_data_buffer(bh); |
265 | } | 278 | } |
266 | 279 | ||
267 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { | 280 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { |
@@ -443,7 +456,7 @@ void journal_commit_transaction(journal_t *journal) | |||
443 | } else { | 456 | } else { |
444 | jbd_unlock_bh_state(bh); | 457 | jbd_unlock_bh_state(bh); |
445 | } | 458 | } |
446 | put_bh(bh); | 459 | release_data_buffer(bh); |
447 | cond_resched_lock(&journal->j_list_lock); | 460 | cond_resched_lock(&journal->j_list_lock); |
448 | } | 461 | } |
449 | spin_unlock(&journal->j_list_lock); | 462 | spin_unlock(&journal->j_list_lock); |
@@ -453,8 +466,6 @@ void journal_commit_transaction(journal_t *journal) | |||
453 | 466 | ||
454 | journal_write_revoke_records(journal, commit_transaction); | 467 | journal_write_revoke_records(journal, commit_transaction); |
455 | 468 | ||
456 | jbd_debug(3, "JBD: commit phase 2\n"); | ||
457 | |||
458 | /* | 469 | /* |
459 | * If we found any dirty or locked buffers, then we should have | 470 | * If we found any dirty or locked buffers, then we should have |
460 | * looped back up to the write_out_data label. If there weren't | 471 | * looped back up to the write_out_data label. If there weren't |