diff options
Diffstat (limited to 'fs/jbd2/transaction.c')
-rw-r--r-- | fs/jbd2/transaction.c | 69 |
1 files changed, 35 insertions, 34 deletions
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 3eec82d32fd4..2d7109414cdd 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | 31 | ||
32 | static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh); | 32 | static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh); |
33 | static void __jbd2_journal_unfile_buffer(struct journal_head *jh); | ||
33 | 34 | ||
34 | /* | 35 | /* |
35 | * jbd2_get_transaction: obtain a new transaction_t object. | 36 | * jbd2_get_transaction: obtain a new transaction_t object. |
@@ -764,7 +765,6 @@ repeat: | |||
764 | if (!jh->b_transaction) { | 765 | if (!jh->b_transaction) { |
765 | JBUFFER_TRACE(jh, "no transaction"); | 766 | JBUFFER_TRACE(jh, "no transaction"); |
766 | J_ASSERT_JH(jh, !jh->b_next_transaction); | 767 | J_ASSERT_JH(jh, !jh->b_next_transaction); |
767 | jh->b_transaction = transaction; | ||
768 | JBUFFER_TRACE(jh, "file as BJ_Reserved"); | 768 | JBUFFER_TRACE(jh, "file as BJ_Reserved"); |
769 | spin_lock(&journal->j_list_lock); | 769 | spin_lock(&journal->j_list_lock); |
770 | __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); | 770 | __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); |
@@ -814,7 +814,6 @@ out: | |||
814 | * int jbd2_journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update. | 814 | * int jbd2_journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update. |
815 | * @handle: transaction to add buffer modifications to | 815 | * @handle: transaction to add buffer modifications to |
816 | * @bh: bh to be used for metadata writes | 816 | * @bh: bh to be used for metadata writes |
817 | * @credits: variable that will receive credits for the buffer | ||
818 | * | 817 | * |
819 | * Returns an error code or 0 on success. | 818 | * Returns an error code or 0 on success. |
820 | * | 819 | * |
@@ -896,8 +895,6 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) | |||
896 | * committed and so it's safe to clear the dirty bit. | 895 | * committed and so it's safe to clear the dirty bit. |
897 | */ | 896 | */ |
898 | clear_buffer_dirty(jh2bh(jh)); | 897 | clear_buffer_dirty(jh2bh(jh)); |
899 | jh->b_transaction = transaction; | ||
900 | |||
901 | /* first access by this transaction */ | 898 | /* first access by this transaction */ |
902 | jh->b_modified = 0; | 899 | jh->b_modified = 0; |
903 | 900 | ||
@@ -932,7 +929,6 @@ out: | |||
932 | * non-rewindable consequences | 929 | * non-rewindable consequences |
933 | * @handle: transaction | 930 | * @handle: transaction |
934 | * @bh: buffer to undo | 931 | * @bh: buffer to undo |
935 | * @credits: store the number of taken credits here (if not NULL) | ||
936 | * | 932 | * |
937 | * Sometimes there is a need to distinguish between metadata which has | 933 | * Sometimes there is a need to distinguish between metadata which has |
938 | * been committed to disk and that which has not. The ext3fs code uses | 934 | * been committed to disk and that which has not. The ext3fs code uses |
@@ -1232,8 +1228,6 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) | |||
1232 | __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); | 1228 | __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); |
1233 | } else { | 1229 | } else { |
1234 | __jbd2_journal_unfile_buffer(jh); | 1230 | __jbd2_journal_unfile_buffer(jh); |
1235 | jbd2_journal_remove_journal_head(bh); | ||
1236 | __brelse(bh); | ||
1237 | if (!buffer_jbd(bh)) { | 1231 | if (!buffer_jbd(bh)) { |
1238 | spin_unlock(&journal->j_list_lock); | 1232 | spin_unlock(&journal->j_list_lock); |
1239 | jbd_unlock_bh_state(bh); | 1233 | jbd_unlock_bh_state(bh); |
@@ -1556,19 +1550,32 @@ void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh) | |||
1556 | mark_buffer_dirty(bh); /* Expose it to the VM */ | 1550 | mark_buffer_dirty(bh); /* Expose it to the VM */ |
1557 | } | 1551 | } |
1558 | 1552 | ||
1559 | void __jbd2_journal_unfile_buffer(struct journal_head *jh) | 1553 | /* |
1554 | * Remove buffer from all transactions. | ||
1555 | * | ||
1556 | * Called with bh_state lock and j_list_lock | ||
1557 | * | ||
1558 | * jh and bh may be already freed when this function returns. | ||
1559 | */ | ||
1560 | static void __jbd2_journal_unfile_buffer(struct journal_head *jh) | ||
1560 | { | 1561 | { |
1561 | __jbd2_journal_temp_unlink_buffer(jh); | 1562 | __jbd2_journal_temp_unlink_buffer(jh); |
1562 | jh->b_transaction = NULL; | 1563 | jh->b_transaction = NULL; |
1564 | jbd2_journal_put_journal_head(jh); | ||
1563 | } | 1565 | } |
1564 | 1566 | ||
1565 | void jbd2_journal_unfile_buffer(journal_t *journal, struct journal_head *jh) | 1567 | void jbd2_journal_unfile_buffer(journal_t *journal, struct journal_head *jh) |
1566 | { | 1568 | { |
1567 | jbd_lock_bh_state(jh2bh(jh)); | 1569 | struct buffer_head *bh = jh2bh(jh); |
1570 | |||
1571 | /* Get reference so that buffer cannot be freed before we unlock it */ | ||
1572 | get_bh(bh); | ||
1573 | jbd_lock_bh_state(bh); | ||
1568 | spin_lock(&journal->j_list_lock); | 1574 | spin_lock(&journal->j_list_lock); |
1569 | __jbd2_journal_unfile_buffer(jh); | 1575 | __jbd2_journal_unfile_buffer(jh); |
1570 | spin_unlock(&journal->j_list_lock); | 1576 | spin_unlock(&journal->j_list_lock); |
1571 | jbd_unlock_bh_state(jh2bh(jh)); | 1577 | jbd_unlock_bh_state(bh); |
1578 | __brelse(bh); | ||
1572 | } | 1579 | } |
1573 | 1580 | ||
1574 | /* | 1581 | /* |
@@ -1595,8 +1602,6 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) | |||
1595 | if (jh->b_jlist == BJ_None) { | 1602 | if (jh->b_jlist == BJ_None) { |
1596 | JBUFFER_TRACE(jh, "remove from checkpoint list"); | 1603 | JBUFFER_TRACE(jh, "remove from checkpoint list"); |
1597 | __jbd2_journal_remove_checkpoint(jh); | 1604 | __jbd2_journal_remove_checkpoint(jh); |
1598 | jbd2_journal_remove_journal_head(bh); | ||
1599 | __brelse(bh); | ||
1600 | } | 1605 | } |
1601 | } | 1606 | } |
1602 | spin_unlock(&journal->j_list_lock); | 1607 | spin_unlock(&journal->j_list_lock); |
@@ -1659,7 +1664,6 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal, | |||
1659 | /* | 1664 | /* |
1660 | * We take our own ref against the journal_head here to avoid | 1665 | * We take our own ref against the journal_head here to avoid |
1661 | * having to add tons of locking around each instance of | 1666 | * having to add tons of locking around each instance of |
1662 | * jbd2_journal_remove_journal_head() and | ||
1663 | * jbd2_journal_put_journal_head(). | 1667 | * jbd2_journal_put_journal_head(). |
1664 | */ | 1668 | */ |
1665 | jh = jbd2_journal_grab_journal_head(bh); | 1669 | jh = jbd2_journal_grab_journal_head(bh); |
@@ -1697,10 +1701,9 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) | |||
1697 | int may_free = 1; | 1701 | int may_free = 1; |
1698 | struct buffer_head *bh = jh2bh(jh); | 1702 | struct buffer_head *bh = jh2bh(jh); |
1699 | 1703 | ||
1700 | __jbd2_journal_unfile_buffer(jh); | ||
1701 | |||
1702 | if (jh->b_cp_transaction) { | 1704 | if (jh->b_cp_transaction) { |
1703 | JBUFFER_TRACE(jh, "on running+cp transaction"); | 1705 | JBUFFER_TRACE(jh, "on running+cp transaction"); |
1706 | __jbd2_journal_temp_unlink_buffer(jh); | ||
1704 | /* | 1707 | /* |
1705 | * We don't want to write the buffer anymore, clear the | 1708 | * We don't want to write the buffer anymore, clear the |
1706 | * bit so that we don't confuse checks in | 1709 | * bit so that we don't confuse checks in |
@@ -1711,8 +1714,7 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) | |||
1711 | may_free = 0; | 1714 | may_free = 0; |
1712 | } else { | 1715 | } else { |
1713 | JBUFFER_TRACE(jh, "on running transaction"); | 1716 | JBUFFER_TRACE(jh, "on running transaction"); |
1714 | jbd2_journal_remove_journal_head(bh); | 1717 | __jbd2_journal_unfile_buffer(jh); |
1715 | __brelse(bh); | ||
1716 | } | 1718 | } |
1717 | return may_free; | 1719 | return may_free; |
1718 | } | 1720 | } |
@@ -1990,6 +1992,8 @@ void __jbd2_journal_file_buffer(struct journal_head *jh, | |||
1990 | 1992 | ||
1991 | if (jh->b_transaction) | 1993 | if (jh->b_transaction) |
1992 | __jbd2_journal_temp_unlink_buffer(jh); | 1994 | __jbd2_journal_temp_unlink_buffer(jh); |
1995 | else | ||
1996 | jbd2_journal_grab_journal_head(bh); | ||
1993 | jh->b_transaction = transaction; | 1997 | jh->b_transaction = transaction; |
1994 | 1998 | ||
1995 | switch (jlist) { | 1999 | switch (jlist) { |
@@ -2041,9 +2045,10 @@ void jbd2_journal_file_buffer(struct journal_head *jh, | |||
2041 | * already started to be used by a subsequent transaction, refile the | 2045 | * already started to be used by a subsequent transaction, refile the |
2042 | * buffer on that transaction's metadata list. | 2046 | * buffer on that transaction's metadata list. |
2043 | * | 2047 | * |
2044 | * Called under journal->j_list_lock | 2048 | * Called under j_list_lock |
2045 | * | ||
2046 | * Called under jbd_lock_bh_state(jh2bh(jh)) | 2049 | * Called under jbd_lock_bh_state(jh2bh(jh)) |
2050 | * | ||
2051 | * jh and bh may be already free when this function returns | ||
2047 | */ | 2052 | */ |
2048 | void __jbd2_journal_refile_buffer(struct journal_head *jh) | 2053 | void __jbd2_journal_refile_buffer(struct journal_head *jh) |
2049 | { | 2054 | { |
@@ -2067,6 +2072,11 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh) | |||
2067 | 2072 | ||
2068 | was_dirty = test_clear_buffer_jbddirty(bh); | 2073 | was_dirty = test_clear_buffer_jbddirty(bh); |
2069 | __jbd2_journal_temp_unlink_buffer(jh); | 2074 | __jbd2_journal_temp_unlink_buffer(jh); |
2075 | /* | ||
2076 | * We set b_transaction here because b_next_transaction will inherit | ||
2077 | * our jh reference and thus __jbd2_journal_file_buffer() must not | ||
2078 | * take a new one. | ||
2079 | */ | ||
2070 | jh->b_transaction = jh->b_next_transaction; | 2080 | jh->b_transaction = jh->b_next_transaction; |
2071 | jh->b_next_transaction = NULL; | 2081 | jh->b_next_transaction = NULL; |
2072 | if (buffer_freed(bh)) | 2082 | if (buffer_freed(bh)) |
@@ -2083,30 +2093,21 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh) | |||
2083 | } | 2093 | } |
2084 | 2094 | ||
2085 | /* | 2095 | /* |
2086 | * For the unlocked version of this call, also make sure that any | 2096 | * __jbd2_journal_refile_buffer() with necessary locking added. We take our |
2087 | * hanging journal_head is cleaned up if necessary. | 2097 | * bh reference so that we can safely unlock bh. |
2088 | * | 2098 | * |
2089 | * __jbd2_journal_refile_buffer is usually called as part of a single locked | 2099 | * The jh and bh may be freed by this call. |
2090 | * operation on a buffer_head, in which the caller is probably going to | ||
2091 | * be hooking the journal_head onto other lists. In that case it is up | ||
2092 | * to the caller to remove the journal_head if necessary. For the | ||
2093 | * unlocked jbd2_journal_refile_buffer call, the caller isn't going to be | ||
2094 | * doing anything else to the buffer so we need to do the cleanup | ||
2095 | * ourselves to avoid a jh leak. | ||
2096 | * | ||
2097 | * *** The journal_head may be freed by this call! *** | ||
2098 | */ | 2100 | */ |
2099 | void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh) | 2101 | void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh) |
2100 | { | 2102 | { |
2101 | struct buffer_head *bh = jh2bh(jh); | 2103 | struct buffer_head *bh = jh2bh(jh); |
2102 | 2104 | ||
2105 | /* Get reference so that buffer cannot be freed before we unlock it */ | ||
2106 | get_bh(bh); | ||
2103 | jbd_lock_bh_state(bh); | 2107 | jbd_lock_bh_state(bh); |
2104 | spin_lock(&journal->j_list_lock); | 2108 | spin_lock(&journal->j_list_lock); |
2105 | |||
2106 | __jbd2_journal_refile_buffer(jh); | 2109 | __jbd2_journal_refile_buffer(jh); |
2107 | jbd_unlock_bh_state(bh); | 2110 | jbd_unlock_bh_state(bh); |
2108 | jbd2_journal_remove_journal_head(bh); | ||
2109 | |||
2110 | spin_unlock(&journal->j_list_lock); | 2111 | spin_unlock(&journal->j_list_lock); |
2111 | __brelse(bh); | 2112 | __brelse(bh); |
2112 | } | 2113 | } |