]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Fix zdb -R decompression
authorChunwei Chen <david.chen@nutanix.com>
Fri, 2 Feb 2018 00:19:36 +0000 (16:19 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 9 Feb 2018 18:11:02 +0000 (10:11 -0800)
There are some issues in the zdb -R decompression implementation.

The first is that ZLE can easily decompress non-ZLE streams. So we add
ZDB_NO_ZLE env to make zdb skip ZLE.

The second is the random bytes appended to pabd, pbuf2 stuff. This serve
no purpose at all, those bytes shouldn't be read during decompression
anyway. Instead, we randomize lbuf2, so that we can make sure
decompression fill exactly to lsize by bcmp lbuf and lbuf2.

The last one is the condition to detect fail is wrong.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: loli10K <ezomori.nozomu@gmail.com>
Signed-off-by: Chunwei Chen <david.chen@nutanix.com>
Closes #7099
Closes #4984

cmd/zdb/zdb.c
man/man8/zdb.8

index c381d02a39b38da8ec30fa6145e6e93c0bb4b818..4c0a8245fb9e4ceea70e6b45e29f7417aed6bf2d 100644 (file)
@@ -3984,13 +3984,6 @@ name:
        return (NULL);
 }
 
-/* ARGSUSED */
-static int
-random_get_pseudo_bytes_cb(void *buf, size_t len, void *unused)
-{
-       return (random_get_pseudo_bytes(buf, len));
-}
-
 /*
  * Read a block from a pool and print it out.  The syntax of the
  * block descriptor is:
@@ -4160,17 +4153,8 @@ zdb_read_block(char *thing, spa_t *spa)
                 * every decompress function at every inflated blocksize.
                 */
                enum zio_compress c;
-               void *pbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
                void *lbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
 
-               abd_copy_to_buf(pbuf2, pabd, psize);
-
-               VERIFY0(abd_iterate_func(pabd, psize, SPA_MAXBLOCKSIZE - psize,
-                   random_get_pseudo_bytes_cb, NULL));
-
-               VERIFY0(random_get_pseudo_bytes((uint8_t *)pbuf2 + psize,
-                   SPA_MAXBLOCKSIZE - psize));
-
                /*
                 * XXX - On the one hand, with SPA_MAXBLOCKSIZE at 16MB,
                 * this could take a while and we should let the user know
@@ -4180,13 +4164,29 @@ zdb_read_block(char *thing, spa_t *spa)
                for (lsize = psize + SPA_MINBLOCKSIZE;
                    lsize <= SPA_MAXBLOCKSIZE; lsize += SPA_MINBLOCKSIZE) {
                        for (c = 0; c < ZIO_COMPRESS_FUNCTIONS; c++) {
+                               /*
+                                * ZLE can easily decompress non zle stream.
+                                * So have an option to disable it.
+                                */
+                               if (c == ZIO_COMPRESS_ZLE &&
+                                   getenv("ZDB_NO_ZLE"))
+                                       continue;
+
                                (void) fprintf(stderr,
                                    "Trying %05llx -> %05llx (%s)\n",
                                    (u_longlong_t)psize, (u_longlong_t)lsize,
                                    zio_compress_table[c].ci_name);
+
+                               /*
+                                * We randomize lbuf2, and decompress to both
+                                * lbuf and lbuf2. This way, we will know if
+                                * decompression fill exactly to lsize.
+                                */
+                               VERIFY0(random_get_pseudo_bytes(lbuf2, lsize));
+
                                if (zio_decompress_data(c, pabd,
                                    lbuf, psize, lsize) == 0 &&
-                                   zio_decompress_data_buf(c, pbuf2,
+                                   zio_decompress_data(c, pabd,
                                    lbuf2, psize, lsize) == 0 &&
                                    bcmp(lbuf, lbuf2, lsize) == 0)
                                        break;
@@ -4194,11 +4194,9 @@ zdb_read_block(char *thing, spa_t *spa)
                        if (c != ZIO_COMPRESS_FUNCTIONS)
                                break;
                }
-
-               umem_free(pbuf2, SPA_MAXBLOCKSIZE);
                umem_free(lbuf2, SPA_MAXBLOCKSIZE);
 
-               if (lsize <= psize) {
+               if (lsize > SPA_MAXBLOCKSIZE) {
                        (void) printf("Decompress of %s failed\n", thing);
                        goto out;
                }
index d69d6f529d13801e92135de06e25ddf156460c49..0ce4d852d890ea82cee0a32d3c6ecf1c0e5ebdf9 100644 (file)
@@ -248,7 +248,9 @@ and, optionally,
 .It Sy b Ar offset
 Print block pointer
 .It Sy d
-Decompress the block
+Decompress the block. Set environment variable
+.Nm ZBD_NO_ZLE
+to skip zle when guessing.
 .It Sy e
 Byte swap the block
 .It Sy g