HAMMER 16/many - Recovery infrastructure, misc bug fixes
[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.11 2008/01/09 00:46:22 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                         ++lock->lockcount;
95                         crit_exit();
96                         return;
97                 }
98                 lock->wanted = 1;
99                 tsleep(lock, 0, "hmrlck", 0);
100         }
101         KKASSERT(lock->lockcount <= 0);
102         --lock->lockcount;
103         crit_exit();
104 }
105
106 void
107 hammer_downgrade(struct hammer_lock *lock)
108 {
109         KKASSERT(lock->lockcount == 1);
110         crit_enter();
111         lock->lockcount = -1;
112         lock->locktd = NULL;
113         if (lock->wanted) {
114                 lock->wanted = 0;
115                 wakeup(lock);
116         }
117         crit_exit();
118         /* XXX memory barrier */
119 }
120
121 void
122 hammer_unlock(struct hammer_lock *lock)
123 {
124         crit_enter();
125         KKASSERT(lock->lockcount != 0);
126         if (lock->lockcount < 0) {
127                 if (++lock->lockcount == 0 && lock->wanted) {
128                         lock->wanted = 0;
129                         wakeup(lock);
130                 }
131         } else {
132                 KKASSERT(lock->locktd == curthread);
133                 if (--lock->lockcount == 0) {
134                         lock->locktd = NULL;
135                         if (lock->wanted) {
136                                 lock->wanted = 0;
137                                 wakeup(lock);
138                         }
139                 }
140
141         }
142         crit_exit();
143 }
144
145 void
146 hammer_ref(struct hammer_lock *lock)
147 {
148         KKASSERT(lock->refs >= 0);
149         crit_enter();
150         ++lock->refs;
151         crit_exit();
152 }
153
154 void
155 hammer_unref(struct hammer_lock *lock)
156 {
157         KKASSERT(lock->refs > 0);
158         crit_enter();
159         --lock->refs;
160         crit_exit();
161 }
162
163 u_int32_t
164 hammer_to_unix_xid(uuid_t *uuid)
165 {
166         return(*(u_int32_t *)&uuid->node[2]);
167 }
168
169 void
170 hammer_guid_to_uuid(uuid_t *uuid, u_int32_t guid)
171 {
172         bzero(uuid, sizeof(*uuid));
173         *(u_int32_t *)&uuid->node[2] = guid;
174 }
175
176 void
177 hammer_to_timespec(hammer_tid_t tid, struct timespec *ts)
178 {
179         ts->tv_sec = tid / 1000000000;
180         ts->tv_nsec = tid % 1000000000;
181 }
182
183 hammer_tid_t
184 hammer_timespec_to_transid(struct timespec *ts)
185 {
186         hammer_tid_t tid;
187
188         tid = ts->tv_nsec + (unsigned long)ts->tv_sec * 1000000000LL;
189         return(tid);
190 }
191
192
193 /*
194  * Convert a HAMMER filesystem object type to a vnode type
195  */
196 enum vtype
197 hammer_get_vnode_type(u_int8_t obj_type)
198 {
199         switch(obj_type) {
200         case HAMMER_OBJTYPE_DIRECTORY:
201                 return(VDIR);
202         case HAMMER_OBJTYPE_REGFILE:
203                 return(VREG);
204         case HAMMER_OBJTYPE_DBFILE:
205                 return(VDATABASE);
206         case HAMMER_OBJTYPE_FIFO:
207                 return(VFIFO);
208         case HAMMER_OBJTYPE_CDEV:
209                 return(VCHR);
210         case HAMMER_OBJTYPE_BDEV:
211                 return(VBLK);
212         case HAMMER_OBJTYPE_SOFTLINK:
213                 return(VLNK);
214         default:
215                 return(VBAD);
216         }
217         /* not reached */
218 }
219
220 int
221 hammer_get_dtype(u_int8_t obj_type)
222 {
223         switch(obj_type) {
224         case HAMMER_OBJTYPE_DIRECTORY:
225                 return(DT_DIR);
226         case HAMMER_OBJTYPE_REGFILE:
227                 return(DT_REG);
228         case HAMMER_OBJTYPE_DBFILE:
229                 return(DT_DBF);
230         case HAMMER_OBJTYPE_FIFO:
231                 return(DT_FIFO);
232         case HAMMER_OBJTYPE_CDEV:
233                 return(DT_CHR);
234         case HAMMER_OBJTYPE_BDEV:
235                 return(DT_BLK);
236         case HAMMER_OBJTYPE_SOFTLINK:
237                 return(DT_LNK);
238         default:
239                 return(DT_UNKNOWN);
240         }
241         /* not reached */
242 }
243
244 u_int8_t
245 hammer_get_obj_type(enum vtype vtype)
246 {
247         switch(vtype) {
248         case VDIR:
249                 return(HAMMER_OBJTYPE_DIRECTORY);
250         case VREG:
251                 return(HAMMER_OBJTYPE_REGFILE);
252         case VDATABASE:
253                 return(HAMMER_OBJTYPE_DBFILE);
254         case VFIFO:
255                 return(HAMMER_OBJTYPE_FIFO);
256         case VCHR:
257                 return(HAMMER_OBJTYPE_CDEV);
258         case VBLK:
259                 return(HAMMER_OBJTYPE_BDEV);
260         case VLNK:
261                 return(HAMMER_OBJTYPE_SOFTLINK);
262         default:
263                 return(HAMMER_OBJTYPE_UNKNOWN);
264         }
265         /* not reached */
266 }
267
268 /*
269  * Return a namekey hash.   The 64 bit namekey hash consists of a 32 bit
270  * crc in the MSB and 0 in the LSB.  The caller will use the low bits to
271  * generate a unique key and will scan all entries with the same upper
272  * 32 bits when issuing a lookup.
273  *
274  * We strip bit 63 in order to provide a positive key, this way a seek
275  * offset of 0 will represent the base of the directory.
276  *
277  * This function can never return 0.  We use the MSB-0 space to synthesize
278  * artificial directory entries such as "." and "..".
279  */
280 int64_t
281 hammer_directory_namekey(void *name, int len)
282 {
283         int64_t key;
284
285         key = (int64_t)(crc32(name, len) & 0x7FFFFFFF) << 32;
286         if (key == 0)
287                 key |= 0x100000000LL;
288         return(key);
289 }
290
291 hammer_tid_t
292 hammer_now_tid(void)
293 {
294         struct timespec ts;
295         hammer_tid_t tid;
296
297         getnanotime(&ts);
298         tid = ts.tv_sec * 1000000000LL + ts.tv_nsec;
299         return(tid);
300 }
301
302 hammer_tid_t
303 hammer_str_to_tid(const char *str)
304 {
305         hammer_tid_t tid;
306
307         tid = strtoq(str, NULL, 16) * 1000000000LL;
308         return(tid);
309 }
310