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, bool is_mtime) 313 { 314 struct timespec *ts; 315 struct stat *st; 316 317 assert(hammer2_curnode); 318 st = stampst.st_ino != 0 ? &stampst : &hammer2_curnode->inode->st; 319 ts = is_mtime ? &st->st_mtim : &st->st_ctim; 320 321 *timep = (uint64_t)ts->tv_sec * 1000000 + ts->tv_nsec / 1000; 322 } 323 324 void 325 hammer2_adjreadcounter(int btype, size_t bytes) 326 { 327 long *counterp; 328 329 switch(btype) { 330 case HAMMER2_BREF_TYPE_DATA: 331 counterp = &hammer2_iod_file_read; 332 break; 333 case HAMMER2_BREF_TYPE_DIRENT: 334 case HAMMER2_BREF_TYPE_INODE: 335 counterp = &hammer2_iod_meta_read; 336 break; 337 case HAMMER2_BREF_TYPE_INDIRECT: 338 counterp = &hammer2_iod_indr_read; 339 break; 340 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 341 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 342 counterp = &hammer2_iod_fmap_read; 343 break; 344 case HAMMER2_BREF_TYPE_FREEMAP: 345 case HAMMER2_BREF_TYPE_VOLUME: 346 counterp = &hammer2_iod_volu_read; 347 break; 348 case HAMMER2_BREF_TYPE_EMPTY: 349 default: 350 return; 351 } 352 *counterp += bytes; 353 } 354 355 void 356 hammer2_adjwritecounter(int btype, size_t bytes) 357 { 358 long *counterp; 359 360 switch(btype) { 361 case HAMMER2_BREF_TYPE_DATA: 362 counterp = &hammer2_iod_file_write; 363 break; 364 case HAMMER2_BREF_TYPE_DIRENT: 365 case HAMMER2_BREF_TYPE_INODE: 366 counterp = &hammer2_iod_meta_write; 367 break; 368 case HAMMER2_BREF_TYPE_INDIRECT: 369 counterp = &hammer2_iod_indr_write; 370 break; 371 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 372 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 373 counterp = &hammer2_iod_fmap_write; 374 break; 375 case HAMMER2_BREF_TYPE_FREEMAP: 376 case HAMMER2_BREF_TYPE_VOLUME: 377 counterp = &hammer2_iod_volu_write; 378 break; 379 case HAMMER2_BREF_TYPE_EMPTY: 380 default: 381 return; 382 } 383 *counterp += bytes; 384 } 385 386 #if 0 387 /* 388 * Check for pending signal to allow interruption. This function will 389 * return immediately if the calling thread is a kernel thread and not 390 * a user thread. 391 */ 392 int 393 hammer2_signal_check(time_t *timep) 394 { 395 thread_t td = curthread; 396 int error = 0; 397 398 if (td->td_lwp) { 399 lwkt_user_yield(); 400 if (*timep != time_second) { 401 *timep = time_second; 402 if (CURSIG_NOBLOCK(curthread->td_lwp) != 0) 403 error = HAMMER2_ERROR_ABORTED; 404 } 405 } else { 406 lwkt_yield(); 407 } 408 return error; 409 } 410 #endif 411 412 const char * 413 hammer2_error_str(int error) 414 { 415 if (error & HAMMER2_ERROR_EIO) 416 return("I/O Error"); 417 if (error & HAMMER2_ERROR_CHECK) 418 return("Check Error"); 419 if (error & HAMMER2_ERROR_INCOMPLETE) 420 return("Cluster Quorum Error"); 421 if (error & HAMMER2_ERROR_DEPTH) 422 return("Chain Depth Error"); 423 if (error & HAMMER2_ERROR_BADBREF) 424 return("Bad Blockref Error"); 425 if (error & HAMMER2_ERROR_ENOSPC) 426 return("No Space on Device"); 427 if (error & HAMMER2_ERROR_ENOENT) 428 return("Entry Not Found"); 429 if (error & HAMMER2_ERROR_ENOTEMPTY) 430 return("Directory Not Empty"); 431 if (error & HAMMER2_ERROR_EAGAIN) 432 return("EAGAIN"); 433 if (error & HAMMER2_ERROR_ENOTDIR) 434 return("Not a Directory"); 435 if (error & HAMMER2_ERROR_EISDIR) 436 return("Is a Directory"); 437 if (error & HAMMER2_ERROR_EINPROGRESS) 438 return("Operation in Progress"); 439 if (error & HAMMER2_ERROR_ABORTED) 440 return("Operation Aborted"); 441 if (error & HAMMER2_ERROR_EOF) 442 return("Operation Complete"); 443 if (error & HAMMER2_ERROR_EINVAL) 444 return("Invalid Operation"); 445 if (error & HAMMER2_ERROR_EEXIST) 446 return("Object Exists"); 447 if (error & HAMMER2_ERROR_EDEADLK) 448 return("Deadlock Detected"); 449 if (error & HAMMER2_ERROR_ESRCH) 450 return("Object Not Found"); 451 if (error & HAMMER2_ERROR_ETIMEDOUT) 452 return("Timeout"); 453 return("Unknown Error"); 454 } 455 456 const char * 457 hammer2_bref_type_str(int btype) 458 { 459 switch(btype) { 460 case HAMMER2_BREF_TYPE_EMPTY: 461 return("empty"); 462 case HAMMER2_BREF_TYPE_INODE: 463 return("inode"); 464 case HAMMER2_BREF_TYPE_INDIRECT: 465 return("indirect"); 466 case HAMMER2_BREF_TYPE_DATA: 467 return("data"); 468 case HAMMER2_BREF_TYPE_DIRENT: 469 return("dirent"); 470 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 471 return("freemap_node"); 472 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 473 return("freemap_leaf"); 474 case HAMMER2_BREF_TYPE_INVALID: 475 return("invalid"); 476 case HAMMER2_BREF_TYPE_FREEMAP: 477 return("freemap"); 478 case HAMMER2_BREF_TYPE_VOLUME: 479 return("volume"); 480 default: 481 return("unknown"); 482 } 483 } 484