xfs
[Top] [All Lists]

[PATCH 16/19] xfs: don't hold onto reserved blocks on remount,ro

To: stable@xxxxxxxxxx
Subject: [PATCH 16/19] xfs: don't hold onto reserved blocks on remount,ro
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Fri, 12 Mar 2010 09:42:14 +1100
Cc: xfs@xxxxxxxxxxx
In-reply-to: <1268347337-7160-1-git-send-email-david@xxxxxxxxxxxxx>
References: <1268347337-7160-1-git-send-email-david@xxxxxxxxxxxxx>
>From cbe132a8bdcff0f9afd9060948fb50597c7400b8
Date: Tue, 26 Jan 2010 15:08:49 +1100
If we hold onto reserved blocks when doing a remount,ro we end
up writing the blocks used count to disk that includes the reserved
blocks. Reserved blocks are not actually used, so this results in
the values in the superblock being incorrect.

Hence if we run xfs_check or xfs_repair -n while the filesystem is
mounted remount,ro we end up with an inconsistent filesystem being
reported. Also, running xfs_copy on the remount,ro filesystem will
result in an inconsistent image being generated.

To fix this, unreserve the blocks when doing the remount,ro, and
reserved them again on remount,rw. This way a remount,ro filesystem
will appear consistent on disk to all utilities.

Signed-off-by: Dave Chinner <david@xxxxxxxxxxxxx>
Reviewed-by: Christoph Hellwig <hch@xxxxxx>
---
 fs/xfs/linux-2.6/xfs_super.c |   28 ++++++++++++++++++++++++++++
 fs/xfs/xfs_mount.h           |    1 +
 2 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index ea7a59a..aae1249 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1323,6 +1323,8 @@ xfs_fs_remount(
 
        /* ro -> rw */
        if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) {
+               __uint64_t resblks;
+
                mp->m_flags &= ~XFS_MOUNT_RDONLY;
                if (mp->m_flags & XFS_MOUNT_BARRIER)
                        xfs_mountfs_check_barriers(mp);
@@ -1340,11 +1342,37 @@ xfs_fs_remount(
                        }
                        mp->m_update_flags = 0;
                }
+
+               /*
+                * Fill out the reserve pool if it is empty. Use the stashed
+                * value if it is non-zero, otherwise go with the default.
+                */
+               if (mp->m_resblks_save) {
+                       resblks = mp->m_resblks_save;
+                       mp->m_resblks_save = 0;
+               } else {
+                       resblks = mp->m_sb.sb_dblocks;
+                       do_div(resblks, 20);
+                       resblks = min_t(__uint64_t, resblks, 1024);
+               }
+               xfs_reserve_blocks(mp, &resblks, NULL);
        }
 
        /* rw -> ro */
        if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) {
+               /*
+                * After we have synced the data but before we sync the
+                * metadata, we need to free up the reserve block pool so that
+                * the used block count in the superblock on disk is correct at
+                * the end of the remount. Stash the current reserve pool size
+                * so that if we get remounted rw, we can return it to the same
+                * size.
+                */
+               __uint64_t resblks = 0;
+
                xfs_quiesce_data(mp);
+               mp->m_resblks_save = mp->m_resblks;
+               xfs_reserve_blocks(mp, &resblks, NULL);
                xfs_quiesce_attr(mp);
                mp->m_flags |= XFS_MOUNT_RDONLY;
        }
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index a6c023b..1e6094f 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -209,6 +209,7 @@ typedef struct xfs_mount {
        __uint64_t              m_maxioffset;   /* maximum inode offset */
        __uint64_t              m_resblks;      /* total reserved blocks */
        __uint64_t              m_resblks_avail;/* available reserved blocks */
+       __uint64_t              m_resblks_save; /* reserved blks @ remount,ro */
        int                     m_dalign;       /* stripe unit */
        int                     m_swidth;       /* stripe width */
        int                     m_sinoalign;    /* stripe unit inode alignment 
*/
-- 
1.6.5

<Prev in Thread] Current Thread [Next in Thread>