diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2014-01-24 06:22:00 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2014-01-24 06:22:00 +0000 |
commit | d70136ad168b3eb8c69638c53cd2c9655c9b5db4 (patch) | |
tree | 3d58f58df8baf2e52f94d964607a2145d76c7b7a | |
parent | ce6961733f68082095b9845c46a6a048de840bda (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.c | 22 |
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); } |