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 <err.h>
21*d0b3ecdcSMartin Matuska #include <stdint.h>
22*d0b3ecdcSMartin Matuska #include <stdlib.h>
23*d0b3ecdcSMartin Matuska #include <sys/byteorder.h>
24*d0b3ecdcSMartin Matuska #include <sys/spa_checksum.h>
25*d0b3ecdcSMartin Matuska #include <sys/stdtypes.h>
26*d0b3ecdcSMartin Matuska #include <sys/zfs_ioctl.h>
27*d0b3ecdcSMartin Matuska
28*d0b3ecdcSMartin Matuska #include "zstream_modules.h"
29*d0b3ecdcSMartin Matuska
30*d0b3ecdcSMartin Matuska /*
31*d0b3ecdcSMartin Matuska * Mostly from dmu_recv.c
32*d0b3ecdcSMartin Matuska */
33*d0b3ecdcSMartin Matuska
34*d0b3ecdcSMartin Matuska #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X))
35*d0b3ecdcSMartin Matuska #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X))
36*d0b3ecdcSMartin Matuska
37*d0b3ecdcSMartin Matuska typedef byteswap_stage_t byteswap_context_t;
38*d0b3ecdcSMartin Matuska
39*d0b3ecdcSMartin Matuska static byteswap_context_t byteswap_contexts[MAX_BYTESWAP];
40*d0b3ecdcSMartin Matuska static int next_context = 0;
41*d0b3ecdcSMartin Matuska
42*d0b3ecdcSMartin Matuska static disposition_t
chain_byteswap(drr_packet_t * item,byteswap_context_t * context)43*d0b3ecdcSMartin Matuska chain_byteswap(drr_packet_t *item, byteswap_context_t *context)
44*d0b3ecdcSMartin Matuska {
45*d0b3ecdcSMartin Matuska if (item == NULL) {
46*d0b3ecdcSMartin Matuska return (D_OK);
47*d0b3ecdcSMartin Matuska }
48*d0b3ecdcSMartin Matuska
49*d0b3ecdcSMartin Matuska struct dmu_replay_record *drr = &item->dp_drr;
50*d0b3ecdcSMartin Matuska boolean_t input_swapped = *context == BS_INCOMING &&
51*d0b3ecdcSMartin Matuska ATTR_IS_SET(CA_BYTESWAPPED);
52*d0b3ecdcSMartin Matuska boolean_t swap = input_swapped || (*context == BS_OUTGOING &&
53*d0b3ecdcSMartin Matuska OPTION_ENABLED(CA_BYTESWAP_ON_OUTPUT));
54*d0b3ecdcSMartin Matuska uint32_t drr_type =
55*d0b3ecdcSMartin Matuska input_swapped ? BSWAP_32(drr->drr_type) : drr->drr_type;
56*d0b3ecdcSMartin Matuska
57*d0b3ecdcSMartin Matuska if (swap) {
58*d0b3ecdcSMartin Matuska byteswap_record(drr, drr_type);
59*d0b3ecdcSMartin Matuska }
60*d0b3ecdcSMartin Matuska return (D_OK);
61*d0b3ecdcSMartin Matuska }
62*d0b3ecdcSMartin Matuska
63*d0b3ecdcSMartin Matuska /*
64*d0b3ecdcSMartin Matuska * Unconditionally byteswap a DMU replay record. drr_type is passed in
65*d0b3ecdcSMartin Matuska * separately because we don't know whether we're doing input or output
66*d0b3ecdcSMartin Matuska * swapping.
67*d0b3ecdcSMartin Matuska */
68*d0b3ecdcSMartin Matuska void
byteswap_record(dmu_replay_record_t * drr,uint32_t drr_type)69*d0b3ecdcSMartin Matuska byteswap_record(dmu_replay_record_t *drr, uint32_t drr_type)
70*d0b3ecdcSMartin Matuska {
71*d0b3ecdcSMartin Matuska drr->drr_type = BSWAP_32(drr->drr_type);
72*d0b3ecdcSMartin Matuska drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen);
73*d0b3ecdcSMartin Matuska
74*d0b3ecdcSMartin Matuska switch (drr_type) {
75*d0b3ecdcSMartin Matuska
76*d0b3ecdcSMartin Matuska case DRR_BEGIN:
77*d0b3ecdcSMartin Matuska DO64(drr_begin.drr_magic);
78*d0b3ecdcSMartin Matuska DO64(drr_begin.drr_versioninfo);
79*d0b3ecdcSMartin Matuska DO64(drr_begin.drr_creation_time);
80*d0b3ecdcSMartin Matuska DO32(drr_begin.drr_type);
81*d0b3ecdcSMartin Matuska DO32(drr_begin.drr_flags);
82*d0b3ecdcSMartin Matuska DO64(drr_begin.drr_toguid);
83*d0b3ecdcSMartin Matuska DO64(drr_begin.drr_fromguid);
84*d0b3ecdcSMartin Matuska break;
85*d0b3ecdcSMartin Matuska
86*d0b3ecdcSMartin Matuska case DRR_END:
87*d0b3ecdcSMartin Matuska DO64(drr_end.drr_toguid);
88*d0b3ecdcSMartin Matuska ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_end.drr_checksum);
89*d0b3ecdcSMartin Matuska break;
90*d0b3ecdcSMartin Matuska
91*d0b3ecdcSMartin Matuska case DRR_OBJECT:
92*d0b3ecdcSMartin Matuska DO64(drr_object.drr_object);
93*d0b3ecdcSMartin Matuska DO32(drr_object.drr_type);
94*d0b3ecdcSMartin Matuska DO32(drr_object.drr_bonustype);
95*d0b3ecdcSMartin Matuska DO32(drr_object.drr_blksz);
96*d0b3ecdcSMartin Matuska DO32(drr_object.drr_bonuslen);
97*d0b3ecdcSMartin Matuska DO32(drr_object.drr_raw_bonuslen);
98*d0b3ecdcSMartin Matuska DO64(drr_object.drr_toguid);
99*d0b3ecdcSMartin Matuska DO64(drr_object.drr_maxblkid);
100*d0b3ecdcSMartin Matuska break;
101*d0b3ecdcSMartin Matuska
102*d0b3ecdcSMartin Matuska case DRR_FREEOBJECTS:
103*d0b3ecdcSMartin Matuska DO64(drr_freeobjects.drr_firstobj);
104*d0b3ecdcSMartin Matuska DO64(drr_freeobjects.drr_numobjs);
105*d0b3ecdcSMartin Matuska DO64(drr_freeobjects.drr_toguid);
106*d0b3ecdcSMartin Matuska break;
107*d0b3ecdcSMartin Matuska
108*d0b3ecdcSMartin Matuska case DRR_WRITE:
109*d0b3ecdcSMartin Matuska DO64(drr_write.drr_object);
110*d0b3ecdcSMartin Matuska DO32(drr_write.drr_type);
111*d0b3ecdcSMartin Matuska DO64(drr_write.drr_offset);
112*d0b3ecdcSMartin Matuska DO64(drr_write.drr_logical_size);
113*d0b3ecdcSMartin Matuska DO64(drr_write.drr_toguid);
114*d0b3ecdcSMartin Matuska ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_write.drr_key.ddk_cksum);
115*d0b3ecdcSMartin Matuska DO64(drr_write.drr_key.ddk_prop);
116*d0b3ecdcSMartin Matuska DO64(drr_write.drr_compressed_size);
117*d0b3ecdcSMartin Matuska break;
118*d0b3ecdcSMartin Matuska
119*d0b3ecdcSMartin Matuska case DRR_WRITE_BYREF:
120*d0b3ecdcSMartin Matuska DO64(drr_write_byref.drr_object);
121*d0b3ecdcSMartin Matuska DO64(drr_write_byref.drr_offset);
122*d0b3ecdcSMartin Matuska DO64(drr_write_byref.drr_length);
123*d0b3ecdcSMartin Matuska DO64(drr_write_byref.drr_toguid);
124*d0b3ecdcSMartin Matuska DO64(drr_write_byref.drr_refguid);
125*d0b3ecdcSMartin Matuska DO64(drr_write_byref.drr_refobject);
126*d0b3ecdcSMartin Matuska DO64(drr_write_byref.drr_refoffset);
127*d0b3ecdcSMartin Matuska ZIO_CHECKSUM_BSWAP(
128*d0b3ecdcSMartin Matuska &drr->drr_u.drr_write_byref.drr_key.ddk_cksum);
129*d0b3ecdcSMartin Matuska DO64(drr_write_byref.drr_key.ddk_prop);
130*d0b3ecdcSMartin Matuska break;
131*d0b3ecdcSMartin Matuska
132*d0b3ecdcSMartin Matuska case DRR_FREE:
133*d0b3ecdcSMartin Matuska DO64(drr_free.drr_object);
134*d0b3ecdcSMartin Matuska DO64(drr_free.drr_offset);
135*d0b3ecdcSMartin Matuska DO64(drr_free.drr_length);
136*d0b3ecdcSMartin Matuska /* Note: toguid not byte-swapped in original zstream_dump.c */
137*d0b3ecdcSMartin Matuska DO64(drr_free.drr_toguid);
138*d0b3ecdcSMartin Matuska break;
139*d0b3ecdcSMartin Matuska
140*d0b3ecdcSMartin Matuska case DRR_SPILL:
141*d0b3ecdcSMartin Matuska DO64(drr_spill.drr_object);
142*d0b3ecdcSMartin Matuska DO64(drr_spill.drr_length);
143*d0b3ecdcSMartin Matuska /* Note: toguid not byte-swapped in original zstream_dump.c */
144*d0b3ecdcSMartin Matuska DO64(drr_spill.drr_toguid);
145*d0b3ecdcSMartin Matuska DO64(drr_spill.drr_compressed_size);
146*d0b3ecdcSMartin Matuska DO32(drr_spill.drr_type);
147*d0b3ecdcSMartin Matuska break;
148*d0b3ecdcSMartin Matuska
149*d0b3ecdcSMartin Matuska case DRR_WRITE_EMBEDDED:
150*d0b3ecdcSMartin Matuska DO64(drr_write_embedded.drr_object);
151*d0b3ecdcSMartin Matuska DO64(drr_write_embedded.drr_offset);
152*d0b3ecdcSMartin Matuska DO64(drr_write_embedded.drr_length);
153*d0b3ecdcSMartin Matuska DO64(drr_write_embedded.drr_toguid);
154*d0b3ecdcSMartin Matuska DO32(drr_write_embedded.drr_lsize);
155*d0b3ecdcSMartin Matuska DO32(drr_write_embedded.drr_psize);
156*d0b3ecdcSMartin Matuska break;
157*d0b3ecdcSMartin Matuska
158*d0b3ecdcSMartin Matuska case DRR_OBJECT_RANGE:
159*d0b3ecdcSMartin Matuska DO64(drr_object_range.drr_firstobj);
160*d0b3ecdcSMartin Matuska DO64(drr_object_range.drr_numslots);
161*d0b3ecdcSMartin Matuska DO64(drr_object_range.drr_toguid);
162*d0b3ecdcSMartin Matuska break;
163*d0b3ecdcSMartin Matuska
164*d0b3ecdcSMartin Matuska case DRR_REDACT:
165*d0b3ecdcSMartin Matuska DO64(drr_redact.drr_object);
166*d0b3ecdcSMartin Matuska DO64(drr_redact.drr_offset);
167*d0b3ecdcSMartin Matuska DO64(drr_redact.drr_length);
168*d0b3ecdcSMartin Matuska DO64(drr_redact.drr_toguid);
169*d0b3ecdcSMartin Matuska break;
170*d0b3ecdcSMartin Matuska
171*d0b3ecdcSMartin Matuska default:
172*d0b3ecdcSMartin Matuska errx(1, "unknown record type %llu, aborting...",
173*d0b3ecdcSMartin Matuska (u_longlong_t)drr_type);
174*d0b3ecdcSMartin Matuska }
175*d0b3ecdcSMartin Matuska
176*d0b3ecdcSMartin Matuska if (drr_type != DRR_BEGIN) {
177*d0b3ecdcSMartin Matuska ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_checksum.drr_checksum);
178*d0b3ecdcSMartin Matuska }
179*d0b3ecdcSMartin Matuska }
180*d0b3ecdcSMartin Matuska
181*d0b3ecdcSMartin Matuska chain_step_t
serial_byteswap(byteswap_stage_t stage)182*d0b3ecdcSMartin Matuska serial_byteswap(byteswap_stage_t stage)
183*d0b3ecdcSMartin Matuska {
184*d0b3ecdcSMartin Matuska int context_ix = next_context++ % MAX_BYTESWAP;
185*d0b3ecdcSMartin Matuska byteswap_context_t *bsc = &byteswap_contexts[context_ix];
186*d0b3ecdcSMartin Matuska
187*d0b3ecdcSMartin Matuska *bsc = stage;
188*d0b3ecdcSMartin Matuska chain_step_t step = {
189*d0b3ecdcSMartin Matuska .cs_type = CS_SERIAL,
190*d0b3ecdcSMartin Matuska .cs_in_size = sizeof (drr_packet_t),
191*d0b3ecdcSMartin Matuska .cs_out_size = sizeof (drr_packet_t),
192*d0b3ecdcSMartin Matuska .cs_context = bsc,
193*d0b3ecdcSMartin Matuska .cs_serial = {
194*d0b3ecdcSMartin Matuska .process = (zc_serial_process_f *)chain_byteswap,
195*d0b3ecdcSMartin Matuska }
196*d0b3ecdcSMartin Matuska };
197*d0b3ecdcSMartin Matuska return (step);
198*d0b3ecdcSMartin Matuska }
199