summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c14
-rw-r--r--fs/xfs/linux-2.6/xfs_vfs.h1
-rw-r--r--fs/xfs/xfs_vfsops.c26
3 files changed, 34 insertions, 7 deletions
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index dab5d380237..003e5f29d68 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -659,9 +659,17 @@ xfs_fs_sync_super(
int error;
int flags;
- if (unlikely(sb->s_frozen == SB_FREEZE_WRITE))
- flags = SYNC_QUIESCE;
- else
+ if (unlikely(sb->s_frozen == SB_FREEZE_WRITE)) {
+ /*
+ * First stage of freeze - no more writers will make progress
+ * now we are here, so we flush delwri and delalloc buffers
+ * here, then wait for all I/O to complete. Data is frozen at
+ * that point. Metadata is not frozen, transactions can still
+ * 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_DIO_WAIT;
+ } else
flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0);
error = bhv_vfs_sync(vfsp, flags, NULL);
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h
index da255bdf526..558823a8306 100644
--- a/fs/xfs/linux-2.6/xfs_vfs.h
+++ b/fs/xfs/linux-2.6/xfs_vfs.h
@@ -92,6 +92,7 @@ typedef enum {
#define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */
#define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */
#define SYNC_QUIESCE 0x0100 /* quiesce fileystem for a snapshot */
+#define SYNC_DIO_WAIT 0x0200 /* wait for direct I/O to complete */
#define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */
#define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index f5ea74b999b..c2a6eab7fa2 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -872,6 +872,10 @@ xfs_statvfs(
* this by simply making sure the log gets flushed
* if SYNC_BDFLUSH is set, and by actually writing it
* out otherwise.
+ * SYNC_DIO_WAIT - The caller wants us to wait for all direct I/Os
+ * as well to ensure all data I/O completes before we
+ * return. Forms the drain side of the write barrier needed
+ * to safely quiesce the filesystem.
*
*/
/*ARGSUSED*/
@@ -883,10 +887,7 @@ xfs_sync(
{
xfs_mount_t *mp = XFS_BHVTOM(bdp);
- if (unlikely(flags == SYNC_QUIESCE))
- return xfs_quiesce_fs(mp);
- else
- return xfs_syncsub(mp, flags, NULL);
+ return xfs_syncsub(mp, flags, NULL);
}
/*
@@ -1172,6 +1173,12 @@ xfs_sync_inodes(
}
}
+ /*
+ * When freezing, we need to wait ensure direct I/O is complete
+ * as well to ensure all data modification is complete here
+ */
+ if (flags & SYNC_DIO_WAIT)
+ vn_iowait(vp);
if (flags & SYNC_BDFLUSH) {
if ((flags & SYNC_ATTR) &&
@@ -1950,15 +1957,26 @@ xfs_showargs(
return 0;
}
+/*
+ * 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.
+ */
STATIC void
xfs_freeze(
bhv_desc_t *bdp)
{
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);
+
+ BUG_ON(atomic_read(&mp->m_active_trans) > 0);
+
/* Push the superblock and write an unmount record */
xfs_log_unmount_write(mp);
xfs_unmountfs_writesb(mp);