xref: /illumos-gate/usr/src/uts/common/fs/fdbuffer.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1998,2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  */
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <sys/fdbuffer.h>
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
40*7c478bd9Sstevel@tonic-gate static int fdb_debug;
41*7c478bd9Sstevel@tonic-gate #define	FDB_D_CREATE	001
42*7c478bd9Sstevel@tonic-gate #define	FDB_D_ALLOC	002
43*7c478bd9Sstevel@tonic-gate #define	FDB_D_IO	004
44*7c478bd9Sstevel@tonic-gate #define	FDB_D_ASYNC	010
45*7c478bd9Sstevel@tonic-gate #define	DEBUGF(lvl, args)	{ if ((lvl) & fdb_debug) cmn_err args; }
46*7c478bd9Sstevel@tonic-gate #else
47*7c478bd9Sstevel@tonic-gate #define	DEBUGF(level, args)
48*7c478bd9Sstevel@tonic-gate #endif
49*7c478bd9Sstevel@tonic-gate static struct kmem_cache *fdb_cache;
50*7c478bd9Sstevel@tonic-gate static void fdb_zero_holes(fdbuffer_t *fdb);
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
53*7c478bd9Sstevel@tonic-gate static int
54*7c478bd9Sstevel@tonic-gate fdb_cache_constructor(void *buf, void *cdrarg, int kmflags)
55*7c478bd9Sstevel@tonic-gate {
56*7c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb = buf;
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate 	mutex_init(&fdb->fd_mutex, NULL, MUTEX_DEFAULT, NULL);
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate 	return (0);
61*7c478bd9Sstevel@tonic-gate }
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
64*7c478bd9Sstevel@tonic-gate static void
65*7c478bd9Sstevel@tonic-gate fdb_cache_destructor(void *buf, void *cdrarg)
66*7c478bd9Sstevel@tonic-gate {
67*7c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb = buf;
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&fdb->fd_mutex);
70*7c478bd9Sstevel@tonic-gate }
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate void
73*7c478bd9Sstevel@tonic-gate fdb_init()
74*7c478bd9Sstevel@tonic-gate {
75*7c478bd9Sstevel@tonic-gate 	fdb_cache = kmem_cache_create("fdb_cache", sizeof (fdbuffer_t),
76*7c478bd9Sstevel@tonic-gate 	    0, fdb_cache_constructor, fdb_cache_destructor,
77*7c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL, 0);
78*7c478bd9Sstevel@tonic-gate }
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate static void
81*7c478bd9Sstevel@tonic-gate fdb_prepare(fdbuffer_t *fdb)
82*7c478bd9Sstevel@tonic-gate {
83*7c478bd9Sstevel@tonic-gate 	fdb->fd_holes = NULL;
84*7c478bd9Sstevel@tonic-gate 	fdb->fd_iofunc = NULL;
85*7c478bd9Sstevel@tonic-gate 	fdb->fd_iargp = NULL;
86*7c478bd9Sstevel@tonic-gate 	fdb->fd_parentbp = NULL;
87*7c478bd9Sstevel@tonic-gate 	fdb->fd_resid = 0;
88*7c478bd9Sstevel@tonic-gate 	fdb->fd_iocount = 0;
89*7c478bd9Sstevel@tonic-gate 	fdb->fd_iodispatch = 0;
90*7c478bd9Sstevel@tonic-gate 	fdb->fd_err = 0;
91*7c478bd9Sstevel@tonic-gate }
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate fdbuffer_t *
94*7c478bd9Sstevel@tonic-gate fdb_page_create(page_t *pp, size_t len, int flags)
95*7c478bd9Sstevel@tonic-gate {
96*7c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb;
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_CREATE, (CE_NOTE,
99*7c478bd9Sstevel@tonic-gate 	    "?fdb_page_create: pp: %p len: %lux flags: %x",
100*7c478bd9Sstevel@tonic-gate 	    (void *)pp, len, flags));
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 	ASSERT(flags & (FDB_READ|FDB_WRITE));
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	fdb = kmem_cache_alloc(fdb_cache, KM_SLEEP);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	fdb_prepare(fdb);
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	fdb->fd_type = FDB_PAGEIO;
109*7c478bd9Sstevel@tonic-gate 	fdb->fd_len = len;
110*7c478bd9Sstevel@tonic-gate 	fdb->fd_state = flags;
111*7c478bd9Sstevel@tonic-gate 	fdb->fd_pages = pp;
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	return (fdb);
114*7c478bd9Sstevel@tonic-gate }
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate fdbuffer_t *
117*7c478bd9Sstevel@tonic-gate fdb_addr_create(
118*7c478bd9Sstevel@tonic-gate 	caddr_t addr,
119*7c478bd9Sstevel@tonic-gate 	size_t len,
120*7c478bd9Sstevel@tonic-gate 	int flags,
121*7c478bd9Sstevel@tonic-gate 	page_t **pplist,
122*7c478bd9Sstevel@tonic-gate 	struct proc *procp)
123*7c478bd9Sstevel@tonic-gate {
124*7c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb;
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_CREATE, (CE_NOTE,
127*7c478bd9Sstevel@tonic-gate 	    "?fdb_addr_create: addr: %p len: %lux flags: %x",
128*7c478bd9Sstevel@tonic-gate 	    (void *)addr, len, flags));
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	ASSERT(flags & (FDB_READ|FDB_WRITE));
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	fdb = kmem_cache_alloc(fdb_cache, KM_SLEEP);
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	fdb_prepare(fdb);
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	fdb->fd_type = FDB_VADDR;
137*7c478bd9Sstevel@tonic-gate 	fdb->fd_len = len;
138*7c478bd9Sstevel@tonic-gate 	fdb->fd_state = flags;
139*7c478bd9Sstevel@tonic-gate 	fdb->fd_addr = addr;
140*7c478bd9Sstevel@tonic-gate 	fdb->fd_shadow = pplist;
141*7c478bd9Sstevel@tonic-gate 	fdb->fd_procp = procp;
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	return (fdb);
144*7c478bd9Sstevel@tonic-gate }
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate void
147*7c478bd9Sstevel@tonic-gate fdb_set_iofunc(fdbuffer_t *fdb, fdb_iodone_t iofunc, void *ioargp, int flag)
148*7c478bd9Sstevel@tonic-gate {
149*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
150*7c478bd9Sstevel@tonic-gate 	ASSERT(iofunc);
151*7c478bd9Sstevel@tonic-gate 	ASSERT((flag & ~FDB_ICALLBACK) == 0);
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	fdb->fd_iofunc = iofunc;
154*7c478bd9Sstevel@tonic-gate 	fdb->fd_iargp = ioargp;
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	if (flag & FDB_ICALLBACK)
159*7c478bd9Sstevel@tonic-gate 		fdb->fd_state |= FDB_ICALLBACK;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	fdb->fd_state |= FDB_ASYNC;
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	mutex_exit(&fdb->fd_mutex);
164*7c478bd9Sstevel@tonic-gate }
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate int
167*7c478bd9Sstevel@tonic-gate fdb_get_error(fdbuffer_t *fdb)
168*7c478bd9Sstevel@tonic-gate {
169*7c478bd9Sstevel@tonic-gate 	return (fdb->fd_err);
170*7c478bd9Sstevel@tonic-gate }
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate void
173*7c478bd9Sstevel@tonic-gate fdb_free(fdbuffer_t *fdb)
174*7c478bd9Sstevel@tonic-gate {
175*7c478bd9Sstevel@tonic-gate 	fdb_holes_t *fdh, *fdhp;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_CREATE, (CE_NOTE, "?fdb_free: addr: %p flags: %x",
178*7c478bd9Sstevel@tonic-gate 	    (void *)fdb, fdb->fd_state));
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
181*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb->fd_iodispatch == 0);
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	if (fdb->fd_state & FDB_ZEROHOLE) {
184*7c478bd9Sstevel@tonic-gate 		fdb_zero_holes(fdb);
185*7c478bd9Sstevel@tonic-gate 	}
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	for (fdh = fdb->fd_holes; fdh; ) {
188*7c478bd9Sstevel@tonic-gate 		fdhp = fdh;
189*7c478bd9Sstevel@tonic-gate 		fdh = fdh->next_hole;
190*7c478bd9Sstevel@tonic-gate 		kmem_free(fdhp, sizeof (fdb_holes_t));
191*7c478bd9Sstevel@tonic-gate 	}
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	if (fdb->fd_parentbp != NULL) {
194*7c478bd9Sstevel@tonic-gate 		switch (fdb->fd_type) {
195*7c478bd9Sstevel@tonic-gate 		case FDB_PAGEIO:
196*7c478bd9Sstevel@tonic-gate 			pageio_done(fdb->fd_parentbp);
197*7c478bd9Sstevel@tonic-gate 			break;
198*7c478bd9Sstevel@tonic-gate 		case FDB_VADDR:
199*7c478bd9Sstevel@tonic-gate 			kmem_free(fdb->fd_parentbp, sizeof (struct buf));
200*7c478bd9Sstevel@tonic-gate 			break;
201*7c478bd9Sstevel@tonic-gate 		default:
202*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "?fdb_free: Unknown fdb type.");
203*7c478bd9Sstevel@tonic-gate 			break;
204*7c478bd9Sstevel@tonic-gate 		}
205*7c478bd9Sstevel@tonic-gate 	}
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	kmem_cache_free(fdb_cache, fdb);
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate }
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate /*
212*7c478bd9Sstevel@tonic-gate  * The offset should be from the begining of the buffer
213*7c478bd9Sstevel@tonic-gate  * it has nothing to do with file offset. This fact should be
214*7c478bd9Sstevel@tonic-gate  * reflected in the caller of this routine.
215*7c478bd9Sstevel@tonic-gate  */
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate void
218*7c478bd9Sstevel@tonic-gate fdb_add_hole(fdbuffer_t *fdb, u_offset_t off, size_t len)
219*7c478bd9Sstevel@tonic-gate {
220*7c478bd9Sstevel@tonic-gate 	fdb_holes_t *this_hole;
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
223*7c478bd9Sstevel@tonic-gate 	ASSERT(off < fdb->fd_len);
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_IO, (CE_NOTE, "?fdb_add_hole: off %llx len %lx",
226*7c478bd9Sstevel@tonic-gate 	    off, len));
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	this_hole = kmem_alloc(sizeof (fdb_holes_t), KM_SLEEP);
229*7c478bd9Sstevel@tonic-gate 	this_hole->off = off;
230*7c478bd9Sstevel@tonic-gate 	this_hole->len = len;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	if (fdb->fd_holes == NULL || off < fdb->fd_holes->off) {
233*7c478bd9Sstevel@tonic-gate 		this_hole->next_hole = fdb->fd_holes;
234*7c478bd9Sstevel@tonic-gate 		fdb->fd_holes = this_hole;
235*7c478bd9Sstevel@tonic-gate 	} else {
236*7c478bd9Sstevel@tonic-gate 		fdb_holes_t *fdhp = fdb->fd_holes;
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 		while (fdhp->next_hole && off > fdhp->next_hole->off)
239*7c478bd9Sstevel@tonic-gate 			fdhp = fdhp->next_hole;
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 		this_hole->next_hole = fdhp->next_hole;
242*7c478bd9Sstevel@tonic-gate 		fdhp->next_hole = this_hole;
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	fdb->fd_iocount += len;
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	mutex_exit(&fdb->fd_mutex);
250*7c478bd9Sstevel@tonic-gate }
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate fdb_holes_t *
253*7c478bd9Sstevel@tonic-gate fdb_get_holes(fdbuffer_t *fdb)
254*7c478bd9Sstevel@tonic-gate {
255*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	if (fdb->fd_state & FDB_ZEROHOLE) {
258*7c478bd9Sstevel@tonic-gate 		fdb_zero_holes(fdb);
259*7c478bd9Sstevel@tonic-gate 	}
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	return (fdb->fd_holes);
262*7c478bd9Sstevel@tonic-gate }
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate /*
265*7c478bd9Sstevel@tonic-gate  * Note that offsets refer to offsets from the begining of the buffer
266*7c478bd9Sstevel@tonic-gate  * and as such the memory should be cleared accordingly.
267*7c478bd9Sstevel@tonic-gate  */
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate static void
270*7c478bd9Sstevel@tonic-gate fdb_zero_holes(fdbuffer_t *fdb)
271*7c478bd9Sstevel@tonic-gate {
272*7c478bd9Sstevel@tonic-gate 	fdb_holes_t *fdh = fdb->fd_holes;
273*7c478bd9Sstevel@tonic-gate 	page_t *pp;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	if (!fdh)
278*7c478bd9Sstevel@tonic-gate 		return;
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	switch (fdb->fd_type) {
281*7c478bd9Sstevel@tonic-gate 	case FDB_PAGEIO:
282*7c478bd9Sstevel@tonic-gate 		pp = fdb->fd_pages;
283*7c478bd9Sstevel@tonic-gate 		while (fdh) {
284*7c478bd9Sstevel@tonic-gate 			fdb_holes_t *pfdh = fdh;
285*7c478bd9Sstevel@tonic-gate 			size_t l = fdh->len;
286*7c478bd9Sstevel@tonic-gate 			u_offset_t o = fdh->off;
287*7c478bd9Sstevel@tonic-gate 			ASSERT(pp);
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 			do {
290*7c478bd9Sstevel@tonic-gate 				int  zerolen;
291*7c478bd9Sstevel@tonic-gate 				ASSERT(o >= pp->p_offset);
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 				/*
294*7c478bd9Sstevel@tonic-gate 				 * This offset is wrong since
295*7c478bd9Sstevel@tonic-gate 				 * the offset passed from the pages
296*7c478bd9Sstevel@tonic-gate 				 * perspective starts at some virtual
297*7c478bd9Sstevel@tonic-gate 				 * address but the hole is relative
298*7c478bd9Sstevel@tonic-gate 				 * to the beginning of the fdbuffer.
299*7c478bd9Sstevel@tonic-gate 				 */
300*7c478bd9Sstevel@tonic-gate 				if (o >= pp->p_offset + PAGESIZE)
301*7c478bd9Sstevel@tonic-gate 					continue;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 				zerolen = min(PAGESIZE, l);
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 				ASSERT(zerolen > 0);
306*7c478bd9Sstevel@tonic-gate 				ASSERT(zerolen <= PAGESIZE);
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 				pagezero(pp, ((uintptr_t)o & PAGEOFFSET),
309*7c478bd9Sstevel@tonic-gate 				    zerolen);
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 				l -= zerolen;
312*7c478bd9Sstevel@tonic-gate 				o += zerolen;
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 				if (l == 0)
315*7c478bd9Sstevel@tonic-gate 					break;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 			} while (pp = page_list_next(pp));
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 			if (!pp)
320*7c478bd9Sstevel@tonic-gate 				break;
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 			fdh = fdh->next_hole;
323*7c478bd9Sstevel@tonic-gate 			kmem_free(pfdh, sizeof (fdb_holes_t));
324*7c478bd9Sstevel@tonic-gate 		}
325*7c478bd9Sstevel@tonic-gate 		break;
326*7c478bd9Sstevel@tonic-gate 	case FDB_VADDR:
327*7c478bd9Sstevel@tonic-gate 		while (fdh) {
328*7c478bd9Sstevel@tonic-gate 			fdb_holes_t *pfdh = fdh;
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 			bzero(fdb->fd_addr + fdh->off, fdh->len);
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 			fdh = fdh->next_hole;
333*7c478bd9Sstevel@tonic-gate 			kmem_free(pfdh, sizeof (fdb_holes_t));
334*7c478bd9Sstevel@tonic-gate 		}
335*7c478bd9Sstevel@tonic-gate 	default:
336*7c478bd9Sstevel@tonic-gate 		panic("fdb_zero_holes: Unknown fdb type.");
337*7c478bd9Sstevel@tonic-gate 		break;
338*7c478bd9Sstevel@tonic-gate 	}
339*7c478bd9Sstevel@tonic-gate }
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate buf_t *
343*7c478bd9Sstevel@tonic-gate fdb_iosetup(fdbuffer_t *fdb, u_offset_t off, size_t len, struct vnode *vp,
344*7c478bd9Sstevel@tonic-gate     int b_flags)
345*7c478bd9Sstevel@tonic-gate {
346*7c478bd9Sstevel@tonic-gate 	buf_t *bp;
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_IO, (CE_NOTE,
349*7c478bd9Sstevel@tonic-gate 	    "?fdb_iosetup: off: %llx len: %lux fdb: len: %lux flags: %x",
350*7c478bd9Sstevel@tonic-gate 	    off, len, fdb->fd_len, fdb->fd_state));
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	ASSERT(((b_flags & B_READ) && (fdb->fd_state & FDB_READ)) ||
357*7c478bd9Sstevel@tonic-gate 	    ((b_flags & B_WRITE) && (fdb->fd_state & FDB_WRITE)));
358*7c478bd9Sstevel@tonic-gate 	/*
359*7c478bd9Sstevel@tonic-gate 	 * The fdb can be used either in sync or async mode, if the
360*7c478bd9Sstevel@tonic-gate 	 * buffer has not been used it may be used in either mode, but
361*7c478bd9Sstevel@tonic-gate 	 * once you have started to use the buf in either mode all
362*7c478bd9Sstevel@tonic-gate 	 * subsequent i/o requests must take place the same way.
363*7c478bd9Sstevel@tonic-gate 	 */
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	ASSERT(((b_flags & B_ASYNC) &&
366*7c478bd9Sstevel@tonic-gate 	    ((fdb->fd_state & FDB_ASYNC) || !(fdb->fd_state & FDB_SYNC))) ||
367*7c478bd9Sstevel@tonic-gate 	    (!(b_flags & B_ASYNC) &&
368*7c478bd9Sstevel@tonic-gate 	    ((fdb->fd_state & FDB_SYNC) || !(fdb->fd_state & FDB_ASYNC))));
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	fdb->fd_state |= b_flags & B_ASYNC ? FDB_ASYNC : FDB_SYNC;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	fdb->fd_iodispatch++;
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	ASSERT((fdb->fd_state & FDB_ASYNC && fdb->fd_iofunc != NULL) ||
376*7c478bd9Sstevel@tonic-gate 	    fdb->fd_state & FDB_SYNC);
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	mutex_exit(&fdb->fd_mutex);
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	ASSERT((len & (DEV_BSIZE - 1)) == 0);
381*7c478bd9Sstevel@tonic-gate 	ASSERT(off+len <= fdb->fd_len);
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	switch (fdb->fd_type) {
384*7c478bd9Sstevel@tonic-gate 	case FDB_PAGEIO:
385*7c478bd9Sstevel@tonic-gate 		if (fdb->fd_parentbp == NULL) {
386*7c478bd9Sstevel@tonic-gate 			bp = pageio_setup(fdb->fd_pages, len, vp, b_flags);
387*7c478bd9Sstevel@tonic-gate 			fdb->fd_parentbp = bp;
388*7c478bd9Sstevel@tonic-gate 		}
389*7c478bd9Sstevel@tonic-gate 		break;
390*7c478bd9Sstevel@tonic-gate 	case FDB_VADDR:
391*7c478bd9Sstevel@tonic-gate 		if (fdb->fd_parentbp == NULL) {
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 			bp = kmem_alloc(sizeof (buf_t), KM_SLEEP);
394*7c478bd9Sstevel@tonic-gate 			bioinit(bp);
395*7c478bd9Sstevel@tonic-gate 			bp->b_error = 0;
396*7c478bd9Sstevel@tonic-gate 			bp->b_proc = fdb->fd_procp;
397*7c478bd9Sstevel@tonic-gate 			bp->b_flags = b_flags | B_BUSY | B_PHYS;
398*7c478bd9Sstevel@tonic-gate 			bp->b_bcount = len;
399*7c478bd9Sstevel@tonic-gate 			bp->b_un.b_addr = fdb->fd_addr;
400*7c478bd9Sstevel@tonic-gate 			bp->b_shadow = fdb->fd_shadow;
401*7c478bd9Sstevel@tonic-gate 			if (fdb->fd_shadow != NULL)
402*7c478bd9Sstevel@tonic-gate 				bp->b_flags |= B_SHADOW;
403*7c478bd9Sstevel@tonic-gate 			fdb->fd_parentbp = bp;
404*7c478bd9Sstevel@tonic-gate 		}
405*7c478bd9Sstevel@tonic-gate 		break;
406*7c478bd9Sstevel@tonic-gate 	default:
407*7c478bd9Sstevel@tonic-gate 		panic("fdb_iosetup: Unsupported fdb type.");
408*7c478bd9Sstevel@tonic-gate 		break;
409*7c478bd9Sstevel@tonic-gate 	};
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	bp = bioclone(fdb->fd_parentbp, off, len, 0, 0,
412*7c478bd9Sstevel@tonic-gate 	    (b_flags & B_ASYNC) ? (int (*)())fdb_iodone : NULL,
413*7c478bd9Sstevel@tonic-gate 	    NULL, KM_SLEEP);
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	bp->b_forw = (struct buf *)fdb;
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	if (b_flags & B_ASYNC)
418*7c478bd9Sstevel@tonic-gate 		bp->b_flags |= B_ASYNC;
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	return (bp);
421*7c478bd9Sstevel@tonic-gate }
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate size_t
424*7c478bd9Sstevel@tonic-gate fdb_get_iolen(fdbuffer_t *fdb)
425*7c478bd9Sstevel@tonic-gate {
426*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
427*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb->fd_iodispatch == 0);
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	return (fdb->fd_iocount - fdb->fd_resid);
430*7c478bd9Sstevel@tonic-gate }
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate void
433*7c478bd9Sstevel@tonic-gate fdb_ioerrdone(fdbuffer_t *fdb, int error)
434*7c478bd9Sstevel@tonic-gate {
435*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
436*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb->fd_state & FDB_ASYNC);
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_IO, (CE_NOTE,
439*7c478bd9Sstevel@tonic-gate 	    "?fdb_ioerrdone: fdb: len: %lux flags: %x error: %d",
440*7c478bd9Sstevel@tonic-gate 	    fdb->fd_len, fdb->fd_state, error));
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	fdb->fd_err = error;
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	if (error)
447*7c478bd9Sstevel@tonic-gate 		fdb->fd_state |= FDB_ERROR;
448*7c478bd9Sstevel@tonic-gate 	else
449*7c478bd9Sstevel@tonic-gate 		fdb->fd_state |= FDB_DONE;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	/*
452*7c478bd9Sstevel@tonic-gate 	 * If there is outstanding i/o return wainting for i/o's to complete.
453*7c478bd9Sstevel@tonic-gate 	 */
454*7c478bd9Sstevel@tonic-gate 	if (fdb->fd_iodispatch > 0) {
455*7c478bd9Sstevel@tonic-gate 		mutex_exit(&fdb->fd_mutex);
456*7c478bd9Sstevel@tonic-gate 		return;
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	mutex_exit(&fdb->fd_mutex);
460*7c478bd9Sstevel@tonic-gate 	fdb->fd_iofunc(fdb, fdb->fd_iargp, NULL);
461*7c478bd9Sstevel@tonic-gate }
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate void
464*7c478bd9Sstevel@tonic-gate fdb_iodone(buf_t *bp)
465*7c478bd9Sstevel@tonic-gate {
466*7c478bd9Sstevel@tonic-gate 	fdbuffer_t *fdb = (fdbuffer_t *)bp->b_forw;
467*7c478bd9Sstevel@tonic-gate 	int	error, isasync;
468*7c478bd9Sstevel@tonic-gate 	int	icallback;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb);
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	DEBUGF(FDB_D_IO, (CE_NOTE,
473*7c478bd9Sstevel@tonic-gate 	    "?fdb_iodone: fdb: len: %lux flags: %x error: %d",
474*7c478bd9Sstevel@tonic-gate 	    fdb->fd_len, fdb->fd_state, geterror(bp)));
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	if (bp->b_flags & B_REMAPPED)
477*7c478bd9Sstevel@tonic-gate 		bp_mapout(bp);
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	mutex_enter(&fdb->fd_mutex);
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	icallback = fdb->fd_state & FDB_ICALLBACK;
482*7c478bd9Sstevel@tonic-gate 	isasync = fdb->fd_state & FDB_ASYNC;
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	ASSERT(fdb->fd_iodispatch > 0);
485*7c478bd9Sstevel@tonic-gate 	fdb->fd_iodispatch--;
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 	if (error = geterror(bp)) {
488*7c478bd9Sstevel@tonic-gate 		fdb->fd_err = error;
489*7c478bd9Sstevel@tonic-gate 		if (bp->b_resid)
490*7c478bd9Sstevel@tonic-gate 			fdb->fd_resid += bp->b_resid;
491*7c478bd9Sstevel@tonic-gate 		else
492*7c478bd9Sstevel@tonic-gate 			fdb->fd_resid += bp->b_bcount;
493*7c478bd9Sstevel@tonic-gate 	}
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	fdb->fd_iocount += bp->b_bcount;
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 	/*
498*7c478bd9Sstevel@tonic-gate 	 * ioack collects the total amount of i/o accounted for
499*7c478bd9Sstevel@tonic-gate 	 * this includes:
500*7c478bd9Sstevel@tonic-gate 	 *
501*7c478bd9Sstevel@tonic-gate 	 *	- i/o completed
502*7c478bd9Sstevel@tonic-gate 	 *	- i/o attempted but not completed,
503*7c478bd9Sstevel@tonic-gate 	 *	- i/o not done due to holes.
504*7c478bd9Sstevel@tonic-gate 	 *
505*7c478bd9Sstevel@tonic-gate 	 * Once the entire i/o ranges has been accounted for we'll
506*7c478bd9Sstevel@tonic-gate 	 * call the async function associated with the fdb.
507*7c478bd9Sstevel@tonic-gate 	 *
508*7c478bd9Sstevel@tonic-gate 	 */
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	if ((fdb->fd_iodispatch == 0) &&
511*7c478bd9Sstevel@tonic-gate 	    (fdb->fd_state & (FDB_ERROR|FDB_DONE))) {
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 		mutex_exit(&fdb->fd_mutex);
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 		if (isasync || icallback) {
516*7c478bd9Sstevel@tonic-gate 			fdb->fd_iofunc(fdb, fdb->fd_iargp, bp);
517*7c478bd9Sstevel@tonic-gate 		}
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	} else {
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 		mutex_exit(&fdb->fd_mutex);
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate 		if (icallback) {
524*7c478bd9Sstevel@tonic-gate 			fdb->fd_iofunc(fdb, fdb->fd_iargp, bp);
525*7c478bd9Sstevel@tonic-gate 		}
526*7c478bd9Sstevel@tonic-gate 	}
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	freerbuf(bp);
529*7c478bd9Sstevel@tonic-gate }
530