xref: /onnv-gate/usr/src/uts/common/fs/ufs/lufs_top.c (revision 4662:9c48274ded8b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*4662Sfrankho  * Common Development and Distribution License (the "License").
6*4662Sfrankho  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*4662Sfrankho  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/systm.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/vnode.h>
310Sstevel@tonic-gate #include <sys/errno.h>
320Sstevel@tonic-gate #include <sys/sysmacros.h>
330Sstevel@tonic-gate #include <sys/debug.h>
340Sstevel@tonic-gate #include <sys/kmem.h>
350Sstevel@tonic-gate #include <sys/conf.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/taskq.h>
380Sstevel@tonic-gate #include <sys/cmn_err.h>
390Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
400Sstevel@tonic-gate #include <sys/fs/ufs_filio.h>
410Sstevel@tonic-gate #include <sys/fs/ufs_log.h>
420Sstevel@tonic-gate #include <sys/fs/ufs_bio.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * FILE SYSTEM INTERFACE TO TRANSACTION OPERATIONS (TOP; like VOP)
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate 
480Sstevel@tonic-gate uint_t topkey; /* tsd transaction key */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * declare a delta
520Sstevel@tonic-gate  */
530Sstevel@tonic-gate void
top_delta(ufsvfs_t * ufsvfsp,offset_t mof,off_t nb,delta_t dtyp,int (* func)(),ulong_t arg)540Sstevel@tonic-gate top_delta(
550Sstevel@tonic-gate 	ufsvfs_t *ufsvfsp,
560Sstevel@tonic-gate 	offset_t mof,
570Sstevel@tonic-gate 	off_t nb,
580Sstevel@tonic-gate 	delta_t dtyp,
590Sstevel@tonic-gate 	int (*func)(),
600Sstevel@tonic-gate 	ulong_t arg)
610Sstevel@tonic-gate {
620Sstevel@tonic-gate 	ml_unit_t		*ul	= ufsvfsp->vfs_log;
630Sstevel@tonic-gate 	threadtrans_t		*tp	= tsd_get(topkey);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
660Sstevel@tonic-gate 	ASSERT(nb);
670Sstevel@tonic-gate 	ASSERT(((ul->un_debug & (MT_TRANSACT|MT_MATAMAP)) == 0) ||
68*4662Sfrankho 	    top_delta_debug(ul, mof, nb, dtyp));
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	deltamap_add(ul->un_deltamap, mof, nb, dtyp, func, arg, tp);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	ul->un_logmap->mtm_ref = 1; /* for roll thread's heuristic */
730Sstevel@tonic-gate 	if (tp) {
740Sstevel@tonic-gate 		tp->any_deltas = 1;
750Sstevel@tonic-gate 	}
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * cancel a delta
800Sstevel@tonic-gate  */
810Sstevel@tonic-gate void
top_cancel(ufsvfs_t * ufsvfsp,offset_t mof,off_t nb,int flags)820Sstevel@tonic-gate top_cancel(ufsvfs_t *ufsvfsp, offset_t mof, off_t nb, int flags)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
850Sstevel@tonic-gate 	int		metadata = flags & (I_DIR|I_IBLK|I_SHAD|I_QUOTA);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
880Sstevel@tonic-gate 	ASSERT(nb);
890Sstevel@tonic-gate 	ASSERT(((ul->un_debug & (MT_TRANSACT|MT_MATAMAP)) == 0) ||
90*4662Sfrankho 	    (!(flags & metadata) ||
91*4662Sfrankho 	    top_delta_debug(ul, mof, nb, DT_CANCEL)));
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	if (metadata)
940Sstevel@tonic-gate 		deltamap_del(ul->un_deltamap, mof, nb);
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	logmap_cancel(ul, mof, nb, metadata);
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	/*
990Sstevel@tonic-gate 	 * needed for the roll thread's heuristic
1000Sstevel@tonic-gate 	 */
1010Sstevel@tonic-gate 	ul->un_logmap->mtm_ref = 1;
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * check if this delta has been canceled (metadata -> userdata)
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate int
top_iscancel(ufsvfs_t * ufsvfsp,offset_t mof,off_t nb)1080Sstevel@tonic-gate top_iscancel(ufsvfs_t *ufsvfsp, offset_t mof, off_t nb)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
1130Sstevel@tonic-gate 	ASSERT(nb);
1140Sstevel@tonic-gate 	if (logmap_iscancel(ul->un_logmap, mof, nb))
1150Sstevel@tonic-gate 		return (1);
1160Sstevel@tonic-gate 	if (ul->un_flags & LDL_ERROR)
1170Sstevel@tonic-gate 		return (1);
1180Sstevel@tonic-gate 	return (0);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * put device into error state
1230Sstevel@tonic-gate  */
1240Sstevel@tonic-gate void
top_seterror(ufsvfs_t * ufsvfsp)1250Sstevel@tonic-gate top_seterror(ufsvfs_t *ufsvfsp)
1260Sstevel@tonic-gate {
1270Sstevel@tonic-gate 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
1300Sstevel@tonic-gate 	ldl_seterror(ul, "ufs is forcing a ufs log error");
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /*
1340Sstevel@tonic-gate  * issue a empty sync op to help empty the delta/log map or the log
1350Sstevel@tonic-gate  */
1360Sstevel@tonic-gate static void
top_issue_sync(void * arg)1370Sstevel@tonic-gate top_issue_sync(void *arg)
1380Sstevel@tonic-gate {
1390Sstevel@tonic-gate 	ufsvfs_t *ufsvfsp = (ufsvfs_t *)arg;
1400Sstevel@tonic-gate 	ml_unit_t *ul = (ml_unit_t *)ufsvfsp->vfs_log;
1410Sstevel@tonic-gate 	mt_map_t *mtm = ul->un_logmap;
1420Sstevel@tonic-gate 	int	error = 0;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	if ((curthread->t_flag & T_DONTBLOCK) == 0)
1450Sstevel@tonic-gate 		curthread->t_flag |= T_DONTBLOCK;
1460Sstevel@tonic-gate 	top_begin_sync(ufsvfsp, TOP_COMMIT_ASYNC, 0, &error);
1470Sstevel@tonic-gate 	if (!error) {
1480Sstevel@tonic-gate 		top_end_sync(ufsvfsp, &error, TOP_COMMIT_ASYNC, 0);
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	/*
1520Sstevel@tonic-gate 	 * If we are a taskq thread, decrement mtm_taskq_sync_count and
1530Sstevel@tonic-gate 	 * wake up the thread waiting on the mtm_cv if the mtm_taskq_sync_count
1540Sstevel@tonic-gate 	 * hits zero.
1550Sstevel@tonic-gate 	 */
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	if (taskq_member(system_taskq, curthread)) {
1580Sstevel@tonic-gate 		mutex_enter(&mtm->mtm_lock);
1590Sstevel@tonic-gate 		mtm->mtm_taskq_sync_count--;
1600Sstevel@tonic-gate 		if (mtm->mtm_taskq_sync_count == 0) {
1610Sstevel@tonic-gate 			cv_signal(&mtm->mtm_cv);
1620Sstevel@tonic-gate 		}
1630Sstevel@tonic-gate 		mutex_exit(&mtm->mtm_lock);
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate  * MOBY TRANSACTION ROUTINES
1690Sstevel@tonic-gate  * begin a moby transaction
1700Sstevel@tonic-gate  *	sync ops enter until first sync op finishes
1710Sstevel@tonic-gate  *	async ops enter until last sync op finishes
1720Sstevel@tonic-gate  * end a moby transaction
1730Sstevel@tonic-gate  *		outstanding deltas are pushed thru log
1740Sstevel@tonic-gate  *		log buffer is committed (incore only)
1750Sstevel@tonic-gate  *		next trans is open to async ops
1760Sstevel@tonic-gate  *		log buffer is committed on the log
1770Sstevel@tonic-gate  *		next trans is open to sync ops
1780Sstevel@tonic-gate  */
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*ARGSUSED*/
1810Sstevel@tonic-gate void
top_begin_sync(ufsvfs_t * ufsvfsp,top_t topid,ulong_t size,int * error)1820Sstevel@tonic-gate top_begin_sync(ufsvfs_t *ufsvfsp, top_t topid, ulong_t size, int *error)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
1850Sstevel@tonic-gate 	mt_map_t	*mtm = ul->un_logmap;
1860Sstevel@tonic-gate 	threadtrans_t	*tp;
1870Sstevel@tonic-gate 	ushort_t	seq;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
1900Sstevel@tonic-gate 	ASSERT(error != NULL);
1910Sstevel@tonic-gate 	ASSERT(*error == 0);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	mutex_enter(&mtm->mtm_lock);
1940Sstevel@tonic-gate 	if (topid == TOP_FSYNC) {
1950Sstevel@tonic-gate 		/*
1960Sstevel@tonic-gate 		 * Error the fsync immediately if this is an nfs thread
1970Sstevel@tonic-gate 		 * and its last transaction has already been committed.
1980Sstevel@tonic-gate 		 * The only transactions outstanding are those
1990Sstevel@tonic-gate 		 * where no commit has even started
2000Sstevel@tonic-gate 		 * (last_async_tid == mtm->mtm_tid)
2010Sstevel@tonic-gate 		 * or those where a commit is in progress
2020Sstevel@tonic-gate 		 * (last_async_tid == mtm->mtm_committid)
2030Sstevel@tonic-gate 		 */
2040Sstevel@tonic-gate 		if (curthread->t_flag & T_DONTPEND) {
2050Sstevel@tonic-gate 			tp = tsd_get(topkey);
2060Sstevel@tonic-gate 			if (tp && (tp->last_async_tid != mtm->mtm_tid) &&
2070Sstevel@tonic-gate 			    (tp->last_async_tid != mtm->mtm_committid)) {
2080Sstevel@tonic-gate 				mutex_exit(&mtm->mtm_lock);
2090Sstevel@tonic-gate 				*error = 1;
2100Sstevel@tonic-gate 				return;
2110Sstevel@tonic-gate 			}
2120Sstevel@tonic-gate 		}
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 		/*
2150Sstevel@tonic-gate 		 * If there's already other synchronous transactions
2160Sstevel@tonic-gate 		 * and we haven't allowed async ones to start yet
2170Sstevel@tonic-gate 		 * then just wait for the commit to complete.
2180Sstevel@tonic-gate 		 */
2190Sstevel@tonic-gate 		if (((mtm->mtm_closed & (TOP_SYNC | TOP_ASYNC)) ==
2200Sstevel@tonic-gate 		    (TOP_SYNC | TOP_ASYNC)) || mtm->mtm_activesync) {
2210Sstevel@tonic-gate 			seq = mtm->mtm_seq;
2220Sstevel@tonic-gate 			do {
2230Sstevel@tonic-gate 				cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
2240Sstevel@tonic-gate 			} while (seq == mtm->mtm_seq);
2250Sstevel@tonic-gate 			mutex_exit(&mtm->mtm_lock);
2260Sstevel@tonic-gate 			*error = 1;
2270Sstevel@tonic-gate 			return;
2280Sstevel@tonic-gate 		}
2290Sstevel@tonic-gate 		if (mtm->mtm_closed & TOP_SYNC) {
2300Sstevel@tonic-gate 			/*
2310Sstevel@tonic-gate 			 * We know we're in the window where a thread is
2320Sstevel@tonic-gate 			 * committing a transaction in top_end_sync() and
2330Sstevel@tonic-gate 			 * has allowed async threads to start but hasn't
2340Sstevel@tonic-gate 			 * got the completion on the commit write to
2350Sstevel@tonic-gate 			 * allow sync threads to start.
2360Sstevel@tonic-gate 			 * So wait for that commit completion then retest
2370Sstevel@tonic-gate 			 * for the quick nfs check and if that fails
2380Sstevel@tonic-gate 			 * go on to start a transaction
2390Sstevel@tonic-gate 			 */
2400Sstevel@tonic-gate 			seq = mtm->mtm_seq;
2410Sstevel@tonic-gate 			do {
2420Sstevel@tonic-gate 				cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
2430Sstevel@tonic-gate 			} while (seq == mtm->mtm_seq);
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 			/* tp is set above if T_DONTPEND */
2460Sstevel@tonic-gate 			if ((curthread->t_flag & T_DONTPEND) && tp &&
2470Sstevel@tonic-gate 			    (tp->last_async_tid != mtm->mtm_tid) &&
2480Sstevel@tonic-gate 			    (tp->last_async_tid != mtm->mtm_committid)) {
2490Sstevel@tonic-gate 				mutex_exit(&mtm->mtm_lock);
2500Sstevel@tonic-gate 				*error = 1;
2510Sstevel@tonic-gate 				return;
2520Sstevel@tonic-gate 			}
2530Sstevel@tonic-gate 		}
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate retry:
2560Sstevel@tonic-gate 	mtm->mtm_ref = 1;
2570Sstevel@tonic-gate 	/*
2580Sstevel@tonic-gate 	 * current transaction closed to sync ops; try for next transaction
2590Sstevel@tonic-gate 	 */
2600Sstevel@tonic-gate 	if ((mtm->mtm_closed & TOP_SYNC) && !panicstr) {
2610Sstevel@tonic-gate 		ulong_t		resv;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		/*
2640Sstevel@tonic-gate 		 * We know a commit is in progress, if we are trying to
2650Sstevel@tonic-gate 		 * commit and we haven't allowed async ones to start yet,
2660Sstevel@tonic-gate 		 * then just wait for the commit completion
2670Sstevel@tonic-gate 		 */
2680Sstevel@tonic-gate 		if ((size == TOP_COMMIT_SIZE) &&
2690Sstevel@tonic-gate 		    (((mtm->mtm_closed & (TOP_SYNC | TOP_ASYNC)) ==
2700Sstevel@tonic-gate 		    (TOP_SYNC | TOP_ASYNC)) || (mtm->mtm_activesync))) {
2710Sstevel@tonic-gate 			seq = mtm->mtm_seq;
2720Sstevel@tonic-gate 			do {
2730Sstevel@tonic-gate 				cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
2740Sstevel@tonic-gate 			} while (seq == mtm->mtm_seq);
2750Sstevel@tonic-gate 			mutex_exit(&mtm->mtm_lock);
2760Sstevel@tonic-gate 			*error = 1;
2770Sstevel@tonic-gate 			return;
2780Sstevel@tonic-gate 		}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		/*
2810Sstevel@tonic-gate 		 * next transaction is full; try for next transaction
2820Sstevel@tonic-gate 		 */
2830Sstevel@tonic-gate 		resv = size + ul->un_resv_wantin + ul->un_resv;
2840Sstevel@tonic-gate 		if (resv > ul->un_maxresv) {
2850Sstevel@tonic-gate 			cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
2860Sstevel@tonic-gate 			goto retry;
2870Sstevel@tonic-gate 		}
2880Sstevel@tonic-gate 		/*
2890Sstevel@tonic-gate 		 * we are in the next transaction; wait for it to start
2900Sstevel@tonic-gate 		 */
2910Sstevel@tonic-gate 		mtm->mtm_wantin++;
2920Sstevel@tonic-gate 		ul->un_resv_wantin += size;
2930Sstevel@tonic-gate 		/*
2940Sstevel@tonic-gate 		 * The corresponding cv_broadcast wakes up
2950Sstevel@tonic-gate 		 * all threads that have been validated to go into
2960Sstevel@tonic-gate 		 * the next transaction. However, because spurious
2970Sstevel@tonic-gate 		 * cv_wait wakeups are possible we use a sequence
2980Sstevel@tonic-gate 		 * number to check that the commit and cv_broadcast
2990Sstevel@tonic-gate 		 * has really occurred. We couldn't use mtm_tid
3000Sstevel@tonic-gate 		 * because on error that doesn't get incremented.
3010Sstevel@tonic-gate 		 */
3020Sstevel@tonic-gate 		seq = mtm->mtm_seq;
3030Sstevel@tonic-gate 		do {
3040Sstevel@tonic-gate 			cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
3050Sstevel@tonic-gate 		} while (seq == mtm->mtm_seq);
3060Sstevel@tonic-gate 	} else {
3070Sstevel@tonic-gate 		/*
3080Sstevel@tonic-gate 		 * if the current transaction is full; try the next one
3090Sstevel@tonic-gate 		 */
3100Sstevel@tonic-gate 		if (size && (ul->un_resv && ((size + ul->un_resv) >
3110Sstevel@tonic-gate 		    ul->un_maxresv)) && !panicstr) {
3120Sstevel@tonic-gate 			/*
3130Sstevel@tonic-gate 			 * log is over reserved and no one will unresv the space
3140Sstevel@tonic-gate 			 *	so generate empty sync op to unresv the space
3150Sstevel@tonic-gate 			 */
3160Sstevel@tonic-gate 			if (mtm->mtm_activesync == 0) {
3170Sstevel@tonic-gate 				mutex_exit(&mtm->mtm_lock);
3180Sstevel@tonic-gate 				top_issue_sync(ufsvfsp);
3190Sstevel@tonic-gate 				mutex_enter(&mtm->mtm_lock);
3200Sstevel@tonic-gate 				goto retry;
3210Sstevel@tonic-gate 			}
3220Sstevel@tonic-gate 			cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
3230Sstevel@tonic-gate 			goto retry;
3240Sstevel@tonic-gate 		}
3250Sstevel@tonic-gate 		/*
3260Sstevel@tonic-gate 		 * we are in the current transaction
3270Sstevel@tonic-gate 		 */
3280Sstevel@tonic-gate 		mtm->mtm_active++;
3290Sstevel@tonic-gate 		mtm->mtm_activesync++;
3300Sstevel@tonic-gate 		ul->un_resv += size;
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	ASSERT(mtm->mtm_active > 0);
3340Sstevel@tonic-gate 	ASSERT(mtm->mtm_activesync > 0);
3350Sstevel@tonic-gate 	mutex_exit(&mtm->mtm_lock);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	ASSERT(((ul->un_debug & MT_TRANSACT) == 0) ||
338*4662Sfrankho 	    top_begin_debug(ul, topid, size));
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate int tryfail_cnt;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate int
top_begin_async(ufsvfs_t * ufsvfsp,top_t topid,ulong_t size,int tryasync)3440Sstevel@tonic-gate top_begin_async(ufsvfs_t *ufsvfsp, top_t topid, ulong_t size, int tryasync)
3450Sstevel@tonic-gate {
3460Sstevel@tonic-gate 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
3470Sstevel@tonic-gate 	mt_map_t	*mtm	= ul->un_logmap;
3480Sstevel@tonic-gate 	threadtrans_t   *tp;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	tp = tsd_get(topkey);
3530Sstevel@tonic-gate 	if (tp == NULL) {
3540Sstevel@tonic-gate 		tp = kmem_zalloc(sizeof (threadtrans_t), KM_SLEEP);
3550Sstevel@tonic-gate 		(void) tsd_set(topkey, tp);
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate 	tp->deltas_size = 0;
3580Sstevel@tonic-gate 	tp->any_deltas = 0;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	mutex_enter(&mtm->mtm_lock);
3610Sstevel@tonic-gate retry:
3620Sstevel@tonic-gate 	mtm->mtm_ref = 1;
3630Sstevel@tonic-gate 	/*
3640Sstevel@tonic-gate 	 * current transaction closed to async ops; try for next transaction
3650Sstevel@tonic-gate 	 */
3660Sstevel@tonic-gate 	if ((mtm->mtm_closed & TOP_ASYNC) && !panicstr) {
3670Sstevel@tonic-gate 		if (tryasync) {
3680Sstevel@tonic-gate 			mutex_exit(&mtm->mtm_lock);
3690Sstevel@tonic-gate 			tryfail_cnt++;
3700Sstevel@tonic-gate 			return (EWOULDBLOCK);
3710Sstevel@tonic-gate 		}
3720Sstevel@tonic-gate 		cv_wait(&mtm->mtm_cv_next, &mtm->mtm_lock);
3730Sstevel@tonic-gate 		goto retry;
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	/*
3770Sstevel@tonic-gate 	 * if the current transaction is full; try the next one
3780Sstevel@tonic-gate 	 */
3790Sstevel@tonic-gate 	if (((size + ul->un_resv + ul->un_resv_wantin) > ul->un_maxresv) &&
3800Sstevel@tonic-gate 	    !panicstr) {
3810Sstevel@tonic-gate 		/*
3820Sstevel@tonic-gate 		 * log is overreserved and no one will unresv the space
3830Sstevel@tonic-gate 		 *	so generate empty sync op to unresv the space
3840Sstevel@tonic-gate 		 * We need TOP_SYNC_FORCED because we want to know when
3850Sstevel@tonic-gate 		 * a top_end_sync is completed.
3860Sstevel@tonic-gate 		 * mtm_taskq_sync_count is needed because we want to keep track
3870Sstevel@tonic-gate 		 * of the pending top_issue_sync dispatches so that during
3880Sstevel@tonic-gate 		 * forced umount we can wait for these to complete.
3890Sstevel@tonic-gate 		 * mtm_taskq_sync_count is decremented in top_issue_sync and
3900Sstevel@tonic-gate 		 * can remain set even after top_end_sync completes.
3910Sstevel@tonic-gate 		 * We have a window between the clearing of TOP_SYNC_FORCED
3920Sstevel@tonic-gate 		 * flag and the decrementing of mtm_taskq_sync_count.
3930Sstevel@tonic-gate 		 * If in this window new async transactions start consuming
3940Sstevel@tonic-gate 		 * log space, the log can get overreserved.
3950Sstevel@tonic-gate 		 * Subsequently a new async transaction would fail to generate
3960Sstevel@tonic-gate 		 * an empty sync transaction via the taskq, since it finds
3970Sstevel@tonic-gate 		 * the mtm_taskq_sync_count set. This can cause a hang.
3980Sstevel@tonic-gate 		 * Hence we do not test for mtm_taskq_sync_count being zero.
3990Sstevel@tonic-gate 		 * Instead, the TOP_SYNC_FORCED flag is tested here.
4000Sstevel@tonic-gate 		 */
4010Sstevel@tonic-gate 		if ((mtm->mtm_activesync == 0) &&
4020Sstevel@tonic-gate 		    (!(mtm->mtm_closed & TOP_SYNC_FORCED))) {
4030Sstevel@tonic-gate 			/*
4040Sstevel@tonic-gate 			 * Set flag to stop multiple forced empty
4050Sstevel@tonic-gate 			 * sync transactions. Increment mtm_taskq_sync_count.
4060Sstevel@tonic-gate 			 */
4070Sstevel@tonic-gate 			mtm->mtm_closed |= TOP_SYNC_FORCED;
4080Sstevel@tonic-gate 			mtm->mtm_taskq_sync_count++;
4090Sstevel@tonic-gate 			mutex_exit(&mtm->mtm_lock);
4100Sstevel@tonic-gate 			(void) taskq_dispatch(system_taskq,
4110Sstevel@tonic-gate 			    top_issue_sync, ufsvfsp, TQ_SLEEP);
4120Sstevel@tonic-gate 			if (tryasync) {
4130Sstevel@tonic-gate 				tryfail_cnt++;
4140Sstevel@tonic-gate 				return (EWOULDBLOCK);
4150Sstevel@tonic-gate 			}
4160Sstevel@tonic-gate 			mutex_enter(&mtm->mtm_lock);
4170Sstevel@tonic-gate 			goto retry;
4180Sstevel@tonic-gate 		}
4190Sstevel@tonic-gate 		if (tryasync) {
4200Sstevel@tonic-gate 			mutex_exit(&mtm->mtm_lock);
4210Sstevel@tonic-gate 			tryfail_cnt++;
4220Sstevel@tonic-gate 			return (EWOULDBLOCK);
4230Sstevel@tonic-gate 		}
4240Sstevel@tonic-gate 		cv_wait(&mtm->mtm_cv_next, &mtm->mtm_lock);
4250Sstevel@tonic-gate 		goto retry;
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 	/*
4280Sstevel@tonic-gate 	 * we are in the current transaction
4290Sstevel@tonic-gate 	 */
4300Sstevel@tonic-gate 	mtm->mtm_active++;
4310Sstevel@tonic-gate 	ul->un_resv += size;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	ASSERT(mtm->mtm_active > 0);
4340Sstevel@tonic-gate 	mutex_exit(&mtm->mtm_lock);
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	ASSERT(((ul->un_debug & MT_TRANSACT) == 0) ||
437*4662Sfrankho 	    top_begin_debug(ul, topid, size));
4380Sstevel@tonic-gate 	return (0);
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate /*ARGSUSED*/
4420Sstevel@tonic-gate void
top_end_sync(ufsvfs_t * ufsvfsp,int * ep,top_t topid,ulong_t size)4430Sstevel@tonic-gate top_end_sync(ufsvfs_t *ufsvfsp, int *ep, top_t topid, ulong_t size)
4440Sstevel@tonic-gate {
4450Sstevel@tonic-gate 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
4460Sstevel@tonic-gate 	mt_map_t	*mtm	= ul->un_logmap;
4470Sstevel@tonic-gate 	mapentry_t	*cancellist;
4480Sstevel@tonic-gate 	uint32_t	tid;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
4510Sstevel@tonic-gate 	ASSERT(((ul->un_debug & MT_TRANSACT) == 0) ||
452*4662Sfrankho 	    top_end_debug(ul, mtm, topid, size));
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	mutex_enter(&mtm->mtm_lock);
4550Sstevel@tonic-gate 	tid = mtm->mtm_tid;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	mtm->mtm_activesync--;
4580Sstevel@tonic-gate 	mtm->mtm_active--;
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	mtm->mtm_ref = 1;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	/*
4630Sstevel@tonic-gate 	 * wait for last syncop to complete
4640Sstevel@tonic-gate 	 */
4650Sstevel@tonic-gate 	if (mtm->mtm_activesync || panicstr) {
4660Sstevel@tonic-gate 		ushort_t seq = mtm->mtm_seq;
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 		mtm->mtm_closed = TOP_SYNC;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 		do {
4710Sstevel@tonic-gate 			cv_wait(&mtm->mtm_cv_commit, &mtm->mtm_lock);
4720Sstevel@tonic-gate 		} while (seq == mtm->mtm_seq);
4730Sstevel@tonic-gate 		mutex_exit(&mtm->mtm_lock);
4740Sstevel@tonic-gate 		goto out;
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 	/*
4770Sstevel@tonic-gate 	 * last syncop; close current transaction to all ops
4780Sstevel@tonic-gate 	 */
4790Sstevel@tonic-gate 	mtm->mtm_closed = TOP_SYNC|TOP_ASYNC;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	/*
4820Sstevel@tonic-gate 	 * wait for last asyncop to finish
4830Sstevel@tonic-gate 	 */
4840Sstevel@tonic-gate 	while (mtm->mtm_active) {
4850Sstevel@tonic-gate 		cv_wait(&mtm->mtm_cv_eot, &mtm->mtm_lock);
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	/*
4890Sstevel@tonic-gate 	 * push dirty metadata thru the log
4900Sstevel@tonic-gate 	 */
4910Sstevel@tonic-gate 	deltamap_push(ul);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	ASSERT(((ul->un_debug & MT_FORCEROLL) == 0) ||
494*4662Sfrankho 	    top_roll_debug(ul));
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	mtm->mtm_tid = tid + 1;	/* can overflow to 0 */
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	/*
4990Sstevel@tonic-gate 	 * Empty the cancellist, but save it for logmap_free_cancel
5000Sstevel@tonic-gate 	 */
5010Sstevel@tonic-gate 	mutex_enter(&mtm->mtm_mutex);
5020Sstevel@tonic-gate 	cancellist = mtm->mtm_cancel;
5030Sstevel@tonic-gate 	mtm->mtm_cancel = NULL;
5040Sstevel@tonic-gate 	mutex_exit(&mtm->mtm_mutex);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	/*
5070Sstevel@tonic-gate 	 * allow async ops
5080Sstevel@tonic-gate 	 */
5090Sstevel@tonic-gate 	ASSERT(mtm->mtm_active == 0);
5100Sstevel@tonic-gate 	ul->un_resv = 0; /* unreserve the log space */
5110Sstevel@tonic-gate 	mtm->mtm_closed = TOP_SYNC;
5120Sstevel@tonic-gate 	/*
5130Sstevel@tonic-gate 	 * Hold the un_log_mutex here until we are done writing
5140Sstevel@tonic-gate 	 * the commit record to prevent any more deltas to be written
5150Sstevel@tonic-gate 	 * to the log after we allow async operations.
5160Sstevel@tonic-gate 	 */
5170Sstevel@tonic-gate 	mutex_enter(&ul->un_log_mutex);
5180Sstevel@tonic-gate 	mutex_exit(&mtm->mtm_lock);
5190Sstevel@tonic-gate 	cv_broadcast(&mtm->mtm_cv_next);
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	/*
5220Sstevel@tonic-gate 	 * asynchronously write the commit record,
5230Sstevel@tonic-gate 	 */
5240Sstevel@tonic-gate 	logmap_commit(ul, tid);
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	/*
5270Sstevel@tonic-gate 	 * wait for outstanding log writes (e.g., commits) to finish
5280Sstevel@tonic-gate 	 */
5290Sstevel@tonic-gate 	ldl_waito(ul);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	/*
5320Sstevel@tonic-gate 	 * Now that we are sure the commit has been written to the log
5330Sstevel@tonic-gate 	 * we can free any canceled deltas.  If we free them before
5340Sstevel@tonic-gate 	 * guaranteeing that the commit was written, we could panic before
5350Sstevel@tonic-gate 	 * the commit, but after an async thread has allocated and written
5360Sstevel@tonic-gate 	 * to canceled freed block.
5370Sstevel@tonic-gate 	 */
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	logmap_free_cancel(mtm, &cancellist);
5400Sstevel@tonic-gate 	mutex_exit(&ul->un_log_mutex);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	/*
5430Sstevel@tonic-gate 	 * now, allow all ops
5440Sstevel@tonic-gate 	 */
5450Sstevel@tonic-gate 	mutex_enter(&mtm->mtm_lock);
5460Sstevel@tonic-gate 	mtm->mtm_active += mtm->mtm_wantin;
5470Sstevel@tonic-gate 	ul->un_resv += ul->un_resv_wantin;
5480Sstevel@tonic-gate 	mtm->mtm_activesync = mtm->mtm_wantin;
5490Sstevel@tonic-gate 	mtm->mtm_wantin = 0;
5500Sstevel@tonic-gate 	mtm->mtm_closed = 0;
5510Sstevel@tonic-gate 	ul->un_resv_wantin = 0;
5520Sstevel@tonic-gate 	mtm->mtm_committid = mtm->mtm_tid;
5530Sstevel@tonic-gate 	mtm->mtm_seq++;
5540Sstevel@tonic-gate 	mutex_exit(&mtm->mtm_lock);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	/*
5570Sstevel@tonic-gate 	 * Finish any other synchronous transactions and
5580Sstevel@tonic-gate 	 * start any waiting new synchronous transactions
5590Sstevel@tonic-gate 	 */
5600Sstevel@tonic-gate 	cv_broadcast(&mtm->mtm_cv_commit);
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	/*
5630Sstevel@tonic-gate 	 * if the logmap is getting full; roll something
5640Sstevel@tonic-gate 	 */
5650Sstevel@tonic-gate 	if (logmap_need_roll_sync(mtm)) {
5660Sstevel@tonic-gate 		logmap_forceroll_nowait(mtm);
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate out:
5700Sstevel@tonic-gate 	if (ul->un_flags & LDL_ERROR)
5710Sstevel@tonic-gate 		*ep = EIO;
5720Sstevel@tonic-gate }
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate /*ARGSUSED*/
5750Sstevel@tonic-gate void
top_end_async(ufsvfs_t * ufsvfsp,top_t topid,ulong_t size)5760Sstevel@tonic-gate top_end_async(ufsvfs_t *ufsvfsp, top_t topid, ulong_t size)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate 	ml_unit_t	*ul	= ufsvfsp->vfs_log;
5790Sstevel@tonic-gate 	mt_map_t	*mtm	= ul->un_logmap;
5800Sstevel@tonic-gate 	threadtrans_t	*tp	= tsd_get(topkey);
5810Sstevel@tonic-gate 	int		wakeup_needed = 0;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	ASSERT(tp);
5840Sstevel@tonic-gate 	ASSERT(ufsvfsp->vfs_dev == ul->un_dev);
5850Sstevel@tonic-gate 	ASSERT(((ul->un_debug & MT_TRANSACT) == 0) ||
586*4662Sfrankho 	    top_end_debug(ul, mtm, topid, size));
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	mutex_enter(&mtm->mtm_lock);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	if (size > tp->deltas_size) {
5910Sstevel@tonic-gate 		ul->un_resv -= (size - tp->deltas_size);
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 	if (tp->any_deltas) {
5940Sstevel@tonic-gate 		tp->last_async_tid = mtm->mtm_tid;
5950Sstevel@tonic-gate 	}
5960Sstevel@tonic-gate 	mtm->mtm_ref = 1;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	mtm->mtm_active--;
5990Sstevel@tonic-gate 	if ((mtm->mtm_active == 0) &&
6000Sstevel@tonic-gate 	    (mtm->mtm_closed == (TOP_SYNC|TOP_ASYNC))) {
6010Sstevel@tonic-gate 		wakeup_needed = 1;
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 	mutex_exit(&mtm->mtm_lock);
6040Sstevel@tonic-gate 	if (wakeup_needed)
6050Sstevel@tonic-gate 		cv_signal(&mtm->mtm_cv_eot);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	/*
6080Sstevel@tonic-gate 	 * Generate a sync op if the log, logmap, or deltamap are heavily used.
6090Sstevel@tonic-gate 	 * Unless we are possibly holding any VM locks, since if we are holding
6100Sstevel@tonic-gate 	 * any VM locks and we issue a top_end_sync(), we could deadlock.
6110Sstevel@tonic-gate 	 */
6120Sstevel@tonic-gate 	if ((mtm->mtm_activesync == 0) &&
6130Sstevel@tonic-gate 	    !(mtm->mtm_closed & TOP_SYNC) &&
6140Sstevel@tonic-gate 	    (deltamap_need_commit(ul->un_deltamap) ||
6150Sstevel@tonic-gate 	    logmap_need_commit(mtm) ||
6160Sstevel@tonic-gate 	    ldl_need_commit(ul)) &&
6170Sstevel@tonic-gate 	    (topid != TOP_GETPAGE)) {
6180Sstevel@tonic-gate 		top_issue_sync(ufsvfsp);
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 	/*
6210Sstevel@tonic-gate 	 * roll something from the log if the logmap is too full
6220Sstevel@tonic-gate 	 */
6230Sstevel@tonic-gate 	if (logmap_need_roll_async(mtm))
6240Sstevel@tonic-gate 		logmap_forceroll_nowait(mtm);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate /*
6280Sstevel@tonic-gate  * Called from roll thread;
6290Sstevel@tonic-gate  *	buffer set for reading master
6300Sstevel@tonic-gate  * Returns
6310Sstevel@tonic-gate  *	0 - success, can continue with next buffer
6320Sstevel@tonic-gate  *	1 - failure due to logmap deltas being in use
6330Sstevel@tonic-gate  */
6340Sstevel@tonic-gate int
top_read_roll(rollbuf_t * rbp,ml_unit_t * ul)6350Sstevel@tonic-gate top_read_roll(rollbuf_t *rbp, ml_unit_t *ul)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate 	buf_t		*bp	= &rbp->rb_bh;
6380Sstevel@tonic-gate 	offset_t	mof	= ldbtob(bp->b_blkno);
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	/*
6410Sstevel@tonic-gate 	 * get a list of deltas
6420Sstevel@tonic-gate 	 */
6430Sstevel@tonic-gate 	if (logmap_list_get_roll(ul->un_logmap, mof, rbp)) {
6440Sstevel@tonic-gate 		/* logmap deltas are in use */
6450Sstevel@tonic-gate 		return (1);
6460Sstevel@tonic-gate 	}
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	/*
6490Sstevel@tonic-gate 	 * no deltas were found, nothing to roll
6500Sstevel@tonic-gate 	 */
6510Sstevel@tonic-gate 	if (rbp->rb_age == NULL) {
6520Sstevel@tonic-gate 		bp->b_flags |= B_INVAL;
6530Sstevel@tonic-gate 		return (0);
6540Sstevel@tonic-gate 	}
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	/*
6570Sstevel@tonic-gate 	 * If there is one cached roll buffer that cover all the deltas then
6580Sstevel@tonic-gate 	 * we can use that instead of copying to a separate roll buffer.
6590Sstevel@tonic-gate 	 */
6600Sstevel@tonic-gate 	if (rbp->rb_crb) {
6610Sstevel@tonic-gate 		rbp->rb_bh.b_blkno = lbtodb(rbp->rb_crb->c_mof);
6620Sstevel@tonic-gate 		return (0);
6630Sstevel@tonic-gate 	}
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	/*
6660Sstevel@tonic-gate 	 * Set up the read.
6670Sstevel@tonic-gate 	 * If no read is needed logmap_setup_read() returns 0.
6680Sstevel@tonic-gate 	 */
6690Sstevel@tonic-gate 	if (logmap_setup_read(rbp->rb_age, rbp)) {
6700Sstevel@tonic-gate 		/*
6710Sstevel@tonic-gate 		 * async read the data from master
6720Sstevel@tonic-gate 		 */
6730Sstevel@tonic-gate 		logstats.ls_rreads.value.ui64++;
6740Sstevel@tonic-gate 		bp->b_bcount = MAPBLOCKSIZE;
6750Sstevel@tonic-gate 		(void) bdev_strategy(bp);
6760Sstevel@tonic-gate 		lwp_stat_update(LWP_STAT_INBLK, 1);
6770Sstevel@tonic-gate 	} else {
6780Sstevel@tonic-gate 		sema_v(&bp->b_io); /* mark read as complete */
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate 	return (0);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate int ufs_crb_enable = 1;
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate /*
6860Sstevel@tonic-gate  * move deltas from deltamap into the log
6870Sstevel@tonic-gate  */
6880Sstevel@tonic-gate void
top_log(ufsvfs_t * ufsvfsp,char * va,offset_t vamof,off_t nb,caddr_t buf,uint32_t bufsz)6890Sstevel@tonic-gate top_log(ufsvfs_t *ufsvfsp, char *va, offset_t vamof, off_t nb,
6900Sstevel@tonic-gate     caddr_t buf, uint32_t bufsz)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate 	ml_unit_t	*ul = ufsvfsp->vfs_log;
6930Sstevel@tonic-gate 	mapentry_t	*me;
6940Sstevel@tonic-gate 	offset_t	hmof;
6950Sstevel@tonic-gate 	uint32_t	hnb, nb1;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	/*
6980Sstevel@tonic-gate 	 * needed for the roll thread's heuristic
6990Sstevel@tonic-gate 	 */
7000Sstevel@tonic-gate 	ul->un_logmap->mtm_ref = 1;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	if (buf && ufs_crb_enable) {
7030Sstevel@tonic-gate 		ASSERT((bufsz & DEV_BMASK) == 0);
7040Sstevel@tonic-gate 		/*
7050Sstevel@tonic-gate 		 * Move any deltas to the logmap. Split requests that
7060Sstevel@tonic-gate 		 * straddle MAPBLOCKSIZE hash boundaries (i.e. summary info).
7070Sstevel@tonic-gate 		 */
7080Sstevel@tonic-gate 		for (hmof = vamof - (va - buf), nb1 = nb; bufsz;
7090Sstevel@tonic-gate 		    bufsz -= hnb, hmof += hnb, buf += hnb, nb1 -= hnb) {
7100Sstevel@tonic-gate 			hnb = MAPBLOCKSIZE - (hmof & MAPBLOCKOFF);
7110Sstevel@tonic-gate 			if (hnb > bufsz)
7120Sstevel@tonic-gate 				hnb = bufsz;
7130Sstevel@tonic-gate 			me = deltamap_remove(ul->un_deltamap,
7140Sstevel@tonic-gate 			    MAX(hmof, vamof), MIN(hnb, nb1));
7150Sstevel@tonic-gate 			if (me) {
7160Sstevel@tonic-gate 				logmap_add_buf(ul, va, hmof, me, buf, hnb);
7170Sstevel@tonic-gate 			}
7180Sstevel@tonic-gate 		}
7190Sstevel@tonic-gate 	} else {
7200Sstevel@tonic-gate 		/*
7210Sstevel@tonic-gate 		 * if there are deltas
7220Sstevel@tonic-gate 		 */
7230Sstevel@tonic-gate 		me = deltamap_remove(ul->un_deltamap, vamof, nb);
7240Sstevel@tonic-gate 		if (me) {
7250Sstevel@tonic-gate 			/*
7260Sstevel@tonic-gate 			 * move to logmap
7270Sstevel@tonic-gate 			 */
7280Sstevel@tonic-gate 			logmap_add(ul, va, vamof, me);
7290Sstevel@tonic-gate 		}
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	ASSERT((ul->un_matamap == NULL) ||
733*4662Sfrankho 	    matamap_within(ul->un_matamap, vamof, nb));
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate static void
top_threadtrans_destroy(void * tp)7380Sstevel@tonic-gate top_threadtrans_destroy(void *tp)
7390Sstevel@tonic-gate {
7400Sstevel@tonic-gate 	kmem_free(tp, sizeof (threadtrans_t));
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate void
_init_top(void)7440Sstevel@tonic-gate _init_top(void)
7450Sstevel@tonic-gate {
7460Sstevel@tonic-gate 	ASSERT(top_init_debug());
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	/*
7490Sstevel@tonic-gate 	 * set up the delta layer
7500Sstevel@tonic-gate 	 */
7510Sstevel@tonic-gate 	_init_map();
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	/*
7540Sstevel@tonic-gate 	 * Initialise the thread specific data transaction key
7550Sstevel@tonic-gate 	 */
7560Sstevel@tonic-gate 	tsd_create(&topkey, top_threadtrans_destroy);
7570Sstevel@tonic-gate }
758