diff options
author | Jan Kara <jack@suse.cz> | 2012-03-13 22:22:54 -0400 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2015-08-12 16:33:15 +0200 |
commit | a3ceb22921615827bfed39d7612a9a370bff0edb (patch) | |
tree | f068d9991d554ad8cba128636e4d25a459d16c4d /fs/jbd2/commit.c | |
parent | dd8ff32c1e7ed10fb0e168b4431983e09acbeb2f (diff) | |
download | lwn-a3ceb22921615827bfed39d7612a9a370bff0edb.tar.gz lwn-a3ceb22921615827bfed39d7612a9a370bff0edb.zip |
jbd2: issue cache flush after checkpointing even with internal journal
commit 79feb521a44705262d15cc819a4117a447b11ea7 upstream.
When we reach jbd2_cleanup_journal_tail(), there is no guarantee that
checkpointed buffers are on a stable storage - especially if buffers were
written out by jbd2_log_do_checkpoint(), they are likely to be only in disk's
caches. Thus when we update journal superblock effectively removing old
transaction from journal, this write of superblock can get to stable storage
before those checkpointed buffers which can result in filesystem corruption
after a crash. Thus we must unconditionally issue a cache flush before we
update journal superblock in these cases.
A similar problem can also occur if journal superblock is written only in
disk's caches, other transaction starts reusing space of the transaction
cleaned from the log and power failure happens. Subsequent journal replay would
still try to replay the old transaction but some of it's blocks may be already
overwritten by the new transaction. For this reason we must use WRITE_FUA when
updating log tail and we must first write new log tail to disk and update
in-memory information only after that.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
[bwh: Prerequisite for "jbd2: fix ocfs2 corrupt when updating journal
superblock fails".
Backported to 3.2:
- Adjust context
- Drop changes to jbd2_journal_update_sb_log_tail trace event]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'fs/jbd2/commit.c')
-rw-r--r-- | fs/jbd2/commit.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index aba8dbd80b9c..bccb60533f93 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -340,7 +340,16 @@ void jbd2_journal_commit_transaction(journal_t *journal) /* Do we need to erase the effects of a prior jbd2_journal_flush? */ if (journal->j_flags & JBD2_FLUSHED) { jbd_debug(3, "super block updated\n"); - jbd2_journal_update_sb_log_tail(journal); + /* + * We hold j_checkpoint_mutex so tail cannot change under us. + * We don't need any special data guarantees for writing sb + * since journal is empty and it is ok for write to be + * flushed only with transaction commit. + */ + jbd2_journal_update_sb_log_tail(journal, + journal->j_tail_sequence, + journal->j_tail, + WRITE_SYNC); } else { jbd_debug(3, "superblock not updated\n"); } |