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.lock); 52 } 53 54 void 55 hammer2_dev_shlock(hammer2_dev_t *hmp) 56 { 57 hammer2_mtx_sh(&hmp->vchain.lock); 58 } 59 60 void 61 hammer2_dev_unlock(hammer2_dev_t *hmp) 62 { 63 hammer2_mtx_unlock(&hmp->vchain.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->meta.type) == HAMMER2_OBJTYPE_HARDLINK) 77 type = ipdata->meta.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(uint8_t type) 111 { 112 switch(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 * The logical block size is currently always PBUFSIZE. 320 */ 321 int 322 hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff, 323 hammer2_key_t *lbasep, hammer2_key_t *leofp) 324 { 325 KKASSERT(ip->flags & HAMMER2_INODE_METAGOOD); 326 if (lbasep) 327 *lbasep = uoff & ~HAMMER2_PBUFMASK64; 328 if (leofp) { 329 *leofp = (ip->meta.size + HAMMER2_PBUFMASK64) & 330 ~HAMMER2_PBUFMASK64; 331 } 332 return (HAMMER2_PBUFSIZE); 333 } 334 335 /* 336 * Calculate the physical block size. pblksize <= lblksize. Primarily 337 * used to calculate a smaller physical block for the logical block 338 * containing the file EOF. 339 * 340 * Returns 0 if the requested base offset is beyond the file EOF. 341 */ 342 int 343 hammer2_calc_physical(hammer2_inode_t *ip, hammer2_key_t lbase) 344 { 345 int lblksize; 346 int pblksize; 347 int eofbytes; 348 349 KKASSERT(ip->flags & HAMMER2_INODE_METAGOOD); 350 lblksize = hammer2_calc_logical(ip, lbase, NULL, NULL); 351 if (lbase + lblksize <= ip->meta.size) 352 return (lblksize); 353 if (lbase >= ip->meta.size) 354 return (0); 355 eofbytes = (int)(ip->meta.size - lbase); 356 pblksize = lblksize; 357 while (pblksize >= eofbytes && pblksize >= HAMMER2_ALLOC_MIN) 358 pblksize >>= 1; 359 pblksize <<= 1; 360 361 return (pblksize); 362 } 363 364 void 365 hammer2_update_time(uint64_t *timep) 366 { 367 struct timeval tv; 368 369 getmicrotime(&tv); 370 *timep = (unsigned long)tv.tv_sec * 1000000 + tv.tv_usec; 371 } 372 373 void 374 hammer2_adjreadcounter(hammer2_blockref_t *bref, size_t bytes) 375 { 376 long *counterp; 377 378 switch(bref->type) { 379 case HAMMER2_BREF_TYPE_DATA: 380 counterp = &hammer2_iod_file_read; 381 break; 382 case HAMMER2_BREF_TYPE_INODE: 383 counterp = &hammer2_iod_meta_read; 384 break; 385 case HAMMER2_BREF_TYPE_INDIRECT: 386 counterp = &hammer2_iod_indr_read; 387 break; 388 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 389 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 390 counterp = &hammer2_iod_fmap_read; 391 break; 392 default: 393 counterp = &hammer2_iod_volu_read; 394 break; 395 } 396 *counterp += bytes; 397 } 398 399 int 400 hammer2_signal_check(time_t *timep) 401 { 402 int error = 0; 403 404 lwkt_user_yield(); 405 if (*timep != time_second) { 406 *timep = time_second; 407 if (CURSIG(curthread->td_lwp) != 0) 408 error = EINTR; 409 } 410 return error; 411 } 412 413 const char * 414 hammer2_error_str(int error) 415 { 416 const char *str; 417 418 switch(error) { 419 case HAMMER2_ERROR_NONE: 420 str = "0"; 421 break; 422 case HAMMER2_ERROR_IO: 423 str = "I/O"; 424 break; 425 case HAMMER2_ERROR_CHECK: 426 str = "check/crc"; 427 break; 428 case HAMMER2_ERROR_INCOMPLETE: 429 str = "incomplete-node"; 430 break; 431 default: 432 str = "unknown"; 433 break; 434 } 435 return (str); 436 } 437