]> err.no Git - linux-2.6/blobdiff - fs/xfs/xfs_mount.c
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[linux-2.6] / fs / xfs / xfs_mount.c
index 2806d43d7d233b4e8032a428924c1de392f96249..8ed164eb9544e4dcd5618eff7d3c9807f659ca26 100644 (file)
@@ -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 }
 };
 
@@ -136,15 +137,9 @@ xfs_mount_init(void)
                mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB;
        }
 
-       spin_lock_init(&mp->m_ail_lock);
        spin_lock_init(&mp->m_sb_lock);
        mutex_init(&mp->m_ilock);
        mutex_init(&mp->m_growlock);
-       /*
-        * Initialize the AIL.
-        */
-       xfs_trans_ail_init(mp);
-
        atomic_set(&mp->m_active_trans, 0);
 
        return mp;
@@ -231,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);
        }
@@ -306,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);
@@ -455,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);
 }
 
 /*
@@ -787,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;
@@ -798,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;
        }
@@ -875,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;
@@ -975,6 +971,38 @@ xfs_mountfs(
        }
        xfs_mount_common(mp, sbp);
 
+       /*
+        * Check for a mismatched features2 values.  Older kernels
+        * read & wrote into the wrong sb offset for sb_features2
+        * on some platforms due to xfs_sb_t not being 64bit size aligned
+        * when sb_features2 was added, which made older superblock
+        * reading/writing routines swap it as a 64-bit value.
+        *
+        * For backwards compatibility, we make both slots equal.
+        *
+        * If we detect a mismatched field, we OR the set bits into the
+        * existing features2 field in case it has already been modified; we
+        * don't want to lose any features.  We then update the bad location
+        * with the ORed value so that older kernels will see any features2
+        * flags, and mark the two fields as needing updates once the
+        * transaction subsystem is online.
+        */
+       if (xfs_sb_has_mismatched_features2(sbp)) {
+               cmn_err(CE_WARN,
+                       "XFS: correcting sb_features alignment problem");
+               sbp->sb_features2 |= sbp->sb_bad_features2;
+               sbp->sb_bad_features2 = sbp->sb_features2;
+               update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
+
+               /*
+                * Re-check for ATTR2 in case it was found in bad_features2
+                * slot.
+                */
+               if (xfs_sb_version_hasattr2(&mp->m_sb))
+                       mp->m_flags |= XFS_MOUNT_ATTR2;
+
+       }
+
        /*
         * Check if sb_agblocks is aligned at stripe boundary
         * If sb_agblocks is NOT aligned turn off m_dalign since
@@ -1165,11 +1193,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
@@ -1881,16 +1908,18 @@ xfs_uuid_unmount(
 
 /*
  * Used to log changes to the superblock unit and width fields which could
- * be altered by the mount options. Only the first superblock is updated.
+ * be altered by the mount options, as well as any potential sb_features2
+ * fixup. 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,
@@ -2343,7 +2372,7 @@ out:
                spin_unlock(&mp->m_sb_lock);
 }
 
-int
+STATIC int
 xfs_icsb_modify_counters(
        xfs_mount_t     *mp,
        xfs_sb_field_t  field,