1 /* 2 * Copyright (c) 2011-2014 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 * Mount-wide locks 47 */ 48 void 49 hammer2_dev_exlock(hammer2_dev_t *hmp) 50 { 51 hammer2_mtx_ex(&hmp->vchain.core.lock); 52 } 53 54 void 55 hammer2_dev_shlock(hammer2_dev_t *hmp) 56 { 57 hammer2_mtx_sh(&hmp->vchain.core.lock); 58 } 59 60 void 61 hammer2_dev_unlock(hammer2_dev_t *hmp) 62 { 63 hammer2_mtx_unlock(&hmp->vchain.core.lock); 64 } 65 66 /* 67 * Return the directory entry type for an inode. 68 * 69 * ip must be locked sh/ex. 70 */ 71 int 72 hammer2_get_dtype(const hammer2_inode_data_t *ipdata) 73 { 74 uint8_t type; 75 76 if ((type = ipdata->type) == HAMMER2_OBJTYPE_HARDLINK) 77 type = ipdata->target_type; 78 79 switch(type) { 80 case HAMMER2_OBJTYPE_UNKNOWN: 81 return (DT_UNKNOWN); 82 case HAMMER2_OBJTYPE_DIRECTORY: 83 return (DT_DIR); 84 case HAMMER2_OBJTYPE_REGFILE: 85 return (DT_REG); 86 case HAMMER2_OBJTYPE_FIFO: 87 return (DT_FIFO); 88 case HAMMER2_OBJTYPE_CDEV: /* not supported */ 89 return (DT_CHR); 90 case HAMMER2_OBJTYPE_BDEV: /* not supported */ 91 return (DT_BLK); 92 case HAMMER2_OBJTYPE_SOFTLINK: 93 return (DT_LNK); 94 case HAMMER2_OBJTYPE_HARDLINK: /* (never directly associated w/vp) */ 95 return (DT_UNKNOWN); 96 case HAMMER2_OBJTYPE_SOCKET: 97 return (DT_SOCK); 98 case HAMMER2_OBJTYPE_WHITEOUT: /* not supported */ 99 return (DT_UNKNOWN); 100 default: 101 return (DT_UNKNOWN); 102 } 103 /* not reached */ 104 } 105 106 /* 107 * Return the directory entry type for an inode 108 */ 109 int 110 hammer2_get_vtype(const hammer2_inode_data_t *ipdata) 111 { 112 switch(ipdata->type) { 113 case HAMMER2_OBJTYPE_UNKNOWN: 114 return (VBAD); 115 case HAMMER2_OBJTYPE_DIRECTORY: 116 return (VDIR); 117 case HAMMER2_OBJTYPE_REGFILE: 118 return (VREG); 119 case HAMMER2_OBJTYPE_FIFO: 120 return (VFIFO); 121 case HAMMER2_OBJTYPE_CDEV: /* not supported */ 122 return (VCHR); 123 case HAMMER2_OBJTYPE_BDEV: /* not supported */ 124 return (VBLK); 125 case HAMMER2_OBJTYPE_SOFTLINK: 126 return (VLNK); 127 case HAMMER2_OBJTYPE_HARDLINK: /* XXX */ 128 return (VBAD); 129 case HAMMER2_OBJTYPE_SOCKET: 130 return (VSOCK); 131 case HAMMER2_OBJTYPE_WHITEOUT: /* not supported */ 132 return (DT_UNKNOWN); 133 default: 134 return (DT_UNKNOWN); 135 } 136 /* not reached */ 137 } 138 139 u_int8_t 140 hammer2_get_obj_type(enum vtype vtype) 141 { 142 switch(vtype) { 143 case VDIR: 144 return(HAMMER2_OBJTYPE_DIRECTORY); 145 case VREG: 146 return(HAMMER2_OBJTYPE_REGFILE); 147 case VFIFO: 148 return(HAMMER2_OBJTYPE_FIFO); 149 case VSOCK: 150 return(HAMMER2_OBJTYPE_SOCKET); 151 case VCHR: 152 return(HAMMER2_OBJTYPE_CDEV); 153 case VBLK: 154 return(HAMMER2_OBJTYPE_BDEV); 155 case VLNK: 156 return(HAMMER2_OBJTYPE_SOFTLINK); 157 default: 158 return(HAMMER2_OBJTYPE_UNKNOWN); 159 } 160 /* not reached */ 161 } 162 163 /* 164 * Convert a hammer2 64-bit time to a timespec. 165 */ 166 void 167 hammer2_time_to_timespec(u_int64_t xtime, struct timespec *ts) 168 { 169 ts->tv_sec = (unsigned long)(xtime / 1000000); 170 ts->tv_nsec = (unsigned int)(xtime % 1000000) * 1000L; 171 } 172 173 u_int64_t 174 hammer2_timespec_to_time(const struct timespec *ts) 175 { 176 u_int64_t xtime; 177 178 xtime = (unsigned)(ts->tv_nsec / 1000) + 179 (unsigned long)ts->tv_sec * 1000000ULL; 180 return(xtime); 181 } 182 183 /* 184 * Convert a uuid to a unix uid or gid 185 */ 186 u_int32_t 187 hammer2_to_unix_xid(const uuid_t *uuid) 188 { 189 return(*(const u_int32_t *)&uuid->node[2]); 190 } 191 192 void 193 hammer2_guid_to_uuid(uuid_t *uuid, u_int32_t guid) 194 { 195 bzero(uuid, sizeof(*uuid)); 196 *(u_int32_t *)&uuid->node[2] = guid; 197 } 198 199 /* 200 * Borrow HAMMER1's directory hash algorithm #1 with a few modifications. 201 * The filename is split into fields which are hashed separately and then 202 * added together. 203 * 204 * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets 205 * it to 0), this is because bit63=0 is used for hidden hardlinked inodes. 206 * (This means we do not need to do a 0-check/or-with-0x100000000 either). 207 * 208 * Also, the iscsi crc code is used instead of the old crc32 code. 209 */ 210 hammer2_key_t 211 hammer2_dirhash(const unsigned char *name, size_t len) 212 { 213 const unsigned char *aname = name; 214 uint32_t crcx; 215 uint64_t key; 216 size_t i; 217 size_t j; 218 219 key = 0; 220 221 /* 222 * m32 223 */ 224 crcx = 0; 225 for (i = j = 0; i < len; ++i) { 226 if (aname[i] == '.' || 227 aname[i] == '-' || 228 aname[i] == '_' || 229 aname[i] == '~') { 230 if (i != j) 231 crcx += hammer2_icrc32(aname + j, i - j); 232 j = i + 1; 233 } 234 } 235 if (i != j) 236 crcx += hammer2_icrc32(aname + j, i - j); 237 238 /* 239 * The directory hash utilizes the top 32 bits of the 64-bit key. 240 * Bit 63 must be set to 1. 241 */ 242 crcx |= 0x80000000U; 243 key |= (uint64_t)crcx << 32; 244 245 /* 246 * l16 - crc of entire filename 247 * 248 * This crc reduces degenerate hash collision conditions 249 */ 250 crcx = hammer2_icrc32(aname, len); 251 crcx = crcx ^ (crcx << 16); 252 key |= crcx & 0xFFFF0000U; 253 254 /* 255 * Set bit 15. This allows readdir to strip bit 63 so a positive 256 * 64-bit cookie/offset can always be returned, and still guarantee 257 * that the values 0x0000-0x7FFF are available for artificial entries. 258 * ('.' and '..'). 259 */ 260 key |= 0x8000U; 261 262 return (key); 263 } 264 265 #if 0 266 /* 267 * Return the power-of-2 radix greater or equal to 268 * the specified number of bytes. 269 * 270 * Always returns at least the minimum media allocation 271 * size radix, HAMMER2_RADIX_MIN (10), which is 1KB. 272 */ 273 int 274 hammer2_allocsize(size_t bytes) 275 { 276 int radix; 277 278 if (bytes < HAMMER2_ALLOC_MIN) 279 bytes = HAMMER2_ALLOC_MIN; 280 if (bytes == HAMMER2_PBUFSIZE) 281 radix = HAMMER2_PBUFRADIX; 282 else if (bytes >= 16384) 283 radix = 14; 284 else if (bytes >= 1024) 285 radix = 10; 286 else 287 radix = HAMMER2_RADIX_MIN; 288 289 while (((size_t)1 << radix) < bytes) 290 ++radix; 291 return (radix); 292 } 293 294 #endif 295 296 /* 297 * Convert bytes to radix with no limitations 298 */ 299 int 300 hammer2_getradix(size_t bytes) 301 { 302 int radix; 303 304 if (bytes == HAMMER2_PBUFSIZE) 305 radix = HAMMER2_PBUFRADIX; 306 else if (bytes >= HAMMER2_LBUFSIZE) 307 radix = HAMMER2_LBUFRADIX; 308 else if (bytes >= HAMMER2_ALLOC_MIN) /* clamp */ 309 radix = HAMMER2_RADIX_MIN; 310 else 311 radix = 0; 312 313 while (((size_t)1 << radix) < bytes) 314 ++radix; 315 return (radix); 316 } 317 318 /* 319 * ip must be locked sh/ex 320 * 321 * Use 16KB logical buffers for file blocks <= 1MB and 64KB logical buffers 322 * otherwise. The write code may utilize smaller device buffers when 323 * compressing or handling the EOF case, but is not able to coalesce smaller 324 * logical buffers into larger device buffers. 325 * 326 * For now this means that even large files will have a bunch of 16KB blocks 327 * at the beginning of the file. On the plus side this tends to cause small 328 * files to cluster together in the freemap. 329 */ 330 int 331 hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff, 332 hammer2_key_t *lbasep, hammer2_key_t *leofp) 333 { 334 #if 0 335 if (uoff < (hammer2_off_t)1024 * 1024) { 336 if (lbasep) 337 *lbasep = uoff & ~HAMMER2_LBUFMASK64; 338 if (leofp) { 339 if (ip->size > (hammer2_key_t)1024 * 1024) 340 *leofp = (hammer2_key_t)1024 * 1024; 341 else 342 *leofp = (ip->size + HAMMER2_LBUFMASK64) & 343 ~HAMMER2_LBUFMASK64; 344 } 345 return (HAMMER2_LBUFSIZE); 346 } else { 347 #endif 348 if (lbasep) 349 *lbasep = uoff & ~HAMMER2_PBUFMASK64; 350 if (leofp) { 351 *leofp = (ip->size + HAMMER2_PBUFMASK64) & 352 ~HAMMER2_PBUFMASK64; 353 } 354 return (HAMMER2_PBUFSIZE); 355 #if 0 356 } 357 #endif 358 } 359 360 /* 361 * Calculate the physical block size. pblksize <= lblksize. Primarily 362 * used to calculate a smaller physical block for the logical block 363 * containing the file EOF. 364 * 365 * Returns 0 if the requested base offset is beyond the file EOF. 366 */ 367 int 368 hammer2_calc_physical(hammer2_inode_t *ip, 369 const hammer2_inode_data_t *ipdata, 370 hammer2_key_t lbase) 371 { 372 int lblksize; 373 int pblksize; 374 int eofbytes; 375 376 lblksize = hammer2_calc_logical(ip, lbase, NULL, NULL); 377 if (lbase + lblksize <= ipdata->size) 378 return (lblksize); 379 if (lbase >= ipdata->size) 380 return (0); 381 eofbytes = (int)(ipdata->size - lbase); 382 pblksize = lblksize; 383 while (pblksize >= eofbytes && pblksize >= HAMMER2_ALLOC_MIN) 384 pblksize >>= 1; 385 pblksize <<= 1; 386 387 return (pblksize); 388 } 389 390 void 391 hammer2_update_time(uint64_t *timep) 392 { 393 struct timeval tv; 394 395 getmicrotime(&tv); 396 *timep = (unsigned long)tv.tv_sec * 1000000 + tv.tv_usec; 397 } 398 399 void 400 hammer2_adjreadcounter(hammer2_blockref_t *bref, size_t bytes) 401 { 402 long *counterp; 403 404 switch(bref->type) { 405 case HAMMER2_BREF_TYPE_DATA: 406 counterp = &hammer2_iod_file_read; 407 break; 408 case HAMMER2_BREF_TYPE_INODE: 409 counterp = &hammer2_iod_meta_read; 410 break; 411 case HAMMER2_BREF_TYPE_INDIRECT: 412 counterp = &hammer2_iod_indr_read; 413 break; 414 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 415 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 416 counterp = &hammer2_iod_fmap_read; 417 break; 418 default: 419 counterp = &hammer2_iod_volu_read; 420 break; 421 } 422 *counterp += bytes; 423 } 424 425 int 426 hammer2_signal_check(time_t *timep) 427 { 428 int error = 0; 429 430 lwkt_user_yield(); 431 if (*timep != time_second) { 432 *timep = time_second; 433 if (CURSIG(curthread->td_lwp) != 0) 434 error = EINTR; 435 } 436 return error; 437 } 438 439 const char * 440 hammer2_error_str(int error) 441 { 442 const char *str; 443 444 switch(error) { 445 case HAMMER2_ERROR_NONE: 446 str = "0"; 447 break; 448 case HAMMER2_ERROR_IO: 449 str = "I/O"; 450 break; 451 case HAMMER2_ERROR_CHECK: 452 str = "check/crc"; 453 break; 454 case HAMMER2_ERROR_INCOMPLETE: 455 str = "incomplete-node"; 456 break; 457 default: 458 str = "unknown"; 459 break; 460 } 461 return (str); 462 } 463