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