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.7 2007/11/27 07:48:52 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 ++lock->lockcount; 60 crit_exit(); 61 } 62 63 /* 64 * Try to obtain an exclusive lock 65 */ 66 int 67 hammer_lock_ex_try(struct hammer_lock *lock) 68 { 69 thread_t td = curthread; 70 71 KKASSERT(lock->refs > 0); 72 crit_enter(); 73 if (lock->locktd != td) { 74 if (lock->locktd != NULL || lock->lockcount) 75 return(EAGAIN); 76 lock->locktd = td; 77 } 78 ++lock->lockcount; 79 crit_exit(); 80 return(0); 81 } 82 83 84 void 85 hammer_lock_sh(struct hammer_lock *lock) 86 { 87 KKASSERT(lock->refs > 0); 88 crit_enter(); 89 while (lock->locktd != NULL) { 90 if (lock->locktd == curthread) { 91 ++lock->lockcount; 92 crit_exit(); 93 return; 94 } 95 lock->wanted = 1; 96 tsleep(lock, 0, "hmrlck", 0); 97 } 98 KKASSERT(lock->lockcount <= 0); 99 --lock->lockcount; 100 crit_exit(); 101 } 102 103 void 104 hammer_downgrade(struct hammer_lock *lock) 105 { 106 KKASSERT(lock->lockcount == 1); 107 crit_enter(); 108 lock->lockcount = -1; 109 lock->locktd = NULL; 110 if (lock->wanted) { 111 lock->wanted = 0; 112 wakeup(lock); 113 } 114 crit_exit(); 115 /* XXX memory barrier */ 116 } 117 118 void 119 hammer_unlock(struct hammer_lock *lock) 120 { 121 crit_enter(); 122 KKASSERT(lock->lockcount != 0); 123 if (lock->lockcount < 0) { 124 if (++lock->lockcount == 0 && lock->wanted) { 125 lock->wanted = 0; 126 wakeup(lock); 127 } 128 } else { 129 KKASSERT(lock->locktd == curthread); 130 if (--lock->lockcount == 0) { 131 lock->locktd = NULL; 132 if (lock->wanted) { 133 lock->wanted = 0; 134 wakeup(lock); 135 } 136 } 137 138 } 139 crit_exit(); 140 } 141 142 void 143 hammer_ref(struct hammer_lock *lock) 144 { 145 crit_enter(); 146 ++lock->refs; 147 crit_exit(); 148 } 149 150 void 151 hammer_unref(struct hammer_lock *lock) 152 { 153 crit_enter(); 154 KKASSERT(lock->refs > 0); 155 --lock->refs; 156 crit_exit(); 157 } 158 159 u_int32_t 160 hammer_to_unix_xid(uuid_t *uuid) 161 { 162 return(*(u_int32_t *)&uuid->node[2]); 163 } 164 165 void 166 hammer_guid_to_uuid(uuid_t *uuid, u_int32_t guid) 167 { 168 bzero(uuid, sizeof(*uuid)); 169 *(u_int32_t *)&uuid->node[2] = guid; 170 } 171 172 void 173 hammer_to_timespec(hammer_tid_t tid, struct timespec *ts) 174 { 175 ts->tv_sec = tid / 1000000000; 176 ts->tv_nsec = tid % 1000000000; 177 } 178 179 hammer_tid_t 180 hammer_timespec_to_transid(struct timespec *ts) 181 { 182 hammer_tid_t tid; 183 184 tid = ts->tv_nsec + (unsigned long)ts->tv_sec * 1000000000LL; 185 return(tid); 186 } 187 188 189 /* 190 * Convert a HAMMER filesystem object type to a vnode type 191 */ 192 enum vtype 193 hammer_get_vnode_type(u_int8_t obj_type) 194 { 195 switch(obj_type) { 196 case HAMMER_OBJTYPE_DIRECTORY: 197 return(VDIR); 198 case HAMMER_OBJTYPE_REGFILE: 199 return(VREG); 200 case HAMMER_OBJTYPE_DBFILE: 201 return(VDATABASE); 202 case HAMMER_OBJTYPE_FIFO: 203 return(VFIFO); 204 case HAMMER_OBJTYPE_CDEV: 205 return(VCHR); 206 case HAMMER_OBJTYPE_BDEV: 207 return(VBLK); 208 case HAMMER_OBJTYPE_SOFTLINK: 209 return(VLNK); 210 default: 211 return(VBAD); 212 } 213 /* not reached */ 214 } 215 216 int 217 hammer_get_dtype(u_int8_t obj_type) 218 { 219 switch(obj_type) { 220 case HAMMER_OBJTYPE_DIRECTORY: 221 return(DT_DIR); 222 case HAMMER_OBJTYPE_REGFILE: 223 return(DT_REG); 224 case HAMMER_OBJTYPE_DBFILE: 225 return(DT_DBF); 226 case HAMMER_OBJTYPE_FIFO: 227 return(DT_FIFO); 228 case HAMMER_OBJTYPE_CDEV: 229 return(DT_CHR); 230 case HAMMER_OBJTYPE_BDEV: 231 return(DT_BLK); 232 case HAMMER_OBJTYPE_SOFTLINK: 233 return(DT_LNK); 234 default: 235 return(DT_UNKNOWN); 236 } 237 /* not reached */ 238 } 239 240 u_int8_t 241 hammer_get_obj_type(enum vtype vtype) 242 { 243 switch(vtype) { 244 case VDIR: 245 return(HAMMER_OBJTYPE_DIRECTORY); 246 case VREG: 247 return(HAMMER_OBJTYPE_REGFILE); 248 case VDATABASE: 249 return(HAMMER_OBJTYPE_DBFILE); 250 case VFIFO: 251 return(HAMMER_OBJTYPE_FIFO); 252 case VCHR: 253 return(HAMMER_OBJTYPE_CDEV); 254 case VBLK: 255 return(HAMMER_OBJTYPE_BDEV); 256 case VLNK: 257 return(HAMMER_OBJTYPE_SOFTLINK); 258 default: 259 return(HAMMER_OBJTYPE_UNKNOWN); 260 } 261 /* not reached */ 262 } 263 264 /* 265 * Return a namekey hash. The 64 bit namekey hash consists of a 32 bit 266 * crc in the MSB and 0 in the LSB. The caller will use the low bits to 267 * generate a unique key and will scan all entries with the same upper 268 * 32 bits when issuing a lookup. 269 * 270 * We strip bit 63 in order to provide a positive key, this way a seek 271 * offset of 0 will represent the base of the directory. 272 */ 273 int64_t 274 hammer_directory_namekey(void *name, int len) 275 { 276 int64_t key; 277 278 key = (int64_t)(crc32(name, len) & 0x7FFFFFFF) << 32; 279 return(key); 280 } 281 282 hammer_tid_t 283 hammer_now_tid(void) 284 { 285 struct timespec ts; 286 hammer_tid_t tid; 287 288 getnanotime(&ts); 289 tid = ts.tv_sec * 1000000000LL + ts.tv_nsec; 290 return(tid); 291 } 292 293