xref: /dragonfly/sys/vfs/hammer/hammer_crc.h (revision 62dc643e)
1 /*
2  * Copyright (c) 2007-2016 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifndef VFS_HAMMER_CRC_H_
36 #define VFS_HAMMER_CRC_H_
37 
38 #include "hammer_disk.h"
39 #include "hammer_ioctl.h"
40 
41 #ifndef _KERNEL
42 /*
43  * These are only for userspace.
44  * Userspace can't include sys/sys/systm.h.
45  */
46 uint32_t crc32(const void *buf, size_t size);
47 uint32_t crc32_ext(const void *buf, size_t size, uint32_t ocrc);
48 uint32_t iscsi_crc32(const void *buf, size_t size);
49 uint32_t iscsi_crc32_ext(const void *buf, size_t size, uint32_t ocrc);
50 #endif
51 
52 /*
53  * hammer_datacrc() expects vol_version to be the volume version of the
54  * currently mounted HAMMER filesystem to do either of the following.
55  * If vol_version is <= 6, do crc32() as it did in the past.
56  * If vol_version is >= 7, do iscsi_crc32().
57  *
58  * hammer_crc_test_xxx() first tests CRC using hammer_datacrc().
59  * If vol_version is <= 6, it's likely to match crc32().
60  * If vol_version is >= 7 and was created using the current newfs_hammer,
61  * it's likely to match iscsi_crc32().  If it's been upgraded, the CRC
62  * generated by old version(s) doesn't match iscsi_crc32(), and requires
63  * retry.  This means there is overhead until CRCs for majority of data
64  * and metadata are upgraded.
65  *
66  * Once the volume is upgraded, all the newly created data and metadata
67  * are initialized with version 7 CRC.  Reblocking the filesystem can
68  * upgrade CRCs upon moving data and metadata.
69  */
70 
71 #define hammer_datacrc(vol_version, buf, size)			\
72 	(((vol_version) >= HAMMER_VOL_VERSION_SEVEN) ?		\
73 	 iscsi_crc32(buf, size) : crc32(buf, size))
74 
75 #define hammer_datacrc_ext(vol_version, buf, size, ocrc)	\
76 	(((vol_version) >= HAMMER_VOL_VERSION_SEVEN) ?		\
77 	 iscsi_crc32_ext(buf, size, ocrc) : crc32_ext(buf, size, ocrc))
78 
79 /*
80  * Blockmap
81  */
82 static __inline hammer_crc_t
83 hammer_crc_get_blockmap(uint32_t vol_version, hammer_blockmap_t blockmap)
84 {
85 	return(hammer_datacrc(vol_version, blockmap, HAMMER_BLOCKMAP_CRCSIZE));
86 }
87 
88 static __inline hammer_crc_t
89 __hammer_crc_get_blockmap(hammer_blockmap_t blockmap)
90 {
91 	return(crc32(blockmap, HAMMER_BLOCKMAP_CRCSIZE));
92 }
93 
94 static __inline void
95 hammer_crc_set_blockmap(uint32_t vol_version, hammer_blockmap_t blockmap)
96 {
97 	blockmap->entry_crc = hammer_crc_get_blockmap(vol_version, blockmap);
98 }
99 
100 static __inline int
101 hammer_crc_test_blockmap(uint32_t vol_version, hammer_blockmap_t blockmap)
102 {
103 	if (blockmap->entry_crc == hammer_crc_get_blockmap(vol_version, blockmap))
104 		return(1);
105 	if (vol_version >= HAMMER_VOL_VERSION_SEVEN) {
106 		if (blockmap->entry_crc == __hammer_crc_get_blockmap(blockmap))
107 			return(1);
108 	}
109 	return(0);
110 }
111 
112 /*
113  * Layer1
114  */
115 static __inline hammer_crc_t
116 hammer_crc_get_layer1(uint32_t vol_version, hammer_blockmap_layer1_t layer1)
117 {
118 	return(hammer_datacrc(vol_version, layer1, HAMMER_LAYER1_CRCSIZE));
119 }
120 
121 static __inline hammer_crc_t
122 __hammer_crc_get_layer1(hammer_blockmap_layer1_t layer1)
123 {
124 	return(crc32(layer1, HAMMER_LAYER1_CRCSIZE));
125 }
126 
127 static __inline void
128 hammer_crc_set_layer1(uint32_t vol_version, hammer_blockmap_layer1_t layer1)
129 {
130 	layer1->layer1_crc = hammer_crc_get_layer1(vol_version, layer1);
131 }
132 
133 static __inline int
134 hammer_crc_test_layer1(uint32_t vol_version, hammer_blockmap_layer1_t layer1)
135 {
136 	if (layer1->layer1_crc == hammer_crc_get_layer1(vol_version, layer1))
137 		return(1);
138 	if (vol_version >= HAMMER_VOL_VERSION_SEVEN) {
139 		if (layer1->layer1_crc == __hammer_crc_get_layer1(layer1))
140 			return(1);
141 	}
142 	return(0);
143 }
144 
145 /*
146  * Layer2
147  */
148 static __inline hammer_crc_t
149 hammer_crc_get_layer2(uint32_t vol_version, hammer_blockmap_layer2_t layer2)
150 {
151 	return(hammer_datacrc(vol_version, layer2, HAMMER_LAYER2_CRCSIZE));
152 }
153 
154 static __inline hammer_crc_t
155 __hammer_crc_get_layer2(hammer_blockmap_layer2_t layer2)
156 {
157 	return(crc32(layer2, HAMMER_LAYER2_CRCSIZE));
158 }
159 
160 static __inline void
161 hammer_crc_set_layer2(uint32_t vol_version, hammer_blockmap_layer2_t layer2)
162 {
163 	layer2->entry_crc = hammer_crc_get_layer2(vol_version, layer2);
164 }
165 
166 static __inline int
167 hammer_crc_test_layer2(uint32_t vol_version, hammer_blockmap_layer2_t layer2)
168 {
169 	if (layer2->entry_crc == hammer_crc_get_layer2(vol_version, layer2))
170 		return(1);
171 	if (vol_version >= HAMMER_VOL_VERSION_SEVEN) {
172 		if (layer2->entry_crc == __hammer_crc_get_layer2(layer2))
173 			return(1);
174 	}
175 	return(0);
176 }
177 
178 /*
179  * Volume
180  */
181 static __inline hammer_crc_t
182 hammer_crc_get_volume(uint32_t vol_version, hammer_volume_ondisk_t ondisk)
183 {
184 	return(hammer_datacrc(vol_version, ondisk, HAMMER_VOL_CRCSIZE1) ^
185 		hammer_datacrc(vol_version, &ondisk->vol_crc + 1, HAMMER_VOL_CRCSIZE2));
186 }
187 
188 static __inline hammer_crc_t
189 __hammer_crc_get_volume(hammer_volume_ondisk_t ondisk)
190 {
191 	return(crc32(ondisk, HAMMER_VOL_CRCSIZE1) ^
192 		crc32(&ondisk->vol_crc + 1, HAMMER_VOL_CRCSIZE2));
193 }
194 
195 static __inline void
196 hammer_crc_set_volume(uint32_t vol_version, hammer_volume_ondisk_t ondisk)
197 {
198 	ondisk->vol_crc = hammer_crc_get_volume(vol_version, ondisk);
199 }
200 
201 static __inline int
202 hammer_crc_test_volume(uint32_t vol_version, hammer_volume_ondisk_t ondisk)
203 {
204 	if (ondisk->vol_crc == hammer_crc_get_volume(vol_version, ondisk))
205 		return(1);
206 	if (vol_version >= HAMMER_VOL_VERSION_SEVEN) {
207 		if (ondisk->vol_crc == __hammer_crc_get_volume(ondisk))
208 			return(1);
209 	}
210 	return(0);
211 }
212 
213 /*
214  * FIFO head
215  */
216 static __inline hammer_crc_t
217 hammer_crc_get_fifo_head(uint32_t vol_version, hammer_fifo_head_t head, int bytes)
218 {
219 	return(hammer_datacrc(vol_version, head, HAMMER_FIFO_HEAD_CRCOFF) ^
220 		hammer_datacrc(vol_version, head + 1, bytes - sizeof(*head)));
221 }
222 
223 static __inline hammer_crc_t
224 __hammer_crc_get_fifo_head(hammer_fifo_head_t head, int bytes)
225 {
226 	return(crc32(head, HAMMER_FIFO_HEAD_CRCOFF) ^
227 		crc32(head + 1, bytes - sizeof(*head)));
228 }
229 
230 static __inline void
231 hammer_crc_set_fifo_head(uint32_t vol_version, hammer_fifo_head_t head, int bytes)
232 {
233 	head->hdr_crc = hammer_crc_get_fifo_head(vol_version, head, bytes);
234 }
235 
236 static __inline int
237 hammer_crc_test_fifo_head(uint32_t vol_version, hammer_fifo_head_t head, int bytes)
238 {
239 	if (head->hdr_crc == hammer_crc_get_fifo_head(vol_version, head, bytes))
240 		return(1);
241 	if (vol_version >= HAMMER_VOL_VERSION_SEVEN) {
242 		if (head->hdr_crc == __hammer_crc_get_fifo_head(head, bytes))
243 			return(1);
244 	}
245 	return(0);
246 }
247 
248 /*
249  * B-Tree node
250  */
251 static __inline hammer_crc_t
252 hammer_crc_get_btree(uint32_t vol_version, hammer_node_ondisk_t node)
253 {
254 	return(hammer_datacrc(vol_version, &node->crc + 1, HAMMER_BTREE_CRCSIZE));
255 }
256 
257 static __inline hammer_crc_t
258 __hammer_crc_get_btree(hammer_node_ondisk_t node)
259 {
260 	return(crc32(&node->crc + 1, HAMMER_BTREE_CRCSIZE));
261 }
262 
263 static __inline void
264 hammer_crc_set_btree(uint32_t vol_version, hammer_node_ondisk_t node)
265 {
266 	node->crc = hammer_crc_get_btree(vol_version, node);
267 }
268 
269 static __inline int
270 hammer_crc_test_btree(uint32_t vol_version, hammer_node_ondisk_t node)
271 {
272 	if (node->crc == hammer_crc_get_btree(vol_version, node))
273 		return(1);
274 	if (vol_version >= HAMMER_VOL_VERSION_SEVEN) {
275 		if (node->crc == __hammer_crc_get_btree(node))
276 			return(1);
277 	}
278 	return(0);
279 }
280 
281 /*
282  * B-Tree leaf elm
283  */
284 /*
285  * Get the leaf->data_crc field.  Deal with any special cases given
286  * a generic B-Tree leaf element and its data.
287  *
288  * NOTE: Inode-data: the atime and mtime fields are not CRCd,
289  *       allowing them to be updated in-place.
290  */
291 static __inline hammer_crc_t
292 hammer_crc_get_leaf(uint32_t vol_version, void *data, hammer_btree_leaf_elm_t leaf)
293 {
294 	hammer_crc_t crc;
295 
296 	if (leaf->data_len == 0)
297 		return(0);
298 
299 	switch(leaf->base.rec_type) {
300 	case HAMMER_RECTYPE_INODE:
301 		if (leaf->data_len != sizeof(struct hammer_inode_data))
302 			return(0);  /* This shouldn't happen */
303 		crc = hammer_datacrc(vol_version, data, HAMMER_INODE_CRCSIZE);
304 		break;
305 	default:
306 		crc = hammer_datacrc(vol_version, data, leaf->data_len);
307 		break;
308 	}
309 	return(crc);
310 }
311 
312 static __inline hammer_crc_t
313 __hammer_crc_get_leaf(void *data, hammer_btree_leaf_elm_t leaf)
314 {
315 	hammer_crc_t crc;
316 
317 	if (leaf->data_len == 0)
318 		return(0);
319 
320 	switch(leaf->base.rec_type) {
321 	case HAMMER_RECTYPE_INODE:
322 		if (leaf->data_len != sizeof(struct hammer_inode_data))
323 			return(0);  /* This shouldn't happen */
324 		crc = crc32(data, HAMMER_INODE_CRCSIZE);
325 		break;
326 	default:
327 		crc = crc32(data, leaf->data_len);
328 		break;
329 	}
330 	return(crc);
331 }
332 
333 static __inline void
334 hammer_crc_set_leaf(uint32_t vol_version, void *data, hammer_btree_leaf_elm_t leaf)
335 {
336 #ifdef _KERNEL
337 #ifdef INVARIANTS
338 	if (leaf->data_len && leaf->base.rec_type == HAMMER_RECTYPE_INODE)
339 		KKASSERT(leaf->data_len == sizeof(struct hammer_inode_data));
340 #endif
341 #endif
342 	leaf->data_crc = hammer_crc_get_leaf(vol_version, data, leaf);
343 }
344 
345 static __inline int
346 hammer_crc_test_leaf(uint32_t vol_version, void *data, hammer_btree_leaf_elm_t leaf)
347 {
348 	if (leaf->data_crc == hammer_crc_get_leaf(vol_version, data, leaf))
349 		return(1);
350 	if (vol_version >= HAMMER_VOL_VERSION_SEVEN) {
351 		if (leaf->data_crc == __hammer_crc_get_leaf(data, leaf))
352 			return(1);
353 	}
354 	return(0);
355 }
356 
357 /*
358  * Mirror record head
359  */
360 static __inline hammer_crc_t
361 hammer_crc_get_mrec_head(struct hammer_ioc_mrecord_head *head, int bytes)
362 {
363 	return(crc32(&head->rec_size, bytes - HAMMER_MREC_CRCOFF));
364 }
365 
366 static __inline void
367 hammer_crc_set_mrec_head(struct hammer_ioc_mrecord_head *head, int bytes)
368 {
369 	head->rec_crc = hammer_crc_get_mrec_head(head, bytes);
370 }
371 
372 static __inline int
373 hammer_crc_test_mrec_head(struct hammer_ioc_mrecord_head *head, int bytes)
374 {
375 	return(head->rec_crc == hammer_crc_get_mrec_head(head, bytes));
376 }
377 
378 #endif /* !VFS_HAMMER_CRC_H_ */
379