aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2008-03-05 21:45:50 -0500
committerLachlan McIlroy <lachlan@redback.melbourne.sgi.com>2008-04-10 02:25:15 -0400
commitee1c090825bf2f1cb9712489c234eabf69a9a78f (patch)
treec261cbeeda46937e6c65994b4348227505665f66 /fs
parent6211870992502efdccf9cd6bae155c83277835fa (diff)
[XFS] Fix superblock features2 field alignment problem
Due to the xfs_dsb_t structure not being 64 bit aligned, the last field of the on-disk superblock can vary in location This causes problems when the filesystem gets moved to a different platform, or there is a 32 bit userspace and 64 bit kernel. This patch detects the defect at mount time, logs a warning such as: XFS: correcting sb_features alignment problem in dmesg and corrects the problem so that everything is OK. it also blacklists the bad field in the superblock so it does not get used for something else later on. SGI-PV: 977636 SGI-Modid: xfs-linux-melb:xfs-kern:30539a Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Eric Sandeen <sandeen@sandeen.net> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_mount.c34
-rw-r--r--fs/xfs/xfs_sb.h37
2 files changed, 62 insertions, 9 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 99bab1e372b..4e93c02faf2 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
47STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t); 47STATIC void xfs_mount_log_sb(xfs_mount_t *, __int64_t);
48STATIC int xfs_uuid_mount(xfs_mount_t *); 48STATIC int xfs_uuid_mount(xfs_mount_t *);
49STATIC void xfs_uuid_unmount(xfs_mount_t *mp); 49STATIC void xfs_uuid_unmount(xfs_mount_t *mp);
50STATIC void xfs_unmountfs_wait(xfs_mount_t *); 50STATIC 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
@@ -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/*
@@ -970,6 +972,26 @@ xfs_mountfs(
970 xfs_mount_common(mp, sbp); 972 xfs_mount_common(mp, sbp);
971 973
972 /* 974 /*
975 * Check for a bad features2 field alignment. This happened on
976 * some platforms due to xfs_sb_t not being 64bit size aligned
977 * when sb_features was added and hence the compiler put it in
978 * the wrong place.
979 *
980 * If we detect a bad field, we or the set bits into the existing
981 * features2 field in case it has already been modified and we
982 * don't want to lose any features. Zero the bad one and mark
983 * the two fields as needing updates once the transaction subsystem
984 * is online.
985 */
986 if (xfs_sb_has_bad_features2(sbp)) {
987 cmn_err(CE_WARN,
988 "XFS: correcting sb_features alignment problem");
989 sbp->sb_features2 |= sbp->sb_bad_features2;
990 sbp->sb_bad_features2 = 0;
991 update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
992 }
993
994 /*
973 * Check if sb_agblocks is aligned at stripe boundary 995 * Check if sb_agblocks is aligned at stripe boundary
974 * If sb_agblocks is NOT aligned turn off m_dalign since 996 * If sb_agblocks is NOT aligned turn off m_dalign since
975 * allocator alignment is within an ag, therefore ag has 997 * allocator alignment is within an ag, therefore ag has
@@ -1159,11 +1181,10 @@ xfs_mountfs(
1159 } 1181 }
1160 1182
1161 /* 1183 /*
1162 * If fs is not mounted readonly, then update the superblock 1184 * If fs is not mounted readonly, then update the superblock changes.
1163 * unit and width changes.
1164 */ 1185 */
1165 if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) 1186 if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY))
1166 xfs_mount_log_sbunit(mp, update_flags); 1187 xfs_mount_log_sb(mp, update_flags);
1167 1188
1168 /* 1189 /*
1169 * Initialise the XFS quota management subsystem for this mount 1190 * Initialise the XFS quota management subsystem for this mount
@@ -1878,13 +1899,14 @@ xfs_uuid_unmount(
1878 * be altered by the mount options. Only the first superblock is updated. 1899 * be altered by the mount options. Only the first superblock is updated.
1879 */ 1900 */
1880STATIC void 1901STATIC void
1881xfs_mount_log_sbunit( 1902xfs_mount_log_sb(
1882 xfs_mount_t *mp, 1903 xfs_mount_t *mp,
1883 __int64_t fields) 1904 __int64_t fields)
1884{ 1905{
1885 xfs_trans_t *tp; 1906 xfs_trans_t *tp;
1886 1907
1887 ASSERT(fields & (XFS_SB_UNIT|XFS_SB_WIDTH|XFS_SB_UUID)); 1908 ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID |
1909 XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2));
1888 1910
1889 tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); 1911 tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT);
1890 if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, 1912 if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
index d3a59735009..b1a83f8ec04 100644
--- a/fs/xfs/xfs_sb.h
+++ b/fs/xfs/xfs_sb.h
@@ -89,6 +89,7 @@ struct xfs_mount;
89 89
90/* 90/*
91 * Superblock - in core version. Must match the ondisk version below. 91 * Superblock - in core version. Must match the ondisk version below.
92 * Must be padded to 64 bit alignment.
92 */ 93 */
93typedef struct xfs_sb { 94typedef struct xfs_sb {
94 __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ 95 __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
@@ -145,10 +146,21 @@ typedef struct xfs_sb {
145 __uint16_t sb_logsectsize; /* sector size for the log, bytes */ 146 __uint16_t sb_logsectsize; /* sector size for the log, bytes */
146 __uint32_t sb_logsunit; /* stripe unit size for the log */ 147 __uint32_t sb_logsunit; /* stripe unit size for the log */
147 __uint32_t sb_features2; /* additional feature bits */ 148 __uint32_t sb_features2; /* additional feature bits */
149
150 /*
151 * bad features2 field as a result of failing to pad the sb
152 * structure to 64 bits. Some machines will be using this field
153 * for features2 bits. Easiest just to mark it bad and not use
154 * it for anything else.
155 */
156 __uint32_t sb_bad_features2;
157
158 /* must be padded to 64 bit alignment */
148} xfs_sb_t; 159} xfs_sb_t;
149 160
150/* 161/*
151 * Superblock - on disk version. Must match the in core version below. 162 * Superblock - on disk version. Must match the in core version above.
163 * Must be padded to 64 bit alignment.
152 */ 164 */
153typedef struct xfs_dsb { 165typedef struct xfs_dsb {
154 __be32 sb_magicnum; /* magic number == XFS_SB_MAGIC */ 166 __be32 sb_magicnum; /* magic number == XFS_SB_MAGIC */
@@ -205,6 +217,15 @@ typedef struct xfs_dsb {
205 __be16 sb_logsectsize; /* sector size for the log, bytes */ 217 __be16 sb_logsectsize; /* sector size for the log, bytes */
206 __be32 sb_logsunit; /* stripe unit size for the log */ 218 __be32 sb_logsunit; /* stripe unit size for the log */
207 __be32 sb_features2; /* additional feature bits */ 219 __be32 sb_features2; /* additional feature bits */
220 /*
221 * bad features2 field as a result of failing to pad the sb
222 * structure to 64 bits. Some machines will be using this field
223 * for features2 bits. Easiest just to mark it bad and not use
224 * it for anything else.
225 */
226 __be32 sb_bad_features2;
227
228 /* must be padded to 64 bit alignment */
208} xfs_dsb_t; 229} xfs_dsb_t;
209 230
210/* 231/*
@@ -223,7 +244,7 @@ typedef enum {
223 XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN, 244 XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
224 XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG, 245 XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
225 XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT, 246 XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
226 XFS_SBS_FEATURES2, 247 XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
227 XFS_SBS_FIELDCOUNT 248 XFS_SBS_FIELDCOUNT
228} xfs_sb_field_t; 249} xfs_sb_field_t;
229 250
@@ -248,13 +269,15 @@ typedef enum {
248#define XFS_SB_IFREE XFS_SB_MVAL(IFREE) 269#define XFS_SB_IFREE XFS_SB_MVAL(IFREE)
249#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS) 270#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS)
250#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2) 271#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2)
272#define XFS_SB_BAD_FEATURES2 XFS_SB_MVAL(BAD_FEATURES2)
251#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT) 273#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
252#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1) 274#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
253#define XFS_SB_MOD_BITS \ 275#define XFS_SB_MOD_BITS \
254 (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \ 276 (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
255 XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \ 277 XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
256 XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \ 278 XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
257 XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2) 279 XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
280 XFS_SB_BAD_FEATURES2)
258 281
259 282
260/* 283/*
@@ -296,6 +319,14 @@ static inline int xfs_sb_good_version(xfs_sb_t *sbp)
296} 319}
297#endif /* __KERNEL__ */ 320#endif /* __KERNEL__ */
298 321
322/*
323 * Detect a bad features2 field
324 */
325static inline int xfs_sb_has_bad_features2(xfs_sb_t *sbp)
326{
327 return (sbp->sb_bad_features2 != 0);
328}
329
299static inline unsigned xfs_sb_version_tonew(unsigned v) 330static inline unsigned xfs_sb_version_tonew(unsigned v)
300{ 331{
301 return ((((v) == XFS_SB_VERSION_1) ? \ 332 return ((((v) == XFS_SB_VERSION_1) ? \