aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2010-01-25 23:08:49 -0500
committerDave Chinner <david@fromorbit.com>2010-01-25 23:08:49 -0500
commitcbe132a8bdcff0f9afd9060948fb50597c7400b8 (patch)
tree2bf70f1520b6cc60fb3097763dde24600466369d /fs
parent9b00f30762fe9f914eb6e03057a616ed63a4e8ca (diff)
xfs: don't hold onto reserved blocks on remount,ro
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@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c28
-rw-r--r--fs/xfs/xfs_mount.h1
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 9f2e398a5616..e9c21454b9e2 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1318,6 +1318,8 @@ xfs_fs_remount(
1318 1318
1319 /* ro -> rw */ 1319 /* ro -> rw */
1320 if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) { 1320 if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) {
1321 __uint64_t resblks;
1322
1321 mp->m_flags &= ~XFS_MOUNT_RDONLY; 1323 mp->m_flags &= ~XFS_MOUNT_RDONLY;
1322 if (mp->m_flags & XFS_MOUNT_BARRIER) 1324 if (mp->m_flags & XFS_MOUNT_BARRIER)
1323 xfs_mountfs_check_barriers(mp); 1325 xfs_mountfs_check_barriers(mp);
@@ -1335,11 +1337,37 @@ xfs_fs_remount(
1335 } 1337 }
1336 mp->m_update_flags = 0; 1338 mp->m_update_flags = 0;
1337 } 1339 }
1340
1341 /*
1342 * Fill out the reserve pool if it is empty. Use the stashed
1343 * value if it is non-zero, otherwise go with the default.
1344 */
1345 if (mp->m_resblks_save) {
1346 resblks = mp->m_resblks_save;
1347 mp->m_resblks_save = 0;
1348 } else {
1349 resblks = mp->m_sb.sb_dblocks;
1350 do_div(resblks, 20);
1351 resblks = min_t(__uint64_t, resblks, 1024);
1352 }
1353 xfs_reserve_blocks(mp, &resblks, NULL);
1338 } 1354 }
1339 1355
1340 /* rw -> ro */ 1356 /* rw -> ro */
1341 if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) { 1357 if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) {
1358 /*
1359 * After we have synced the data but before we sync the
1360 * metadata, we need to free up the reserve block pool so that
1361 * the used block count in the superblock on disk is correct at
1362 * the end of the remount. Stash the current reserve pool size
1363 * so that if we get remounted rw, we can return it to the same
1364 * size.
1365 */
1366 __uint64_t resblks = 0;
1367
1342 xfs_quiesce_data(mp); 1368 xfs_quiesce_data(mp);
1369 mp->m_resblks_save = mp->m_resblks;
1370 xfs_reserve_blocks(mp, &resblks, NULL);
1343 xfs_quiesce_attr(mp); 1371 xfs_quiesce_attr(mp);
1344 mp->m_flags |= XFS_MOUNT_RDONLY; 1372 mp->m_flags |= XFS_MOUNT_RDONLY;
1345 } 1373 }
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index f4d1441f3f15..02d45f213e58 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -225,6 +225,7 @@ typedef struct xfs_mount {
225 __uint64_t m_maxioffset; /* maximum inode offset */ 225 __uint64_t m_maxioffset; /* maximum inode offset */
226 __uint64_t m_resblks; /* total reserved blocks */ 226 __uint64_t m_resblks; /* total reserved blocks */
227 __uint64_t m_resblks_avail;/* available reserved blocks */ 227 __uint64_t m_resblks_avail;/* available reserved blocks */
228 __uint64_t m_resblks_save; /* reserved blks @ remount,ro */
228 int m_dalign; /* stripe unit */ 229 int m_dalign; /* stripe unit */
229 int m_swidth; /* stripe width */ 230 int m_swidth; /* stripe width */
230 int m_sinoalign; /* stripe unit inode alignment */ 231 int m_sinoalign; /* stripe unit inode alignment */