]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
closefs.c (ext2fs_flush): Make sure the master superblock is
authorTheodore Ts'o <tytso@mit.edu>
Thu, 27 May 2004 01:29:14 +0000 (21:29 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 27 May 2004 01:29:14 +0000 (21:29 -0400)
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
lib/ext2fs/closefs.c

index 54ea2e9c776918a0a4fceb389dacd3cb6a4aab77..751aa9d432bf528e8f94b77e1c0b3807caf7edb5 100644 (file)
@@ -1,5 +1,12 @@
 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
index 1256385b09d0afa98cd6891fc31f85f7e72a9623..71fa9e49ee073a0ef7c42a87f5b3c7474ba3ff37 100644 (file)
@@ -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) {