Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xfs: open code sb verifier feature checks

The superblock verifiers are one of the last places that use the sb
version functions to do feature checks. This are all quite simple
uses, and there aren't many of them so open code them all.

Also, move the good version number check into xfs_sb.c instead of it
being an inline function in xfs_format.h

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>

authored by

Dave Chinner and committed by
Darrick J. Wong
fe08cc50 03288b19

+81 -65
-29
fs/xfs/libxfs/xfs_format.h
··· 265 265 /* must be padded to 64 bit alignment */ 266 266 } xfs_dsb_t; 267 267 268 - 269 268 /* 270 269 * Misc. Flags - warning - these will be cleared by xfs_repair unless 271 270 * a feature bit is set when the flag is used. ··· 278 279 #define XFS_SB_MAX_SHARED_VN 0 279 280 280 281 #define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS) 281 - 282 - /* 283 - * The first XFS version we support is a v4 superblock with V2 directories. 284 - */ 285 - static inline bool xfs_sb_good_v4_features(struct xfs_sb *sbp) 286 - { 287 - if (!(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) 288 - return false; 289 - if (!(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)) 290 - return false; 291 - 292 - /* check for unknown features in the fs */ 293 - if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || 294 - ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && 295 - (sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS))) 296 - return false; 297 - 298 - return true; 299 - } 300 - 301 - static inline bool xfs_sb_good_version(struct xfs_sb *sbp) 302 - { 303 - if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) 304 - return true; 305 - if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) 306 - return xfs_sb_good_v4_features(sbp); 307 - return false; 308 - } 309 282 310 283 static inline bool xfs_sb_version_hasrealtime(struct xfs_sb *sbp) 311 284 {
+80 -36
fs/xfs/libxfs/xfs_sb.c
··· 30 30 * Physical superblock buffer manipulations. Shared with libxfs in userspace. 31 31 */ 32 32 33 + /* 34 + * We support all XFS versions newer than a v4 superblock with V2 directories. 35 + */ 36 + bool 37 + xfs_sb_good_version( 38 + struct xfs_sb *sbp) 39 + { 40 + /* all v5 filesystems are supported */ 41 + if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) 42 + return true; 43 + 44 + /* versions prior to v4 are not supported */ 45 + if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4) 46 + return false; 47 + 48 + /* V4 filesystems need v2 directories and unwritten extents */ 49 + if (!(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) 50 + return false; 51 + if (!(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)) 52 + return false; 53 + 54 + /* And must not have any unknown v4 feature bits set */ 55 + if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || 56 + ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && 57 + (sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS))) 58 + return false; 59 + 60 + /* It's a supported v4 filesystem */ 61 + return true; 62 + } 63 + 33 64 uint64_t 34 65 xfs_sb_version_to_features( 35 66 struct xfs_sb *sbp) ··· 259 228 struct xfs_dsb *dsb = bp->b_addr; 260 229 uint32_t agcount = 0; 261 230 uint32_t rem; 231 + bool has_dalign; 262 232 263 233 if (!xfs_verify_magic(bp, dsb->sb_magicnum)) { 264 234 xfs_warn(mp, "bad magic number"); ··· 271 239 return -EWRONGFS; 272 240 } 273 241 274 - if (xfs_sb_version_haspquotino(sbp)) { 242 + /* 243 + * Validate feature flags and state 244 + */ 245 + if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) { 246 + if (sbp->sb_blocksize < XFS_MIN_CRC_BLOCKSIZE) { 247 + xfs_notice(mp, 248 + "Block size (%u bytes) too small for Version 5 superblock (minimum %d bytes)", 249 + sbp->sb_blocksize, XFS_MIN_CRC_BLOCKSIZE); 250 + return -EFSCORRUPTED; 251 + } 252 + 253 + /* V5 has a separate project quota inode */ 275 254 if (sbp->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) { 276 255 xfs_notice(mp, 277 256 "Version 5 of Super block has XFS_OQUOTA bits."); 278 257 return -EFSCORRUPTED; 258 + } 259 + 260 + /* 261 + * Full inode chunks must be aligned to inode chunk size when 262 + * sparse inodes are enabled to support the sparse chunk 263 + * allocation algorithm and prevent overlapping inode records. 264 + */ 265 + if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_SPINODES) { 266 + uint32_t align; 267 + 268 + align = XFS_INODES_PER_CHUNK * sbp->sb_inodesize 269 + >> sbp->sb_blocklog; 270 + if (sbp->sb_inoalignmt != align) { 271 + xfs_warn(mp, 272 + "Inode block alignment (%u) must match chunk size (%u) for sparse inodes.", 273 + sbp->sb_inoalignmt, align); 274 + return -EINVAL; 275 + } 279 276 } 280 277 } else if (sbp->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD | 281 278 XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) { 282 279 xfs_notice(mp, 283 280 "Superblock earlier than Version 5 has XFS_{P|G}QUOTA_{ENFD|CHKD} bits."); 284 281 return -EFSCORRUPTED; 285 - } 286 - 287 - /* 288 - * Full inode chunks must be aligned to inode chunk size when 289 - * sparse inodes are enabled to support the sparse chunk 290 - * allocation algorithm and prevent overlapping inode records. 291 - */ 292 - if (xfs_sb_version_hassparseinodes(sbp)) { 293 - uint32_t align; 294 - 295 - align = XFS_INODES_PER_CHUNK * sbp->sb_inodesize 296 - >> sbp->sb_blocklog; 297 - if (sbp->sb_inoalignmt != align) { 298 - xfs_warn(mp, 299 - "Inode block alignment (%u) must match chunk size (%u) for sparse inodes.", 300 - sbp->sb_inoalignmt, align); 301 - return -EINVAL; 302 - } 303 282 } 304 283 305 284 if (unlikely( ··· 412 369 * Either (sb_unit and !hasdalign) or (!sb_unit and hasdalign) 413 370 * would imply the image is corrupted. 414 371 */ 415 - if (!!sbp->sb_unit ^ xfs_sb_version_hasdalign(sbp)) { 372 + has_dalign = sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT; 373 + if (!!sbp->sb_unit ^ has_dalign) { 416 374 xfs_notice(mp, "SB stripe alignment sanity check failed"); 417 375 return -EFSCORRUPTED; 418 376 } ··· 421 377 if (!xfs_validate_stripe_geometry(mp, XFS_FSB_TO_B(mp, sbp->sb_unit), 422 378 XFS_FSB_TO_B(mp, sbp->sb_width), 0, false)) 423 379 return -EFSCORRUPTED; 424 - 425 - if (xfs_sb_version_hascrc(sbp) && 426 - sbp->sb_blocksize < XFS_MIN_CRC_BLOCKSIZE) { 427 - xfs_notice(mp, "v5 SB sanity check failed"); 428 - return -EFSCORRUPTED; 429 - } 430 380 431 381 /* 432 382 * Currently only very few inode sizes are supported. ··· 465 427 * We need to do these manipilations only if we are working 466 428 * with an older version of on-disk superblock. 467 429 */ 468 - if (xfs_sb_version_haspquotino(sbp)) 430 + if (XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_5) 469 431 return; 470 432 471 433 if (sbp->sb_qflags & XFS_OQUOTA_ENFD) ··· 558 520 * sb_meta_uuid is only on disk if it differs from sb_uuid and the 559 521 * feature flag is set; if not set we keep it only in memory. 560 522 */ 561 - if (xfs_sb_version_hasmetauuid(to)) 523 + if (XFS_SB_VERSION_NUM(to) == XFS_SB_VERSION_5 && 524 + (to->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID)) 562 525 uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid); 563 526 else 564 527 uuid_copy(&to->sb_meta_uuid, &from->sb_uuid); ··· 584 545 uint16_t qflags = from->sb_qflags; 585 546 586 547 to->sb_uquotino = cpu_to_be64(from->sb_uquotino); 587 - if (xfs_sb_version_haspquotino(from)) { 548 + 549 + /* 550 + * The in-memory superblock quota state matches the v5 on-disk format so 551 + * just write them out and return 552 + */ 553 + if (XFS_SB_VERSION_NUM(from) == XFS_SB_VERSION_5) { 588 554 to->sb_qflags = cpu_to_be16(from->sb_qflags); 589 555 to->sb_gquotino = cpu_to_be64(from->sb_gquotino); 590 556 to->sb_pquotino = cpu_to_be64(from->sb_pquotino); ··· 597 553 } 598 554 599 555 /* 600 - * The in-core version of sb_qflags do not have XFS_OQUOTA_* 601 - * flags, whereas the on-disk version does. So, convert incore 602 - * XFS_{PG}QUOTA_* flags to on-disk XFS_OQUOTA_* flags. 556 + * For older superblocks (v4), the in-core version of sb_qflags do not 557 + * have XFS_OQUOTA_* flags, whereas the on-disk version does. So, 558 + * convert incore XFS_{PG}QUOTA_* flags to on-disk XFS_OQUOTA_* flags. 603 559 */ 604 560 qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD | 605 561 XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD); ··· 699 655 to->sb_features2 = cpu_to_be32(from->sb_features2); 700 656 to->sb_bad_features2 = cpu_to_be32(from->sb_bad_features2); 701 657 702 - if (xfs_sb_version_hascrc(from)) { 658 + if (XFS_SB_VERSION_NUM(from) == XFS_SB_VERSION_5) { 703 659 to->sb_features_compat = cpu_to_be32(from->sb_features_compat); 704 660 to->sb_features_ro_compat = 705 661 cpu_to_be32(from->sb_features_ro_compat); ··· 709 665 cpu_to_be32(from->sb_features_log_incompat); 710 666 to->sb_spino_align = cpu_to_be32(from->sb_spino_align); 711 667 to->sb_lsn = cpu_to_be64(from->sb_lsn); 712 - if (xfs_sb_version_hasmetauuid(from)) 668 + if (from->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID) 713 669 uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid); 714 670 } 715 671 } ··· 747 703 if (!xfs_buf_verify_cksum(bp, XFS_SB_CRC_OFF)) { 748 704 /* Only fail bad secondaries on a known V5 filesystem */ 749 705 if (bp->b_maps[0].bm_bn == XFS_SB_DADDR || 750 - xfs_sb_version_hascrc(&mp->m_sb)) { 706 + xfs_has_crc(mp)) { 751 707 error = -EFSBADCRC; 752 708 goto out_error; 753 709 } ··· 814 770 if (error) 815 771 goto out_error; 816 772 817 - if (!xfs_sb_version_hascrc(&sb)) 773 + if (XFS_SB_VERSION_NUM(&sb) != XFS_SB_VERSION_5) 818 774 return; 819 775 820 776 if (bip)
+1
fs/xfs/libxfs/xfs_sb.h
··· 20 20 extern void xfs_sb_from_disk(struct xfs_sb *to, struct xfs_dsb *from); 21 21 extern void xfs_sb_to_disk(struct xfs_dsb *to, struct xfs_sb *from); 22 22 extern void xfs_sb_quota_from_disk(struct xfs_sb *sbp); 23 + extern bool xfs_sb_good_version(struct xfs_sb *sbp); 23 24 extern uint64_t xfs_sb_version_to_features(struct xfs_sb *sbp); 24 25 25 26 extern int xfs_update_secondary_sbs(struct xfs_mount *mp);