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