- 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
This commit is contained in:
parent
96f4c1e385
commit
9838b8b0ee
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
error = 0;
|
||||
break;
|
||||
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)
|
||||
break;
|
||||
}
|
||||
if (error != 0)
|
||||
printf("ZFS: i/o error - all block copies unavailable\n");
|
||||
|
@ -181,14 +181,17 @@ zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset)
|
||||
}
|
||||
|
||||
static int
|
||||
zio_checksum_verify(const blkptr_t *bp, void *data, uint64_t offset,
|
||||
uint64_t size)
|
||||
zio_checksum_verify(const blkptr_t *bp, void *data)
|
||||
{
|
||||
unsigned int checksum = BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp);
|
||||
uint64_t size;
|
||||
unsigned int checksum;
|
||||
zio_checksum_info_t *ci;
|
||||
zio_cksum_t actual_cksum, expected_cksum, verifier;
|
||||
int byteswap;
|
||||
|
||||
checksum = BP_GET_CHECKSUM(bp);
|
||||
size = BP_GET_PSIZE(bp);
|
||||
|
||||
if (checksum >= ZIO_CHECKSUM_FUNCTIONS)
|
||||
return (EINVAL);
|
||||
ci = &zio_checksum_table[checksum];
|
||||
@ -206,7 +209,8 @@ zio_checksum_verify(const blkptr_t *bp, void *data, uint64_t offset,
|
||||
if (checksum == ZIO_CHECKSUM_GANG_HEADER)
|
||||
zio_checksum_gang_verifier(&verifier, bp);
|
||||
else if (checksum == ZIO_CHECKSUM_LABEL)
|
||||
zio_checksum_label_verifier(&verifier, offset);
|
||||
zio_checksum_label_verifier(&verifier,
|
||||
DVA_GET_OFFSET(BP_IDENTITY(bp)));
|
||||
else
|
||||
verifier = bp->blk_cksum;
|
||||
|
||||
@ -224,7 +228,6 @@ zio_checksum_verify(const blkptr_t *bp, void *data, uint64_t offset,
|
||||
byteswap_uint64_array(&expected_cksum,
|
||||
sizeof (zio_cksum_t));
|
||||
} else {
|
||||
ASSERT(!BP_IS_GANG(bp));
|
||||
expected_cksum = bp->blk_cksum;
|
||||
ci->ci_func[0](data, size, &actual_cksum);
|
||||
}
|
||||
@ -1243,7 +1246,7 @@ static int
|
||||
raidz_checksum_verify(const blkptr_t *bp, void *data, uint64_t size)
|
||||
{
|
||||
|
||||
return (zio_checksum_verify(bp, data, 0, size));
|
||||
return (zio_checksum_verify(bp, data));
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user