summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2014-01-24 06:22:00 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2014-01-24 06:22:00 +0000
commitd70136ad168b3eb8c69638c53cd2c9655c9b5db4 (patch)
tree3d58f58df8baf2e52f94d964607a2145d76c7b7a
parentce6961733f68082095b9845c46a6a048de840bda (diff)
treat C_SCSIXFER as a reference count and use it as a guard to pool_put.
fixes cd panics where the free_xfer path is called after scsi_done calls xfer_put.
-rw-r--r--sys/dev/ic/wdc.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/sys/dev/ic/wdc.c b/sys/dev/ic/wdc.c
index 0a944455ae0..f107d2c69f0 100644
--- a/sys/dev/ic/wdc.c
+++ b/sys/dev/ic/wdc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdc.c,v 1.122 2014/01/22 06:05:21 dlg Exp $ */
+/* $OpenBSD: wdc.c,v 1.123 2014/01/24 06:21:59 dlg Exp $ */
/* $NetBSD: wdc.c,v 1.68 1999/06/23 19:00:17 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -1937,9 +1937,21 @@ wdc_scrub_xfer(struct wdc_xfer *xfer)
}
void
-wdc_xfer_put(void *null, void *xfer)
+wdc_xfer_put(void *null, void *xxfer)
{
- pool_put(&wdc_xfer_pool, xfer);
+ struct wdc_xfer *xfer = xxfer;
+ int put = 0;
+ int s;
+
+ s = splbio();
+ if (ISSET(xfer->c_flags, C_SCSIXFER))
+ CLR(xfer->c_flags, C_SCSIXFER);
+ else
+ put = 1;
+ splx(s);
+
+ if (put)
+ pool_put(&wdc_xfer_pool, xfer);
}
struct wdc_xfer *
@@ -1952,6 +1964,7 @@ wdc_get_xfer(int flags)
void
wdc_free_xfer(struct channel_softc *chp, struct wdc_xfer *xfer)
{
+ int put = 0;
int s;
if (xfer->c_flags & C_PRIVATEXFER) {
@@ -1963,9 +1976,10 @@ wdc_free_xfer(struct channel_softc *chp, struct wdc_xfer *xfer)
s = splbio();
chp->ch_flags &= ~WDCF_ACTIVE;
TAILQ_REMOVE(&chp->ch_queue->sc_xfer, xfer, c_xferchain);
+ put = !ISSET(xfer->c_flags, C_SCSIXFER);
splx(s);
- if (!ISSET(xfer->c_flags, C_SCSIXFER))
+ if (put)
scsi_io_put(&wdc_xfer_iopool, xfer);
}