[XFS] Fix remount,readonly path to flush everything correctly.
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>
This commit is contained in:
parent
957d0ebed0
commit
516b2e7c26
|
@ -664,7 +664,7 @@ xfs_fs_sync_super(
|
||||||
* occur here so don't bother flushing the buftarg (i.e
|
* occur here so don't bother flushing the buftarg (i.e
|
||||||
* SYNC_QUIESCE) because it'll just get dirty again.
|
* SYNC_QUIESCE) because it'll just get dirty again.
|
||||||
*/
|
*/
|
||||||
flags = SYNC_FSDATA | SYNC_DELWRI | SYNC_WAIT | SYNC_IOWAIT;
|
flags = SYNC_DATA_QUIESCE;
|
||||||
} else
|
} else
|
||||||
flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0);
|
flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0);
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,20 @@ typedef enum {
|
||||||
#define SYNC_IOWAIT 0x0100 /* wait for all I/O to complete */
|
#define SYNC_IOWAIT 0x0100 /* wait for all I/O to complete */
|
||||||
#define SYNC_SUPER 0x0200 /* flush superblock to disk */
|
#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_META_IO_ERROR 0x0001 /* write attempt to metadata failed */
|
||||||
#define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */
|
#define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */
|
||||||
#define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */
|
#define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */
|
||||||
|
|
|
@ -640,7 +640,7 @@ xfs_quiesce_fs(
|
||||||
* we can write the unmount record.
|
* we can write the unmount record.
|
||||||
*/
|
*/
|
||||||
do {
|
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);
|
pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
|
||||||
if (!pincount) {
|
if (!pincount) {
|
||||||
delay(50);
|
delay(50);
|
||||||
|
@ -651,6 +651,30 @@ xfs_quiesce_fs(
|
||||||
return 0;
|
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
|
STATIC int
|
||||||
xfs_mntupdate(
|
xfs_mntupdate(
|
||||||
bhv_desc_t *bdp,
|
bhv_desc_t *bdp,
|
||||||
|
@ -670,11 +694,8 @@ xfs_mntupdate(
|
||||||
mp->m_flags &= ~XFS_MOUNT_BARRIER;
|
mp->m_flags &= ~XFS_MOUNT_BARRIER;
|
||||||
}
|
}
|
||||||
} else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */
|
} else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */
|
||||||
bhv_vfs_sync(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL);
|
bhv_vfs_sync(vfsp, SYNC_DATA_QUIESCE, NULL);
|
||||||
xfs_quiesce_fs(mp);
|
xfs_attr_quiesce(mp);
|
||||||
xfs_log_sbcount(mp, 1);
|
|
||||||
xfs_log_unmount_write(mp);
|
|
||||||
xfs_unmountfs_writesb(mp);
|
|
||||||
vfsp->vfs_flag |= VFS_RDONLY;
|
vfsp->vfs_flag |= VFS_RDONLY;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1952,9 +1973,9 @@ xfs_showargs(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Second stage of a freeze. The data is already frozen, now we have to take
|
* Second stage of a freeze. The data is already frozen so we only
|
||||||
* care of the metadata. New transactions are already blocked, so we need to
|
* need to take care of themetadata. Once that's done write a dummy
|
||||||
* wait for any remaining transactions to drain out before proceding.
|
* record to dirty the log in case of a crash while frozen.
|
||||||
*/
|
*/
|
||||||
STATIC void
|
STATIC void
|
||||||
xfs_freeze(
|
xfs_freeze(
|
||||||
|
@ -1962,19 +1983,7 @@ xfs_freeze(
|
||||||
{
|
{
|
||||||
xfs_mount_t *mp = XFS_BHVTOM(bdp);
|
xfs_mount_t *mp = XFS_BHVTOM(bdp);
|
||||||
|
|
||||||
/* wait for all modifications to complete */
|
xfs_attr_quiesce(mp);
|
||||||
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_fs_log_dummy(mp);
|
xfs_fs_log_dummy(mp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue