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