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*732a1697SMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.24 2008/07/19 18:44:49 dillon Exp $
3566325755SMatthew Dillon  */
3666325755SMatthew Dillon 
3766325755SMatthew Dillon #include "hammer.h"
3866325755SMatthew Dillon 
395de0c0e5SMatthew Dillon static hammer_tid_t hammer_alloc_tid(hammer_mount_t hmp, 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 {
49ddfdf542SMatthew Dillon 	struct timeval tv;
50a89aec1bSMatthew Dillon 	int error;
5166325755SMatthew Dillon 
52b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_STD;
5366325755SMatthew Dillon 	trans->hmp = hmp;
54a89aec1bSMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
55a89aec1bSMatthew Dillon 	KKASSERT(error == 0);
56b84de5afSMatthew Dillon 	trans->tid = 0;
572f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
58ddfdf542SMatthew Dillon 
59ddfdf542SMatthew Dillon 	getmicrotime(&tv);
60dd94f1b1SMatthew Dillon 	trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec;
61dd94f1b1SMatthew Dillon 	trans->time32 = (u_int32_t)tv.tv_sec;
6266325755SMatthew Dillon }
6366325755SMatthew Dillon 
64b84de5afSMatthew Dillon /*
65b84de5afSMatthew Dillon  * Start a simple read-only transaction.  This will not stall.
66b84de5afSMatthew Dillon  */
6766325755SMatthew Dillon void
6836f82b23SMatthew Dillon hammer_simple_transaction(struct hammer_transaction *trans,
6936f82b23SMatthew Dillon 			  struct hammer_mount *hmp)
7036f82b23SMatthew Dillon {
71ddfdf542SMatthew Dillon 	struct timeval tv;
7236f82b23SMatthew Dillon 	int error;
7336f82b23SMatthew Dillon 
74b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_RO;
7536f82b23SMatthew Dillon 	trans->hmp = hmp;
7636f82b23SMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
7736f82b23SMatthew Dillon 	KKASSERT(error == 0);
78b84de5afSMatthew Dillon 	trans->tid = 0;
792f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
80ddfdf542SMatthew Dillon 
81ddfdf542SMatthew Dillon 	getmicrotime(&tv);
82dd94f1b1SMatthew Dillon 	trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec;
83dd94f1b1SMatthew Dillon 	trans->time32 = (u_int32_t)tv.tv_sec;
8436f82b23SMatthew Dillon }
8536f82b23SMatthew Dillon 
86b84de5afSMatthew Dillon /*
87b84de5afSMatthew Dillon  * Start a transaction using a particular TID.  Used by the sync code.
88b84de5afSMatthew Dillon  * This does not stall.
892f85fa4dSMatthew Dillon  *
902f85fa4dSMatthew Dillon  * This routine may only be called from the flusher thread.  We predispose
912f85fa4dSMatthew Dillon  * sync_lock_refs, implying serialization against the synchronization stage
922f85fa4dSMatthew Dillon  * (which the flusher is responsible for).
93b84de5afSMatthew Dillon  */
9436f82b23SMatthew Dillon void
95b84de5afSMatthew Dillon hammer_start_transaction_fls(struct hammer_transaction *trans,
96b84de5afSMatthew Dillon 			     struct hammer_mount *hmp)
97d113fda1SMatthew Dillon {
98ddfdf542SMatthew Dillon 	struct timeval tv;
99d113fda1SMatthew Dillon 	int error;
100d113fda1SMatthew Dillon 
1019f5097dcSMatthew Dillon 	bzero(trans, sizeof(*trans));
1029f5097dcSMatthew Dillon 
103b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_FLS;
104d113fda1SMatthew Dillon 	trans->hmp = hmp;
105d113fda1SMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
106d113fda1SMatthew Dillon 	KKASSERT(error == 0);
1075de0c0e5SMatthew Dillon 	trans->tid = hammer_alloc_tid(hmp, 1);
1082f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 1;
109ddfdf542SMatthew Dillon 
110ddfdf542SMatthew Dillon 	getmicrotime(&tv);
111dd94f1b1SMatthew Dillon 	trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec;
112dd94f1b1SMatthew Dillon 	trans->time32 = (u_int32_t)tv.tv_sec;
113d113fda1SMatthew Dillon }
114d113fda1SMatthew Dillon 
115d113fda1SMatthew Dillon void
116b84de5afSMatthew Dillon hammer_done_transaction(struct hammer_transaction *trans)
11766325755SMatthew Dillon {
1182f85fa4dSMatthew Dillon 	int expected_lock_refs;
1192f85fa4dSMatthew Dillon 
120a89aec1bSMatthew Dillon 	hammer_rel_volume(trans->rootvol, 0);
121b84de5afSMatthew Dillon 	trans->rootvol = NULL;
1222f85fa4dSMatthew Dillon 	expected_lock_refs = (trans->type == HAMMER_TRANS_FLS) ? 1 : 0;
1232f85fa4dSMatthew Dillon 	KKASSERT(trans->sync_lock_refs == expected_lock_refs);
1242f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
12566325755SMatthew Dillon }
12666325755SMatthew Dillon 
127d113fda1SMatthew Dillon /*
1285de0c0e5SMatthew Dillon  * Allocate (count) TIDs.  If running in multi-master mode the returned
1295de0c0e5SMatthew Dillon  * base will be aligned to a 16-count plus the master id (0-15).
1305de0c0e5SMatthew Dillon  * Multi-master mode allows non-conflicting to run and new objects to be
1315de0c0e5SMatthew Dillon  * created on multiple masters in parallel.  The transaction id identifies
1325de0c0e5SMatthew Dillon  * the original master.  The object_id is also subject to this rule in
1335de0c0e5SMatthew Dillon  * order to allow objects to be created on multiple masters in parallel.
1345de0c0e5SMatthew Dillon  *
1355de0c0e5SMatthew Dillon  * Directories may pre-allocate a large number of object ids (100,000).
1365de0c0e5SMatthew Dillon  *
1375de0c0e5SMatthew Dillon  * NOTE: There is no longer a requirement that successive transaction
1385de0c0e5SMatthew Dillon  * ids be 2 apart for separator generation.
139d113fda1SMatthew Dillon  */
1400729c8c8SMatthew Dillon static hammer_tid_t
1415de0c0e5SMatthew Dillon hammer_alloc_tid(hammer_mount_t hmp, int count)
142a89aec1bSMatthew Dillon {
143a89aec1bSMatthew Dillon 	hammer_tid_t tid;
144a89aec1bSMatthew Dillon 
145*732a1697SMatthew Dillon 	if (hmp->master_id < 0) {
146c82af904SMatthew Dillon 		tid = hmp->next_tid + 1;
147c82af904SMatthew Dillon 		hmp->next_tid = tid + count;
148c82af904SMatthew Dillon 	} else {
149c82af904SMatthew Dillon 		tid = (hmp->next_tid + HAMMER_MAX_MASTERS) &
150c82af904SMatthew Dillon 		      ~(hammer_tid_t)(HAMMER_MAX_MASTERS - 1);
151c82af904SMatthew Dillon 		hmp->next_tid = tid + count * HAMMER_MAX_MASTERS;
152*732a1697SMatthew Dillon 		tid |= hmp->master_id;
153c82af904SMatthew Dillon 	}
154c82af904SMatthew Dillon 	if (tid >= 0xFFFFFFFFFF000000ULL)
155a89aec1bSMatthew Dillon 		panic("hammer_start_transaction: Ran out of TIDs!");
1565de0c0e5SMatthew Dillon 	if (hammer_debug_tid)
1575de0c0e5SMatthew Dillon 		kprintf("alloc_tid %016llx\n", tid);
158a89aec1bSMatthew Dillon 	return(tid);
159a89aec1bSMatthew Dillon }
160a89aec1bSMatthew Dillon 
1610729c8c8SMatthew Dillon /*
1620729c8c8SMatthew Dillon  * Allocate an object id
1630729c8c8SMatthew Dillon  */
1640729c8c8SMatthew Dillon hammer_tid_t
1655de0c0e5SMatthew Dillon hammer_alloc_objid(hammer_mount_t hmp, hammer_inode_t dip)
1660729c8c8SMatthew Dillon {
1670729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
1680729c8c8SMatthew Dillon 	hammer_tid_t tid;
1690729c8c8SMatthew Dillon 
1700729c8c8SMatthew Dillon 	while ((ocp = dip->objid_cache) == NULL) {
1715de0c0e5SMatthew Dillon 		if (hmp->objid_cache_count < OBJID_CACHE_SIZE) {
1720729c8c8SMatthew Dillon 			ocp = kmalloc(sizeof(*ocp), M_HAMMER, M_WAITOK|M_ZERO);
1735de0c0e5SMatthew Dillon 			ocp->next_tid = hammer_alloc_tid(hmp, OBJID_CACHE_BULK);
1740729c8c8SMatthew Dillon 			ocp->count = OBJID_CACHE_BULK;
1755de0c0e5SMatthew Dillon 			TAILQ_INSERT_HEAD(&hmp->objid_cache_list, ocp, entry);
1765de0c0e5SMatthew Dillon 			++hmp->objid_cache_count;
1770729c8c8SMatthew Dillon 			/* may have blocked, recheck */
1780729c8c8SMatthew Dillon 			if (dip->objid_cache == NULL) {
1790729c8c8SMatthew Dillon 				dip->objid_cache = ocp;
1800729c8c8SMatthew Dillon 				ocp->dip = dip;
1810729c8c8SMatthew Dillon 			}
1820729c8c8SMatthew Dillon 		} else {
1835de0c0e5SMatthew Dillon 			ocp = TAILQ_FIRST(&hmp->objid_cache_list);
1840729c8c8SMatthew Dillon 			if (ocp->dip)
1850729c8c8SMatthew Dillon 				ocp->dip->objid_cache = NULL;
1860729c8c8SMatthew Dillon 			dip->objid_cache = ocp;
1870729c8c8SMatthew Dillon 			ocp->dip = dip;
1880729c8c8SMatthew Dillon 		}
1890729c8c8SMatthew Dillon 	}
1905de0c0e5SMatthew Dillon 	TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
1915de0c0e5SMatthew Dillon 
1925de0c0e5SMatthew Dillon 	/*
1935de0c0e5SMatthew Dillon 	 * The TID is incremented by 1 or by 16 depending what mode the
1945de0c0e5SMatthew Dillon 	 * mount is operating in.
1955de0c0e5SMatthew Dillon 	 */
1960729c8c8SMatthew Dillon 	tid = ocp->next_tid;
197*732a1697SMatthew Dillon 	ocp->next_tid += (hmp->master_id < 0) ? 1 : HAMMER_MAX_MASTERS;
1985de0c0e5SMatthew Dillon 
1990729c8c8SMatthew Dillon 	if (--ocp->count == 0) {
2000729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
2015de0c0e5SMatthew Dillon 		--hmp->objid_cache_count;
2020729c8c8SMatthew Dillon 		ocp->dip = NULL;
2030729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
2040729c8c8SMatthew Dillon 	} else {
2055de0c0e5SMatthew Dillon 		TAILQ_INSERT_TAIL(&hmp->objid_cache_list, ocp, entry);
2060729c8c8SMatthew Dillon 	}
2070729c8c8SMatthew Dillon 	return(tid);
2080729c8c8SMatthew Dillon }
2090729c8c8SMatthew Dillon 
2100729c8c8SMatthew Dillon void
2110729c8c8SMatthew Dillon hammer_clear_objid(hammer_inode_t dip)
2120729c8c8SMatthew Dillon {
2130729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
2140729c8c8SMatthew Dillon 
2150729c8c8SMatthew Dillon 	if ((ocp = dip->objid_cache) != NULL) {
2160729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
2170729c8c8SMatthew Dillon 		ocp->dip = NULL;
2180729c8c8SMatthew Dillon 		TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry);
2190729c8c8SMatthew Dillon 		TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry);
2200729c8c8SMatthew Dillon 	}
2210729c8c8SMatthew Dillon }
2220729c8c8SMatthew Dillon 
2230729c8c8SMatthew Dillon void
2240729c8c8SMatthew Dillon hammer_destroy_objid_cache(hammer_mount_t hmp)
2250729c8c8SMatthew Dillon {
2260729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
2270729c8c8SMatthew Dillon 
2280729c8c8SMatthew Dillon 	while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) {
2290729c8c8SMatthew Dillon 		TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
230f437a2abSMatthew Dillon 		if (ocp->dip)
231f437a2abSMatthew Dillon 			ocp->dip->objid_cache = NULL;
2320729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
2330729c8c8SMatthew Dillon 	}
2340729c8c8SMatthew Dillon }
2350729c8c8SMatthew Dillon 
236