summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_mount.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_mount.c')
-rw-r--r--fs/xfs/xfs_mount.c49
1 files changed, 33 insertions, 16 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 6409b3762995..5be0328bbfbb 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -44,7 +44,7 @@
#include "xfs_quota.h"
#include "xfs_fsops.h"
-STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t);
+STATIC void xfs_mount_log_sb(xfs_mount_t *, __int64_t);
STATIC int xfs_uuid_mount(xfs_mount_t *);
STATIC void xfs_uuid_unmount(xfs_mount_t *mp);
STATIC void xfs_unmountfs_wait(xfs_mount_t *);
@@ -119,6 +119,7 @@ static const struct {
{ offsetof(xfs_sb_t, sb_logsectsize),0 },
{ offsetof(xfs_sb_t, sb_logsunit), 0 },
{ offsetof(xfs_sb_t, sb_features2), 0 },
+ { offsetof(xfs_sb_t, sb_bad_features2), 0 },
{ sizeof(xfs_sb_t), 0 }
};
@@ -225,7 +226,7 @@ xfs_mount_validate_sb(
return XFS_ERROR(EWRONGFS);
}
- if (!XFS_SB_GOOD_VERSION(sbp)) {
+ if (!xfs_sb_good_version(sbp)) {
xfs_fs_mount_cmn_err(flags, "bad version");
return XFS_ERROR(EWRONGFS);
}
@@ -300,7 +301,7 @@ xfs_mount_validate_sb(
/*
* Version 1 directory format has never worked on Linux.
*/
- if (unlikely(!XFS_SB_VERSION_HASDIRV2(sbp))) {
+ if (unlikely(!xfs_sb_version_hasdirv2(sbp))) {
xfs_fs_mount_cmn_err(flags,
"file system using version 1 directory format");
return XFS_ERROR(ENOSYS);
@@ -449,6 +450,7 @@ xfs_sb_from_disk(
to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize);
to->sb_logsunit = be32_to_cpu(from->sb_logsunit);
to->sb_features2 = be32_to_cpu(from->sb_features2);
+ to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2);
}
/*
@@ -781,7 +783,7 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags)
* Update superblock with new values
* and log changes
*/
- if (XFS_SB_VERSION_HASDALIGN(sbp)) {
+ if (xfs_sb_version_hasdalign(sbp)) {
if (sbp->sb_unit != mp->m_dalign) {
sbp->sb_unit = mp->m_dalign;
*update_flags |= XFS_SB_UNIT;
@@ -792,7 +794,7 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags)
}
}
} else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN &&
- XFS_SB_VERSION_HASDALIGN(&mp->m_sb)) {
+ xfs_sb_version_hasdalign(&mp->m_sb)) {
mp->m_dalign = sbp->sb_unit;
mp->m_swidth = sbp->sb_width;
}
@@ -869,7 +871,7 @@ xfs_set_rw_sizes(xfs_mount_t *mp)
STATIC void
xfs_set_inoalignment(xfs_mount_t *mp)
{
- if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) &&
+ if (xfs_sb_version_hasalign(&mp->m_sb) &&
mp->m_sb.sb_inoalignmt >=
XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size))
mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1;
@@ -962,14 +964,29 @@ xfs_mountfs(
int uuid_mounted = 0;
int error = 0;
- if (mp->m_sb_bp == NULL) {
- error = xfs_readsb(mp, mfsi_flags);
- if (error)
- return error;
- }
xfs_mount_common(mp, sbp);
/*
+ * Check for a bad features2 field alignment. This happened on
+ * some platforms due to xfs_sb_t not being 64bit size aligned
+ * when sb_features was added and hence the compiler put it in
+ * the wrong place.
+ *
+ * If we detect a bad field, we or the set bits into the existing
+ * features2 field in case it has already been modified and we
+ * don't want to lose any features. Zero the bad one and mark
+ * the two fields as needing updates once the transaction subsystem
+ * is online.
+ */
+ if (xfs_sb_has_bad_features2(sbp)) {
+ cmn_err(CE_WARN,
+ "XFS: correcting sb_features alignment problem");
+ sbp->sb_features2 |= sbp->sb_bad_features2;
+ sbp->sb_bad_features2 = 0;
+ update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
+ }
+
+ /*
* Check if sb_agblocks is aligned at stripe boundary
* If sb_agblocks is NOT aligned turn off m_dalign since
* allocator alignment is within an ag, therefore ag has
@@ -1159,11 +1176,10 @@ xfs_mountfs(
}
/*
- * If fs is not mounted readonly, then update the superblock
- * unit and width changes.
+ * If fs is not mounted readonly, then update the superblock changes.
*/
if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY))
- xfs_mount_log_sbunit(mp, update_flags);
+ xfs_mount_log_sb(mp, update_flags);
/*
* Initialise the XFS quota management subsystem for this mount
@@ -1878,13 +1894,14 @@ xfs_uuid_unmount(
* be altered by the mount options. Only the first superblock is updated.
*/
STATIC void
-xfs_mount_log_sbunit(
+xfs_mount_log_sb(
xfs_mount_t *mp,
__int64_t fields)
{
xfs_trans_t *tp;
- ASSERT(fields & (XFS_SB_UNIT|XFS_SB_WIDTH|XFS_SB_UUID));
+ ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID |
+ XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2));
tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT);
if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,