xref: /dragonfly/sys/vfs/hammer/hammer_subs.c (revision 9b5ae8ee)
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