xref: /freebsd/sys/contrib/openzfs/cmd/zstream/zstream_chain.h (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 #ifndef _ZSTREAM_CHAIN_H
21*d0b3ecdcSMartin Matuska #define	_ZSTREAM_CHAIN_H
22*d0b3ecdcSMartin Matuska 
23*d0b3ecdcSMartin Matuska #ifdef __cplusplus
24*d0b3ecdcSMartin Matuska extern "C" {
25*d0b3ecdcSMartin Matuska #endif
26*d0b3ecdcSMartin Matuska 
27*d0b3ecdcSMartin Matuska #include <stddef.h>
28*d0b3ecdcSMartin Matuska #include <stdint.h>
29*d0b3ecdcSMartin Matuska #include <sys/zfs_ioctl.h>
30*d0b3ecdcSMartin Matuska 
31*d0b3ecdcSMartin Matuska /*
32*d0b3ecdcSMartin Matuska  * A chain is a linear series of steps that process packets of data. It's
33*d0b3ecdcSMartin Matuska  * designed to modularize common functionality, reduce code duplication, and
34*d0b3ecdcSMartin Matuska  * separate processing structure from implementation.
35*d0b3ecdcSMartin Matuska  *
36*d0b3ecdcSMartin Matuska  * Some terms:
37*d0b3ecdcSMartin Matuska  *
38*d0b3ecdcSMartin Matuska  * **STEP** - A chain_step_t struct that represents a packet-processing
39*d0b3ecdcSMartin Matuska  * module and any arguments or context that it needs. Chain modules
40*d0b3ecdcSMartin Matuska  * generally define a function named serial_* that produces a chain_step_t
41*d0b3ecdcSMartin Matuska  * that can be incorporated directly into a chain.
42*d0b3ecdcSMartin Matuska  *
43*d0b3ecdcSMartin Matuska  * **CHAIN** - An array of chain_step_t's. It's just data, so you can create
44*d0b3ecdcSMartin Matuska  * the array however you like. But normally you'd just declare the whole
45*d0b3ecdcSMartin Matuska  * thing:
46*d0b3ecdcSMartin Matuska  *
47*d0b3ecdcSMartin Matuska  *	zstream_chain_t dump_chain = {
48*d0b3ecdcSMartin Matuska  *		serial_read_stream(infile),
49*d0b3ecdcSMartin Matuska  *		serial_validate_fletcher4(),
50*d0b3ecdcSMartin Matuska  *		serial_byteswap(BS_INCOMING),
51*d0b3ecdcSMartin Matuska  *		serial_validate_records(),
52*d0b3ecdcSMartin Matuska  *		serial_dump_records(&dump_args),
53*d0b3ecdcSMartin Matuska  *		serial_null_output(),
54*d0b3ecdcSMartin Matuska  *		chain_terminator()
55*d0b3ecdcSMartin Matuska  *	}
56*d0b3ecdcSMartin Matuska  *
57*d0b3ecdcSMartin Matuska  * Or more succinctly:
58*d0b3ecdcSMartin Matuska  *
59*d0b3ecdcSMartin Matuska  *	zstream_chain_t dump_chain = {
60*d0b3ecdcSMartin Matuska  *		STANDARD_INPUT_STACK(infile),
61*d0b3ecdcSMartin Matuska  *		serial_dump_records(&dump_args),
62*d0b3ecdcSMartin Matuska  *		NULL_OUTPUT_STACK()
63*d0b3ecdcSMartin Matuska  *	};
64*d0b3ecdcSMartin Matuska  *
65*d0b3ecdcSMartin Matuska  * Chains must be terminated by a step of type CS_TERMINATE.
66*d0b3ecdcSMartin Matuska  *
67*d0b3ecdcSMartin Matuska  * **ITEMS** - The data packets that flow through a chain. Each step accepts
68*d0b3ecdcSMartin Matuska  * items of one size and emits items of another size, which may be smaller,
69*d0b3ecdcSMartin Matuska  * larger, or the same size. Items will generally be structs that start with
70*d0b3ecdcSMartin Matuska  * a drr_packet_t (defined in zstream_io.h) and may include additional
71*d0b3ecdcSMartin Matuska  * module-specific fields.
72*d0b3ecdcSMartin Matuska  *
73*d0b3ecdcSMartin Matuska  * **PROCESSING FUNCTION** - Each step names a processing function that does
74*d0b3ecdcSMartin Matuska  * the actual work of transforming an input buffer into an output buffer.
75*d0b3ecdcSMartin Matuska  * The transformation happens in place, in a single buffer provided by the
76*d0b3ecdcSMartin Matuska  * chain.
77*d0b3ecdcSMartin Matuska  *
78*d0b3ecdcSMartin Matuska  * The processing function should return a disposition_t, normally D_OK. A
79*d0b3ecdcSMartin Matuska  * function can return D_DROP to remove an item from the stream entirely. It
80*d0b3ecdcSMartin Matuska  * can also return D_EOF to indicate that no more data will be forthcoming.
81*d0b3ecdcSMartin Matuska  * However, only the first step in the chain should ever return D_EOF.
82*d0b3ecdcSMartin Matuska  *
83*d0b3ecdcSMartin Matuska  * Functions are called with a NULL packet pointer when the end of the
84*d0b3ecdcSMartin Matuska  * stream passes by them.
85*d0b3ecdcSMartin Matuska  *
86*d0b3ecdcSMartin Matuska  * **CONTEXT** - An arbitrary void * that the chain passes along to the
87*d0b3ecdcSMartin Matuska  * processing function as an argument.
88*d0b3ecdcSMartin Matuska  *
89*d0b3ecdcSMartin Matuska  * **CHAIN ATTRIBUTES** - A global set of flags available to all steps.
90*d0b3ecdcSMartin Matuska  */
91*d0b3ecdcSMartin Matuska 
92*d0b3ecdcSMartin Matuska #define	CA_BYTESWAPPED			(1ULL << 0)	/* ca_attrs */
93*d0b3ecdcSMartin Matuska #define	CA_BIG_ENDIAN_INPUT		(1ULL << 1)
94*d0b3ecdcSMartin Matuska #define	CA_LITTLE_ENDIAN_INPUT		(1ULL << 2)
95*d0b3ecdcSMartin Matuska 
96*d0b3ecdcSMartin Matuska #define	CA_VERBOSE			(1ULL << 0)	/* ca_command_opts */
97*d0b3ecdcSMartin Matuska #define	CA_VERY_VERBOSE			(1ULL << 1)
98*d0b3ecdcSMartin Matuska #define	CA_DUMP_DATA			(1ULL << 2)
99*d0b3ecdcSMartin Matuska #define	CA_IGNORE_CKSUMS		(1ULL << 3)
100*d0b3ecdcSMartin Matuska #define	CA_DO_NOT_VALIDATE		(1ULL << 4)
101*d0b3ecdcSMartin Matuska #define	CA_FORBID_DEDUP			(1ULL << 5)
102*d0b3ecdcSMartin Matuska #define	CA_REQUIRE_DEDUP		(1ULL << 6)
103*d0b3ecdcSMartin Matuska #define	CA_REQUIRE_NATIVE_ENDIAN	(1ULL << 7)
104*d0b3ecdcSMartin Matuska #define	CA_BYTESWAP_ON_OUTPUT		(1ULL << 8)
105*d0b3ecdcSMartin Matuska #define	CA_BIG_ENDIAN_OUT		(1ULL << 9)
106*d0b3ecdcSMartin Matuska #define	CA_LITTLE_ENDIAN_OUT		(1ULL << 10)
107*d0b3ecdcSMartin Matuska #define	CA_OPPOSITE_ENDIAN_OUT		(1ULL << 11)
108*d0b3ecdcSMartin Matuska 
109*d0b3ecdcSMartin Matuska #define	OPTION_ENABLED(option) (!!(chain_attrs->ca_command_opts & (option)))
110*d0b3ecdcSMartin Matuska #define	STREAM_HAS_FEATURE(feat) (!!(chain_attrs->ca_feature_flags & (feat)))
111*d0b3ecdcSMartin Matuska #define	ATTR_IS_SET(attr) (!!(chain_attrs->ca_attrs & (attr)))
112*d0b3ecdcSMartin Matuska 
113*d0b3ecdcSMartin Matuska #define	ENABLE_OPTION(attrs, opt) ((attrs)->ca_command_opts |= (opt))
114*d0b3ecdcSMartin Matuska #define	SET_ATTR(attr) (chain_attrs->ca_attrs |= (attr))
115*d0b3ecdcSMartin Matuska 
116*d0b3ecdcSMartin Matuska typedef struct {
117*d0b3ecdcSMartin Matuska 	uint64_t	rs_num_records;
118*d0b3ecdcSMartin Matuska 	uint64_t	rs_total_header_bytes;
119*d0b3ecdcSMartin Matuska 	uint64_t	rs_total_payload_bytes;
120*d0b3ecdcSMartin Matuska } record_stats_t;
121*d0b3ecdcSMartin Matuska 
122*d0b3ecdcSMartin Matuska /*
123*d0b3ecdcSMartin Matuska  * Chain attribute flags that describe the stream. Statistics are maintained
124*d0b3ecdcSMartin Matuska  * by the zstream_io modules.
125*d0b3ecdcSMartin Matuska  */
126*d0b3ecdcSMartin Matuska typedef struct {
127*d0b3ecdcSMartin Matuska 	uint64_t	ca_feature_flags;	/* From drr_versioninfo */
128*d0b3ecdcSMartin Matuska 	uint64_t	ca_attrs;		/* Discovered attributes */
129*d0b3ecdcSMartin Matuska 	uint64_t	ca_command_opts;	/* Command line options */
130*d0b3ecdcSMartin Matuska 	record_stats_t	ca_totals_in;
131*d0b3ecdcSMartin Matuska 	record_stats_t	ca_totals_out;
132*d0b3ecdcSMartin Matuska 	record_stats_t	ca_stats_in[DRR_NUMTYPES];
133*d0b3ecdcSMartin Matuska 	record_stats_t	ca_stats_out[DRR_NUMTYPES];
134*d0b3ecdcSMartin Matuska } chain_attrs_t;
135*d0b3ecdcSMartin Matuska 
136*d0b3ecdcSMartin Matuska typedef enum { CS_SERIAL, CS_TERMINATE } step_type_t;
137*d0b3ecdcSMartin Matuska typedef enum { D_OK, D_EOF, D_DROP } disposition_t;
138*d0b3ecdcSMartin Matuska 
139*d0b3ecdcSMartin Matuska typedef disposition_t
140*d0b3ecdcSMartin Matuska zc_serial_process_f(void *item, void *context);
141*d0b3ecdcSMartin Matuska 
142*d0b3ecdcSMartin Matuska typedef struct chain_step
143*d0b3ecdcSMartin Matuska {
144*d0b3ecdcSMartin Matuska 	step_type_t	cs_type;
145*d0b3ecdcSMartin Matuska 	size_t		cs_in_size;
146*d0b3ecdcSMartin Matuska 	size_t		cs_out_size;
147*d0b3ecdcSMartin Matuska 	void		*cs_context;
148*d0b3ecdcSMartin Matuska 	struct {
149*d0b3ecdcSMartin Matuska 		zc_serial_process_f	*process;
150*d0b3ecdcSMartin Matuska 	} cs_serial;
151*d0b3ecdcSMartin Matuska } chain_step_t;
152*d0b3ecdcSMartin Matuska 
153*d0b3ecdcSMartin Matuska typedef chain_step_t zstream_chain_t[];
154*d0b3ecdcSMartin Matuska 
155*d0b3ecdcSMartin Matuska /*
156*d0b3ecdcSMartin Matuska  * Chain attributes accessible to any step on the chain. In theory this
157*d0b3ecdcSMartin Matuska  * could cause a race condition between reading and setting, but all
158*d0b3ecdcSMartin Matuska  * attributes are typically set by the time the first record has been read.
159*d0b3ecdcSMartin Matuska  * Ergo, nobody else will be executing while that first chain_read() runs.
160*d0b3ecdcSMartin Matuska  */
161*d0b3ecdcSMartin Matuska extern chain_attrs_t *chain_attrs;
162*d0b3ecdcSMartin Matuska 
163*d0b3ecdcSMartin Matuska /*
164*d0b3ecdcSMartin Matuska  * Execute a chain. Returns once execution is complete. You can pass NULL
165*d0b3ecdcSMartin Matuska  * for the attrs if you're not interested in preserving them after the chain
166*d0b3ecdcSMartin Matuska  * has run.
167*d0b3ecdcSMartin Matuska  */
168*d0b3ecdcSMartin Matuska void
169*d0b3ecdcSMartin Matuska zstream_chain_exec(zstream_chain_t chain, chain_attrs_t *attrs);
170*d0b3ecdcSMartin Matuska 
171*d0b3ecdcSMartin Matuska chain_step_t
172*d0b3ecdcSMartin Matuska serial_null_step(void);
173*d0b3ecdcSMartin Matuska 
174*d0b3ecdcSMartin Matuska chain_step_t
175*d0b3ecdcSMartin Matuska chain_terminator(void);
176*d0b3ecdcSMartin Matuska 
177*d0b3ecdcSMartin Matuska #ifdef __cplusplus
178*d0b3ecdcSMartin Matuska }
179*d0b3ecdcSMartin Matuska #endif
180*d0b3ecdcSMartin Matuska 
181*d0b3ecdcSMartin Matuska #endif	/* _ZSTREAM_CHAIN_H */
182