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