1 /* 2 * Copyright (c) 2007-2008 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_transaction.c,v 1.14 2008/04/29 01:10:37 dillon Exp $ 35 */ 36 37 #include "hammer.h" 38 39 static hammer_tid_t hammer_alloc_tid(hammer_transaction_t trans, int count); 40 41 42 /* 43 * Start a standard transaction. 44 */ 45 void 46 hammer_start_transaction(struct hammer_transaction *trans, 47 struct hammer_mount *hmp) 48 { 49 int error; 50 51 trans->type = HAMMER_TRANS_STD; 52 trans->hmp = hmp; 53 trans->rootvol = hammer_get_root_volume(hmp, &error); 54 KKASSERT(error == 0); 55 trans->tid = 0; 56 trans->time = hammer_alloc_tid(trans, 1); 57 } 58 59 /* 60 * Start a simple read-only transaction. This will not stall. 61 */ 62 void 63 hammer_simple_transaction(struct hammer_transaction *trans, 64 struct hammer_mount *hmp) 65 { 66 int error; 67 68 trans->type = HAMMER_TRANS_RO; 69 trans->hmp = hmp; 70 trans->rootvol = hammer_get_root_volume(hmp, &error); 71 KKASSERT(error == 0); 72 trans->tid = 0; 73 trans->time = hammer_alloc_tid(trans, 1); 74 } 75 76 /* 77 * Start a transaction using a particular TID. Used by the sync code. 78 * This does not stall. 79 */ 80 void 81 hammer_start_transaction_fls(struct hammer_transaction *trans, 82 struct hammer_mount *hmp) 83 { 84 int error; 85 86 trans->type = HAMMER_TRANS_FLS; 87 trans->hmp = hmp; 88 trans->rootvol = hammer_get_root_volume(hmp, &error); 89 KKASSERT(error == 0); 90 trans->tid = hammer_alloc_tid(trans, 1); 91 trans->time = trans->tid; 92 } 93 94 void 95 hammer_done_transaction(struct hammer_transaction *trans) 96 { 97 hammer_rel_volume(trans->rootvol, 0); 98 trans->rootvol = NULL; 99 } 100 101 /* 102 * Note: Successive transaction ids must be at least 2 apart so the 103 * B-Tree code can make a separator that does not match either the 104 * left or right hand sides. 105 */ 106 static hammer_tid_t 107 hammer_alloc_tid(hammer_transaction_t trans, int count) 108 { 109 struct timespec ts; 110 hammer_tid_t tid; 111 112 getnanotime(&ts); 113 tid = ts.tv_sec * 1000000000LL + ts.tv_nsec; 114 if (tid < trans->hmp->next_tid) 115 tid = trans->hmp->next_tid; 116 if (tid >= 0xFFFFFFFFFFFFF000ULL) 117 panic("hammer_start_transaction: Ran out of TIDs!"); 118 trans->hmp->next_tid = tid + count * 2; 119 if (hammer_debug_tid) { 120 kprintf("alloc_tid %016llx (0x%08x)\n", 121 tid, (int)(tid / 1000000000LL)); 122 } 123 return(tid); 124 } 125 126 /* 127 * Allocate an object id 128 */ 129 hammer_tid_t 130 hammer_alloc_objid(hammer_transaction_t trans, hammer_inode_t dip) 131 { 132 hammer_objid_cache_t ocp; 133 hammer_tid_t tid; 134 135 while ((ocp = dip->objid_cache) == NULL) { 136 if (trans->hmp->objid_cache_count < OBJID_CACHE_SIZE) { 137 ocp = kmalloc(sizeof(*ocp), M_HAMMER, M_WAITOK|M_ZERO); 138 ocp->next_tid = hammer_alloc_tid(trans, 139 OBJID_CACHE_BULK); 140 ocp->count = OBJID_CACHE_BULK; 141 TAILQ_INSERT_HEAD(&trans->hmp->objid_cache_list, ocp, 142 entry); 143 ++trans->hmp->objid_cache_count; 144 /* may have blocked, recheck */ 145 if (dip->objid_cache == NULL) { 146 dip->objid_cache = ocp; 147 ocp->dip = dip; 148 } 149 } else { 150 ocp = TAILQ_FIRST(&trans->hmp->objid_cache_list); 151 if (ocp->dip) 152 ocp->dip->objid_cache = NULL; 153 dip->objid_cache = ocp; 154 ocp->dip = dip; 155 } 156 } 157 TAILQ_REMOVE(&trans->hmp->objid_cache_list, ocp, entry); 158 tid = ocp->next_tid; 159 ocp->next_tid += 2; 160 if (--ocp->count == 0) { 161 dip->objid_cache = NULL; 162 --trans->hmp->objid_cache_count; 163 ocp->dip = NULL; 164 kfree(ocp, M_HAMMER); 165 } else { 166 TAILQ_INSERT_TAIL(&trans->hmp->objid_cache_list, ocp, entry); 167 } 168 return(tid); 169 } 170 171 void 172 hammer_clear_objid(hammer_inode_t dip) 173 { 174 hammer_objid_cache_t ocp; 175 176 if ((ocp = dip->objid_cache) != NULL) { 177 dip->objid_cache = NULL; 178 ocp->dip = NULL; 179 TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry); 180 TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry); 181 } 182 } 183 184 void 185 hammer_destroy_objid_cache(hammer_mount_t hmp) 186 { 187 hammer_objid_cache_t ocp; 188 189 while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) { 190 TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry); 191 kfree(ocp, M_HAMMER); 192 } 193 } 194 195