aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd/commit.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-07-11 17:16:25 -0400
committerJan Kara <jack@suse.cz>2012-09-12 09:52:03 -0400
commit09e05d4805e6c524c1af74e524e5d0528bb3fef3 (patch)
tree8522776e5ad521026885806f5fb8276be0c7dc1b /fs/jbd/commit.c
parent5eec54fcde7e065eb3d8a6e70e61d90673ca706b (diff)
jbd: Fix assertion failure in commit code due to lacking transaction credits
ext3 users of data=journal mode with blocksize < pagesize were occasionally hitting assertion failure in journal_commit_transaction() checking whether the transaction has at least as many credits reserved as buffers attached. The core of the problem is that when a file gets truncated, buffers that still need checkpointing or that are attached to the committing transaction are left with buffer_mapped set. When this happens to buffers beyond i_size attached to a page stradding i_size, subsequent write extending the file will see these buffers and as they are mapped (but underlying blocks were freed) things go awry from here. The assertion failure just coincidentally (and in this case luckily as we would start corrupting filesystem) triggers due to journal_head not being properly cleaned up as well. Under some rare circumstances this bug could even hit data=ordered mode users. There the assertion won't trigger and we would end up corrupting the filesystem. We fix the problem by unmapping buffers if possible (in lots of cases we just need a buffer attached to a transaction as a place holder but it must not be written out anyway). And in one case, we just have to bite the bullet and wait for transaction commit to finish. Reviewed-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/jbd/commit.c')
-rw-r--r--fs/jbd/commit.c45
1 files changed, 34 insertions, 11 deletions
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 52c15c776029..86b39b167c23 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -86,7 +86,12 @@ nope:
86static void release_data_buffer(struct buffer_head *bh) 86static void release_data_buffer(struct buffer_head *bh)
87{ 87{
88 if (buffer_freed(bh)) { 88 if (buffer_freed(bh)) {
89 WARN_ON_ONCE(buffer_dirty(bh));
89 clear_buffer_freed(bh); 90 clear_buffer_freed(bh);
91 clear_buffer_mapped(bh);
92 clear_buffer_new(bh);
93 clear_buffer_req(bh);
94 bh->b_bdev = NULL;
90 release_buffer_page(bh); 95 release_buffer_page(bh);
91 } else 96 } else
92 put_bh(bh); 97 put_bh(bh);
@@ -866,17 +871,35 @@ restart_loop:
866 * there's no point in keeping a checkpoint record for 871 * there's no point in keeping a checkpoint record for
867 * it. */ 872 * it. */
868 873
869 /* A buffer which has been freed while still being 874 /*
870 * journaled by a previous transaction may end up still 875 * A buffer which has been freed while still being journaled by
871 * being dirty here, but we want to avoid writing back 876 * a previous transaction.
872 * that buffer in the future after the "add to orphan" 877 */
873 * operation been committed, That's not only a performance 878 if (buffer_freed(bh)) {
874 * gain, it also stops aliasing problems if the buffer is 879 /*
875 * left behind for writeback and gets reallocated for another 880 * If the running transaction is the one containing
876 * use in a different page. */ 881 * "add to orphan" operation (b_next_transaction !=
877 if (buffer_freed(bh) && !jh->b_next_transaction) { 882 * NULL), we have to wait for that transaction to
878 clear_buffer_freed(bh); 883 * commit before we can really get rid of the buffer.
879 clear_buffer_jbddirty(bh); 884 * So just clear b_modified to not confuse transaction
885 * credit accounting and refile the buffer to
886 * BJ_Forget of the running transaction. If the just
887 * committed transaction contains "add to orphan"
888 * operation, we can completely invalidate the buffer
889 * now. We are rather throughout in that since the
890 * buffer may be still accessible when blocksize <
891 * pagesize and it is attached to the last partial
892 * page.
893 */
894 jh->b_modified = 0;
895 if (!jh->b_next_transaction) {
896 clear_buffer_freed(bh);
897 clear_buffer_jbddirty(bh);
898 clear_buffer_mapped(bh);
899 clear_buffer_new(bh);
900 clear_buffer_req(bh);
901 bh->b_bdev = NULL;
902 }
880 } 903 }
881 904
882 if (buffer_jbddirty(bh)) { 905 if (buffer_jbddirty(bh)) {