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*2f85fa4dSMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.15 2008/05/18 01:48:50 dillon Exp $
3566325755SMatthew Dillon  */
3666325755SMatthew Dillon 
3766325755SMatthew Dillon #include "hammer.h"
3866325755SMatthew Dillon 
390729c8c8SMatthew Dillon static hammer_tid_t hammer_alloc_tid(hammer_transaction_t trans, int count);
400729c8c8SMatthew Dillon 
410729c8c8SMatthew 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;
560729c8c8SMatthew Dillon 	trans->time = hammer_alloc_tid(trans, 1);
57*2f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
5866325755SMatthew Dillon }
5966325755SMatthew Dillon 
60b84de5afSMatthew Dillon /*
61b84de5afSMatthew Dillon  * Start a simple read-only transaction.  This will not stall.
62b84de5afSMatthew Dillon  */
6366325755SMatthew Dillon void
6436f82b23SMatthew Dillon hammer_simple_transaction(struct hammer_transaction *trans,
6536f82b23SMatthew Dillon 			  struct hammer_mount *hmp)
6636f82b23SMatthew Dillon {
6736f82b23SMatthew Dillon 	int error;
6836f82b23SMatthew Dillon 
69b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_RO;
7036f82b23SMatthew Dillon 	trans->hmp = hmp;
7136f82b23SMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
7236f82b23SMatthew Dillon 	KKASSERT(error == 0);
73b84de5afSMatthew Dillon 	trans->tid = 0;
740729c8c8SMatthew Dillon 	trans->time = hammer_alloc_tid(trans, 1);
75*2f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
7636f82b23SMatthew Dillon }
7736f82b23SMatthew Dillon 
78b84de5afSMatthew Dillon /*
79b84de5afSMatthew Dillon  * Start a transaction using a particular TID.  Used by the sync code.
80b84de5afSMatthew Dillon  * This does not stall.
81*2f85fa4dSMatthew Dillon  *
82*2f85fa4dSMatthew Dillon  * This routine may only be called from the flusher thread.  We predispose
83*2f85fa4dSMatthew Dillon  * sync_lock_refs, implying serialization against the synchronization stage
84*2f85fa4dSMatthew Dillon  * (which the flusher is responsible for).
85b84de5afSMatthew Dillon  */
8636f82b23SMatthew Dillon void
87b84de5afSMatthew Dillon hammer_start_transaction_fls(struct hammer_transaction *trans,
88b84de5afSMatthew Dillon 			     struct hammer_mount *hmp)
89d113fda1SMatthew Dillon {
90d113fda1SMatthew Dillon 	int error;
91d113fda1SMatthew Dillon 
92*2f85fa4dSMatthew Dillon 	KKASSERT(curthread == hmp->flusher_td);
93*2f85fa4dSMatthew Dillon 
94b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_FLS;
95d113fda1SMatthew Dillon 	trans->hmp = hmp;
96d113fda1SMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
97d113fda1SMatthew Dillon 	KKASSERT(error == 0);
980729c8c8SMatthew Dillon 	trans->tid = hammer_alloc_tid(trans, 1);
99b84de5afSMatthew Dillon 	trans->time = trans->tid;
100*2f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 1;
101d113fda1SMatthew Dillon }
102d113fda1SMatthew Dillon 
103d113fda1SMatthew Dillon void
104b84de5afSMatthew Dillon hammer_done_transaction(struct hammer_transaction *trans)
10566325755SMatthew Dillon {
106*2f85fa4dSMatthew Dillon 	int expected_lock_refs;
107*2f85fa4dSMatthew Dillon 
108a89aec1bSMatthew Dillon 	hammer_rel_volume(trans->rootvol, 0);
109b84de5afSMatthew Dillon 	trans->rootvol = NULL;
110*2f85fa4dSMatthew Dillon 	expected_lock_refs = (trans->type == HAMMER_TRANS_FLS) ? 1 : 0;
111*2f85fa4dSMatthew Dillon 	KKASSERT(trans->sync_lock_refs == expected_lock_refs);
112*2f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
11366325755SMatthew Dillon }
11466325755SMatthew Dillon 
115d113fda1SMatthew Dillon /*
116d113fda1SMatthew Dillon  * Note: Successive transaction ids must be at least 2 apart so the
117d113fda1SMatthew Dillon  * B-Tree code can make a separator that does not match either the
118d113fda1SMatthew Dillon  * left or right hand sides.
119d113fda1SMatthew Dillon  */
1200729c8c8SMatthew Dillon static hammer_tid_t
1210729c8c8SMatthew Dillon hammer_alloc_tid(hammer_transaction_t trans, int count)
122a89aec1bSMatthew Dillon {
123a89aec1bSMatthew Dillon 	struct timespec ts;
124a89aec1bSMatthew Dillon 	hammer_tid_t tid;
125a89aec1bSMatthew Dillon 
126a89aec1bSMatthew Dillon 	getnanotime(&ts);
127a89aec1bSMatthew Dillon 	tid = ts.tv_sec * 1000000000LL + ts.tv_nsec;
128b84de5afSMatthew Dillon 	if (tid < trans->hmp->next_tid)
129b84de5afSMatthew Dillon 		tid = trans->hmp->next_tid;
1300729c8c8SMatthew Dillon 	if (tid >= 0xFFFFFFFFFFFFF000ULL)
131a89aec1bSMatthew Dillon 		panic("hammer_start_transaction: Ran out of TIDs!");
1320729c8c8SMatthew Dillon 	trans->hmp->next_tid = tid + count * 2;
133d113fda1SMatthew Dillon 	if (hammer_debug_tid) {
134d113fda1SMatthew Dillon 		kprintf("alloc_tid %016llx (0x%08x)\n",
135d113fda1SMatthew Dillon 			tid, (int)(tid / 1000000000LL));
136d113fda1SMatthew Dillon 	}
137a89aec1bSMatthew Dillon 	return(tid);
138a89aec1bSMatthew Dillon }
139a89aec1bSMatthew Dillon 
1400729c8c8SMatthew Dillon /*
1410729c8c8SMatthew Dillon  * Allocate an object id
1420729c8c8SMatthew Dillon  */
1430729c8c8SMatthew Dillon hammer_tid_t
1440729c8c8SMatthew Dillon hammer_alloc_objid(hammer_transaction_t trans, hammer_inode_t dip)
1450729c8c8SMatthew Dillon {
1460729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
1470729c8c8SMatthew Dillon 	hammer_tid_t tid;
1480729c8c8SMatthew Dillon 
1490729c8c8SMatthew Dillon 	while ((ocp = dip->objid_cache) == NULL) {
1500729c8c8SMatthew Dillon 		if (trans->hmp->objid_cache_count < OBJID_CACHE_SIZE) {
1510729c8c8SMatthew Dillon 			ocp = kmalloc(sizeof(*ocp), M_HAMMER, M_WAITOK|M_ZERO);
1520729c8c8SMatthew Dillon 			ocp->next_tid = hammer_alloc_tid(trans,
1530729c8c8SMatthew Dillon 							 OBJID_CACHE_BULK);
1540729c8c8SMatthew Dillon 			ocp->count = OBJID_CACHE_BULK;
1550729c8c8SMatthew Dillon 			TAILQ_INSERT_HEAD(&trans->hmp->objid_cache_list, ocp,
1560729c8c8SMatthew Dillon 					  entry);
1570729c8c8SMatthew Dillon 			++trans->hmp->objid_cache_count;
1580729c8c8SMatthew Dillon 			/* may have blocked, recheck */
1590729c8c8SMatthew Dillon 			if (dip->objid_cache == NULL) {
1600729c8c8SMatthew Dillon 				dip->objid_cache = ocp;
1610729c8c8SMatthew Dillon 				ocp->dip = dip;
1620729c8c8SMatthew Dillon 			}
1630729c8c8SMatthew Dillon 		} else {
1640729c8c8SMatthew Dillon 			ocp = TAILQ_FIRST(&trans->hmp->objid_cache_list);
1650729c8c8SMatthew Dillon 			if (ocp->dip)
1660729c8c8SMatthew Dillon 				ocp->dip->objid_cache = NULL;
1670729c8c8SMatthew Dillon 			dip->objid_cache = ocp;
1680729c8c8SMatthew Dillon 			ocp->dip = dip;
1690729c8c8SMatthew Dillon 		}
1700729c8c8SMatthew Dillon 	}
1710729c8c8SMatthew Dillon 	TAILQ_REMOVE(&trans->hmp->objid_cache_list, ocp, entry);
1720729c8c8SMatthew Dillon 	tid = ocp->next_tid;
1730729c8c8SMatthew Dillon 	ocp->next_tid += 2;
1740729c8c8SMatthew Dillon 	if (--ocp->count == 0) {
1750729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
1760729c8c8SMatthew Dillon 		--trans->hmp->objid_cache_count;
1770729c8c8SMatthew Dillon 		ocp->dip = NULL;
1780729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
1790729c8c8SMatthew Dillon 	} else {
1800729c8c8SMatthew Dillon 		TAILQ_INSERT_TAIL(&trans->hmp->objid_cache_list, ocp, entry);
1810729c8c8SMatthew Dillon 	}
1820729c8c8SMatthew Dillon 	return(tid);
1830729c8c8SMatthew Dillon }
1840729c8c8SMatthew Dillon 
1850729c8c8SMatthew Dillon void
1860729c8c8SMatthew Dillon hammer_clear_objid(hammer_inode_t dip)
1870729c8c8SMatthew Dillon {
1880729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
1890729c8c8SMatthew Dillon 
1900729c8c8SMatthew Dillon 	if ((ocp = dip->objid_cache) != NULL) {
1910729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
1920729c8c8SMatthew Dillon 		ocp->dip = NULL;
1930729c8c8SMatthew Dillon 		TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry);
1940729c8c8SMatthew Dillon 		TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry);
1950729c8c8SMatthew Dillon 	}
1960729c8c8SMatthew Dillon }
1970729c8c8SMatthew Dillon 
1980729c8c8SMatthew Dillon void
1990729c8c8SMatthew Dillon hammer_destroy_objid_cache(hammer_mount_t hmp)
2000729c8c8SMatthew Dillon {
2010729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
2020729c8c8SMatthew Dillon 
2030729c8c8SMatthew Dillon 	while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) {
2040729c8c8SMatthew Dillon 		TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
2050729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
2060729c8c8SMatthew Dillon 	}
2070729c8c8SMatthew Dillon }
2080729c8c8SMatthew Dillon 
209