1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/vfs/hammer/hammer_subs.c,v 1.13 2008/02/04 08:33:17 dillon Exp $ 35 */ 36 /* 37 * HAMMER structural locking 38 */ 39 40 #include "hammer.h" 41 #include <sys/dirent.h> 42 43 void 44 hammer_lock_ex(struct hammer_lock *lock) 45 { 46 thread_t td = curthread; 47 48 KKASSERT(lock->refs > 0); 49 crit_enter(); 50 if (lock->locktd != td) { 51 while (lock->locktd != NULL || lock->lockcount) { 52 lock->wanted = 1; 53 kprintf("hammer_lock_ex: held by %p\n", lock->locktd); 54 tsleep(lock, 0, "hmrlck", 0); 55 kprintf("hammer_lock_ex: try again\n"); 56 } 57 lock->locktd = td; 58 } 59 KKASSERT(lock->lockcount >= 0); 60 ++lock->lockcount; 61 crit_exit(); 62 } 63 64 /* 65 * Try to obtain an exclusive lock 66 */ 67 int 68 hammer_lock_ex_try(struct hammer_lock *lock) 69 { 70 thread_t td = curthread; 71 72 KKASSERT(lock->refs > 0); 73 crit_enter(); 74 if (lock->locktd != td) { 75 if (lock->locktd != NULL || lock->lockcount) { 76 crit_exit(); 77 return(EAGAIN); 78 } 79 lock->locktd = td; 80 } 81 KKASSERT(lock->lockcount >= 0); 82 ++lock->lockcount; 83 crit_exit(); 84 return(0); 85 } 86 87 void 88 hammer_lock_sh(struct hammer_lock *lock) 89 { 90 KKASSERT(lock->refs > 0); 91 crit_enter(); 92 while (lock->locktd != NULL) { 93 if (lock->locktd == curthread) { 94 Debugger("hammer_lock_sh: lock_sh on exclusive"); 95 ++lock->lockcount; 96 crit_exit(); 97 return; 98 } 99 lock->wanted = 1; 100 tsleep(lock, 0, "hmrlck", 0); 101 } 102 KKASSERT(lock->lockcount <= 0); 103 --lock->lockcount; 104 crit_exit(); 105 } 106 107 /* 108 * Upgrade a shared lock to an exclusively held lock. This function will 109 * return EDEADLK If there is more then one shared holder. 110 * 111 * No error occurs and no action is taken if the lock is already exclusively 112 * held by the caller. 113 */ 114 int 115 hammer_lock_upgrade(struct hammer_lock *lock) 116 { 117 int error; 118 119 crit_enter(); 120 if (lock->lockcount > 0) { 121 KKASSERT(lock->locktd == curthread); 122 error = 0; 123 } else if (lock->lockcount == -1) { 124 lock->lockcount = 1; 125 lock->locktd = curthread; 126 error = 0; 127 } else { 128 error = EDEADLK; 129 } 130 crit_exit(); 131 return(error); 132 } 133 134 /* 135 * Downgrade an exclusively held lock to a shared lock. 136 */ 137 void 138 hammer_lock_downgrade(struct hammer_lock *lock) 139 { 140 KKASSERT(lock->lockcount == 1); 141 crit_enter(); 142 lock->lockcount = -1; 143 lock->locktd = NULL; 144 if (lock->wanted) { 145 lock->wanted = 0; 146 wakeup(lock); 147 } 148 crit_exit(); 149 /* XXX memory barrier */ 150 } 151 152 void 153 hammer_unlock(struct hammer_lock *lock) 154 { 155 crit_enter(); 156 KKASSERT(lock->lockcount != 0); 157 if (lock->lockcount < 0) { 158 if (++lock->lockcount == 0 && lock->wanted) { 159 lock->wanted = 0; 160 wakeup(lock); 161 } 162 } else { 163 KKASSERT(lock->locktd == curthread); 164 if (--lock->lockcount == 0) { 165 lock->locktd = NULL; 166 if (lock->wanted) { 167 lock->wanted = 0; 168 wakeup(lock); 169 } 170 } 171 172 } 173 crit_exit(); 174 } 175 176 void 177 hammer_ref(struct hammer_lock *lock) 178 { 179 KKASSERT(lock->refs >= 0); 180 crit_enter(); 181 ++lock->refs; 182 crit_exit(); 183 } 184 185 void 186 hammer_unref(struct hammer_lock *lock) 187 { 188 KKASSERT(lock->refs > 0); 189 crit_enter(); 190 --lock->refs; 191 crit_exit(); 192 } 193 194 u_int32_t 195 hammer_to_unix_xid(uuid_t *uuid) 196 { 197 return(*(u_int32_t *)&uuid->node[2]); 198 } 199 200 void 201 hammer_guid_to_uuid(uuid_t *uuid, u_int32_t guid) 202 { 203 bzero(uuid, sizeof(*uuid)); 204 *(u_int32_t *)&uuid->node[2] = guid; 205 } 206 207 void 208 hammer_to_timespec(hammer_tid_t tid, struct timespec *ts) 209 { 210 ts->tv_sec = tid / 1000000000; 211 ts->tv_nsec = tid % 1000000000; 212 } 213 214 hammer_tid_t 215 hammer_timespec_to_transid(struct timespec *ts) 216 { 217 hammer_tid_t tid; 218 219 tid = ts->tv_nsec + (unsigned long)ts->tv_sec * 1000000000LL; 220 return(tid); 221 } 222 223 224 /* 225 * Convert a HAMMER filesystem object type to a vnode type 226 */ 227 enum vtype 228 hammer_get_vnode_type(u_int8_t obj_type) 229 { 230 switch(obj_type) { 231 case HAMMER_OBJTYPE_DIRECTORY: 232 return(VDIR); 233 case HAMMER_OBJTYPE_REGFILE: 234 return(VREG); 235 case HAMMER_OBJTYPE_DBFILE: 236 return(VDATABASE); 237 case HAMMER_OBJTYPE_FIFO: 238 return(VFIFO); 239 case HAMMER_OBJTYPE_CDEV: 240 return(VCHR); 241 case HAMMER_OBJTYPE_BDEV: 242 return(VBLK); 243 case HAMMER_OBJTYPE_SOFTLINK: 244 return(VLNK); 245 default: 246 return(VBAD); 247 } 248 /* not reached */ 249 } 250 251 int 252 hammer_get_dtype(u_int8_t obj_type) 253 { 254 switch(obj_type) { 255 case HAMMER_OBJTYPE_DIRECTORY: 256 return(DT_DIR); 257 case HAMMER_OBJTYPE_REGFILE: 258 return(DT_REG); 259 case HAMMER_OBJTYPE_DBFILE: 260 return(DT_DBF); 261 case HAMMER_OBJTYPE_FIFO: 262 return(DT_FIFO); 263 case HAMMER_OBJTYPE_CDEV: 264 return(DT_CHR); 265 case HAMMER_OBJTYPE_BDEV: 266 return(DT_BLK); 267 case HAMMER_OBJTYPE_SOFTLINK: 268 return(DT_LNK); 269 default: 270 return(DT_UNKNOWN); 271 } 272 /* not reached */ 273 } 274 275 u_int8_t 276 hammer_get_obj_type(enum vtype vtype) 277 { 278 switch(vtype) { 279 case VDIR: 280 return(HAMMER_OBJTYPE_DIRECTORY); 281 case VREG: 282 return(HAMMER_OBJTYPE_REGFILE); 283 case VDATABASE: 284 return(HAMMER_OBJTYPE_DBFILE); 285 case VFIFO: 286 return(HAMMER_OBJTYPE_FIFO); 287 case VCHR: 288 return(HAMMER_OBJTYPE_CDEV); 289 case VBLK: 290 return(HAMMER_OBJTYPE_BDEV); 291 case VLNK: 292 return(HAMMER_OBJTYPE_SOFTLINK); 293 default: 294 return(HAMMER_OBJTYPE_UNKNOWN); 295 } 296 /* not reached */ 297 } 298 299 /* 300 * Return a namekey hash. The 64 bit namekey hash consists of a 32 bit 301 * crc in the MSB and 0 in the LSB. The caller will use the low bits to 302 * generate a unique key and will scan all entries with the same upper 303 * 32 bits when issuing a lookup. 304 * 305 * We strip bit 63 in order to provide a positive key, this way a seek 306 * offset of 0 will represent the base of the directory. 307 * 308 * This function can never return 0. We use the MSB-0 space to synthesize 309 * artificial directory entries such as "." and "..". 310 */ 311 int64_t 312 hammer_directory_namekey(void *name, int len) 313 { 314 int64_t key; 315 316 key = (int64_t)(crc32(name, len) & 0x7FFFFFFF) << 32; 317 if (key == 0) 318 key |= 0x100000000LL; 319 return(key); 320 } 321 322 hammer_tid_t 323 hammer_now_tid(void) 324 { 325 struct timespec ts; 326 hammer_tid_t tid; 327 328 getnanotime(&ts); 329 tid = ts.tv_sec * 1000000000LL + ts.tv_nsec; 330 return(tid); 331 } 332 333 hammer_tid_t 334 hammer_str_to_tid(const char *str) 335 { 336 hammer_tid_t tid; 337 int len = strlen(str); 338 339 if (len > 10) 340 tid = strtouq(str, NULL, 0); /* full TID */ 341 else 342 tid = strtouq(str, NULL, 0) * 1000000000LL; /* time_t */ 343 return(tid); 344 } 345 346