diff options
-rw-r--r-- | fs/jbd2/commit.c | 10 | ||||
-rw-r--r-- | fs/jbd2/transaction.c | 43 |
2 files changed, 36 insertions, 17 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 1bc74b6f26d2..3ee211ed58f1 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -930,12 +930,12 @@ restart_loop: | |||
930 | /* A buffer which has been freed while still being | 930 | /* A buffer which has been freed while still being |
931 | * journaled by a previous transaction may end up still | 931 | * journaled by a previous transaction may end up still |
932 | * being dirty here, but we want to avoid writing back | 932 | * being dirty here, but we want to avoid writing back |
933 | * that buffer in the future now that the last use has | 933 | * that buffer in the future after the "add to orphan" |
934 | * been committed. That's not only a performance gain, | 934 | * operation been committed, That's not only a performance |
935 | * it also stops aliasing problems if the buffer is left | 935 | * gain, it also stops aliasing problems if the buffer is |
936 | * behind for writeback and gets reallocated for another | 936 | * left behind for writeback and gets reallocated for another |
937 | * use in a different page. */ | 937 | * use in a different page. */ |
938 | if (buffer_freed(bh)) { | 938 | if (buffer_freed(bh) && !jh->b_next_transaction) { |
939 | clear_buffer_freed(bh); | 939 | clear_buffer_freed(bh); |
940 | clear_buffer_jbddirty(bh); | 940 | clear_buffer_jbddirty(bh); |
941 | } | 941 | } |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index a0512700542f..bfc70f57900f 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -1727,6 +1727,21 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) | |||
1727 | if (!jh) | 1727 | if (!jh) |
1728 | goto zap_buffer_no_jh; | 1728 | goto zap_buffer_no_jh; |
1729 | 1729 | ||
1730 | /* | ||
1731 | * We cannot remove the buffer from checkpoint lists until the | ||
1732 | * transaction adding inode to orphan list (let's call it T) | ||
1733 | * is committed. Otherwise if the transaction changing the | ||
1734 | * buffer would be cleaned from the journal before T is | ||
1735 | * committed, a crash will cause that the correct contents of | ||
1736 | * the buffer will be lost. On the other hand we have to | ||
1737 | * clear the buffer dirty bit at latest at the moment when the | ||
1738 | * transaction marking the buffer as freed in the filesystem | ||
1739 | * structures is committed because from that moment on the | ||
1740 | * buffer can be reallocated and used by a different page. | ||
1741 | * Since the block hasn't been freed yet but the inode has | ||
1742 | * already been added to orphan list, it is safe for us to add | ||
1743 | * the buffer to BJ_Forget list of the newest transaction. | ||
1744 | */ | ||
1730 | transaction = jh->b_transaction; | 1745 | transaction = jh->b_transaction; |
1731 | if (transaction == NULL) { | 1746 | if (transaction == NULL) { |
1732 | /* First case: not on any transaction. If it | 1747 | /* First case: not on any transaction. If it |
@@ -1783,16 +1798,15 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) | |||
1783 | } else if (transaction == journal->j_committing_transaction) { | 1798 | } else if (transaction == journal->j_committing_transaction) { |
1784 | JBUFFER_TRACE(jh, "on committing transaction"); | 1799 | JBUFFER_TRACE(jh, "on committing transaction"); |
1785 | /* | 1800 | /* |
1786 | * If it is committing, we simply cannot touch it. We | 1801 | * The buffer is committing, we simply cannot touch |
1787 | * can remove it's next_transaction pointer from the | 1802 | * it. So we just set j_next_transaction to the |
1788 | * running transaction if that is set, but nothing | 1803 | * running transaction (if there is one) and mark |
1789 | * else. */ | 1804 | * buffer as freed so that commit code knows it should |
1805 | * clear dirty bits when it is done with the buffer. | ||
1806 | */ | ||
1790 | set_buffer_freed(bh); | 1807 | set_buffer_freed(bh); |
1791 | if (jh->b_next_transaction) { | 1808 | if (journal->j_running_transaction && buffer_jbddirty(bh)) |
1792 | J_ASSERT(jh->b_next_transaction == | 1809 | jh->b_next_transaction = journal->j_running_transaction; |
1793 | journal->j_running_transaction); | ||
1794 | jh->b_next_transaction = NULL; | ||
1795 | } | ||
1796 | jbd2_journal_put_journal_head(jh); | 1810 | jbd2_journal_put_journal_head(jh); |
1797 | spin_unlock(&journal->j_list_lock); | 1811 | spin_unlock(&journal->j_list_lock); |
1798 | jbd_unlock_bh_state(bh); | 1812 | jbd_unlock_bh_state(bh); |
@@ -1969,7 +1983,7 @@ void jbd2_journal_file_buffer(struct journal_head *jh, | |||
1969 | */ | 1983 | */ |
1970 | void __jbd2_journal_refile_buffer(struct journal_head *jh) | 1984 | void __jbd2_journal_refile_buffer(struct journal_head *jh) |
1971 | { | 1985 | { |
1972 | int was_dirty; | 1986 | int was_dirty, jlist; |
1973 | struct buffer_head *bh = jh2bh(jh); | 1987 | struct buffer_head *bh = jh2bh(jh); |
1974 | 1988 | ||
1975 | J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); | 1989 | J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); |
@@ -1991,8 +2005,13 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh) | |||
1991 | __jbd2_journal_temp_unlink_buffer(jh); | 2005 | __jbd2_journal_temp_unlink_buffer(jh); |
1992 | jh->b_transaction = jh->b_next_transaction; | 2006 | jh->b_transaction = jh->b_next_transaction; |
1993 | jh->b_next_transaction = NULL; | 2007 | jh->b_next_transaction = NULL; |
1994 | __jbd2_journal_file_buffer(jh, jh->b_transaction, | 2008 | if (buffer_freed(bh)) |
1995 | jh->b_modified ? BJ_Metadata : BJ_Reserved); | 2009 | jlist = BJ_Forget; |
2010 | else if (jh->b_modified) | ||
2011 | jlist = BJ_Metadata; | ||
2012 | else | ||
2013 | jlist = BJ_Reserved; | ||
2014 | __jbd2_journal_file_buffer(jh, jh->b_transaction, jlist); | ||
1996 | J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); | 2015 | J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); |
1997 | 2016 | ||
1998 | if (was_dirty) | 2017 | if (was_dirty) |