diff options
-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 | */ |