summaryrefslogtreecommitdiffstats
path: root/sys/boot
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2011-10-20 15:42:38 +0000
committerpjd <pjd@FreeBSD.org>2011-10-20 15:42:38 +0000
commit57635fa52e9f95b6a653902df3016f529eecafed (patch)
tree34bb2766b10bb39c5ddb972e29c822c9b1a3e318 /sys/boot
parent7277eaaa56b5b705b2fa4c0c088241743754e1e8 (diff)
downloadFreeBSD-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.c102
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");
OpenPOWER on IntegriCloud