Skip to content

Commit

Permalink
xfs: allow lazy sb counter sync during filesystem freeze sequence
Browse files Browse the repository at this point in the history
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:

	92821e2 [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 <[email protected]>
Reviewed-by: Dave Chinner <[email protected]>
Signed-off-by: Dave Chinner <[email protected]>
  • Loading branch information
Brian Foster authored and dchinner committed Nov 28, 2014
1 parent 5d45ee1 commit 91ee575
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 10 deletions.
2 changes: 1 addition & 1 deletion fs/xfs/xfs_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,7 @@ xfs_log_need_covered(xfs_mount_t *mp)
struct xlog *log = mp->m_log;
int needed = 0;

if (!xfs_fs_writable(mp))
if (!xfs_fs_writable(mp, SB_FREEZE_WRITE))
return 0;

if (!xlog_cil_empty(log))
Expand Down
29 changes: 21 additions & 8 deletions fs/xfs/xfs_mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -1074,29 +1074,42 @@ xfs_unmountfs(
xfs_sysfs_del(&mp->m_kobj);
}

int
xfs_fs_writable(xfs_mount_t *mp)
/*
* Determine whether modifications can proceed. The caller specifies the minimum
* freeze level for which modifications should not be allowed. This allows
* certain operations to proceed while the freeze sequence is in progress, if
* necessary.
*/
bool
xfs_fs_writable(
struct xfs_mount *mp,
int level)
{
return !(mp->m_super->s_writers.frozen || XFS_FORCED_SHUTDOWN(mp) ||
(mp->m_flags & XFS_MOUNT_RDONLY));
ASSERT(level > SB_UNFROZEN);
if ((mp->m_super->s_writers.frozen >= level) ||
XFS_FORCED_SHUTDOWN(mp) || (mp->m_flags & XFS_MOUNT_RDONLY))
return false;

return true;
}

/*
* xfs_log_sbcount
*
* Sync the superblock counters to disk.
*
* Note this code can be called during the process of freezing, so
* we may need to use the transaction allocator which does not
* block when the transaction subsystem is in its frozen state.
* Note this code can be called during the process of freezing, so we use the
* transaction allocator that does not block when the transaction subsystem is
* in its frozen state.
*/
int
xfs_log_sbcount(xfs_mount_t *mp)
{
xfs_trans_t *tp;
int error;

if (!xfs_fs_writable(mp))
/* allow this to proceed during the freeze sequence... */
if (!xfs_fs_writable(mp, SB_FREEZE_COMPLETE))
return 0;

xfs_icsb_sync_counters(mp, 0);
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ extern int xfs_mount_log_sb(xfs_mount_t *, __int64_t);
extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
extern int xfs_readsb(xfs_mount_t *, int);
extern void xfs_freesb(xfs_mount_t *);
extern int xfs_fs_writable(xfs_mount_t *);
extern bool xfs_fs_writable(struct xfs_mount *mp, int level);
extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t);

extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
Expand Down

0 comments on commit 91ee575

Please sign in to comment.