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