From a63d12678369f4ab0edf8fc5741825c035e78bf9 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 26 May 2004 21:29:14 -0400 Subject: [PATCH] closefs.c (ext2fs_flush): Make sure the master superblock is written last, and only after other I/O has been flushed to disk. Thanks to Junfeng Yang from the Stanford Metacompilation group for pointing a potential ordering constraint problem if we don't write things out in the right order. --- lib/ext2fs/ChangeLog | 7 +++++++ lib/ext2fs/closefs.c | 46 +++++++++++++++++++++++--------------------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index 54ea2e9c7..751aa9d43 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,5 +1,12 @@ 2004-05-26 Theodore Ts'o + * closefs.c (ext2fs_flush): Make sure the master superblock is + written last, and only after other I/O has been flushed to + disk. Thanks to Junfeng Yang from the Stanford + Metacompilation group for pointing a potential ordering + constraint problem if we don't write things out in the + right order. + * test_io.c: Implement the ability to abort after n reads or writes to a particular block. The block is specified by TEST_IO_BLOCK environment variable, and the read/write diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c index 1256385b0..71fa9e49e 100644 --- a/lib/ext2fs/closefs.c +++ b/lib/ext2fs/closefs.c @@ -234,10 +234,6 @@ errcode_t ext2fs_flush(ext2_filsys fs) memset(group_shadow, 0, (size_t) fs->blocksize * fs->desc_blocks); - /* swap the superblock */ - *super_shadow = *fs->super; - ext2fs_swap_super(super_shadow); - /* swap the group descriptors */ for (j=0, s=fs->group_desc, t=group_shadow; j < fs->group_desc_count; j++, t++, s++) { @@ -253,29 +249,18 @@ errcode_t ext2fs_flush(ext2_filsys fs) group_shadow = fs->group_desc; #endif - /* - * Write out master superblock. This has to be done - * separately, since it is located at a fixed location - * (SUPERBLOCK_OFFSET). - */ - retval = write_primary_superblock(fs, super_shadow); - if (retval) - goto errout; - /* * If this is an external journal device, don't write out the * block group descriptors or any of the backup superblocks */ if (fs->super->s_feature_incompat & - EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { - retval = 0; - goto errout; - } + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + goto write_primary_superblock_only; /* * Set the state of the FS to be non-valid. (The state has - * already been backed up earlier, and will be restored when - * we exit.) + * already been backed up earlier, and will be restored after + * we write out the backup superblocks.) */ fs->super->s_state &= ~EXT2_VALID_FS; #ifdef EXT2FS_ENABLE_SWAPFS @@ -326,6 +311,13 @@ errcode_t ext2fs_flush(ext2_filsys fs) } } fs->super->s_block_group_nr = 0; + fs->super->s_state = fs_state; +#ifdef EXT2FS_ENABLE_SWAPFS + if (fs->flags & EXT2_FLAG_SWAP_BYTES) { + *super_shadow = *fs->super; + ext2fs_swap_super(super_shadow); + } +#endif /* * If the write_bitmaps() function is present, call it to @@ -339,12 +331,22 @@ errcode_t ext2fs_flush(ext2_filsys fs) goto errout; } - fs->flags &= ~EXT2_FLAG_DIRTY; - +write_primary_superblock_only: /* - * Flush the blocks out to disk + * Write out master superblock. This has to be done + * separately, since it is located at a fixed location + * (SUPERBLOCK_OFFSET). We flush all other pending changes + * out to disk first, just to avoid a race condition with an + * insy-tinsy window.... */ retval = io_channel_flush(fs->io); + retval = write_primary_superblock(fs, super_shadow); + if (retval) + goto errout; + + fs->flags &= ~EXT2_FLAG_DIRTY; + + retval = io_channel_flush(fs->io); errout: fs->super->s_state = fs_state; if (fs->flags & EXT2_FLAG_SWAP_BYTES) { -- 2.47.3