diff options
author | Theodore Ts'o <tytso@mit.edu> | 2013-07-01 08:12:41 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-07-01 08:12:41 -0400 |
commit | 41a5b913197c3a25fddef1735dc9b3d1fdc57428 (patch) | |
tree | 2377e2cf3164271457785f1356ff77f8c4b79b2b /fs/jbd2 | |
parent | 21ddd568c133024196d394c43923f55cad1e7bd0 (diff) |
jbd2: invalidate handle if jbd2_journal_restart() fails
If jbd2_journal_restart() fails the handle will have been disconnected
from the current transaction. In this situation, the handle must not
be used for for any jbd2 function other than jbd2_journal_stop().
Enforce this with by treating a handle which has a NULL transaction
pointer as an aborted handle, and issue a kernel warning if
jbd2_journal_extent(), jbd2_journal_get_write_access(),
jbd2_journal_dirty_metadata(), etc. is called with an invalid handle.
This commit also fixes a bug where jbd2_journal_stop() would trip over
a kernel jbd2 assertion check when trying to free an invalid handle.
Also move the responsibility of setting current->journal_info to
start_this_handle(), simplifying the three users of this function.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reported-by: Younger Liu <younger.liu@huawei.com>
Cc: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/jbd2')
-rw-r--r-- | fs/jbd2/transaction.c | 74 |
1 files changed, 43 insertions, 31 deletions
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 383b0fbc6e19..7aa9a32573bb 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -368,6 +368,7 @@ repeat: | |||
368 | atomic_read(&transaction->t_outstanding_credits), | 368 | atomic_read(&transaction->t_outstanding_credits), |
369 | jbd2_log_space_left(journal)); | 369 | jbd2_log_space_left(journal)); |
370 | read_unlock(&journal->j_state_lock); | 370 | read_unlock(&journal->j_state_lock); |
371 | current->journal_info = handle; | ||
371 | 372 | ||
372 | lock_map_acquire(&handle->h_lockdep_map); | 373 | lock_map_acquire(&handle->h_lockdep_map); |
373 | jbd2_journal_free_transaction(new_transaction); | 374 | jbd2_journal_free_transaction(new_transaction); |
@@ -442,14 +443,11 @@ handle_t *jbd2__journal_start(journal_t *journal, int nblocks, int rsv_blocks, | |||
442 | handle->h_rsv_handle = rsv_handle; | 443 | handle->h_rsv_handle = rsv_handle; |
443 | } | 444 | } |
444 | 445 | ||
445 | current->journal_info = handle; | ||
446 | |||
447 | err = start_this_handle(journal, handle, gfp_mask); | 446 | err = start_this_handle(journal, handle, gfp_mask); |
448 | if (err < 0) { | 447 | if (err < 0) { |
449 | if (handle->h_rsv_handle) | 448 | if (handle->h_rsv_handle) |
450 | jbd2_free_handle(handle->h_rsv_handle); | 449 | jbd2_free_handle(handle->h_rsv_handle); |
451 | jbd2_free_handle(handle); | 450 | jbd2_free_handle(handle); |
452 | current->journal_info = NULL; | ||
453 | return ERR_PTR(err); | 451 | return ERR_PTR(err); |
454 | } | 452 | } |
455 | handle->h_type = type; | 453 | handle->h_type = type; |
@@ -511,16 +509,13 @@ int jbd2_journal_start_reserved(handle_t *handle, unsigned int type, | |||
511 | } | 509 | } |
512 | 510 | ||
513 | handle->h_journal = NULL; | 511 | handle->h_journal = NULL; |
514 | current->journal_info = handle; | ||
515 | /* | 512 | /* |
516 | * GFP_NOFS is here because callers are likely from writeback or | 513 | * GFP_NOFS is here because callers are likely from writeback or |
517 | * similarly constrained call sites | 514 | * similarly constrained call sites |
518 | */ | 515 | */ |
519 | ret = start_this_handle(journal, handle, GFP_NOFS); | 516 | ret = start_this_handle(journal, handle, GFP_NOFS); |
520 | if (ret < 0) { | 517 | if (ret < 0) |
521 | current->journal_info = NULL; | ||
522 | jbd2_journal_free_reserved(handle); | 518 | jbd2_journal_free_reserved(handle); |
523 | } | ||
524 | handle->h_type = type; | 519 | handle->h_type = type; |
525 | handle->h_line_no = line_no; | 520 | handle->h_line_no = line_no; |
526 | return ret; | 521 | return ret; |
@@ -550,20 +545,21 @@ EXPORT_SYMBOL(jbd2_journal_start_reserved); | |||
550 | int jbd2_journal_extend(handle_t *handle, int nblocks) | 545 | int jbd2_journal_extend(handle_t *handle, int nblocks) |
551 | { | 546 | { |
552 | transaction_t *transaction = handle->h_transaction; | 547 | transaction_t *transaction = handle->h_transaction; |
553 | journal_t *journal = transaction->t_journal; | 548 | journal_t *journal; |
554 | int result; | 549 | int result; |
555 | int wanted; | 550 | int wanted; |
556 | 551 | ||
557 | result = -EIO; | 552 | WARN_ON(!transaction); |
558 | if (is_handle_aborted(handle)) | 553 | if (is_handle_aborted(handle)) |
559 | goto out; | 554 | return -EROFS; |
555 | journal = transaction->t_journal; | ||
560 | 556 | ||
561 | result = 1; | 557 | result = 1; |
562 | 558 | ||
563 | read_lock(&journal->j_state_lock); | 559 | read_lock(&journal->j_state_lock); |
564 | 560 | ||
565 | /* Don't extend a locked-down transaction! */ | 561 | /* Don't extend a locked-down transaction! */ |
566 | if (handle->h_transaction->t_state != T_RUNNING) { | 562 | if (transaction->t_state != T_RUNNING) { |
567 | jbd_debug(3, "denied handle %p %d blocks: " | 563 | jbd_debug(3, "denied handle %p %d blocks: " |
568 | "transaction not running\n", handle, nblocks); | 564 | "transaction not running\n", handle, nblocks); |
569 | goto error_out; | 565 | goto error_out; |
@@ -589,7 +585,7 @@ int jbd2_journal_extend(handle_t *handle, int nblocks) | |||
589 | } | 585 | } |
590 | 586 | ||
591 | trace_jbd2_handle_extend(journal->j_fs_dev->bd_dev, | 587 | trace_jbd2_handle_extend(journal->j_fs_dev->bd_dev, |
592 | handle->h_transaction->t_tid, | 588 | transaction->t_tid, |
593 | handle->h_type, handle->h_line_no, | 589 | handle->h_type, handle->h_line_no, |
594 | handle->h_buffer_credits, | 590 | handle->h_buffer_credits, |
595 | nblocks); | 591 | nblocks); |
@@ -603,7 +599,6 @@ unlock: | |||
603 | spin_unlock(&transaction->t_handle_lock); | 599 | spin_unlock(&transaction->t_handle_lock); |
604 | error_out: | 600 | error_out: |
605 | read_unlock(&journal->j_state_lock); | 601 | read_unlock(&journal->j_state_lock); |
606 | out: | ||
607 | return result; | 602 | return result; |
608 | } | 603 | } |
609 | 604 | ||
@@ -626,14 +621,16 @@ out: | |||
626 | int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask) | 621 | int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask) |
627 | { | 622 | { |
628 | transaction_t *transaction = handle->h_transaction; | 623 | transaction_t *transaction = handle->h_transaction; |
629 | journal_t *journal = transaction->t_journal; | 624 | journal_t *journal; |
630 | tid_t tid; | 625 | tid_t tid; |
631 | int need_to_start, ret; | 626 | int need_to_start, ret; |
632 | 627 | ||
628 | WARN_ON(!transaction); | ||
633 | /* If we've had an abort of any type, don't even think about | 629 | /* If we've had an abort of any type, don't even think about |
634 | * actually doing the restart! */ | 630 | * actually doing the restart! */ |
635 | if (is_handle_aborted(handle)) | 631 | if (is_handle_aborted(handle)) |
636 | return 0; | 632 | return 0; |
633 | journal = transaction->t_journal; | ||
637 | 634 | ||
638 | /* | 635 | /* |
639 | * First unlink the handle from its current transaction, and start the | 636 | * First unlink the handle from its current transaction, and start the |
@@ -654,6 +651,8 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask) | |||
654 | wake_up(&journal->j_wait_updates); | 651 | wake_up(&journal->j_wait_updates); |
655 | tid = transaction->t_tid; | 652 | tid = transaction->t_tid; |
656 | spin_unlock(&transaction->t_handle_lock); | 653 | spin_unlock(&transaction->t_handle_lock); |
654 | handle->h_transaction = NULL; | ||
655 | current->journal_info = NULL; | ||
657 | 656 | ||
658 | jbd_debug(2, "restarting handle %p\n", handle); | 657 | jbd_debug(2, "restarting handle %p\n", handle); |
659 | need_to_start = !tid_geq(journal->j_commit_request, tid); | 658 | need_to_start = !tid_geq(journal->j_commit_request, tid); |
@@ -783,17 +782,16 @@ do_get_write_access(handle_t *handle, struct journal_head *jh, | |||
783 | int force_copy) | 782 | int force_copy) |
784 | { | 783 | { |
785 | struct buffer_head *bh; | 784 | struct buffer_head *bh; |
786 | transaction_t *transaction; | 785 | transaction_t *transaction = handle->h_transaction; |
787 | journal_t *journal; | 786 | journal_t *journal; |
788 | int error; | 787 | int error; |
789 | char *frozen_buffer = NULL; | 788 | char *frozen_buffer = NULL; |
790 | int need_copy = 0; | 789 | int need_copy = 0; |
791 | unsigned long start_lock, time_lock; | 790 | unsigned long start_lock, time_lock; |
792 | 791 | ||
792 | WARN_ON(!transaction); | ||
793 | if (is_handle_aborted(handle)) | 793 | if (is_handle_aborted(handle)) |
794 | return -EROFS; | 794 | return -EROFS; |
795 | |||
796 | transaction = handle->h_transaction; | ||
797 | journal = transaction->t_journal; | 795 | journal = transaction->t_journal; |
798 | 796 | ||
799 | jbd_debug(5, "journal_head %p, force_copy %d\n", jh, force_copy); | 797 | jbd_debug(5, "journal_head %p, force_copy %d\n", jh, force_copy); |
@@ -1052,14 +1050,16 @@ int jbd2_journal_get_write_access(handle_t *handle, struct buffer_head *bh) | |||
1052 | int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) | 1050 | int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) |
1053 | { | 1051 | { |
1054 | transaction_t *transaction = handle->h_transaction; | 1052 | transaction_t *transaction = handle->h_transaction; |
1055 | journal_t *journal = transaction->t_journal; | 1053 | journal_t *journal; |
1056 | struct journal_head *jh = jbd2_journal_add_journal_head(bh); | 1054 | struct journal_head *jh = jbd2_journal_add_journal_head(bh); |
1057 | int err; | 1055 | int err; |
1058 | 1056 | ||
1059 | jbd_debug(5, "journal_head %p\n", jh); | 1057 | jbd_debug(5, "journal_head %p\n", jh); |
1058 | WARN_ON(!transaction); | ||
1060 | err = -EROFS; | 1059 | err = -EROFS; |
1061 | if (is_handle_aborted(handle)) | 1060 | if (is_handle_aborted(handle)) |
1062 | goto out; | 1061 | goto out; |
1062 | journal = transaction->t_journal; | ||
1063 | err = 0; | 1063 | err = 0; |
1064 | 1064 | ||
1065 | JBUFFER_TRACE(jh, "entry"); | 1065 | JBUFFER_TRACE(jh, "entry"); |
@@ -1265,12 +1265,14 @@ void jbd2_buffer_abort_trigger(struct journal_head *jh, | |||
1265 | int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) | 1265 | int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) |
1266 | { | 1266 | { |
1267 | transaction_t *transaction = handle->h_transaction; | 1267 | transaction_t *transaction = handle->h_transaction; |
1268 | journal_t *journal = transaction->t_journal; | 1268 | journal_t *journal; |
1269 | struct journal_head *jh; | 1269 | struct journal_head *jh; |
1270 | int ret = 0; | 1270 | int ret = 0; |
1271 | 1271 | ||
1272 | WARN_ON(!transaction); | ||
1272 | if (is_handle_aborted(handle)) | 1273 | if (is_handle_aborted(handle)) |
1273 | goto out; | 1274 | return -EROFS; |
1275 | journal = transaction->t_journal; | ||
1274 | jh = jbd2_journal_grab_journal_head(bh); | 1276 | jh = jbd2_journal_grab_journal_head(bh); |
1275 | if (!jh) { | 1277 | if (!jh) { |
1276 | ret = -EUCLEAN; | 1278 | ret = -EUCLEAN; |
@@ -1364,7 +1366,7 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) | |||
1364 | 1366 | ||
1365 | JBUFFER_TRACE(jh, "file as BJ_Metadata"); | 1367 | JBUFFER_TRACE(jh, "file as BJ_Metadata"); |
1366 | spin_lock(&journal->j_list_lock); | 1368 | spin_lock(&journal->j_list_lock); |
1367 | __jbd2_journal_file_buffer(jh, handle->h_transaction, BJ_Metadata); | 1369 | __jbd2_journal_file_buffer(jh, transaction, BJ_Metadata); |
1368 | spin_unlock(&journal->j_list_lock); | 1370 | spin_unlock(&journal->j_list_lock); |
1369 | out_unlock_bh: | 1371 | out_unlock_bh: |
1370 | jbd_unlock_bh_state(bh); | 1372 | jbd_unlock_bh_state(bh); |
@@ -1395,12 +1397,17 @@ out: | |||
1395 | int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) | 1397 | int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) |
1396 | { | 1398 | { |
1397 | transaction_t *transaction = handle->h_transaction; | 1399 | transaction_t *transaction = handle->h_transaction; |
1398 | journal_t *journal = transaction->t_journal; | 1400 | journal_t *journal; |
1399 | struct journal_head *jh; | 1401 | struct journal_head *jh; |
1400 | int drop_reserve = 0; | 1402 | int drop_reserve = 0; |
1401 | int err = 0; | 1403 | int err = 0; |
1402 | int was_modified = 0; | 1404 | int was_modified = 0; |
1403 | 1405 | ||
1406 | WARN_ON(!transaction); | ||
1407 | if (is_handle_aborted(handle)) | ||
1408 | return -EROFS; | ||
1409 | journal = transaction->t_journal; | ||
1410 | |||
1404 | BUFFER_TRACE(bh, "entry"); | 1411 | BUFFER_TRACE(bh, "entry"); |
1405 | 1412 | ||
1406 | jbd_lock_bh_state(bh); | 1413 | jbd_lock_bh_state(bh); |
@@ -1427,7 +1434,7 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) | |||
1427 | */ | 1434 | */ |
1428 | jh->b_modified = 0; | 1435 | jh->b_modified = 0; |
1429 | 1436 | ||
1430 | if (jh->b_transaction == handle->h_transaction) { | 1437 | if (jh->b_transaction == transaction) { |
1431 | J_ASSERT_JH(jh, !jh->b_frozen_data); | 1438 | J_ASSERT_JH(jh, !jh->b_frozen_data); |
1432 | 1439 | ||
1433 | /* If we are forgetting a buffer which is already part | 1440 | /* If we are forgetting a buffer which is already part |
@@ -1522,19 +1529,21 @@ drop: | |||
1522 | int jbd2_journal_stop(handle_t *handle) | 1529 | int jbd2_journal_stop(handle_t *handle) |
1523 | { | 1530 | { |
1524 | transaction_t *transaction = handle->h_transaction; | 1531 | transaction_t *transaction = handle->h_transaction; |
1525 | journal_t *journal = transaction->t_journal; | 1532 | journal_t *journal; |
1526 | int err, wait_for_commit = 0; | 1533 | int err = 0, wait_for_commit = 0; |
1527 | tid_t tid; | 1534 | tid_t tid; |
1528 | pid_t pid; | 1535 | pid_t pid; |
1529 | 1536 | ||
1537 | if (!transaction) | ||
1538 | goto free_and_exit; | ||
1539 | journal = transaction->t_journal; | ||
1540 | |||
1530 | J_ASSERT(journal_current_handle() == handle); | 1541 | J_ASSERT(journal_current_handle() == handle); |
1531 | 1542 | ||
1532 | if (is_handle_aborted(handle)) | 1543 | if (is_handle_aborted(handle)) |
1533 | err = -EIO; | 1544 | err = -EIO; |
1534 | else { | 1545 | else |
1535 | J_ASSERT(atomic_read(&transaction->t_updates) > 0); | 1546 | J_ASSERT(atomic_read(&transaction->t_updates) > 0); |
1536 | err = 0; | ||
1537 | } | ||
1538 | 1547 | ||
1539 | if (--handle->h_ref > 0) { | 1548 | if (--handle->h_ref > 0) { |
1540 | jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, | 1549 | jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, |
@@ -1544,7 +1553,7 @@ int jbd2_journal_stop(handle_t *handle) | |||
1544 | 1553 | ||
1545 | jbd_debug(4, "Handle %p going down\n", handle); | 1554 | jbd_debug(4, "Handle %p going down\n", handle); |
1546 | trace_jbd2_handle_stats(journal->j_fs_dev->bd_dev, | 1555 | trace_jbd2_handle_stats(journal->j_fs_dev->bd_dev, |
1547 | handle->h_transaction->t_tid, | 1556 | transaction->t_tid, |
1548 | handle->h_type, handle->h_line_no, | 1557 | handle->h_type, handle->h_line_no, |
1549 | jiffies - handle->h_start_jiffies, | 1558 | jiffies - handle->h_start_jiffies, |
1550 | handle->h_sync, handle->h_requested_credits, | 1559 | handle->h_sync, handle->h_requested_credits, |
@@ -1657,6 +1666,7 @@ int jbd2_journal_stop(handle_t *handle) | |||
1657 | 1666 | ||
1658 | if (handle->h_rsv_handle) | 1667 | if (handle->h_rsv_handle) |
1659 | jbd2_journal_free_reserved(handle->h_rsv_handle); | 1668 | jbd2_journal_free_reserved(handle->h_rsv_handle); |
1669 | free_and_exit: | ||
1660 | jbd2_free_handle(handle); | 1670 | jbd2_free_handle(handle); |
1661 | return err; | 1671 | return err; |
1662 | } | 1672 | } |
@@ -2362,10 +2372,12 @@ void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh) | |||
2362 | int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode) | 2372 | int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode) |
2363 | { | 2373 | { |
2364 | transaction_t *transaction = handle->h_transaction; | 2374 | transaction_t *transaction = handle->h_transaction; |
2365 | journal_t *journal = transaction->t_journal; | 2375 | journal_t *journal; |
2366 | 2376 | ||
2377 | WARN_ON(!transaction); | ||
2367 | if (is_handle_aborted(handle)) | 2378 | if (is_handle_aborted(handle)) |
2368 | return -EIO; | 2379 | return -EROFS; |
2380 | journal = transaction->t_journal; | ||
2369 | 2381 | ||
2370 | jbd_debug(4, "Adding inode %lu, tid:%d\n", jinode->i_vfs_inode->i_ino, | 2382 | jbd_debug(4, "Adding inode %lu, tid:%d\n", jinode->i_vfs_inode->i_ino, |
2371 | transaction->t_tid); | 2383 | transaction->t_tid); |