1 /* 2 * Copyright (c) 2007-2008 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 * $DragonFly: src/sys/vfs/hammer/hammer_subs.c,v 1.35 2008/10/15 22:38:37 dillon Exp $ 35 */ 36 /* 37 * HAMMER structural locking 38 */ 39 40 #include "hammer.h" 41 #include <sys/dirent.h> 42 43 void 44 hammer_lock_ex_ident(struct hammer_lock *lock, const char *ident) 45 { 46 thread_t td = curthread; 47 u_int lv; 48 u_int nlv; 49 50 KKASSERT(lock->refs > 0); 51 for (;;) { 52 lv = lock->lockval; 53 54 if (lv == 0) { 55 nlv = 1 | HAMMER_LOCKF_EXCLUSIVE; 56 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 57 lock->owner = td; 58 break; 59 } 60 } else if ((lv & HAMMER_LOCKF_EXCLUSIVE) && lock->owner == td) { 61 nlv = (lv + 1); 62 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) 63 break; 64 } else { 65 if (hammer_debug_locks) { 66 kprintf("hammer_lock_ex: held by %p\n", 67 lock->owner); 68 } 69 nlv = lv | HAMMER_LOCKF_WANTED; 70 ++hammer_contention_count; 71 tsleep_interlock(lock, 0); 72 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 73 tsleep(lock, PINTERLOCKED, ident, 0); 74 if (hammer_debug_locks) 75 kprintf("hammer_lock_ex: try again\n"); 76 } 77 } 78 } 79 } 80 81 /* 82 * Try to obtain an exclusive lock 83 */ 84 int 85 hammer_lock_ex_try(struct hammer_lock *lock) 86 { 87 thread_t td = curthread; 88 int error; 89 u_int lv; 90 u_int nlv; 91 92 KKASSERT(lock->refs > 0); 93 for (;;) { 94 lv = lock->lockval; 95 96 if (lv == 0) { 97 nlv = 1 | HAMMER_LOCKF_EXCLUSIVE; 98 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 99 lock->owner = td; 100 error = 0; 101 break; 102 } 103 } else if ((lv & HAMMER_LOCKF_EXCLUSIVE) && lock->owner == td) { 104 nlv = (lv + 1); 105 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 106 error = 0; 107 break; 108 } 109 } else { 110 error = EAGAIN; 111 break; 112 } 113 } 114 return (error); 115 } 116 117 /* 118 * Obtain a shared lock 119 * 120 * We do not give pending exclusive locks priority over shared locks as 121 * doing so could lead to a deadlock. 122 */ 123 void 124 hammer_lock_sh(struct hammer_lock *lock) 125 { 126 thread_t td = curthread; 127 u_int lv; 128 u_int nlv; 129 130 KKASSERT(lock->refs > 0); 131 for (;;) { 132 lv = lock->lockval; 133 134 if ((lv & HAMMER_LOCKF_EXCLUSIVE) == 0) { 135 nlv = (lv + 1); 136 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) 137 break; 138 } else if (lock->owner == td) { 139 /* 140 * Disallowed case, drop into kernel debugger for 141 * now. A cont continues w/ an exclusive lock. 142 */ 143 nlv = (lv + 1); 144 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 145 if (hammer_debug_critical) 146 Debugger("hammer_lock_sh: holding ex"); 147 break; 148 } 149 } else { 150 nlv = lv | HAMMER_LOCKF_WANTED; 151 ++hammer_contention_count; 152 tsleep_interlock(lock, 0); 153 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 154 tsleep(lock, PINTERLOCKED, "hmrlck", 0); 155 } 156 } 157 } 158 } 159 160 int 161 hammer_lock_sh_try(struct hammer_lock *lock) 162 { 163 thread_t td = curthread; 164 u_int lv; 165 u_int nlv; 166 int error; 167 168 KKASSERT(lock->refs > 0); 169 for (;;) { 170 lv = lock->lockval; 171 172 if ((lv & HAMMER_LOCKF_EXCLUSIVE) == 0) { 173 nlv = (lv + 1); 174 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 175 error = 0; 176 break; 177 } 178 } else if (lock->owner == td) { 179 /* 180 * Disallowed case, drop into kernel debugger for 181 * now. A cont continues w/ an exclusive lock. 182 */ 183 nlv = (lv + 1); 184 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 185 if (hammer_debug_critical) 186 Debugger("hammer_lock_sh: holding ex"); 187 error = 0; 188 break; 189 } 190 } else { 191 error = EAGAIN; 192 break; 193 } 194 } 195 return (error); 196 } 197 198 /* 199 * Upgrade a shared lock to an exclusively held lock. This function will 200 * return EDEADLK If there is more then one shared holder. 201 * 202 * No error occurs and no action is taken if the lock is already exclusively 203 * held by the caller. If the lock is not held at all or held exclusively 204 * by someone else, this function will panic. 205 */ 206 int 207 hammer_lock_upgrade(struct hammer_lock *lock) 208 { 209 thread_t td = curthread; 210 u_int lv; 211 u_int nlv; 212 int error; 213 214 for (;;) { 215 lv = lock->lockval; 216 217 if ((lv & ~HAMMER_LOCKF_WANTED) == 1) { 218 nlv = lv | HAMMER_LOCKF_EXCLUSIVE; 219 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 220 lock->owner = td; 221 error = 0; 222 break; 223 } 224 } else if (lv & HAMMER_LOCKF_EXCLUSIVE) { 225 if (lock->owner != curthread) 226 panic("hammer_lock_upgrade: illegal state"); 227 error = 0; 228 break; 229 } else if ((lv & ~HAMMER_LOCKF_WANTED) == 0) { 230 panic("hammer_lock_upgrade: lock is not held"); 231 /* NOT REACHED */ 232 error = EDEADLK; 233 break; 234 } else { 235 error = EDEADLK; 236 break; 237 } 238 } 239 return (error); 240 } 241 242 /* 243 * Downgrade an exclusively held lock to a shared lock. 244 */ 245 void 246 hammer_lock_downgrade(struct hammer_lock *lock) 247 { 248 thread_t td __debugvar = curthread; 249 u_int lv; 250 u_int nlv; 251 252 KKASSERT((lock->lockval & ~HAMMER_LOCKF_WANTED) == 253 (HAMMER_LOCKF_EXCLUSIVE | 1)); 254 KKASSERT(lock->owner == td); 255 256 /* 257 * NOTE: Must clear owner before releasing exclusivity 258 */ 259 lock->owner = NULL; 260 261 for (;;) { 262 lv = lock->lockval; 263 nlv = lv & ~(HAMMER_LOCKF_EXCLUSIVE | HAMMER_LOCKF_WANTED); 264 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 265 if (lv & HAMMER_LOCKF_WANTED) 266 wakeup(lock); 267 break; 268 } 269 } 270 } 271 272 void 273 hammer_unlock(struct hammer_lock *lock) 274 { 275 thread_t td __debugvar = curthread; 276 u_int lv; 277 u_int nlv; 278 279 lv = lock->lockval; 280 KKASSERT(lv != 0); 281 if (lv & HAMMER_LOCKF_EXCLUSIVE) 282 KKASSERT(lock->owner == td); 283 284 for (;;) { 285 lv = lock->lockval; 286 nlv = lv & ~(HAMMER_LOCKF_EXCLUSIVE | HAMMER_LOCKF_WANTED); 287 if (nlv > 1) { 288 nlv = lv - 1; 289 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) 290 break; 291 } else if (nlv == 1) { 292 nlv = 0; 293 if (lv & HAMMER_LOCKF_EXCLUSIVE) 294 lock->owner = NULL; 295 if (atomic_cmpset_int(&lock->lockval, lv, nlv)) { 296 if (lv & HAMMER_LOCKF_WANTED) 297 wakeup(lock); 298 break; 299 } 300 } else { 301 panic("hammer_unlock: lock %p is not held", lock); 302 } 303 } 304 } 305 306 /* 307 * The calling thread must be holding a shared or exclusive lock. 308 * Returns < 0 if lock is held shared, and > 0 if held exlusively. 309 */ 310 int 311 hammer_lock_status(struct hammer_lock *lock) 312 { 313 u_int lv = lock->lockval; 314 315 if (lv & HAMMER_LOCKF_EXCLUSIVE) 316 return(1); 317 else if (lv) 318 return(-1); 319 panic("hammer_lock_status: lock must be held: %p", lock); 320 } 321 322 void 323 hammer_ref(struct hammer_lock *lock) 324 { 325 KKASSERT(lock->refs >= 0); 326 atomic_add_int(&lock->refs, 1); 327 } 328 329 void 330 hammer_unref(struct hammer_lock *lock) 331 { 332 KKASSERT(lock->refs > 0); 333 atomic_subtract_int(&lock->refs, 1); 334 } 335 336 /* 337 * The sync_lock must be held when doing any modifying operations on 338 * meta-data. It does not have to be held when modifying non-meta-data buffers 339 * (backend or frontend). 340 * 341 * The flusher holds the lock exclusively while all other consumers hold it 342 * shared. All modifying operations made while holding the lock are atomic 343 * in that they will be made part of the same flush group. 344 * 345 * Due to the atomicy requirement deadlock recovery code CANNOT release the 346 * sync lock, nor can we give pending exclusive sync locks priority over 347 * a shared sync lock as this could lead to a 3-way deadlock. 348 */ 349 void 350 hammer_sync_lock_ex(hammer_transaction_t trans) 351 { 352 ++trans->sync_lock_refs; 353 hammer_lock_ex(&trans->hmp->sync_lock); 354 } 355 356 void 357 hammer_sync_lock_sh(hammer_transaction_t trans) 358 { 359 ++trans->sync_lock_refs; 360 hammer_lock_sh(&trans->hmp->sync_lock); 361 } 362 363 int 364 hammer_sync_lock_sh_try(hammer_transaction_t trans) 365 { 366 int error; 367 368 ++trans->sync_lock_refs; 369 if ((error = hammer_lock_sh_try(&trans->hmp->sync_lock)) != 0) 370 --trans->sync_lock_refs; 371 return (error); 372 } 373 374 void 375 hammer_sync_unlock(hammer_transaction_t trans) 376 { 377 --trans->sync_lock_refs; 378 hammer_unlock(&trans->hmp->sync_lock); 379 } 380 381 /* 382 * Misc 383 */ 384 u_int32_t 385 hammer_to_unix_xid(uuid_t *uuid) 386 { 387 return(*(u_int32_t *)&uuid->node[2]); 388 } 389 390 void 391 hammer_guid_to_uuid(uuid_t *uuid, u_int32_t guid) 392 { 393 bzero(uuid, sizeof(*uuid)); 394 *(u_int32_t *)&uuid->node[2] = guid; 395 } 396 397 void 398 hammer_time_to_timespec(u_int64_t xtime, struct timespec *ts) 399 { 400 ts->tv_sec = (unsigned long)(xtime / 1000000); 401 ts->tv_nsec = (unsigned int)(xtime % 1000000) * 1000L; 402 } 403 404 u_int64_t 405 hammer_timespec_to_time(struct timespec *ts) 406 { 407 u_int64_t xtime; 408 409 xtime = (unsigned)(ts->tv_nsec / 1000) + 410 (unsigned long)ts->tv_sec * 1000000ULL; 411 return(xtime); 412 } 413 414 415 /* 416 * Convert a HAMMER filesystem object type to a vnode type 417 */ 418 enum vtype 419 hammer_get_vnode_type(u_int8_t obj_type) 420 { 421 switch(obj_type) { 422 case HAMMER_OBJTYPE_DIRECTORY: 423 return(VDIR); 424 case HAMMER_OBJTYPE_REGFILE: 425 return(VREG); 426 case HAMMER_OBJTYPE_DBFILE: 427 return(VDATABASE); 428 case HAMMER_OBJTYPE_FIFO: 429 return(VFIFO); 430 case HAMMER_OBJTYPE_SOCKET: 431 return(VSOCK); 432 case HAMMER_OBJTYPE_CDEV: 433 return(VCHR); 434 case HAMMER_OBJTYPE_BDEV: 435 return(VBLK); 436 case HAMMER_OBJTYPE_SOFTLINK: 437 return(VLNK); 438 default: 439 return(VBAD); 440 } 441 /* not reached */ 442 } 443 444 int 445 hammer_get_dtype(u_int8_t obj_type) 446 { 447 switch(obj_type) { 448 case HAMMER_OBJTYPE_DIRECTORY: 449 return(DT_DIR); 450 case HAMMER_OBJTYPE_REGFILE: 451 return(DT_REG); 452 case HAMMER_OBJTYPE_DBFILE: 453 return(DT_DBF); 454 case HAMMER_OBJTYPE_FIFO: 455 return(DT_FIFO); 456 case HAMMER_OBJTYPE_SOCKET: 457 return(DT_SOCK); 458 case HAMMER_OBJTYPE_CDEV: 459 return(DT_CHR); 460 case HAMMER_OBJTYPE_BDEV: 461 return(DT_BLK); 462 case HAMMER_OBJTYPE_SOFTLINK: 463 return(DT_LNK); 464 default: 465 return(DT_UNKNOWN); 466 } 467 /* not reached */ 468 } 469 470 u_int8_t 471 hammer_get_obj_type(enum vtype vtype) 472 { 473 switch(vtype) { 474 case VDIR: 475 return(HAMMER_OBJTYPE_DIRECTORY); 476 case VREG: 477 return(HAMMER_OBJTYPE_REGFILE); 478 case VDATABASE: 479 return(HAMMER_OBJTYPE_DBFILE); 480 case VFIFO: 481 return(HAMMER_OBJTYPE_FIFO); 482 case VSOCK: 483 return(HAMMER_OBJTYPE_SOCKET); 484 case VCHR: 485 return(HAMMER_OBJTYPE_CDEV); 486 case VBLK: 487 return(HAMMER_OBJTYPE_BDEV); 488 case VLNK: 489 return(HAMMER_OBJTYPE_SOFTLINK); 490 default: 491 return(HAMMER_OBJTYPE_UNKNOWN); 492 } 493 /* not reached */ 494 } 495 496 /* 497 * Return flags for hammer_delete_at_cursor() 498 */ 499 int 500 hammer_nohistory(hammer_inode_t ip) 501 { 502 if (ip->hmp->hflags & HMNT_NOHISTORY) 503 return(HAMMER_DELETE_DESTROY); 504 if (ip->ino_data.uflags & (SF_NOHISTORY|UF_NOHISTORY)) 505 return(HAMMER_DELETE_DESTROY); 506 return(0); 507 } 508 509 /* 510 * ALGORITHM VERSION 1: 511 * Return a namekey hash. The 64 bit namekey hash consists of a 32 bit 512 * crc in the MSB and 0 in the LSB. The caller will use the low 32 bits 513 * to generate a unique key and will scan all entries with the same upper 514 * 32 bits when issuing a lookup. 515 * 516 * 0hhhhhhhhhhhhhhh hhhhhhhhhhhhhhhh 0000000000000000 0000000000000000 517 * 518 * ALGORITHM VERSION 2: 519 * 520 * The 64 bit hash key is generated from the following components. The 521 * first three characters are encoded as 5-bit quantities, the middle 522 * N characters are hashed into a 6 bit quantity, and the last two 523 * characters are encoded as 5-bit quantities. A 32 bit hash of the 524 * entire filename is encoded in the low 32 bits. Bit 0 is set to 525 * 0 to guarantee us a 2^24 bit iteration space. 526 * 527 * 0aaaaabbbbbccccc mmmmmmyyyyyzzzzz hhhhhhhhhhhhhhhh hhhhhhhhhhhhhhh0 528 * 529 * This gives us a domain sort for the first three characters, the last 530 * two characters, and breaks the middle space into 64 random domains. 531 * The domain sort folds upper case, lower case, digits, and punctuation 532 * spaces together, the idea being the filenames tend to not be a mix 533 * of those domains. 534 * 535 * The 64 random domains act as a sub-sort for the middle characters 536 * but may cause a random seek. If the filesystem is being accessed 537 * in sorted order we should tend to get very good linearity for most 538 * filenames and devolve into more random seeks otherwise. 539 * 540 * We strip bit 63 in order to provide a positive key, this way a seek 541 * offset of 0 will represent the base of the directory. 542 * 543 * This function can never return 0. We use the MSB-0 space to synthesize 544 * artificial directory entries such as "." and "..". 545 */ 546 int64_t 547 hammer_directory_namekey(hammer_inode_t dip, const void *name, int len, 548 u_int32_t *max_iterationsp) 549 { 550 int64_t key; 551 int32_t crcx; 552 const char *aname = name; 553 554 switch (dip->ino_data.cap_flags & HAMMER_INODE_CAP_DIRHASH_MASK) { 555 case HAMMER_INODE_CAP_DIRHASH_ALG0: 556 key = (int64_t)(crc32(aname, len) & 0x7FFFFFFF) << 32; 557 if (key == 0) 558 key |= 0x100000000LL; 559 *max_iterationsp = 0xFFFFFFFFU; 560 break; 561 case HAMMER_INODE_CAP_DIRHASH_ALG1: 562 key = (u_int32_t)crc32(aname, len) & 0xFFFFFFFEU; 563 564 switch(len) { 565 default: 566 crcx = crc32(aname + 3, len - 5); 567 crcx = crcx ^ (crcx >> 6) ^ (crcx >> 12); 568 key |= (int64_t)(crcx & 0x3F) << 42; 569 /* fall through */ 570 case 5: 571 case 4: 572 /* fall through */ 573 case 3: 574 key |= ((int64_t)(aname[2] & 0x1F) << 48); 575 /* fall through */ 576 case 2: 577 key |= ((int64_t)(aname[1] & 0x1F) << 53) | 578 ((int64_t)(aname[len-2] & 0x1F) << 37); 579 /* fall through */ 580 case 1: 581 key |= ((int64_t)(aname[0] & 0x1F) << 58) | 582 ((int64_t)(aname[len-1] & 0x1F) << 32); 583 /* fall through */ 584 case 0: 585 break; 586 } 587 if ((key & 0xFFFFFFFF00000000LL) == 0) 588 key |= 0x100000000LL; 589 if (hammer_debug_general & 0x0400) { 590 kprintf("namekey2: 0x%016llx %*.*s\n", 591 (long long)key, len, len, aname); 592 } 593 *max_iterationsp = 0x00FFFFFF; 594 break; 595 case HAMMER_INODE_CAP_DIRHASH_ALG2: 596 case HAMMER_INODE_CAP_DIRHASH_ALG3: 597 default: 598 key = 0; /* compiler warning */ 599 *max_iterationsp = 1; /* sanity */ 600 panic("hammer_directory_namekey: bad algorithm %p\n", dip); 601 break; 602 } 603 return(key); 604 } 605 606 /* 607 * Convert string after @@ (@@ not included) to TID. Returns 0 on success, 608 * EINVAL on failure. 609 * 610 * If this function fails *ispfs, *tidp, and *localizationp will not 611 * be modified. 612 */ 613 int 614 hammer_str_to_tid(const char *str, int *ispfsp, 615 hammer_tid_t *tidp, u_int32_t *localizationp) 616 { 617 hammer_tid_t tid; 618 u_int32_t localization; 619 char *ptr; 620 int ispfs; 621 int n; 622 623 /* 624 * Forms allowed for TID: "0x%016llx" 625 * "-1" 626 */ 627 tid = strtouq(str, &ptr, 0); 628 n = ptr - str; 629 if (n == 2 && str[0] == '-' && str[1] == '1') { 630 /* ok */ 631 } else if (n == 18 && str[0] == '0' && (str[1] | 0x20) == 'x') { 632 /* ok */ 633 } else { 634 return(EINVAL); 635 } 636 637 /* 638 * Forms allowed for PFS: ":%05d" (i.e. "...:0" would be illegal). 639 */ 640 str = ptr; 641 if (*str == ':') { 642 localization = strtoul(str + 1, &ptr, 10) << 16; 643 if (ptr - str != 6) 644 return(EINVAL); 645 str = ptr; 646 ispfs = 1; 647 } else { 648 localization = *localizationp; 649 ispfs = 0; 650 } 651 652 /* 653 * Any trailing junk invalidates special extension handling. 654 */ 655 if (*str) 656 return(EINVAL); 657 *tidp = tid; 658 *localizationp = localization; 659 *ispfsp = ispfs; 660 return(0); 661 } 662 663 void 664 hammer_crc_set_blockmap(hammer_blockmap_t blockmap) 665 { 666 blockmap->entry_crc = crc32(blockmap, HAMMER_BLOCKMAP_CRCSIZE); 667 } 668 669 void 670 hammer_crc_set_volume(hammer_volume_ondisk_t ondisk) 671 { 672 ondisk->vol_crc = crc32(ondisk, HAMMER_VOL_CRCSIZE1) ^ 673 crc32(&ondisk->vol_crc + 1, HAMMER_VOL_CRCSIZE2); 674 } 675 676 int 677 hammer_crc_test_blockmap(hammer_blockmap_t blockmap) 678 { 679 hammer_crc_t crc; 680 681 crc = crc32(blockmap, HAMMER_BLOCKMAP_CRCSIZE); 682 return (blockmap->entry_crc == crc); 683 } 684 685 int 686 hammer_crc_test_volume(hammer_volume_ondisk_t ondisk) 687 { 688 hammer_crc_t crc; 689 690 crc = crc32(ondisk, HAMMER_VOL_CRCSIZE1) ^ 691 crc32(&ondisk->vol_crc + 1, HAMMER_VOL_CRCSIZE2); 692 return (ondisk->vol_crc == crc); 693 } 694 695 int 696 hammer_crc_test_btree(hammer_node_ondisk_t ondisk) 697 { 698 hammer_crc_t crc; 699 700 crc = crc32(&ondisk->crc + 1, HAMMER_BTREE_CRCSIZE); 701 return (ondisk->crc == crc); 702 } 703 704 /* 705 * Test or set the leaf->data_crc field. Deal with any special cases given 706 * a generic B-Tree leaf element and its data. 707 * 708 * NOTE: Inode-data: the atime and mtime fields are not CRCd, allowing them 709 * to be updated in-place. 710 */ 711 int 712 hammer_crc_test_leaf(void *data, hammer_btree_leaf_elm_t leaf) 713 { 714 hammer_crc_t crc; 715 716 if (leaf->data_len == 0) { 717 crc = 0; 718 } else { 719 switch(leaf->base.rec_type) { 720 case HAMMER_RECTYPE_INODE: 721 if (leaf->data_len != sizeof(struct hammer_inode_data)) 722 return(0); 723 crc = crc32(data, HAMMER_INODE_CRCSIZE); 724 break; 725 default: 726 crc = crc32(data, leaf->data_len); 727 break; 728 } 729 } 730 return (leaf->data_crc == crc); 731 } 732 733 void 734 hammer_crc_set_leaf(void *data, hammer_btree_leaf_elm_t leaf) 735 { 736 if (leaf->data_len == 0) { 737 leaf->data_crc = 0; 738 } else { 739 switch(leaf->base.rec_type) { 740 case HAMMER_RECTYPE_INODE: 741 KKASSERT(leaf->data_len == 742 sizeof(struct hammer_inode_data)); 743 leaf->data_crc = crc32(data, HAMMER_INODE_CRCSIZE); 744 break; 745 default: 746 leaf->data_crc = crc32(data, leaf->data_len); 747 break; 748 } 749 } 750 } 751 752 void 753 hkprintf(const char *ctl, ...) 754 { 755 __va_list va; 756 757 if (hammer_debug_debug) { 758 __va_start(va, ctl); 759 kvprintf(ctl, va); 760 __va_end(va); 761 } 762 } 763 764 /* 765 * Return the block size at the specified file offset. 766 */ 767 int 768 hammer_blocksize(int64_t file_offset) 769 { 770 if (file_offset < HAMMER_XDEMARC) 771 return(HAMMER_BUFSIZE); 772 else 773 return(HAMMER_XBUFSIZE); 774 } 775 776 int 777 hammer_blockoff(int64_t file_offset) 778 { 779 if (file_offset < HAMMER_XDEMARC) 780 return((int)file_offset & HAMMER_BUFMASK); 781 else 782 return((int)file_offset & HAMMER_XBUFMASK); 783 } 784 785 /* 786 * Return the demarkation point between the two offsets where 787 * the block size changes. 788 */ 789 int64_t 790 hammer_blockdemarc(int64_t file_offset1, int64_t file_offset2) 791 { 792 if (file_offset1 < HAMMER_XDEMARC) { 793 if (file_offset2 <= HAMMER_XDEMARC) 794 return(file_offset2); 795 return(HAMMER_XDEMARC); 796 } 797 panic("hammer_blockdemarc: illegal range %lld %lld\n", 798 (long long)file_offset1, (long long)file_offset2); 799 } 800 801 udev_t 802 hammer_fsid_to_udev(uuid_t *uuid) 803 { 804 u_int32_t crc; 805 806 crc = crc32(uuid, sizeof(*uuid)); 807 return((udev_t)crc); 808 } 809 810