summaryrefslogtreecommitdiffstats
path: root/sys/scsi
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>1997-06-25 19:07:43 +0000
committertegge <tegge@FreeBSD.org>1997-06-25 19:07:43 +0000
commit988f978710326fc294e3ebe6b7231a5b2807c6f8 (patch)
treeab7e9ccf1be3e96bf94b4abd5d5faf132b743dd1 /sys/scsi
parent228f6410f312edf048c05ed76a7d84d3d954a339 (diff)
downloadFreeBSD-src-988f978710326fc294e3ebe6b7231a5b2807c6f8.zip
FreeBSD-src-988f978710326fc294e3ebe6b7231a5b2807c6f8.tar.gz
Introduce an advisory exclusive lock on the scsi link structure.
Change sd_open, sd_close and sd_ioctl to use this lock to ensure serialization of some critical operations, thus avoiding some race conditions. Ideas picked from NetBSD (ccd and sd devices). This fixes one of the problems noted in PR kern/3688. Reviewed by: "Justin T. Gibbs" <gibbs@plutotech.com>
Diffstat (limited to 'sys/scsi')
-rw-r--r--sys/scsi/scsi_driver.c24
-rw-r--r--sys/scsi/scsi_driver.h4
-rw-r--r--sys/scsi/scsiconf.h4
-rw-r--r--sys/scsi/sd.c19
4 files changed, 47 insertions, 4 deletions
diff --git a/sys/scsi/scsi_driver.c b/sys/scsi/scsi_driver.c
index 06c1ebf..32d9c7b 100644
--- a/sys/scsi/scsi_driver.c
+++ b/sys/scsi/scsi_driver.c
@@ -35,7 +35,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: scsi_driver.c,v 1.22 1997/02/22 09:44:31 peter Exp $
+ * $Id: scsi_driver.c,v 1.23 1997/03/23 06:33:47 bde Exp $
*
*/
@@ -232,3 +232,25 @@ scsi_strategy(struct buf *bp, struct scsi_device *device)
}
}
}
+
+int scsi_device_lock(struct scsi_link *sc_link)
+{
+ int error;
+ while (sc_link->flags & SDEV_XLOCK) {
+ sc_link->flags |= SDEV_WANT;
+ error = tsleep(&sc_link->flags, PRIBIO | PCATCH, "sdevlk",0);
+ if (error)
+ return error;
+ }
+ sc_link->flags |= SDEV_XLOCK;
+ return 0;
+}
+
+void scsi_device_unlock(struct scsi_link *sc_link)
+{
+ sc_link->flags &= ~SDEV_XLOCK;
+ if (sc_link->flags & SDEV_WANT) {
+ sc_link->flags &= ~SDEV_WANT;
+ wakeup(&sc_link->flags);
+ }
+}
diff --git a/sys/scsi/scsi_driver.h b/sys/scsi/scsi_driver.h
index f6875da..bbbe318 100644
--- a/sys/scsi/scsi_driver.h
+++ b/sys/scsi/scsi_driver.h
@@ -35,7 +35,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: scsi_driver.h,v 1.10 1997/02/22 09:44:31 peter Exp $
+ * $Id: scsi_driver.h,v 1.11 1997/03/23 04:39:07 bde Exp $
*
*/
#ifndef _SCSI__DRIVER_H_
@@ -50,6 +50,8 @@ struct proc;
int scsi_goaway __P((int));
int scsi_device_attach __P((struct scsi_link *));
+int scsi_device_lock __P((struct scsi_link *));
+void scsi_device_unlock __P((struct scsi_link *));
int scsi_open __P((dev_t, int, int, struct proc *, struct scsi_device *));
int scsi_close __P((dev_t, int, int, struct proc *, struct scsi_device *));
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index 563645f..6c14350 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -14,7 +14,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsiconf.h,v 1.53 1997/04/03 10:09:29 kato Exp $
+ * $Id: scsiconf.h,v 1.54 1997/05/19 17:32:10 jmz Exp $
*/
#ifndef SCSI_SCSICONF_H
#define SCSI_SCSICONF_H 1
@@ -337,6 +337,8 @@ struct scsi_link
#define SDEV_TARGET_OPS 0x0800 /* XXX-HA: Supports target ops */
#define SDEV_IS_OPEN 0x1000 /* at least 1 open session */
#define SDEV_UK 0x2000 /* this is the "uk" device */
+#define SDEV_XLOCK 0x4000 /* Device is locked */
+#define SDEV_WANT 0x8000 /* A process is waiting for lock */
/*
* One of these is allocated and filled in for each scsi bus.
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
index cef96bd..8386c42 100644
--- a/sys/scsi/sd.c
+++ b/sys/scsi/sd.c
@@ -15,7 +15,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992
*
- * $Id: sd.c,v 1.104 1997/03/24 11:25:02 bde Exp $
+ * $Id: sd.c,v 1.105 1997/05/01 19:15:38 sos Exp $
*/
#include "opt_bounce.h"
@@ -279,6 +279,10 @@ sd_open(dev, mode, fmt, p, sc_link)
*/
scsi_test_unit_ready(sc_link, 0);
+ errcode = scsi_device_lock(sc_link);
+ if (errcode)
+ return errcode;
+
/*
* If it's been invalidated, then forget the label
*/
@@ -354,6 +358,7 @@ sd_open(dev, mode, fmt, p, sc_link)
SC_DEBUG(sc_link, SDEV_DB3, ("open %ld %ld\n", sdstrats, sdqueues));
+ scsi_device_unlock(sc_link);
return 0;
bad:
@@ -361,6 +366,7 @@ bad:
scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT);
sc_link->flags &= ~SDEV_OPEN;
}
+ scsi_device_unlock(sc_link);
return errcode;
}
@@ -377,13 +383,18 @@ sd_close(dev, fflag, fmt, p, sc_link)
struct scsi_link *sc_link;
{
struct scsi_data *sd;
+ errval errcode;
sd = sc_link->sd;
+ errcode = scsi_device_lock(sc_link);
+ if (errcode)
+ return errcode;
dsclose(dev, fmt, sd->dk_slices);
if (!dsisopen(sd->dk_slices)) {
scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK);
sc_link->flags &= ~SDEV_OPEN;
}
+ scsi_device_unlock(sc_link);
return (0);
}
@@ -661,8 +672,14 @@ sd_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p,
if (cmd == DIOCSBAD)
return (EINVAL); /* XXX */
+
+ error = scsi_device_lock(sc_link);
+ if (error)
+ return error;
+
error = dsioctl("sd", dev, cmd, addr, flag, &sd->dk_slices,
sdstrategy1, (ds_setgeom_t *)NULL);
+ scsi_device_unlock(sc_link);
if (error != -1)
return (error);
if (PARTITION(dev) != RAW_PART)
OpenPOWER on IntegriCloud