Author: pjd
Date: Thu Oct 20 15:42:38 2011
New Revision: 226568
URL: http://svn.freebsd.org/changeset/base/226568

Log:
  - 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

Modified:
  head/sys/boot/zfs/zfsimpl.c
  head/sys/cddl/boot/zfs/zfssubr.c

Modified: head/sys/boot/zfs/zfsimpl.c
==============================================================================
--- head/sys/boot/zfs/zfsimpl.c Thu Oct 20 15:34:17 2011        (r226567)
+++ head/sys/boot/zfs/zfsimpl.c Thu Oct 20 15:42:38 2011        (r226568)
@@ -347,7 +347,7 @@ vdev_read_phys(vdev_t *vdev, const blkpt
        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 
        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 
                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);
+       /* 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);
 
-       if (vdev->v_read(vdev, bp, &zio_gb, offset, SPA_GANGBLOCKSIZE))
+       /* 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,
                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");

Modified: head/sys/cddl/boot/zfs/zfssubr.c
==============================================================================
--- head/sys/cddl/boot/zfs/zfssubr.c    Thu Oct 20 15:34:17 2011        
(r226567)
+++ head/sys/cddl/boot/zfs/zfssubr.c    Thu Oct 20 15:42:38 2011        
(r226568)
@@ -181,14 +181,17 @@ zio_checksum_label_verifier(zio_cksum_t 
 }
 
 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, 
                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, 
                        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));
 }
 
 /*
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to