| Commit | Line | Data |
|---|---|---|
| 66325755 | 1 | /* |
| b84de5af | 2 | * Copyright (c) 2007-2008 The DragonFly Project. All rights reserved. |
| 66325755 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 | * | |
| 21fde338 | 34 | * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.25 2008/09/23 21:03:52 dillon Exp $ |
| 66325755 MD |
35 | */ |
| 36 | ||
| 37 | #include "hammer.h" | |
| 38 | ||
| 5de0c0e5 | 39 | static hammer_tid_t hammer_alloc_tid(hammer_mount_t hmp, int count); |
| 5a64efa1 | 40 | static u_int32_t ocp_allocbit(hammer_objid_cache_t ocp, u_int32_t n); |
| 0729c8c8 MD |
41 | |
| 42 | ||
| b84de5af MD |
43 | /* |
| 44 | * Start a standard transaction. | |
| 45 | */ | |
| 66325755 | 46 | void |
| 8cd0a023 MD |
47 | hammer_start_transaction(struct hammer_transaction *trans, |
| 48 | struct hammer_mount *hmp) | |
| 66325755 | 49 | { |
| ddfdf542 | 50 | struct timeval tv; |
| a89aec1b | 51 | int error; |
| 66325755 | 52 | |
| b84de5af | 53 | trans->type = HAMMER_TRANS_STD; |
| 66325755 | 54 | trans->hmp = hmp; |
| a89aec1b MD |
55 | trans->rootvol = hammer_get_root_volume(hmp, &error); |
| 56 | KKASSERT(error == 0); | |
| b84de5af | 57 | trans->tid = 0; |
| 2f85fa4d | 58 | trans->sync_lock_refs = 0; |
| 21fde338 | 59 | trans->flags = 0; |
| ddfdf542 MD |
60 | |
| 61 | getmicrotime(&tv); | |
| dd94f1b1 MD |
62 | trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec; |
| 63 | trans->time32 = (u_int32_t)tv.tv_sec; | |
| 66325755 MD |
64 | } |
| 65 | ||
| b84de5af MD |
66 | /* |
| 67 | * Start a simple read-only transaction. This will not stall. | |
| 68 | */ | |
| 66325755 | 69 | void |
| 36f82b23 MD |
70 | hammer_simple_transaction(struct hammer_transaction *trans, |
| 71 | struct hammer_mount *hmp) | |
| 72 | { | |
| ddfdf542 | 73 | struct timeval tv; |
| 36f82b23 MD |
74 | int error; |
| 75 | ||
| b84de5af | 76 | trans->type = HAMMER_TRANS_RO; |
| 36f82b23 MD |
77 | trans->hmp = hmp; |
| 78 | trans->rootvol = hammer_get_root_volume(hmp, &error); | |
| 36f82b23 | 79 | KKASSERT(error == 0); |
| b84de5af | 80 | trans->tid = 0; |
| 2f85fa4d | 81 | trans->sync_lock_refs = 0; |
| 21fde338 | 82 | trans->flags = 0; |
| ddfdf542 MD |
83 | |
| 84 | getmicrotime(&tv); | |
| dd94f1b1 MD |
85 | trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec; |
| 86 | trans->time32 = (u_int32_t)tv.tv_sec; | |
| 36f82b23 MD |
87 | } |
| 88 | ||
| b84de5af MD |
89 | /* |
| 90 | * Start a transaction using a particular TID. Used by the sync code. | |
| 91 | * This does not stall. | |
| 2f85fa4d MD |
92 | * |
| 93 | * This routine may only be called from the flusher thread. We predispose | |
| 94 | * sync_lock_refs, implying serialization against the synchronization stage | |
| 95 | * (which the flusher is responsible for). | |
| b84de5af | 96 | */ |
| 36f82b23 | 97 | void |
| b84de5af MD |
98 | hammer_start_transaction_fls(struct hammer_transaction *trans, |
| 99 | struct hammer_mount *hmp) | |
| d113fda1 | 100 | { |
| ddfdf542 | 101 | struct timeval tv; |
| d113fda1 MD |
102 | int error; |
| 103 | ||
| 9f5097dc MD |
104 | bzero(trans, sizeof(*trans)); |
| 105 | ||
| b84de5af | 106 | trans->type = HAMMER_TRANS_FLS; |
| d113fda1 MD |
107 | trans->hmp = hmp; |
| 108 | trans->rootvol = hammer_get_root_volume(hmp, &error); | |
| 109 | KKASSERT(error == 0); | |
| 5de0c0e5 | 110 | trans->tid = hammer_alloc_tid(hmp, 1); |
| 2f85fa4d | 111 | trans->sync_lock_refs = 1; |
| 21fde338 | 112 | trans->flags = 0; |
| ddfdf542 MD |
113 | |
| 114 | getmicrotime(&tv); | |
| dd94f1b1 MD |
115 | trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec; |
| 116 | trans->time32 = (u_int32_t)tv.tv_sec; | |
| 66325755 MD |
117 | } |
| 118 | ||
| 119 | void | |
| b84de5af | 120 | hammer_done_transaction(struct hammer_transaction *trans) |
| 66325755 | 121 | { |
| 82010f9f | 122 | hammer_mount_t hmp = trans->hmp; |
| 2f85fa4d MD |
123 | int expected_lock_refs; |
| 124 | ||
| a89aec1b | 125 | hammer_rel_volume(trans->rootvol, 0); |
| b84de5af | 126 | trans->rootvol = NULL; |
| 2f85fa4d MD |
127 | expected_lock_refs = (trans->type == HAMMER_TRANS_FLS) ? 1 : 0; |
| 128 | KKASSERT(trans->sync_lock_refs == expected_lock_refs); | |
| 129 | trans->sync_lock_refs = 0; | |
| 82010f9f MD |
130 | if (trans->type != HAMMER_TRANS_FLS) { |
| 131 | if (trans->flags & HAMMER_TRANSF_NEWINODE) | |
| 132 | hammer_inode_waitreclaims(hmp); | |
| 133 | else if (trans->flags & HAMMER_TRANSF_DIDIO) | |
| 134 | hammer_inode_waithard(hmp); | |
| 135 | } | |
| 66325755 MD |
136 | } |
| 137 | ||
| d113fda1 | 138 | /* |
| 5de0c0e5 MD |
139 | * Allocate (count) TIDs. If running in multi-master mode the returned |
| 140 | * base will be aligned to a 16-count plus the master id (0-15). | |
| 141 | * Multi-master mode allows non-conflicting to run and new objects to be | |
| 142 | * created on multiple masters in parallel. The transaction id identifies | |
| 143 | * the original master. The object_id is also subject to this rule in | |
| 144 | * order to allow objects to be created on multiple masters in parallel. | |
| 145 | * | |
| 146 | * Directories may pre-allocate a large number of object ids (100,000). | |
| 147 | * | |
| 148 | * NOTE: There is no longer a requirement that successive transaction | |
| 149 | * ids be 2 apart for separator generation. | |
| d113fda1 | 150 | */ |
| 0729c8c8 | 151 | static hammer_tid_t |
| 5de0c0e5 | 152 | hammer_alloc_tid(hammer_mount_t hmp, int count) |
| a89aec1b | 153 | { |
| a89aec1b MD |
154 | hammer_tid_t tid; |
| 155 | ||
| 732a1697 | 156 | if (hmp->master_id < 0) { |
| c82af904 MD |
157 | tid = hmp->next_tid + 1; |
| 158 | hmp->next_tid = tid + count; | |
| 159 | } else { | |
| 160 | tid = (hmp->next_tid + HAMMER_MAX_MASTERS) & | |
| 161 | ~(hammer_tid_t)(HAMMER_MAX_MASTERS - 1); | |
| 162 | hmp->next_tid = tid + count * HAMMER_MAX_MASTERS; | |
| 732a1697 | 163 | tid |= hmp->master_id; |
| c82af904 MD |
164 | } |
| 165 | if (tid >= 0xFFFFFFFFFF000000ULL) | |
| a89aec1b | 166 | panic("hammer_start_transaction: Ran out of TIDs!"); |
| 5de0c0e5 | 167 | if (hammer_debug_tid) |
| 973c11b9 | 168 | kprintf("alloc_tid %016llx\n", (long long)tid); |
| a89aec1b MD |
169 | return(tid); |
| 170 | } | |
| 171 | ||
| 0729c8c8 | 172 | /* |
| 5a64efa1 MD |
173 | * Allocate an object id. |
| 174 | * | |
| 175 | * We use the upper OBJID_CACHE_BITS bits of the namekey to try to match | |
| 176 | * the low bits of the objid we allocate. | |
| 0729c8c8 MD |
177 | */ |
| 178 | hammer_tid_t | |
| 5a64efa1 | 179 | hammer_alloc_objid(hammer_mount_t hmp, hammer_inode_t dip, int64_t namekey) |
| 0729c8c8 MD |
180 | { |
| 181 | hammer_objid_cache_t ocp; | |
| 182 | hammer_tid_t tid; | |
| 5a64efa1 MD |
183 | int incluster; |
| 184 | u_int32_t n; | |
| 0729c8c8 MD |
185 | |
| 186 | while ((ocp = dip->objid_cache) == NULL) { | |
| 5de0c0e5 | 187 | if (hmp->objid_cache_count < OBJID_CACHE_SIZE) { |
| bac808fe MD |
188 | ocp = kmalloc(sizeof(*ocp), hmp->m_misc, |
| 189 | M_WAITOK|M_ZERO); | |
| 5a64efa1 MD |
190 | ocp->base_tid = hammer_alloc_tid(hmp, |
| 191 | OBJID_CACHE_BULK * 2); | |
| 192 | ocp->base_tid += OBJID_CACHE_BULK_MASK64; | |
| 193 | ocp->base_tid &= ~OBJID_CACHE_BULK_MASK64; | |
| 5de0c0e5 MD |
194 | TAILQ_INSERT_HEAD(&hmp->objid_cache_list, ocp, entry); |
| 195 | ++hmp->objid_cache_count; | |
| 0729c8c8 MD |
196 | /* may have blocked, recheck */ |
| 197 | if (dip->objid_cache == NULL) { | |
| 198 | dip->objid_cache = ocp; | |
| 199 | ocp->dip = dip; | |
| 200 | } | |
| 201 | } else { | |
| 5a64efa1 MD |
202 | /* |
| 203 | * Steal one from another directory? | |
| 204 | * | |
| 205 | * Throw away ocp's that are more then half full, they | |
| 206 | * aren't worth stealing. | |
| 207 | */ | |
| 5de0c0e5 | 208 | ocp = TAILQ_FIRST(&hmp->objid_cache_list); |
| 0729c8c8 MD |
209 | if (ocp->dip) |
| 210 | ocp->dip->objid_cache = NULL; | |
| 5a64efa1 MD |
211 | if (ocp->count >= OBJID_CACHE_BULK / 2) { |
| 212 | --hmp->objid_cache_count; | |
| 213 | kfree(ocp, hmp->m_misc); | |
| 214 | } else { | |
| 215 | dip->objid_cache = ocp; | |
| 216 | ocp->dip = dip; | |
| 217 | } | |
| 0729c8c8 MD |
218 | } |
| 219 | } | |
| 5de0c0e5 MD |
220 | TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry); |
| 221 | ||
| 222 | /* | |
| 5a64efa1 MD |
223 | * Allocate a bit based on our namekey for the low bits of our |
| 224 | * objid. | |
| 225 | */ | |
| 226 | incluster = (hmp->master_id >= 0); | |
| 227 | n = (namekey >> (63 - OBJID_CACHE_BULK_BITS)) & OBJID_CACHE_BULK_MASK; | |
| 228 | n = ocp_allocbit(ocp, n); | |
| 229 | tid = ocp->base_tid + n; | |
| 230 | ||
| 231 | #if 0 | |
| 232 | /* | |
| 5de0c0e5 MD |
233 | * The TID is incremented by 1 or by 16 depending what mode the |
| 234 | * mount is operating in. | |
| 235 | */ | |
| 732a1697 | 236 | ocp->next_tid += (hmp->master_id < 0) ? 1 : HAMMER_MAX_MASTERS; |
| 5a64efa1 MD |
237 | #endif |
| 238 | if (ocp->count >= OBJID_CACHE_BULK / 2) { | |
| 0729c8c8 | 239 | dip->objid_cache = NULL; |
| 5de0c0e5 | 240 | --hmp->objid_cache_count; |
| 0729c8c8 | 241 | ocp->dip = NULL; |
| bac808fe | 242 | kfree(ocp, hmp->m_misc); |
| 0729c8c8 | 243 | } else { |
| 5de0c0e5 | 244 | TAILQ_INSERT_TAIL(&hmp->objid_cache_list, ocp, entry); |
| 0729c8c8 MD |
245 | } |
| 246 | return(tid); | |
| 247 | } | |
| 248 | ||
| 5a64efa1 MD |
249 | /* |
| 250 | * Allocate a bit starting with bit n. Wrap if necessary. | |
| 251 | * | |
| 252 | * This routine is only ever called if a bit is available somewhere | |
| 253 | * in the bitmap. | |
| 254 | */ | |
| 255 | static u_int32_t | |
| 256 | ocp_allocbit(hammer_objid_cache_t ocp, u_int32_t n) | |
| 257 | { | |
| 258 | u_int32_t n0; | |
| 259 | ||
| 260 | n0 = (n >> 5) & 31; | |
| 261 | n &= 31; | |
| 262 | ||
| 263 | while (ocp->bm1[n0] & (1 << n)) { | |
| 264 | if (ocp->bm0 & (1 << n0)) { | |
| 265 | n0 = (n0 + 1) & 31; | |
| 266 | n = 0; | |
| 267 | } else if (++n == 32) { | |
| 268 | n0 = (n0 + 1) & 31; | |
| 269 | n = 0; | |
| 270 | } | |
| 271 | } | |
| 272 | ++ocp->count; | |
| 273 | ocp->bm1[n0] |= 1 << n; | |
| 274 | if (ocp->bm1[n0] == 0xFFFFFFFFU) | |
| 275 | ocp->bm0 |= 1 << n0; | |
| 276 | return((n0 << 5) + n); | |
| 277 | } | |
| 278 | ||
| 0729c8c8 MD |
279 | void |
| 280 | hammer_clear_objid(hammer_inode_t dip) | |
| 281 | { | |
| 282 | hammer_objid_cache_t ocp; | |
| 283 | ||
| 284 | if ((ocp = dip->objid_cache) != NULL) { | |
| 285 | dip->objid_cache = NULL; | |
| 286 | ocp->dip = NULL; | |
| 287 | TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry); | |
| 288 | TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry); | |
| 289 | } | |
| 290 | } | |
| 291 | ||
| 292 | void | |
| 293 | hammer_destroy_objid_cache(hammer_mount_t hmp) | |
| 294 | { | |
| 295 | hammer_objid_cache_t ocp; | |
| 296 | ||
| 297 | while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) { | |
| 298 | TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry); | |
| f437a2ab MD |
299 | if (ocp->dip) |
| 300 | ocp->dip->objid_cache = NULL; | |
| bac808fe | 301 | kfree(ocp, hmp->m_misc); |
| 0729c8c8 MD |
302 | } |
| 303 | } | |
| 304 |