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*21fde338SMatthew 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 
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;
58*21fde338SMatthew 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;
81*21fde338SMatthew 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;
111*21fde338SMatthew 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;
128*21fde338SMatthew Dillon 	if (trans->flags & HAMMER_TRANSF_NEWINODE)
129*21fde338SMatthew Dillon 		hammer_inode_waitreclaims(trans->hmp);
13066325755SMatthew Dillon }
13166325755SMatthew Dillon 
132d113fda1SMatthew Dillon /*
1335de0c0e5SMatthew Dillon  * Allocate (count) TIDs.  If running in multi-master mode the returned
1345de0c0e5SMatthew Dillon  * base will be aligned to a 16-count plus the master id (0-15).
1355de0c0e5SMatthew Dillon  * Multi-master mode allows non-conflicting to run and new objects to be
1365de0c0e5SMatthew Dillon  * created on multiple masters in parallel.  The transaction id identifies
1375de0c0e5SMatthew Dillon  * the original master.  The object_id is also subject to this rule in
1385de0c0e5SMatthew Dillon  * order to allow objects to be created on multiple masters in parallel.
1395de0c0e5SMatthew Dillon  *
1405de0c0e5SMatthew Dillon  * Directories may pre-allocate a large number of object ids (100,000).
1415de0c0e5SMatthew Dillon  *
1425de0c0e5SMatthew Dillon  * NOTE: There is no longer a requirement that successive transaction
1435de0c0e5SMatthew Dillon  * ids be 2 apart for separator generation.
144d113fda1SMatthew Dillon  */
1450729c8c8SMatthew Dillon static hammer_tid_t
1465de0c0e5SMatthew Dillon hammer_alloc_tid(hammer_mount_t hmp, int count)
147a89aec1bSMatthew Dillon {
148a89aec1bSMatthew Dillon 	hammer_tid_t tid;
149a89aec1bSMatthew Dillon 
150732a1697SMatthew Dillon 	if (hmp->master_id < 0) {
151c82af904SMatthew Dillon 		tid = hmp->next_tid + 1;
152c82af904SMatthew Dillon 		hmp->next_tid = tid + count;
153c82af904SMatthew Dillon 	} else {
154c82af904SMatthew Dillon 		tid = (hmp->next_tid + HAMMER_MAX_MASTERS) &
155c82af904SMatthew Dillon 		      ~(hammer_tid_t)(HAMMER_MAX_MASTERS - 1);
156c82af904SMatthew Dillon 		hmp->next_tid = tid + count * HAMMER_MAX_MASTERS;
157732a1697SMatthew Dillon 		tid |= hmp->master_id;
158c82af904SMatthew Dillon 	}
159c82af904SMatthew Dillon 	if (tid >= 0xFFFFFFFFFF000000ULL)
160a89aec1bSMatthew Dillon 		panic("hammer_start_transaction: Ran out of TIDs!");
1615de0c0e5SMatthew Dillon 	if (hammer_debug_tid)
1625de0c0e5SMatthew Dillon 		kprintf("alloc_tid %016llx\n", tid);
163a89aec1bSMatthew Dillon 	return(tid);
164a89aec1bSMatthew Dillon }
165a89aec1bSMatthew Dillon 
1660729c8c8SMatthew Dillon /*
1670729c8c8SMatthew Dillon  * Allocate an object id
1680729c8c8SMatthew Dillon  */
1690729c8c8SMatthew Dillon hammer_tid_t
1705de0c0e5SMatthew Dillon hammer_alloc_objid(hammer_mount_t hmp, hammer_inode_t dip)
1710729c8c8SMatthew Dillon {
1720729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
1730729c8c8SMatthew Dillon 	hammer_tid_t tid;
1740729c8c8SMatthew Dillon 
1750729c8c8SMatthew Dillon 	while ((ocp = dip->objid_cache) == NULL) {
1765de0c0e5SMatthew Dillon 		if (hmp->objid_cache_count < OBJID_CACHE_SIZE) {
1770729c8c8SMatthew Dillon 			ocp = kmalloc(sizeof(*ocp), M_HAMMER, M_WAITOK|M_ZERO);
1785de0c0e5SMatthew Dillon 			ocp->next_tid = hammer_alloc_tid(hmp, OBJID_CACHE_BULK);
1790729c8c8SMatthew Dillon 			ocp->count = OBJID_CACHE_BULK;
1805de0c0e5SMatthew Dillon 			TAILQ_INSERT_HEAD(&hmp->objid_cache_list, ocp, entry);
1815de0c0e5SMatthew Dillon 			++hmp->objid_cache_count;
1820729c8c8SMatthew Dillon 			/* may have blocked, recheck */
1830729c8c8SMatthew Dillon 			if (dip->objid_cache == NULL) {
1840729c8c8SMatthew Dillon 				dip->objid_cache = ocp;
1850729c8c8SMatthew Dillon 				ocp->dip = dip;
1860729c8c8SMatthew Dillon 			}
1870729c8c8SMatthew Dillon 		} else {
1885de0c0e5SMatthew Dillon 			ocp = TAILQ_FIRST(&hmp->objid_cache_list);
1890729c8c8SMatthew Dillon 			if (ocp->dip)
1900729c8c8SMatthew Dillon 				ocp->dip->objid_cache = NULL;
1910729c8c8SMatthew Dillon 			dip->objid_cache = ocp;
1920729c8c8SMatthew Dillon 			ocp->dip = dip;
1930729c8c8SMatthew Dillon 		}
1940729c8c8SMatthew Dillon 	}
1955de0c0e5SMatthew Dillon 	TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
1965de0c0e5SMatthew Dillon 
1975de0c0e5SMatthew Dillon 	/*
1985de0c0e5SMatthew Dillon 	 * The TID is incremented by 1 or by 16 depending what mode the
1995de0c0e5SMatthew Dillon 	 * mount is operating in.
2005de0c0e5SMatthew Dillon 	 */
2010729c8c8SMatthew Dillon 	tid = ocp->next_tid;
202732a1697SMatthew Dillon 	ocp->next_tid += (hmp->master_id < 0) ? 1 : HAMMER_MAX_MASTERS;
2035de0c0e5SMatthew Dillon 
2040729c8c8SMatthew Dillon 	if (--ocp->count == 0) {
2050729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
2065de0c0e5SMatthew Dillon 		--hmp->objid_cache_count;
2070729c8c8SMatthew Dillon 		ocp->dip = NULL;
2080729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
2090729c8c8SMatthew Dillon 	} else {
2105de0c0e5SMatthew Dillon 		TAILQ_INSERT_TAIL(&hmp->objid_cache_list, ocp, entry);
2110729c8c8SMatthew Dillon 	}
2120729c8c8SMatthew Dillon 	return(tid);
2130729c8c8SMatthew Dillon }
2140729c8c8SMatthew Dillon 
2150729c8c8SMatthew Dillon void
2160729c8c8SMatthew Dillon hammer_clear_objid(hammer_inode_t dip)
2170729c8c8SMatthew Dillon {
2180729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
2190729c8c8SMatthew Dillon 
2200729c8c8SMatthew Dillon 	if ((ocp = dip->objid_cache) != NULL) {
2210729c8c8SMatthew Dillon 		dip->objid_cache = NULL;
2220729c8c8SMatthew Dillon 		ocp->dip = NULL;
2230729c8c8SMatthew Dillon 		TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry);
2240729c8c8SMatthew Dillon 		TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry);
2250729c8c8SMatthew Dillon 	}
2260729c8c8SMatthew Dillon }
2270729c8c8SMatthew Dillon 
2280729c8c8SMatthew Dillon void
2290729c8c8SMatthew Dillon hammer_destroy_objid_cache(hammer_mount_t hmp)
2300729c8c8SMatthew Dillon {
2310729c8c8SMatthew Dillon 	hammer_objid_cache_t ocp;
2320729c8c8SMatthew Dillon 
2330729c8c8SMatthew Dillon 	while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) {
2340729c8c8SMatthew Dillon 		TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
235f437a2abSMatthew Dillon 		if (ocp->dip)
236f437a2abSMatthew Dillon 			ocp->dip->objid_cache = NULL;
2370729c8c8SMatthew Dillon 		kfree(ocp, M_HAMMER);
2380729c8c8SMatthew Dillon 	}
2390729c8c8SMatthew Dillon }
2400729c8c8SMatthew Dillon 
241