xref: /illumos-gate/usr/src/uts/common/fs/fdbuffer.c (revision b94c9724)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright (c) 1998,2001 by Sun Microsystems, Inc.
247c478bd9Sstevel@tonic-gate  * All rights reserved.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
307c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
317c478bd9Sstevel@tonic-gate #include <sys/systm.h>
327c478bd9Sstevel@tonic-gate #include <sys/debug.h>
337c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <sys/fdbuffer.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #ifdef DEBUG
387c478bd9Sstevel@tonic-gate static int fdb_debug;
397c478bd9Sstevel@tonic-gate #define	FDB_D_CREATE	001
407c478bd9Sstevel@tonic-gate #define	FDB_D_ALLOC	002
417c478bd9Sstevel@tonic-gate #define	FDB_D_IO	004
427c478bd9Sstevel@tonic-gate #define	FDB_D_ASYNC	010
437c478bd9Sstevel@tonic-gate #define	DEBUGF(lvl, args)	{ if ((lvl) & fdb_debug) cmn_err args; }
447c478bd9Sstevel@tonic-gate #else
457c478bd9Sstevel@tonic-gate #define	DEBUGF(level, args)
467c478bd9Sstevel@tonic-gate #endif
477c478bd9Sstevel@tonic-gate static struct kmem_cache *fdb_cache;
487c478bd9Sstevel@tonic-gate static void fdb_zero_holes(fdbuffer_t *fdb);
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /* ARGSUSED */
517c478bd9Sstevel@tonic-gate static int
fdb_cache_constructor(void * buf,void * cdrarg,int kmflags)527c478bd9Sstevel@tonic-gate fdb_cache_constructor(void *buf, void *cdrarg, int kmflags)
537c478bd9Sstevel@tonic-gate {
547c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb = buf;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	mutex_init(&fdb->fd_mutex, NULL, MUTEX_DEFAULT, NULL);
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	return (0);
597c478bd9Sstevel@tonic-gate }
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /* ARGSUSED */
627c478bd9Sstevel@tonic-gate static void
fdb_cache_destructor(void * buf,void * cdrarg)637c478bd9Sstevel@tonic-gate fdb_cache_destructor(void *buf, void *cdrarg)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb = buf;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	mutex_destroy(&fdb->fd_mutex);
687c478bd9Sstevel@tonic-gate }
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate void
fdb_init()717c478bd9Sstevel@tonic-gate fdb_init()
727c478bd9Sstevel@tonic-gate {
737c478bd9Sstevel@tonic-gate 	fdb_cache = kmem_cache_create("fdb_cache", sizeof (fdbuffer_t),
747c478bd9Sstevel@tonic-gate 	    0, fdb_cache_constructor, fdb_cache_destructor,
757c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL, 0);
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static void
fdb_prepare(fdbuffer_t * fdb)797c478bd9Sstevel@tonic-gate fdb_prepare(fdbuffer_t *fdb)
807c478bd9Sstevel@tonic-gate {
817c478bd9Sstevel@tonic-gate 	fdb->fd_holes = NULL;
827c478bd9Sstevel@tonic-gate 	fdb->fd_iofunc = NULL;
837c478bd9Sstevel@tonic-gate 	fdb->fd_iargp = NULL;
847c478bd9Sstevel@tonic-gate 	fdb->fd_parentbp = NULL;
857c478bd9Sstevel@tonic-gate 	fdb->fd_resid = 0;
867c478bd9Sstevel@tonic-gate 	fdb->fd_iocount = 0;
877c478bd9Sstevel@tonic-gate 	fdb->fd_iodispatch = 0;
887c478bd9Sstevel@tonic-gate 	fdb->fd_err = 0;
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate fdbuffer_t *
fdb_page_create(page_t * pp,size_t len,int flags)927c478bd9Sstevel@tonic-gate fdb_page_create(page_t *pp, size_t len, int flags)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_CREATE, (CE_NOTE,
977c478bd9Sstevel@tonic-gate 	    "?fdb_page_create: pp: %p len: %lux flags: %x",
987c478bd9Sstevel@tonic-gate 	    (void *)pp, len, flags));
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	ASSERT(flags & (FDB_READ|FDB_WRITE));
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	fdb = kmem_cache_alloc(fdb_cache, KM_SLEEP);
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	fdb_prepare(fdb);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	fdb->fd_type = FDB_PAGEIO;
1077c478bd9Sstevel@tonic-gate 	fdb->fd_len = len;
1087c478bd9Sstevel@tonic-gate 	fdb->fd_state = flags;
1097c478bd9Sstevel@tonic-gate 	fdb->fd_pages = pp;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	return (fdb);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate fdbuffer_t *
fdb_addr_create(caddr_t addr,size_t len,int flags,page_t ** pplist,struct proc * procp)1157c478bd9Sstevel@tonic-gate fdb_addr_create(
1167c478bd9Sstevel@tonic-gate 	caddr_t addr,
1177c478bd9Sstevel@tonic-gate 	size_t len,
1187c478bd9Sstevel@tonic-gate 	int flags,
1197c478bd9Sstevel@tonic-gate 	page_t **pplist,
1207c478bd9Sstevel@tonic-gate 	struct proc *procp)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_CREATE, (CE_NOTE,
1257c478bd9Sstevel@tonic-gate 	    "?fdb_addr_create: addr: %p len: %lux flags: %x",
1267c478bd9Sstevel@tonic-gate 	    (void *)addr, len, flags));
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	ASSERT(flags & (FDB_READ|FDB_WRITE));
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	fdb = kmem_cache_alloc(fdb_cache, KM_SLEEP);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	fdb_prepare(fdb);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	fdb->fd_type = FDB_VADDR;
1357c478bd9Sstevel@tonic-gate 	fdb->fd_len = len;
1367c478bd9Sstevel@tonic-gate 	fdb->fd_state = flags;
1377c478bd9Sstevel@tonic-gate 	fdb->fd_addr = addr;
1387c478bd9Sstevel@tonic-gate 	fdb->fd_shadow = pplist;
1397c478bd9Sstevel@tonic-gate 	fdb->fd_procp = procp;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	return (fdb);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate void
fdb_set_iofunc(fdbuffer_t * fdb,fdb_iodone_t iofunc,void * ioargp,int flag)1457c478bd9Sstevel@tonic-gate fdb_set_iofunc(fdbuffer_t *fdb, fdb_iodone_t iofunc, void *ioargp, int flag)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
1487c478bd9Sstevel@tonic-gate 	ASSERT(iofunc);
1497c478bd9Sstevel@tonic-gate 	ASSERT((flag & ~FDB_ICALLBACK) == 0);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	fdb->fd_iofunc = iofunc;
1527c478bd9Sstevel@tonic-gate 	fdb->fd_iargp = ioargp;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	if (flag & FDB_ICALLBACK)
1577c478bd9Sstevel@tonic-gate 		fdb->fd_state |= FDB_ICALLBACK;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	fdb->fd_state |= FDB_ASYNC;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	mutex_exit(&fdb->fd_mutex);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate int
fdb_get_error(fdbuffer_t * fdb)1657c478bd9Sstevel@tonic-gate fdb_get_error(fdbuffer_t *fdb)
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate 	return (fdb->fd_err);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate void
fdb_free(fdbuffer_t * fdb)1717c478bd9Sstevel@tonic-gate fdb_free(fdbuffer_t *fdb)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	fdb_holes_t *fdh, *fdhp;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_CREATE, (CE_NOTE, "?fdb_free: addr: %p flags: %x",
1767c478bd9Sstevel@tonic-gate 	    (void *)fdb, fdb->fd_state));
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
1797c478bd9Sstevel@tonic-gate 	ASSERT(fdb->fd_iodispatch == 0);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (fdb->fd_state & FDB_ZEROHOLE) {
1827c478bd9Sstevel@tonic-gate 		fdb_zero_holes(fdb);
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	for (fdh = fdb->fd_holes; fdh; ) {
1867c478bd9Sstevel@tonic-gate 		fdhp = fdh;
1877c478bd9Sstevel@tonic-gate 		fdh = fdh->next_hole;
1887c478bd9Sstevel@tonic-gate 		kmem_free(fdhp, sizeof (fdb_holes_t));
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if (fdb->fd_parentbp != NULL) {
1927c478bd9Sstevel@tonic-gate 		switch (fdb->fd_type) {
1937c478bd9Sstevel@tonic-gate 		case FDB_PAGEIO:
1947c478bd9Sstevel@tonic-gate 			pageio_done(fdb->fd_parentbp);
1957c478bd9Sstevel@tonic-gate 			break;
1967c478bd9Sstevel@tonic-gate 		case FDB_VADDR:
1977c478bd9Sstevel@tonic-gate 			kmem_free(fdb->fd_parentbp, sizeof (struct buf));
1987c478bd9Sstevel@tonic-gate 			break;
1997c478bd9Sstevel@tonic-gate 		default:
2007c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "?fdb_free: Unknown fdb type.");
2017c478bd9Sstevel@tonic-gate 			break;
2027c478bd9Sstevel@tonic-gate 		}
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	kmem_cache_free(fdb_cache, fdb);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate  * The offset should be from the begining of the buffer
2117c478bd9Sstevel@tonic-gate  * it has nothing to do with file offset. This fact should be
2127c478bd9Sstevel@tonic-gate  * reflected in the caller of this routine.
2137c478bd9Sstevel@tonic-gate  */
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate void
fdb_add_hole(fdbuffer_t * fdb,u_offset_t off,size_t len)2167c478bd9Sstevel@tonic-gate fdb_add_hole(fdbuffer_t *fdb, u_offset_t off, size_t len)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	fdb_holes_t *this_hole;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
2217c478bd9Sstevel@tonic-gate 	ASSERT(off < fdb->fd_len);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_IO, (CE_NOTE, "?fdb_add_hole: off %llx len %lx",
2247c478bd9Sstevel@tonic-gate 	    off, len));
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	this_hole = kmem_alloc(sizeof (fdb_holes_t), KM_SLEEP);
2277c478bd9Sstevel@tonic-gate 	this_hole->off = off;
2287c478bd9Sstevel@tonic-gate 	this_hole->len = len;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if (fdb->fd_holes == NULL || off < fdb->fd_holes->off) {
2317c478bd9Sstevel@tonic-gate 		this_hole->next_hole = fdb->fd_holes;
2327c478bd9Sstevel@tonic-gate 		fdb->fd_holes = this_hole;
2337c478bd9Sstevel@tonic-gate 	} else {
2347c478bd9Sstevel@tonic-gate 		fdb_holes_t *fdhp = fdb->fd_holes;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 		while (fdhp->next_hole && off > fdhp->next_hole->off)
2377c478bd9Sstevel@tonic-gate 			fdhp = fdhp->next_hole;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 		this_hole->next_hole = fdhp->next_hole;
2407c478bd9Sstevel@tonic-gate 		fdhp->next_hole = this_hole;
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	fdb->fd_iocount += len;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	mutex_exit(&fdb->fd_mutex);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate fdb_holes_t *
fdb_get_holes(fdbuffer_t * fdb)2517c478bd9Sstevel@tonic-gate fdb_get_holes(fdbuffer_t *fdb)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	if (fdb->fd_state & FDB_ZEROHOLE) {
2567c478bd9Sstevel@tonic-gate 		fdb_zero_holes(fdb);
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	return (fdb->fd_holes);
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate  * Note that offsets refer to offsets from the begining of the buffer
2647c478bd9Sstevel@tonic-gate  * and as such the memory should be cleared accordingly.
2657c478bd9Sstevel@tonic-gate  */
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate static void
fdb_zero_holes(fdbuffer_t * fdb)2687c478bd9Sstevel@tonic-gate fdb_zero_holes(fdbuffer_t *fdb)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	fdb_holes_t *fdh = fdb->fd_holes;
2717c478bd9Sstevel@tonic-gate 	page_t *pp;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	if (!fdh)
2767c478bd9Sstevel@tonic-gate 		return;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	switch (fdb->fd_type) {
2797c478bd9Sstevel@tonic-gate 	case FDB_PAGEIO:
2807c478bd9Sstevel@tonic-gate 		pp = fdb->fd_pages;
2817c478bd9Sstevel@tonic-gate 		while (fdh) {
2827c478bd9Sstevel@tonic-gate 			fdb_holes_t *pfdh = fdh;
2837c478bd9Sstevel@tonic-gate 			size_t l = fdh->len;
2847c478bd9Sstevel@tonic-gate 			u_offset_t o = fdh->off;
2857c478bd9Sstevel@tonic-gate 			ASSERT(pp);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 			do {
2887c478bd9Sstevel@tonic-gate 				int  zerolen;
2897c478bd9Sstevel@tonic-gate 				ASSERT(o >= pp->p_offset);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 				/*
2927c478bd9Sstevel@tonic-gate 				 * This offset is wrong since
2937c478bd9Sstevel@tonic-gate 				 * the offset passed from the pages
2947c478bd9Sstevel@tonic-gate 				 * perspective starts at some virtual
2957c478bd9Sstevel@tonic-gate 				 * address but the hole is relative
2967c478bd9Sstevel@tonic-gate 				 * to the beginning of the fdbuffer.
2977c478bd9Sstevel@tonic-gate 				 */
2987c478bd9Sstevel@tonic-gate 				if (o >= pp->p_offset + PAGESIZE)
2997c478bd9Sstevel@tonic-gate 					continue;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 				zerolen = min(PAGESIZE, l);
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 				ASSERT(zerolen > 0);
3047c478bd9Sstevel@tonic-gate 				ASSERT(zerolen <= PAGESIZE);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 				pagezero(pp, ((uintptr_t)o & PAGEOFFSET),
3077c478bd9Sstevel@tonic-gate 				    zerolen);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 				l -= zerolen;
3107c478bd9Sstevel@tonic-gate 				o += zerolen;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 				if (l == 0)
3137c478bd9Sstevel@tonic-gate 					break;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 			} while (pp = page_list_next(pp));
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 			if (!pp)
3187c478bd9Sstevel@tonic-gate 				break;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 			fdh = fdh->next_hole;
3217c478bd9Sstevel@tonic-gate 			kmem_free(pfdh, sizeof (fdb_holes_t));
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 		break;
3247c478bd9Sstevel@tonic-gate 	case FDB_VADDR:
3257c478bd9Sstevel@tonic-gate 		while (fdh) {
3267c478bd9Sstevel@tonic-gate 			fdb_holes_t *pfdh = fdh;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 			bzero(fdb->fd_addr + fdh->off, fdh->len);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 			fdh = fdh->next_hole;
3317c478bd9Sstevel@tonic-gate 			kmem_free(pfdh, sizeof (fdb_holes_t));
3327c478bd9Sstevel@tonic-gate 		}
333a9f62b1aSToomas Soome 		break;
3347c478bd9Sstevel@tonic-gate 	default:
3357c478bd9Sstevel@tonic-gate 		panic("fdb_zero_holes: Unknown fdb type.");
3367c478bd9Sstevel@tonic-gate 		break;
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate buf_t *
fdb_iosetup(fdbuffer_t * fdb,u_offset_t off,size_t len,struct vnode * vp,int b_flags)3427c478bd9Sstevel@tonic-gate fdb_iosetup(fdbuffer_t *fdb, u_offset_t off, size_t len, struct vnode *vp,
3437c478bd9Sstevel@tonic-gate     int b_flags)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	buf_t *bp;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_IO, (CE_NOTE,
3487c478bd9Sstevel@tonic-gate 	    "?fdb_iosetup: off: %llx len: %lux fdb: len: %lux flags: %x",
3497c478bd9Sstevel@tonic-gate 	    off, len, fdb->fd_len, fdb->fd_state));
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	ASSERT(((b_flags & B_READ) && (fdb->fd_state & FDB_READ)) ||
3567c478bd9Sstevel@tonic-gate 	    ((b_flags & B_WRITE) && (fdb->fd_state & FDB_WRITE)));
3577c478bd9Sstevel@tonic-gate 	/*
3587c478bd9Sstevel@tonic-gate 	 * The fdb can be used either in sync or async mode, if the
3597c478bd9Sstevel@tonic-gate 	 * buffer has not been used it may be used in either mode, but
3607c478bd9Sstevel@tonic-gate 	 * once you have started to use the buf in either mode all
3617c478bd9Sstevel@tonic-gate 	 * subsequent i/o requests must take place the same way.
3627c478bd9Sstevel@tonic-gate 	 */
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	ASSERT(((b_flags & B_ASYNC) &&
3657c478bd9Sstevel@tonic-gate 	    ((fdb->fd_state & FDB_ASYNC) || !(fdb->fd_state & FDB_SYNC))) ||
3667c478bd9Sstevel@tonic-gate 	    (!(b_flags & B_ASYNC) &&
3677c478bd9Sstevel@tonic-gate 	    ((fdb->fd_state & FDB_SYNC) || !(fdb->fd_state & FDB_ASYNC))));
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	fdb->fd_state |= b_flags & B_ASYNC ? FDB_ASYNC : FDB_SYNC;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	fdb->fd_iodispatch++;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	ASSERT((fdb->fd_state & FDB_ASYNC && fdb->fd_iofunc != NULL) ||
3757c478bd9Sstevel@tonic-gate 	    fdb->fd_state & FDB_SYNC);
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	mutex_exit(&fdb->fd_mutex);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	ASSERT((len & (DEV_BSIZE - 1)) == 0);
3807c478bd9Sstevel@tonic-gate 	ASSERT(off+len <= fdb->fd_len);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	switch (fdb->fd_type) {
3837c478bd9Sstevel@tonic-gate 	case FDB_PAGEIO:
3847c478bd9Sstevel@tonic-gate 		if (fdb->fd_parentbp == NULL) {
3857c478bd9Sstevel@tonic-gate 			bp = pageio_setup(fdb->fd_pages, len, vp, b_flags);
3867c478bd9Sstevel@tonic-gate 			fdb->fd_parentbp = bp;
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 		break;
3897c478bd9Sstevel@tonic-gate 	case FDB_VADDR:
3907c478bd9Sstevel@tonic-gate 		if (fdb->fd_parentbp == NULL) {
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 			bp = kmem_alloc(sizeof (buf_t), KM_SLEEP);
3937c478bd9Sstevel@tonic-gate 			bioinit(bp);
3947c478bd9Sstevel@tonic-gate 			bp->b_error = 0;
3957c478bd9Sstevel@tonic-gate 			bp->b_proc = fdb->fd_procp;
3967c478bd9Sstevel@tonic-gate 			bp->b_flags = b_flags | B_BUSY | B_PHYS;
3977c478bd9Sstevel@tonic-gate 			bp->b_bcount = len;
3987c478bd9Sstevel@tonic-gate 			bp->b_un.b_addr = fdb->fd_addr;
3997c478bd9Sstevel@tonic-gate 			bp->b_shadow = fdb->fd_shadow;
4007c478bd9Sstevel@tonic-gate 			if (fdb->fd_shadow != NULL)
4017c478bd9Sstevel@tonic-gate 				bp->b_flags |= B_SHADOW;
4027c478bd9Sstevel@tonic-gate 			fdb->fd_parentbp = bp;
4037c478bd9Sstevel@tonic-gate 		}
4047c478bd9Sstevel@tonic-gate 		break;
4057c478bd9Sstevel@tonic-gate 	default:
4067c478bd9Sstevel@tonic-gate 		panic("fdb_iosetup: Unsupported fdb type.");
4077c478bd9Sstevel@tonic-gate 		break;
4087c478bd9Sstevel@tonic-gate 	};
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	bp = bioclone(fdb->fd_parentbp, off, len, 0, 0,
411*b94c9724SToomas Soome 	    (b_flags & B_ASYNC) ? fdb_iodone : NULL,
4127c478bd9Sstevel@tonic-gate 	    NULL, KM_SLEEP);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	bp->b_forw = (struct buf *)fdb;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if (b_flags & B_ASYNC)
4177c478bd9Sstevel@tonic-gate 		bp->b_flags |= B_ASYNC;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	return (bp);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate size_t
fdb_get_iolen(fdbuffer_t * fdb)4237c478bd9Sstevel@tonic-gate fdb_get_iolen(fdbuffer_t *fdb)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
4267c478bd9Sstevel@tonic-gate 	ASSERT(fdb->fd_iodispatch == 0);
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	return (fdb->fd_iocount - fdb->fd_resid);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate void
fdb_ioerrdone(fdbuffer_t * fdb,int error)4327c478bd9Sstevel@tonic-gate fdb_ioerrdone(fdbuffer_t *fdb, int error)
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
4357c478bd9Sstevel@tonic-gate 	ASSERT(fdb->fd_state & FDB_ASYNC);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_IO, (CE_NOTE,
4387c478bd9Sstevel@tonic-gate 	    "?fdb_ioerrdone: fdb: len: %lux flags: %x error: %d",
4397c478bd9Sstevel@tonic-gate 	    fdb->fd_len, fdb->fd_state, error));
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	fdb->fd_err = error;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	if (error)
4467c478bd9Sstevel@tonic-gate 		fdb->fd_state |= FDB_ERROR;
4477c478bd9Sstevel@tonic-gate 	else
4487c478bd9Sstevel@tonic-gate 		fdb->fd_state |= FDB_DONE;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/*
4517c478bd9Sstevel@tonic-gate 	 * If there is outstanding i/o return wainting for i/o's to complete.
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	if (fdb->fd_iodispatch > 0) {
4547c478bd9Sstevel@tonic-gate 		mutex_exit(&fdb->fd_mutex);
4557c478bd9Sstevel@tonic-gate 		return;
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	mutex_exit(&fdb->fd_mutex);
4597c478bd9Sstevel@tonic-gate 	fdb->fd_iofunc(fdb, fdb->fd_iargp, NULL);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
462*b94c9724SToomas Soome int
fdb_iodone(buf_t * bp)4637c478bd9Sstevel@tonic-gate fdb_iodone(buf_t *bp)
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb = (fdbuffer_t *)bp->b_forw;
4667c478bd9Sstevel@tonic-gate 	int	error, isasync;
4677c478bd9Sstevel@tonic-gate 	int	icallback;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_IO, (CE_NOTE,
4727c478bd9Sstevel@tonic-gate 	    "?fdb_iodone: fdb: len: %lux flags: %x error: %d",
4737c478bd9Sstevel@tonic-gate 	    fdb->fd_len, fdb->fd_state, geterror(bp)));
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	if (bp->b_flags & B_REMAPPED)
4767c478bd9Sstevel@tonic-gate 		bp_mapout(bp);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	icallback = fdb->fd_state & FDB_ICALLBACK;
4817c478bd9Sstevel@tonic-gate 	isasync = fdb->fd_state & FDB_ASYNC;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	ASSERT(fdb->fd_iodispatch > 0);
4847c478bd9Sstevel@tonic-gate 	fdb->fd_iodispatch--;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	if (error = geterror(bp)) {
4877c478bd9Sstevel@tonic-gate 		fdb->fd_err = error;
4887c478bd9Sstevel@tonic-gate 		if (bp->b_resid)
4897c478bd9Sstevel@tonic-gate 			fdb->fd_resid += bp->b_resid;
4907c478bd9Sstevel@tonic-gate 		else
4917c478bd9Sstevel@tonic-gate 			fdb->fd_resid += bp->b_bcount;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	fdb->fd_iocount += bp->b_bcount;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	/*
4977c478bd9Sstevel@tonic-gate 	 * ioack collects the total amount of i/o accounted for
4987c478bd9Sstevel@tonic-gate 	 * this includes:
4997c478bd9Sstevel@tonic-gate 	 *
5007c478bd9Sstevel@tonic-gate 	 *	- i/o completed
5017c478bd9Sstevel@tonic-gate 	 *	- i/o attempted but not completed,
5027c478bd9Sstevel@tonic-gate 	 *	- i/o not done due to holes.
5037c478bd9Sstevel@tonic-gate 	 *
5047c478bd9Sstevel@tonic-gate 	 * Once the entire i/o ranges has been accounted for we'll
5057c478bd9Sstevel@tonic-gate 	 * call the async function associated with the fdb.
5067c478bd9Sstevel@tonic-gate 	 *
5077c478bd9Sstevel@tonic-gate 	 */
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	if ((fdb->fd_iodispatch == 0) &&
5107c478bd9Sstevel@tonic-gate 	    (fdb->fd_state & (FDB_ERROR|FDB_DONE))) {
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		mutex_exit(&fdb->fd_mutex);
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 		if (isasync || icallback) {
5157c478bd9Sstevel@tonic-gate 			fdb->fd_iofunc(fdb, fdb->fd_iargp, bp);
5167c478bd9Sstevel@tonic-gate 		}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	} else {
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 		mutex_exit(&fdb->fd_mutex);
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 		if (icallback) {
5237c478bd9Sstevel@tonic-gate 			fdb->fd_iofunc(fdb, fdb->fd_iargp, bp);
5247c478bd9Sstevel@tonic-gate 		}
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	freerbuf(bp);
528*b94c9724SToomas Soome 	return (0);
5297c478bd9Sstevel@tonic-gate }
530