HAMMER 56A/Many: Performance tuning - MEDIA STRUCTURES CHANGED!
[dragonfly.git] / sys / vfs / hammer / hammer_subs.c
CommitLineData
427e5fc6 1/*
b84de5af 2 * Copyright (c) 2007-2008 The DragonFly Project. All rights reserved.
427e5fc6
MD
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 *
af209b0f 34 * $DragonFly: src/sys/vfs/hammer/hammer_subs.c,v 1.24 2008/06/10 22:30:21 dillon Exp $
427e5fc6
MD
35 */
36/*
37 * HAMMER structural locking
38 */
39
40#include "hammer.h"
6b4f890b 41#include <sys/dirent.h>
427e5fc6
MD
42
43void
af209b0f 44hammer_lock_ex_ident(struct hammer_lock *lock, const char *ident)
427e5fc6
MD
45{
46 thread_t td = curthread;
47
8cd0a023 48 KKASSERT(lock->refs > 0);
66325755 49 crit_enter();
427e5fc6 50 if (lock->locktd != td) {
c0ade690 51 while (lock->locktd != NULL || lock->lockcount) {
427e5fc6 52 lock->wanted = 1;
7d683b0f
MD
53 if (hammer_debug_locks) {
54 kprintf("hammer_lock_ex: held by %p\n",
55 lock->locktd);
56 }
57 ++hammer_contention_count;
af209b0f 58 tsleep(lock, 0, ident, 0);
7d683b0f
MD
59 if (hammer_debug_locks)
60 kprintf("hammer_lock_ex: try again\n");
427e5fc6
MD
61 }
62 lock->locktd = td;
63 }
0b075555 64 KKASSERT(lock->lockcount >= 0);
8cd0a023 65 ++lock->lockcount;
66325755 66 crit_exit();
427e5fc6
MD
67}
68
8cd0a023
MD
69/*
70 * Try to obtain an exclusive lock
71 */
72int
73hammer_lock_ex_try(struct hammer_lock *lock)
74{
75 thread_t td = curthread;
76
77 KKASSERT(lock->refs > 0);
78 crit_enter();
79 if (lock->locktd != td) {
4d75d829
MD
80 if (lock->locktd != NULL || lock->lockcount) {
81 crit_exit();
8cd0a023 82 return(EAGAIN);
4d75d829 83 }
8cd0a023
MD
84 lock->locktd = td;
85 }
0b075555 86 KKASSERT(lock->lockcount >= 0);
8cd0a023
MD
87 ++lock->lockcount;
88 crit_exit();
89 return(0);
90}
91
427e5fc6 92void
8cd0a023 93hammer_lock_sh(struct hammer_lock *lock)
427e5fc6 94{
427e5fc6 95 KKASSERT(lock->refs > 0);
66325755 96 crit_enter();
8cd0a023
MD
97 while (lock->locktd != NULL) {
98 if (lock->locktd == curthread) {
6a37e7e4 99 Debugger("hammer_lock_sh: lock_sh on exclusive");
8cd0a023
MD
100 ++lock->lockcount;
101 crit_exit();
102 return;
427e5fc6 103 }
8cd0a023
MD
104 lock->wanted = 1;
105 tsleep(lock, 0, "hmrlck", 0);
427e5fc6 106 }
8cd0a023
MD
107 KKASSERT(lock->lockcount <= 0);
108 --lock->lockcount;
66325755
MD
109 crit_exit();
110}
111
47637bff
MD
112int
113hammer_lock_sh_try(struct hammer_lock *lock)
114{
115 KKASSERT(lock->refs > 0);
116 crit_enter();
117 if (lock->locktd) {
118 crit_exit();
119 return(EAGAIN);
120 }
121 KKASSERT(lock->lockcount <= 0);
122 --lock->lockcount;
123 crit_exit();
124 return(0);
125}
126
6a37e7e4
MD
127/*
128 * Upgrade a shared lock to an exclusively held lock. This function will
129 * return EDEADLK If there is more then one shared holder.
130 *
131 * No error occurs and no action is taken if the lock is already exclusively
7aa3b8a6
MD
132 * held by the caller. If the lock is not held at all or held exclusively
133 * by someone else, this function will panic.
6a37e7e4
MD
134 */
135int
136hammer_lock_upgrade(struct hammer_lock *lock)
137{
138 int error;
139
140 crit_enter();
141 if (lock->lockcount > 0) {
7aa3b8a6
MD
142 if (lock->locktd != curthread)
143 panic("hammer_lock_upgrade: illegal lock state");
6a37e7e4
MD
144 error = 0;
145 } else if (lock->lockcount == -1) {
146 lock->lockcount = 1;
147 lock->locktd = curthread;
148 error = 0;
7aa3b8a6 149 } else if (lock->lockcount != 0) {
6a37e7e4 150 error = EDEADLK;
7aa3b8a6
MD
151 } else {
152 panic("hammer_lock_upgrade: lock is not held");
153 /* NOT REACHED */
154 error = 0;
6a37e7e4
MD
155 }
156 crit_exit();
157 return(error);
158}
159
160/*
161 * Downgrade an exclusively held lock to a shared lock.
162 */
66325755 163void
6a37e7e4 164hammer_lock_downgrade(struct hammer_lock *lock)
66325755 165{
7aa3b8a6 166 KKASSERT(lock->lockcount == 1 && lock->locktd == curthread);
66325755 167 crit_enter();
8cd0a023
MD
168 lock->lockcount = -1;
169 lock->locktd = NULL;
170 if (lock->wanted) {
171 lock->wanted = 0;
172 wakeup(lock);
173 }
66325755 174 crit_exit();
8cd0a023 175 /* XXX memory barrier */
66325755
MD
176}
177
178void
8cd0a023 179hammer_unlock(struct hammer_lock *lock)
66325755
MD
180{
181 crit_enter();
8cd0a023
MD
182 KKASSERT(lock->lockcount != 0);
183 if (lock->lockcount < 0) {
184 if (++lock->lockcount == 0 && lock->wanted) {
185 lock->wanted = 0;
186 wakeup(lock);
187 }
188 } else {
189 KKASSERT(lock->locktd == curthread);
190 if (--lock->lockcount == 0) {
191 lock->locktd = NULL;
192 if (lock->wanted) {
193 lock->wanted = 0;
194 wakeup(lock);
195 }
196 }
197
198 }
66325755
MD
199 crit_exit();
200}
201
202void
8cd0a023 203hammer_ref(struct hammer_lock *lock)
66325755 204{
0b075555 205 KKASSERT(lock->refs >= 0);
66325755
MD
206 crit_enter();
207 ++lock->refs;
66325755
MD
208 crit_exit();
209}
210
211void
8cd0a023 212hammer_unref(struct hammer_lock *lock)
66325755 213{
a89aec1b 214 KKASSERT(lock->refs > 0);
0b075555 215 crit_enter();
66325755
MD
216 --lock->refs;
217 crit_exit();
218}
219
2f85fa4d
MD
220/*
221 * The sync_lock must be held when doing any modifying operations on
222 * meta-data. The flusher holds the lock exclusively while the reblocker
223 * and pruner use a shared lock.
224 *
225 * Modifying operations can run in parallel until the flusher needs to
226 * sync the disk media.
227 */
228void
229hammer_sync_lock_ex(hammer_transaction_t trans)
230{
231 ++trans->sync_lock_refs;
7538695e 232 hammer_lock_ex(&trans->hmp->sync_lock);
2f85fa4d
MD
233}
234
235void
236hammer_sync_lock_sh(hammer_transaction_t trans)
237{
238 ++trans->sync_lock_refs;
7538695e 239 hammer_lock_sh(&trans->hmp->sync_lock);
2f85fa4d
MD
240}
241
47637bff
MD
242int
243hammer_sync_lock_sh_try(hammer_transaction_t trans)
244{
245 int error;
246
247 ++trans->sync_lock_refs;
248 if ((error = hammer_lock_sh_try(&trans->hmp->sync_lock)) != 0)
249 --trans->sync_lock_refs;
250 return (error);
251}
252
2f85fa4d
MD
253void
254hammer_sync_unlock(hammer_transaction_t trans)
255{
256 --trans->sync_lock_refs;
257 hammer_unlock(&trans->hmp->sync_lock);
258}
259
260/*
261 * Misc
262 */
66325755
MD
263u_int32_t
264hammer_to_unix_xid(uuid_t *uuid)
265{
266 return(*(u_int32_t *)&uuid->node[2]);
267}
268
269void
8cd0a023
MD
270hammer_guid_to_uuid(uuid_t *uuid, u_int32_t guid)
271{
272 bzero(uuid, sizeof(*uuid));
273 *(u_int32_t *)&uuid->node[2] = guid;
274}
275
276void
277hammer_to_timespec(hammer_tid_t tid, struct timespec *ts)
66325755 278{
8cd0a023
MD
279 ts->tv_sec = tid / 1000000000;
280 ts->tv_nsec = tid % 1000000000;
66325755
MD
281}
282
8cd0a023
MD
283hammer_tid_t
284hammer_timespec_to_transid(struct timespec *ts)
285{
286 hammer_tid_t tid;
287
288 tid = ts->tv_nsec + (unsigned long)ts->tv_sec * 1000000000LL;
289 return(tid);
290}
291
292
66325755
MD
293/*
294 * Convert a HAMMER filesystem object type to a vnode type
295 */
296enum vtype
297hammer_get_vnode_type(u_int8_t obj_type)
298{
299 switch(obj_type) {
300 case HAMMER_OBJTYPE_DIRECTORY:
301 return(VDIR);
302 case HAMMER_OBJTYPE_REGFILE:
303 return(VREG);
304 case HAMMER_OBJTYPE_DBFILE:
305 return(VDATABASE);
306 case HAMMER_OBJTYPE_FIFO:
307 return(VFIFO);
308 case HAMMER_OBJTYPE_CDEV:
309 return(VCHR);
310 case HAMMER_OBJTYPE_BDEV:
311 return(VBLK);
312 case HAMMER_OBJTYPE_SOFTLINK:
313 return(VLNK);
314 default:
315 return(VBAD);
316 }
317 /* not reached */
318}
319
6b4f890b
MD
320int
321hammer_get_dtype(u_int8_t obj_type)
322{
323 switch(obj_type) {
324 case HAMMER_OBJTYPE_DIRECTORY:
325 return(DT_DIR);
326 case HAMMER_OBJTYPE_REGFILE:
327 return(DT_REG);
328 case HAMMER_OBJTYPE_DBFILE:
329 return(DT_DBF);
330 case HAMMER_OBJTYPE_FIFO:
331 return(DT_FIFO);
332 case HAMMER_OBJTYPE_CDEV:
333 return(DT_CHR);
334 case HAMMER_OBJTYPE_BDEV:
335 return(DT_BLK);
336 case HAMMER_OBJTYPE_SOFTLINK:
337 return(DT_LNK);
338 default:
339 return(DT_UNKNOWN);
340 }
341 /* not reached */
342}
343
66325755
MD
344u_int8_t
345hammer_get_obj_type(enum vtype vtype)
346{
347 switch(vtype) {
348 case VDIR:
349 return(HAMMER_OBJTYPE_DIRECTORY);
350 case VREG:
351 return(HAMMER_OBJTYPE_REGFILE);
352 case VDATABASE:
353 return(HAMMER_OBJTYPE_DBFILE);
354 case VFIFO:
355 return(HAMMER_OBJTYPE_FIFO);
356 case VCHR:
357 return(HAMMER_OBJTYPE_CDEV);
358 case VBLK:
359 return(HAMMER_OBJTYPE_BDEV);
360 case VLNK:
361 return(HAMMER_OBJTYPE_SOFTLINK);
362 default:
363 return(HAMMER_OBJTYPE_UNKNOWN);
364 }
365 /* not reached */
366}
367
e63644f0
MD
368int
369hammer_nohistory(hammer_inode_t ip)
370{
371 if (ip->hmp->hflags & HMNT_NOHISTORY)
372 return(1);
373 if (ip->ino_data.uflags & (SF_NOHISTORY|UF_NOHISTORY))
374 return(1);
375 return(0);
376}
377
66325755
MD
378/*
379 * Return a namekey hash. The 64 bit namekey hash consists of a 32 bit
380 * crc in the MSB and 0 in the LSB. The caller will use the low bits to
381 * generate a unique key and will scan all entries with the same upper
382 * 32 bits when issuing a lookup.
6b4f890b
MD
383 *
384 * We strip bit 63 in order to provide a positive key, this way a seek
385 * offset of 0 will represent the base of the directory.
b3deaf57
MD
386 *
387 * This function can never return 0. We use the MSB-0 space to synthesize
388 * artificial directory entries such as "." and "..".
66325755
MD
389 */
390int64_t
391hammer_directory_namekey(void *name, int len)
392{
393 int64_t key;
394
6b4f890b 395 key = (int64_t)(crc32(name, len) & 0x7FFFFFFF) << 32;
b3deaf57
MD
396 if (key == 0)
397 key |= 0x100000000LL;
66325755 398 return(key);
427e5fc6
MD
399}
400
7f7c1f84
MD
401hammer_tid_t
402hammer_now_tid(void)
403{
404 struct timespec ts;
405 hammer_tid_t tid;
406
407 getnanotime(&ts);
408 tid = ts.tv_sec * 1000000000LL + ts.tv_nsec;
409 return(tid);
410}
411
d113fda1
MD
412hammer_tid_t
413hammer_str_to_tid(const char *str)
414{
415 hammer_tid_t tid;
7dc57964 416 int len = strlen(str);
d113fda1 417
7dc57964
MD
418 if (len > 10)
419 tid = strtouq(str, NULL, 0); /* full TID */
420 else
421 tid = strtouq(str, NULL, 0) * 1000000000LL; /* time_t */
d113fda1
MD
422 return(tid);
423}
424
19619882
MD
425void
426hammer_crc_set_blockmap(hammer_blockmap_t blockmap)
427{
428 blockmap->entry_crc = crc32(blockmap, HAMMER_BLOCKMAP_CRCSIZE);
429}
430
431void
432hammer_crc_set_volume(hammer_volume_ondisk_t ondisk)
433{
434 ondisk->vol_crc = crc32(ondisk, HAMMER_VOL_CRCSIZE1) ^
435 crc32(&ondisk->vol_crc + 1, HAMMER_VOL_CRCSIZE2);
436}
437
438int
439hammer_crc_test_blockmap(hammer_blockmap_t blockmap)
440{
441 hammer_crc_t crc;
442
443 crc = crc32(blockmap, HAMMER_BLOCKMAP_CRCSIZE);
444 return (blockmap->entry_crc == crc);
445}
446
447int
448hammer_crc_test_volume(hammer_volume_ondisk_t ondisk)
449{
450 hammer_crc_t crc;
451
452 crc = crc32(ondisk, HAMMER_VOL_CRCSIZE1) ^
453 crc32(&ondisk->vol_crc + 1, HAMMER_VOL_CRCSIZE2);
454 return (ondisk->vol_crc == crc);
455}
456
19619882
MD
457int
458hammer_crc_test_btree(hammer_node_ondisk_t ondisk)
459{
460 hammer_crc_t crc;
461
462 crc = crc32(&ondisk->crc + 1, HAMMER_BTREE_CRCSIZE);
463 return (ondisk->crc == crc);
464}
465
77062c8a
MD
466void
467hkprintf(const char *ctl, ...)
468{
469 __va_list va;
470
471 if (hammer_debug_debug) {
472 __va_start(va, ctl);
473 kvprintf(ctl, va);
474 __va_end(va);
475 }
476}
477