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