1 /* 2 * Copyright (c) 2011-2018 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@dragonflybsd.org> 6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 #include <sys/cdefs.h> 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/types.h> 39 #include <sys/lock.h> 40 #include <sys/uuid.h> 41 #include <sys/dirent.h> 42 43 #include "hammer2.h" 44 45 /* 46 * Mount-wide locks 47 */ 48 void 49 hammer2_dev_exlock(hammer2_dev_t *hmp) 50 { 51 hammer2_mtx_ex(&hmp->vchain.lock); 52 } 53 54 void 55 hammer2_dev_shlock(hammer2_dev_t *hmp) 56 { 57 hammer2_mtx_sh(&hmp->vchain.lock); 58 } 59 60 void 61 hammer2_dev_unlock(hammer2_dev_t *hmp) 62 { 63 hammer2_mtx_unlock(&hmp->vchain.lock); 64 } 65 66 /* 67 * Return the directory entry type for an inode. 68 */ 69 int 70 hammer2_get_dtype(uint8_t type) 71 { 72 switch(type) { 73 case HAMMER2_OBJTYPE_UNKNOWN: 74 return (DT_UNKNOWN); 75 case HAMMER2_OBJTYPE_DIRECTORY: 76 return (DT_DIR); 77 case HAMMER2_OBJTYPE_REGFILE: 78 return (DT_REG); 79 case HAMMER2_OBJTYPE_FIFO: 80 return (DT_FIFO); 81 case HAMMER2_OBJTYPE_CDEV: 82 return (DT_CHR); 83 case HAMMER2_OBJTYPE_BDEV: 84 return (DT_BLK); 85 case HAMMER2_OBJTYPE_SOFTLINK: 86 return (DT_LNK); 87 case HAMMER2_OBJTYPE_SOCKET: 88 return (DT_SOCK); 89 case HAMMER2_OBJTYPE_WHITEOUT: /* not supported */ 90 return (DT_UNKNOWN); 91 default: 92 return (DT_UNKNOWN); 93 } 94 /* not reached */ 95 } 96 97 /* 98 * Return the directory entry type for an inode 99 */ 100 int 101 hammer2_get_vtype(uint8_t type) 102 { 103 switch(type) { 104 case HAMMER2_OBJTYPE_UNKNOWN: 105 return (VBAD); 106 case HAMMER2_OBJTYPE_DIRECTORY: 107 return (VDIR); 108 case HAMMER2_OBJTYPE_REGFILE: 109 return (VREG); 110 case HAMMER2_OBJTYPE_FIFO: 111 return (VFIFO); 112 case HAMMER2_OBJTYPE_CDEV: 113 return (VCHR); 114 case HAMMER2_OBJTYPE_BDEV: 115 return (VBLK); 116 case HAMMER2_OBJTYPE_SOFTLINK: 117 return (VLNK); 118 case HAMMER2_OBJTYPE_SOCKET: 119 return (VSOCK); 120 case HAMMER2_OBJTYPE_WHITEOUT: /* not supported */ 121 return (VBAD); 122 default: 123 return (VBAD); 124 } 125 /* not reached */ 126 } 127 128 uint8_t 129 hammer2_get_obj_type(enum vtype vtype) 130 { 131 switch(vtype) { 132 case VDIR: 133 return(HAMMER2_OBJTYPE_DIRECTORY); 134 case VREG: 135 return(HAMMER2_OBJTYPE_REGFILE); 136 case VFIFO: 137 return(HAMMER2_OBJTYPE_FIFO); 138 case VSOCK: 139 return(HAMMER2_OBJTYPE_SOCKET); 140 case VCHR: 141 return(HAMMER2_OBJTYPE_CDEV); 142 case VBLK: 143 return(HAMMER2_OBJTYPE_BDEV); 144 case VLNK: 145 return(HAMMER2_OBJTYPE_SOFTLINK); 146 default: 147 return(HAMMER2_OBJTYPE_UNKNOWN); 148 } 149 /* not reached */ 150 } 151 152 /* 153 * Convert a hammer2 64-bit time to a timespec. 154 */ 155 void 156 hammer2_time_to_timespec(uint64_t xtime, struct timespec *ts) 157 { 158 ts->tv_sec = (unsigned long)(xtime / 1000000); 159 ts->tv_nsec = (unsigned int)(xtime % 1000000) * 1000L; 160 } 161 162 uint64_t 163 hammer2_timespec_to_time(const struct timespec *ts) 164 { 165 uint64_t xtime; 166 167 xtime = (unsigned)(ts->tv_nsec / 1000) + 168 (unsigned long)ts->tv_sec * 1000000ULL; 169 return(xtime); 170 } 171 172 /* 173 * Convert a uuid to a unix uid or gid 174 */ 175 uint32_t 176 hammer2_to_unix_xid(const uuid_t *uuid) 177 { 178 return(*(const uint32_t *)&uuid->node[2]); 179 } 180 181 void 182 hammer2_guid_to_uuid(uuid_t *uuid, uint32_t guid) 183 { 184 bzero(uuid, sizeof(*uuid)); 185 *(uint32_t *)&uuid->node[2] = guid; 186 } 187 188 /* 189 * Borrow HAMMER1's directory hash algorithm #1 with a few modifications. 190 * The filename is split into fields which are hashed separately and then 191 * added together. 192 * 193 * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets 194 * it to 0), this is because bit63=0 is used for hidden hardlinked inodes. 195 * (This means we do not need to do a 0-check/or-with-0x100000000 either). 196 * 197 * Also, the iscsi crc code is used instead of the old crc32 code. 198 */ 199 hammer2_key_t 200 hammer2_dirhash(const unsigned char *name, size_t len) 201 { 202 const unsigned char *aname = name; 203 uint32_t crcx; 204 uint64_t key; 205 size_t i; 206 size_t j; 207 208 key = 0; 209 210 /* 211 * m32 212 */ 213 crcx = 0; 214 for (i = j = 0; i < len; ++i) { 215 if (aname[i] == '.' || 216 aname[i] == '-' || 217 aname[i] == '_' || 218 aname[i] == '~') { 219 if (i != j) 220 crcx += hammer2_icrc32(aname + j, i - j); 221 j = i + 1; 222 } 223 } 224 if (i != j) 225 crcx += hammer2_icrc32(aname + j, i - j); 226 227 /* 228 * The directory hash utilizes the top 32 bits of the 64-bit key. 229 * Bit 63 must be set to 1. 230 */ 231 crcx |= 0x80000000U; 232 key |= (uint64_t)crcx << 32; 233 234 /* 235 * l16 - crc of entire filename 236 * 237 * This crc reduces degenerate hash collision conditions 238 */ 239 crcx = hammer2_icrc32(aname, len); 240 crcx = crcx ^ (crcx << 16); 241 key |= crcx & 0xFFFF0000U; 242 243 /* 244 * Set bit 15. This allows readdir to strip bit 63 so a positive 245 * 64-bit cookie/offset can always be returned, and still guarantee 246 * that the values 0x0000-0x7FFF are available for artificial entries. 247 * ('.' and '..'). 248 */ 249 key |= 0x8000U; 250 251 return (key); 252 } 253 254 /* 255 * Convert bytes to radix with no limitations. 256 * 257 * 0 bytes is special-cased to a radix of zero (which would normally 258 * translate to (1 << 0) == 1). 259 */ 260 int 261 hammer2_getradix(size_t bytes) 262 { 263 int radix; 264 265 /* 266 * Optimize the iteration by pre-checking commonly used radii. 267 */ 268 if (bytes == HAMMER2_PBUFSIZE) 269 radix = HAMMER2_PBUFRADIX; 270 else if (bytes >= HAMMER2_LBUFSIZE) 271 radix = HAMMER2_LBUFRADIX; 272 else if (bytes >= HAMMER2_ALLOC_MIN) /* clamp */ 273 radix = HAMMER2_RADIX_MIN; 274 else 275 radix = 0; 276 277 /* 278 * Iterate as needed. Note that bytes == 0 is expected to return 279 * a radix of 0 as a special case. 280 */ 281 while (((size_t)1 << radix) < bytes) 282 ++radix; 283 return (radix); 284 } 285 286 /* 287 * The logical block size is currently always PBUFSIZE. 288 */ 289 int 290 hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff, 291 hammer2_key_t *lbasep, hammer2_key_t *leofp) 292 { 293 KKASSERT(ip->flags & HAMMER2_INODE_METAGOOD); 294 if (lbasep) 295 *lbasep = uoff & ~HAMMER2_PBUFMASK64; 296 if (leofp) { 297 *leofp = (ip->meta.size + HAMMER2_PBUFMASK64) & 298 ~HAMMER2_PBUFMASK64; 299 } 300 return (HAMMER2_PBUFSIZE); 301 } 302 303 /* 304 * Calculate the physical block size. pblksize <= lblksize. Primarily 305 * used to calculate a smaller physical block for the logical block 306 * containing the file EOF. 307 * 308 * Returns 0 if the requested base offset is beyond the file EOF. 309 */ 310 int 311 hammer2_calc_physical(hammer2_inode_t *ip, hammer2_key_t lbase) 312 { 313 int lblksize; 314 int pblksize; 315 int eofbytes; 316 317 KKASSERT(ip->flags & HAMMER2_INODE_METAGOOD); 318 lblksize = hammer2_calc_logical(ip, lbase, NULL, NULL); 319 if (lbase + lblksize <= ip->meta.size) 320 return (lblksize); 321 if (lbase >= ip->meta.size) 322 return (0); 323 eofbytes = (int)(ip->meta.size - lbase); 324 pblksize = lblksize; 325 while (pblksize >= eofbytes && pblksize >= HAMMER2_ALLOC_MIN) 326 pblksize >>= 1; 327 pblksize <<= 1; 328 329 return (pblksize); 330 } 331 332 void 333 hammer2_update_time(uint64_t *timep) 334 { 335 struct timespec ts; 336 337 vfs_timestamp(&ts); 338 *timep = (unsigned long)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 339 } 340 341 void 342 hammer2_adjreadcounter(int btype, size_t bytes) 343 { 344 long *counterp; 345 346 switch(btype) { 347 case HAMMER2_BREF_TYPE_DATA: 348 counterp = &hammer2_iod_file_read; 349 break; 350 case HAMMER2_BREF_TYPE_DIRENT: 351 case HAMMER2_BREF_TYPE_INODE: 352 counterp = &hammer2_iod_meta_read; 353 break; 354 case HAMMER2_BREF_TYPE_INDIRECT: 355 counterp = &hammer2_iod_indr_read; 356 break; 357 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 358 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 359 counterp = &hammer2_iod_fmap_read; 360 break; 361 case HAMMER2_BREF_TYPE_FREEMAP: 362 case HAMMER2_BREF_TYPE_VOLUME: 363 counterp = &hammer2_iod_volu_read; 364 break; 365 case HAMMER2_BREF_TYPE_EMPTY: 366 default: 367 return; 368 } 369 *counterp += bytes; 370 } 371 372 void 373 hammer2_adjwritecounter(int btype, size_t bytes) 374 { 375 long *counterp; 376 377 switch(btype) { 378 case HAMMER2_BREF_TYPE_DATA: 379 counterp = &hammer2_iod_file_write; 380 break; 381 case HAMMER2_BREF_TYPE_DIRENT: 382 case HAMMER2_BREF_TYPE_INODE: 383 counterp = &hammer2_iod_meta_write; 384 break; 385 case HAMMER2_BREF_TYPE_INDIRECT: 386 counterp = &hammer2_iod_indr_write; 387 break; 388 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 389 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 390 counterp = &hammer2_iod_fmap_write; 391 break; 392 case HAMMER2_BREF_TYPE_FREEMAP: 393 case HAMMER2_BREF_TYPE_VOLUME: 394 counterp = &hammer2_iod_volu_write; 395 break; 396 case HAMMER2_BREF_TYPE_EMPTY: 397 default: 398 return; 399 } 400 *counterp += bytes; 401 } 402 403 /* 404 * Check for pending signal to allow interruption. This function will 405 * return immediately if the calling thread is a kernel thread and not 406 * a user thread. 407 */ 408 int 409 hammer2_signal_check(time_t *timep) 410 { 411 thread_t td = curthread; 412 int error = 0; 413 414 if (td->td_lwp) { 415 lwkt_user_yield(); 416 if (*timep != time_second) { 417 *timep = time_second; 418 if (CURSIG_NOBLOCK(curthread->td_lwp) != 0) 419 error = HAMMER2_ERROR_ABORTED; 420 } 421 } else { 422 lwkt_yield(); 423 } 424 return error; 425 } 426 427 const char * 428 hammer2_error_str(int error) 429 { 430 if (error & HAMMER2_ERROR_EIO) 431 return("I/O Error"); 432 if (error & HAMMER2_ERROR_CHECK) 433 return("Check Error"); 434 if (error & HAMMER2_ERROR_INCOMPLETE) 435 return("Cluster Quorum Error"); 436 if (error & HAMMER2_ERROR_DEPTH) 437 return("Chain Depth Error"); 438 if (error & HAMMER2_ERROR_BADBREF) 439 return("Bad Blockref Error"); 440 if (error & HAMMER2_ERROR_ENOSPC) 441 return("No Space on Device"); 442 if (error & HAMMER2_ERROR_ENOENT) 443 return("Entry Not Found"); 444 if (error & HAMMER2_ERROR_ENOTEMPTY) 445 return("Directory Not Empty"); 446 if (error & HAMMER2_ERROR_EAGAIN) 447 return("EAGAIN"); 448 if (error & HAMMER2_ERROR_ENOTDIR) 449 return("Not a Directory"); 450 if (error & HAMMER2_ERROR_EISDIR) 451 return("Is a Directory"); 452 if (error & HAMMER2_ERROR_EINPROGRESS) 453 return("Operation in Progress"); 454 if (error & HAMMER2_ERROR_ABORTED) 455 return("Operation Aborted"); 456 if (error & HAMMER2_ERROR_EOF) 457 return("Operation Complete"); 458 if (error & HAMMER2_ERROR_EINVAL) 459 return("Invalid Operation"); 460 if (error & HAMMER2_ERROR_EEXIST) 461 return("Object Exists"); 462 if (error & HAMMER2_ERROR_EDEADLK) 463 return("Deadlock Detected"); 464 if (error & HAMMER2_ERROR_ESRCH) 465 return("Object Not Found"); 466 if (error & HAMMER2_ERROR_ETIMEDOUT) 467 return("Timeout"); 468 return("Unknown Error"); 469 } 470 471 const char * 472 hammer2_bref_type_str(int btype) 473 { 474 switch(btype) { 475 case HAMMER2_BREF_TYPE_EMPTY: 476 return("empty"); 477 case HAMMER2_BREF_TYPE_INODE: 478 return("inode"); 479 case HAMMER2_BREF_TYPE_INDIRECT: 480 return("indirect"); 481 case HAMMER2_BREF_TYPE_DATA: 482 return("data"); 483 case HAMMER2_BREF_TYPE_DIRENT: 484 return("dirent"); 485 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 486 return("freemap_node"); 487 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 488 return("freemap_leaf"); 489 case HAMMER2_BREF_TYPE_FREEMAP: 490 return("freemap"); 491 case HAMMER2_BREF_TYPE_VOLUME: 492 return("volume"); 493 default: 494 return("unknown"); 495 } 496 } 497