4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1998,2001 by Sun Microsystems, Inc.
24 * All rights reserved.
28 #include <sys/types.h>
29 #include <sys/cmn_err.h>
31 #include <sys/systm.h>
32 #include <sys/debug.h>
35 #include <sys/fdbuffer.h>
39 #define FDB_D_CREATE 001
40 #define FDB_D_ALLOC 002
42 #define FDB_D_ASYNC 010
43 #define DEBUGF(lvl, args) { if ((lvl) & fdb_debug) cmn_err args; }
45 #define DEBUGF(level, args)
47 static struct kmem_cache
*fdb_cache
;
48 static void fdb_zero_holes(fdbuffer_t
*fdb
);
52 fdb_cache_constructor(void *buf
, void *cdrarg
, int kmflags
)
54 fdbuffer_t
*fdb
= buf
;
56 mutex_init(&fdb
->fd_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
63 fdb_cache_destructor(void *buf
, void *cdrarg
)
65 fdbuffer_t
*fdb
= buf
;
67 mutex_destroy(&fdb
->fd_mutex
);
73 fdb_cache
= kmem_cache_create("fdb_cache", sizeof (fdbuffer_t
),
74 0, fdb_cache_constructor
, fdb_cache_destructor
,
79 fdb_prepare(fdbuffer_t
*fdb
)
82 fdb
->fd_iofunc
= NULL
;
84 fdb
->fd_parentbp
= NULL
;
87 fdb
->fd_iodispatch
= 0;
92 fdb_page_create(page_t
*pp
, size_t len
, int flags
)
96 DEBUGF(FDB_D_CREATE
, (CE_NOTE
,
97 "?fdb_page_create: pp: %p len: %lux flags: %x",
98 (void *)pp
, len
, flags
));
100 ASSERT(flags
& (FDB_READ
|FDB_WRITE
));
102 fdb
= kmem_cache_alloc(fdb_cache
, KM_SLEEP
);
106 fdb
->fd_type
= FDB_PAGEIO
;
108 fdb
->fd_state
= flags
;
124 DEBUGF(FDB_D_CREATE
, (CE_NOTE
,
125 "?fdb_addr_create: addr: %p len: %lux flags: %x",
126 (void *)addr
, len
, flags
));
128 ASSERT(flags
& (FDB_READ
|FDB_WRITE
));
130 fdb
= kmem_cache_alloc(fdb_cache
, KM_SLEEP
);
134 fdb
->fd_type
= FDB_VADDR
;
136 fdb
->fd_state
= flags
;
138 fdb
->fd_shadow
= pplist
;
139 fdb
->fd_procp
= procp
;
145 fdb_set_iofunc(fdbuffer_t
*fdb
, fdb_iodone_t iofunc
, void *ioargp
, int flag
)
149 ASSERT((flag
& ~FDB_ICALLBACK
) == 0);
151 fdb
->fd_iofunc
= iofunc
;
152 fdb
->fd_iargp
= ioargp
;
154 mutex_enter(&fdb
->fd_mutex
);
156 if (flag
& FDB_ICALLBACK
)
157 fdb
->fd_state
|= FDB_ICALLBACK
;
159 fdb
->fd_state
|= FDB_ASYNC
;
161 mutex_exit(&fdb
->fd_mutex
);
165 fdb_get_error(fdbuffer_t
*fdb
)
167 return (fdb
->fd_err
);
171 fdb_free(fdbuffer_t
*fdb
)
173 fdb_holes_t
*fdh
, *fdhp
;
175 DEBUGF(FDB_D_CREATE
, (CE_NOTE
, "?fdb_free: addr: %p flags: %x",
176 (void *)fdb
, fdb
->fd_state
));
179 ASSERT(fdb
->fd_iodispatch
== 0);
181 if (fdb
->fd_state
& FDB_ZEROHOLE
) {
185 for (fdh
= fdb
->fd_holes
; fdh
; ) {
187 fdh
= fdh
->next_hole
;
188 kmem_free(fdhp
, sizeof (fdb_holes_t
));
191 if (fdb
->fd_parentbp
!= NULL
) {
192 switch (fdb
->fd_type
) {
194 pageio_done(fdb
->fd_parentbp
);
197 kmem_free(fdb
->fd_parentbp
, sizeof (struct buf
));
200 cmn_err(CE_CONT
, "?fdb_free: Unknown fdb type.");
205 kmem_cache_free(fdb_cache
, fdb
);
210 * The offset should be from the begining of the buffer
211 * it has nothing to do with file offset. This fact should be
212 * reflected in the caller of this routine.
216 fdb_add_hole(fdbuffer_t
*fdb
, uoff_t off
, size_t len
)
218 fdb_holes_t
*this_hole
;
221 ASSERT(off
< fdb
->fd_len
);
223 DEBUGF(FDB_D_IO
, (CE_NOTE
, "?fdb_add_hole: off %llx len %lx",
226 this_hole
= kmem_alloc(sizeof (fdb_holes_t
), KM_SLEEP
);
227 this_hole
->off
= off
;
228 this_hole
->len
= len
;
230 if (fdb
->fd_holes
== NULL
|| off
< fdb
->fd_holes
->off
) {
231 this_hole
->next_hole
= fdb
->fd_holes
;
232 fdb
->fd_holes
= this_hole
;
234 fdb_holes_t
*fdhp
= fdb
->fd_holes
;
236 while (fdhp
->next_hole
&& off
> fdhp
->next_hole
->off
)
237 fdhp
= fdhp
->next_hole
;
239 this_hole
->next_hole
= fdhp
->next_hole
;
240 fdhp
->next_hole
= this_hole
;
243 mutex_enter(&fdb
->fd_mutex
);
245 fdb
->fd_iocount
+= len
;
247 mutex_exit(&fdb
->fd_mutex
);
251 fdb_get_holes(fdbuffer_t
*fdb
)
255 if (fdb
->fd_state
& FDB_ZEROHOLE
) {
259 return (fdb
->fd_holes
);
263 * Note that offsets refer to offsets from the begining of the buffer
264 * and as such the memory should be cleared accordingly.
268 fdb_zero_holes(fdbuffer_t
*fdb
)
270 fdb_holes_t
*fdh
= fdb
->fd_holes
;
278 switch (fdb
->fd_type
) {
282 fdb_holes_t
*pfdh
= fdh
;
289 ASSERT(o
>= pp
->p_offset
);
292 * This offset is wrong since
293 * the offset passed from the pages
294 * perspective starts at some virtual
295 * address but the hole is relative
296 * to the beginning of the fdbuffer.
298 if (o
>= pp
->p_offset
+ PAGESIZE
)
301 zerolen
= min(PAGESIZE
, l
);
304 ASSERT(zerolen
<= PAGESIZE
);
306 pagezero(pp
, ((uintptr_t)o
& PAGEOFFSET
),
315 } while (pp
= page_list_next(pp
));
320 fdh
= fdh
->next_hole
;
321 kmem_free(pfdh
, sizeof (fdb_holes_t
));
326 fdb_holes_t
*pfdh
= fdh
;
328 bzero(fdb
->fd_addr
+ fdh
->off
, fdh
->len
);
330 fdh
= fdh
->next_hole
;
331 kmem_free(pfdh
, sizeof (fdb_holes_t
));
335 panic("fdb_zero_holes: Unknown fdb type.");
342 fdb_iosetup(fdbuffer_t
*fdb
, uoff_t off
, size_t len
, struct vnode
*vp
,
347 DEBUGF(FDB_D_IO
, (CE_NOTE
,
348 "?fdb_iosetup: off: %llx len: %lux fdb: len: %lux flags: %x",
349 off
, len
, fdb
->fd_len
, fdb
->fd_state
));
353 mutex_enter(&fdb
->fd_mutex
);
355 ASSERT(((b_flags
& B_READ
) && (fdb
->fd_state
& FDB_READ
)) ||
356 ((b_flags
& B_WRITE
) && (fdb
->fd_state
& FDB_WRITE
)));
358 * The fdb can be used either in sync or async mode, if the
359 * buffer has not been used it may be used in either mode, but
360 * once you have started to use the buf in either mode all
361 * subsequent i/o requests must take place the same way.
364 ASSERT(((b_flags
& B_ASYNC
) &&
365 ((fdb
->fd_state
& FDB_ASYNC
) || !(fdb
->fd_state
& FDB_SYNC
))) ||
366 (!(b_flags
& B_ASYNC
) &&
367 ((fdb
->fd_state
& FDB_SYNC
) || !(fdb
->fd_state
& FDB_ASYNC
))));
370 fdb
->fd_state
|= b_flags
& B_ASYNC
? FDB_ASYNC
: FDB_SYNC
;
372 fdb
->fd_iodispatch
++;
374 ASSERT((fdb
->fd_state
& FDB_ASYNC
&& fdb
->fd_iofunc
!= NULL
) ||
375 fdb
->fd_state
& FDB_SYNC
);
377 mutex_exit(&fdb
->fd_mutex
);
379 ASSERT((len
& (DEV_BSIZE
- 1)) == 0);
380 ASSERT(off
+len
<= fdb
->fd_len
);
382 switch (fdb
->fd_type
) {
384 if (fdb
->fd_parentbp
== NULL
) {
385 bp
= pageio_setup(fdb
->fd_pages
, len
, vp
, b_flags
);
386 fdb
->fd_parentbp
= bp
;
390 if (fdb
->fd_parentbp
== NULL
) {
392 bp
= kmem_alloc(sizeof (buf_t
), KM_SLEEP
);
395 bp
->b_proc
= fdb
->fd_procp
;
396 bp
->b_flags
= b_flags
| B_BUSY
| B_PHYS
;
398 bp
->b_un
.b_addr
= fdb
->fd_addr
;
399 bp
->b_shadow
= fdb
->fd_shadow
;
400 if (fdb
->fd_shadow
!= NULL
)
401 bp
->b_flags
|= B_SHADOW
;
402 fdb
->fd_parentbp
= bp
;
406 panic("fdb_iosetup: Unsupported fdb type.");
410 bp
= bioclone(fdb
->fd_parentbp
, off
, len
, 0, 0,
411 (b_flags
& B_ASYNC
) ? (int (*)())fdb_iodone
: NULL
,
414 bp
->b_forw
= (struct buf
*)fdb
;
416 if (b_flags
& B_ASYNC
)
417 bp
->b_flags
|= B_ASYNC
;
423 fdb_get_iolen(fdbuffer_t
*fdb
)
426 ASSERT(fdb
->fd_iodispatch
== 0);
428 return (fdb
->fd_iocount
- fdb
->fd_resid
);
432 fdb_ioerrdone(fdbuffer_t
*fdb
, int error
)
435 ASSERT(fdb
->fd_state
& FDB_ASYNC
);
437 DEBUGF(FDB_D_IO
, (CE_NOTE
,
438 "?fdb_ioerrdone: fdb: len: %lux flags: %x error: %d",
439 fdb
->fd_len
, fdb
->fd_state
, error
));
441 mutex_enter(&fdb
->fd_mutex
);
446 fdb
->fd_state
|= FDB_ERROR
;
448 fdb
->fd_state
|= FDB_DONE
;
451 * If there is outstanding i/o return wainting for i/o's to complete.
453 if (fdb
->fd_iodispatch
> 0) {
454 mutex_exit(&fdb
->fd_mutex
);
458 mutex_exit(&fdb
->fd_mutex
);
459 fdb
->fd_iofunc(fdb
, fdb
->fd_iargp
, NULL
);
463 fdb_iodone(buf_t
*bp
)
465 fdbuffer_t
*fdb
= (fdbuffer_t
*)bp
->b_forw
;
471 DEBUGF(FDB_D_IO
, (CE_NOTE
,
472 "?fdb_iodone: fdb: len: %lux flags: %x error: %d",
473 fdb
->fd_len
, fdb
->fd_state
, geterror(bp
)));
475 if (bp
->b_flags
& B_REMAPPED
)
478 mutex_enter(&fdb
->fd_mutex
);
480 icallback
= fdb
->fd_state
& FDB_ICALLBACK
;
481 isasync
= fdb
->fd_state
& FDB_ASYNC
;
483 ASSERT(fdb
->fd_iodispatch
> 0);
484 fdb
->fd_iodispatch
--;
486 if (error
= geterror(bp
)) {
489 fdb
->fd_resid
+= bp
->b_resid
;
491 fdb
->fd_resid
+= bp
->b_bcount
;
494 fdb
->fd_iocount
+= bp
->b_bcount
;
497 * ioack collects the total amount of i/o accounted for
501 * - i/o attempted but not completed,
502 * - i/o not done due to holes.
504 * Once the entire i/o ranges has been accounted for we'll
505 * call the async function associated with the fdb.
509 if ((fdb
->fd_iodispatch
== 0) &&
510 (fdb
->fd_state
& (FDB_ERROR
|FDB_DONE
))) {
512 mutex_exit(&fdb
->fd_mutex
);
514 if (isasync
|| icallback
) {
515 fdb
->fd_iofunc(fdb
, fdb
->fd_iargp
, bp
);
520 mutex_exit(&fdb
->fd_mutex
);
523 fdb
->fd_iofunc(fdb
, fdb
->fd_iargp
, bp
);