Loading fs/xfs/libxfs/xfs_btree.c +105 −35 Original line number Diff line number Diff line Loading @@ -51,6 +51,52 @@ xfs_btree_magic( return magic; } static xfs_failaddr_t xfs_btree_check_lblock_siblings( struct xfs_mount *mp, struct xfs_btree_cur *cur, int level, xfs_fsblock_t fsb, xfs_fsblock_t sibling) { if (sibling == NULLFSBLOCK) return NULL; if (sibling == fsb) return __this_address; if (level >= 0) { if (!xfs_btree_check_lptr(cur, sibling, level + 1)) return __this_address; } else { if (!xfs_verify_fsbno(mp, sibling)) return __this_address; } return NULL; } static xfs_failaddr_t xfs_btree_check_sblock_siblings( struct xfs_mount *mp, struct xfs_btree_cur *cur, int level, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_agblock_t sibling) { if (sibling == NULLAGBLOCK) return NULL; if (sibling == agbno) return __this_address; if (level >= 0) { if (!xfs_btree_check_sptr(cur, sibling, level + 1)) return __this_address; } else { if (!xfs_verify_agbno(mp, agno, sibling)) return __this_address; } return NULL; } /* * Check a long btree block header. Return the address of the failing check, * or NULL if everything is ok. Loading @@ -65,6 +111,8 @@ __xfs_btree_check_lblock( struct xfs_mount *mp = cur->bc_mp; xfs_btnum_t btnum = cur->bc_btnum; int crc = xfs_has_crc(mp); xfs_failaddr_t fa; xfs_fsblock_t fsb = NULLFSBLOCK; if (crc) { if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid)) Loading @@ -83,16 +131,16 @@ __xfs_btree_check_lblock( if (be16_to_cpu(block->bb_numrecs) > cur->bc_ops->get_maxrecs(cur, level)) return __this_address; if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) && !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_leftsib), level + 1)) return __this_address; if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) && !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_rightsib), level + 1)) return __this_address; return NULL; if (bp) fsb = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp)); fa = xfs_btree_check_lblock_siblings(mp, cur, level, fsb, be64_to_cpu(block->bb_u.l.bb_leftsib)); if (!fa) fa = xfs_btree_check_lblock_siblings(mp, cur, level, fsb, be64_to_cpu(block->bb_u.l.bb_rightsib)); return fa; } /* Check a long btree block header. */ Loading Loading @@ -130,6 +178,9 @@ __xfs_btree_check_sblock( struct xfs_mount *mp = cur->bc_mp; xfs_btnum_t btnum = cur->bc_btnum; int crc = xfs_has_crc(mp); xfs_failaddr_t fa; xfs_agblock_t agbno = NULLAGBLOCK; xfs_agnumber_t agno = NULLAGNUMBER; if (crc) { if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) Loading @@ -146,16 +197,18 @@ __xfs_btree_check_sblock( if (be16_to_cpu(block->bb_numrecs) > cur->bc_ops->get_maxrecs(cur, level)) return __this_address; if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) && !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_leftsib), level + 1)) return __this_address; if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) && !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_rightsib), level + 1)) return __this_address; return NULL; if (bp) { agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp)); agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp)); } fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno, agbno, be32_to_cpu(block->bb_u.s.bb_leftsib)); if (!fa) fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno, agbno, be32_to_cpu(block->bb_u.s.bb_rightsib)); return fa; } /* Check a short btree block header. */ Loading Loading @@ -4271,6 +4324,21 @@ xfs_btree_visit_block( if (xfs_btree_ptr_is_null(cur, &rptr)) return -ENOENT; /* * We only visit blocks once in this walk, so we have to avoid the * internal xfs_btree_lookup_get_block() optimisation where it will * return the same block without checking if the right sibling points * back to us and creates a cyclic reference in the btree. */ if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (be64_to_cpu(rptr.l) == XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(bp))) return -EFSCORRUPTED; } else { if (be32_to_cpu(rptr.s) == xfs_daddr_to_agbno(cur->bc_mp, xfs_buf_daddr(bp))) return -EFSCORRUPTED; } return xfs_btree_lookup_get_block(cur, level, &rptr, &block); } Loading Loading @@ -4445,20 +4513,21 @@ xfs_btree_lblock_verify( { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); xfs_fsblock_t fsb; xfs_failaddr_t fa; /* numrecs verification */ if (be16_to_cpu(block->bb_numrecs) > max_recs) return __this_address; /* sibling pointer verification */ if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) && !xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_leftsib))) return __this_address; if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) && !xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_rightsib))) return __this_address; return NULL; fsb = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp)); fa = xfs_btree_check_lblock_siblings(mp, NULL, -1, fsb, be64_to_cpu(block->bb_u.l.bb_leftsib)); if (!fa) fa = xfs_btree_check_lblock_siblings(mp, NULL, -1, fsb, be64_to_cpu(block->bb_u.l.bb_rightsib)); return fa; } /** Loading Loading @@ -4499,7 +4568,9 @@ xfs_btree_sblock_verify( { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); xfs_agblock_t agno; xfs_agnumber_t agno; xfs_agblock_t agbno; xfs_failaddr_t fa; /* numrecs verification */ if (be16_to_cpu(block->bb_numrecs) > max_recs) Loading @@ -4507,14 +4578,13 @@ xfs_btree_sblock_verify( /* sibling pointer verification */ agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp)); if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) && !xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_leftsib))) return __this_address; if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) && !xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_rightsib))) return __this_address; return NULL; agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp)); fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno, be32_to_cpu(block->bb_u.s.bb_leftsib)); if (!fa) fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno, be32_to_cpu(block->bb_u.s.bb_rightsib)); return fa; } /* Loading fs/xfs/libxfs/xfs_inode_buf.c +26 −9 Original line number Diff line number Diff line Loading @@ -357,21 +357,38 @@ xfs_dinode_verify_fork( { xfs_extnum_t di_nextents; xfs_extnum_t max_extents; mode_t mode = be16_to_cpu(dip->di_mode); uint32_t fork_size = XFS_DFORK_SIZE(dip, mp, whichfork); uint32_t fork_format = XFS_DFORK_FORMAT(dip, whichfork); di_nextents = xfs_dfork_nextents(dip, whichfork); switch (XFS_DFORK_FORMAT(dip, whichfork)) { case XFS_DINODE_FMT_LOCAL: /* * no local regular files yet * For fork types that can contain local data, check that the fork * format matches the size of local data contained within the fork. * * For all types, check that when the size says the should be in extent * or btree format, the inode isn't claiming it is in local format. */ if (whichfork == XFS_DATA_FORK) { if (S_ISREG(be16_to_cpu(dip->di_mode))) if (S_ISDIR(mode) || S_ISLNK(mode)) { if (be64_to_cpu(dip->di_size) <= fork_size && fork_format != XFS_DINODE_FMT_LOCAL) return __this_address; if (be64_to_cpu(dip->di_size) > XFS_DFORK_SIZE(dip, mp, whichfork)) } if (be64_to_cpu(dip->di_size) > fork_size && fork_format == XFS_DINODE_FMT_LOCAL) return __this_address; } switch (fork_format) { case XFS_DINODE_FMT_LOCAL: /* * No local regular files yet. */ if (S_ISREG(mode) && whichfork == XFS_DATA_FORK) return __this_address; if (di_nextents) return __this_address; break; Loading fs/xfs/libxfs/xfs_sb.c +60 −10 Original line number Diff line number Diff line Loading @@ -30,6 +30,47 @@ * Physical superblock buffer manipulations. Shared with libxfs in userspace. */ /* * Check that all the V4 feature bits that the V5 filesystem format requires are * correctly set. */ static bool xfs_sb_validate_v5_features( struct xfs_sb *sbp) { /* We must not have any unknown V4 feature bits set */ if (sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) return false; /* * The CRC bit is considered an invalid V4 flag, so we have to add it * manually to the OKBITS mask. */ if (sbp->sb_features2 & ~(XFS_SB_VERSION2_OKBITS | XFS_SB_VERSION2_CRCBIT)) return false; /* Now check all the required V4 feature flags are set. */ #define V5_VERS_FLAGS (XFS_SB_VERSION_NLINKBIT | \ XFS_SB_VERSION_ALIGNBIT | \ XFS_SB_VERSION_LOGV2BIT | \ XFS_SB_VERSION_EXTFLGBIT | \ XFS_SB_VERSION_DIRV2BIT | \ XFS_SB_VERSION_MOREBITSBIT) #define V5_FEAT_FLAGS (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ XFS_SB_VERSION2_ATTR2BIT | \ XFS_SB_VERSION2_PROJID32BIT | \ XFS_SB_VERSION2_CRCBIT) if ((sbp->sb_versionnum & V5_VERS_FLAGS) != V5_VERS_FLAGS) return false; if ((sbp->sb_features2 & V5_FEAT_FLAGS) != V5_FEAT_FLAGS) return false; return true; } /* * We support all XFS versions newer than a v4 superblock with V2 directories. */ Loading @@ -37,9 +78,19 @@ bool xfs_sb_good_version( struct xfs_sb *sbp) { /* all v5 filesystems are supported */ /* * All v5 filesystems are supported, but we must check that all the * required v4 feature flags are enabled correctly as the code checks * those flags and not for v5 support. */ if (xfs_sb_is_v5(sbp)) return true; return xfs_sb_validate_v5_features(sbp); /* We must not have any unknown v4 feature bits set */ if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && (sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS))) return false; /* versions prior to v4 are not supported */ if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4) Loading @@ -51,12 +102,6 @@ xfs_sb_good_version( if (!(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)) return false; /* And must not have any unknown v4 feature bits set */ if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && (sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS))) return false; /* It's a supported v4 filesystem */ return true; } Loading @@ -70,6 +115,8 @@ xfs_sb_version_to_features( /* optional V4 features */ if (sbp->sb_rblocks > 0) features |= XFS_FEAT_REALTIME; if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT) features |= XFS_FEAT_NLINK; if (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT) features |= XFS_FEAT_ATTR; if (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT) Loading Loading @@ -265,12 +312,15 @@ xfs_validate_sb_common( bool has_dalign; if (!xfs_verify_magic(bp, dsb->sb_magicnum)) { xfs_warn(mp, "bad magic number"); xfs_warn(mp, "Superblock has bad magic number 0x%x. Not an XFS filesystem?", be32_to_cpu(dsb->sb_magicnum)); return -EWRONGFS; } if (!xfs_sb_good_version(sbp)) { xfs_warn(mp, "bad version"); xfs_warn(mp, "Superblock has unknown features enabled or corrupted feature masks."); return -EWRONGFS; } Loading Loading
fs/xfs/libxfs/xfs_btree.c +105 −35 Original line number Diff line number Diff line Loading @@ -51,6 +51,52 @@ xfs_btree_magic( return magic; } static xfs_failaddr_t xfs_btree_check_lblock_siblings( struct xfs_mount *mp, struct xfs_btree_cur *cur, int level, xfs_fsblock_t fsb, xfs_fsblock_t sibling) { if (sibling == NULLFSBLOCK) return NULL; if (sibling == fsb) return __this_address; if (level >= 0) { if (!xfs_btree_check_lptr(cur, sibling, level + 1)) return __this_address; } else { if (!xfs_verify_fsbno(mp, sibling)) return __this_address; } return NULL; } static xfs_failaddr_t xfs_btree_check_sblock_siblings( struct xfs_mount *mp, struct xfs_btree_cur *cur, int level, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_agblock_t sibling) { if (sibling == NULLAGBLOCK) return NULL; if (sibling == agbno) return __this_address; if (level >= 0) { if (!xfs_btree_check_sptr(cur, sibling, level + 1)) return __this_address; } else { if (!xfs_verify_agbno(mp, agno, sibling)) return __this_address; } return NULL; } /* * Check a long btree block header. Return the address of the failing check, * or NULL if everything is ok. Loading @@ -65,6 +111,8 @@ __xfs_btree_check_lblock( struct xfs_mount *mp = cur->bc_mp; xfs_btnum_t btnum = cur->bc_btnum; int crc = xfs_has_crc(mp); xfs_failaddr_t fa; xfs_fsblock_t fsb = NULLFSBLOCK; if (crc) { if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid)) Loading @@ -83,16 +131,16 @@ __xfs_btree_check_lblock( if (be16_to_cpu(block->bb_numrecs) > cur->bc_ops->get_maxrecs(cur, level)) return __this_address; if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) && !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_leftsib), level + 1)) return __this_address; if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) && !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_rightsib), level + 1)) return __this_address; return NULL; if (bp) fsb = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp)); fa = xfs_btree_check_lblock_siblings(mp, cur, level, fsb, be64_to_cpu(block->bb_u.l.bb_leftsib)); if (!fa) fa = xfs_btree_check_lblock_siblings(mp, cur, level, fsb, be64_to_cpu(block->bb_u.l.bb_rightsib)); return fa; } /* Check a long btree block header. */ Loading Loading @@ -130,6 +178,9 @@ __xfs_btree_check_sblock( struct xfs_mount *mp = cur->bc_mp; xfs_btnum_t btnum = cur->bc_btnum; int crc = xfs_has_crc(mp); xfs_failaddr_t fa; xfs_agblock_t agbno = NULLAGBLOCK; xfs_agnumber_t agno = NULLAGNUMBER; if (crc) { if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) Loading @@ -146,16 +197,18 @@ __xfs_btree_check_sblock( if (be16_to_cpu(block->bb_numrecs) > cur->bc_ops->get_maxrecs(cur, level)) return __this_address; if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) && !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_leftsib), level + 1)) return __this_address; if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) && !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_rightsib), level + 1)) return __this_address; return NULL; if (bp) { agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp)); agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp)); } fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno, agbno, be32_to_cpu(block->bb_u.s.bb_leftsib)); if (!fa) fa = xfs_btree_check_sblock_siblings(mp, cur, level, agno, agbno, be32_to_cpu(block->bb_u.s.bb_rightsib)); return fa; } /* Check a short btree block header. */ Loading Loading @@ -4271,6 +4324,21 @@ xfs_btree_visit_block( if (xfs_btree_ptr_is_null(cur, &rptr)) return -ENOENT; /* * We only visit blocks once in this walk, so we have to avoid the * internal xfs_btree_lookup_get_block() optimisation where it will * return the same block without checking if the right sibling points * back to us and creates a cyclic reference in the btree. */ if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (be64_to_cpu(rptr.l) == XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(bp))) return -EFSCORRUPTED; } else { if (be32_to_cpu(rptr.s) == xfs_daddr_to_agbno(cur->bc_mp, xfs_buf_daddr(bp))) return -EFSCORRUPTED; } return xfs_btree_lookup_get_block(cur, level, &rptr, &block); } Loading Loading @@ -4445,20 +4513,21 @@ xfs_btree_lblock_verify( { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); xfs_fsblock_t fsb; xfs_failaddr_t fa; /* numrecs verification */ if (be16_to_cpu(block->bb_numrecs) > max_recs) return __this_address; /* sibling pointer verification */ if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) && !xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_leftsib))) return __this_address; if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) && !xfs_verify_fsbno(mp, be64_to_cpu(block->bb_u.l.bb_rightsib))) return __this_address; return NULL; fsb = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp)); fa = xfs_btree_check_lblock_siblings(mp, NULL, -1, fsb, be64_to_cpu(block->bb_u.l.bb_leftsib)); if (!fa) fa = xfs_btree_check_lblock_siblings(mp, NULL, -1, fsb, be64_to_cpu(block->bb_u.l.bb_rightsib)); return fa; } /** Loading Loading @@ -4499,7 +4568,9 @@ xfs_btree_sblock_verify( { struct xfs_mount *mp = bp->b_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); xfs_agblock_t agno; xfs_agnumber_t agno; xfs_agblock_t agbno; xfs_failaddr_t fa; /* numrecs verification */ if (be16_to_cpu(block->bb_numrecs) > max_recs) Loading @@ -4507,14 +4578,13 @@ xfs_btree_sblock_verify( /* sibling pointer verification */ agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp)); if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) && !xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_leftsib))) return __this_address; if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) && !xfs_verify_agbno(mp, agno, be32_to_cpu(block->bb_u.s.bb_rightsib))) return __this_address; return NULL; agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp)); fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno, be32_to_cpu(block->bb_u.s.bb_leftsib)); if (!fa) fa = xfs_btree_check_sblock_siblings(mp, NULL, -1, agno, agbno, be32_to_cpu(block->bb_u.s.bb_rightsib)); return fa; } /* Loading
fs/xfs/libxfs/xfs_inode_buf.c +26 −9 Original line number Diff line number Diff line Loading @@ -357,21 +357,38 @@ xfs_dinode_verify_fork( { xfs_extnum_t di_nextents; xfs_extnum_t max_extents; mode_t mode = be16_to_cpu(dip->di_mode); uint32_t fork_size = XFS_DFORK_SIZE(dip, mp, whichfork); uint32_t fork_format = XFS_DFORK_FORMAT(dip, whichfork); di_nextents = xfs_dfork_nextents(dip, whichfork); switch (XFS_DFORK_FORMAT(dip, whichfork)) { case XFS_DINODE_FMT_LOCAL: /* * no local regular files yet * For fork types that can contain local data, check that the fork * format matches the size of local data contained within the fork. * * For all types, check that when the size says the should be in extent * or btree format, the inode isn't claiming it is in local format. */ if (whichfork == XFS_DATA_FORK) { if (S_ISREG(be16_to_cpu(dip->di_mode))) if (S_ISDIR(mode) || S_ISLNK(mode)) { if (be64_to_cpu(dip->di_size) <= fork_size && fork_format != XFS_DINODE_FMT_LOCAL) return __this_address; if (be64_to_cpu(dip->di_size) > XFS_DFORK_SIZE(dip, mp, whichfork)) } if (be64_to_cpu(dip->di_size) > fork_size && fork_format == XFS_DINODE_FMT_LOCAL) return __this_address; } switch (fork_format) { case XFS_DINODE_FMT_LOCAL: /* * No local regular files yet. */ if (S_ISREG(mode) && whichfork == XFS_DATA_FORK) return __this_address; if (di_nextents) return __this_address; break; Loading
fs/xfs/libxfs/xfs_sb.c +60 −10 Original line number Diff line number Diff line Loading @@ -30,6 +30,47 @@ * Physical superblock buffer manipulations. Shared with libxfs in userspace. */ /* * Check that all the V4 feature bits that the V5 filesystem format requires are * correctly set. */ static bool xfs_sb_validate_v5_features( struct xfs_sb *sbp) { /* We must not have any unknown V4 feature bits set */ if (sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) return false; /* * The CRC bit is considered an invalid V4 flag, so we have to add it * manually to the OKBITS mask. */ if (sbp->sb_features2 & ~(XFS_SB_VERSION2_OKBITS | XFS_SB_VERSION2_CRCBIT)) return false; /* Now check all the required V4 feature flags are set. */ #define V5_VERS_FLAGS (XFS_SB_VERSION_NLINKBIT | \ XFS_SB_VERSION_ALIGNBIT | \ XFS_SB_VERSION_LOGV2BIT | \ XFS_SB_VERSION_EXTFLGBIT | \ XFS_SB_VERSION_DIRV2BIT | \ XFS_SB_VERSION_MOREBITSBIT) #define V5_FEAT_FLAGS (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ XFS_SB_VERSION2_ATTR2BIT | \ XFS_SB_VERSION2_PROJID32BIT | \ XFS_SB_VERSION2_CRCBIT) if ((sbp->sb_versionnum & V5_VERS_FLAGS) != V5_VERS_FLAGS) return false; if ((sbp->sb_features2 & V5_FEAT_FLAGS) != V5_FEAT_FLAGS) return false; return true; } /* * We support all XFS versions newer than a v4 superblock with V2 directories. */ Loading @@ -37,9 +78,19 @@ bool xfs_sb_good_version( struct xfs_sb *sbp) { /* all v5 filesystems are supported */ /* * All v5 filesystems are supported, but we must check that all the * required v4 feature flags are enabled correctly as the code checks * those flags and not for v5 support. */ if (xfs_sb_is_v5(sbp)) return true; return xfs_sb_validate_v5_features(sbp); /* We must not have any unknown v4 feature bits set */ if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && (sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS))) return false; /* versions prior to v4 are not supported */ if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4) Loading @@ -51,12 +102,6 @@ xfs_sb_good_version( if (!(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)) return false; /* And must not have any unknown v4 feature bits set */ if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && (sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS))) return false; /* It's a supported v4 filesystem */ return true; } Loading @@ -70,6 +115,8 @@ xfs_sb_version_to_features( /* optional V4 features */ if (sbp->sb_rblocks > 0) features |= XFS_FEAT_REALTIME; if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT) features |= XFS_FEAT_NLINK; if (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT) features |= XFS_FEAT_ATTR; if (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT) Loading Loading @@ -265,12 +312,15 @@ xfs_validate_sb_common( bool has_dalign; if (!xfs_verify_magic(bp, dsb->sb_magicnum)) { xfs_warn(mp, "bad magic number"); xfs_warn(mp, "Superblock has bad magic number 0x%x. Not an XFS filesystem?", be32_to_cpu(dsb->sb_magicnum)); return -EWRONGFS; } if (!xfs_sb_good_version(sbp)) { xfs_warn(mp, "bad version"); xfs_warn(mp, "Superblock has unknown features enabled or corrupted feature masks."); return -EWRONGFS; } Loading