HAMMER 5/many - in-memory cache and more vnops.
[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.5 2007/11/20 22:55:40 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) {
52                         lock->wanted = 1;
53                         tsleep(lock, 0, "hmrlck", 0);
54                 }
55                 lock->locktd = td;
56         }
57         ++lock->lockcount;
58         crit_exit();
59 }
60
61 /*
62  * Try to obtain an exclusive lock
63  */
64 int
65 hammer_lock_ex_try(struct hammer_lock *lock)
66 {
67         thread_t td = curthread;
68
69         KKASSERT(lock->refs > 0);
70         crit_enter();
71         if (lock->locktd != td) {
72                 if (lock->locktd != NULL)
73                         return(EAGAIN);
74                 lock->locktd = td;
75         }
76         ++lock->lockcount;
77         crit_exit();
78         return(0);
79 }
80
81
82 void
83 hammer_lock_sh(struct hammer_lock *lock)
84 {
85         KKASSERT(lock->refs > 0);
86         crit_enter();
87         while (lock->locktd != NULL) {
88                 if (lock->locktd == curthread) {
89                         ++lock->lockcount;
90                         crit_exit();
91                         return;
92                 }
93                 lock->wanted = 1;
94                 tsleep(lock, 0, "hmrlck", 0);
95         }
96         KKASSERT(lock->lockcount <= 0);
97         --lock->lockcount;
98         crit_exit();
99 }
100
101 void
102 hammer_downgrade(struct hammer_lock *lock)
103 {
104         KKASSERT(lock->lockcount == 1);
105         crit_enter();
106         lock->lockcount = -1;
107         lock->locktd = NULL;
108         if (lock->wanted) {
109                 lock->wanted = 0;
110                 wakeup(lock);
111         }
112         crit_exit();
113         /* XXX memory barrier */
114 }
115
116 void
117 hammer_unlock(struct hammer_lock *lock)
118 {
119         crit_enter();
120         KKASSERT(lock->lockcount != 0);
121         if (lock->lockcount < 0) {
122                 if (++lock->lockcount == 0 && lock->wanted) {
123                         lock->wanted = 0;
124                         wakeup(lock);
125                 }
126         } else {
127                 KKASSERT(lock->locktd == curthread);
128                 if (--lock->lockcount == 0) {
129                         lock->locktd = NULL;
130                         if (lock->wanted) {
131                                 lock->wanted = 0;
132                                 wakeup(lock);
133                         }
134                 }
135
136         }
137         crit_exit();
138 }
139
140 void
141 hammer_ref(struct hammer_lock *lock)
142 {
143         crit_enter();
144         ++lock->refs;
145         crit_exit();
146 }
147
148 void
149 hammer_unref(struct hammer_lock *lock)
150 {
151         crit_enter();
152         KKASSERT(lock->refs > 0);
153         --lock->refs;
154         crit_exit();
155 }
156
157 u_int32_t
158 hammer_to_unix_xid(uuid_t *uuid)
159 {
160         return(*(u_int32_t *)&uuid->node[2]);
161 }
162
163 void
164 hammer_guid_to_uuid(uuid_t *uuid, u_int32_t guid)
165 {
166         bzero(uuid, sizeof(*uuid));
167         *(u_int32_t *)&uuid->node[2] = guid;
168 }
169
170 void
171 hammer_to_timespec(hammer_tid_t tid, struct timespec *ts)
172 {
173         ts->tv_sec = tid / 1000000000;
174         ts->tv_nsec = tid % 1000000000;
175 }
176
177 hammer_tid_t
178 hammer_timespec_to_transid(struct timespec *ts)
179 {
180         hammer_tid_t tid;
181
182         tid = ts->tv_nsec + (unsigned long)ts->tv_sec * 1000000000LL;
183         return(tid);
184 }
185
186
187 /*
188  * Convert a HAMMER filesystem object type to a vnode type
189  */
190 enum vtype
191 hammer_get_vnode_type(u_int8_t obj_type)
192 {
193         switch(obj_type) {
194         case HAMMER_OBJTYPE_DIRECTORY:
195                 return(VDIR);
196         case HAMMER_OBJTYPE_REGFILE:
197                 return(VREG);
198         case HAMMER_OBJTYPE_DBFILE:
199                 return(VDATABASE);
200         case HAMMER_OBJTYPE_FIFO:
201                 return(VFIFO);
202         case HAMMER_OBJTYPE_CDEV:
203                 return(VCHR);
204         case HAMMER_OBJTYPE_BDEV:
205                 return(VBLK);
206         case HAMMER_OBJTYPE_SOFTLINK:
207                 return(VLNK);
208         default:
209                 return(VBAD);
210         }
211         /* not reached */
212 }
213
214 int
215 hammer_get_dtype(u_int8_t obj_type)
216 {
217         switch(obj_type) {
218         case HAMMER_OBJTYPE_DIRECTORY:
219                 return(DT_DIR);
220         case HAMMER_OBJTYPE_REGFILE:
221                 return(DT_REG);
222         case HAMMER_OBJTYPE_DBFILE:
223                 return(DT_DBF);
224         case HAMMER_OBJTYPE_FIFO:
225                 return(DT_FIFO);
226         case HAMMER_OBJTYPE_CDEV:
227                 return(DT_CHR);
228         case HAMMER_OBJTYPE_BDEV:
229                 return(DT_BLK);
230         case HAMMER_OBJTYPE_SOFTLINK:
231                 return(DT_LNK);
232         default:
233                 return(DT_UNKNOWN);
234         }
235         /* not reached */
236 }
237
238 u_int8_t
239 hammer_get_obj_type(enum vtype vtype)
240 {
241         switch(vtype) {
242         case VDIR:
243                 return(HAMMER_OBJTYPE_DIRECTORY);
244         case VREG:
245                 return(HAMMER_OBJTYPE_REGFILE);
246         case VDATABASE:
247                 return(HAMMER_OBJTYPE_DBFILE);
248         case VFIFO:
249                 return(HAMMER_OBJTYPE_FIFO);
250         case VCHR:
251                 return(HAMMER_OBJTYPE_CDEV);
252         case VBLK:
253                 return(HAMMER_OBJTYPE_BDEV);
254         case VLNK:
255                 return(HAMMER_OBJTYPE_SOFTLINK);
256         default:
257                 return(HAMMER_OBJTYPE_UNKNOWN);
258         }
259         /* not reached */
260 }
261
262 /*
263  * Return a namekey hash.   The 64 bit namekey hash consists of a 32 bit
264  * crc in the MSB and 0 in the LSB.  The caller will use the low bits to
265  * generate a unique key and will scan all entries with the same upper
266  * 32 bits when issuing a lookup.
267  *
268  * We strip bit 63 in order to provide a positive key, this way a seek
269  * offset of 0 will represent the base of the directory.
270  */
271 int64_t
272 hammer_directory_namekey(void *name, int len)
273 {
274         int64_t key;
275
276         key = (int64_t)(crc32(name, len) & 0x7FFFFFFF) << 32;
277         return(key);
278 }
279