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  *
3421fde338SMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.25 2008/09/23 21:03:52 dillon Exp $
3566325755SMatthew Dillon  */
3666325755SMatthew Dillon 
3766325755SMatthew Dillon #include "hammer.h"
3866325755SMatthew Dillon 
395a64efa1SMatthew Dillon static u_int32_t ocp_allocbit(hammer_objid_cache_t ocp, u_int32_t n);
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;
5821fde338SMatthew Dillon 	trans->flags = 0;
59ddfdf542SMatthew Dillon 
60ddfdf542SMatthew Dillon 	getmicrotime(&tv);
61dd94f1b1SMatthew Dillon 	trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec;
62dd94f1b1SMatthew Dillon 	trans->time32 = (u_int32_t)tv.tv_sec;
6366325755SMatthew Dillon }
6466325755SMatthew Dillon 
65b84de5afSMatthew Dillon /*
66b84de5afSMatthew Dillon  * Start a simple read-only transaction.  This will not stall.
67b84de5afSMatthew Dillon  */
6866325755SMatthew Dillon void
6936f82b23SMatthew Dillon hammer_simple_transaction(struct hammer_transaction *trans,
7036f82b23SMatthew Dillon 			  struct hammer_mount *hmp)
7136f82b23SMatthew Dillon {
72ddfdf542SMatthew Dillon 	struct timeval tv;
7336f82b23SMatthew Dillon 	int error;
7436f82b23SMatthew Dillon 
75b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_RO;
7636f82b23SMatthew Dillon 	trans->hmp = hmp;
7736f82b23SMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
7836f82b23SMatthew Dillon 	KKASSERT(error == 0);
79b84de5afSMatthew Dillon 	trans->tid = 0;
802f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
8121fde338SMatthew Dillon 	trans->flags = 0;
82ddfdf542SMatthew Dillon 
83ddfdf542SMatthew Dillon 	getmicrotime(&tv);
84dd94f1b1SMatthew Dillon 	trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec;
85dd94f1b1SMatthew Dillon 	trans->time32 = (u_int32_t)tv.tv_sec;
8636f82b23SMatthew Dillon }
8736f82b23SMatthew Dillon 
88b84de5afSMatthew Dillon /*
89b84de5afSMatthew Dillon  * Start a transaction using a particular TID.  Used by the sync code.
90b84de5afSMatthew Dillon  * This does not stall.
912f85fa4dSMatthew Dillon  *
922f85fa4dSMatthew Dillon  * This routine may only be called from the flusher thread.  We predispose
932f85fa4dSMatthew Dillon  * sync_lock_refs, implying serialization against the synchronization stage
942f85fa4dSMatthew Dillon  * (which the flusher is responsible for).
95b84de5afSMatthew Dillon  */
9636f82b23SMatthew Dillon void
97b84de5afSMatthew Dillon hammer_start_transaction_fls(struct hammer_transaction *trans,
98b84de5afSMatthew Dillon 			     struct hammer_mount *hmp)
99d113fda1SMatthew Dillon {
100ddfdf542SMatthew Dillon 	struct timeval tv;
101d113fda1SMatthew Dillon 	int error;
102d113fda1SMatthew Dillon 
1039f5097dcSMatthew Dillon 	bzero(trans, sizeof(*trans));
1049f5097dcSMatthew Dillon 
105b84de5afSMatthew Dillon 	trans->type = HAMMER_TRANS_FLS;
106d113fda1SMatthew Dillon 	trans->hmp = hmp;
107d113fda1SMatthew Dillon 	trans->rootvol = hammer_get_root_volume(hmp, &error);
108d113fda1SMatthew Dillon 	KKASSERT(error == 0);
1095de0c0e5SMatthew Dillon 	trans->tid = hammer_alloc_tid(hmp, 1);
1102f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 1;
11121fde338SMatthew Dillon 	trans->flags = 0;
112ddfdf542SMatthew Dillon 
113ddfdf542SMatthew Dillon 	getmicrotime(&tv);
114dd94f1b1SMatthew Dillon 	trans->time = (unsigned long)tv.tv_sec * 1000000ULL + tv.tv_usec;
115dd94f1b1SMatthew Dillon 	trans->time32 = (u_int32_t)tv.tv_sec;
116d113fda1SMatthew Dillon }
117d113fda1SMatthew Dillon 
118d113fda1SMatthew Dillon void
119b84de5afSMatthew Dillon hammer_done_transaction(struct hammer_transaction *trans)
12066325755SMatthew Dillon {
1212f85fa4dSMatthew Dillon 	int expected_lock_refs;
1222f85fa4dSMatthew Dillon 
123a89aec1bSMatthew Dillon 	hammer_rel_volume(trans->rootvol, 0);
124b84de5afSMatthew Dillon 	trans->rootvol = NULL;
1252f85fa4dSMatthew Dillon 	expected_lock_refs = (trans->type == HAMMER_TRANS_FLS) ? 1 : 0;
1262f85fa4dSMatthew Dillon 	KKASSERT(trans->sync_lock_refs == expected_lock_refs);
1272f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
12882010f9fSMatthew Dillon 	if (trans->type != HAMMER_TRANS_FLS) {
12921fde338SMatthew Dillon 		if (trans->flags & HAMMER_TRANSF_NEWINODE)
130e98f1b96SMatthew Dillon 			hammer_inode_waitreclaims(trans);
131e98f1b96SMatthew Dillon 		/*
13282010f9fSMatthew Dillon 		else if (trans->flags & HAMMER_TRANSF_DIDIO)
133e98f1b96SMatthew Dillon 			hammer_inode_waitreclaims(trans);
134e98f1b96SMatthew Dillon 		*/
13582010f9fSMatthew Dillon 	}
13666325755SMatthew Dillon }
13766325755SMatthew Dillon 
138d113fda1SMatthew Dillon /*
1395de0c0e5SMatthew Dillon  * Allocate (count) TIDs.  If running in multi-master mode the returned
1405de0c0e5SMatthew Dillon  * base will be aligned to a 16-count plus the master id (0-15).
1415de0c0e5SMatthew Dillon  * Multi-master mode allows non-conflicting to run and new objects to be
1425de0c0e5SMatthew Dillon  * created on multiple masters in parallel.  The transaction id identifies
1435de0c0e5SMatthew Dillon  * the original master.  The object_id is also subject to this rule in
1445de0c0e5SMatthew Dillon  * order to allow objects to be created on multiple masters in parallel.
1455de0c0e5SMatthew Dillon  *
1465de0c0e5SMatthew Dillon  * Directories may pre-allocate a large number of object ids (100,000).
1475de0c0e5SMatthew Dillon  *
1485de0c0e5SMatthew Dillon  * NOTE: There is no longer a requirement that successive transaction
1495de0c0e5SMatthew Dillon  *	 ids be 2 apart for separator generation.
150*83f2a3aaSMatthew Dillon  *
151*83f2a3aaSMatthew Dillon  * NOTE: When called by pseudo-backends such as ioctls the allocated
152*83f2a3aaSMatthew Dillon  *	 TID will be larger then the current flush TID, if a flush is running,
153*83f2a3aaSMatthew Dillon  *	 so any mirroring will pick the records up on a later flush.
154d113fda1SMatthew Dillon  */
155*83f2a3aaSMatthew Dillon hammer_tid_t
1565de0c0e5SMatthew Dillon hammer_alloc_tid(hammer_mount_t hmp, int count)
157a89aec1bSMatthew Dillon {
158a89aec1bSMatthew Dillon 	hammer_tid_t tid;
159a89aec1bSMatthew Dillon 
160732a1697SMatthew Dillon 	if (hmp->master_id < 0) {
161c82af904SMatthew Dillon 		tid = hmp->next_tid + 1;
162c82af904SMatthew Dillon 		hmp->next_tid = tid + count;
163c82af904SMatthew Dillon 	} else {
164c82af904SMatthew Dillon 		tid = (hmp->next_tid + HAMMER_MAX_MASTERS) &
165c82af904SMatthew Dillon 		      ~(hammer_tid_t)(HAMMER_MAX_MASTERS - 1);
166c82af904SMatthew Dillon 		hmp->next_tid = tid + count * HAMMER_MAX_MASTERS;
167732a1697SMatthew Dillon 		tid |= hmp->master_id;
168c82af904SMatthew Dillon 	}
169c82af904SMatthew Dillon 	if (tid >= 0xFFFFFFFFFF000000ULL)
170a89aec1bSMatthew Dillon 		panic("hammer_start_transaction: Ran out of TIDs!");
1715de0c0e5SMatthew Dillon 	if (hammer_debug_tid)
172973c11b9SMatthew Dillon 		kprintf("alloc_tid %016llx\n", (long long)tid);
173a89aec1bSMatthew Dillon 	return(tid);
174a89aec1bSMatthew Dillon }
175a89aec1bSMatthew Dillon 
1760729c8c8SMatthew Dillon /*
1775a64efa1SMatthew Dillon  * Allocate an object id.
1785a64efa1SMatthew Dillon  *
1795a64efa1SMatthew Dillon  * We use the upper OBJID_CACHE_BITS bits of the namekey to try to match
1805a64efa1SMatthew Dillon  * the low bits of the objid we allocate.
1810729c8c8SMatthew Dillon  */
1820729c8c8SMatthew Dillon hammer_tid_t
1835a64efa1SMatthew Dillon hammer_alloc_objid(hammer_mount_t hmp, hammer_inode_t dip, int64_t namekey)
1840729c8c8SMatthew Dillon {
1850729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
1860729c8c8SMatthew Dillon 	hammer_tid_t tid;
1875a64efa1SMatthew Dillon 	u_int32_t n;
1880729c8c8SMatthew Dillon 
1890729c8c8SMatthew Dillon 	while ((ocp = dip->objid_cache) == NULL) {
1905de0c0e5SMatthew Dillon 		if (hmp->objid_cache_count < OBJID_CACHE_SIZE) {
191bac808feSMatthew Dillon 			ocp = kmalloc(sizeof(*ocp), hmp->m_misc,
192bac808feSMatthew Dillon 				      M_WAITOK|M_ZERO);
1935a64efa1SMatthew Dillon 			ocp->base_tid = hammer_alloc_tid(hmp,
1945a64efa1SMatthew Dillon 							OBJID_CACHE_BULK * 2);
1955a64efa1SMatthew Dillon 			ocp->base_tid += OBJID_CACHE_BULK_MASK64;
1965a64efa1SMatthew Dillon 			ocp->base_tid &= ~OBJID_CACHE_BULK_MASK64;
1970729c8c8SMatthew Dillon 			/* may have blocked, recheck */
1980729c8c8SMatthew Dillon 			if (dip->objid_cache == NULL) {
199d1ce1558SMatthew Dillon 				TAILQ_INSERT_TAIL(&hmp->objid_cache_list,
200d1ce1558SMatthew Dillon 						  ocp, entry);
201d1ce1558SMatthew Dillon 				++hmp->objid_cache_count;
2020729c8c8SMatthew Dillon 				dip->objid_cache = ocp;
2030729c8c8SMatthew Dillon 				ocp->dip = dip;
204d1ce1558SMatthew Dillon 			} else {
205d1ce1558SMatthew Dillon 				kfree(ocp, hmp->m_misc);
2060729c8c8SMatthew Dillon 			}
2070729c8c8SMatthew Dillon 		} else {
2085a64efa1SMatthew Dillon 			/*
2095a64efa1SMatthew Dillon 			 * Steal one from another directory?
2105a64efa1SMatthew Dillon 			 *
2115a64efa1SMatthew Dillon 			 * Throw away ocp's that are more then half full, they
2125a64efa1SMatthew Dillon 			 * aren't worth stealing.
2135a64efa1SMatthew Dillon 			 */
2145de0c0e5SMatthew Dillon 			ocp = TAILQ_FIRST(&hmp->objid_cache_list);
2150729c8c8SMatthew Dillon 			if (ocp->dip)
2160729c8c8SMatthew Dillon 				ocp->dip->objid_cache = NULL;
2175a64efa1SMatthew Dillon 			if (ocp->count >= OBJID_CACHE_BULK / 2) {
218d1ce1558SMatthew Dillon 				TAILQ_REMOVE(&hmp->objid_cache_list,
219d1ce1558SMatthew Dillon 					     ocp, entry);
2205a64efa1SMatthew Dillon 				--hmp->objid_cache_count;
2215a64efa1SMatthew Dillon 				kfree(ocp, hmp->m_misc);
2225a64efa1SMatthew Dillon 			} else {
2230729c8c8SMatthew Dillon 				dip->objid_cache = ocp;
2240729c8c8SMatthew Dillon 				ocp->dip = dip;
2250729c8c8SMatthew Dillon 			}
2260729c8c8SMatthew Dillon 		}
2275a64efa1SMatthew Dillon 	}
2285de0c0e5SMatthew Dillon 	TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
2295de0c0e5SMatthew Dillon 
2305de0c0e5SMatthew Dillon 	/*
231d1ce1558SMatthew Dillon 	 * Allocate inode numbers uniformly.
2325a64efa1SMatthew Dillon 	 */
233d1ce1558SMatthew Dillon 
2345a64efa1SMatthew Dillon 	n = (namekey >> (63 - OBJID_CACHE_BULK_BITS)) & OBJID_CACHE_BULK_MASK;
2355a64efa1SMatthew Dillon 	n = ocp_allocbit(ocp, n);
2365a64efa1SMatthew Dillon 	tid = ocp->base_tid + n;
2375a64efa1SMatthew Dillon 
2385a64efa1SMatthew Dillon #if 0
2395a64efa1SMatthew Dillon 	/*
2405de0c0e5SMatthew Dillon 	 * The TID is incremented by 1 or by 16 depending what mode the
2415de0c0e5SMatthew Dillon 	 * mount is operating in.
2425de0c0e5SMatthew Dillon 	 */
243732a1697SMatthew Dillon 	ocp->next_tid += (hmp->master_id < 0) ? 1 : HAMMER_MAX_MASTERS;
2445a64efa1SMatthew Dillon #endif
245d1ce1558SMatthew Dillon 	if (ocp->count >= OBJID_CACHE_BULK * 3 / 4) {
2460729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
2475de0c0e5SMatthew Dillon 		--hmp->objid_cache_count;
2480729c8c8SMatthew Dillon 		ocp->dip = NULL;
249bac808feSMatthew Dillon 		kfree(ocp, hmp->m_misc);
2500729c8c8SMatthew Dillon 	} else {
2515de0c0e5SMatthew Dillon 		TAILQ_INSERT_TAIL(&hmp->objid_cache_list, ocp, entry);
2520729c8c8SMatthew Dillon 	}
2530729c8c8SMatthew Dillon 	return(tid);
2540729c8c8SMatthew Dillon }
2550729c8c8SMatthew Dillon 
2565a64efa1SMatthew Dillon /*
2575a64efa1SMatthew Dillon  * Allocate a bit starting with bit n.  Wrap if necessary.
2585a64efa1SMatthew Dillon  *
2595a64efa1SMatthew Dillon  * This routine is only ever called if a bit is available somewhere
2605a64efa1SMatthew Dillon  * in the bitmap.
2615a64efa1SMatthew Dillon  */
2625a64efa1SMatthew Dillon static u_int32_t
2635a64efa1SMatthew Dillon ocp_allocbit(hammer_objid_cache_t ocp, u_int32_t n)
2645a64efa1SMatthew Dillon {
2655a64efa1SMatthew Dillon 	u_int32_t n0;
2665a64efa1SMatthew Dillon 
2675a64efa1SMatthew Dillon 	n0 = (n >> 5) & 31;
2685a64efa1SMatthew Dillon 	n &= 31;
2695a64efa1SMatthew Dillon 
2705a64efa1SMatthew Dillon 	while (ocp->bm1[n0] & (1 << n)) {
2715a64efa1SMatthew Dillon 		if (ocp->bm0 & (1 << n0)) {
2725a64efa1SMatthew Dillon 			n0 = (n0 + 1) & 31;
2735a64efa1SMatthew Dillon 			n = 0;
2745a64efa1SMatthew Dillon 		} else if (++n == 32) {
2755a64efa1SMatthew Dillon 			n0 = (n0 + 1) & 31;
2765a64efa1SMatthew Dillon 			n = 0;
2775a64efa1SMatthew Dillon 		}
2785a64efa1SMatthew Dillon 	}
2795a64efa1SMatthew Dillon 	++ocp->count;
2805a64efa1SMatthew Dillon 	ocp->bm1[n0] |= 1 << n;
2815a64efa1SMatthew Dillon 	if (ocp->bm1[n0] == 0xFFFFFFFFU)
2825a64efa1SMatthew Dillon 		ocp->bm0 |= 1 << n0;
2835a64efa1SMatthew Dillon 	return((n0 << 5) + n);
2845a64efa1SMatthew Dillon }
2855a64efa1SMatthew Dillon 
2860729c8c8SMatthew Dillon void
2870729c8c8SMatthew Dillon hammer_clear_objid(hammer_inode_t dip)
2880729c8c8SMatthew Dillon {
2890729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
2900729c8c8SMatthew Dillon 
2910729c8c8SMatthew Dillon 	if ((ocp = dip->objid_cache) != NULL) {
2920729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
2930729c8c8SMatthew Dillon 		ocp->dip = NULL;
2940729c8c8SMatthew Dillon 		TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry);
2950729c8c8SMatthew Dillon 		TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry);
2960729c8c8SMatthew Dillon 	}
2970729c8c8SMatthew Dillon }
2980729c8c8SMatthew Dillon 
2990729c8c8SMatthew Dillon void
3000729c8c8SMatthew Dillon hammer_destroy_objid_cache(hammer_mount_t hmp)
3010729c8c8SMatthew Dillon {
3020729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
3030729c8c8SMatthew Dillon 
3040729c8c8SMatthew Dillon 	while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) {
3050729c8c8SMatthew Dillon 		TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
306f437a2abSMatthew Dillon 		if (ocp->dip)
307f437a2abSMatthew Dillon 			ocp->dip->objid_cache = NULL;
308bac808feSMatthew Dillon 		kfree(ocp, hmp->m_misc);
309d1ce1558SMatthew Dillon 		--hmp->objid_cache_count;
3100729c8c8SMatthew Dillon 	}
311d1ce1558SMatthew Dillon 	KKASSERT(hmp->objid_cache_count == 0);
3120729c8c8SMatthew Dillon }
3130729c8c8SMatthew Dillon 
314