2 * Copyright (c) 2007-2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
34 * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.17 2008/06/10 08:51:02 dillon Exp $
39 static hammer_tid_t
hammer_alloc_tid(hammer_transaction_t trans
, int count
);
43 * Start a standard transaction.
46 hammer_start_transaction(struct hammer_transaction
*trans
,
47 struct hammer_mount
*hmp
)
51 trans
->type
= HAMMER_TRANS_STD
;
53 trans
->rootvol
= hammer_get_root_volume(hmp
, &error
);
56 trans
->time
= hammer_alloc_tid(trans
, 1);
57 trans
->sync_lock_refs
= 0;
61 * Start a simple read-only transaction. This will not stall.
64 hammer_simple_transaction(struct hammer_transaction
*trans
,
65 struct hammer_mount
*hmp
)
69 trans
->type
= HAMMER_TRANS_RO
;
71 trans
->rootvol
= hammer_get_root_volume(hmp
, &error
);
74 trans
->time
= hammer_alloc_tid(trans
, 1);
75 trans
->sync_lock_refs
= 0;
79 * Start a transaction using a particular TID. Used by the sync code.
80 * This does not stall.
82 * This routine may only be called from the flusher thread. We predispose
83 * sync_lock_refs, implying serialization against the synchronization stage
84 * (which the flusher is responsible for).
87 hammer_start_transaction_fls(struct hammer_transaction
*trans
,
88 struct hammer_mount
*hmp
)
92 bzero(trans
, sizeof(*trans
));
94 trans
->type
= HAMMER_TRANS_FLS
;
96 trans
->rootvol
= hammer_get_root_volume(hmp
, &error
);
98 trans
->tid
= hammer_alloc_tid(trans
, 1);
99 trans
->time
= trans
->tid
;
100 trans
->sync_lock_refs
= 1;
104 hammer_done_transaction(struct hammer_transaction
*trans
)
106 int expected_lock_refs
;
108 hammer_rel_volume(trans
->rootvol
, 0);
109 trans
->rootvol
= NULL
;
110 expected_lock_refs
= (trans
->type
== HAMMER_TRANS_FLS
) ? 1 : 0;
111 KKASSERT(trans
->sync_lock_refs
== expected_lock_refs
);
112 trans
->sync_lock_refs
= 0;
116 * Note: Successive transaction ids must be at least 2 apart so the
117 * B-Tree code can make a separator that does not match either the
118 * left or right hand sides.
121 hammer_alloc_tid(hammer_transaction_t trans
, int count
)
127 tid
= ts
.tv_sec
* 1000000000LL + ts
.tv_nsec
;
128 if (tid
< trans
->hmp
->next_tid
)
129 tid
= trans
->hmp
->next_tid
;
130 if (tid
>= 0xFFFFFFFFFFFFF000ULL
)
131 panic("hammer_start_transaction: Ran out of TIDs!");
132 trans
->hmp
->next_tid
= tid
+ count
* 2;
133 if (hammer_debug_tid
) {
134 kprintf("alloc_tid %016llx (0x%08x)\n",
135 tid
, (int)(tid
/ 1000000000LL));
141 * Allocate an object id
144 hammer_alloc_objid(hammer_transaction_t trans
, hammer_inode_t dip
)
146 hammer_objid_cache_t ocp
;
149 while ((ocp
= dip
->objid_cache
) == NULL
) {
150 if (trans
->hmp
->objid_cache_count
< OBJID_CACHE_SIZE
) {
151 ocp
= kmalloc(sizeof(*ocp
), M_HAMMER
, M_WAITOK
|M_ZERO
);
152 ocp
->next_tid
= hammer_alloc_tid(trans
,
154 ocp
->count
= OBJID_CACHE_BULK
;
155 TAILQ_INSERT_HEAD(&trans
->hmp
->objid_cache_list
, ocp
,
157 ++trans
->hmp
->objid_cache_count
;
158 /* may have blocked, recheck */
159 if (dip
->objid_cache
== NULL
) {
160 dip
->objid_cache
= ocp
;
164 ocp
= TAILQ_FIRST(&trans
->hmp
->objid_cache_list
);
166 ocp
->dip
->objid_cache
= NULL
;
167 dip
->objid_cache
= ocp
;
171 TAILQ_REMOVE(&trans
->hmp
->objid_cache_list
, ocp
, entry
);
174 if (--ocp
->count
== 0) {
175 dip
->objid_cache
= NULL
;
176 --trans
->hmp
->objid_cache_count
;
178 kfree(ocp
, M_HAMMER
);
180 TAILQ_INSERT_TAIL(&trans
->hmp
->objid_cache_list
, ocp
, entry
);
186 hammer_clear_objid(hammer_inode_t dip
)
188 hammer_objid_cache_t ocp
;
190 if ((ocp
= dip
->objid_cache
) != NULL
) {
191 dip
->objid_cache
= NULL
;
193 TAILQ_REMOVE(&dip
->hmp
->objid_cache_list
, ocp
, entry
);
194 TAILQ_INSERT_HEAD(&dip
->hmp
->objid_cache_list
, ocp
, entry
);
199 hammer_destroy_objid_cache(hammer_mount_t hmp
)
201 hammer_objid_cache_t ocp
;
203 while ((ocp
= TAILQ_FIRST(&hmp
->objid_cache_list
)) != NULL
) {
204 TAILQ_REMOVE(&hmp
->objid_cache_list
, ocp
, entry
);
205 kfree(ocp
, M_HAMMER
);