]> err.no Git - linux-2.6/commitdiff
[XFS] Fix remount,readonly path to flush everything correctly.
authorDavid Chinner <dgc@sgi.com>
Mon, 18 Jun 2007 06:50:48 +0000 (16:50 +1000)
committerTim Shimmin <tes@chook.melbourne.sgi.com>
Sat, 14 Jul 2007 05:35:58 +0000 (15:35 +1000)
The remount readonly path can fail to writeback properly because we still
have active transactions after calling xfs_quiesce_fs(). Further
investigation shows that this path is broken in the same ways that the xfs
freeze path was broken so fix it the same way.

SGI-PV: 964464
SGI-Modid: xfs-linux-melb:xfs-kern:28869a

Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Tim Shimmin <tes@sgi.com>
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_vfs.h
fs/xfs/xfs_vfsops.c

index 05f188ed120620034f38b0fd80d366d995dce21d..06894cf00b129dfd7dd3d146213387ffa20bb082 100644 (file)
@@ -664,7 +664,7 @@ xfs_fs_sync_super(
                 * occur here so don't bother flushing the buftarg (i.e
                 * SYNC_QUIESCE) because it'll just get dirty again.
                 */
-               flags = SYNC_FSDATA | SYNC_DELWRI | SYNC_WAIT | SYNC_IOWAIT;
+               flags = SYNC_DATA_QUIESCE;
        } else
                flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0);
 
index cb7b0d62fb96dd11acaaa51a382e0336e2e2fe30..dca3481aaafa4c0b71b2a550347d2c3c68dced8e 100644 (file)
@@ -94,6 +94,20 @@ typedef enum {
 #define SYNC_IOWAIT            0x0100  /* wait for all I/O to complete */
 #define SYNC_SUPER             0x0200  /* flush superblock to disk */
 
+/*
+ * When remounting a filesystem read-only or freezing the filesystem,
+ * we have two phases to execute. This first phase is syncing the data
+ * before we quiesce the fielsystem, and the second is flushing all the
+ * inodes out after we've waited for all the transactions created by
+ * the first phase to complete. The second phase uses SYNC_INODE_QUIESCE
+ * to ensure that the inodes are written to their location on disk
+ * rather than just existing in transactions in the log. This means
+ * after a quiesce there is no log replay required to write the inodes
+ * to disk (this is the main difference between a sync and a quiesce).
+ */
+#define SYNC_DATA_QUIESCE      (SYNC_DELWRI|SYNC_FSDATA|SYNC_WAIT|SYNC_IOWAIT)
+#define SYNC_INODE_QUIESCE     (SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT)
+
 #define SHUTDOWN_META_IO_ERROR 0x0001  /* write attempt to metadata failed */
 #define SHUTDOWN_LOG_IO_ERROR  0x0002  /* write attempt to the log failed */
 #define SHUTDOWN_FORCE_UMOUNT  0x0004  /* shutdown from a forced unmount */
index 3a647339f40ebc9df7ba6bda5d4f741963adb0f5..c343fde10ef9cab03bf6302b96f65981df2d2e4f 100644 (file)
@@ -640,7 +640,7 @@ xfs_quiesce_fs(
         * we can write the unmount record.
         */
        do {
-               xfs_syncsub(mp, SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT, NULL);
+               xfs_syncsub(mp, SYNC_INODE_QUIESCE, NULL);
                pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
                if (!pincount) {
                        delay(50);
@@ -651,6 +651,30 @@ xfs_quiesce_fs(
        return 0;
 }
 
+/*
+ * Second stage of a quiesce. The data is already synced, now we have to take
+ * care of the metadata. New transactions are already blocked, so we need to
+ * wait for any remaining transactions to drain out before proceding.
+ */
+STATIC void
+xfs_attr_quiesce(
+       xfs_mount_t     *mp)
+{
+       /* wait for all modifications to complete */
+       while (atomic_read(&mp->m_active_trans) > 0)
+               delay(100);
+
+       /* flush inodes and push all remaining buffers out to disk */
+       xfs_quiesce_fs(mp);
+
+       ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0);
+
+       /* Push the superblock and write an unmount record */
+       xfs_log_sbcount(mp, 1);
+       xfs_log_unmount_write(mp);
+       xfs_unmountfs_writesb(mp);
+}
+
 STATIC int
 xfs_mntupdate(
        bhv_desc_t                      *bdp,
@@ -670,11 +694,8 @@ xfs_mntupdate(
                        mp->m_flags &= ~XFS_MOUNT_BARRIER;
                }
        } else if (!(vfsp->vfs_flag & VFS_RDONLY)) {    /* rw -> ro */
-               bhv_vfs_sync(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL);
-               xfs_quiesce_fs(mp);
-               xfs_log_sbcount(mp, 1);
-               xfs_log_unmount_write(mp);
-               xfs_unmountfs_writesb(mp);
+               bhv_vfs_sync(vfsp, SYNC_DATA_QUIESCE, NULL);
+               xfs_attr_quiesce(mp);
                vfsp->vfs_flag |= VFS_RDONLY;
        }
        return 0;
@@ -1952,9 +1973,9 @@ xfs_showargs(
 }
 
 /*
- * Second stage of a freeze. The data is already frozen, now we have to take
- * care of the metadata. New transactions are already blocked, so we need to
- * wait for any remaining transactions to drain out before proceding.
+ * Second stage of a freeze. The data is already frozen so we only
+ * need to take care of themetadata. Once that's done write a dummy
+ * record to dirty the log in case of a crash while frozen.
  */
 STATIC void
 xfs_freeze(
@@ -1962,19 +1983,7 @@ xfs_freeze(
 {
        xfs_mount_t     *mp = XFS_BHVTOM(bdp);
 
-       /* wait for all modifications to complete */
-       while (atomic_read(&mp->m_active_trans) > 0)
-               delay(100);
-
-       /* flush inodes and push all remaining buffers out to disk */
-       xfs_quiesce_fs(mp);
-
-       ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0);
-
-       /* Push the superblock and write an unmount record */
-       xfs_log_sbcount(mp, 1);
-       xfs_log_unmount_write(mp);
-       xfs_unmountfs_writesb(mp);
+       xfs_attr_quiesce(mp);
        xfs_fs_log_dummy(mp);
 }