diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-08-15 12:15:17 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-08-15 12:15:17 -0400 |
| commit | f3efbe582b5396d134024c03a5fa253f2a85d9a6 (patch) | |
| tree | e4e15b7567b82d24cb1e7327398286a2b88df04c /fs/jbd/commit.c | |
| parent | 05d3ed0a1fe3ea05ab9f3b8d32576a0bc2e19660 (diff) | |
| parent | b635acec48bcaa9183fcbf4e3955616b0d4119b5 (diff) | |
Merge branch 'linus' into x86/gart
Diffstat (limited to 'fs/jbd/commit.c')
| -rw-r--r-- | fs/jbd/commit.c | 68 |
1 files changed, 50 insertions, 18 deletions
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 5a8ca61498ca..ae08c057e751 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 | { |
| @@ -63,7 +63,7 @@ static void release_buffer_page(struct buffer_head *bh) | |||
| 63 | goto nope; | 63 | goto nope; |
| 64 | 64 | ||
| 65 | /* OK, it's a truncated page */ | 65 | /* OK, it's a truncated page */ |
| 66 | if (TestSetPageLocked(page)) | 66 | if (!trylock_page(page)) |
| 67 | goto nope; | 67 | goto nope; |
| 68 | 68 | ||
| 69 | page_cache_get(page); | 69 | page_cache_get(page); |
| @@ -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. |
| @@ -172,7 +185,7 @@ static void journal_do_submit_data(struct buffer_head **wbuf, int bufs) | |||
| 172 | /* | 185 | /* |
| 173 | * Submit all the data buffers to disk | 186 | * Submit all the data buffers to disk |
| 174 | */ | 187 | */ |
| 175 | static void journal_submit_data_buffers(journal_t *journal, | 188 | static int journal_submit_data_buffers(journal_t *journal, |
| 176 | transaction_t *commit_transaction) | 189 | transaction_t *commit_transaction) |
| 177 | { | 190 | { |
| 178 | struct journal_head *jh; | 191 | struct journal_head *jh; |
| @@ -180,6 +193,7 @@ static void journal_submit_data_buffers(journal_t *journal, | |||
| 180 | int locked; | 193 | int locked; |
| 181 | int bufs = 0; | 194 | int bufs = 0; |
| 182 | struct buffer_head **wbuf = journal->j_wbuf; | 195 | struct buffer_head **wbuf = journal->j_wbuf; |
| 196 | int err = 0; | ||
| 183 | 197 | ||
| 184 | /* | 198 | /* |
| 185 | * Whenever we unlock the journal and sleep, things can get added | 199 | * Whenever we unlock the journal and sleep, things can get added |
| @@ -207,7 +221,7 @@ write_out_data: | |||
| 207 | * blocking lock_buffer(). | 221 | * blocking lock_buffer(). |
| 208 | */ | 222 | */ |
| 209 | if (buffer_dirty(bh)) { | 223 | if (buffer_dirty(bh)) { |
| 210 | if (test_set_buffer_locked(bh)) { | 224 | if (!trylock_buffer(bh)) { |
| 211 | BUFFER_TRACE(bh, "needs blocking lock"); | 225 | BUFFER_TRACE(bh, "needs blocking lock"); |
| 212 | spin_unlock(&journal->j_list_lock); | 226 | spin_unlock(&journal->j_list_lock); |
| 213 | /* Write out all data to prevent deadlocks */ | 227 | /* Write out all data to prevent deadlocks */ |
| @@ -231,7 +245,7 @@ write_out_data: | |||
| 231 | if (locked) | 245 | if (locked) |
| 232 | unlock_buffer(bh); | 246 | unlock_buffer(bh); |
| 233 | BUFFER_TRACE(bh, "already cleaned up"); | 247 | BUFFER_TRACE(bh, "already cleaned up"); |
| 234 | put_bh(bh); | 248 | release_data_buffer(bh); |
| 235 | continue; | 249 | continue; |
| 236 | } | 250 | } |
| 237 | if (locked && test_clear_buffer_dirty(bh)) { | 251 | if (locked && test_clear_buffer_dirty(bh)) { |
| @@ -253,15 +267,17 @@ write_out_data: | |||
| 253 | put_bh(bh); | 267 | put_bh(bh); |
| 254 | } else { | 268 | } else { |
| 255 | BUFFER_TRACE(bh, "writeout complete: unfile"); | 269 | BUFFER_TRACE(bh, "writeout complete: unfile"); |
| 270 | if (unlikely(!buffer_uptodate(bh))) | ||
| 271 | err = -EIO; | ||
| 256 | __journal_unfile_buffer(jh); | 272 | __journal_unfile_buffer(jh); |
| 257 | jbd_unlock_bh_state(bh); | 273 | jbd_unlock_bh_state(bh); |
| 258 | if (locked) | 274 | if (locked) |
| 259 | unlock_buffer(bh); | 275 | unlock_buffer(bh); |
| 260 | journal_remove_journal_head(bh); | 276 | journal_remove_journal_head(bh); |
| 261 | /* Once for our safety reference, once for | 277 | /* One for our safety reference, other for |
| 262 | * journal_remove_journal_head() */ | 278 | * journal_remove_journal_head() */ |
| 263 | put_bh(bh); | 279 | put_bh(bh); |
| 264 | put_bh(bh); | 280 | release_data_buffer(bh); |
| 265 | } | 281 | } |
| 266 | 282 | ||
| 267 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { | 283 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { |
| @@ -271,6 +287,8 @@ write_out_data: | |||
| 271 | } | 287 | } |
| 272 | spin_unlock(&journal->j_list_lock); | 288 | spin_unlock(&journal->j_list_lock); |
| 273 | journal_do_submit_data(wbuf, bufs); | 289 | journal_do_submit_data(wbuf, bufs); |
| 290 | |||
| 291 | return err; | ||
| 274 | } | 292 | } |
| 275 | 293 | ||
| 276 | /* | 294 | /* |
| @@ -410,8 +428,7 @@ void journal_commit_transaction(journal_t *journal) | |||
| 410 | * Now start flushing things to disk, in the order they appear | 428 | * Now start flushing things to disk, in the order they appear |
| 411 | * on the transaction lists. Data blocks go first. | 429 | * on the transaction lists. Data blocks go first. |
| 412 | */ | 430 | */ |
| 413 | err = 0; | 431 | err = journal_submit_data_buffers(journal, commit_transaction); |
| 414 | journal_submit_data_buffers(journal, commit_transaction); | ||
| 415 | 432 | ||
| 416 | /* | 433 | /* |
| 417 | * Wait for all previously submitted IO to complete. | 434 | * Wait for all previously submitted IO to complete. |
| @@ -426,10 +443,21 @@ void journal_commit_transaction(journal_t *journal) | |||
| 426 | if (buffer_locked(bh)) { | 443 | if (buffer_locked(bh)) { |
| 427 | spin_unlock(&journal->j_list_lock); | 444 | spin_unlock(&journal->j_list_lock); |
| 428 | wait_on_buffer(bh); | 445 | wait_on_buffer(bh); |
| 429 | if (unlikely(!buffer_uptodate(bh))) | ||
| 430 | err = -EIO; | ||
| 431 | spin_lock(&journal->j_list_lock); | 446 | spin_lock(&journal->j_list_lock); |
| 432 | } | 447 | } |
| 448 | if (unlikely(!buffer_uptodate(bh))) { | ||
| 449 | if (!trylock_page(bh->b_page)) { | ||
| 450 | spin_unlock(&journal->j_list_lock); | ||
| 451 | lock_page(bh->b_page); | ||
| 452 | spin_lock(&journal->j_list_lock); | ||
| 453 | } | ||
| 454 | if (bh->b_page->mapping) | ||
| 455 | set_bit(AS_EIO, &bh->b_page->mapping->flags); | ||
| 456 | |||
| 457 | unlock_page(bh->b_page); | ||
| 458 | SetPageError(bh->b_page); | ||
| 459 | err = -EIO; | ||
| 460 | } | ||
| 433 | if (!inverted_lock(journal, bh)) { | 461 | if (!inverted_lock(journal, bh)) { |
| 434 | put_bh(bh); | 462 | put_bh(bh); |
| 435 | spin_lock(&journal->j_list_lock); | 463 | spin_lock(&journal->j_list_lock); |
| @@ -443,17 +471,21 @@ void journal_commit_transaction(journal_t *journal) | |||
| 443 | } else { | 471 | } else { |
| 444 | jbd_unlock_bh_state(bh); | 472 | jbd_unlock_bh_state(bh); |
| 445 | } | 473 | } |
| 446 | put_bh(bh); | 474 | release_data_buffer(bh); |
| 447 | cond_resched_lock(&journal->j_list_lock); | 475 | cond_resched_lock(&journal->j_list_lock); |
| 448 | } | 476 | } |
| 449 | spin_unlock(&journal->j_list_lock); | 477 | spin_unlock(&journal->j_list_lock); |
| 450 | 478 | ||
| 451 | if (err) | 479 | if (err) { |
| 452 | journal_abort(journal, err); | 480 | char b[BDEVNAME_SIZE]; |
| 453 | 481 | ||
| 454 | journal_write_revoke_records(journal, commit_transaction); | 482 | printk(KERN_WARNING |
| 483 | "JBD: Detected IO errors while flushing file data " | ||
| 484 | "on %s\n", bdevname(journal->j_fs_dev, b)); | ||
| 485 | err = 0; | ||
| 486 | } | ||
| 455 | 487 | ||
| 456 | jbd_debug(3, "JBD: commit phase 2\n"); | 488 | journal_write_revoke_records(journal, commit_transaction); |
| 457 | 489 | ||
| 458 | /* | 490 | /* |
| 459 | * If we found any dirty or locked buffers, then we should have | 491 | * If we found any dirty or locked buffers, then we should have |
