diff options
Diffstat (limited to 'fs/xfs/xfs_mount.c')
-rw-r--r-- | fs/xfs/xfs_mount.c | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 6409b3762995..8ed164eb9544 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include "xfs_quota.h" | 44 | #include "xfs_quota.h" |
45 | #include "xfs_fsops.h" | 45 | #include "xfs_fsops.h" |
46 | 46 | ||
47 | STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t); | 47 | STATIC void xfs_mount_log_sb(xfs_mount_t *, __int64_t); |
48 | STATIC int xfs_uuid_mount(xfs_mount_t *); | 48 | STATIC int xfs_uuid_mount(xfs_mount_t *); |
49 | STATIC void xfs_uuid_unmount(xfs_mount_t *mp); | 49 | STATIC void xfs_uuid_unmount(xfs_mount_t *mp); |
50 | STATIC void xfs_unmountfs_wait(xfs_mount_t *); | 50 | STATIC void xfs_unmountfs_wait(xfs_mount_t *); |
@@ -119,6 +119,7 @@ static const struct { | |||
119 | { offsetof(xfs_sb_t, sb_logsectsize),0 }, | 119 | { offsetof(xfs_sb_t, sb_logsectsize),0 }, |
120 | { offsetof(xfs_sb_t, sb_logsunit), 0 }, | 120 | { offsetof(xfs_sb_t, sb_logsunit), 0 }, |
121 | { offsetof(xfs_sb_t, sb_features2), 0 }, | 121 | { offsetof(xfs_sb_t, sb_features2), 0 }, |
122 | { offsetof(xfs_sb_t, sb_bad_features2), 0 }, | ||
122 | { sizeof(xfs_sb_t), 0 } | 123 | { sizeof(xfs_sb_t), 0 } |
123 | }; | 124 | }; |
124 | 125 | ||
@@ -225,7 +226,7 @@ xfs_mount_validate_sb( | |||
225 | return XFS_ERROR(EWRONGFS); | 226 | return XFS_ERROR(EWRONGFS); |
226 | } | 227 | } |
227 | 228 | ||
228 | if (!XFS_SB_GOOD_VERSION(sbp)) { | 229 | if (!xfs_sb_good_version(sbp)) { |
229 | xfs_fs_mount_cmn_err(flags, "bad version"); | 230 | xfs_fs_mount_cmn_err(flags, "bad version"); |
230 | return XFS_ERROR(EWRONGFS); | 231 | return XFS_ERROR(EWRONGFS); |
231 | } | 232 | } |
@@ -300,7 +301,7 @@ xfs_mount_validate_sb( | |||
300 | /* | 301 | /* |
301 | * Version 1 directory format has never worked on Linux. | 302 | * Version 1 directory format has never worked on Linux. |
302 | */ | 303 | */ |
303 | if (unlikely(!XFS_SB_VERSION_HASDIRV2(sbp))) { | 304 | if (unlikely(!xfs_sb_version_hasdirv2(sbp))) { |
304 | xfs_fs_mount_cmn_err(flags, | 305 | xfs_fs_mount_cmn_err(flags, |
305 | "file system using version 1 directory format"); | 306 | "file system using version 1 directory format"); |
306 | return XFS_ERROR(ENOSYS); | 307 | return XFS_ERROR(ENOSYS); |
@@ -449,6 +450,7 @@ xfs_sb_from_disk( | |||
449 | to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); | 450 | to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); |
450 | to->sb_logsunit = be32_to_cpu(from->sb_logsunit); | 451 | to->sb_logsunit = be32_to_cpu(from->sb_logsunit); |
451 | to->sb_features2 = be32_to_cpu(from->sb_features2); | 452 | to->sb_features2 = be32_to_cpu(from->sb_features2); |
453 | to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2); | ||
452 | } | 454 | } |
453 | 455 | ||
454 | /* | 456 | /* |
@@ -781,7 +783,7 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) | |||
781 | * Update superblock with new values | 783 | * Update superblock with new values |
782 | * and log changes | 784 | * and log changes |
783 | */ | 785 | */ |
784 | if (XFS_SB_VERSION_HASDALIGN(sbp)) { | 786 | if (xfs_sb_version_hasdalign(sbp)) { |
785 | if (sbp->sb_unit != mp->m_dalign) { | 787 | if (sbp->sb_unit != mp->m_dalign) { |
786 | sbp->sb_unit = mp->m_dalign; | 788 | sbp->sb_unit = mp->m_dalign; |
787 | *update_flags |= XFS_SB_UNIT; | 789 | *update_flags |= XFS_SB_UNIT; |
@@ -792,7 +794,7 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) | |||
792 | } | 794 | } |
793 | } | 795 | } |
794 | } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && | 796 | } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && |
795 | XFS_SB_VERSION_HASDALIGN(&mp->m_sb)) { | 797 | xfs_sb_version_hasdalign(&mp->m_sb)) { |
796 | mp->m_dalign = sbp->sb_unit; | 798 | mp->m_dalign = sbp->sb_unit; |
797 | mp->m_swidth = sbp->sb_width; | 799 | mp->m_swidth = sbp->sb_width; |
798 | } | 800 | } |
@@ -869,7 +871,7 @@ xfs_set_rw_sizes(xfs_mount_t *mp) | |||
869 | STATIC void | 871 | STATIC void |
870 | xfs_set_inoalignment(xfs_mount_t *mp) | 872 | xfs_set_inoalignment(xfs_mount_t *mp) |
871 | { | 873 | { |
872 | if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) && | 874 | if (xfs_sb_version_hasalign(&mp->m_sb) && |
873 | mp->m_sb.sb_inoalignmt >= | 875 | mp->m_sb.sb_inoalignmt >= |
874 | XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) | 876 | XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) |
875 | mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; | 877 | mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; |
@@ -970,6 +972,38 @@ xfs_mountfs( | |||
970 | xfs_mount_common(mp, sbp); | 972 | xfs_mount_common(mp, sbp); |
971 | 973 | ||
972 | /* | 974 | /* |
975 | * Check for a mismatched features2 values. Older kernels | ||
976 | * read & wrote into the wrong sb offset for sb_features2 | ||
977 | * on some platforms due to xfs_sb_t not being 64bit size aligned | ||
978 | * when sb_features2 was added, which made older superblock | ||
979 | * reading/writing routines swap it as a 64-bit value. | ||
980 | * | ||
981 | * For backwards compatibility, we make both slots equal. | ||
982 | * | ||
983 | * If we detect a mismatched field, we OR the set bits into the | ||
984 | * existing features2 field in case it has already been modified; we | ||
985 | * don't want to lose any features. We then update the bad location | ||
986 | * with the ORed value so that older kernels will see any features2 | ||
987 | * flags, and mark the two fields as needing updates once the | ||
988 | * transaction subsystem is online. | ||
989 | */ | ||
990 | if (xfs_sb_has_mismatched_features2(sbp)) { | ||
991 | cmn_err(CE_WARN, | ||
992 | "XFS: correcting sb_features alignment problem"); | ||
993 | sbp->sb_features2 |= sbp->sb_bad_features2; | ||
994 | sbp->sb_bad_features2 = sbp->sb_features2; | ||
995 | update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2; | ||
996 | |||
997 | /* | ||
998 | * Re-check for ATTR2 in case it was found in bad_features2 | ||
999 | * slot. | ||
1000 | */ | ||
1001 | if (xfs_sb_version_hasattr2(&mp->m_sb)) | ||
1002 | mp->m_flags |= XFS_MOUNT_ATTR2; | ||
1003 | |||
1004 | } | ||
1005 | |||
1006 | /* | ||
973 | * Check if sb_agblocks is aligned at stripe boundary | 1007 | * Check if sb_agblocks is aligned at stripe boundary |
974 | * If sb_agblocks is NOT aligned turn off m_dalign since | 1008 | * If sb_agblocks is NOT aligned turn off m_dalign since |
975 | * allocator alignment is within an ag, therefore ag has | 1009 | * allocator alignment is within an ag, therefore ag has |
@@ -1159,11 +1193,10 @@ xfs_mountfs( | |||
1159 | } | 1193 | } |
1160 | 1194 | ||
1161 | /* | 1195 | /* |
1162 | * If fs is not mounted readonly, then update the superblock | 1196 | * If fs is not mounted readonly, then update the superblock changes. |
1163 | * unit and width changes. | ||
1164 | */ | 1197 | */ |
1165 | if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) | 1198 | if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) |
1166 | xfs_mount_log_sbunit(mp, update_flags); | 1199 | xfs_mount_log_sb(mp, update_flags); |
1167 | 1200 | ||
1168 | /* | 1201 | /* |
1169 | * Initialise the XFS quota management subsystem for this mount | 1202 | * Initialise the XFS quota management subsystem for this mount |
@@ -1875,16 +1908,18 @@ xfs_uuid_unmount( | |||
1875 | 1908 | ||
1876 | /* | 1909 | /* |
1877 | * Used to log changes to the superblock unit and width fields which could | 1910 | * Used to log changes to the superblock unit and width fields which could |
1878 | * be altered by the mount options. Only the first superblock is updated. | 1911 | * be altered by the mount options, as well as any potential sb_features2 |
1912 | * fixup. Only the first superblock is updated. | ||
1879 | */ | 1913 | */ |
1880 | STATIC void | 1914 | STATIC void |
1881 | xfs_mount_log_sbunit( | 1915 | xfs_mount_log_sb( |
1882 | xfs_mount_t *mp, | 1916 | xfs_mount_t *mp, |
1883 | __int64_t fields) | 1917 | __int64_t fields) |
1884 | { | 1918 | { |
1885 | xfs_trans_t *tp; | 1919 | xfs_trans_t *tp; |
1886 | 1920 | ||
1887 | ASSERT(fields & (XFS_SB_UNIT|XFS_SB_WIDTH|XFS_SB_UUID)); | 1921 | ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID | |
1922 | XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2)); | ||
1888 | 1923 | ||
1889 | tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); | 1924 | tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); |
1890 | if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, | 1925 | if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, |