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