aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/zio.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/zio.c')
-rw-r--r--module/zfs/zio.c56
1 files changed, 49 insertions, 7 deletions
diff --git a/module/zfs/zio.c b/module/zfs/zio.c
index 892b86fba..e26822e34 100644
--- a/module/zfs/zio.c
+++ b/module/zfs/zio.c
@@ -2363,19 +2363,30 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
{
spa_t *spa = zio->io_spa;
int p;
+ boolean_t do_raw = !!(zio->io_flags & ZIO_FLAG_RAW);
- ASSERT0(zio->io_flags & ZIO_FLAG_RAW);
+ ASSERT(!(zio->io_bp_override && do_raw));
/*
* Note: we compare the original data, not the transformed data,
* because when zio->io_bp is an override bp, we will not have
* pushed the I/O transforms. That's an important optimization
* because otherwise we'd compress/encrypt all dmu_sync() data twice.
+ * However, we should never get a raw, override zio so in these
+ * cases we can compare the io_data directly. This is useful because
+ * it allows us to do dedup verification even if we don't have access
+ * to the original data (for instance, if the encryption keys aren't
+ * loaded).
*/
+
for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
zio_t *lio = dde->dde_lead_zio[p];
- if (lio != NULL) {
+ if (lio != NULL && do_raw) {
+ return (lio->io_size != zio->io_size ||
+ bcmp(zio->io_data, lio->io_data,
+ zio->io_size) != 0);
+ } else if (lio != NULL) {
return (lio->io_orig_size != zio->io_orig_size ||
bcmp(zio->io_orig_data, lio->io_orig_data,
zio->io_orig_size) != 0);
@@ -2385,7 +2396,36 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
ddt_phys_t *ddp = &dde->dde_phys[p];
- if (ddp->ddp_phys_birth != 0) {
+ if (ddp->ddp_phys_birth != 0 && do_raw) {
+ blkptr_t blk = *zio->io_bp;
+ uint64_t psize;
+ void *tmpbuf;
+ int error;
+
+ ddt_bp_fill(ddp, &blk, ddp->ddp_phys_birth);
+ psize = BP_GET_PSIZE(&blk);
+
+ if (psize != zio->io_size)
+ return (B_TRUE);
+
+ ddt_exit(ddt);
+
+ tmpbuf = zio_buf_alloc(psize);
+
+ error = zio_wait(zio_read(NULL, spa, &blk, tmpbuf,
+ psize, NULL, NULL, ZIO_PRIORITY_SYNC_READ,
+ ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE |
+ ZIO_FLAG_RAW, &zio->io_bookmark));
+
+ if (error == 0) {
+ if (bcmp(tmpbuf, zio->io_data, psize) != 0)
+ error = SET_ERROR(ENOENT);
+ }
+
+ zio_buf_free(tmpbuf, psize);
+ ddt_enter(ddt);
+ return (error != 0);
+ } else if (ddp->ddp_phys_birth != 0) {
arc_buf_t *abuf = NULL;
arc_flags_t aflags = ARC_FLAG_WAIT;
blkptr_t blk = *zio->io_bp;
@@ -2393,6 +2433,9 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
ddt_bp_fill(ddp, &blk, ddp->ddp_phys_birth);
+ if (BP_GET_LSIZE(&blk) != zio->io_orig_size)
+ return (B_TRUE);
+
ddt_exit(ddt);
error = arc_read(NULL, spa, &blk,
@@ -2401,10 +2444,9 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
&aflags, &zio->io_bookmark);
if (error == 0) {
- if (arc_buf_size(abuf) != zio->io_orig_size ||
- bcmp(abuf->b_data, zio->io_orig_data,
+ if (bcmp(abuf->b_data, zio->io_orig_data,
zio->io_orig_size) != 0)
- error = SET_ERROR(EEXIST);
+ error = SET_ERROR(ENOENT);
arc_buf_destroy(abuf, &abuf);
}
@@ -2511,7 +2553,7 @@ zio_ddt_write(zio_t *zio)
ASSERT(BP_GET_DEDUP(bp));
ASSERT(BP_GET_CHECKSUM(bp) == zp->zp_checksum);
ASSERT(BP_IS_HOLE(bp) || zio->io_bp_override);
- ASSERT0(zio->io_flags & ZIO_FLAG_RAW);
+ ASSERT(!(zio->io_bp_override && (zio->io_flags & ZIO_FLAG_RAW)));
ddt_enter(ddt);
dde = ddt_lookup(ddt, bp, B_TRUE);