]> granicus.if.org Git - zfs/commitdiff
Enable raw writes to perform dedup with verification
authorTom Caputi <tcaputi@datto.com>
Tue, 13 Sep 2016 01:34:19 +0000 (21:34 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 13 Sep 2016 16:59:04 +0000 (09:59 -0700)
Reviewed by: Dan Kimmel <dan.kimmel@delphix.com>
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: David Quigley <david.quigley@intel.com>
Signed-off-by: Tom Caputi <tcaputi@datto.com>
Issue #5078

module/zfs/zio.c

index 892b86fbaf43b4a41e8adfc979343a04d6f05753..e26822e34d114dd7ce484d27e32845b22ab665a1 100644 (file)
@@ -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);