diff options
Diffstat (limited to 'fs/jbd')
-rw-r--r-- | fs/jbd/commit.c | 10 | ||||
-rw-r--r-- | fs/jbd/transaction.c | 43 |
2 files changed, 36 insertions, 17 deletions
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 4bd882548c45..2c90e3ef625f 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
@@ -862,12 +862,12 @@ restart_loop: | |||
862 | /* A buffer which has been freed while still being | 862 | /* A buffer which has been freed while still being |
863 | * journaled by a previous transaction may end up still | 863 | * journaled by a previous transaction may end up still |
864 | * being dirty here, but we want to avoid writing back | 864 | * being dirty here, but we want to avoid writing back |
865 | * that buffer in the future now that the last use has | 865 | * that buffer in the future after the "add to orphan" |
866 | * been committed. That's not only a performance gain, | 866 | * operation been committed, That's not only a performance |
867 | * it also stops aliasing problems if the buffer is left | 867 | * gain, it also stops aliasing problems if the buffer is |
868 | * behind for writeback and gets reallocated for another | 868 | * left behind for writeback and gets reallocated for another |
869 | * use in a different page. */ | 869 | * use in a different page. */ |
870 | if (buffer_freed(bh)) { | 870 | if (buffer_freed(bh) && !jh->b_next_transaction) { |
871 | clear_buffer_freed(bh); | 871 | clear_buffer_freed(bh); |
872 | clear_buffer_jbddirty(bh); | 872 | clear_buffer_jbddirty(bh); |
873 | } | 873 | } |
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 | */ |
2121 | void __journal_refile_buffer(struct journal_head *jh) | 2135 | void __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) |