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 {
12182010f9fSMatthew Dillon 	hammer_mount_t hmp = trans->hmp;
1222f85fa4dSMatthew Dillon 	int expected_lock_refs;
1232f85fa4dSMatthew Dillon 
124a89aec1bSMatthew Dillon 	hammer_rel_volume(trans->rootvol, 0);
125b84de5afSMatthew Dillon 	trans->rootvol = NULL;
1262f85fa4dSMatthew Dillon 	expected_lock_refs = (trans->type == HAMMER_TRANS_FLS) ? 1 : 0;
1272f85fa4dSMatthew Dillon 	KKASSERT(trans->sync_lock_refs == expected_lock_refs);
1282f85fa4dSMatthew Dillon 	trans->sync_lock_refs = 0;
12982010f9fSMatthew Dillon 	if (trans->type != HAMMER_TRANS_FLS) {
13021fde338SMatthew Dillon 		if (trans->flags & HAMMER_TRANSF_NEWINODE)
13182010f9fSMatthew Dillon 			hammer_inode_waitreclaims(hmp);
13282010f9fSMatthew Dillon 		else if (trans->flags & HAMMER_TRANSF_DIDIO)
133ccf6a64dSMatthew Dillon 			hammer_inode_waitreclaims(hmp);
13482010f9fSMatthew Dillon 	}
13566325755SMatthew Dillon }
13666325755SMatthew Dillon 
137d113fda1SMatthew Dillon /*
1385de0c0e5SMatthew Dillon  * Allocate (count) TIDs.  If running in multi-master mode the returned
1395de0c0e5SMatthew Dillon  * base will be aligned to a 16-count plus the master id (0-15).
1405de0c0e5SMatthew Dillon  * Multi-master mode allows non-conflicting to run and new objects to be
1415de0c0e5SMatthew Dillon  * created on multiple masters in parallel.  The transaction id identifies
1425de0c0e5SMatthew Dillon  * the original master.  The object_id is also subject to this rule in
1435de0c0e5SMatthew Dillon  * order to allow objects to be created on multiple masters in parallel.
1445de0c0e5SMatthew Dillon  *
1455de0c0e5SMatthew Dillon  * Directories may pre-allocate a large number of object ids (100,000).
1465de0c0e5SMatthew Dillon  *
1475de0c0e5SMatthew Dillon  * NOTE: There is no longer a requirement that successive transaction
1485de0c0e5SMatthew Dillon  *	 ids be 2 apart for separator generation.
149*83f2a3aaSMatthew Dillon  *
150*83f2a3aaSMatthew Dillon  * NOTE: When called by pseudo-backends such as ioctls the allocated
151*83f2a3aaSMatthew Dillon  *	 TID will be larger then the current flush TID, if a flush is running,
152*83f2a3aaSMatthew Dillon  *	 so any mirroring will pick the records up on a later flush.
153d113fda1SMatthew Dillon  */
154*83f2a3aaSMatthew Dillon hammer_tid_t
1555de0c0e5SMatthew Dillon hammer_alloc_tid(hammer_mount_t hmp, int count)
156a89aec1bSMatthew Dillon {
157a89aec1bSMatthew Dillon 	hammer_tid_t tid;
158a89aec1bSMatthew Dillon 
159732a1697SMatthew Dillon 	if (hmp->master_id < 0) {
160c82af904SMatthew Dillon 		tid = hmp->next_tid + 1;
161c82af904SMatthew Dillon 		hmp->next_tid = tid + count;
162c82af904SMatthew Dillon 	} else {
163c82af904SMatthew Dillon 		tid = (hmp->next_tid + HAMMER_MAX_MASTERS) &
164c82af904SMatthew Dillon 		      ~(hammer_tid_t)(HAMMER_MAX_MASTERS - 1);
165c82af904SMatthew Dillon 		hmp->next_tid = tid + count * HAMMER_MAX_MASTERS;
166732a1697SMatthew Dillon 		tid |= hmp->master_id;
167c82af904SMatthew Dillon 	}
168c82af904SMatthew Dillon 	if (tid >= 0xFFFFFFFFFF000000ULL)
169a89aec1bSMatthew Dillon 		panic("hammer_start_transaction: Ran out of TIDs!");
1705de0c0e5SMatthew Dillon 	if (hammer_debug_tid)
171973c11b9SMatthew Dillon 		kprintf("alloc_tid %016llx\n", (long long)tid);
172a89aec1bSMatthew Dillon 	return(tid);
173a89aec1bSMatthew Dillon }
174a89aec1bSMatthew Dillon 
1750729c8c8SMatthew Dillon /*
1765a64efa1SMatthew Dillon  * Allocate an object id.
1775a64efa1SMatthew Dillon  *
1785a64efa1SMatthew Dillon  * We use the upper OBJID_CACHE_BITS bits of the namekey to try to match
1795a64efa1SMatthew Dillon  * the low bits of the objid we allocate.
1800729c8c8SMatthew Dillon  */
1810729c8c8SMatthew Dillon hammer_tid_t
1825a64efa1SMatthew Dillon hammer_alloc_objid(hammer_mount_t hmp, hammer_inode_t dip, int64_t namekey)
1830729c8c8SMatthew Dillon {
1840729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
1850729c8c8SMatthew Dillon 	hammer_tid_t tid;
1865a64efa1SMatthew Dillon 	int incluster;
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;
1975de0c0e5SMatthew Dillon 			TAILQ_INSERT_HEAD(&hmp->objid_cache_list, ocp, entry);
1985de0c0e5SMatthew Dillon 			++hmp->objid_cache_count;
1990729c8c8SMatthew Dillon 			/* may have blocked, recheck */
2000729c8c8SMatthew Dillon 			if (dip->objid_cache == NULL) {
2010729c8c8SMatthew Dillon 				dip->objid_cache = ocp;
2020729c8c8SMatthew Dillon 				ocp->dip = dip;
2030729c8c8SMatthew Dillon 			}
2040729c8c8SMatthew Dillon 		} else {
2055a64efa1SMatthew Dillon 			/*
2065a64efa1SMatthew Dillon 			 * Steal one from another directory?
2075a64efa1SMatthew Dillon 			 *
2085a64efa1SMatthew Dillon 			 * Throw away ocp's that are more then half full, they
2095a64efa1SMatthew Dillon 			 * aren't worth stealing.
2105a64efa1SMatthew Dillon 			 */
2115de0c0e5SMatthew Dillon 			ocp = TAILQ_FIRST(&hmp->objid_cache_list);
2120729c8c8SMatthew Dillon 			if (ocp->dip)
2130729c8c8SMatthew Dillon 				ocp->dip->objid_cache = NULL;
2145a64efa1SMatthew Dillon 			if (ocp->count >= OBJID_CACHE_BULK / 2) {
2155a64efa1SMatthew Dillon 				--hmp->objid_cache_count;
2165a64efa1SMatthew Dillon 				kfree(ocp, hmp->m_misc);
2175a64efa1SMatthew Dillon 			} else {
2180729c8c8SMatthew Dillon 				dip->objid_cache = ocp;
2190729c8c8SMatthew Dillon 				ocp->dip = dip;
2200729c8c8SMatthew Dillon 			}
2210729c8c8SMatthew Dillon 		}
2225a64efa1SMatthew Dillon 	}
2235de0c0e5SMatthew Dillon 	TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
2245de0c0e5SMatthew Dillon 
2255de0c0e5SMatthew Dillon 	/*
2265a64efa1SMatthew Dillon 	 * Allocate a bit based on our namekey for the low bits of our
2275a64efa1SMatthew Dillon 	 * objid.
2285a64efa1SMatthew Dillon 	 */
2295a64efa1SMatthew Dillon 	incluster = (hmp->master_id >= 0);
2305a64efa1SMatthew Dillon 	n = (namekey >> (63 - OBJID_CACHE_BULK_BITS)) & OBJID_CACHE_BULK_MASK;
2315a64efa1SMatthew Dillon 	n = ocp_allocbit(ocp, n);
2325a64efa1SMatthew Dillon 	tid = ocp->base_tid + n;
2335a64efa1SMatthew Dillon 
2345a64efa1SMatthew Dillon #if 0
2355a64efa1SMatthew Dillon 	/*
2365de0c0e5SMatthew Dillon 	 * The TID is incremented by 1 or by 16 depending what mode the
2375de0c0e5SMatthew Dillon 	 * mount is operating in.
2385de0c0e5SMatthew Dillon 	 */
239732a1697SMatthew Dillon 	ocp->next_tid += (hmp->master_id < 0) ? 1 : HAMMER_MAX_MASTERS;
2405a64efa1SMatthew Dillon #endif
2415a64efa1SMatthew Dillon 	if (ocp->count >= OBJID_CACHE_BULK / 2) {
2420729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
2435de0c0e5SMatthew Dillon 		--hmp->objid_cache_count;
2440729c8c8SMatthew Dillon 		ocp->dip = NULL;
245bac808feSMatthew Dillon 		kfree(ocp, hmp->m_misc);
2460729c8c8SMatthew Dillon 	} else {
2475de0c0e5SMatthew Dillon 		TAILQ_INSERT_TAIL(&hmp->objid_cache_list, ocp, entry);
2480729c8c8SMatthew Dillon 	}
2490729c8c8SMatthew Dillon 	return(tid);
2500729c8c8SMatthew Dillon }
2510729c8c8SMatthew Dillon 
2525a64efa1SMatthew Dillon /*
2535a64efa1SMatthew Dillon  * Allocate a bit starting with bit n.  Wrap if necessary.
2545a64efa1SMatthew Dillon  *
2555a64efa1SMatthew Dillon  * This routine is only ever called if a bit is available somewhere
2565a64efa1SMatthew Dillon  * in the bitmap.
2575a64efa1SMatthew Dillon  */
2585a64efa1SMatthew Dillon static u_int32_t
2595a64efa1SMatthew Dillon ocp_allocbit(hammer_objid_cache_t ocp, u_int32_t n)
2605a64efa1SMatthew Dillon {
2615a64efa1SMatthew Dillon 	u_int32_t n0;
2625a64efa1SMatthew Dillon 
2635a64efa1SMatthew Dillon 	n0 = (n >> 5) & 31;
2645a64efa1SMatthew Dillon 	n &= 31;
2655a64efa1SMatthew Dillon 
2665a64efa1SMatthew Dillon 	while (ocp->bm1[n0] & (1 << n)) {
2675a64efa1SMatthew Dillon 		if (ocp->bm0 & (1 << n0)) {
2685a64efa1SMatthew Dillon 			n0 = (n0 + 1) & 31;
2695a64efa1SMatthew Dillon 			n = 0;
2705a64efa1SMatthew Dillon 		} else if (++n == 32) {
2715a64efa1SMatthew Dillon 			n0 = (n0 + 1) & 31;
2725a64efa1SMatthew Dillon 			n = 0;
2735a64efa1SMatthew Dillon 		}
2745a64efa1SMatthew Dillon 	}
2755a64efa1SMatthew Dillon 	++ocp->count;
2765a64efa1SMatthew Dillon 	ocp->bm1[n0] |= 1 << n;
2775a64efa1SMatthew Dillon 	if (ocp->bm1[n0] == 0xFFFFFFFFU)
2785a64efa1SMatthew Dillon 		ocp->bm0 |= 1 << n0;
2795a64efa1SMatthew Dillon 	return((n0 << 5) + n);
2805a64efa1SMatthew Dillon }
2815a64efa1SMatthew Dillon 
2820729c8c8SMatthew Dillon void
2830729c8c8SMatthew Dillon hammer_clear_objid(hammer_inode_t dip)
2840729c8c8SMatthew Dillon {
2850729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
2860729c8c8SMatthew Dillon 
2870729c8c8SMatthew Dillon 	if ((ocp = dip->objid_cache) != NULL) {
2880729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
2890729c8c8SMatthew Dillon 		ocp->dip = NULL;
2900729c8c8SMatthew Dillon 		TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry);
2910729c8c8SMatthew Dillon 		TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry);
2920729c8c8SMatthew Dillon 	}
2930729c8c8SMatthew Dillon }
2940729c8c8SMatthew Dillon 
2950729c8c8SMatthew Dillon void
2960729c8c8SMatthew Dillon hammer_destroy_objid_cache(hammer_mount_t hmp)
2970729c8c8SMatthew Dillon {
2980729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
2990729c8c8SMatthew Dillon 
3000729c8c8SMatthew Dillon 	while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) {
3010729c8c8SMatthew Dillon 		TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
302f437a2abSMatthew Dillon 		if (ocp->dip)
303f437a2abSMatthew Dillon 			ocp->dip->objid_cache = NULL;
304bac808feSMatthew Dillon 		kfree(ocp, hmp->m_misc);
3050729c8c8SMatthew Dillon 	}
3060729c8c8SMatthew Dillon }
3070729c8c8SMatthew Dillon 
308