mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
xfs: update quota flags on secondary supers when metadir enabled
xfs/085 exposes an interesting bug when metadir is enabled, quotas are
enabled via mount option, and the primary superblock crc fails
validation:
Phase 1 - find and verify superblock...
bad primary superblock - bad CRC in superblock !!!
attempting to find secondary superblock...
.found candidate secondary superblock...
verified secondary superblock...
quota accounting and enforcement flags lost
<snip>
Phase 3 - for each AG...
- scan and clear agi unlinked lists...
- process known inodes and perform inode discovery...
- agno = 0
- agno = 1
- agno = 2
unexpected regular file inode 16908418 with metadata flag will zap
cleared inode 16908418
unexpected regular file inode 16908419 with metadata flag will zap
cleared inode 16908419
unexpected regular file inode 16908420 with metadata flag will zap
cleared inode 16908420
- agno = 3
- process newly discovered inodes...
Quota files have been created, but xfs_repair thinks that quotas aren't
enabled and trashes the quota files. Looking at the filesystem reveals
that the quota accounting flags were indeed persisted to the primary
superblock but not the secondary:
# xfs_db -c 'sb 0' -c 'print qflags' -c 'sb 1' -c 'print qflags' /dev/sdf
Metadata corruption detected at 0x561c68436080, inode 0x81 dinode
xfs_db: Failed to load metadir root directory, error 117
Metadata corruption detected at 0x561c683f7c80, xfs_agf block 0x1/0x200
xfs_db: cannot init perag data (117). Continuing anyway.
Metadata CRC error detected at 0x561c6844d1b5, xfs_sb block 0x0/0x200
qflags = 0x7cf
qflags = 0
On a metadir filesystem, quota state is supposed to persist across
mount cycles if the sysadmin doesn't provide any quota mount options.
Therefore, any time we update the quota flags on a metadir filesystem,
we should write the same change to the secondary supers so that
xfs_repair will find the quota data if it ever has to restore from a
secondary.
Cc: stable@vger.kernel.org # v6.13
Fixes: d5d9dd5b30 ("xfs: persist quota flags with metadir")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
parent
6e82b76418
commit
9d9ea6e6cb
|
|
@ -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[] = {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user