aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd/transaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jbd/transaction.c')
-rw-r--r--fs/jbd/transaction.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 006f9ad838a2..99e9fea11077 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1864,6 +1864,21 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
1864 if (!jh) 1864 if (!jh)
1865 goto zap_buffer_no_jh; 1865 goto zap_buffer_no_jh;
1866 1866
1867 /*
1868 * We cannot remove the buffer from checkpoint lists until the
1869 * transaction adding inode to orphan list (let's call it T)
1870 * is committed. Otherwise if the transaction changing the
1871 * buffer would be cleaned from the journal before T is
1872 * committed, a crash will cause that the correct contents of
1873 * the buffer will be lost. On the other hand we have to
1874 * clear the buffer dirty bit at latest at the moment when the
1875 * transaction marking the buffer as freed in the filesystem
1876 * structures is committed because from that moment on the
1877 * buffer can be reallocated and used by a different page.
1878 * Since the block hasn't been freed yet but the inode has
1879 * already been added to orphan list, it is safe for us to add
1880 * the buffer to BJ_Forget list of the newest transaction.
1881 */
1867 transaction = jh->b_transaction; 1882 transaction = jh->b_transaction;
1868 if (transaction == NULL) { 1883 if (transaction == NULL) {
1869 /* First case: not on any transaction. If it 1884 /* First case: not on any transaction. If it
@@ -1929,16 +1944,15 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
1929 goto zap_buffer; 1944 goto zap_buffer;
1930 } 1945 }
1931 /* 1946 /*
1932 * If it is committing, we simply cannot touch it. We 1947 * The buffer is committing, we simply cannot touch
1933 * can remove it's next_transaction pointer from the 1948 * it. So we just set j_next_transaction to the
1934 * running transaction if that is set, but nothing 1949 * running transaction (if there is one) and mark
1935 * else. */ 1950 * buffer as freed so that commit code knows it should
1951 * clear dirty bits when it is done with the buffer.
1952 */
1936 set_buffer_freed(bh); 1953 set_buffer_freed(bh);
1937 if (jh->b_next_transaction) { 1954 if (journal->j_running_transaction && buffer_jbddirty(bh))
1938 J_ASSERT(jh->b_next_transaction == 1955 jh->b_next_transaction = journal->j_running_transaction;
1939 journal->j_running_transaction);
1940 jh->b_next_transaction = NULL;
1941 }
1942 journal_put_journal_head(jh); 1956 journal_put_journal_head(jh);
1943 spin_unlock(&journal->j_list_lock); 1957 spin_unlock(&journal->j_list_lock);
1944 jbd_unlock_bh_state(bh); 1958 jbd_unlock_bh_state(bh);
@@ -2120,7 +2134,7 @@ void journal_file_buffer(struct journal_head *jh,
2120 */ 2134 */
2121void __journal_refile_buffer(struct journal_head *jh) 2135void __journal_refile_buffer(struct journal_head *jh)
2122{ 2136{
2123 int was_dirty; 2137 int was_dirty, jlist;
2124 struct buffer_head *bh = jh2bh(jh); 2138 struct buffer_head *bh = jh2bh(jh);
2125 2139
2126 J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); 2140 J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
@@ -2142,8 +2156,13 @@ void __journal_refile_buffer(struct journal_head *jh)
2142 __journal_temp_unlink_buffer(jh); 2156 __journal_temp_unlink_buffer(jh);
2143 jh->b_transaction = jh->b_next_transaction; 2157 jh->b_transaction = jh->b_next_transaction;
2144 jh->b_next_transaction = NULL; 2158 jh->b_next_transaction = NULL;
2145 __journal_file_buffer(jh, jh->b_transaction, 2159 if (buffer_freed(bh))
2146 jh->b_modified ? BJ_Metadata : BJ_Reserved); 2160 jlist = BJ_Forget;
2161 else if (jh->b_modified)
2162 jlist = BJ_Metadata;
2163 else
2164 jlist = BJ_Reserved;
2165 __journal_file_buffer(jh, jh->b_transaction, jlist);
2147 J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); 2166 J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
2148 2167
2149 if (was_dirty) 2168 if (was_dirty)