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