aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@sandeen.net>2013-10-11 15:14:05 -0400
committerBen Myers <bpm@sgi.com>2013-10-17 14:31:42 -0400
commit59e5a0e821d838854b3afd030d31f82cee3ecd58 (patch)
tree673ceea71ff3fdc366cbe7500dfb8c56c0ed643c
parent31625f28ad7be67701dc4cefcf52087addd88af4 (diff)
xfs: don't break from growfs ag update loop on error
When xfs_growfs_data_private() is updating backup superblocks, it bails out on the first error encountered, whether reading or writing: * If we get an error writing out the alternate superblocks, * just issue a warning and continue. The real work is * already done and committed. This can cause a problem later during repair, because repair looks at all superblocks, and picks the most prevalent one as correct. If we bail out early in the backup superblock loop, we can end up with more "bad" matching superblocks than good, and a post-growfs repair may revert the filesystem to the old geometry. With the combination of superblock verifiers and old bugs, we're more likely to encounter read errors due to verification. And perhaps even worse, we don't even properly write any of the newly-added superblocks in the new AGs. Even with this change, growfs will still say: xfs_growfs: XFS_IOC_FSGROWFSDATA xfsctl failed: Structure needs cleaning data blocks changed from 319815680 to 335216640 which might be confusing to the user, but it at least communicates that something has gone wrong, and dmesg will probably highlight the need for an xfs_repair. And this is still best-effort; if verifiers fail on more than half the backup supers, they may still "win" - but that's probably best left to repair to more gracefully handle by doing its own strict verification as part of the backup super "voting." Signed-off-by: Eric Sandeen <sandeen@redhat.com> Acked-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
-rw-r--r--fs/xfs/xfs_fsops.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index fdae4ec5f21b..76c7b2b4fa8d 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -155,7 +155,7 @@ xfs_growfs_data_private(
155 xfs_buf_t *bp; 155 xfs_buf_t *bp;
156 int bucket; 156 int bucket;
157 int dpct; 157 int dpct;
158 int error; 158 int error, saved_error = 0;
159 xfs_agnumber_t nagcount; 159 xfs_agnumber_t nagcount;
160 xfs_agnumber_t nagimax = 0; 160 xfs_agnumber_t nagimax = 0;
161 xfs_rfsblock_t nb, nb_mod; 161 xfs_rfsblock_t nb, nb_mod;
@@ -498,29 +498,33 @@ xfs_growfs_data_private(
498 error = ENOMEM; 498 error = ENOMEM;
499 } 499 }
500 500
501 /*
502 * If we get an error reading or writing alternate superblocks,
503 * continue. xfs_repair chooses the "best" superblock based
504 * on most matches; if we break early, we'll leave more
505 * superblocks un-updated than updated, and xfs_repair may
506 * pick them over the properly-updated primary.
507 */
501 if (error) { 508 if (error) {
502 xfs_warn(mp, 509 xfs_warn(mp,
503 "error %d reading secondary superblock for ag %d", 510 "error %d reading secondary superblock for ag %d",
504 error, agno); 511 error, agno);
505 break; 512 saved_error = error;
513 continue;
506 } 514 }
507 xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS); 515 xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS);
508 516
509 /*
510 * If we get an error writing out the alternate superblocks,
511 * just issue a warning and continue. The real work is
512 * already done and committed.
513 */
514 error = xfs_bwrite(bp); 517 error = xfs_bwrite(bp);
515 xfs_buf_relse(bp); 518 xfs_buf_relse(bp);
516 if (error) { 519 if (error) {
517 xfs_warn(mp, 520 xfs_warn(mp,
518 "write error %d updating secondary superblock for ag %d", 521 "write error %d updating secondary superblock for ag %d",
519 error, agno); 522 error, agno);
520 break; /* no point in continuing */ 523 saved_error = error;
524 continue;
521 } 525 }
522 } 526 }
523 return error; 527 return saved_error ? saved_error : error;
524 528
525 error0: 529 error0:
526 xfs_trans_cancel(tp, XFS_TRANS_ABORT); 530 xfs_trans_cancel(tp, XFS_TRANS_ABORT);