xref: /freebsd/sys/contrib/openzfs/cmd/zstream/zstream_byteswap.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 <err.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <sys/byteorder.h>
24 #include <sys/spa_checksum.h>
25 #include <sys/stdtypes.h>
26 #include <sys/zfs_ioctl.h>
27 
28 #include "zstream_modules.h"
29 
30 /*
31  * Mostly from dmu_recv.c
32  */
33 
34 #define	DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X))
35 #define	DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X))
36 
37 typedef byteswap_stage_t byteswap_context_t;
38 
39 static byteswap_context_t byteswap_contexts[MAX_BYTESWAP];
40 static int next_context = 0;
41 
42 static disposition_t
chain_byteswap(drr_packet_t * item,byteswap_context_t * context)43 chain_byteswap(drr_packet_t *item, byteswap_context_t *context)
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 = (zc_serial_process_f *)chain_byteswap,
195 		}
196 	};
197 	return (step);
198 }
199