Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 15922f5

Browse files
Dave ChinnerChandan Babu R
authored andcommitted
xfs: allow sunit mount option to repair bad primary sb stripe values
If a filesystem has a busted stripe alignment configuration on disk (e.g. because broken RAID firmware told mkfs that swidth was smaller than sunit), then the filesystem will refuse to mount due to the stripe validation failing. This failure is triggering during distro upgrades from old kernels lacking this check to newer kernels with this check, and currently the only way to fix it is with offline xfs_db surgery. This runtime validity checking occurs when we read the superblock for the first time and causes the mount to fail immediately. This prevents the rewrite of stripe unit/width via mount options that occurs later in the mount process. Hence there is no way to recover this situation without resorting to offline xfs_db rewrite of the values. However, we parse the mount options long before we read the superblock, and we know if the mount has been asked to re-write the stripe alignment configuration when we are reading the superblock and verifying it for the first time. Hence we can conditionally ignore stripe verification failures if the mount options specified will correct the issue. We validate that the new stripe unit/width are valid before we overwrite the superblock values, so we can ignore the invalid config at verification and fail the mount later if the new values are not valid. This, at least, gives users the chance of correcting the issue after a kernel upgrade without having to resort to xfs-db hacks. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: "Darrick J. Wong" <djwong@kernel.org> Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
1 parent 4cece76 commit 15922f5

File tree

2 files changed

+34
-11
lines changed

2 files changed

+34
-11
lines changed

fs/xfs/libxfs/xfs_sb.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,8 @@ xfs_validate_sb_common(
530530
}
531531

532532
if (!xfs_validate_stripe_geometry(mp, XFS_FSB_TO_B(mp, sbp->sb_unit),
533-
XFS_FSB_TO_B(mp, sbp->sb_width), 0, false))
533+
XFS_FSB_TO_B(mp, sbp->sb_width), 0,
534+
xfs_buf_daddr(bp) == XFS_SB_DADDR, false))
534535
return -EFSCORRUPTED;
535536

536537
/*
@@ -1323,61 +1324,82 @@ xfs_sb_get_secondary(
13231324
}
13241325

13251326
/*
1326-
* sunit, swidth, sectorsize(optional with 0) should be all in bytes,
1327-
* so users won't be confused by values in error messages.
1327+
* sunit, swidth, sectorsize(optional with 0) should be all in bytes, so users
1328+
* won't be confused by values in error messages. This function returns false
1329+
* if the stripe geometry is invalid and the caller is unable to repair the
1330+
* stripe configuration later in the mount process.
13281331
*/
13291332
bool
13301333
xfs_validate_stripe_geometry(
13311334
struct xfs_mount *mp,
13321335
__s64 sunit,
13331336
__s64 swidth,
13341337
int sectorsize,
1338+
bool may_repair,
13351339
bool silent)
13361340
{
13371341
if (swidth > INT_MAX) {
13381342
if (!silent)
13391343
xfs_notice(mp,
13401344
"stripe width (%lld) is too large", swidth);
1341-
return false;
1345+
goto check_override;
13421346
}
13431347

13441348
if (sunit > swidth) {
13451349
if (!silent)
13461350
xfs_notice(mp,
13471351
"stripe unit (%lld) is larger than the stripe width (%lld)", sunit, swidth);
1348-
return false;
1352+
goto check_override;
13491353
}
13501354

13511355
if (sectorsize && (int)sunit % sectorsize) {
13521356
if (!silent)
13531357
xfs_notice(mp,
13541358
"stripe unit (%lld) must be a multiple of the sector size (%d)",
13551359
sunit, sectorsize);
1356-
return false;
1360+
goto check_override;
13571361
}
13581362

13591363
if (sunit && !swidth) {
13601364
if (!silent)
13611365
xfs_notice(mp,
13621366
"invalid stripe unit (%lld) and stripe width of 0", sunit);
1363-
return false;
1367+
goto check_override;
13641368
}
13651369

13661370
if (!sunit && swidth) {
13671371
if (!silent)
13681372
xfs_notice(mp,
13691373
"invalid stripe width (%lld) and stripe unit of 0", swidth);
1370-
return false;
1374+
goto check_override;
13711375
}
13721376

13731377
if (sunit && (int)swidth % (int)sunit) {
13741378
if (!silent)
13751379
xfs_notice(mp,
13761380
"stripe width (%lld) must be a multiple of the stripe unit (%lld)",
13771381
swidth, sunit);
1378-
return false;
1382+
goto check_override;
13791383
}
13801384
return true;
1385+
1386+
check_override:
1387+
if (!may_repair)
1388+
return false;
1389+
/*
1390+
* During mount, mp->m_dalign will not be set unless the sunit mount
1391+
* option was set. If it was set, ignore the bad stripe alignment values
1392+
* and allow the validation and overwrite later in the mount process to
1393+
* attempt to overwrite the bad stripe alignment values with the values
1394+
* supplied by mount options.
1395+
*/
1396+
if (!mp->m_dalign)
1397+
return false;
1398+
if (!silent)
1399+
xfs_notice(mp,
1400+
"Will try to correct with specified mount options sunit (%d) and swidth (%d)",
1401+
BBTOB(mp->m_dalign), BBTOB(mp->m_swidth));
1402+
return true;
13811403
}
13821404

13831405
/*

fs/xfs/libxfs/xfs_sb.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ extern int xfs_sb_get_secondary(struct xfs_mount *mp,
3535
struct xfs_trans *tp, xfs_agnumber_t agno,
3636
struct xfs_buf **bpp);
3737

38-
extern bool xfs_validate_stripe_geometry(struct xfs_mount *mp,
39-
__s64 sunit, __s64 swidth, int sectorsize, bool silent);
38+
bool xfs_validate_stripe_geometry(struct xfs_mount *mp,
39+
__s64 sunit, __s64 swidth, int sectorsize, bool may_repair,
40+
bool silent);
4041

4142
uint8_t xfs_compute_rextslog(xfs_rtbxlen_t rtextents);
4243

0 commit comments

Comments
 (0)