xref: /dflybsd-src/sys/vfs/hammer/hammer_subs.c (revision 6a37e7e4b492073cdb3c293d5a142462d05342eb)
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