1427e5fc6SMatthew Dillon /* 2427e5fc6SMatthew Dillon * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3427e5fc6SMatthew Dillon * 4427e5fc6SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 5427e5fc6SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 6427e5fc6SMatthew Dillon * 7427e5fc6SMatthew Dillon * Redistribution and use in source and binary forms, with or without 8427e5fc6SMatthew Dillon * modification, are permitted provided that the following conditions 9427e5fc6SMatthew Dillon * are met: 10427e5fc6SMatthew Dillon * 11427e5fc6SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 12427e5fc6SMatthew Dillon * notice, this list of conditions and the following disclaimer. 13427e5fc6SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 14427e5fc6SMatthew Dillon * notice, this list of conditions and the following disclaimer in 15427e5fc6SMatthew Dillon * the documentation and/or other materials provided with the 16427e5fc6SMatthew Dillon * distribution. 17427e5fc6SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 18427e5fc6SMatthew Dillon * contributors may be used to endorse or promote products derived 19427e5fc6SMatthew Dillon * from this software without specific, prior written permission. 20427e5fc6SMatthew Dillon * 21427e5fc6SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22427e5fc6SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23427e5fc6SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24427e5fc6SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25427e5fc6SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26427e5fc6SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27427e5fc6SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28427e5fc6SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29427e5fc6SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30427e5fc6SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31427e5fc6SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32427e5fc6SMatthew Dillon * SUCH DAMAGE. 33427e5fc6SMatthew Dillon * 34*6a37e7e4SMatthew Dillon * $DragonFly: src/sys/vfs/hammer/hammer_subs.c,v 1.12 2008/01/18 07:02:41 dillon Exp $ 35427e5fc6SMatthew Dillon */ 36427e5fc6SMatthew Dillon /* 37427e5fc6SMatthew Dillon * HAMMER structural locking 38427e5fc6SMatthew Dillon */ 39427e5fc6SMatthew Dillon 40427e5fc6SMatthew Dillon #include "hammer.h" 416b4f890bSMatthew Dillon #include <sys/dirent.h> 42427e5fc6SMatthew Dillon 43427e5fc6SMatthew Dillon void 448cd0a023SMatthew Dillon hammer_lock_ex(struct hammer_lock *lock) 45427e5fc6SMatthew Dillon { 46427e5fc6SMatthew Dillon thread_t td = curthread; 47427e5fc6SMatthew Dillon 488cd0a023SMatthew Dillon KKASSERT(lock->refs > 0); 4966325755SMatthew Dillon crit_enter(); 50427e5fc6SMatthew Dillon if (lock->locktd != td) { 51c0ade690SMatthew Dillon while (lock->locktd != NULL || lock->lockcount) { 52427e5fc6SMatthew Dillon lock->wanted = 1; 53c0ade690SMatthew Dillon kprintf("hammer_lock_ex: held by %p\n", lock->locktd); 54427e5fc6SMatthew Dillon tsleep(lock, 0, "hmrlck", 0); 55c0ade690SMatthew Dillon kprintf("hammer_lock_ex: try again\n"); 56427e5fc6SMatthew Dillon } 57427e5fc6SMatthew Dillon lock->locktd = td; 58427e5fc6SMatthew Dillon } 590b075555SMatthew Dillon KKASSERT(lock->lockcount >= 0); 608cd0a023SMatthew Dillon ++lock->lockcount; 618cd0a023SMatthew Dillon crit_exit(); 628cd0a023SMatthew Dillon } 638cd0a023SMatthew Dillon 648cd0a023SMatthew Dillon /* 658cd0a023SMatthew Dillon * Try to obtain an exclusive lock 668cd0a023SMatthew Dillon */ 678cd0a023SMatthew Dillon int 688cd0a023SMatthew Dillon hammer_lock_ex_try(struct hammer_lock *lock) 698cd0a023SMatthew Dillon { 708cd0a023SMatthew Dillon thread_t td = curthread; 718cd0a023SMatthew Dillon 728cd0a023SMatthew Dillon KKASSERT(lock->refs > 0); 738cd0a023SMatthew Dillon crit_enter(); 748cd0a023SMatthew Dillon if (lock->locktd != td) { 754d75d829SMatthew Dillon if (lock->locktd != NULL || lock->lockcount) { 764d75d829SMatthew Dillon crit_exit(); 778cd0a023SMatthew Dillon return(EAGAIN); 784d75d829SMatthew Dillon } 798cd0a023SMatthew Dillon lock->locktd = td; 808cd0a023SMatthew Dillon } 810b075555SMatthew Dillon KKASSERT(lock->lockcount >= 0); 828cd0a023SMatthew Dillon ++lock->lockcount; 838cd0a023SMatthew Dillon crit_exit(); 848cd0a023SMatthew Dillon return(0); 858cd0a023SMatthew Dillon } 868cd0a023SMatthew Dillon 878cd0a023SMatthew Dillon void 888cd0a023SMatthew Dillon hammer_lock_sh(struct hammer_lock *lock) 898cd0a023SMatthew Dillon { 908cd0a023SMatthew Dillon KKASSERT(lock->refs > 0); 918cd0a023SMatthew Dillon crit_enter(); 928cd0a023SMatthew Dillon while (lock->locktd != NULL) { 938cd0a023SMatthew Dillon if (lock->locktd == curthread) { 94*6a37e7e4SMatthew Dillon Debugger("hammer_lock_sh: lock_sh on exclusive"); 958cd0a023SMatthew Dillon ++lock->lockcount; 968cd0a023SMatthew Dillon crit_exit(); 978cd0a023SMatthew Dillon return; 988cd0a023SMatthew Dillon } 998cd0a023SMatthew Dillon lock->wanted = 1; 1008cd0a023SMatthew Dillon tsleep(lock, 0, "hmrlck", 0); 1018cd0a023SMatthew Dillon } 1028cd0a023SMatthew Dillon KKASSERT(lock->lockcount <= 0); 1038cd0a023SMatthew Dillon --lock->lockcount; 10466325755SMatthew Dillon crit_exit(); 105427e5fc6SMatthew Dillon } 106427e5fc6SMatthew Dillon 107*6a37e7e4SMatthew Dillon /* 108*6a37e7e4SMatthew Dillon * Upgrade a shared lock to an exclusively held lock. This function will 109*6a37e7e4SMatthew Dillon * return EDEADLK If there is more then one shared holder. 110*6a37e7e4SMatthew Dillon * 111*6a37e7e4SMatthew Dillon * No error occurs and no action is taken if the lock is already exclusively 112*6a37e7e4SMatthew Dillon * held by the caller. 113*6a37e7e4SMatthew Dillon */ 114*6a37e7e4SMatthew Dillon int 115*6a37e7e4SMatthew Dillon hammer_lock_upgrade(struct hammer_lock *lock) 116*6a37e7e4SMatthew Dillon { 117*6a37e7e4SMatthew Dillon int error; 118*6a37e7e4SMatthew Dillon 119*6a37e7e4SMatthew Dillon crit_enter(); 120*6a37e7e4SMatthew Dillon if (lock->lockcount > 0) { 121*6a37e7e4SMatthew Dillon KKASSERT(lock->locktd == curthread); 122*6a37e7e4SMatthew Dillon error = 0; 123*6a37e7e4SMatthew Dillon } else if (lock->lockcount == -1) { 124*6a37e7e4SMatthew Dillon lock->lockcount = 1; 125*6a37e7e4SMatthew Dillon lock->locktd = curthread; 126*6a37e7e4SMatthew Dillon error = 0; 127*6a37e7e4SMatthew Dillon } else { 128*6a37e7e4SMatthew Dillon error = EDEADLK; 129*6a37e7e4SMatthew Dillon } 130*6a37e7e4SMatthew Dillon crit_exit(); 131*6a37e7e4SMatthew Dillon return(error); 132*6a37e7e4SMatthew Dillon } 133*6a37e7e4SMatthew Dillon 134*6a37e7e4SMatthew Dillon /* 135*6a37e7e4SMatthew Dillon * Downgrade an exclusively held lock to a shared lock. 136*6a37e7e4SMatthew Dillon */ 137427e5fc6SMatthew Dillon void 138*6a37e7e4SMatthew Dillon hammer_lock_downgrade(struct hammer_lock *lock) 139427e5fc6SMatthew Dillon { 1408cd0a023SMatthew Dillon KKASSERT(lock->lockcount == 1); 14166325755SMatthew Dillon crit_enter(); 1428cd0a023SMatthew Dillon lock->lockcount = -1; 143427e5fc6SMatthew Dillon lock->locktd = NULL; 144427e5fc6SMatthew Dillon if (lock->wanted) { 145427e5fc6SMatthew Dillon lock->wanted = 0; 146427e5fc6SMatthew Dillon wakeup(lock); 147427e5fc6SMatthew Dillon } 1488cd0a023SMatthew Dillon crit_exit(); 1498cd0a023SMatthew Dillon /* XXX memory barrier */ 1508cd0a023SMatthew Dillon } 1518cd0a023SMatthew Dillon 1528cd0a023SMatthew Dillon void 1538cd0a023SMatthew Dillon hammer_unlock(struct hammer_lock *lock) 1548cd0a023SMatthew Dillon { 1558cd0a023SMatthew Dillon crit_enter(); 1568cd0a023SMatthew Dillon KKASSERT(lock->lockcount != 0); 1578cd0a023SMatthew Dillon if (lock->lockcount < 0) { 1588cd0a023SMatthew Dillon if (++lock->lockcount == 0 && lock->wanted) { 1598cd0a023SMatthew Dillon lock->wanted = 0; 1608cd0a023SMatthew Dillon wakeup(lock); 1618cd0a023SMatthew Dillon } 1628cd0a023SMatthew Dillon } else { 1638cd0a023SMatthew Dillon KKASSERT(lock->locktd == curthread); 1648cd0a023SMatthew Dillon if (--lock->lockcount == 0) { 1658cd0a023SMatthew Dillon lock->locktd = NULL; 1668cd0a023SMatthew Dillon if (lock->wanted) { 1678cd0a023SMatthew Dillon lock->wanted = 0; 1688cd0a023SMatthew Dillon wakeup(lock); 1698cd0a023SMatthew Dillon } 1708cd0a023SMatthew Dillon } 1718cd0a023SMatthew Dillon 172427e5fc6SMatthew Dillon } 17366325755SMatthew Dillon crit_exit(); 17466325755SMatthew Dillon } 17566325755SMatthew Dillon 17666325755SMatthew Dillon void 17766325755SMatthew Dillon hammer_ref(struct hammer_lock *lock) 17866325755SMatthew Dillon { 1790b075555SMatthew Dillon KKASSERT(lock->refs >= 0); 18066325755SMatthew Dillon crit_enter(); 18166325755SMatthew Dillon ++lock->refs; 18266325755SMatthew Dillon crit_exit(); 18366325755SMatthew Dillon } 18466325755SMatthew Dillon 18566325755SMatthew Dillon void 18666325755SMatthew Dillon hammer_unref(struct hammer_lock *lock) 18766325755SMatthew Dillon { 188a89aec1bSMatthew Dillon KKASSERT(lock->refs > 0); 1890b075555SMatthew Dillon crit_enter(); 19066325755SMatthew Dillon --lock->refs; 19166325755SMatthew Dillon crit_exit(); 19266325755SMatthew Dillon } 19366325755SMatthew Dillon 19466325755SMatthew Dillon u_int32_t 19566325755SMatthew Dillon hammer_to_unix_xid(uuid_t *uuid) 19666325755SMatthew Dillon { 19766325755SMatthew Dillon return(*(u_int32_t *)&uuid->node[2]); 19866325755SMatthew Dillon } 19966325755SMatthew Dillon 20066325755SMatthew Dillon void 2018cd0a023SMatthew Dillon hammer_guid_to_uuid(uuid_t *uuid, u_int32_t guid) 20266325755SMatthew Dillon { 2038cd0a023SMatthew Dillon bzero(uuid, sizeof(*uuid)); 2048cd0a023SMatthew Dillon *(u_int32_t *)&uuid->node[2] = guid; 20566325755SMatthew Dillon } 20666325755SMatthew Dillon 2078cd0a023SMatthew Dillon void 2088cd0a023SMatthew Dillon hammer_to_timespec(hammer_tid_t tid, struct timespec *ts) 2098cd0a023SMatthew Dillon { 2108cd0a023SMatthew Dillon ts->tv_sec = tid / 1000000000; 2118cd0a023SMatthew Dillon ts->tv_nsec = tid % 1000000000; 2128cd0a023SMatthew Dillon } 2138cd0a023SMatthew Dillon 2148cd0a023SMatthew Dillon hammer_tid_t 2158cd0a023SMatthew Dillon hammer_timespec_to_transid(struct timespec *ts) 2168cd0a023SMatthew Dillon { 2178cd0a023SMatthew Dillon hammer_tid_t tid; 2188cd0a023SMatthew Dillon 2198cd0a023SMatthew Dillon tid = ts->tv_nsec + (unsigned long)ts->tv_sec * 1000000000LL; 2208cd0a023SMatthew Dillon return(tid); 2218cd0a023SMatthew Dillon } 2228cd0a023SMatthew Dillon 2238cd0a023SMatthew Dillon 22466325755SMatthew Dillon /* 22566325755SMatthew Dillon * Convert a HAMMER filesystem object type to a vnode type 22666325755SMatthew Dillon */ 22766325755SMatthew Dillon enum vtype 22866325755SMatthew Dillon hammer_get_vnode_type(u_int8_t obj_type) 22966325755SMatthew Dillon { 23066325755SMatthew Dillon switch(obj_type) { 23166325755SMatthew Dillon case HAMMER_OBJTYPE_DIRECTORY: 23266325755SMatthew Dillon return(VDIR); 23366325755SMatthew Dillon case HAMMER_OBJTYPE_REGFILE: 23466325755SMatthew Dillon return(VREG); 23566325755SMatthew Dillon case HAMMER_OBJTYPE_DBFILE: 23666325755SMatthew Dillon return(VDATABASE); 23766325755SMatthew Dillon case HAMMER_OBJTYPE_FIFO: 23866325755SMatthew Dillon return(VFIFO); 23966325755SMatthew Dillon case HAMMER_OBJTYPE_CDEV: 24066325755SMatthew Dillon return(VCHR); 24166325755SMatthew Dillon case HAMMER_OBJTYPE_BDEV: 24266325755SMatthew Dillon return(VBLK); 24366325755SMatthew Dillon case HAMMER_OBJTYPE_SOFTLINK: 24466325755SMatthew Dillon return(VLNK); 24566325755SMatthew Dillon default: 24666325755SMatthew Dillon return(VBAD); 24766325755SMatthew Dillon } 24866325755SMatthew Dillon /* not reached */ 24966325755SMatthew Dillon } 25066325755SMatthew Dillon 2516b4f890bSMatthew Dillon int 2526b4f890bSMatthew Dillon hammer_get_dtype(u_int8_t obj_type) 2536b4f890bSMatthew Dillon { 2546b4f890bSMatthew Dillon switch(obj_type) { 2556b4f890bSMatthew Dillon case HAMMER_OBJTYPE_DIRECTORY: 2566b4f890bSMatthew Dillon return(DT_DIR); 2576b4f890bSMatthew Dillon case HAMMER_OBJTYPE_REGFILE: 2586b4f890bSMatthew Dillon return(DT_REG); 2596b4f890bSMatthew Dillon case HAMMER_OBJTYPE_DBFILE: 2606b4f890bSMatthew Dillon return(DT_DBF); 2616b4f890bSMatthew Dillon case HAMMER_OBJTYPE_FIFO: 2626b4f890bSMatthew Dillon return(DT_FIFO); 2636b4f890bSMatthew Dillon case HAMMER_OBJTYPE_CDEV: 2646b4f890bSMatthew Dillon return(DT_CHR); 2656b4f890bSMatthew Dillon case HAMMER_OBJTYPE_BDEV: 2666b4f890bSMatthew Dillon return(DT_BLK); 2676b4f890bSMatthew Dillon case HAMMER_OBJTYPE_SOFTLINK: 2686b4f890bSMatthew Dillon return(DT_LNK); 2696b4f890bSMatthew Dillon default: 2706b4f890bSMatthew Dillon return(DT_UNKNOWN); 2716b4f890bSMatthew Dillon } 2726b4f890bSMatthew Dillon /* not reached */ 2736b4f890bSMatthew Dillon } 2746b4f890bSMatthew Dillon 27566325755SMatthew Dillon u_int8_t 27666325755SMatthew Dillon hammer_get_obj_type(enum vtype vtype) 27766325755SMatthew Dillon { 27866325755SMatthew Dillon switch(vtype) { 27966325755SMatthew Dillon case VDIR: 28066325755SMatthew Dillon return(HAMMER_OBJTYPE_DIRECTORY); 28166325755SMatthew Dillon case VREG: 28266325755SMatthew Dillon return(HAMMER_OBJTYPE_REGFILE); 28366325755SMatthew Dillon case VDATABASE: 28466325755SMatthew Dillon return(HAMMER_OBJTYPE_DBFILE); 28566325755SMatthew Dillon case VFIFO: 28666325755SMatthew Dillon return(HAMMER_OBJTYPE_FIFO); 28766325755SMatthew Dillon case VCHR: 28866325755SMatthew Dillon return(HAMMER_OBJTYPE_CDEV); 28966325755SMatthew Dillon case VBLK: 29066325755SMatthew Dillon return(HAMMER_OBJTYPE_BDEV); 29166325755SMatthew Dillon case VLNK: 29266325755SMatthew Dillon return(HAMMER_OBJTYPE_SOFTLINK); 29366325755SMatthew Dillon default: 29466325755SMatthew Dillon return(HAMMER_OBJTYPE_UNKNOWN); 29566325755SMatthew Dillon } 29666325755SMatthew Dillon /* not reached */ 29766325755SMatthew Dillon } 29866325755SMatthew Dillon 29966325755SMatthew Dillon /* 30066325755SMatthew Dillon * Return a namekey hash. The 64 bit namekey hash consists of a 32 bit 30166325755SMatthew Dillon * crc in the MSB and 0 in the LSB. The caller will use the low bits to 30266325755SMatthew Dillon * generate a unique key and will scan all entries with the same upper 30366325755SMatthew Dillon * 32 bits when issuing a lookup. 3046b4f890bSMatthew Dillon * 3056b4f890bSMatthew Dillon * We strip bit 63 in order to provide a positive key, this way a seek 3066b4f890bSMatthew Dillon * offset of 0 will represent the base of the directory. 307b3deaf57SMatthew Dillon * 308b3deaf57SMatthew Dillon * This function can never return 0. We use the MSB-0 space to synthesize 309b3deaf57SMatthew Dillon * artificial directory entries such as "." and "..". 31066325755SMatthew Dillon */ 31166325755SMatthew Dillon int64_t 31266325755SMatthew Dillon hammer_directory_namekey(void *name, int len) 31366325755SMatthew Dillon { 31466325755SMatthew Dillon int64_t key; 31566325755SMatthew Dillon 3166b4f890bSMatthew Dillon key = (int64_t)(crc32(name, len) & 0x7FFFFFFF) << 32; 317b3deaf57SMatthew Dillon if (key == 0) 318b3deaf57SMatthew Dillon key |= 0x100000000LL; 31966325755SMatthew Dillon return(key); 320427e5fc6SMatthew Dillon } 321427e5fc6SMatthew Dillon 3227f7c1f84SMatthew Dillon hammer_tid_t 3237f7c1f84SMatthew Dillon hammer_now_tid(void) 3247f7c1f84SMatthew Dillon { 3257f7c1f84SMatthew Dillon struct timespec ts; 3267f7c1f84SMatthew Dillon hammer_tid_t tid; 3277f7c1f84SMatthew Dillon 3287f7c1f84SMatthew Dillon getnanotime(&ts); 3297f7c1f84SMatthew Dillon tid = ts.tv_sec * 1000000000LL + ts.tv_nsec; 3307f7c1f84SMatthew Dillon return(tid); 3317f7c1f84SMatthew Dillon } 3327f7c1f84SMatthew Dillon 333d113fda1SMatthew Dillon hammer_tid_t 334d113fda1SMatthew Dillon hammer_str_to_tid(const char *str) 335d113fda1SMatthew Dillon { 336d113fda1SMatthew Dillon hammer_tid_t tid; 337d113fda1SMatthew Dillon 338d113fda1SMatthew Dillon tid = strtoq(str, NULL, 16) * 1000000000LL; 339d113fda1SMatthew Dillon return(tid); 340d113fda1SMatthew Dillon } 341d113fda1SMatthew Dillon 342