2004-05-26 Theodore Ts'o <tytso@mit.edu>
+ * 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
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++) {
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
}
}
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
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) {