Skip to content

Commit

Permalink
xfs: convert remaining mount flags to state flags
Browse files Browse the repository at this point in the history
The remaining mount flags kept in m_flags are actually runtime state
flags. These change dynamically, so they really should be updated
atomically so we don't potentially lose an update due to racing
modifications.

Convert these remaining flags to be stored in m_opstate and use
atomic bitops to set and clear the flags. This also adds a couple of
simple wrappers for common state checks - read only and shutdown.

Signed-off-by: Dave Chinner <[email protected]>
Reviewed-by: Darrick J. Wong <[email protected]>
Signed-off-by: Darrick J. Wong <[email protected]>
  • Loading branch information
Dave Chinner authored and Darrick J. Wong committed Aug 19, 2021
1 parent 0560f31 commit 2e973b2
Show file tree
Hide file tree
Showing 18 changed files with 82 additions and 83 deletions.
2 changes: 1 addition & 1 deletion fs/xfs/libxfs/xfs_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3166,7 +3166,7 @@ xfs_alloc_vextent(
* the first a.g. fails.
*/
if ((args->datatype & XFS_ALLOC_INITIAL_USER_DATA) &&
(mp->m_flags & XFS_MOUNT_32BITINODES)) {
xfs_is_inode32(mp)) {
args->fsbno = XFS_AGB_TO_FSB(mp,
((mp->m_agfrotor / rotorstep) %
mp->m_sb.sb_agcount), 0);
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/libxfs/xfs_sb.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ xfs_validate_sb_read(
"Superblock has unknown read-only compatible features (0x%x) enabled.",
(sbp->sb_features_ro_compat &
XFS_SB_FEAT_RO_COMPAT_UNKNOWN));
if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
if (!xfs_is_readonly(mp)) {
xfs_warn(mp,
"Attempted to mount read-only compatible filesystem read-write.");
xfs_warn(mp,
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/scrub/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ xchk_start_reaping(
* Readonly filesystems do not perform inactivation or speculative
* preallocation, so there's no need to restart the workers.
*/
if (!(sc->mp->m_flags & XFS_MOUNT_RDONLY)) {
if (!xfs_is_readonly(sc->mp)) {
xfs_inodegc_start(sc->mp);
xfs_blockgc_start(sc->mp);
}
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/scrub/scrub.c
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ xchk_validate_inputs(
goto out;

error = -EROFS;
if (mp->m_flags & XFS_MOUNT_RDONLY)
if (xfs_is_readonly(mp))
goto out;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ xfs_buf_ioerror_permanent(
return true;

/* At unmount we may treat errors differently */
if ((mp->m_flags & XFS_MOUNT_UNMOUNTING) && mp->m_fail_unmount)
if (xfs_is_unmounting(mp) && mp->m_fail_unmount)
return true;

return false;
Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_export.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ xfs_fs_encode_fh(
int *max_len,
struct inode *parent)
{
struct xfs_mount *mp = XFS_M(inode->i_sb);
struct fid *fid = (struct fid *)fh;
struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fh;
int fileid_type;
Expand All @@ -63,8 +64,7 @@ xfs_fs_encode_fh(
* large enough filesystem may contain them, thus the slightly
* confusing looking conditional below.
*/
if (!xfs_has_small_inums(XFS_M(inode->i_sb)) ||
(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_32BITINODES))
if (!xfs_has_small_inums(mp) || xfs_is_inode32(mp))
fileid_type |= XFS_FILEID_TYPE_64FLAG;

/*
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_filestream.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ xfs_filestream_lookup_ag(
* Set the starting AG using the rotor for inode32, otherwise
* use the directory inode's AG.
*/
if (mp->m_flags & XFS_MOUNT_32BITINODES) {
if (xfs_is_inode32(mp)) {
xfs_agnumber_t rotorstep = xfs_rotorstep;
startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount;
mp->m_agfrotor = (mp->m_agfrotor + 1) %
Expand Down
7 changes: 1 addition & 6 deletions fs/xfs/xfs_fsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,15 +528,10 @@ xfs_do_force_shutdown(
int tag;
const char *why;

spin_lock(&mp->m_sb_lock);
if (XFS_FORCED_SHUTDOWN(mp)) {
spin_unlock(&mp->m_sb_lock);
if (test_and_set_bit(XFS_OPSTATE_SHUTDOWN, &mp->m_opstate))
return;
}
mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN;
if (mp->m_sb_bp)
mp->m_sb_bp->b_flags |= XBF_DONE;
spin_unlock(&mp->m_sb_lock);

if (flags & SHUTDOWN_FORCE_UMOUNT)
xfs_alert(mp, "User initiated shutdown received.");
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_icache.c
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ static inline bool
xfs_want_reclaim_sick(
struct xfs_mount *mp)
{
return (mp->m_flags & XFS_MOUNT_UNMOUNTING) || xfs_has_norecovery(mp) ||
return xfs_is_unmounting(mp) || xfs_has_norecovery(mp) ||
XFS_FORCED_SHUTDOWN(mp);
}

Expand Down
6 changes: 3 additions & 3 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1434,7 +1434,7 @@ xfs_release(
return 0;

/* If this is a read-only mount, don't do this (would generate I/O) */
if (mp->m_flags & XFS_MOUNT_RDONLY)
if (xfs_is_readonly(mp))
return 0;

if (!XFS_FORCED_SHUTDOWN(mp)) {
Expand Down Expand Up @@ -1674,7 +1674,7 @@ xfs_inode_needs_inactive(
return false;

/* If this is a read-only mount, don't do this (would generate I/O) */
if (mp->m_flags & XFS_MOUNT_RDONLY)
if (xfs_is_readonly(mp))
return false;

/* If the log isn't running, push inodes straight to reclaim. */
Expand Down Expand Up @@ -1735,7 +1735,7 @@ xfs_inactive(
ASSERT(!xfs_iflags_test(ip, XFS_IRECOVERY));

/* If this is a read-only mount, don't do this (would generate I/O) */
if (mp->m_flags & XFS_MOUNT_RDONLY)
if (xfs_is_readonly(mp))
goto out;

/* Metadata inodes require explicit resource cleanup. */
Expand Down
6 changes: 3 additions & 3 deletions fs/xfs/xfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1262,7 +1262,7 @@ xfs_ioctl_setattr_get_trans(
struct xfs_trans *tp;
int error = -EROFS;

if (mp->m_flags & XFS_MOUNT_RDONLY)
if (xfs_is_readonly(mp))
goto out_error;
error = -EIO;
if (XFS_FORCED_SHUTDOWN(mp))
Expand Down Expand Up @@ -2080,7 +2080,7 @@ xfs_file_ioctl(
if (!capable(CAP_SYS_ADMIN))
return -EPERM;

if (mp->m_flags & XFS_MOUNT_RDONLY)
if (xfs_is_readonly(mp))
return -EROFS;

if (copy_from_user(&inout, arg, sizeof(inout)))
Expand Down Expand Up @@ -2197,7 +2197,7 @@ xfs_file_ioctl(
if (!capable(CAP_SYS_ADMIN))
return -EPERM;

if (mp->m_flags & XFS_MOUNT_RDONLY)
if (xfs_is_readonly(mp))
return -EROFS;

if (copy_from_user(&eofb, arg, sizeof(eofb)))
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ xfs_vn_change_ok(
{
struct xfs_mount *mp = XFS_I(d_inode(dentry))->i_mount;

if (mp->m_flags & XFS_MOUNT_RDONLY)
if (xfs_is_readonly(mp))
return -EROFS;

if (XFS_FORCED_SHUTDOWN(mp))
Expand Down
31 changes: 17 additions & 14 deletions fs/xfs/xfs_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ xfs_log_mount(
xfs_notice(mp,
"Mounting V%d filesystem in no-recovery mode. Filesystem will be inconsistent.",
XFS_SB_VERSION_NUM(&mp->m_sb));
ASSERT(mp->m_flags & XFS_MOUNT_RDONLY);
ASSERT(xfs_is_readonly(mp));
}

log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks);
Expand Down Expand Up @@ -720,15 +720,15 @@ xfs_log_mount(
* just worked.
*/
if (!xfs_has_norecovery(mp)) {
bool readonly = (mp->m_flags & XFS_MOUNT_RDONLY);

if (readonly)
mp->m_flags &= ~XFS_MOUNT_RDONLY;

/*
* log recovery ignores readonly state and so we need to clear
* mount-based read only state so it can write to disk.
*/
bool readonly = test_and_clear_bit(XFS_OPSTATE_READONLY,
&mp->m_opstate);
error = xlog_recover(log);

if (readonly)
mp->m_flags |= XFS_MOUNT_RDONLY;
set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);
if (error) {
xfs_warn(mp, "log mount/recovery failed: error %d",
error);
Expand Down Expand Up @@ -777,17 +777,20 @@ xfs_log_mount_finish(
struct xfs_mount *mp)
{
struct xlog *log = mp->m_log;
bool readonly = (mp->m_flags & XFS_MOUNT_RDONLY);
bool readonly;
int error = 0;

if (xfs_has_norecovery(mp)) {
ASSERT(readonly);
ASSERT(xfs_is_readonly(mp));
return 0;
} else if (readonly) {
/* Allow unlinked processing to proceed */
mp->m_flags &= ~XFS_MOUNT_RDONLY;
}

/*
* log recovery ignores readonly state and so we need to clear
* mount-based read only state so it can write to disk.
*/
readonly = test_and_clear_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);

/*
* During the second phase of log recovery, we need iget and
* iput to behave like they do for an active filesystem.
Expand Down Expand Up @@ -839,7 +842,7 @@ xfs_log_mount_finish(

clear_bit(XLOG_RECOVERY_NEEDED, &log->l_opstate);
if (readonly)
mp->m_flags |= XFS_MOUNT_RDONLY;
set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);

/* Make sure the log is dead if we're returning failure. */
ASSERT(!error || xlog_is_shutdown(log));
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_log_recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -1347,7 +1347,7 @@ xlog_find_tail(
* headers if we have a filesystem using non-persistent counters.
*/
if (clean)
log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN;
set_bit(XFS_OPSTATE_CLEAN, &log->l_mp->m_opstate);

/*
* Make sure that there are no blocks in front of the head
Expand Down
15 changes: 7 additions & 8 deletions fs/xfs/xfs_mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ xfs_check_summary_counts(
* counters. If any of them are obviously incorrect, we can recompute
* them from the AGF headers in the next step.
*/
if (XFS_LAST_UNMOUNT_WAS_CLEAN(mp) &&
if (xfs_is_clean(mp) &&
(mp->m_sb.sb_fdblocks > mp->m_sb.sb_dblocks ||
!xfs_verify_icount(mp, mp->m_sb.sb_icount) ||
mp->m_sb.sb_ifree > mp->m_sb.sb_icount))
Expand All @@ -505,8 +505,7 @@ xfs_check_summary_counts(
* superblock to be correct and we don't need to do anything here.
* Otherwise, recalculate the summary counters.
*/
if ((!xfs_has_lazysbcount(mp) ||
XFS_LAST_UNMOUNT_WAS_CLEAN(mp)) &&
if ((!xfs_has_lazysbcount(mp) || xfs_is_clean(mp)) &&
!xfs_fs_has_sickness(mp, XFS_SICK_FS_COUNTERS))
return 0;

Expand Down Expand Up @@ -547,7 +546,7 @@ xfs_unmount_flush_inodes(
xfs_extent_busy_wait_all(mp);
flush_workqueue(xfs_discard_wq);

mp->m_flags |= XFS_MOUNT_UNMOUNTING;
set_bit(XFS_OPSTATE_UNMOUNTING, &mp->m_opstate);

xfs_ail_push_all_sync(mp->m_ail);
xfs_inodegc_stop(mp);
Expand Down Expand Up @@ -835,7 +834,7 @@ xfs_mountfs(
* the next remount into writeable mode. Otherwise we would never
* perform the update e.g. for the root filesystem.
*/
if (mp->m_update_sb && !(mp->m_flags & XFS_MOUNT_RDONLY)) {
if (mp->m_update_sb && !xfs_is_readonly(mp)) {
error = xfs_sync_sb(mp, false);
if (error) {
xfs_warn(mp, "failed to write sb changes");
Expand Down Expand Up @@ -892,7 +891,7 @@ xfs_mountfs(
* We use the same quiesce mechanism as the rw->ro remount, as they are
* semantically identical operations.
*/
if ((mp->m_flags & XFS_MOUNT_RDONLY) && !xfs_has_norecovery(mp))
if (xfs_is_readonly(mp) && !xfs_has_norecovery(mp))
xfs_log_clean(mp);

/*
Expand All @@ -916,7 +915,7 @@ xfs_mountfs(
* This may drive us straight to ENOSPC on mount, but that implies
* we were already there on the last unmount. Warn if this occurs.
*/
if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
if (!xfs_is_readonly(mp)) {
resblks = xfs_default_resblks(mp);
error = xfs_reserve_blocks(mp, &resblks, NULL);
if (error)
Expand Down Expand Up @@ -1077,7 +1076,7 @@ xfs_fs_writable(
{
ASSERT(level > SB_UNFROZEN);
if ((mp->m_super->s_writers.frozen >= level) ||
XFS_FORCED_SHUTDOWN(mp) || (mp->m_flags & XFS_MOUNT_RDONLY))
XFS_FORCED_SHUTDOWN(mp) || xfs_is_readonly(mp))
return false;

return true;
Expand Down
42 changes: 23 additions & 19 deletions fs/xfs/xfs_mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ typedef struct xfs_mount {
uint m_rsumsize; /* size of rt summary, bytes */
int m_fixedfsid[2]; /* unchanged for life of FS */
uint m_qflags; /* quota status flags */
uint64_t m_flags; /* global mount flags */
uint64_t m_features; /* active filesystem features */
uint64_t m_low_space[XFS_LOWSP_MAX];
uint64_t m_low_rtexts[XFS_LOWSP_MAX];
Expand Down Expand Up @@ -342,8 +341,8 @@ __XFS_HAS_FEAT(needsrepair, NEEDSREPAIR)
/*
* Mount features
*
* These do not change dynamically - features that can come and go,
* such as 32 bit inodes and read-only state, are kept as flags rather than
* These do not change dynamically - features that can come and go, such as 32
* bit inodes and read-only state, are kept as operational state rather than
* features.
*/
__XFS_HAS_FEAT(noattr2, NOATTR2)
Expand All @@ -364,31 +363,28 @@ __XFS_HAS_FEAT(norecovery, NORECOVERY)
__XFS_HAS_FEAT(nouuid, NOUUID)

/*
* Flags for m_flags.
* Operational mount state flags
*
* Use these with atomic bit ops only!
*/
#define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops
must be synchronous except
for space allocations */
#define XFS_MOUNT_UNMOUNTING (1ULL << 1) /* filesystem is unmounting */
#define XFS_MOUNT_WAS_CLEAN (1ULL << 2)
#define XFS_MOUNT_FS_SHUTDOWN (1ULL << 3) /* atomic stop of all filesystem
operations, typically for
disk errors in metadata */
#define XFS_MOUNT_32BITINODES (1ULL << 15) /* inode32 allocator active */
#define XFS_MOUNT_RDONLY (1ULL << 4) /* read-only fs */
#define XFS_OPSTATE_UNMOUNTING 0 /* filesystem is unmounting */
#define XFS_OPSTATE_CLEAN 1 /* mount was clean */
#define XFS_OPSTATE_SHUTDOWN 2 /* stop all fs operations */
#define XFS_OPSTATE_INODE32 3 /* inode32 allocator active */
#define XFS_OPSTATE_READONLY 4 /* read-only fs */

/*
* If set, inactivation worker threads will be scheduled to process queued
* inodegc work. If not, queued inodes remain in memory waiting to be
* processed.
*/
#define XFS_OPSTATE_INODEGC_ENABLED 0
#define XFS_OPSTATE_INODEGC_ENABLED 5
/*
* If set, background speculative prealloc gc worker threads will be scheduled
* to process queued blockgc work. If not, inodes retain their preallocations
* until explicitly deleted.
*/
#define XFS_OPSTATE_BLOCKGC_ENABLED 1
#define XFS_OPSTATE_BLOCKGC_ENABLED 6

#define __XFS_IS_OPSTATE(name, NAME) \
static inline bool xfs_is_ ## name (struct xfs_mount *mp) \
Expand All @@ -404,10 +400,20 @@ static inline bool xfs_set_ ## name (struct xfs_mount *mp) \
return test_and_set_bit(XFS_OPSTATE_ ## NAME, &mp->m_opstate); \
}

__XFS_IS_OPSTATE(unmounting, UNMOUNTING)
__XFS_IS_OPSTATE(clean, CLEAN)
__XFS_IS_OPSTATE(shutdown, SHUTDOWN)
__XFS_IS_OPSTATE(inode32, INODE32)
__XFS_IS_OPSTATE(readonly, READONLY)
__XFS_IS_OPSTATE(inodegc_enabled, INODEGC_ENABLED)
__XFS_IS_OPSTATE(blockgc_enabled, BLOCKGC_ENABLED)

#define XFS_OPSTATE_STRINGS \
{ (1UL << XFS_OPSTATE_UNMOUNTING), "unmounting" }, \
{ (1UL << XFS_OPSTATE_CLEAN), "clean" }, \
{ (1UL << XFS_OPSTATE_SHUTDOWN), "shutdown" }, \
{ (1UL << XFS_OPSTATE_INODE32), "inode32" }, \
{ (1UL << XFS_OPSTATE_READONLY), "read_only" }, \
{ (1UL << XFS_OPSTATE_INODEGC_ENABLED), "inodegc" }, \
{ (1UL << XFS_OPSTATE_BLOCKGC_ENABLED), "blockgc" }

Expand All @@ -418,9 +424,7 @@ __XFS_IS_OPSTATE(blockgc_enabled, BLOCKGC_ENABLED)
#define XFS_MAX_IO_LOG 30 /* 1G */
#define XFS_MIN_IO_LOG PAGE_SHIFT

#define XFS_LAST_UNMOUNT_WAS_CLEAN(mp) \
((mp)->m_flags & XFS_MOUNT_WAS_CLEAN)
#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN)
#define XFS_FORCED_SHUTDOWN(mp) xfs_is_shutdown(mp)
void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname,
int lnnum);
#define xfs_force_shutdown(m,f) \
Expand Down
Loading

0 comments on commit 2e973b2

Please sign in to comment.