diff options
author | David Chinner <dgc@sgi.com> | 2007-06-18 02:50:48 -0400 |
---|---|---|
committer | Tim Shimmin <tes@chook.melbourne.sgi.com> | 2007-07-14 01:35:58 -0400 |
commit | 516b2e7c2661615ba5d5ad9fb584f068363502d3 (patch) | |
tree | 984aed9e4dd27cb2acb547dd587525b5e4bf53d9 /fs | |
parent | 957d0ebed04239b734552c7da3fae9094b6f090c (diff) |
[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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_super.c | 2 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_vfs.h | 14 | ||||
-rw-r--r-- | fs/xfs/xfs_vfsops.c | 53 |
3 files changed, 46 insertions, 23 deletions
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 05f188ed1206..06894cf00b12 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
@@ -664,7 +664,7 @@ xfs_fs_sync_super( | |||
664 | * occur here so don't bother flushing the buftarg (i.e | 664 | * occur here so don't bother flushing the buftarg (i.e |
665 | * SYNC_QUIESCE) because it'll just get dirty again. | 665 | * SYNC_QUIESCE) because it'll just get dirty again. |
666 | */ | 666 | */ |
667 | flags = SYNC_FSDATA | SYNC_DELWRI | SYNC_WAIT | SYNC_IOWAIT; | 667 | flags = SYNC_DATA_QUIESCE; |
668 | } else | 668 | } else |
669 | flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0); | 669 | flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0); |
670 | 670 | ||
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h index cb7b0d62fb96..dca3481aaafa 100644 --- a/fs/xfs/linux-2.6/xfs_vfs.h +++ b/fs/xfs/linux-2.6/xfs_vfs.h | |||
@@ -94,6 +94,20 @@ typedef enum { | |||
94 | #define SYNC_IOWAIT 0x0100 /* wait for all I/O to complete */ | 94 | #define SYNC_IOWAIT 0x0100 /* wait for all I/O to complete */ |
95 | #define SYNC_SUPER 0x0200 /* flush superblock to disk */ | 95 | #define SYNC_SUPER 0x0200 /* flush superblock to disk */ |
96 | 96 | ||
97 | /* | ||
98 | * When remounting a filesystem read-only or freezing the filesystem, | ||
99 | * we have two phases to execute. This first phase is syncing the data | ||
100 | * before we quiesce the fielsystem, and the second is flushing all the | ||
101 | * inodes out after we've waited for all the transactions created by | ||
102 | * the first phase to complete. The second phase uses SYNC_INODE_QUIESCE | ||
103 | * to ensure that the inodes are written to their location on disk | ||
104 | * rather than just existing in transactions in the log. This means | ||
105 | * after a quiesce there is no log replay required to write the inodes | ||
106 | * to disk (this is the main difference between a sync and a quiesce). | ||
107 | */ | ||
108 | #define SYNC_DATA_QUIESCE (SYNC_DELWRI|SYNC_FSDATA|SYNC_WAIT|SYNC_IOWAIT) | ||
109 | #define SYNC_INODE_QUIESCE (SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT) | ||
110 | |||
97 | #define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */ | 111 | #define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */ |
98 | #define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */ | 112 | #define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */ |
99 | #define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */ | 113 | #define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */ |
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 3a647339f40e..c343fde10ef9 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c | |||
@@ -640,7 +640,7 @@ xfs_quiesce_fs( | |||
640 | * we can write the unmount record. | 640 | * we can write the unmount record. |
641 | */ | 641 | */ |
642 | do { | 642 | do { |
643 | xfs_syncsub(mp, SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT, NULL); | 643 | xfs_syncsub(mp, SYNC_INODE_QUIESCE, NULL); |
644 | pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); | 644 | pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); |
645 | if (!pincount) { | 645 | if (!pincount) { |
646 | delay(50); | 646 | delay(50); |
@@ -651,6 +651,30 @@ xfs_quiesce_fs( | |||
651 | return 0; | 651 | return 0; |
652 | } | 652 | } |
653 | 653 | ||
654 | /* | ||
655 | * Second stage of a quiesce. The data is already synced, now we have to take | ||
656 | * care of the metadata. New transactions are already blocked, so we need to | ||
657 | * wait for any remaining transactions to drain out before proceding. | ||
658 | */ | ||
659 | STATIC void | ||
660 | xfs_attr_quiesce( | ||
661 | xfs_mount_t *mp) | ||
662 | { | ||
663 | /* wait for all modifications to complete */ | ||
664 | while (atomic_read(&mp->m_active_trans) > 0) | ||
665 | delay(100); | ||
666 | |||
667 | /* flush inodes and push all remaining buffers out to disk */ | ||
668 | xfs_quiesce_fs(mp); | ||
669 | |||
670 | ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0); | ||
671 | |||
672 | /* Push the superblock and write an unmount record */ | ||
673 | xfs_log_sbcount(mp, 1); | ||
674 | xfs_log_unmount_write(mp); | ||
675 | xfs_unmountfs_writesb(mp); | ||
676 | } | ||
677 | |||
654 | STATIC int | 678 | STATIC int |
655 | xfs_mntupdate( | 679 | xfs_mntupdate( |
656 | bhv_desc_t *bdp, | 680 | bhv_desc_t *bdp, |
@@ -670,11 +694,8 @@ xfs_mntupdate( | |||
670 | mp->m_flags &= ~XFS_MOUNT_BARRIER; | 694 | mp->m_flags &= ~XFS_MOUNT_BARRIER; |
671 | } | 695 | } |
672 | } else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */ | 696 | } else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */ |
673 | bhv_vfs_sync(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL); | 697 | bhv_vfs_sync(vfsp, SYNC_DATA_QUIESCE, NULL); |
674 | xfs_quiesce_fs(mp); | 698 | xfs_attr_quiesce(mp); |
675 | xfs_log_sbcount(mp, 1); | ||
676 | xfs_log_unmount_write(mp); | ||
677 | xfs_unmountfs_writesb(mp); | ||
678 | vfsp->vfs_flag |= VFS_RDONLY; | 699 | vfsp->vfs_flag |= VFS_RDONLY; |
679 | } | 700 | } |
680 | return 0; | 701 | return 0; |
@@ -1952,9 +1973,9 @@ xfs_showargs( | |||
1952 | } | 1973 | } |
1953 | 1974 | ||
1954 | /* | 1975 | /* |
1955 | * Second stage of a freeze. The data is already frozen, now we have to take | 1976 | * Second stage of a freeze. The data is already frozen so we only |
1956 | * care of the metadata. New transactions are already blocked, so we need to | 1977 | * need to take care of themetadata. Once that's done write a dummy |
1957 | * wait for any remaining transactions to drain out before proceding. | 1978 | * record to dirty the log in case of a crash while frozen. |
1958 | */ | 1979 | */ |
1959 | STATIC void | 1980 | STATIC void |
1960 | xfs_freeze( | 1981 | xfs_freeze( |
@@ -1962,19 +1983,7 @@ xfs_freeze( | |||
1962 | { | 1983 | { |
1963 | xfs_mount_t *mp = XFS_BHVTOM(bdp); | 1984 | xfs_mount_t *mp = XFS_BHVTOM(bdp); |
1964 | 1985 | ||
1965 | /* wait for all modifications to complete */ | 1986 | xfs_attr_quiesce(mp); |
1966 | while (atomic_read(&mp->m_active_trans) > 0) | ||
1967 | delay(100); | ||
1968 | |||
1969 | /* flush inodes and push all remaining buffers out to disk */ | ||
1970 | xfs_quiesce_fs(mp); | ||
1971 | |||
1972 | ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0); | ||
1973 | |||
1974 | /* Push the superblock and write an unmount record */ | ||
1975 | xfs_log_sbcount(mp, 1); | ||
1976 | xfs_log_unmount_write(mp); | ||
1977 | xfs_unmountfs_writesb(mp); | ||
1978 | xfs_fs_log_dummy(mp); | 1987 | xfs_fs_log_dummy(mp); |
1979 | } | 1988 | } |
1980 | 1989 | ||