From: Darrick J. Wong <djwong@xxxxxxxxxx> Don't allow log recovery to proceed on a readonly mount if the primary superblock advertises unknown rocompat bits. We used to allow this, but due to a misunderstanding between Dave and Darrick back in 2016, we cannot do that anymore. The XFS_SB_FEAT_RO_COMPAT_RMAPBT feature (4.8) protects RUI log items, and the REFLINK feature (4.9) protects CUI/BUI log items, which is why we can't allow older kernels to recover them. Fixes: b87049444ac4 ("xfs: introduce rmap btree definitions") Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- fs/xfs/xfs_log.c | 17 ----------------- fs/xfs/xfs_log_recover.c | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 79004d193e54..51c100c86177 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -715,15 +715,7 @@ xfs_log_mount( * just worked. */ if (!xfs_has_norecovery(mp)) { - /* - * 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) - set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate); if (error) { xfs_warn(mp, "log mount/recovery failed: error %d", error); @@ -772,7 +764,6 @@ xfs_log_mount_finish( struct xfs_mount *mp) { struct xlog *log = mp->m_log; - bool readonly; int error = 0; if (xfs_has_norecovery(mp)) { @@ -780,12 +771,6 @@ xfs_log_mount_finish( return 0; } - /* - * 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. @@ -835,8 +820,6 @@ xfs_log_mount_finish( xfs_buftarg_drain(mp->m_ddev_targp); clear_bit(XLOG_RECOVERY_NEEDED, &log->l_opstate); - if (readonly) - 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)); diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 82c81d20459d..b4458b7fd6f7 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -3354,6 +3354,7 @@ xlog_recover( struct xlog *log) { xfs_daddr_t head_blk, tail_blk; + bool unknown_rocompat = false; int error; /* find the tail of the log */ @@ -3370,6 +3371,12 @@ xlog_recover( !xfs_log_check_lsn(log->l_mp, log->l_mp->m_sb.sb_lsn)) return -EINVAL; + /* Detect unknown rocompat features in the superblock */ + if (xfs_has_crc(log->l_mp) && + xfs_sb_has_ro_compat_feature(&log->l_mp->m_sb, + XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) + unknown_rocompat = true; + if (tail_blk != head_blk) { /* There used to be a comment here: * @@ -3407,6 +3414,24 @@ xlog_recover( return -EINVAL; } + /* + * Don't allow log recovery on a ro mount if there are unknown + * ro compat bits set. We used to allow this, but BUI/CUI log + * items are protected by the REFLINK rocompat bit so now we + * cannot. + */ + if (xfs_is_readonly(log->l_mp) && unknown_rocompat) { + xfs_alert(log->l_mp, +"Superblock has unknown read-only compatible features (0x%x) enabled.", + (log->l_mp->m_sb.sb_features_ro_compat & + XFS_SB_FEAT_RO_COMPAT_UNKNOWN)); + xfs_warn(log->l_mp, +"The log can not be fully and/or safely recovered by this kernel."); + xfs_warn(log->l_mp, +"Please recover the log on a kernel that supports the unknown features."); + return -EINVAL; + } + /* * Delay log recovery if the debug hook is set. This is debug * instrumentation to coordinate simulation of I/O failures with