aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2014-11-27 22:02:59 -0500
committerDave Chinner <david@fromorbit.com>2014-11-27 22:02:59 -0500
commit91ee575f2b35d1307412f917787195c2f6a38dfb (patch)
tree48656a90f7f4cfb87f743b3228fd9537dea9db30 /fs/xfs
parent5d45ee1b41b02269ce04920a48cd2c6b2a458090 (diff)
xfs: allow lazy sb counter sync during filesystem freeze sequence
The expectation since the introduction the lazy superblock counters is that the counters are synced and superblock logged appropriately as part of the filesystem freeze sequence. This does not occur, however, due to the logic in xfs_fs_writable() that prevents progress when the fs is in any state other than SB_UNFROZEN. While this is a bug, it has not been exposed to date because the last thing XFS does during freeze is dirty the log. The log recovery process recalculates the counters from AGI/AGF metadata to ensure everything is correct. Therefore should a crash occur while an fs is frozen, the subsequent log recovery puts everything back in order. See the following commit for reference: 92821e2b [XFS] Lazy Superblock Counters We might not always want to rely on dirtying the log on a frozen fs. Modify xfs_log_sbcount() to proceed when the filesystem is freezing but not once the freeze process has completed. Modify xfs_fs_writable() to accept the minimum freeze level for which modifications should be blocked to support various codepaths. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_log.c2
-rw-r--r--fs/xfs/xfs_mount.c29
-rw-r--r--fs/xfs/xfs_mount.h2
3 files changed, 23 insertions, 10 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index fe88ef67f93a..e810e9df91b7 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -1031,7 +1031,7 @@ xfs_log_need_covered(xfs_mount_t *mp)
1031 struct xlog *log = mp->m_log; 1031 struct xlog *log = mp->m_log;
1032 int needed = 0; 1032 int needed = 0;
1033 1033
1034 if (!xfs_fs_writable(mp)) 1034 if (!xfs_fs_writable(mp, SB_FREEZE_WRITE))
1035 return 0; 1035 return 0;
1036 1036
1037 if (!xlog_cil_empty(log)) 1037 if (!xlog_cil_empty(log))
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 51435dbce9c4..13d117089101 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1074,11 +1074,23 @@ xfs_unmountfs(
1074 xfs_sysfs_del(&mp->m_kobj); 1074 xfs_sysfs_del(&mp->m_kobj);
1075} 1075}
1076 1076
1077int 1077/*
1078xfs_fs_writable(xfs_mount_t *mp) 1078 * Determine whether modifications can proceed. The caller specifies the minimum
1079 * freeze level for which modifications should not be allowed. This allows
1080 * certain operations to proceed while the freeze sequence is in progress, if
1081 * necessary.
1082 */
1083bool
1084xfs_fs_writable(
1085 struct xfs_mount *mp,
1086 int level)
1079{ 1087{
1080 return !(mp->m_super->s_writers.frozen || XFS_FORCED_SHUTDOWN(mp) || 1088 ASSERT(level > SB_UNFROZEN);
1081 (mp->m_flags & XFS_MOUNT_RDONLY)); 1089 if ((mp->m_super->s_writers.frozen >= level) ||
1090 XFS_FORCED_SHUTDOWN(mp) || (mp->m_flags & XFS_MOUNT_RDONLY))
1091 return false;
1092
1093 return true;
1082} 1094}
1083 1095
1084/* 1096/*
@@ -1086,9 +1098,9 @@ xfs_fs_writable(xfs_mount_t *mp)
1086 * 1098 *
1087 * Sync the superblock counters to disk. 1099 * Sync the superblock counters to disk.
1088 * 1100 *
1089 * Note this code can be called during the process of freezing, so 1101 * Note this code can be called during the process of freezing, so we use the
1090 * we may need to use the transaction allocator which does not 1102 * transaction allocator that does not block when the transaction subsystem is
1091 * block when the transaction subsystem is in its frozen state. 1103 * in its frozen state.
1092 */ 1104 */
1093int 1105int
1094xfs_log_sbcount(xfs_mount_t *mp) 1106xfs_log_sbcount(xfs_mount_t *mp)
@@ -1096,7 +1108,8 @@ xfs_log_sbcount(xfs_mount_t *mp)
1096 xfs_trans_t *tp; 1108 xfs_trans_t *tp;
1097 int error; 1109 int error;
1098 1110
1099 if (!xfs_fs_writable(mp)) 1111 /* allow this to proceed during the freeze sequence... */
1112 if (!xfs_fs_writable(mp, SB_FREEZE_COMPLETE))
1100 return 0; 1113 return 0;
1101 1114
1102 xfs_icsb_sync_counters(mp, 0); 1115 xfs_icsb_sync_counters(mp, 0);
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 394bc711171a..01fb28f5ae1c 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -385,7 +385,7 @@ extern int xfs_mount_log_sb(xfs_mount_t *, __int64_t);
385extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int); 385extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
386extern int xfs_readsb(xfs_mount_t *, int); 386extern int xfs_readsb(xfs_mount_t *, int);
387extern void xfs_freesb(xfs_mount_t *); 387extern void xfs_freesb(xfs_mount_t *);
388extern int xfs_fs_writable(xfs_mount_t *); 388extern bool xfs_fs_writable(struct xfs_mount *mp, int level);
389extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t); 389extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t);
390 390
391extern int xfs_dev_is_read_only(struct xfs_mount *, char *); 391extern int xfs_dev_is_read_only(struct xfs_mount *, char *);