166325755SMatthew Dillon /*
2b84de5afSMatthew Dillon  * Copyright (c) 2007-2008 The DragonFly Project.  All rights reserved.
366325755SMatthew Dillon  *
466325755SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
566325755SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
666325755SMatthew Dillon  *
766325755SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
866325755SMatthew Dillon  * modification, are permitted provided that the following conditions
966325755SMatthew Dillon  * are met:
1066325755SMatthew Dillon  *
1166325755SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
1266325755SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
1366325755SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
1466325755SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
1566325755SMatthew Dillon  *    the documentation and/or other materials provided with the
1666325755SMatthew Dillon  *    distribution.
1766325755SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
1866325755SMatthew Dillon  *    contributors may be used to endorse or promote products derived
1966325755SMatthew Dillon  *    from this software without specific, prior written permission.
2066325755SMatthew Dillon  *
2166325755SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2266325755SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2366325755SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2466325755SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
2566325755SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2666325755SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2766325755SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2866325755SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2966325755SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3066325755SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3166325755SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3266325755SMatthew Dillon  * SUCH DAMAGE.
3366325755SMatthew Dillon  *
34*0729c8c8SMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.14 2008/04/29 01:10:37 dillon Exp $
3566325755SMatthew Dillon  */
3666325755SMatthew Dillon 
3766325755SMatthew Dillon #include "hammer.h"
3866325755SMatthew Dillon 
39*0729c8c8SMatthew Dillon static hammer_tid_t hammer_alloc_tid(hammer_transaction_t trans, int count);
40*0729c8c8SMatthew Dillon 
41*0729c8c8SMatthew Dillon 
42b84de5afSMatthew Dillon /*
43b84de5afSMatthew Dillon  * Start a standard transaction.
44b84de5afSMatthew Dillon  */
4566325755SMatthew Dillon void
468cd0a023SMatthew Dillon hammer_start_transaction(struct hammer_transaction *trans,
478cd0a023SMatthew Dillon 			 struct hammer_mount *hmp)
4866325755SMatthew Dillon {
49a89aec1bSMatthew Dillon 	int error;
5066325755SMatthew Dillon 
51b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_STD;
5266325755SMatthew Dillon 	trans->hmp = hmp;
53a89aec1bSMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
54a89aec1bSMatthew Dillon 	KKASSERT(error == 0);
55b84de5afSMatthew Dillon 	trans->tid = 0;
56*0729c8c8SMatthew Dillon 	trans->time = hammer_alloc_tid(trans, 1);
5766325755SMatthew Dillon }
5866325755SMatthew Dillon 
59b84de5afSMatthew Dillon /*
60b84de5afSMatthew Dillon  * Start a simple read-only transaction.  This will not stall.
61b84de5afSMatthew Dillon  */
6266325755SMatthew Dillon void
6336f82b23SMatthew Dillon hammer_simple_transaction(struct hammer_transaction *trans,
6436f82b23SMatthew Dillon 			  struct hammer_mount *hmp)
6536f82b23SMatthew Dillon {
6636f82b23SMatthew Dillon 	int error;
6736f82b23SMatthew Dillon 
68b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_RO;
6936f82b23SMatthew Dillon 	trans->hmp = hmp;
7036f82b23SMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
7136f82b23SMatthew Dillon 	KKASSERT(error == 0);
72b84de5afSMatthew Dillon 	trans->tid = 0;
73*0729c8c8SMatthew Dillon 	trans->time = hammer_alloc_tid(trans, 1);
7436f82b23SMatthew Dillon }
7536f82b23SMatthew Dillon 
76b84de5afSMatthew Dillon /*
77b84de5afSMatthew Dillon  * Start a transaction using a particular TID.  Used by the sync code.
78b84de5afSMatthew Dillon  * This does not stall.
79b84de5afSMatthew Dillon  */
8036f82b23SMatthew Dillon void
81b84de5afSMatthew Dillon hammer_start_transaction_fls(struct hammer_transaction *trans,
82b84de5afSMatthew Dillon 			     struct hammer_mount *hmp)
83d113fda1SMatthew Dillon {
84d113fda1SMatthew Dillon 	int error;
85d113fda1SMatthew Dillon 
86b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_FLS;
87d113fda1SMatthew Dillon 	trans->hmp = hmp;
88d113fda1SMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
89d113fda1SMatthew Dillon 	KKASSERT(error == 0);
90*0729c8c8SMatthew Dillon 	trans->tid = hammer_alloc_tid(trans, 1);
91b84de5afSMatthew Dillon 	trans->time = trans->tid;
92d113fda1SMatthew Dillon }
93d113fda1SMatthew Dillon 
94d113fda1SMatthew Dillon void
95b84de5afSMatthew Dillon hammer_done_transaction(struct hammer_transaction *trans)
9666325755SMatthew Dillon {
97a89aec1bSMatthew Dillon 	hammer_rel_volume(trans->rootvol, 0);
98b84de5afSMatthew Dillon 	trans->rootvol = NULL;
9966325755SMatthew Dillon }
10066325755SMatthew Dillon 
101d113fda1SMatthew Dillon /*
102d113fda1SMatthew Dillon  * Note: Successive transaction ids must be at least 2 apart so the
103d113fda1SMatthew Dillon  * B-Tree code can make a separator that does not match either the
104d113fda1SMatthew Dillon  * left or right hand sides.
105d113fda1SMatthew Dillon  */
106*0729c8c8SMatthew Dillon static hammer_tid_t
107*0729c8c8SMatthew Dillon hammer_alloc_tid(hammer_transaction_t trans, int count)
108a89aec1bSMatthew Dillon {
109a89aec1bSMatthew Dillon 	struct timespec ts;
110a89aec1bSMatthew Dillon 	hammer_tid_t tid;
111a89aec1bSMatthew Dillon 
112a89aec1bSMatthew Dillon 	getnanotime(&ts);
113a89aec1bSMatthew Dillon 	tid = ts.tv_sec * 1000000000LL + ts.tv_nsec;
114b84de5afSMatthew Dillon 	if (tid < trans->hmp->next_tid)
115b84de5afSMatthew Dillon 		tid = trans->hmp->next_tid;
116*0729c8c8SMatthew Dillon 	if (tid >= 0xFFFFFFFFFFFFF000ULL)
117a89aec1bSMatthew Dillon 		panic("hammer_start_transaction: Ran out of TIDs!");
118*0729c8c8SMatthew Dillon 	trans->hmp->next_tid = tid + count * 2;
119d113fda1SMatthew Dillon 	if (hammer_debug_tid) {
120d113fda1SMatthew Dillon 		kprintf("alloc_tid %016llx (0x%08x)\n",
121d113fda1SMatthew Dillon 			tid, (int)(tid / 1000000000LL));
122d113fda1SMatthew Dillon 	}
123a89aec1bSMatthew Dillon 	return(tid);
124a89aec1bSMatthew Dillon }
125a89aec1bSMatthew Dillon 
126*0729c8c8SMatthew Dillon /*
127*0729c8c8SMatthew Dillon  * Allocate an object id
128*0729c8c8SMatthew Dillon  */
129*0729c8c8SMatthew Dillon hammer_tid_t
130*0729c8c8SMatthew Dillon hammer_alloc_objid(hammer_transaction_t trans, hammer_inode_t dip)
131*0729c8c8SMatthew Dillon {
132*0729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
133*0729c8c8SMatthew Dillon 	hammer_tid_t tid;
134*0729c8c8SMatthew Dillon 
135*0729c8c8SMatthew Dillon 	while ((ocp = dip->objid_cache) == NULL) {
136*0729c8c8SMatthew Dillon 		if (trans->hmp->objid_cache_count < OBJID_CACHE_SIZE) {
137*0729c8c8SMatthew Dillon 			ocp = kmalloc(sizeof(*ocp), M_HAMMER, M_WAITOK|M_ZERO);
138*0729c8c8SMatthew Dillon 			ocp->next_tid = hammer_alloc_tid(trans,
139*0729c8c8SMatthew Dillon 							 OBJID_CACHE_BULK);
140*0729c8c8SMatthew Dillon 			ocp->count = OBJID_CACHE_BULK;
141*0729c8c8SMatthew Dillon 			TAILQ_INSERT_HEAD(&trans->hmp->objid_cache_list, ocp,
142*0729c8c8SMatthew Dillon 					  entry);
143*0729c8c8SMatthew Dillon 			++trans->hmp->objid_cache_count;
144*0729c8c8SMatthew Dillon 			/* may have blocked, recheck */
145*0729c8c8SMatthew Dillon 			if (dip->objid_cache == NULL) {
146*0729c8c8SMatthew Dillon 				dip->objid_cache = ocp;
147*0729c8c8SMatthew Dillon 				ocp->dip = dip;
148*0729c8c8SMatthew Dillon 			}
149*0729c8c8SMatthew Dillon 		} else {
150*0729c8c8SMatthew Dillon 			ocp = TAILQ_FIRST(&trans->hmp->objid_cache_list);
151*0729c8c8SMatthew Dillon 			if (ocp->dip)
152*0729c8c8SMatthew Dillon 				ocp->dip->objid_cache = NULL;
153*0729c8c8SMatthew Dillon 			dip->objid_cache = ocp;
154*0729c8c8SMatthew Dillon 			ocp->dip = dip;
155*0729c8c8SMatthew Dillon 		}
156*0729c8c8SMatthew Dillon 	}
157*0729c8c8SMatthew Dillon 	TAILQ_REMOVE(&trans->hmp->objid_cache_list, ocp, entry);
158*0729c8c8SMatthew Dillon 	tid = ocp->next_tid;
159*0729c8c8SMatthew Dillon 	ocp->next_tid += 2;
160*0729c8c8SMatthew Dillon 	if (--ocp->count == 0) {
161*0729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
162*0729c8c8SMatthew Dillon 		--trans->hmp->objid_cache_count;
163*0729c8c8SMatthew Dillon 		ocp->dip = NULL;
164*0729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
165*0729c8c8SMatthew Dillon 	} else {
166*0729c8c8SMatthew Dillon 		TAILQ_INSERT_TAIL(&trans->hmp->objid_cache_list, ocp, entry);
167*0729c8c8SMatthew Dillon 	}
168*0729c8c8SMatthew Dillon 	return(tid);
169*0729c8c8SMatthew Dillon }
170*0729c8c8SMatthew Dillon 
171*0729c8c8SMatthew Dillon void
172*0729c8c8SMatthew Dillon hammer_clear_objid(hammer_inode_t dip)
173*0729c8c8SMatthew Dillon {
174*0729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
175*0729c8c8SMatthew Dillon 
176*0729c8c8SMatthew Dillon 	if ((ocp = dip->objid_cache) != NULL) {
177*0729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
178*0729c8c8SMatthew Dillon 		ocp->dip = NULL;
179*0729c8c8SMatthew Dillon 		TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry);
180*0729c8c8SMatthew Dillon 		TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry);
181*0729c8c8SMatthew Dillon 	}
182*0729c8c8SMatthew Dillon }
183*0729c8c8SMatthew Dillon 
184*0729c8c8SMatthew Dillon void
185*0729c8c8SMatthew Dillon hammer_destroy_objid_cache(hammer_mount_t hmp)
186*0729c8c8SMatthew Dillon {
187*0729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
188*0729c8c8SMatthew Dillon 
189*0729c8c8SMatthew Dillon 	while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) {
190*0729c8c8SMatthew Dillon 		TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
191*0729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
192*0729c8c8SMatthew Dillon 	}
193*0729c8c8SMatthew Dillon }
194*0729c8c8SMatthew Dillon 
195