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 void 89 hammer_crc_set_blockmap(uint32_t vol_version, hammer_blockmap_t blockmap) 90 { 91 blockmap->entry_crc = hammer_crc_get_blockmap(vol_version, blockmap); 92 } 93 94 static __inline int 95 hammer_crc_test_blockmap(uint32_t vol_version, hammer_blockmap_t blockmap) 96 { 97 if (blockmap->entry_crc == hammer_crc_get_blockmap(vol_version, blockmap)) 98 return(1); 99 if (vol_version >= HAMMER_VOL_VERSION_SEVEN) { 100 if (blockmap->entry_crc == hammer_crc_get_blockmap( 101 HAMMER_VOL_VERSION_SIX, blockmap)) 102 return(1); 103 } 104 return(0); 105 } 106 107 /* 108 * Layer1 109 */ 110 static __inline hammer_crc_t 111 hammer_crc_get_layer1(uint32_t vol_version, hammer_blockmap_layer1_t layer1) 112 { 113 return(hammer_datacrc(vol_version, layer1, HAMMER_LAYER1_CRCSIZE)); 114 } 115 116 static __inline void 117 hammer_crc_set_layer1(uint32_t vol_version, hammer_blockmap_layer1_t layer1) 118 { 119 layer1->layer1_crc = hammer_crc_get_layer1(vol_version, layer1); 120 } 121 122 static __inline int 123 hammer_crc_test_layer1(uint32_t vol_version, hammer_blockmap_layer1_t layer1) 124 { 125 if (layer1->layer1_crc == hammer_crc_get_layer1(vol_version, layer1)) 126 return(1); 127 if (vol_version >= HAMMER_VOL_VERSION_SEVEN) { 128 if (layer1->layer1_crc == hammer_crc_get_layer1( 129 HAMMER_VOL_VERSION_SIX, layer1)) 130 return(1); 131 } 132 return(0); 133 } 134 135 /* 136 * Layer2 137 */ 138 static __inline hammer_crc_t 139 hammer_crc_get_layer2(uint32_t vol_version, hammer_blockmap_layer2_t layer2) 140 { 141 return(hammer_datacrc(vol_version, layer2, HAMMER_LAYER2_CRCSIZE)); 142 } 143 144 static __inline void 145 hammer_crc_set_layer2(uint32_t vol_version, hammer_blockmap_layer2_t layer2) 146 { 147 layer2->entry_crc = hammer_crc_get_layer2(vol_version, layer2); 148 } 149 150 static __inline int 151 hammer_crc_test_layer2(uint32_t vol_version, hammer_blockmap_layer2_t layer2) 152 { 153 if (layer2->entry_crc == hammer_crc_get_layer2(vol_version, layer2)) 154 return(1); 155 if (vol_version >= HAMMER_VOL_VERSION_SEVEN) { 156 if (layer2->entry_crc == hammer_crc_get_layer2( 157 HAMMER_VOL_VERSION_SIX, layer2)) 158 return(1); 159 } 160 return(0); 161 } 162 163 /* 164 * Volume 165 */ 166 static __inline hammer_crc_t 167 hammer_crc_get_volume(uint32_t vol_version, hammer_volume_ondisk_t ondisk) 168 { 169 return(hammer_datacrc(vol_version, ondisk, HAMMER_VOL_CRCSIZE1) ^ 170 hammer_datacrc(vol_version, &ondisk->vol_crc + 1, HAMMER_VOL_CRCSIZE2)); 171 } 172 173 static __inline void 174 hammer_crc_set_volume(uint32_t vol_version, hammer_volume_ondisk_t ondisk) 175 { 176 ondisk->vol_crc = hammer_crc_get_volume(vol_version, ondisk); 177 } 178 179 static __inline int 180 hammer_crc_test_volume(uint32_t vol_version, hammer_volume_ondisk_t ondisk) 181 { 182 if (ondisk->vol_crc == hammer_crc_get_volume(vol_version, ondisk)) 183 return(1); 184 if (vol_version >= HAMMER_VOL_VERSION_SEVEN) { 185 if (ondisk->vol_crc == hammer_crc_get_volume( 186 HAMMER_VOL_VERSION_SIX, ondisk)) 187 return(1); 188 } 189 return(0); 190 } 191 192 /* 193 * FIFO head 194 */ 195 static __inline hammer_crc_t 196 hammer_crc_get_fifo_head(uint32_t vol_version, hammer_fifo_head_t head, int bytes) 197 { 198 return(hammer_datacrc(vol_version, head, HAMMER_FIFO_HEAD_CRCOFF) ^ 199 hammer_datacrc(vol_version, head + 1, bytes - sizeof(*head))); 200 } 201 202 static __inline void 203 hammer_crc_set_fifo_head(uint32_t vol_version, hammer_fifo_head_t head, int bytes) 204 { 205 head->hdr_crc = hammer_crc_get_fifo_head(vol_version, head, bytes); 206 } 207 208 static __inline int 209 hammer_crc_test_fifo_head(uint32_t vol_version, hammer_fifo_head_t head, int bytes) 210 { 211 if (head->hdr_crc == hammer_crc_get_fifo_head(vol_version, head, bytes)) 212 return(1); 213 if (vol_version >= HAMMER_VOL_VERSION_SEVEN) { 214 if (head->hdr_crc == hammer_crc_get_fifo_head( 215 HAMMER_VOL_VERSION_SIX, head, bytes)) 216 return(1); 217 } 218 return(0); 219 } 220 221 /* 222 * B-Tree node 223 */ 224 static __inline hammer_crc_t 225 hammer_crc_get_btree(uint32_t vol_version, hammer_node_ondisk_t node) 226 { 227 return(hammer_datacrc(vol_version, &node->crc + 1, HAMMER_BTREE_CRCSIZE)); 228 } 229 230 static __inline void 231 hammer_crc_set_btree(uint32_t vol_version, hammer_node_ondisk_t node) 232 { 233 node->crc = hammer_crc_get_btree(vol_version, node); 234 } 235 236 static __inline int 237 hammer_crc_test_btree(uint32_t vol_version, hammer_node_ondisk_t node) 238 { 239 if (node->crc == hammer_crc_get_btree(vol_version, node)) 240 return(1); 241 if (vol_version >= HAMMER_VOL_VERSION_SEVEN) { 242 if (node->crc == hammer_crc_get_btree( 243 HAMMER_VOL_VERSION_SIX, node)) 244 return(1); 245 } 246 return(0); 247 } 248 249 /* 250 * B-Tree leaf elm 251 */ 252 /* 253 * Get the leaf->data_crc field. Deal with any special cases given 254 * a generic B-Tree leaf element and its data. 255 * 256 * NOTE: Inode-data: the atime and mtime fields are not CRCd, 257 * allowing them to be updated in-place. 258 */ 259 static __inline hammer_crc_t 260 hammer_crc_get_leaf(uint32_t vol_version, void *data, hammer_btree_leaf_elm_t leaf) 261 { 262 hammer_crc_t crc; 263 264 if (leaf->data_len == 0) 265 return(0); 266 267 switch(leaf->base.rec_type) { 268 case HAMMER_RECTYPE_INODE: 269 if (leaf->data_len != sizeof(struct hammer_inode_data)) 270 return(0); /* This shouldn't happen */ 271 crc = hammer_datacrc(vol_version, data, HAMMER_INODE_CRCSIZE); 272 break; 273 default: 274 crc = hammer_datacrc(vol_version, data, leaf->data_len); 275 break; 276 } 277 return(crc); 278 } 279 280 static __inline void 281 hammer_crc_set_leaf(uint32_t vol_version, void *data, hammer_btree_leaf_elm_t leaf) 282 { 283 #ifdef _KERNEL 284 #ifdef INVARIANTS 285 if (leaf->data_len && leaf->base.rec_type == HAMMER_RECTYPE_INODE) 286 KKASSERT(leaf->data_len == sizeof(struct hammer_inode_data)); 287 #endif 288 #endif 289 leaf->data_crc = hammer_crc_get_leaf(vol_version, data, leaf); 290 } 291 292 static __inline int 293 hammer_crc_test_leaf(uint32_t vol_version, void *data, hammer_btree_leaf_elm_t leaf) 294 { 295 if (leaf->data_crc == hammer_crc_get_leaf(vol_version, data, leaf)) 296 return(1); 297 if (vol_version >= HAMMER_VOL_VERSION_SEVEN) { 298 if (leaf->data_crc == hammer_crc_get_leaf( 299 HAMMER_VOL_VERSION_SIX, data, leaf)) 300 return(1); 301 } 302 return(0); 303 } 304 305 /* 306 * Mirror record head 307 */ 308 static __inline hammer_crc_t 309 hammer_crc_get_mrec_head(struct hammer_ioc_mrecord_head *head, int bytes) 310 { 311 return(crc32(&head->rec_size, bytes - HAMMER_MREC_CRCOFF)); 312 } 313 314 static __inline void 315 hammer_crc_set_mrec_head(struct hammer_ioc_mrecord_head *head, int bytes) 316 { 317 head->rec_crc = hammer_crc_get_mrec_head(head, bytes); 318 } 319 320 static __inline int 321 hammer_crc_test_mrec_head(struct hammer_ioc_mrecord_head *head, int bytes) 322 { 323 return(head->rec_crc == hammer_crc_get_mrec_head(head, bytes)); 324 } 325 326 #endif /* !VFS_HAMMER_CRC_H_ */ 327