1dbd5678dSMartin Matuska /* 2dbd5678dSMartin Matuska * CDDL HEADER START 3dbd5678dSMartin Matuska * 4dbd5678dSMartin Matuska * The contents of this file are subject to the terms of the 5dbd5678dSMartin Matuska * Common Development and Distribution License (the "License"). 6dbd5678dSMartin Matuska * You may not use this file except in compliance with the License. 7dbd5678dSMartin Matuska * 8dbd5678dSMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9dbd5678dSMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10dbd5678dSMartin Matuska * See the License for the specific language governing permissions 11dbd5678dSMartin Matuska * and limitations under the License. 12dbd5678dSMartin Matuska * 13dbd5678dSMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each 14dbd5678dSMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15dbd5678dSMartin Matuska * If applicable, add the following below this CDDL HEADER, with the 16dbd5678dSMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying 17dbd5678dSMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner] 18dbd5678dSMartin Matuska * 19dbd5678dSMartin Matuska * CDDL HEADER END 20dbd5678dSMartin Matuska */ 21dbd5678dSMartin Matuska 22dbd5678dSMartin Matuska /* 23dbd5678dSMartin Matuska * Copyright 2022 Axcient. All rights reserved. 24dbd5678dSMartin Matuska * Use is subject to license terms. 25e2df9bb4SMartin Matuska * 26dbd5678dSMartin Matuska * Copyright (c) 2022 by Delphix. All rights reserved. 27e2df9bb4SMartin Matuska * Copyright (c) 2024, Klara, Inc. 28dbd5678dSMartin Matuska */ 29dbd5678dSMartin Matuska 30dbd5678dSMartin Matuska #include <err.h> 31dbd5678dSMartin Matuska #include <stdio.h> 32dbd5678dSMartin Matuska #include <stdlib.h> 33dbd5678dSMartin Matuska #include <unistd.h> 34dbd5678dSMartin Matuska #include <sys/zfs_ioctl.h> 35dbd5678dSMartin Matuska #include <sys/zio_checksum.h> 36dbd5678dSMartin Matuska #include <sys/zstd/zstd.h> 37dbd5678dSMartin Matuska #include "zfs_fletcher.h" 38dbd5678dSMartin Matuska #include "zstream.h" 39dbd5678dSMartin Matuska 40dbd5678dSMartin Matuska static int 41dbd5678dSMartin Matuska dump_record(dmu_replay_record_t *drr, void *payload, int payload_len, 42dbd5678dSMartin Matuska zio_cksum_t *zc, int outfd) 43dbd5678dSMartin Matuska { 44dbd5678dSMartin Matuska assert(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum) 45dbd5678dSMartin Matuska == sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t)); 46dbd5678dSMartin Matuska fletcher_4_incremental_native(drr, 47dbd5678dSMartin Matuska offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), zc); 48dbd5678dSMartin Matuska if (drr->drr_type != DRR_BEGIN) { 49dbd5678dSMartin Matuska assert(ZIO_CHECKSUM_IS_ZERO(&drr->drr_u. 50dbd5678dSMartin Matuska drr_checksum.drr_checksum)); 51dbd5678dSMartin Matuska drr->drr_u.drr_checksum.drr_checksum = *zc; 52dbd5678dSMartin Matuska } 53dbd5678dSMartin Matuska fletcher_4_incremental_native(&drr->drr_u.drr_checksum.drr_checksum, 54dbd5678dSMartin Matuska sizeof (zio_cksum_t), zc); 55dbd5678dSMartin Matuska if (write(outfd, drr, sizeof (*drr)) == -1) 56dbd5678dSMartin Matuska return (errno); 57dbd5678dSMartin Matuska if (payload_len != 0) { 58dbd5678dSMartin Matuska fletcher_4_incremental_native(payload, payload_len, zc); 59dbd5678dSMartin Matuska if (write(outfd, payload, payload_len) == -1) 60dbd5678dSMartin Matuska return (errno); 61dbd5678dSMartin Matuska } 62dbd5678dSMartin Matuska return (0); 63dbd5678dSMartin Matuska } 64dbd5678dSMartin Matuska 65dbd5678dSMartin Matuska int 66dbd5678dSMartin Matuska zstream_do_recompress(int argc, char *argv[]) 67dbd5678dSMartin Matuska { 68dbd5678dSMartin Matuska int bufsz = SPA_MAXBLOCKSIZE; 69dbd5678dSMartin Matuska char *buf = safe_malloc(bufsz); 70dbd5678dSMartin Matuska dmu_replay_record_t thedrr; 71dbd5678dSMartin Matuska dmu_replay_record_t *drr = &thedrr; 72dbd5678dSMartin Matuska zio_cksum_t stream_cksum; 73dbd5678dSMartin Matuska int c; 74e2df9bb4SMartin Matuska int level = 0; 75dbd5678dSMartin Matuska 76dbd5678dSMartin Matuska while ((c = getopt(argc, argv, "l:")) != -1) { 77dbd5678dSMartin Matuska switch (c) { 78dbd5678dSMartin Matuska case 'l': 79aca928a5SMartin Matuska if (sscanf(optarg, "%d", &level) != 1) { 80dbd5678dSMartin Matuska fprintf(stderr, 81dbd5678dSMartin Matuska "failed to parse level '%s'\n", 82dbd5678dSMartin Matuska optarg); 83dbd5678dSMartin Matuska zstream_usage(); 84dbd5678dSMartin Matuska } 85dbd5678dSMartin Matuska break; 86dbd5678dSMartin Matuska case '?': 87dbd5678dSMartin Matuska (void) fprintf(stderr, "invalid option '%c'\n", 88dbd5678dSMartin Matuska optopt); 89dbd5678dSMartin Matuska zstream_usage(); 90dbd5678dSMartin Matuska break; 91dbd5678dSMartin Matuska } 92dbd5678dSMartin Matuska } 93dbd5678dSMartin Matuska 94dbd5678dSMartin Matuska argc -= optind; 95dbd5678dSMartin Matuska argv += optind; 96dbd5678dSMartin Matuska 97dbd5678dSMartin Matuska if (argc != 1) 98dbd5678dSMartin Matuska zstream_usage(); 99e2df9bb4SMartin Matuska 100e2df9bb4SMartin Matuska enum zio_compress ctype; 101e2df9bb4SMartin Matuska if (strcmp(argv[0], "off") == 0) { 102e2df9bb4SMartin Matuska ctype = ZIO_COMPRESS_OFF; 103dbd5678dSMartin Matuska } else { 104e2df9bb4SMartin Matuska for (ctype = 0; ctype < ZIO_COMPRESS_FUNCTIONS; ctype++) { 105e2df9bb4SMartin Matuska if (strcmp(argv[0], 106e2df9bb4SMartin Matuska zio_compress_table[ctype].ci_name) == 0) 107dbd5678dSMartin Matuska break; 108dbd5678dSMartin Matuska } 109e2df9bb4SMartin Matuska if (ctype == ZIO_COMPRESS_FUNCTIONS || 110e2df9bb4SMartin Matuska zio_compress_table[ctype].ci_compress == NULL) { 111dbd5678dSMartin Matuska fprintf(stderr, "Invalid compression type %s.\n", 112dbd5678dSMartin Matuska argv[0]); 113dbd5678dSMartin Matuska exit(2); 114dbd5678dSMartin Matuska } 115dbd5678dSMartin Matuska } 116dbd5678dSMartin Matuska 117dbd5678dSMartin Matuska if (isatty(STDIN_FILENO)) { 118dbd5678dSMartin Matuska (void) fprintf(stderr, 119dbd5678dSMartin Matuska "Error: The send stream is a binary format " 120dbd5678dSMartin Matuska "and can not be read from a\n" 121dbd5678dSMartin Matuska "terminal. Standard input must be redirected.\n"); 122dbd5678dSMartin Matuska exit(1); 123dbd5678dSMartin Matuska } 124dbd5678dSMartin Matuska 125e2df9bb4SMartin Matuska abd_init(); 126dbd5678dSMartin Matuska fletcher_4_init(); 127dbd5678dSMartin Matuska zio_init(); 128dbd5678dSMartin Matuska zstd_init(); 12915f0b8c3SMartin Matuska int begin = 0; 13015f0b8c3SMartin Matuska boolean_t seen = B_FALSE; 131dbd5678dSMartin Matuska while (sfread(drr, sizeof (*drr), stdin) != 0) { 132dbd5678dSMartin Matuska struct drr_write *drrw; 133dbd5678dSMartin Matuska uint64_t payload_size = 0; 134dbd5678dSMartin Matuska 135dbd5678dSMartin Matuska /* 136dbd5678dSMartin Matuska * We need to regenerate the checksum. 137dbd5678dSMartin Matuska */ 138dbd5678dSMartin Matuska if (drr->drr_type != DRR_BEGIN) { 139dbd5678dSMartin Matuska memset(&drr->drr_u.drr_checksum.drr_checksum, 0, 140dbd5678dSMartin Matuska sizeof (drr->drr_u.drr_checksum.drr_checksum)); 141dbd5678dSMartin Matuska } 142dbd5678dSMartin Matuska 143dbd5678dSMartin Matuska 144dbd5678dSMartin Matuska switch (drr->drr_type) { 145dbd5678dSMartin Matuska case DRR_BEGIN: 146dbd5678dSMartin Matuska { 147dbd5678dSMartin Matuska ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0); 14815f0b8c3SMartin Matuska VERIFY0(begin++); 14915f0b8c3SMartin Matuska seen = B_TRUE; 150dbd5678dSMartin Matuska 15115f0b8c3SMartin Matuska uint32_t sz = drr->drr_payloadlen; 15215f0b8c3SMartin Matuska 15315f0b8c3SMartin Matuska VERIFY3U(sz, <=, 1U << 28); 15415f0b8c3SMartin Matuska 155dbd5678dSMartin Matuska if (sz != 0) { 156dbd5678dSMartin Matuska if (sz > bufsz) { 157dbd5678dSMartin Matuska buf = realloc(buf, sz); 158dbd5678dSMartin Matuska if (buf == NULL) 159dbd5678dSMartin Matuska err(1, "realloc"); 160dbd5678dSMartin Matuska bufsz = sz; 161dbd5678dSMartin Matuska } 162dbd5678dSMartin Matuska (void) sfread(buf, sz, stdin); 163dbd5678dSMartin Matuska } 164dbd5678dSMartin Matuska payload_size = sz; 165dbd5678dSMartin Matuska break; 166dbd5678dSMartin Matuska } 167dbd5678dSMartin Matuska case DRR_END: 168dbd5678dSMartin Matuska { 169dbd5678dSMartin Matuska struct drr_end *drre = &drr->drr_u.drr_end; 170dbd5678dSMartin Matuska /* 17115f0b8c3SMartin Matuska * We would prefer to just check --begin == 0, but 17215f0b8c3SMartin Matuska * replication streams have an end of stream END 17315f0b8c3SMartin Matuska * record, so we must avoid tripping it. 17415f0b8c3SMartin Matuska */ 17515f0b8c3SMartin Matuska VERIFY3B(seen, ==, B_TRUE); 17615f0b8c3SMartin Matuska begin--; 17715f0b8c3SMartin Matuska /* 178dbd5678dSMartin Matuska * Use the recalculated checksum, unless this is 179dbd5678dSMartin Matuska * the END record of a stream package, which has 180dbd5678dSMartin Matuska * no checksum. 181dbd5678dSMartin Matuska */ 182dbd5678dSMartin Matuska if (!ZIO_CHECKSUM_IS_ZERO(&drre->drr_checksum)) 183dbd5678dSMartin Matuska drre->drr_checksum = stream_cksum; 184dbd5678dSMartin Matuska break; 185dbd5678dSMartin Matuska } 186dbd5678dSMartin Matuska 187dbd5678dSMartin Matuska case DRR_OBJECT: 188dbd5678dSMartin Matuska { 189dbd5678dSMartin Matuska struct drr_object *drro = &drr->drr_u.drr_object; 19015f0b8c3SMartin Matuska VERIFY3S(begin, ==, 1); 191dbd5678dSMartin Matuska 192dbd5678dSMartin Matuska if (drro->drr_bonuslen > 0) { 193dbd5678dSMartin Matuska payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro); 194dbd5678dSMartin Matuska (void) sfread(buf, payload_size, stdin); 195dbd5678dSMartin Matuska } 196dbd5678dSMartin Matuska break; 197dbd5678dSMartin Matuska } 198dbd5678dSMartin Matuska 199dbd5678dSMartin Matuska case DRR_SPILL: 200dbd5678dSMartin Matuska { 201dbd5678dSMartin Matuska struct drr_spill *drrs = &drr->drr_u.drr_spill; 20215f0b8c3SMartin Matuska VERIFY3S(begin, ==, 1); 203dbd5678dSMartin Matuska payload_size = DRR_SPILL_PAYLOAD_SIZE(drrs); 204dbd5678dSMartin Matuska (void) sfread(buf, payload_size, stdin); 205dbd5678dSMartin Matuska break; 206dbd5678dSMartin Matuska } 207dbd5678dSMartin Matuska 208dbd5678dSMartin Matuska case DRR_WRITE_BYREF: 20915f0b8c3SMartin Matuska VERIFY3S(begin, ==, 1); 210dbd5678dSMartin Matuska fprintf(stderr, 211dbd5678dSMartin Matuska "Deduplicated streams are not supported\n"); 212dbd5678dSMartin Matuska exit(1); 213dbd5678dSMartin Matuska break; 214dbd5678dSMartin Matuska 215dbd5678dSMartin Matuska case DRR_WRITE: 216dbd5678dSMartin Matuska { 21715f0b8c3SMartin Matuska VERIFY3S(begin, ==, 1); 218dbd5678dSMartin Matuska drrw = &thedrr.drr_u.drr_write; 219dbd5678dSMartin Matuska payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw); 220dbd5678dSMartin Matuska /* 221dbd5678dSMartin Matuska * In order to recompress an encrypted block, you have 222dbd5678dSMartin Matuska * to decrypt, decompress, recompress, and 223dbd5678dSMartin Matuska * re-encrypt. That can be a future enhancement (along 224dbd5678dSMartin Matuska * with decryption or re-encryption), but for now we 225dbd5678dSMartin Matuska * skip encrypted blocks. 226dbd5678dSMartin Matuska */ 227dbd5678dSMartin Matuska boolean_t encrypted = B_FALSE; 228dbd5678dSMartin Matuska for (int i = 0; i < ZIO_DATA_SALT_LEN; i++) { 229dbd5678dSMartin Matuska if (drrw->drr_salt[i] != 0) { 230dbd5678dSMartin Matuska encrypted = B_TRUE; 231dbd5678dSMartin Matuska break; 232dbd5678dSMartin Matuska } 233dbd5678dSMartin Matuska } 234dbd5678dSMartin Matuska if (encrypted) { 235dbd5678dSMartin Matuska (void) sfread(buf, payload_size, stdin); 236dbd5678dSMartin Matuska break; 237dbd5678dSMartin Matuska } 238e2df9bb4SMartin Matuska enum zio_compress dtype = drrw->drr_compressiontype; 239e2df9bb4SMartin Matuska if (dtype >= ZIO_COMPRESS_FUNCTIONS) { 240dbd5678dSMartin Matuska fprintf(stderr, "Invalid compression type in " 241e2df9bb4SMartin Matuska "stream: %d\n", dtype); 242dbd5678dSMartin Matuska exit(3); 243dbd5678dSMartin Matuska } 244e2df9bb4SMartin Matuska if (zio_compress_table[dtype].ci_decompress == NULL) 245e2df9bb4SMartin Matuska dtype = ZIO_COMPRESS_OFF; 246dbd5678dSMartin Matuska 247dbd5678dSMartin Matuska /* Set up buffers to minimize memcpys */ 248dbd5678dSMartin Matuska char *cbuf, *dbuf; 249e2df9bb4SMartin Matuska if (ctype == ZIO_COMPRESS_OFF) 250dbd5678dSMartin Matuska dbuf = buf; 251dbd5678dSMartin Matuska else 252dbd5678dSMartin Matuska dbuf = safe_calloc(bufsz); 253dbd5678dSMartin Matuska 254e2df9bb4SMartin Matuska if (dtype == ZIO_COMPRESS_OFF) 255dbd5678dSMartin Matuska cbuf = dbuf; 256dbd5678dSMartin Matuska else 257dbd5678dSMartin Matuska cbuf = safe_calloc(payload_size); 258dbd5678dSMartin Matuska 259dbd5678dSMartin Matuska /* Read and decompress the payload */ 260dbd5678dSMartin Matuska (void) sfread(cbuf, payload_size, stdin); 261e2df9bb4SMartin Matuska if (dtype != ZIO_COMPRESS_OFF) { 262e2df9bb4SMartin Matuska abd_t cabd, dabd; 263e2df9bb4SMartin Matuska abd_get_from_buf_struct(&cabd, 264e2df9bb4SMartin Matuska cbuf, payload_size); 265e2df9bb4SMartin Matuska abd_get_from_buf_struct(&dabd, dbuf, 266e2df9bb4SMartin Matuska MIN(bufsz, drrw->drr_logical_size)); 267e2df9bb4SMartin Matuska if (zio_decompress_data(dtype, &cabd, &dabd, 268e2df9bb4SMartin Matuska payload_size, abd_get_size(&dabd), 269e2df9bb4SMartin Matuska NULL) != 0) { 270dbd5678dSMartin Matuska warnx("decompression type %d failed " 271dbd5678dSMartin Matuska "for ino %llu offset %llu", 272e2df9bb4SMartin Matuska dtype, 273dbd5678dSMartin Matuska (u_longlong_t)drrw->drr_object, 274dbd5678dSMartin Matuska (u_longlong_t)drrw->drr_offset); 275dbd5678dSMartin Matuska exit(4); 276dbd5678dSMartin Matuska } 277dbd5678dSMartin Matuska payload_size = drrw->drr_logical_size; 278e2df9bb4SMartin Matuska abd_free(&dabd); 279e2df9bb4SMartin Matuska abd_free(&cabd); 280dbd5678dSMartin Matuska free(cbuf); 281dbd5678dSMartin Matuska } 282dbd5678dSMartin Matuska 283dbd5678dSMartin Matuska /* Recompress the payload */ 284e2df9bb4SMartin Matuska if (ctype != ZIO_COMPRESS_OFF) { 285e2df9bb4SMartin Matuska abd_t dabd, abd; 286e2df9bb4SMartin Matuska abd_get_from_buf_struct(&dabd, 287e2df9bb4SMartin Matuska dbuf, drrw->drr_logical_size); 288e2df9bb4SMartin Matuska abd_t *pabd = 289e2df9bb4SMartin Matuska abd_get_from_buf_struct(&abd, buf, bufsz); 290e2df9bb4SMartin Matuska size_t csize = zio_compress_data(ctype, &dabd, 291*7a7741afSMartin Matuska &pabd, drrw->drr_logical_size, 292*7a7741afSMartin Matuska drrw->drr_logical_size, level); 293e2df9bb4SMartin Matuska size_t rounded = 294e2df9bb4SMartin Matuska P2ROUNDUP(csize, SPA_MINBLOCKSIZE); 295e2df9bb4SMartin Matuska if (rounded >= drrw->drr_logical_size) { 296dbd5678dSMartin Matuska memcpy(buf, dbuf, payload_size); 297dbd5678dSMartin Matuska drrw->drr_compressiontype = 0; 298dbd5678dSMartin Matuska drrw->drr_compressed_size = 0; 299e2df9bb4SMartin Matuska } else { 300e2df9bb4SMartin Matuska abd_zero_off(pabd, csize, 301e2df9bb4SMartin Matuska rounded - csize); 302e2df9bb4SMartin Matuska drrw->drr_compressiontype = ctype; 303e2df9bb4SMartin Matuska drrw->drr_compressed_size = 304e2df9bb4SMartin Matuska payload_size = rounded; 305dbd5678dSMartin Matuska } 306e2df9bb4SMartin Matuska abd_free(&abd); 307e2df9bb4SMartin Matuska abd_free(&dabd); 308dbd5678dSMartin Matuska free(dbuf); 309dbd5678dSMartin Matuska } else { 310e2df9bb4SMartin Matuska drrw->drr_compressiontype = 0; 311dbd5678dSMartin Matuska drrw->drr_compressed_size = 0; 312dbd5678dSMartin Matuska } 313dbd5678dSMartin Matuska break; 314dbd5678dSMartin Matuska } 315dbd5678dSMartin Matuska 316dbd5678dSMartin Matuska case DRR_WRITE_EMBEDDED: 317dbd5678dSMartin Matuska { 318dbd5678dSMartin Matuska struct drr_write_embedded *drrwe = 319dbd5678dSMartin Matuska &drr->drr_u.drr_write_embedded; 32015f0b8c3SMartin Matuska VERIFY3S(begin, ==, 1); 321dbd5678dSMartin Matuska payload_size = 322dbd5678dSMartin Matuska P2ROUNDUP((uint64_t)drrwe->drr_psize, 8); 323dbd5678dSMartin Matuska (void) sfread(buf, payload_size, stdin); 324dbd5678dSMartin Matuska break; 325dbd5678dSMartin Matuska } 326dbd5678dSMartin Matuska 327dbd5678dSMartin Matuska case DRR_FREEOBJECTS: 328dbd5678dSMartin Matuska case DRR_FREE: 329dbd5678dSMartin Matuska case DRR_OBJECT_RANGE: 33015f0b8c3SMartin Matuska VERIFY3S(begin, ==, 1); 331dbd5678dSMartin Matuska break; 332dbd5678dSMartin Matuska 333dbd5678dSMartin Matuska default: 334dbd5678dSMartin Matuska (void) fprintf(stderr, "INVALID record type 0x%x\n", 335dbd5678dSMartin Matuska drr->drr_type); 336dbd5678dSMartin Matuska /* should never happen, so assert */ 337dbd5678dSMartin Matuska assert(B_FALSE); 338dbd5678dSMartin Matuska } 339dbd5678dSMartin Matuska 340dbd5678dSMartin Matuska if (feof(stdout)) { 341dbd5678dSMartin Matuska fprintf(stderr, "Error: unexpected end-of-file\n"); 342dbd5678dSMartin Matuska exit(1); 343dbd5678dSMartin Matuska } 344dbd5678dSMartin Matuska if (ferror(stdout)) { 345dbd5678dSMartin Matuska fprintf(stderr, "Error while reading file: %s\n", 346dbd5678dSMartin Matuska strerror(errno)); 347dbd5678dSMartin Matuska exit(1); 348dbd5678dSMartin Matuska } 349dbd5678dSMartin Matuska 350dbd5678dSMartin Matuska /* 351dbd5678dSMartin Matuska * We need to recalculate the checksum, and it needs to be 352dbd5678dSMartin Matuska * initially zero to do that. BEGIN records don't have 353dbd5678dSMartin Matuska * a checksum. 354dbd5678dSMartin Matuska */ 355dbd5678dSMartin Matuska if (drr->drr_type != DRR_BEGIN) { 356dbd5678dSMartin Matuska memset(&drr->drr_u.drr_checksum.drr_checksum, 0, 357dbd5678dSMartin Matuska sizeof (drr->drr_u.drr_checksum.drr_checksum)); 358dbd5678dSMartin Matuska } 359dbd5678dSMartin Matuska if (dump_record(drr, buf, payload_size, 360dbd5678dSMartin Matuska &stream_cksum, STDOUT_FILENO) != 0) 361dbd5678dSMartin Matuska break; 362dbd5678dSMartin Matuska if (drr->drr_type == DRR_END) { 363dbd5678dSMartin Matuska /* 364dbd5678dSMartin Matuska * Typically the END record is either the last 365dbd5678dSMartin Matuska * thing in the stream, or it is followed 366dbd5678dSMartin Matuska * by a BEGIN record (which also zeros the checksum). 367dbd5678dSMartin Matuska * However, a stream package ends with two END 368dbd5678dSMartin Matuska * records. The last END record's checksum starts 369dbd5678dSMartin Matuska * from zero. 370dbd5678dSMartin Matuska */ 371dbd5678dSMartin Matuska ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0); 372dbd5678dSMartin Matuska } 373dbd5678dSMartin Matuska } 374dbd5678dSMartin Matuska free(buf); 375dbd5678dSMartin Matuska fletcher_4_fini(); 376dbd5678dSMartin Matuska zio_fini(); 377dbd5678dSMartin Matuska zstd_fini(); 378e2df9bb4SMartin Matuska abd_fini(); 379dbd5678dSMartin Matuska 380dbd5678dSMartin Matuska return (0); 381dbd5678dSMartin Matuska } 382