xref: /freebsd/sys/contrib/openzfs/cmd/zstream/zstream_chain.c (revision d0b3ecdc274930e190ea233b6b69ff03782eaf8d)
1*d0b3ecdcSMartin Matuska // SPDX-License-Identifier: CDDL-1.0
2*d0b3ecdcSMartin Matuska /*
3*d0b3ecdcSMartin Matuska  * CDDL HEADER START
4*d0b3ecdcSMartin Matuska  *
5*d0b3ecdcSMartin Matuska  * This file and its contents are supplied under the terms of the Common
6*d0b3ecdcSMartin Matuska  * Development and Distribution License ("CDDL"), version 1.0. You may only use
7*d0b3ecdcSMartin Matuska  * this file in accordance with the terms of version 1.0 of the CDDL.
8*d0b3ecdcSMartin Matuska  *
9*d0b3ecdcSMartin Matuska  * A full copy of the text of the CDDL should have accompanied this source. A
10*d0b3ecdcSMartin Matuska  * copy of the CDDL is also available via the Internet at
11*d0b3ecdcSMartin Matuska  * http://www.illumos.org/license/CDDL.
12*d0b3ecdcSMartin Matuska  *
13*d0b3ecdcSMartin Matuska  * CDDL HEADER END
14*d0b3ecdcSMartin Matuska  */
15*d0b3ecdcSMartin Matuska 
16*d0b3ecdcSMartin Matuska /*
17*d0b3ecdcSMartin Matuska  * Copyright (c) 2026 by Garth Snyder. All rights reserved.
18*d0b3ecdcSMartin Matuska  */
19*d0b3ecdcSMartin Matuska 
20*d0b3ecdcSMartin Matuska #include <assert.h>
21*d0b3ecdcSMartin Matuska #include <err.h>
22*d0b3ecdcSMartin Matuska #include <libspl.h>
23*d0b3ecdcSMartin Matuska #include <stdio.h>
24*d0b3ecdcSMartin Matuska #include <stdlib.h>
25*d0b3ecdcSMartin Matuska #include <sys/abd.h>
26*d0b3ecdcSMartin Matuska #include <sys/param.h>
27*d0b3ecdcSMartin Matuska #include <sys/stdtypes.h>
28*d0b3ecdcSMartin Matuska #include <sys/zio.h>
29*d0b3ecdcSMartin Matuska #include <sys/zstd/zstd.h>
30*d0b3ecdcSMartin Matuska #include <zfs_fletcher.h>
31*d0b3ecdcSMartin Matuska 
32*d0b3ecdcSMartin Matuska #include "zstream_chain.h"
33*d0b3ecdcSMartin Matuska 
34*d0b3ecdcSMartin Matuska #define	MAX_CHAIN_LENGTH 32
35*d0b3ecdcSMartin Matuska 
36*d0b3ecdcSMartin Matuska chain_attrs_t *chain_attrs;
37*d0b3ecdcSMartin Matuska 
38*d0b3ecdcSMartin Matuska static disposition_t
chain_null_step(void * item,void * context)39*d0b3ecdcSMartin Matuska chain_null_step(void *item, void *context)
40*d0b3ecdcSMartin Matuska {
41*d0b3ecdcSMartin Matuska 	(void) item;
42*d0b3ecdcSMartin Matuska 	(void) context;
43*d0b3ecdcSMartin Matuska 	return (D_OK);
44*d0b3ecdcSMartin Matuska }
45*d0b3ecdcSMartin Matuska 
46*d0b3ecdcSMartin Matuska chain_step_t
serial_null_step(void)47*d0b3ecdcSMartin Matuska serial_null_step(void)
48*d0b3ecdcSMartin Matuska {
49*d0b3ecdcSMartin Matuska 	chain_step_t step = {
50*d0b3ecdcSMartin Matuska 		.cs_type = CS_SERIAL,
51*d0b3ecdcSMartin Matuska 		.cs_serial = {
52*d0b3ecdcSMartin Matuska 		    .process = (zc_serial_process_f *)chain_null_step
53*d0b3ecdcSMartin Matuska 		}
54*d0b3ecdcSMartin Matuska 	};
55*d0b3ecdcSMartin Matuska 	return (step);
56*d0b3ecdcSMartin Matuska }
57*d0b3ecdcSMartin Matuska 
58*d0b3ecdcSMartin Matuska chain_step_t
chain_terminator(void)59*d0b3ecdcSMartin Matuska chain_terminator(void)
60*d0b3ecdcSMartin Matuska {
61*d0b3ecdcSMartin Matuska 	chain_step_t step = { .cs_type = CS_TERMINATE };
62*d0b3ecdcSMartin Matuska 	return (step);
63*d0b3ecdcSMartin Matuska }
64*d0b3ecdcSMartin Matuska 
65*d0b3ecdcSMartin Matuska static void
libraries_init(void)66*d0b3ecdcSMartin Matuska libraries_init(void)
67*d0b3ecdcSMartin Matuska {
68*d0b3ecdcSMartin Matuska 	zfs_refcount_init();
69*d0b3ecdcSMartin Matuska 	abd_init();
70*d0b3ecdcSMartin Matuska 	zio_init();
71*d0b3ecdcSMartin Matuska 	zstd_init();
72*d0b3ecdcSMartin Matuska 	libspl_init();
73*d0b3ecdcSMartin Matuska 	fletcher_4_init();
74*d0b3ecdcSMartin Matuska }
75*d0b3ecdcSMartin Matuska 
76*d0b3ecdcSMartin Matuska static void
libraries_fini(void)77*d0b3ecdcSMartin Matuska libraries_fini(void)
78*d0b3ecdcSMartin Matuska {
79*d0b3ecdcSMartin Matuska 	fletcher_4_fini();
80*d0b3ecdcSMartin Matuska 	libspl_fini();
81*d0b3ecdcSMartin Matuska 	zio_fini();
82*d0b3ecdcSMartin Matuska 	zstd_fini();
83*d0b3ecdcSMartin Matuska 	abd_fini();
84*d0b3ecdcSMartin Matuska 	zfs_refcount_fini();
85*d0b3ecdcSMartin Matuska }
86*d0b3ecdcSMartin Matuska 
87*d0b3ecdcSMartin Matuska /*
88*d0b3ecdcSMartin Matuska  * Execute a chain of serial processing steps.
89*d0b3ecdcSMartin Matuska  *
90*d0b3ecdcSMartin Matuska  * For simplicity, we normalize the chain item size to that of the largest
91*d0b3ecdcSMartin Matuska  * output of any step. Packets with data beyond the base drr_record_t should
92*d0b3ecdcSMartin Matuska  * add their additional data to the end of the packet, and this area may be
93*d0b3ecdcSMartin Matuska  * reused for different purposes as items travel down the chain.
94*d0b3ecdcSMartin Matuska  *
95*d0b3ecdcSMartin Matuska  * Each item traverses the entire chain before the next item is read.
96*d0b3ecdcSMartin Matuska  */
97*d0b3ecdcSMartin Matuska void
zstream_chain_exec(zstream_chain_t chain,chain_attrs_t * attrs)98*d0b3ecdcSMartin Matuska zstream_chain_exec(zstream_chain_t chain, chain_attrs_t *attrs)
99*d0b3ecdcSMartin Matuska {
100*d0b3ecdcSMartin Matuska 	int num_steps = 0;
101*d0b3ecdcSMartin Matuska 	size_t packet_size = 0;
102*d0b3ecdcSMartin Matuska 	chain_attrs_t backup_attrs = {0};
103*d0b3ecdcSMartin Matuska 
104*d0b3ecdcSMartin Matuska 	chain_attrs = attrs ? attrs : &backup_attrs;
105*d0b3ecdcSMartin Matuska 
106*d0b3ecdcSMartin Matuska 	while (chain[num_steps].cs_type != CS_TERMINATE) {
107*d0b3ecdcSMartin Matuska 		packet_size = MAX(packet_size, chain[num_steps].cs_out_size);
108*d0b3ecdcSMartin Matuska 		num_steps++;
109*d0b3ecdcSMartin Matuska 		if (num_steps >= MAX_CHAIN_LENGTH) {
110*d0b3ecdcSMartin Matuska 			errx(1, "unterminated zstream_chain");
111*d0b3ecdcSMartin Matuska 		}
112*d0b3ecdcSMartin Matuska 	}
113*d0b3ecdcSMartin Matuska 	VERIFY3U(num_steps, >, 0);
114*d0b3ecdcSMartin Matuska 
115*d0b3ecdcSMartin Matuska 	/*
116*d0b3ecdcSMartin Matuska 	 * Check for consistency of input and output packet sizes in
117*d0b3ecdcSMartin Matuska 	 * adjacent steps. A declared packet size of zero waives this check.
118*d0b3ecdcSMartin Matuska 	 */
119*d0b3ecdcSMartin Matuska 	for (int i = 0; i < num_steps; i++) {
120*d0b3ecdcSMartin Matuska 		boolean_t mismatch = i > 0 &&
121*d0b3ecdcSMartin Matuska 		    chain[i].cs_in_size != 0 &&
122*d0b3ecdcSMartin Matuska 		    chain[i-1].cs_out_size != 0 &&
123*d0b3ecdcSMartin Matuska 		    chain[i].cs_in_size != chain[i-1].cs_out_size;
124*d0b3ecdcSMartin Matuska 		if (mismatch) {
125*d0b3ecdcSMartin Matuska 			warnx("note - chain steps %d and %d have "
126*d0b3ecdcSMartin Matuska 			    "mismatched packet sizes", i - 1, i);
127*d0b3ecdcSMartin Matuska 		}
128*d0b3ecdcSMartin Matuska 	}
129*d0b3ecdcSMartin Matuska 
130*d0b3ecdcSMartin Matuska 	libraries_init();
131*d0b3ecdcSMartin Matuska 
132*d0b3ecdcSMartin Matuska 	uint8_t buffer[packet_size];
133*d0b3ecdcSMartin Matuska 	boolean_t done = B_FALSE;
134*d0b3ecdcSMartin Matuska 
135*d0b3ecdcSMartin Matuska 	while (!done) {
136*d0b3ecdcSMartin Matuska 		for (int i = 0; i < num_steps; i++) {
137*d0b3ecdcSMartin Matuska 			if (done) {
138*d0b3ecdcSMartin Matuska 				(void) chain[i].cs_serial.process(NULL,
139*d0b3ecdcSMartin Matuska 				    chain[i].cs_context);
140*d0b3ecdcSMartin Matuska 			} else {
141*d0b3ecdcSMartin Matuska 				disposition_t dispo =
142*d0b3ecdcSMartin Matuska 				    chain[i].cs_serial.process(buffer,
143*d0b3ecdcSMartin Matuska 				    chain[i].cs_context);
144*d0b3ecdcSMartin Matuska 				if (dispo == D_EOF) {
145*d0b3ecdcSMartin Matuska 					VERIFY0(i);
146*d0b3ecdcSMartin Matuska 					done = B_TRUE;
147*d0b3ecdcSMartin Matuska 				} else if (dispo == D_DROP) {
148*d0b3ecdcSMartin Matuska 					break;
149*d0b3ecdcSMartin Matuska 				}
150*d0b3ecdcSMartin Matuska 			}
151*d0b3ecdcSMartin Matuska 		}
152*d0b3ecdcSMartin Matuska 	}
153*d0b3ecdcSMartin Matuska 
154*d0b3ecdcSMartin Matuska 	libraries_fini();
155*d0b3ecdcSMartin Matuska }
156