xfs: fix bad_features2 fixups for the root filesystem
authorChristoph Hellwig <hch@lst.de>
Mon, 19 Jan 2009 01:04:07 +0000 (02:04 +0100)
committerLachlan McIlroy <lachlan@sgi.com>
Mon, 19 Jan 2009 03:45:04 +0000 (14:45 +1100)
Currently the bad_features2 fixup and the alignment updates in the superblock
are skipped if we mount a filesystem read-only.  But for the root filesystem
the typical case is to mount read-only first and only later remount writeable
so we'll never perform this update at all.  It's not a big problem but means
the logs of people needing the fixup get spammed at every boot because they
never happen on disk.

Reported-by: Arkadiusz Miskiewicz <arekm@maven.pl>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <david@fromorbit.com>
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h

index 95a971080368d3ab0136b66bdef1e5f37f8dfc86..c71e226da7f5c4bd36f337b06e5315228cea9a67 100644 (file)
@@ -1197,6 +1197,7 @@ xfs_fs_remount(
        struct xfs_mount        *mp = XFS_M(sb);
        substring_t             args[MAX_OPT_ARGS];
        char                    *p;
+       int                     error;
 
        while ((p = strsep(&options, ",")) != NULL) {
                int token;
@@ -1247,11 +1248,25 @@ xfs_fs_remount(
                }
        }
 
-       /* rw/ro -> rw */
+       /* ro -> rw */
        if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) {
                mp->m_flags &= ~XFS_MOUNT_RDONLY;
                if (mp->m_flags & XFS_MOUNT_BARRIER)
                        xfs_mountfs_check_barriers(mp);
+
+               /*
+                * If this is the first remount to writeable state we
+                * might have some superblock changes to update.
+                */
+               if (mp->m_update_flags) {
+                       error = xfs_mount_log_sb(mp, mp->m_update_flags);
+                       if (error) {
+                               cmn_err(CE_WARN,
+                                       "XFS: failed to write sb changes");
+                               return error;
+                       }
+                       mp->m_update_flags = 0;
+               }
        }
 
        /* rw -> ro */
index 3c97c6463a4e418af83145d350d7aac3e49cc617..35300250e86d55fa2d44c7b3b15173fd8aa93767 100644 (file)
@@ -45,7 +45,6 @@
 #include "xfs_fsops.h"
 #include "xfs_utils.h"
 
-STATIC int     xfs_mount_log_sb(xfs_mount_t *, __int64_t);
 STATIC int     xfs_uuid_mount(xfs_mount_t *);
 STATIC void    xfs_unmountfs_wait(xfs_mount_t *);
 
@@ -682,7 +681,7 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount)
  * Update alignment values based on mount options and sb values
  */
 STATIC int
-xfs_update_alignment(xfs_mount_t *mp, __uint64_t *update_flags)
+xfs_update_alignment(xfs_mount_t *mp)
 {
        xfs_sb_t        *sbp = &(mp->m_sb);
 
@@ -736,11 +735,11 @@ xfs_update_alignment(xfs_mount_t *mp, __uint64_t *update_flags)
                if (xfs_sb_version_hasdalign(sbp)) {
                        if (sbp->sb_unit != mp->m_dalign) {
                                sbp->sb_unit = mp->m_dalign;
-                               *update_flags |= XFS_SB_UNIT;
+                               mp->m_update_flags |= XFS_SB_UNIT;
                        }
                        if (sbp->sb_width != mp->m_swidth) {
                                sbp->sb_width = mp->m_swidth;
-                               *update_flags |= XFS_SB_WIDTH;
+                               mp->m_update_flags |= XFS_SB_WIDTH;
                        }
                }
        } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN &&
@@ -905,7 +904,6 @@ xfs_mountfs(
        xfs_sb_t        *sbp = &(mp->m_sb);
        xfs_inode_t     *rip;
        __uint64_t      resblks;
-       __int64_t       update_flags = 0LL;
        uint            quotamount, quotaflags;
        int             uuid_mounted = 0;
        int             error = 0;
@@ -933,7 +931,7 @@ xfs_mountfs(
                        "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;
+               mp->m_update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
 
                /*
                 * Re-check for ATTR2 in case it was found in bad_features2
@@ -947,11 +945,11 @@ xfs_mountfs(
        if (xfs_sb_version_hasattr2(&mp->m_sb) &&
           (mp->m_flags & XFS_MOUNT_NOATTR2)) {
                xfs_sb_version_removeattr2(&mp->m_sb);
-               update_flags |= XFS_SB_FEATURES2;
+               mp->m_update_flags |= XFS_SB_FEATURES2;
 
                /* update sb_versionnum for the clearing of the morebits */
                if (!sbp->sb_features2)
-                       update_flags |= XFS_SB_VERSIONNUM;
+                       mp->m_update_flags |= XFS_SB_VERSIONNUM;
        }
 
        /*
@@ -960,7 +958,7 @@ xfs_mountfs(
         * allocator alignment is within an ag, therefore ag has
         * to be aligned at stripe boundary.
         */
-       error = xfs_update_alignment(mp, &update_flags);
+       error = xfs_update_alignment(mp);
        if (error)
                goto error1;
 
@@ -1137,10 +1135,12 @@ xfs_mountfs(
        }
 
        /*
-        * If fs is not mounted readonly, then update the superblock changes.
+        * If this is a read-only mount defer the superblock updates until
+        * the next remount into writeable mode.  Otherwise we would never
+        * perform the update e.g. for the root filesystem.
         */
-       if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) {
-               error = xfs_mount_log_sb(mp, update_flags);
+       if (mp->m_update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) {
+               error = xfs_mount_log_sb(mp, mp->m_update_flags);
                if (error) {
                        cmn_err(CE_WARN, "XFS: failed to write sb changes");
                        goto error4;
@@ -1820,7 +1820,7 @@ xfs_uuid_mount(
  * be altered by the mount options, as well as any potential sb_features2
  * fixup. Only the first superblock is updated.
  */
-STATIC int
+int
 xfs_mount_log_sb(
        xfs_mount_t     *mp,
        __int64_t       fields)
index c1e0284673272990d971396c71f937e4cc665aee..e37eff6761eb4a573d672a2aeadcf389cdd4e6ec 100644 (file)
@@ -327,6 +327,8 @@ typedef struct xfs_mount {
        spinlock_t              m_sync_lock;    /* work item list lock */
        int                     m_sync_seq;     /* sync thread generation no. */
        wait_queue_head_t       m_wait_single_sync_task;
+       __int64_t               m_update_flags; /* sb flags we need to update
+                                                  on the next remount,rw */
 } xfs_mount_t;
 
 /*
@@ -514,6 +516,7 @@ extern int  xfs_mod_incore_sb_unlocked(xfs_mount_t *, xfs_sb_field_t,
                        int64_t, int);
 extern int     xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
                        uint, int);
+extern int     xfs_mount_log_sb(xfs_mount_t *, __int64_t);
 extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
 extern int     xfs_readsb(xfs_mount_t *, int);
 extern void    xfs_freesb(xfs_mount_t *);