Merge from vendor branch GDB:
[dragonfly.git] / sys / vfs / hammer / hammer_subs.c
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.12 2008/01/18 07:02:41 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
338         tid = strtoq(str, NULL, 16) * 1000000000LL;
339         return(tid);
340 }
341