aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@redhat.com>2014-02-18 23:39:16 -0500
committerDave Chinner <david@fromorbit.com>2014-02-18 23:39:16 -0500
commitdaba5427dad6b260256053f914de2c0b79f7a79f (patch)
tree65f5c19a6ba3c2d65ff69099cd48f14cb41342fe
parent82daa86a77e592b38b7fa3f533173d1a3c1299a1 (diff)
xfs: skip verification on initial "guess" superblock read
When xfs_readsb() does the very first read of the superblock, it makes a guess at the length of the buffer, based on the sector size of the underlying storage. This may or may not match the filesystem sector size in sb_sectsize, so we can't i.e. do a CRC check on it; it might be too short. In fact, mounting a filesystem with sb_sectsize larger than the device sector size will cause a mount failure if CRCs are enabled, because we are checksumming a length which exceeds the buffer passed to it. So always read twice; the first time we read with NULL buffer ops to skip verification; then set the proper read length, hook up the proper verifier, and give it another go. Once we are sure that we've got the right buffer length, we can also use bp->b_length in the xfs_sb_read_verify, rather than the less-trusted on-disk sectorsize for secondary superblocks. Before this we ran the risk of passing junk to the crc32c routines, which didn't always handle extreme values. Signed-off-by: Eric Sandeen <sandeen@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/xfs_mount.c24
-rw-r--r--fs/xfs/xfs_sb.c3
2 files changed, 17 insertions, 10 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 02df7b408a26..f96c05669a9e 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -282,22 +282,29 @@ xfs_readsb(
282 struct xfs_sb *sbp = &mp->m_sb; 282 struct xfs_sb *sbp = &mp->m_sb;
283 int error; 283 int error;
284 int loud = !(flags & XFS_MFSI_QUIET); 284 int loud = !(flags & XFS_MFSI_QUIET);
285 const struct xfs_buf_ops *buf_ops;
285 286
286 ASSERT(mp->m_sb_bp == NULL); 287 ASSERT(mp->m_sb_bp == NULL);
287 ASSERT(mp->m_ddev_targp != NULL); 288 ASSERT(mp->m_ddev_targp != NULL);
288 289
289 /* 290 /*
291 * For the initial read, we must guess at the sector
292 * size based on the block device. It's enough to
293 * get the sb_sectsize out of the superblock and
294 * then reread with the proper length.
295 * We don't verify it yet, because it may not be complete.
296 */
297 sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
298 buf_ops = NULL;
299
300 /*
290 * Allocate a (locked) buffer to hold the superblock. 301 * Allocate a (locked) buffer to hold the superblock.
291 * This will be kept around at all times to optimize 302 * This will be kept around at all times to optimize
292 * access to the superblock. 303 * access to the superblock.
293 */ 304 */
294 sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
295
296reread: 305reread:
297 bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR, 306 bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
298 BTOBB(sector_size), 0, 307 BTOBB(sector_size), 0, buf_ops);
299 loud ? &xfs_sb_buf_ops
300 : &xfs_sb_quiet_buf_ops);
301 if (!bp) { 308 if (!bp) {
302 if (loud) 309 if (loud)
303 xfs_warn(mp, "SB buffer read failed"); 310 xfs_warn(mp, "SB buffer read failed");
@@ -328,12 +335,13 @@ reread:
328 } 335 }
329 336
330 /* 337 /*
331 * If device sector size is smaller than the superblock size, 338 * Re-read the superblock so the buffer is correctly sized,
332 * re-read the superblock so the buffer is correctly sized. 339 * and properly verified.
333 */ 340 */
334 if (sector_size < sbp->sb_sectsize) { 341 if (buf_ops == NULL) {
335 xfs_buf_relse(bp); 342 xfs_buf_relse(bp);
336 sector_size = sbp->sb_sectsize; 343 sector_size = sbp->sb_sectsize;
344 buf_ops = loud ? &xfs_sb_buf_ops : &xfs_sb_quiet_buf_ops;
337 goto reread; 345 goto reread;
338 } 346 }
339 347
diff --git a/fs/xfs/xfs_sb.c b/fs/xfs/xfs_sb.c
index 5071ccb67f07..359b19a4df42 100644
--- a/fs/xfs/xfs_sb.c
+++ b/fs/xfs/xfs_sb.c
@@ -611,7 +611,7 @@ xfs_sb_read_verify(
611 XFS_SB_VERSION_5) || 611 XFS_SB_VERSION_5) ||
612 dsb->sb_crc != 0)) { 612 dsb->sb_crc != 0)) {
613 613
614 if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize), 614 if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
615 offsetof(struct xfs_sb, sb_crc))) { 615 offsetof(struct xfs_sb, sb_crc))) {
616 /* Only fail bad secondaries on a known V5 filesystem */ 616 /* Only fail bad secondaries on a known V5 filesystem */
617 if (bp->b_bn == XFS_SB_DADDR || 617 if (bp->b_bn == XFS_SB_DADDR ||
@@ -644,7 +644,6 @@ xfs_sb_quiet_read_verify(
644{ 644{
645 struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); 645 struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp);
646 646
647
648 if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) { 647 if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) {
649 /* XFS filesystem, verify noisily! */ 648 /* XFS filesystem, verify noisily! */
650 xfs_sb_read_verify(bp); 649 xfs_sb_read_verify(bp);