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 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <sys/types.h>
31 #include <sys/cmn_err.h>
33 #include <sys/systm.h>
34 #include <sys/debug.h>
37 #include <sys/fdbuffer.h>
41 #define FDB_D_CREATE 001
42 #define FDB_D_ALLOC 002
44 #define FDB_D_ASYNC 010
45 #define DEBUGF(lvl, args) { if ((lvl) & fdb_debug) cmn_err args; }
47 #define DEBUGF(level, args)
49 static struct kmem_cache
*fdb_cache
;
50 static void fdb_zero_holes(fdbuffer_t
*fdb
);
54 fdb_cache_constructor(void *buf
, void *cdrarg
, int kmflags
)
56 fdbuffer_t
*fdb
= buf
;
58 mutex_init(&fdb
->fd_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
65 fdb_cache_destructor(void *buf
, void *cdrarg
)
67 fdbuffer_t
*fdb
= buf
;
69 mutex_destroy(&fdb
->fd_mutex
);
75 fdb_cache
= kmem_cache_create("fdb_cache", sizeof (fdbuffer_t
),
76 0, fdb_cache_constructor
, fdb_cache_destructor
,
81 fdb_prepare(fdbuffer_t
*fdb
)
84 fdb
->fd_iofunc
= NULL
;
86 fdb
->fd_parentbp
= NULL
;
89 fdb
->fd_iodispatch
= 0;
94 fdb_page_create(page_t
*pp
, size_t len
, int flags
)
98 DEBUGF(FDB_D_CREATE
, (CE_NOTE
,
99 "?fdb_page_create: pp: %p len: %lux flags: %x",
100 (void *)pp
, len
, flags
));
102 ASSERT(flags
& (FDB_READ
|FDB_WRITE
));
104 fdb
= kmem_cache_alloc(fdb_cache
, KM_SLEEP
);
108 fdb
->fd_type
= FDB_PAGEIO
;
110 fdb
->fd_state
= flags
;
126 DEBUGF(FDB_D_CREATE
, (CE_NOTE
,
127 "?fdb_addr_create: addr: %p len: %lux flags: %x",
128 (void *)addr
, len
, flags
));
130 ASSERT(flags
& (FDB_READ
|FDB_WRITE
));
132 fdb
= kmem_cache_alloc(fdb_cache
, KM_SLEEP
);
136 fdb
->fd_type
= FDB_VADDR
;
138 fdb
->fd_state
= flags
;
140 fdb
->fd_shadow
= pplist
;
141 fdb
->fd_procp
= procp
;
147 fdb_set_iofunc(fdbuffer_t
*fdb
, fdb_iodone_t iofunc
, void *ioargp
, int flag
)
151 ASSERT((flag
& ~FDB_ICALLBACK
) == 0);
153 fdb
->fd_iofunc
= iofunc
;
154 fdb
->fd_iargp
= ioargp
;
156 mutex_enter(&fdb
->fd_mutex
);
158 if (flag
& FDB_ICALLBACK
)
159 fdb
->fd_state
|= FDB_ICALLBACK
;
161 fdb
->fd_state
|= FDB_ASYNC
;
163 mutex_exit(&fdb
->fd_mutex
);
167 fdb_get_error(fdbuffer_t
*fdb
)
169 return (fdb
->fd_err
);
173 fdb_free(fdbuffer_t
*fdb
)
175 fdb_holes_t
*fdh
, *fdhp
;
177 DEBUGF(FDB_D_CREATE
, (CE_NOTE
, "?fdb_free: addr: %p flags: %x",
178 (void *)fdb
, fdb
->fd_state
));
181 ASSERT(fdb
->fd_iodispatch
== 0);
183 if (fdb
->fd_state
& FDB_ZEROHOLE
) {
187 for (fdh
= fdb
->fd_holes
; fdh
; ) {
189 fdh
= fdh
->next_hole
;
190 kmem_free(fdhp
, sizeof (fdb_holes_t
));
193 if (fdb
->fd_parentbp
!= NULL
) {
194 switch (fdb
->fd_type
) {
196 pageio_done(fdb
->fd_parentbp
);
199 kmem_free(fdb
->fd_parentbp
, sizeof (struct buf
));
202 cmn_err(CE_CONT
, "?fdb_free: Unknown fdb type.");
207 kmem_cache_free(fdb_cache
, fdb
);
212 * The offset should be from the begining of the buffer
213 * it has nothing to do with file offset. This fact should be
214 * reflected in the caller of this routine.
218 fdb_add_hole(fdbuffer_t
*fdb
, uoff_t off
, size_t len
)
220 fdb_holes_t
*this_hole
;
223 ASSERT(off
< fdb
->fd_len
);
225 DEBUGF(FDB_D_IO
, (CE_NOTE
, "?fdb_add_hole: off %llx len %lx",
228 this_hole
= kmem_alloc(sizeof (fdb_holes_t
), KM_SLEEP
);
229 this_hole
->off
= off
;
230 this_hole
->len
= len
;
232 if (fdb
->fd_holes
== NULL
|| off
< fdb
->fd_holes
->off
) {
233 this_hole
->next_hole
= fdb
->fd_holes
;
234 fdb
->fd_holes
= this_hole
;
236 fdb_holes_t
*fdhp
= fdb
->fd_holes
;
238 while (fdhp
->next_hole
&& off
> fdhp
->next_hole
->off
)
239 fdhp
= fdhp
->next_hole
;
241 this_hole
->next_hole
= fdhp
->next_hole
;
242 fdhp
->next_hole
= this_hole
;
245 mutex_enter(&fdb
->fd_mutex
);
247 fdb
->fd_iocount
+= len
;
249 mutex_exit(&fdb
->fd_mutex
);
253 fdb_get_holes(fdbuffer_t
*fdb
)
257 if (fdb
->fd_state
& FDB_ZEROHOLE
) {
261 return (fdb
->fd_holes
);
265 * Note that offsets refer to offsets from the begining of the buffer
266 * and as such the memory should be cleared accordingly.
270 fdb_zero_holes(fdbuffer_t
*fdb
)
272 fdb_holes_t
*fdh
= fdb
->fd_holes
;
280 switch (fdb
->fd_type
) {
284 fdb_holes_t
*pfdh
= fdh
;
291 ASSERT(o
>= pp
->p_offset
);
294 * This offset is wrong since
295 * the offset passed from the pages
296 * perspective starts at some virtual
297 * address but the hole is relative
298 * to the beginning of the fdbuffer.
300 if (o
>= pp
->p_offset
+ PAGESIZE
)
303 zerolen
= min(PAGESIZE
, l
);
306 ASSERT(zerolen
<= PAGESIZE
);
308 pagezero(pp
, ((uintptr_t)o
& PAGEOFFSET
),
317 } while (pp
= page_list_next(pp
));
322 fdh
= fdh
->next_hole
;
323 kmem_free(pfdh
, sizeof (fdb_holes_t
));
328 fdb_holes_t
*pfdh
= fdh
;
330 bzero(fdb
->fd_addr
+ fdh
->off
, fdh
->len
);
332 fdh
= fdh
->next_hole
;
333 kmem_free(pfdh
, sizeof (fdb_holes_t
));
336 panic("fdb_zero_holes: Unknown fdb type.");
343 fdb_iosetup(fdbuffer_t
*fdb
, uoff_t off
, size_t len
, struct vnode
*vp
,
348 DEBUGF(FDB_D_IO
, (CE_NOTE
,
349 "?fdb_iosetup: off: %llx len: %lux fdb: len: %lux flags: %x",
350 off
, len
, fdb
->fd_len
, fdb
->fd_state
));
354 mutex_enter(&fdb
->fd_mutex
);
356 ASSERT(((b_flags
& B_READ
) && (fdb
->fd_state
& FDB_READ
)) ||
357 ((b_flags
& B_WRITE
) && (fdb
->fd_state
& FDB_WRITE
)));
359 * The fdb can be used either in sync or async mode, if the
360 * buffer has not been used it may be used in either mode, but
361 * once you have started to use the buf in either mode all
362 * subsequent i/o requests must take place the same way.
365 ASSERT(((b_flags
& B_ASYNC
) &&
366 ((fdb
->fd_state
& FDB_ASYNC
) || !(fdb
->fd_state
& FDB_SYNC
))) ||
367 (!(b_flags
& B_ASYNC
) &&
368 ((fdb
->fd_state
& FDB_SYNC
) || !(fdb
->fd_state
& FDB_ASYNC
))));
371 fdb
->fd_state
|= b_flags
& B_ASYNC
? FDB_ASYNC
: FDB_SYNC
;
373 fdb
->fd_iodispatch
++;
375 ASSERT((fdb
->fd_state
& FDB_ASYNC
&& fdb
->fd_iofunc
!= NULL
) ||
376 fdb
->fd_state
& FDB_SYNC
);
378 mutex_exit(&fdb
->fd_mutex
);
380 ASSERT((len
& (DEV_BSIZE
- 1)) == 0);
381 ASSERT(off
+len
<= fdb
->fd_len
);
383 switch (fdb
->fd_type
) {
385 if (fdb
->fd_parentbp
== NULL
) {
386 bp
= pageio_setup(fdb
->fd_pages
, len
, vp
, b_flags
);
387 fdb
->fd_parentbp
= bp
;
391 if (fdb
->fd_parentbp
== NULL
) {
393 bp
= kmem_alloc(sizeof (buf_t
), KM_SLEEP
);
396 bp
->b_proc
= fdb
->fd_procp
;
397 bp
->b_flags
= b_flags
| B_BUSY
| B_PHYS
;
399 bp
->b_un
.b_addr
= fdb
->fd_addr
;
400 bp
->b_shadow
= fdb
->fd_shadow
;
401 if (fdb
->fd_shadow
!= NULL
)
402 bp
->b_flags
|= B_SHADOW
;
403 fdb
->fd_parentbp
= bp
;
407 panic("fdb_iosetup: Unsupported fdb type.");
411 bp
= bioclone(fdb
->fd_parentbp
, off
, len
, 0, 0,
412 (b_flags
& B_ASYNC
) ? (int (*)())fdb_iodone
: NULL
,
415 bp
->b_forw
= (struct buf
*)fdb
;
417 if (b_flags
& B_ASYNC
)
418 bp
->b_flags
|= B_ASYNC
;
424 fdb_get_iolen(fdbuffer_t
*fdb
)
427 ASSERT(fdb
->fd_iodispatch
== 0);
429 return (fdb
->fd_iocount
- fdb
->fd_resid
);
433 fdb_ioerrdone(fdbuffer_t
*fdb
, int error
)
436 ASSERT(fdb
->fd_state
& FDB_ASYNC
);
438 DEBUGF(FDB_D_IO
, (CE_NOTE
,
439 "?fdb_ioerrdone: fdb: len: %lux flags: %x error: %d",
440 fdb
->fd_len
, fdb
->fd_state
, error
));
442 mutex_enter(&fdb
->fd_mutex
);
447 fdb
->fd_state
|= FDB_ERROR
;
449 fdb
->fd_state
|= FDB_DONE
;
452 * If there is outstanding i/o return wainting for i/o's to complete.
454 if (fdb
->fd_iodispatch
> 0) {
455 mutex_exit(&fdb
->fd_mutex
);
459 mutex_exit(&fdb
->fd_mutex
);
460 fdb
->fd_iofunc(fdb
, fdb
->fd_iargp
, NULL
);
464 fdb_iodone(buf_t
*bp
)
466 fdbuffer_t
*fdb
= (fdbuffer_t
*)bp
->b_forw
;
472 DEBUGF(FDB_D_IO
, (CE_NOTE
,
473 "?fdb_iodone: fdb: len: %lux flags: %x error: %d",
474 fdb
->fd_len
, fdb
->fd_state
, geterror(bp
)));
476 if (bp
->b_flags
& B_REMAPPED
)
479 mutex_enter(&fdb
->fd_mutex
);
481 icallback
= fdb
->fd_state
& FDB_ICALLBACK
;
482 isasync
= fdb
->fd_state
& FDB_ASYNC
;
484 ASSERT(fdb
->fd_iodispatch
> 0);
485 fdb
->fd_iodispatch
--;
487 if (error
= geterror(bp
)) {
490 fdb
->fd_resid
+= bp
->b_resid
;
492 fdb
->fd_resid
+= bp
->b_bcount
;
495 fdb
->fd_iocount
+= bp
->b_bcount
;
498 * ioack collects the total amount of i/o accounted for
502 * - i/o attempted but not completed,
503 * - i/o not done due to holes.
505 * Once the entire i/o ranges has been accounted for we'll
506 * call the async function associated with the fdb.
510 if ((fdb
->fd_iodispatch
== 0) &&
511 (fdb
->fd_state
& (FDB_ERROR
|FDB_DONE
))) {
513 mutex_exit(&fdb
->fd_mutex
);
515 if (isasync
|| icallback
) {
516 fdb
->fd_iofunc(fdb
, fdb
->fd_iargp
, bp
);
521 mutex_exit(&fdb
->fd_mutex
);
524 fdb
->fd_iofunc(fdb
, fdb
->fd_iargp
, bp
);