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/uuid.h> 40 #include <sys/dirent.h> 41 42 #include "hammer2.h" 43 44 /* 45 * Return the directory entry type for an inode. 46 */ 47 int 48 hammer2_get_dtype(uint8_t type) 49 { 50 switch(type) { 51 case HAMMER2_OBJTYPE_UNKNOWN: 52 return (DT_UNKNOWN); 53 case HAMMER2_OBJTYPE_DIRECTORY: 54 return (DT_DIR); 55 case HAMMER2_OBJTYPE_REGFILE: 56 return (DT_REG); 57 case HAMMER2_OBJTYPE_FIFO: 58 return (DT_FIFO); 59 case HAMMER2_OBJTYPE_CDEV: 60 return (DT_CHR); 61 case HAMMER2_OBJTYPE_BDEV: 62 return (DT_BLK); 63 case HAMMER2_OBJTYPE_SOFTLINK: 64 return (DT_LNK); 65 case HAMMER2_OBJTYPE_SOCKET: 66 return (DT_SOCK); 67 case HAMMER2_OBJTYPE_WHITEOUT: /* not supported */ 68 return (DT_UNKNOWN); 69 default: 70 return (DT_UNKNOWN); 71 } 72 /* not reached */ 73 } 74 75 /* 76 * Return the directory entry type for an inode 77 */ 78 int 79 hammer2_get_vtype(uint8_t type) 80 { 81 switch(type) { 82 case HAMMER2_OBJTYPE_UNKNOWN: 83 return (VBAD); 84 case HAMMER2_OBJTYPE_DIRECTORY: 85 return (VDIR); 86 case HAMMER2_OBJTYPE_REGFILE: 87 return (VREG); 88 case HAMMER2_OBJTYPE_FIFO: 89 return (VFIFO); 90 case HAMMER2_OBJTYPE_CDEV: 91 return (VCHR); 92 case HAMMER2_OBJTYPE_BDEV: 93 return (VBLK); 94 case HAMMER2_OBJTYPE_SOFTLINK: 95 return (VLNK); 96 case HAMMER2_OBJTYPE_SOCKET: 97 return (VSOCK); 98 case HAMMER2_OBJTYPE_WHITEOUT: /* not supported */ 99 return (VBAD); 100 default: 101 return (VBAD); 102 } 103 /* not reached */ 104 } 105 106 uint8_t 107 hammer2_get_obj_type(enum vtype vtype) 108 { 109 switch(vtype) { 110 case VDIR: 111 return(HAMMER2_OBJTYPE_DIRECTORY); 112 case VREG: 113 return(HAMMER2_OBJTYPE_REGFILE); 114 case VFIFO: 115 return(HAMMER2_OBJTYPE_FIFO); 116 case VSOCK: 117 return(HAMMER2_OBJTYPE_SOCKET); 118 case VCHR: 119 return(HAMMER2_OBJTYPE_CDEV); 120 case VBLK: 121 return(HAMMER2_OBJTYPE_BDEV); 122 case VLNK: 123 return(HAMMER2_OBJTYPE_SOFTLINK); 124 default: 125 return(HAMMER2_OBJTYPE_UNKNOWN); 126 } 127 /* not reached */ 128 } 129 130 /* 131 * Convert a hammer2 64-bit time to a timespec. 132 */ 133 void 134 hammer2_time_to_timespec(uint64_t xtime, struct timespec *ts) 135 { 136 ts->tv_sec = (unsigned long)(xtime / 1000000); 137 ts->tv_nsec = (unsigned int)(xtime % 1000000) * 1000L; 138 } 139 140 uint64_t 141 hammer2_timespec_to_time(const struct timespec *ts) 142 { 143 uint64_t xtime; 144 145 xtime = (unsigned)(ts->tv_nsec / 1000) + 146 (unsigned long)ts->tv_sec * 1000000ULL; 147 return(xtime); 148 } 149 150 /* 151 * Convert a uuid to a unix uid or gid 152 */ 153 uint32_t 154 hammer2_to_unix_xid(const uuid_t *uuid) 155 { 156 return(*(const uint32_t *)&uuid->node[2]); 157 } 158 159 void 160 hammer2_guid_to_uuid(uuid_t *uuid, uint32_t guid) 161 { 162 bzero(uuid, sizeof(*uuid)); 163 *(uint32_t *)&uuid->node[2] = guid; 164 } 165 166 /* 167 * Borrow HAMMER1's directory hash algorithm #1 with a few modifications. 168 * The filename is split into fields which are hashed separately and then 169 * added together. 170 * 171 * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets 172 * it to 0), this is because bit63=0 is used for hidden hardlinked inodes. 173 * (This means we do not need to do a 0-check/or-with-0x100000000 either). 174 * 175 * Also, the iscsi crc code is used instead of the old crc32 code. 176 */ 177 hammer2_key_t 178 hammer2_dirhash(const char *aname, size_t len) 179 { 180 uint32_t crcx; 181 uint64_t key; 182 size_t i; 183 size_t j; 184 185 key = 0; 186 187 /* 188 * m32 189 */ 190 crcx = 0; 191 for (i = j = 0; i < len; ++i) { 192 if (aname[i] == '.' || 193 aname[i] == '-' || 194 aname[i] == '_' || 195 aname[i] == '~') { 196 if (i != j) 197 crcx += hammer2_icrc32(aname + j, i - j); 198 j = i + 1; 199 } 200 } 201 if (i != j) 202 crcx += hammer2_icrc32(aname + j, i - j); 203 204 /* 205 * The directory hash utilizes the top 32 bits of the 64-bit key. 206 * Bit 63 must be set to 1. 207 */ 208 crcx |= 0x80000000U; 209 key |= (uint64_t)crcx << 32; 210 211 /* 212 * l16 - crc of entire filename 213 * 214 * This crc reduces degenerate hash collision conditions. 215 */ 216 crcx = hammer2_icrc32(aname, len); 217 crcx = crcx ^ (crcx << 16); 218 key |= crcx & 0xFFFF0000U; 219 220 /* 221 * Set bit 15. This allows readdir to strip bit 63 so a positive 222 * 64-bit cookie/offset can always be returned, and still guarantee 223 * that the values 0x0000-0x7FFF are available for artificial entries. 224 * ('.' and '..'). 225 */ 226 key |= 0x8000U; 227 228 return (key); 229 } 230 231 /* 232 * Convert bytes to radix with no limitations. 233 * 234 * 0 bytes is special-cased to a radix of zero (which would normally 235 * translate to (1 << 0) == 1). 236 */ 237 int 238 hammer2_getradix(size_t bytes) 239 { 240 int radix; 241 242 /* 243 * Optimize the iteration by pre-checking commonly used radixes. 244 */ 245 if (bytes == HAMMER2_PBUFSIZE) 246 radix = HAMMER2_PBUFRADIX; 247 else if (bytes >= HAMMER2_LBUFSIZE) 248 radix = HAMMER2_LBUFRADIX; 249 else if (bytes >= HAMMER2_ALLOC_MIN) /* clamp */ 250 radix = HAMMER2_RADIX_MIN; 251 else 252 radix = 0; 253 254 /* 255 * Iterate as needed. Note that bytes == 0 is expected to return 256 * a radix of 0 as a special case. 257 */ 258 while (((size_t)1 << radix) < bytes) 259 ++radix; 260 return (radix); 261 } 262 263 /* 264 * The logical block size is currently always PBUFSIZE. 265 */ 266 int 267 hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff, 268 hammer2_key_t *lbasep, hammer2_key_t *leofp) 269 { 270 if (lbasep) 271 *lbasep = uoff & ~HAMMER2_PBUFMASK64; 272 if (leofp) { 273 *leofp = (ip->meta.size + HAMMER2_PBUFMASK64) & 274 ~HAMMER2_PBUFMASK64; 275 } 276 return (HAMMER2_PBUFSIZE); 277 } 278 279 /* 280 * Calculate the physical block size. pblksize <= lblksize. Primarily 281 * used to calculate a smaller physical block for the logical block 282 * containing the file EOF. 283 * 284 * Returns 0 if the requested base offset is beyond the file EOF. 285 */ 286 int 287 hammer2_calc_physical(hammer2_inode_t *ip, hammer2_key_t lbase) 288 { 289 int lblksize; 290 int pblksize; 291 int eofbytes; 292 293 lblksize = hammer2_calc_logical(ip, lbase, NULL, NULL); 294 if (lbase + lblksize <= ip->meta.size) 295 return (lblksize); 296 if (lbase >= ip->meta.size) 297 return (0); 298 eofbytes = (int)(ip->meta.size - lbase); 299 pblksize = lblksize; 300 while (pblksize >= eofbytes && pblksize >= HAMMER2_ALLOC_MIN) 301 pblksize >>= 1; 302 pblksize <<= 1; 303 304 return (pblksize); 305 } 306 307 void 308 hammer2_update_time(uint64_t *timep) 309 { 310 struct timespec ts; 311 312 vfs_timestamp(&ts); 313 *timep = (unsigned long)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 314 } 315 316 void 317 hammer2_adjreadcounter(int btype, size_t bytes) 318 { 319 long *counterp; 320 321 switch(btype) { 322 case HAMMER2_BREF_TYPE_DATA: 323 counterp = &hammer2_iod_file_read; 324 break; 325 case HAMMER2_BREF_TYPE_DIRENT: 326 case HAMMER2_BREF_TYPE_INODE: 327 counterp = &hammer2_iod_meta_read; 328 break; 329 case HAMMER2_BREF_TYPE_INDIRECT: 330 counterp = &hammer2_iod_indr_read; 331 break; 332 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 333 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 334 counterp = &hammer2_iod_fmap_read; 335 break; 336 case HAMMER2_BREF_TYPE_FREEMAP: 337 case HAMMER2_BREF_TYPE_VOLUME: 338 counterp = &hammer2_iod_volu_read; 339 break; 340 case HAMMER2_BREF_TYPE_EMPTY: 341 default: 342 return; 343 } 344 *counterp += bytes; 345 } 346 347 void 348 hammer2_adjwritecounter(int btype, size_t bytes) 349 { 350 long *counterp; 351 352 switch(btype) { 353 case HAMMER2_BREF_TYPE_DATA: 354 counterp = &hammer2_iod_file_write; 355 break; 356 case HAMMER2_BREF_TYPE_DIRENT: 357 case HAMMER2_BREF_TYPE_INODE: 358 counterp = &hammer2_iod_meta_write; 359 break; 360 case HAMMER2_BREF_TYPE_INDIRECT: 361 counterp = &hammer2_iod_indr_write; 362 break; 363 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 364 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 365 counterp = &hammer2_iod_fmap_write; 366 break; 367 case HAMMER2_BREF_TYPE_FREEMAP: 368 case HAMMER2_BREF_TYPE_VOLUME: 369 counterp = &hammer2_iod_volu_write; 370 break; 371 case HAMMER2_BREF_TYPE_EMPTY: 372 default: 373 return; 374 } 375 *counterp += bytes; 376 } 377 378 /* 379 * Check for pending signal to allow interruption. This function will 380 * return immediately if the calling thread is a kernel thread and not 381 * a user thread. 382 */ 383 int 384 hammer2_signal_check(time_t *timep) 385 { 386 thread_t td = curthread; 387 int error = 0; 388 389 if (td->td_lwp) { 390 lwkt_user_yield(); 391 if (*timep != time_second) { 392 *timep = time_second; 393 if (CURSIG_NOBLOCK(curthread->td_lwp) != 0) 394 error = HAMMER2_ERROR_ABORTED; 395 } 396 } else { 397 lwkt_yield(); 398 } 399 return error; 400 } 401 402 const char * 403 hammer2_error_str(int error) 404 { 405 if (error & HAMMER2_ERROR_EIO) 406 return("I/O Error"); 407 if (error & HAMMER2_ERROR_CHECK) 408 return("Check Error"); 409 if (error & HAMMER2_ERROR_INCOMPLETE) 410 return("Cluster Quorum Error"); 411 if (error & HAMMER2_ERROR_DEPTH) 412 return("Chain Depth Error"); 413 if (error & HAMMER2_ERROR_BADBREF) 414 return("Bad Blockref Error"); 415 if (error & HAMMER2_ERROR_ENOSPC) 416 return("No Space on Device"); 417 if (error & HAMMER2_ERROR_ENOENT) 418 return("Entry Not Found"); 419 if (error & HAMMER2_ERROR_ENOTEMPTY) 420 return("Directory Not Empty"); 421 if (error & HAMMER2_ERROR_EAGAIN) 422 return("EAGAIN"); 423 if (error & HAMMER2_ERROR_ENOTDIR) 424 return("Not a Directory"); 425 if (error & HAMMER2_ERROR_EISDIR) 426 return("Is a Directory"); 427 if (error & HAMMER2_ERROR_EINPROGRESS) 428 return("Operation in Progress"); 429 if (error & HAMMER2_ERROR_ABORTED) 430 return("Operation Aborted"); 431 if (error & HAMMER2_ERROR_EOF) 432 return("Operation Complete"); 433 if (error & HAMMER2_ERROR_EINVAL) 434 return("Invalid Operation"); 435 if (error & HAMMER2_ERROR_EEXIST) 436 return("Object Exists"); 437 if (error & HAMMER2_ERROR_EDEADLK) 438 return("Deadlock Detected"); 439 if (error & HAMMER2_ERROR_ESRCH) 440 return("Object Not Found"); 441 if (error & HAMMER2_ERROR_ETIMEDOUT) 442 return("Timeout"); 443 return("Unknown Error"); 444 } 445 446 const char * 447 hammer2_bref_type_str(int btype) 448 { 449 switch(btype) { 450 case HAMMER2_BREF_TYPE_EMPTY: 451 return("empty"); 452 case HAMMER2_BREF_TYPE_INODE: 453 return("inode"); 454 case HAMMER2_BREF_TYPE_INDIRECT: 455 return("indirect"); 456 case HAMMER2_BREF_TYPE_DATA: 457 return("data"); 458 case HAMMER2_BREF_TYPE_DIRENT: 459 return("dirent"); 460 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 461 return("freemap_node"); 462 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 463 return("freemap_leaf"); 464 case HAMMER2_BREF_TYPE_INVALID: 465 return("invalid"); 466 case HAMMER2_BREF_TYPE_FREEMAP: 467 return("freemap"); 468 case HAMMER2_BREF_TYPE_VOLUME: 469 return("volume"); 470 default: 471 return("unknown"); 472 } 473 } 474