diff options
| author | Dave Chinner <dchinner@redhat.com> | 2013-04-03 01:11:32 -0400 |
|---|---|---|
| committer | Ben Myers <bpm@sgi.com> | 2013-04-27 14:05:18 -0400 |
| commit | e721f504cf46a0c84741ba2137d7a052d79436db (patch) | |
| tree | dd9d92321068cab132cecebc4abb9c6489e36986 | |
| parent | 04a1e6c5b222b089c6960dfc5352002002a4355f (diff) | |
xfs: implement extended feature masks
The version 5 superblock has extended feature masks for compatible,
incompatible and read-only compatible feature sets. Implement the
masking and mount-time checking for these feature masks.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
| -rw-r--r-- | fs/xfs/xfs_log_recover.c | 19 | ||||
| -rw-r--r-- | fs/xfs/xfs_mount.c | 48 | ||||
| -rw-r--r-- | fs/xfs/xfs_sb.h | 70 |
3 files changed, 129 insertions, 8 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 5303b3db3c98..35ac5044ddfd 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
| @@ -3959,6 +3959,25 @@ xlog_recover( | |||
| 3959 | return error; | 3959 | return error; |
| 3960 | } | 3960 | } |
| 3961 | 3961 | ||
| 3962 | /* | ||
| 3963 | * Version 5 superblock log feature mask validation. We know the | ||
| 3964 | * log is dirty so check if there are any unknown log features | ||
| 3965 | * in what we need to recover. If there are unknown features | ||
| 3966 | * (e.g. unsupported transactions, then simply reject the | ||
| 3967 | * attempt at recovery before touching anything. | ||
| 3968 | */ | ||
| 3969 | if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 && | ||
| 3970 | xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb, | ||
| 3971 | XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) { | ||
| 3972 | xfs_warn(log->l_mp, | ||
| 3973 | "Superblock has unknown incompatible log features (0x%x) enabled.\n" | ||
| 3974 | "The log can not be fully and/or safely recovered by this kernel.\n" | ||
| 3975 | "Please recover the log on a kernel that supports the unknown features.", | ||
| 3976 | (log->l_mp->m_sb.sb_features_log_incompat & | ||
| 3977 | XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)); | ||
| 3978 | return EINVAL; | ||
| 3979 | } | ||
| 3980 | |||
| 3962 | xfs_notice(log->l_mp, "Starting recovery (logdev: %s)", | 3981 | xfs_notice(log->l_mp, "Starting recovery (logdev: %s)", |
| 3963 | log->l_mp->m_logname ? log->l_mp->m_logname | 3982 | log->l_mp->m_logname ? log->l_mp->m_logname |
| 3964 | : "internal"); | 3983 | : "internal"); |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 140136cf2dc0..f6bfbd734669 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
| @@ -114,7 +114,9 @@ static const struct { | |||
| 114 | { offsetof(xfs_sb_t, sb_features_compat), 0 }, | 114 | { offsetof(xfs_sb_t, sb_features_compat), 0 }, |
| 115 | { offsetof(xfs_sb_t, sb_features_ro_compat), 0 }, | 115 | { offsetof(xfs_sb_t, sb_features_ro_compat), 0 }, |
| 116 | { offsetof(xfs_sb_t, sb_features_incompat), 0 }, | 116 | { offsetof(xfs_sb_t, sb_features_incompat), 0 }, |
| 117 | { offsetof(xfs_sb_t, sb_features_log_incompat), 0 }, | ||
| 117 | { offsetof(xfs_sb_t, sb_crc), 0 }, | 118 | { offsetof(xfs_sb_t, sb_crc), 0 }, |
| 119 | { offsetof(xfs_sb_t, sb_pad), 0 }, | ||
| 118 | { offsetof(xfs_sb_t, sb_pquotino), 0 }, | 120 | { offsetof(xfs_sb_t, sb_pquotino), 0 }, |
| 119 | { offsetof(xfs_sb_t, sb_lsn), 0 }, | 121 | { offsetof(xfs_sb_t, sb_lsn), 0 }, |
| 120 | { sizeof(xfs_sb_t), 0 } | 122 | { sizeof(xfs_sb_t), 0 } |
| @@ -334,14 +336,45 @@ xfs_mount_validate_sb( | |||
| 334 | } | 336 | } |
| 335 | 337 | ||
| 336 | /* | 338 | /* |
| 337 | * Do not allow Version 5 superblocks to mount right now, even though | 339 | * Version 5 superblock feature mask validation. Reject combinations the |
| 338 | * support is in place. We need to implement the proper feature masks | 340 | * kernel cannot support up front before checking anything else. |
| 339 | * first. | ||
| 340 | */ | 341 | */ |
| 341 | if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) { | 342 | if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) { |
| 342 | xfs_alert(mp, | 343 | xfs_alert(mp, |
| 343 | "Version 5 superblock detected. Experimental support not yet enabled!"); | 344 | "Version 5 superblock detected. This kernel has EXPERIMENTAL support enabled!\n" |
| 344 | return XFS_ERROR(EINVAL); | 345 | "Use of these features in this kernel is at your own risk!"); |
| 346 | |||
| 347 | if (xfs_sb_has_compat_feature(sbp, | ||
| 348 | XFS_SB_FEAT_COMPAT_UNKNOWN)) { | ||
| 349 | xfs_warn(mp, | ||
| 350 | "Superblock has unknown compatible features (0x%x) enabled.\n" | ||
| 351 | "Using a more recent kernel is recommended.", | ||
| 352 | (sbp->sb_features_compat & | ||
| 353 | XFS_SB_FEAT_COMPAT_UNKNOWN)); | ||
| 354 | } | ||
| 355 | |||
| 356 | if (xfs_sb_has_ro_compat_feature(sbp, | ||
| 357 | XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { | ||
| 358 | xfs_alert(mp, | ||
| 359 | "Superblock has unknown read-only compatible features (0x%x) enabled.", | ||
| 360 | (sbp->sb_features_ro_compat & | ||
| 361 | XFS_SB_FEAT_RO_COMPAT_UNKNOWN)); | ||
| 362 | if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { | ||
| 363 | xfs_warn(mp, | ||
| 364 | "Attempted to mount read-only compatible filesystem read-write.\n" | ||
| 365 | "Filesystem can only be safely mounted read only."); | ||
| 366 | return XFS_ERROR(EINVAL); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | if (xfs_sb_has_incompat_feature(sbp, | ||
| 370 | XFS_SB_FEAT_INCOMPAT_UNKNOWN)) { | ||
| 371 | xfs_warn(mp, | ||
| 372 | "Superblock has unknown incompatible features (0x%x) enabled.\n" | ||
| 373 | "Filesystem can not be safely mounted by this kernel.", | ||
| 374 | (sbp->sb_features_incompat & | ||
| 375 | XFS_SB_FEAT_INCOMPAT_UNKNOWN)); | ||
| 376 | return XFS_ERROR(EINVAL); | ||
| 377 | } | ||
| 345 | } | 378 | } |
| 346 | 379 | ||
| 347 | if (unlikely( | 380 | if (unlikely( |
| @@ -580,6 +613,9 @@ xfs_sb_from_disk( | |||
| 580 | to->sb_features_compat = be32_to_cpu(from->sb_features_compat); | 613 | to->sb_features_compat = be32_to_cpu(from->sb_features_compat); |
| 581 | to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat); | 614 | to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat); |
| 582 | to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat); | 615 | to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat); |
| 616 | to->sb_features_log_incompat = | ||
| 617 | be32_to_cpu(from->sb_features_log_incompat); | ||
| 618 | to->sb_pad = 0; | ||
| 583 | to->sb_pquotino = be64_to_cpu(from->sb_pquotino); | 619 | to->sb_pquotino = be64_to_cpu(from->sb_pquotino); |
| 584 | to->sb_lsn = be64_to_cpu(from->sb_lsn); | 620 | to->sb_lsn = be64_to_cpu(from->sb_lsn); |
| 585 | } | 621 | } |
| @@ -786,7 +822,7 @@ reread: | |||
| 786 | if (bp->b_error) { | 822 | if (bp->b_error) { |
| 787 | error = bp->b_error; | 823 | error = bp->b_error; |
| 788 | if (loud) | 824 | if (loud) |
| 789 | xfs_warn(mp, "SB validate failed"); | 825 | xfs_warn(mp, "SB validate failed with error %d.", error); |
| 790 | goto release_buf; | 826 | goto release_buf; |
| 791 | } | 827 | } |
| 792 | 828 | ||
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h index 457fefae5683..2de58a85833c 100644 --- a/fs/xfs/xfs_sb.h +++ b/fs/xfs/xfs_sb.h | |||
| @@ -168,8 +168,10 @@ typedef struct xfs_sb { | |||
| 168 | __uint32_t sb_features_compat; | 168 | __uint32_t sb_features_compat; |
| 169 | __uint32_t sb_features_ro_compat; | 169 | __uint32_t sb_features_ro_compat; |
| 170 | __uint32_t sb_features_incompat; | 170 | __uint32_t sb_features_incompat; |
| 171 | __uint32_t sb_features_log_incompat; | ||
| 171 | 172 | ||
| 172 | __uint32_t sb_crc; /* superblock crc */ | 173 | __uint32_t sb_crc; /* superblock crc */ |
| 174 | __uint32_t sb_pad; | ||
| 173 | 175 | ||
| 174 | xfs_ino_t sb_pquotino; /* project quota inode */ | 176 | xfs_ino_t sb_pquotino; /* project quota inode */ |
| 175 | xfs_lsn_t sb_lsn; /* last write sequence */ | 177 | xfs_lsn_t sb_lsn; /* last write sequence */ |
| @@ -250,8 +252,10 @@ typedef struct xfs_dsb { | |||
| 250 | __be32 sb_features_compat; | 252 | __be32 sb_features_compat; |
| 251 | __be32 sb_features_ro_compat; | 253 | __be32 sb_features_ro_compat; |
| 252 | __be32 sb_features_incompat; | 254 | __be32 sb_features_incompat; |
| 255 | __be32 sb_features_log_incompat; | ||
| 253 | 256 | ||
| 254 | __le32 sb_crc; /* superblock crc */ | 257 | __le32 sb_crc; /* superblock crc */ |
| 258 | __be32 sb_pad; | ||
| 255 | 259 | ||
| 256 | __be64 sb_pquotino; /* project quota inode */ | 260 | __be64 sb_pquotino; /* project quota inode */ |
| 257 | __be64 sb_lsn; /* last write sequence */ | 261 | __be64 sb_lsn; /* last write sequence */ |
| @@ -276,7 +280,8 @@ typedef enum { | |||
| 276 | XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG, | 280 | XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG, |
| 277 | XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT, | 281 | XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT, |
| 278 | XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2, XFS_SBS_FEATURES_COMPAT, | 282 | XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2, XFS_SBS_FEATURES_COMPAT, |
| 279 | XFS_SBS_FEATURES_RO_COMPAT, XFS_SBS_FEATURES_INCOMPAT, XFS_SBS_CRC, | 283 | XFS_SBS_FEATURES_RO_COMPAT, XFS_SBS_FEATURES_INCOMPAT, |
| 284 | XFS_SBS_FEATURES_LOG_INCOMPAT, XFS_SBS_CRC, XFS_SBS_PAD, | ||
| 280 | XFS_SBS_PQUOTINO, XFS_SBS_LSN, | 285 | XFS_SBS_PQUOTINO, XFS_SBS_LSN, |
| 281 | XFS_SBS_FIELDCOUNT | 286 | XFS_SBS_FIELDCOUNT |
| 282 | } xfs_sb_field_t; | 287 | } xfs_sb_field_t; |
| @@ -306,6 +311,7 @@ typedef enum { | |||
| 306 | #define XFS_SB_FEATURES_COMPAT XFS_SB_MVAL(FEATURES_COMPAT) | 311 | #define XFS_SB_FEATURES_COMPAT XFS_SB_MVAL(FEATURES_COMPAT) |
| 307 | #define XFS_SB_FEATURES_RO_COMPAT XFS_SB_MVAL(FEATURES_RO_COMPAT) | 312 | #define XFS_SB_FEATURES_RO_COMPAT XFS_SB_MVAL(FEATURES_RO_COMPAT) |
| 308 | #define XFS_SB_FEATURES_INCOMPAT XFS_SB_MVAL(FEATURES_INCOMPAT) | 313 | #define XFS_SB_FEATURES_INCOMPAT XFS_SB_MVAL(FEATURES_INCOMPAT) |
| 314 | #define XFS_SB_FEATURES_LOG_INCOMPAT XFS_SB_MVAL(FEATURES_LOG_INCOMPAT) | ||
| 309 | #define XFS_SB_CRC XFS_SB_MVAL(CRC) | 315 | #define XFS_SB_CRC XFS_SB_MVAL(CRC) |
| 310 | #define XFS_SB_PQUOTINO XFS_SB_MVAL(PQUOTINO) | 316 | #define XFS_SB_PQUOTINO XFS_SB_MVAL(PQUOTINO) |
| 311 | #define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT) | 317 | #define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT) |
| @@ -316,7 +322,8 @@ typedef enum { | |||
| 316 | XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \ | 322 | XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \ |
| 317 | XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \ | 323 | XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \ |
| 318 | XFS_SB_BAD_FEATURES2 | XFS_SB_FEATURES_COMPAT | \ | 324 | XFS_SB_BAD_FEATURES2 | XFS_SB_FEATURES_COMPAT | \ |
| 319 | XFS_SB_FEATURES_RO_COMPAT | XFS_SB_FEATURES_INCOMPAT | XFS_SB_PQUOTINO) | 325 | XFS_SB_FEATURES_RO_COMPAT | XFS_SB_FEATURES_INCOMPAT | \ |
| 326 | XFS_SB_FEATURES_LOG_INCOMPAT | XFS_SB_PQUOTINO) | ||
| 320 | 327 | ||
| 321 | 328 | ||
| 322 | /* | 329 | /* |
| @@ -552,6 +559,65 @@ static inline int xfs_sb_version_hascrc(xfs_sb_t *sbp) | |||
| 552 | return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5; | 559 | return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5; |
| 553 | } | 560 | } |
| 554 | 561 | ||
| 562 | |||
| 563 | /* | ||
| 564 | * Extended v5 superblock feature masks. These are to be used for new v5 | ||
| 565 | * superblock features only. | ||
| 566 | * | ||
| 567 | * Compat features are new features that old kernels will not notice or affect | ||
| 568 | * and so can mount read-write without issues. | ||
| 569 | * | ||
| 570 | * RO-Compat (read only) are features that old kernels can read but will break | ||
| 571 | * if they write. Hence only read-only mounts of such filesystems are allowed on | ||
| 572 | * kernels that don't support the feature bit. | ||
| 573 | * | ||
| 574 | * InCompat features are features which old kernels will not understand and so | ||
| 575 | * must not mount. | ||
| 576 | * | ||
| 577 | * Log-InCompat features are for changes to log formats or new transactions that | ||
| 578 | * can't be replayed on older kernels. The fields are set when the filesystem is | ||
| 579 | * mounted, and a clean unmount clears the fields. | ||
| 580 | */ | ||
| 581 | #define XFS_SB_FEAT_COMPAT_ALL 0 | ||
| 582 | #define XFS_SB_FEAT_COMPAT_UNKNOWN ~XFS_SB_FEAT_COMPAT_ALL | ||
| 583 | static inline bool | ||
| 584 | xfs_sb_has_compat_feature( | ||
| 585 | struct xfs_sb *sbp, | ||
| 586 | __uint32_t feature) | ||
| 587 | { | ||
| 588 | return (sbp->sb_features_compat & feature) != 0; | ||
| 589 | } | ||
| 590 | |||
| 591 | #define XFS_SB_FEAT_RO_COMPAT_ALL 0 | ||
| 592 | #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL | ||
| 593 | static inline bool | ||
| 594 | xfs_sb_has_ro_compat_feature( | ||
| 595 | struct xfs_sb *sbp, | ||
| 596 | __uint32_t feature) | ||
| 597 | { | ||
| 598 | return (sbp->sb_features_ro_compat & feature) != 0; | ||
| 599 | } | ||
| 600 | |||
| 601 | #define XFS_SB_FEAT_INCOMPAT_ALL 0 | ||
| 602 | #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL | ||
| 603 | static inline bool | ||
| 604 | xfs_sb_has_incompat_feature( | ||
| 605 | struct xfs_sb *sbp, | ||
| 606 | __uint32_t feature) | ||
| 607 | { | ||
| 608 | return (sbp->sb_features_incompat & feature) != 0; | ||
| 609 | } | ||
| 610 | |||
| 611 | #define XFS_SB_FEAT_INCOMPAT_LOG_ALL 0 | ||
| 612 | #define XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_LOG_ALL | ||
| 613 | static inline bool | ||
| 614 | xfs_sb_has_incompat_log_feature( | ||
| 615 | struct xfs_sb *sbp, | ||
| 616 | __uint32_t feature) | ||
| 617 | { | ||
| 618 | return (sbp->sb_features_log_incompat & feature) != 0; | ||
| 619 | } | ||
| 620 | |||
| 555 | /* | 621 | /* |
| 556 | * end of superblock version macros | 622 | * end of superblock version macros |
| 557 | */ | 623 | */ |
