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 unsigned char *name, size_t len) 179 { 180 const unsigned char *aname = name; 181 uint32_t crcx; 182 uint64_t key; 183 size_t i; 184 size_t j; 185 186 key = 0; 187 188 /* 189 * m32 190 */ 191 crcx = 0; 192 for (i = j = 0; i < len; ++i) { 193 if (aname[i] == '.' || 194 aname[i] == '-' || 195 aname[i] == '_' || 196 aname[i] == '~') { 197 if (i != j) 198 crcx += hammer2_icrc32(aname + j, i - j); 199 j = i + 1; 200 } 201 } 202 if (i != j) 203 crcx += hammer2_icrc32(aname + j, i - j); 204 205 /* 206 * The directory hash utilizes the top 32 bits of the 64-bit key. 207 * Bit 63 must be set to 1. 208 */ 209 crcx |= 0x80000000U; 210 key |= (uint64_t)crcx << 32; 211 212 /* 213 * l16 - crc of entire filename 214 * 215 * This crc reduces degenerate hash collision conditions. 216 */ 217 crcx = hammer2_icrc32(aname, len); 218 crcx = crcx ^ (crcx << 16); 219 key |= crcx & 0xFFFF0000U; 220 221 /* 222 * Set bit 15. This allows readdir to strip bit 63 so a positive 223 * 64-bit cookie/offset can always be returned, and still guarantee 224 * that the values 0x0000-0x7FFF are available for artificial entries. 225 * ('.' and '..'). 226 */ 227 key |= 0x8000U; 228 229 return (key); 230 } 231 232 /* 233 * Convert bytes to radix with no limitations. 234 * 235 * 0 bytes is special-cased to a radix of zero (which would normally 236 * translate to (1 << 0) == 1). 237 */ 238 int 239 hammer2_getradix(size_t bytes) 240 { 241 int radix; 242 243 /* 244 * Optimize the iteration by pre-checking commonly used radii. 245 */ 246 if (bytes == HAMMER2_PBUFSIZE) 247 radix = HAMMER2_PBUFRADIX; 248 else if (bytes >= HAMMER2_LBUFSIZE) 249 radix = HAMMER2_LBUFRADIX; 250 else if (bytes >= HAMMER2_ALLOC_MIN) /* clamp */ 251 radix = HAMMER2_RADIX_MIN; 252 else 253 radix = 0; 254 255 /* 256 * Iterate as needed. Note that bytes == 0 is expected to return 257 * a radix of 0 as a special case. 258 */ 259 while (((size_t)1 << radix) < bytes) 260 ++radix; 261 return (radix); 262 } 263 264 /* 265 * The logical block size is currently always PBUFSIZE. 266 */ 267 int 268 hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff, 269 hammer2_key_t *lbasep, hammer2_key_t *leofp) 270 { 271 if (lbasep) 272 *lbasep = uoff & ~HAMMER2_PBUFMASK64; 273 if (leofp) { 274 *leofp = (ip->meta.size + HAMMER2_PBUFMASK64) & 275 ~HAMMER2_PBUFMASK64; 276 } 277 return (HAMMER2_PBUFSIZE); 278 } 279 280 /* 281 * Calculate the physical block size. pblksize <= lblksize. Primarily 282 * used to calculate a smaller physical block for the logical block 283 * containing the file EOF. 284 * 285 * Returns 0 if the requested base offset is beyond the file EOF. 286 */ 287 int 288 hammer2_calc_physical(hammer2_inode_t *ip, hammer2_key_t lbase) 289 { 290 int lblksize; 291 int pblksize; 292 int eofbytes; 293 294 lblksize = hammer2_calc_logical(ip, lbase, NULL, NULL); 295 if (lbase + lblksize <= ip->meta.size) 296 return (lblksize); 297 if (lbase >= ip->meta.size) 298 return (0); 299 eofbytes = (int)(ip->meta.size - lbase); 300 pblksize = lblksize; 301 while (pblksize >= eofbytes && pblksize >= HAMMER2_ALLOC_MIN) 302 pblksize >>= 1; 303 pblksize <<= 1; 304 305 return (pblksize); 306 } 307 308 void 309 hammer2_update_time(uint64_t *timep) 310 { 311 struct timespec ts; 312 313 vfs_timestamp(&ts); 314 *timep = (unsigned long)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 315 } 316 317 void 318 hammer2_adjreadcounter(int btype, size_t bytes) 319 { 320 long *counterp; 321 322 switch(btype) { 323 case HAMMER2_BREF_TYPE_DATA: 324 counterp = &hammer2_iod_file_read; 325 break; 326 case HAMMER2_BREF_TYPE_DIRENT: 327 case HAMMER2_BREF_TYPE_INODE: 328 counterp = &hammer2_iod_meta_read; 329 break; 330 case HAMMER2_BREF_TYPE_INDIRECT: 331 counterp = &hammer2_iod_indr_read; 332 break; 333 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 334 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 335 counterp = &hammer2_iod_fmap_read; 336 break; 337 case HAMMER2_BREF_TYPE_FREEMAP: 338 case HAMMER2_BREF_TYPE_VOLUME: 339 counterp = &hammer2_iod_volu_read; 340 break; 341 case HAMMER2_BREF_TYPE_EMPTY: 342 default: 343 return; 344 } 345 *counterp += bytes; 346 } 347 348 void 349 hammer2_adjwritecounter(int btype, size_t bytes) 350 { 351 long *counterp; 352 353 switch(btype) { 354 case HAMMER2_BREF_TYPE_DATA: 355 counterp = &hammer2_iod_file_write; 356 break; 357 case HAMMER2_BREF_TYPE_DIRENT: 358 case HAMMER2_BREF_TYPE_INODE: 359 counterp = &hammer2_iod_meta_write; 360 break; 361 case HAMMER2_BREF_TYPE_INDIRECT: 362 counterp = &hammer2_iod_indr_write; 363 break; 364 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 365 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 366 counterp = &hammer2_iod_fmap_write; 367 break; 368 case HAMMER2_BREF_TYPE_FREEMAP: 369 case HAMMER2_BREF_TYPE_VOLUME: 370 counterp = &hammer2_iod_volu_write; 371 break; 372 case HAMMER2_BREF_TYPE_EMPTY: 373 default: 374 return; 375 } 376 *counterp += bytes; 377 } 378 379 /* 380 * Check for pending signal to allow interruption. This function will 381 * return immediately if the calling thread is a kernel thread and not 382 * a user thread. 383 */ 384 int 385 hammer2_signal_check(time_t *timep) 386 { 387 thread_t td = curthread; 388 int error = 0; 389 390 if (td->td_lwp) { 391 lwkt_user_yield(); 392 if (*timep != time_second) { 393 *timep = time_second; 394 if (CURSIG_NOBLOCK(curthread->td_lwp) != 0) 395 error = HAMMER2_ERROR_ABORTED; 396 } 397 } else { 398 lwkt_yield(); 399 } 400 return error; 401 } 402 403 const char * 404 hammer2_error_str(int error) 405 { 406 if (error & HAMMER2_ERROR_EIO) 407 return("I/O Error"); 408 if (error & HAMMER2_ERROR_CHECK) 409 return("Check Error"); 410 if (error & HAMMER2_ERROR_INCOMPLETE) 411 return("Cluster Quorum Error"); 412 if (error & HAMMER2_ERROR_DEPTH) 413 return("Chain Depth Error"); 414 if (error & HAMMER2_ERROR_BADBREF) 415 return("Bad Blockref Error"); 416 if (error & HAMMER2_ERROR_ENOSPC) 417 return("No Space on Device"); 418 if (error & HAMMER2_ERROR_ENOENT) 419 return("Entry Not Found"); 420 if (error & HAMMER2_ERROR_ENOTEMPTY) 421 return("Directory Not Empty"); 422 if (error & HAMMER2_ERROR_EAGAIN) 423 return("EAGAIN"); 424 if (error & HAMMER2_ERROR_ENOTDIR) 425 return("Not a Directory"); 426 if (error & HAMMER2_ERROR_EISDIR) 427 return("Is a Directory"); 428 if (error & HAMMER2_ERROR_EINPROGRESS) 429 return("Operation in Progress"); 430 if (error & HAMMER2_ERROR_ABORTED) 431 return("Operation Aborted"); 432 if (error & HAMMER2_ERROR_EOF) 433 return("Operation Complete"); 434 if (error & HAMMER2_ERROR_EINVAL) 435 return("Invalid Operation"); 436 if (error & HAMMER2_ERROR_EEXIST) 437 return("Object Exists"); 438 if (error & HAMMER2_ERROR_EDEADLK) 439 return("Deadlock Detected"); 440 if (error & HAMMER2_ERROR_ESRCH) 441 return("Object Not Found"); 442 if (error & HAMMER2_ERROR_ETIMEDOUT) 443 return("Timeout"); 444 return("Unknown Error"); 445 } 446 447 const char * 448 hammer2_bref_type_str(int btype) 449 { 450 switch(btype) { 451 case HAMMER2_BREF_TYPE_EMPTY: 452 return("empty"); 453 case HAMMER2_BREF_TYPE_INODE: 454 return("inode"); 455 case HAMMER2_BREF_TYPE_INDIRECT: 456 return("indirect"); 457 case HAMMER2_BREF_TYPE_DATA: 458 return("data"); 459 case HAMMER2_BREF_TYPE_DIRENT: 460 return("dirent"); 461 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 462 return("freemap_node"); 463 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 464 return("freemap_leaf"); 465 case HAMMER2_BREF_TYPE_INVALID: 466 return("invalid"); 467 case HAMMER2_BREF_TYPE_FREEMAP: 468 return("freemap"); 469 case HAMMER2_BREF_TYPE_VOLUME: 470 return("volume"); 471 default: 472 return("unknown"); 473 } 474 } 475