diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index be90c7b03994..8838eff1f054 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -446,6 +446,8 @@ int xfs_mount_reset_sbqflags( struct xfs_mount *mp) { + int error; + mp->m_qflags = 0; /* It is OK to look at sb_qflags in the mount path without m_sb_lock. */ @@ -458,7 +460,12 @@ xfs_mount_reset_sbqflags( if (!xfs_fs_writable(mp, SB_FREEZE_WRITE)) return 0; - return xfs_sync_sb(mp, false); + error = xfs_sync_sb(mp, false); + if (error) + return error; + + xfs_qm_update_secondary_sb(mp); + return 0; } static const char *const xfs_free_pool_name[] = { diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 008fed8624be..dd5011f578a6 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -693,6 +693,32 @@ xfs_qm_create_metadir_qinos( return 0; } +/* + * For metadir filesystems, quota flag state persists across mounts, so update + * secondary superblocks in case xfs_repair ever has to recover the primary + * from a secondary. growfs also updates backup supers so lock against that. + * Note that the secondary backups are opportunistic, so we log but do not + * return write errors. + */ +void +__xfs_qm_update_secondary_sb( + struct xfs_mount *mp, + const char *func) +{ + int error; + + if (!xfs_has_metadir(mp)) + return; + + mutex_lock(&mp->m_growlock); + error = xfs_update_secondary_sbs(mp); + mutex_unlock(&mp->m_growlock); + + if (error) + xfs_alert(mp, "%s: Secondary super update failed, err=%d!", + func, error); +} + /* * Add QUOTABIT to sb_versionnum and initialize qflags in preparation for * creating quota files on a metadir filesystem. @@ -718,7 +744,12 @@ xfs_qm_prep_metadir_sb( spin_unlock(&mp->m_sb_lock); xfs_log_sb(tp); - return xfs_trans_commit(tp); + error = xfs_trans_commit(tp); + if (error) + return error; + + xfs_qm_update_secondary_sb(mp); + return 0; } /* @@ -1683,6 +1714,9 @@ xfs_qm_mount_quotas( ASSERT(!(XFS_IS_QUOTA_ON(mp))); xfs_alert(mp, "%s: Superblock update failed!", __func__); + } else { + /* Primary update succeeded, try to write secondary */ + xfs_qm_update_secondary_sb(mp); } } diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 105e6eb57620..b323a72dafbc 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h @@ -151,6 +151,8 @@ void xfs_dqtrx_hook_setup(struct xfs_dqtrx_hook *hook, notifier_fn_t mod_fn, xfs_trans_mod_dquot((tp), (dqp), (field), (delta)) # endif /* CONFIG_XFS_LIVE_HOOKS */ +void __xfs_qm_update_secondary_sb(struct xfs_mount *mp, + const char *func); #else static inline int xfs_qm_vop_dqalloc(struct xfs_inode *ip, kuid_t kuid, kgid_t kgid, @@ -216,8 +218,15 @@ static inline int xfs_quota_reserve_blkres(struct xfs_inode *ip, int64_t blocks) # define xfs_dqtrx_hook_disable() ((void)0) # endif /* CONFIG_XFS_LIVE_HOOKS */ +static inline void __xfs_qm_update_secondary_sb(struct xfs_mount *mp, + const char *func) +{ +} #endif /* CONFIG_XFS_QUOTA */ +#define xfs_qm_update_secondary_sb(mp) \ + __xfs_qm_update_secondary_sb((mp), __func__) + static inline void xfs_quota_unreserve_blkres(struct xfs_inode *ip, uint64_t blocks) {