1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/scsi/scsi.h>
27 #include <sys/ddi.h>
28 #include <sys/sunddi.h>
29 #include <sys/thread.h>
30 #include <sys/var.h>
31
32 #include "sd_xbuf.h"
33
34 /*
35 * xbuf.c: buf(9s) extension facility.
36 *
37 * The buf(9S) extension facility is intended to allow block drivers to
38 * allocate additional memory that is associated with a particular buf(9S)
39 * struct. It is further intended to help in addressing the usual set of
40 * problems associated with such allocations, in particular those involving
41 * recovery from allocation failures, especially in code paths that the
42 * system relies on to free memory.
43 *
44 * CAVEAT: Currently this code is completely private to the sd driver and in
45 * NO WAY constitutes a public or supported interface of any kind. It is
46 * envisioned that this may one day migrate into the Solaris DDI, but until
47 * that time this ought to be considered completely unstable and is subject
48 * to change without notice. This code may NOT in any way be utilized by
49 * ANY code outside the sd driver.
50 */
51
52
53 static int xbuf_iostart(ddi_xbuf_attr_t xap);
54 static void xbuf_dispatch(ddi_xbuf_attr_t xap);
55 static void xbuf_restart_callback(void *arg);
56 static int xbuf_brk_done(struct buf *bp);
57
58
59 /*
60 * Note: Should this be exposed to the caller.... do we want to give the
61 * caller the fexibility of specifying the parameters for the thread pool?
62 * Note: these values are just estimates at this time, based upon what
63 * seems reasonable for the sd driver. It may be preferable to make these
64 * parameters self-scaling in a real (future) implementation.
65 */
66 #define XBUF_TQ_MINALLOC 64
67 #define XBUF_TQ_MAXALLOC 512
68 #define XBUF_DISPATCH_DELAY (drv_usectohz(50000)) /* 50 msec */
69
70 static taskq_t *xbuf_tq = NULL;
71 static int xbuf_attr_tq_minalloc = XBUF_TQ_MINALLOC;
72 static int xbuf_attr_tq_maxalloc = XBUF_TQ_MAXALLOC;
73
74 static kmutex_t xbuf_mutex = { 0 };
75 static uint32_t xbuf_refcount = 0;
76
77 /*
78 * Private wrapper for buf cloned via ddi_xbuf_qstrategy()
79 */
80 struct xbuf_brk {
81 kmutex_t mutex;
82 struct buf *bp0;
83 uint8_t nbufs; /* number of buf allocated */
84 uint8_t active; /* number of active xfer */
85
86 size_t brksize; /* break size used for this buf */
87 int brkblk;
88
89 /* xfer position */
90 off_t off;
91 off_t noff;
92 daddr_t blkno;
93 };
94
_NOTE(DATA_READABLE_WITHOUT_LOCK (xbuf_brk::off))95 _NOTE(DATA_READABLE_WITHOUT_LOCK(xbuf_brk::off))
96
97 /*
98 * Hack needed in the prototype so buf breakup will work.
99 * Here we can rely on the sd code not changing the value in
100 * b_forw.
101 */
102 #define b_clone_private b_forw
103
104
105 /* ARGSUSED */
106 DDII ddi_xbuf_attr_t
107 ddi_xbuf_attr_create(size_t xsize,
108 void (*xa_strategy)(struct buf *bp, ddi_xbuf_t xp, void *attr_arg),
109 void *attr_arg, uint32_t active_limit, uint32_t reserve_limit,
110 major_t major, int flags)
111 {
112 ddi_xbuf_attr_t xap;
113
114 xap = kmem_zalloc(sizeof (struct __ddi_xbuf_attr), KM_SLEEP);
115
116 mutex_init(&xap->xa_mutex, NULL, MUTEX_DRIVER, NULL);
117 mutex_init(&xap->xa_reserve_mutex, NULL, MUTEX_DRIVER, NULL);
118
119 /* Future: Allow the caller to specify alignment requirements? */
120 xap->xa_allocsize = max(xsize, sizeof (void *));
121 xap->xa_active_limit = active_limit;
122 xap->xa_active_lowater = xap->xa_active_limit / 2;
123 xap->xa_reserve_limit = reserve_limit;
124 xap->xa_strategy = xa_strategy;
125 xap->xa_attr_arg = attr_arg;
126
127 mutex_enter(&xbuf_mutex);
128 if (xbuf_refcount == 0) {
129 ASSERT(xbuf_tq == NULL);
130 /*
131 * Note: Would be nice if: (1) #threads in the taskq pool (set
132 * to the value of 'ncpus' at the time the taskq is created)
133 * could adjust automatically with DR; (2) the taskq
134 * minalloc/maxalloc counts could be grown/shrunk on the fly.
135 */
136 xbuf_tq = taskq_create("xbuf_taskq", ncpus,
137 (v.v_maxsyspri - 2), xbuf_attr_tq_minalloc,
138 xbuf_attr_tq_maxalloc, TASKQ_PREPOPULATE);
139 }
140 xbuf_refcount++;
141 mutex_exit(&xbuf_mutex);
142
143 /* In this prototype we just always use the global system pool. */
144 xap->xa_tq = xbuf_tq;
145
146 return (xap);
147 }
148
149
150 DDII void
ddi_xbuf_attr_destroy(ddi_xbuf_attr_t xap)151 ddi_xbuf_attr_destroy(ddi_xbuf_attr_t xap)
152 {
153 ddi_xbuf_t xp;
154
155 mutex_destroy(&xap->xa_mutex);
156 mutex_destroy(&xap->xa_reserve_mutex);
157
158 /* Free any xbufs on the reserve list */
159 while (xap->xa_reserve_count != 0) {
160 xp = xap->xa_reserve_headp;
161 xap->xa_reserve_headp = *((void **)xp);
162 xap->xa_reserve_count--;
163 kmem_free(xp, xap->xa_allocsize);
164 }
165 ASSERT(xap->xa_reserve_headp == NULL);
166
167 mutex_enter(&xbuf_mutex);
168 ASSERT((xbuf_refcount != 0) && (xbuf_tq != NULL));
169 xbuf_refcount--;
170 if (xbuf_refcount == 0) {
171 taskq_destroy(xbuf_tq);
172 xbuf_tq = NULL;
173 }
174 mutex_exit(&xbuf_mutex);
175
176 kmem_free(xap, sizeof (struct __ddi_xbuf_attr));
177 }
178
179
180 /* ARGSUSED */
181 DDII void
ddi_xbuf_attr_register_devinfo(ddi_xbuf_attr_t xbuf_attr,dev_info_t * dip)182 ddi_xbuf_attr_register_devinfo(ddi_xbuf_attr_t xbuf_attr, dev_info_t *dip)
183 {
184 /* Currently a no-op in this prototype */
185 }
186
187
188 /* ARGSUSED */
189 DDII void
ddi_xbuf_attr_unregister_devinfo(ddi_xbuf_attr_t xbuf_attr,dev_info_t * dip)190 ddi_xbuf_attr_unregister_devinfo(ddi_xbuf_attr_t xbuf_attr, dev_info_t *dip)
191 {
192 /* Currently a no-op in this prototype */
193 }
194
195 DDII int
ddi_xbuf_attr_setup_brk(ddi_xbuf_attr_t xap,size_t size)196 ddi_xbuf_attr_setup_brk(ddi_xbuf_attr_t xap, size_t size)
197 {
198 if (size < DEV_BSIZE)
199 return (0);
200
201 mutex_enter(&xap->xa_mutex);
202 xap->xa_brksize = size & ~(DEV_BSIZE - 1);
203 mutex_exit(&xap->xa_mutex);
204 return (1);
205 }
206
207
208
209 /*
210 * Enqueue the given buf and attempt to initiate IO.
211 * Called from the driver strategy(9E) routine.
212 */
213
214 DDII int
ddi_xbuf_qstrategy(struct buf * bp,ddi_xbuf_attr_t xap)215 ddi_xbuf_qstrategy(struct buf *bp, ddi_xbuf_attr_t xap)
216 {
217 ASSERT(xap != NULL);
218 ASSERT(!mutex_owned(&xap->xa_mutex));
219 ASSERT(!mutex_owned(&xap->xa_reserve_mutex));
220
221 mutex_enter(&xap->xa_mutex);
222
223 ASSERT((bp->b_bcount & (DEV_BSIZE - 1)) == 0);
224
225 /*
226 * Breakup buf if necessary. bp->b_private is temporarily
227 * used to save xbuf_brk
228 */
229 if (xap->xa_brksize && bp->b_bcount > xap->xa_brksize) {
230 struct xbuf_brk *brkp;
231
232 brkp = kmem_zalloc(sizeof (struct xbuf_brk), KM_SLEEP);
233 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*brkp))
234 mutex_init(&brkp->mutex, NULL, MUTEX_DRIVER, NULL);
235 brkp->bp0 = bp;
236 brkp->brksize = xap->xa_brksize;
237 brkp->brkblk = btodt(xap->xa_brksize);
238 brkp->noff = xap->xa_brksize;
239 brkp->blkno = bp->b_blkno;
240 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*brkp))
241 bp->b_private = brkp;
242 } else {
243 bp->b_private = NULL;
244 }
245
246 /* Enqueue buf */
247 if (xap->xa_headp == NULL) {
248 xap->xa_headp = xap->xa_tailp = bp;
249 } else {
250 xap->xa_tailp->av_forw = bp;
251 xap->xa_tailp = bp;
252 }
253 bp->av_forw = NULL;
254
255 xap->xa_pending++;
256 mutex_exit(&xap->xa_mutex);
257 return (xbuf_iostart(xap));
258 }
259
260
261 /*
262 * Drivers call this immediately before calling biodone(9F), to notify the
263 * framework that the indicated xbuf is no longer being used by the driver.
264 * May be called under interrupt context.
265 */
266
267 DDII int
ddi_xbuf_done(struct buf * bp,ddi_xbuf_attr_t xap)268 ddi_xbuf_done(struct buf *bp, ddi_xbuf_attr_t xap)
269 {
270 ddi_xbuf_t xp;
271 int done;
272
273 ASSERT(bp != NULL);
274 ASSERT(xap != NULL);
275 ASSERT(!mutex_owned(&xap->xa_mutex));
276 ASSERT(!mutex_owned(&xap->xa_reserve_mutex));
277
278 xp = ddi_xbuf_get(bp, xap);
279
280 mutex_enter(&xap->xa_mutex);
281
282 #ifdef SDDEBUG
283 if (xap->xa_active_limit != 0) {
284 ASSERT(xap->xa_active_count > 0);
285 }
286 #endif
287 xap->xa_active_count--;
288
289 if (xap->xa_reserve_limit != 0) {
290 mutex_enter(&xap->xa_reserve_mutex);
291 if (xap->xa_reserve_count < xap->xa_reserve_limit) {
292 /* Put this xbuf onto the reserve list & exit */
293 *((void **)xp) = xap->xa_reserve_headp;
294 xap->xa_reserve_headp = xp;
295 xap->xa_reserve_count++;
296 mutex_exit(&xap->xa_reserve_mutex);
297 goto done;
298 }
299 mutex_exit(&xap->xa_reserve_mutex);
300 }
301
302 kmem_free(xp, xap->xa_allocsize); /* return it to the system */
303
304 done:
305 if (bp->b_iodone == xbuf_brk_done) {
306 struct xbuf_brk *brkp = (struct xbuf_brk *)bp->b_clone_private;
307
308 brkp->active--;
309 if (brkp->active || xap->xa_headp == brkp->bp0) {
310 done = 0;
311 } else {
312 brkp->off = -1; /* mark bp0 as completed */
313 done = 1;
314 }
315 } else {
316 done = 1;
317 }
318
319 if ((xap->xa_active_limit == 0) ||
320 (xap->xa_active_count <= xap->xa_active_lowater)) {
321 xbuf_dispatch(xap);
322 }
323
324 mutex_exit(&xap->xa_mutex);
325 return (done);
326 }
327
328 static int
xbuf_brk_done(struct buf * bp)329 xbuf_brk_done(struct buf *bp)
330 {
331 struct xbuf_brk *brkp = (struct xbuf_brk *)bp->b_clone_private;
332 struct buf *bp0 = brkp->bp0;
333 int done;
334
335 mutex_enter(&brkp->mutex);
336 if (bp->b_flags & B_ERROR && !(bp0->b_flags & B_ERROR)) {
337 bp0->b_flags |= B_ERROR;
338 bp0->b_error = bp->b_error;
339 }
340 if (bp->b_resid)
341 bp0->b_resid = bp0->b_bcount;
342
343 freerbuf(bp);
344 brkp->nbufs--;
345
346 done = (brkp->off == -1 && brkp->nbufs == 0);
347 mutex_exit(&brkp->mutex);
348
349 /* All buf segments done */
350 if (done) {
351 mutex_destroy(&brkp->mutex);
352 kmem_free(brkp, sizeof (struct xbuf_brk));
353 biodone(bp0);
354 }
355 return (0);
356 }
357
358 DDII void
ddi_xbuf_dispatch(ddi_xbuf_attr_t xap)359 ddi_xbuf_dispatch(ddi_xbuf_attr_t xap)
360 {
361 mutex_enter(&xap->xa_mutex);
362 if ((xap->xa_active_limit == 0) ||
363 (xap->xa_active_count <= xap->xa_active_lowater)) {
364 xbuf_dispatch(xap);
365 }
366 mutex_exit(&xap->xa_mutex);
367 }
368
369
370 /*
371 * ISSUE: in this prototype we cannot really implement ddi_xbuf_get()
372 * unless we explicitly hide the xbuf pointer somewhere in the buf
373 * during allocation, and then rely on the driver never changing it.
374 * We can probably get away with using b_private for this for now,
375 * tho it really is kinda gnarly.....
376 */
377
378 /* ARGSUSED */
379 DDII ddi_xbuf_t
ddi_xbuf_get(struct buf * bp,ddi_xbuf_attr_t xap)380 ddi_xbuf_get(struct buf *bp, ddi_xbuf_attr_t xap)
381 {
382 return (bp->b_private);
383 }
384
385
386 /*
387 * Initiate IOs for bufs on the queue. Called from kernel thread or taskq
388 * thread context. May execute concurrently for the same ddi_xbuf_attr_t.
389 */
390
391 static int
xbuf_iostart(ddi_xbuf_attr_t xap)392 xbuf_iostart(ddi_xbuf_attr_t xap)
393 {
394 struct buf *bp;
395 ddi_xbuf_t xp;
396
397 ASSERT(xap != NULL);
398 ASSERT(!mutex_owned(&xap->xa_mutex));
399 ASSERT(!mutex_owned(&xap->xa_reserve_mutex));
400
401 /*
402 * For each request on the queue, attempt to allocate the specified
403 * xbuf extension area, and call the driver's iostart() routine.
404 * We process as many requests on the queue as we can, until either
405 * (1) we run out of requests; or
406 * (2) we run out of resources; or
407 * (3) we reach the maximum limit for the given ddi_xbuf_attr_t.
408 */
409 for (;;) {
410 mutex_enter(&xap->xa_mutex);
411
412 if ((bp = xap->xa_headp) == NULL) {
413 break; /* queue empty */
414 }
415
416 if ((xap->xa_active_limit != 0) &&
417 (xap->xa_active_count >= xap->xa_active_limit)) {
418 break; /* allocation limit reached */
419 }
420
421 /*
422 * If the reserve_limit is non-zero then work with the
423 * reserve else always allocate a new struct.
424 */
425 if (xap->xa_reserve_limit != 0) {
426 /*
427 * Don't penalize EVERY I/O by always allocating a new
428 * struct. for the sake of maintaining and not touching
429 * a reserve for a pathalogical condition that may never
430 * happen. Use the reserve entries first, this uses it
431 * like a local pool rather than a reserve that goes
432 * untouched. Make sure it's re-populated whenever it
433 * gets fully depleted just in case it really is needed.
434 * This is safe because under the pathalogical
435 * condition, when the system runs out of memory such
436 * that the below allocs fail, the reserve will still
437 * be available whether the entries are saved away on
438 * the queue unused or in-transport somewhere. Thus
439 * progress can still continue, however slowly.
440 */
441 mutex_enter(&xap->xa_reserve_mutex);
442 if (xap->xa_reserve_count != 0) {
443 ASSERT(xap->xa_reserve_headp != NULL);
444 /* Grab an xbuf from the reserve */
445 xp = xap->xa_reserve_headp;
446 xap->xa_reserve_headp = *((void **)xp);
447 ASSERT(xap->xa_reserve_count > 0);
448 xap->xa_reserve_count--;
449 } else {
450 /*
451 * Either this is the first time through,
452 * or the reserve has been totally depleted.
453 * Re-populate the reserve (pool). Excess
454 * structs. get released in the done path.
455 */
456 while (xap->xa_reserve_count <
457 xap->xa_reserve_limit) {
458 xp = kmem_alloc(xap->xa_allocsize,
459 KM_NOSLEEP);
460 if (xp == NULL) {
461 break;
462 }
463 *((void **)xp) = xap->xa_reserve_headp;
464 xap->xa_reserve_headp = xp;
465 xap->xa_reserve_count++;
466 }
467 /* And one more to use right now. */
468 xp = kmem_alloc(xap->xa_allocsize, KM_NOSLEEP);
469 }
470 mutex_exit(&xap->xa_reserve_mutex);
471 } else {
472 /*
473 * Try to alloc a new xbuf struct. If this fails just
474 * exit for now. We'll get back here again either upon
475 * cmd completion or via the timer handler.
476 * Question: what if the allocation attempt for the very
477 * first cmd. fails? There are no outstanding cmds so
478 * how do we get back here?
479 * Should look at un_ncmds_in_transport, if it's zero
480 * then schedule xbuf_restart_callback via the timer.
481 * Athough that breaks the architecture by bringing
482 * softstate data into this code.
483 */
484 xp = kmem_alloc(xap->xa_allocsize, KM_NOSLEEP);
485 }
486 if (xp == NULL) {
487 break; /* Can't process a cmd. right now. */
488 }
489
490 /*
491 * Always run the counter. It's used/needed when xa_active_limit
492 * is non-zero which is the typical (and right now only) case.
493 */
494 xap->xa_active_count++;
495
496 if (bp->b_private) {
497 struct xbuf_brk *brkp = bp->b_private;
498 struct buf *bp0 = bp;
499
500 brkp->active++;
501
502 mutex_enter(&brkp->mutex);
503 brkp->nbufs++;
504 mutex_exit(&brkp->mutex);
505
506 if (brkp->noff < bp0->b_bcount) {
507 bp = bioclone(bp0, brkp->off, brkp->brksize,
508 bp0->b_edev, brkp->blkno, xbuf_brk_done,
509 NULL, KM_SLEEP);
510
511 /* update xfer position */
512 brkp->off = brkp->noff;
513 brkp->noff += brkp->brksize;
514 brkp->blkno += brkp->brkblk;
515 } else {
516 bp = bioclone(bp0, brkp->off,
517 bp0->b_bcount - brkp->off, bp0->b_edev,
518 brkp->blkno, xbuf_brk_done, NULL, KM_SLEEP);
519
520 /* unlink the buf from the list */
521 xap->xa_headp = bp0->av_forw;
522 bp0->av_forw = NULL;
523 }
524 bp->b_clone_private = (struct buf *)brkp;
525 } else {
526 /* unlink the buf from the list */
527 xap->xa_headp = bp->av_forw;
528 bp->av_forw = NULL;
529 }
530
531 /*
532 * Hack needed in the prototype so ddi_xbuf_get() will work.
533 * Here we can rely on the sd code not changing the value in
534 * b_private (in fact it wants it there). See ddi_get_xbuf()
535 */
536 bp->b_private = xp;
537
538 /* call the driver's iostart routine */
539 mutex_exit(&xap->xa_mutex);
540 (*(xap->xa_strategy))(bp, xp, xap->xa_attr_arg);
541 }
542
543 ASSERT(xap->xa_pending > 0);
544 xap->xa_pending--;
545 mutex_exit(&xap->xa_mutex);
546 return (0);
547 }
548
549
550 /*
551 * Re-start IO processing if there is anything on the queue, AND if the
552 * restart function is not already running/pending for this ddi_xbuf_attr_t
553 */
554 static void
xbuf_dispatch(ddi_xbuf_attr_t xap)555 xbuf_dispatch(ddi_xbuf_attr_t xap)
556 {
557 ASSERT(xap != NULL);
558 ASSERT(xap->xa_tq != NULL);
559 ASSERT(mutex_owned(&xap->xa_mutex));
560
561 if ((xap->xa_headp != NULL) && (xap->xa_timeid == NULL) &&
562 (xap->xa_pending == 0)) {
563 /*
564 * First try to see if we can dispatch the restart function
565 * immediately, in a taskq thread. If this fails, then
566 * schedule a timeout(9F) callback to try again later.
567 */
568 if (taskq_dispatch(xap->xa_tq,
569 (void (*)(void *)) xbuf_iostart, xap, KM_NOSLEEP) == 0) {
570 /*
571 * Unable to enqueue the request for the taskq thread,
572 * try again later. Note that this will keep re-trying
573 * until taskq_dispatch() succeeds.
574 */
575 xap->xa_timeid = timeout(xbuf_restart_callback, xap,
576 XBUF_DISPATCH_DELAY);
577 } else {
578 /*
579 * This indicates that xbuf_iostart() will soon be
580 * run for this ddi_xbuf_attr_t, and we do not need to
581 * schedule another invocation via timeout/taskq
582 */
583 xap->xa_pending++;
584 }
585 }
586 }
587
588 /* timeout(9F) callback routine for xbuf restart mechanism. */
589 static void
xbuf_restart_callback(void * arg)590 xbuf_restart_callback(void *arg)
591 {
592 ddi_xbuf_attr_t xap = arg;
593
594 ASSERT(xap != NULL);
595 ASSERT(xap->xa_tq != NULL);
596 ASSERT(!mutex_owned(&xap->xa_mutex));
597
598 mutex_enter(&xap->xa_mutex);
599 xap->xa_timeid = NULL;
600 xbuf_dispatch(xap);
601 mutex_exit(&xap->xa_mutex);
602 }
603
604
605 DDII void
ddi_xbuf_flushq(ddi_xbuf_attr_t xap,int (* funcp)(struct buf *))606 ddi_xbuf_flushq(ddi_xbuf_attr_t xap, int (*funcp)(struct buf *))
607 {
608 struct buf *bp;
609 struct buf *next_bp;
610 struct buf *prev_bp = NULL;
611
612 ASSERT(xap != NULL);
613 ASSERT(xap->xa_tq != NULL);
614 ASSERT(!mutex_owned(&xap->xa_mutex));
615
616 mutex_enter(&xap->xa_mutex);
617
618 for (bp = xap->xa_headp; bp != NULL; bp = next_bp) {
619
620 next_bp = bp->av_forw; /* Save for next iteration */
621
622 /*
623 * If the user-supplied function is non-NULL and returns
624 * FALSE, then just leave the current bp on the queue.
625 */
626 if ((funcp != NULL) && (!(*funcp)(bp))) {
627 prev_bp = bp;
628 continue;
629 }
630
631 /* de-queue the bp */
632 if (bp == xap->xa_headp) {
633 xap->xa_headp = next_bp;
634 if (xap->xa_headp == NULL) {
635 xap->xa_tailp = NULL;
636 }
637 } else {
638 ASSERT(xap->xa_headp != NULL);
639 ASSERT(prev_bp != NULL);
640 if (bp == xap->xa_tailp) {
641 ASSERT(next_bp == NULL);
642 xap->xa_tailp = prev_bp;
643 }
644 prev_bp->av_forw = next_bp;
645 }
646 bp->av_forw = NULL;
647
648 /* Add the bp to the flush queue */
649 if (xap->xa_flush_headp == NULL) {
650 ASSERT(xap->xa_flush_tailp == NULL);
651 xap->xa_flush_headp = xap->xa_flush_tailp = bp;
652 } else {
653 ASSERT(xap->xa_flush_tailp != NULL);
654 xap->xa_flush_tailp->av_forw = bp;
655 xap->xa_flush_tailp = bp;
656 }
657 }
658
659 while ((bp = xap->xa_flush_headp) != NULL) {
660 xap->xa_flush_headp = bp->av_forw;
661 if (xap->xa_flush_headp == NULL) {
662 xap->xa_flush_tailp = NULL;
663 }
664 mutex_exit(&xap->xa_mutex);
665 bioerror(bp, EIO);
666 bp->b_resid = bp->b_bcount;
667 biodone(bp);
668 mutex_enter(&xap->xa_mutex);
669 }
670
671 mutex_exit(&xap->xa_mutex);
672 }
673