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*9f5097dcSMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.16 2008/06/09 04:19:10 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);
572f85fa4dSMatthew 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);
752f85fa4dSMatthew 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.
812f85fa4dSMatthew Dillon  *
822f85fa4dSMatthew Dillon  * This routine may only be called from the flusher thread.  We predispose
832f85fa4dSMatthew Dillon  * sync_lock_refs, implying serialization against the synchronization stage
842f85fa4dSMatthew 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 
922f85fa4dSMatthew Dillon 	KKASSERT(curthread == hmp->flusher_td);
932f85fa4dSMatthew Dillon 
94*9f5097dcSMatthew Dillon 	bzero(trans, sizeof(*trans));
95*9f5097dcSMatthew Dillon 
96b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_FLS;
97d113fda1SMatthew Dillon 	trans->hmp = hmp;
98d113fda1SMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
99d113fda1SMatthew Dillon 	KKASSERT(error == 0);
1000729c8c8SMatthew Dillon 	trans->tid = hammer_alloc_tid(trans, 1);
101b84de5afSMatthew Dillon 	trans->time = trans->tid;
1022f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 1;
103d113fda1SMatthew Dillon }
104d113fda1SMatthew Dillon 
105d113fda1SMatthew Dillon void
106b84de5afSMatthew Dillon hammer_done_transaction(struct hammer_transaction *trans)
10766325755SMatthew Dillon {
1082f85fa4dSMatthew Dillon 	int expected_lock_refs;
1092f85fa4dSMatthew Dillon 
110a89aec1bSMatthew Dillon 	hammer_rel_volume(trans->rootvol, 0);
111b84de5afSMatthew Dillon 	trans->rootvol = NULL;
1122f85fa4dSMatthew Dillon 	expected_lock_refs = (trans->type == HAMMER_TRANS_FLS) ? 1 : 0;
1132f85fa4dSMatthew Dillon 	KKASSERT(trans->sync_lock_refs == expected_lock_refs);
1142f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
11566325755SMatthew Dillon }
11666325755SMatthew Dillon 
117d113fda1SMatthew Dillon /*
118d113fda1SMatthew Dillon  * Note: Successive transaction ids must be at least 2 apart so the
119d113fda1SMatthew Dillon  * B-Tree code can make a separator that does not match either the
120d113fda1SMatthew Dillon  * left or right hand sides.
121d113fda1SMatthew Dillon  */
1220729c8c8SMatthew Dillon static hammer_tid_t
1230729c8c8SMatthew Dillon hammer_alloc_tid(hammer_transaction_t trans, int count)
124a89aec1bSMatthew Dillon {
125a89aec1bSMatthew Dillon 	struct timespec ts;
126a89aec1bSMatthew Dillon 	hammer_tid_t tid;
127a89aec1bSMatthew Dillon 
128a89aec1bSMatthew Dillon 	getnanotime(&ts);
129a89aec1bSMatthew Dillon 	tid = ts.tv_sec * 1000000000LL + ts.tv_nsec;
130b84de5afSMatthew Dillon 	if (tid < trans->hmp->next_tid)
131b84de5afSMatthew Dillon 		tid = trans->hmp->next_tid;
1320729c8c8SMatthew Dillon 	if (tid >= 0xFFFFFFFFFFFFF000ULL)
133a89aec1bSMatthew Dillon 		panic("hammer_start_transaction: Ran out of TIDs!");
1340729c8c8SMatthew Dillon 	trans->hmp->next_tid = tid + count * 2;
135d113fda1SMatthew Dillon 	if (hammer_debug_tid) {
136d113fda1SMatthew Dillon 		kprintf("alloc_tid %016llx (0x%08x)\n",
137d113fda1SMatthew Dillon 			tid, (int)(tid / 1000000000LL));
138d113fda1SMatthew Dillon 	}
139a89aec1bSMatthew Dillon 	return(tid);
140a89aec1bSMatthew Dillon }
141a89aec1bSMatthew Dillon 
1420729c8c8SMatthew Dillon /*
1430729c8c8SMatthew Dillon  * Allocate an object id
1440729c8c8SMatthew Dillon  */
1450729c8c8SMatthew Dillon hammer_tid_t
1460729c8c8SMatthew Dillon hammer_alloc_objid(hammer_transaction_t trans, hammer_inode_t dip)
1470729c8c8SMatthew Dillon {
1480729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
1490729c8c8SMatthew Dillon 	hammer_tid_t tid;
1500729c8c8SMatthew Dillon 
1510729c8c8SMatthew Dillon 	while ((ocp = dip->objid_cache) == NULL) {
1520729c8c8SMatthew Dillon 		if (trans->hmp->objid_cache_count < OBJID_CACHE_SIZE) {
1530729c8c8SMatthew Dillon 			ocp = kmalloc(sizeof(*ocp), M_HAMMER, M_WAITOK|M_ZERO);
1540729c8c8SMatthew Dillon 			ocp->next_tid = hammer_alloc_tid(trans,
1550729c8c8SMatthew Dillon 							 OBJID_CACHE_BULK);
1560729c8c8SMatthew Dillon 			ocp->count = OBJID_CACHE_BULK;
1570729c8c8SMatthew Dillon 			TAILQ_INSERT_HEAD(&trans->hmp->objid_cache_list, ocp,
1580729c8c8SMatthew Dillon 					  entry);
1590729c8c8SMatthew Dillon 			++trans->hmp->objid_cache_count;
1600729c8c8SMatthew Dillon 			/* may have blocked, recheck */
1610729c8c8SMatthew Dillon 			if (dip->objid_cache == NULL) {
1620729c8c8SMatthew Dillon 				dip->objid_cache = ocp;
1630729c8c8SMatthew Dillon 				ocp->dip = dip;
1640729c8c8SMatthew Dillon 			}
1650729c8c8SMatthew Dillon 		} else {
1660729c8c8SMatthew Dillon 			ocp = TAILQ_FIRST(&trans->hmp->objid_cache_list);
1670729c8c8SMatthew Dillon 			if (ocp->dip)
1680729c8c8SMatthew Dillon 				ocp->dip->objid_cache = NULL;
1690729c8c8SMatthew Dillon 			dip->objid_cache = ocp;
1700729c8c8SMatthew Dillon 			ocp->dip = dip;
1710729c8c8SMatthew Dillon 		}
1720729c8c8SMatthew Dillon 	}
1730729c8c8SMatthew Dillon 	TAILQ_REMOVE(&trans->hmp->objid_cache_list, ocp, entry);
1740729c8c8SMatthew Dillon 	tid = ocp->next_tid;
1750729c8c8SMatthew Dillon 	ocp->next_tid += 2;
1760729c8c8SMatthew Dillon 	if (--ocp->count == 0) {
1770729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
1780729c8c8SMatthew Dillon 		--trans->hmp->objid_cache_count;
1790729c8c8SMatthew Dillon 		ocp->dip = NULL;
1800729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
1810729c8c8SMatthew Dillon 	} else {
1820729c8c8SMatthew Dillon 		TAILQ_INSERT_TAIL(&trans->hmp->objid_cache_list, ocp, entry);
1830729c8c8SMatthew Dillon 	}
1840729c8c8SMatthew Dillon 	return(tid);
1850729c8c8SMatthew Dillon }
1860729c8c8SMatthew Dillon 
1870729c8c8SMatthew Dillon void
1880729c8c8SMatthew Dillon hammer_clear_objid(hammer_inode_t dip)
1890729c8c8SMatthew Dillon {
1900729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
1910729c8c8SMatthew Dillon 
1920729c8c8SMatthew Dillon 	if ((ocp = dip->objid_cache) != NULL) {
1930729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
1940729c8c8SMatthew Dillon 		ocp->dip = NULL;
1950729c8c8SMatthew Dillon 		TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry);
1960729c8c8SMatthew Dillon 		TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry);
1970729c8c8SMatthew Dillon 	}
1980729c8c8SMatthew Dillon }
1990729c8c8SMatthew Dillon 
2000729c8c8SMatthew Dillon void
2010729c8c8SMatthew Dillon hammer_destroy_objid_cache(hammer_mount_t hmp)
2020729c8c8SMatthew Dillon {
2030729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
2040729c8c8SMatthew Dillon 
2050729c8c8SMatthew Dillon 	while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) {
2060729c8c8SMatthew Dillon 		TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
2070729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
2080729c8c8SMatthew Dillon 	}
2090729c8c8SMatthew Dillon }
2100729c8c8SMatthew Dillon 
211