diff options
author | pjd <pjd@FreeBSD.org> | 2011-10-20 15:42:38 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2011-10-20 15:42:38 +0000 |
commit | 57635fa52e9f95b6a653902df3016f529eecafed (patch) | |
tree | 34bb2766b10bb39c5ddb972e29c822c9b1a3e318 /sys/boot | |
parent | 7277eaaa56b5b705b2fa4c0c088241743754e1e8 (diff) | |
download | FreeBSD-src-57635fa52e9f95b6a653902df3016f529eecafed.zip FreeBSD-src-57635fa52e9f95b6a653902df3016f529eecafed.tar.gz |
- Correctly read gang header from raidz.
- Decompress assembled gang block data if compressed.
- Verify checksum of a gang header.
- Verify checksum of assembled gang block data.
- Verify checksum of uber block.
Submitted by: avg
MFC after: 3 days
Diffstat (limited to 'sys/boot')
-rw-r--r-- | sys/boot/zfs/zfsimpl.c | 102 |
1 files changed, 51 insertions, 51 deletions
diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c index dd721ed..c97c2de 100644 --- a/sys/boot/zfs/zfsimpl.c +++ b/sys/boot/zfs/zfsimpl.c @@ -347,7 +347,7 @@ vdev_read_phys(vdev_t *vdev, const blkptr_t *bp, void *buf, rc = vdev->v_phys_read(vdev, vdev->v_read_priv, offset, buf, psize); if (rc) return (rc); - if (bp && zio_checksum_verify(bp, buf, offset, psize)) + if (bp && zio_checksum_verify(bp, buf)) return (EIO); return (0); @@ -798,6 +798,7 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap) BP_SET_PSIZE(&bp, sizeof(vdev_phys_t)); BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); + DVA_SET_OFFSET(BP_IDENTITY(&bp), off); ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); if (vdev_read_phys(&vtmp, &bp, vdev_label, off, 0)) return (EIO); @@ -940,7 +941,7 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap) BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); - if (vdev_read_phys(vdev, NULL, upbuf, off, VDEV_UBERBLOCK_SIZE(vdev))) + if (vdev_read_phys(vdev, &bp, upbuf, off, 0)) continue; if (up->ub_magic != UBERBLOCK_MAGIC) @@ -973,35 +974,39 @@ ilog2(int n) } static int -zio_read_gang(spa_t *spa, const blkptr_t *bp, const dva_t *dva, void *buf) +zio_read_gang(spa_t *spa, const blkptr_t *bp, void *buf) { + blkptr_t gbh_bp; zio_gbh_phys_t zio_gb; - vdev_t *vdev; - int vdevid; - off_t offset; + char *pbuf; int i; - vdevid = DVA_GET_VDEV(dva); - offset = DVA_GET_OFFSET(dva); - STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) - if (vdev->v_id == vdevid) - break; - if (!vdev || !vdev->v_read) - return (EIO); - - if (vdev->v_read(vdev, bp, &zio_gb, offset, SPA_GANGBLOCKSIZE)) + /* Artificial BP for gang block header. */ + gbh_bp = *bp; + BP_SET_PSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); + BP_SET_LSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); + BP_SET_CHECKSUM(&gbh_bp, ZIO_CHECKSUM_GANG_HEADER); + BP_SET_COMPRESS(&gbh_bp, ZIO_COMPRESS_OFF); + for (i = 0; i < SPA_DVAS_PER_BP; i++) + DVA_SET_GANG(&gbh_bp.blk_dva[i], 0); + + /* Read gang header block using the artificial BP. */ + if (zio_read(spa, &gbh_bp, &zio_gb)) return (EIO); + pbuf = buf; for (i = 0; i < SPA_GBH_NBLKPTRS; i++) { blkptr_t *gbp = &zio_gb.zg_blkptr[i]; if (BP_IS_HOLE(gbp)) continue; - if (zio_read(spa, gbp, buf)) + if (zio_read(spa, gbp, pbuf)) return (EIO); - buf = (char*)buf + BP_GET_PSIZE(gbp); + pbuf += BP_GET_PSIZE(gbp); } - + + if (zio_checksum_verify(bp, buf)) + return (EIO); return (0); } @@ -1024,46 +1029,41 @@ zio_read(spa_t *spa, const blkptr_t *bp, void *buf) if (!dva->dva_word[0] && !dva->dva_word[1]) continue; - if (DVA_GET_GANG(dva)) { - error = zio_read_gang(spa, bp, dva, buf); - if (error != 0) - continue; - } else { - vdevid = DVA_GET_VDEV(dva); - offset = DVA_GET_OFFSET(dva); - STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) { - if (vdev->v_id == vdevid) - break; - } - if (!vdev || !vdev->v_read) - continue; + vdevid = DVA_GET_VDEV(dva); + offset = DVA_GET_OFFSET(dva); + STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) { + if (vdev->v_id == vdevid) + break; + } + if (!vdev || !vdev->v_read) + continue; - size = BP_GET_PSIZE(bp); + size = BP_GET_PSIZE(bp); + if (vdev->v_read == vdev_raidz_read) { align = 1ULL << vdev->v_top->v_ashift; if (P2PHASE(size, align) != 0) size = P2ROUNDUP(size, align); - if (size != BP_GET_PSIZE(bp) || cpfunc != ZIO_COMPRESS_OFF) - pbuf = zfs_alloc(size); - else - pbuf = buf; + } + if (size != BP_GET_PSIZE(bp) || cpfunc != ZIO_COMPRESS_OFF) + pbuf = zfs_alloc(size); + else + pbuf = buf; + if (DVA_GET_GANG(dva)) + error = zio_read_gang(spa, bp, pbuf); + else error = vdev->v_read(vdev, bp, pbuf, offset, size); - if (error == 0) { - if (cpfunc != ZIO_COMPRESS_OFF) { - error = zio_decompress_data(cpfunc, - pbuf, BP_GET_PSIZE(bp), buf, - BP_GET_LSIZE(bp)); - } else if (size != BP_GET_PSIZE(bp)) { - bcopy(pbuf, buf, BP_GET_PSIZE(bp)); - } - } - if (buf != pbuf) - zfs_free(pbuf, size); - if (error != 0) - continue; + if (error == 0) { + if (cpfunc != ZIO_COMPRESS_OFF) + error = zio_decompress_data(cpfunc, pbuf, + BP_GET_PSIZE(bp), buf, BP_GET_LSIZE(bp)); + else if (size != BP_GET_PSIZE(bp)) + bcopy(pbuf, buf, BP_GET_PSIZE(bp)); } - error = 0; - break; + if (buf != pbuf) + zfs_free(pbuf, size); + if (error == 0) + break; } if (error != 0) printf("ZFS: i/o error - all block copies unavailable\n"); |