Subject: DIOCEJECT changes
To: None <tech-kern@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-kern
Date: 02/03/1999 12:00:36
[ Initially posted to the wrong list - sorry ]

-----Forwarded message from Manuel Bouyer <bouyer@antioche.eu.org>-----

Hi,

One thing that always annoyed me with the DIOCEJECT ioctl is that on
devices that can lock the door, the calling program needs to unlock it first.
But this program can't really check if this device is in use or not.
For devices that can't lock the door things are worse: the media is ejected
without control.

I'd like to change DIOCEJECT to check that the only partition open is the one
doing the ioctl. If so, the door is unlocked before doing the eject.
If not, EBUSY is returned. DIOCEJECT would take an interger as argument,
and bypass the above check if set (that is, it would have the old behavior).
The old DIOCEJECT would be renamed to ODIOCEJECT for binary compatibility.

This would allow us to have a much cleaner eject(1), along with better
reliability.

Diffs for this change are appened below. If I don't get complains, I'll
commit this next week.
Comments ?

--
Manuel Bouyer <bouyer@antioche.eu.org>
--

diff -ubr sys.old/dev/scsipi/cd.c sys/dev/scsipi/cd.c
--- sys.old/dev/scsipi/cd.c	Fri Jan 29 12:17:58 1999
+++ sys/dev/scsipi/cd.c	Tue Feb  2 22:04:57 1999
@@ -709,6 +709,7 @@
 	struct proc *p;
 {
 	struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(dev)];
+	int part = CDPART(dev);
 	int error;
 
 	SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%lx ", cmd));
@@ -721,6 +722,7 @@
 		switch (cmd) {
 		case DIOCWLABEL:
 		case DIOCLOCK:
+		case ODIOCEJECT:
 		case DIOCEJECT:
 		case SCIOCIDENTIFY:
 		case OSCIOCIDENTIFY:
@@ -742,7 +744,7 @@
 		case CDIOCRESET:
 		case SCIOCRESET:
 		case CDIOCLOADUNLOAD:
-			if (CDPART(dev) == RAW_PART)
+			if (part == RAW_PART)
 				break;
 		/* FALLTHROUGH */
 		default:
@@ -761,7 +763,7 @@
 	case DIOCGPART:
 		((struct partinfo *)addr)->disklab = cd->sc_dk.dk_label;
 		((struct partinfo *)addr)->part =
-		    &cd->sc_dk.dk_label->d_partitions[CDPART(dev)];
+		    &cd->sc_dk.dk_label->d_partitions[part];
 		return (0);
 
 	case DIOCWDINFO:
@@ -967,8 +969,26 @@
 		return (scsipi_start(cd->sc_link, SSS_STOP, 0));
 	case CDIOCCLOSE:
 		return (scsipi_start(cd->sc_link, SSS_START|SSS_LOEJ, 0));
-	case CDIOCEJECT: /* FALLTHROUGH */
 	case DIOCEJECT:
+		if (*(int *)addr == 0) {
+			/*
+			 * Don't force eject: check that we are the only
+			 * partition open. If so, unlock it.
+			 */
+			if ((cd->sc_dk.dk_openmask & ~(1 << part)) == 0 &&
+			    cd->sc_dk.dk_bopenmask + cd->sc_dk.dk_copenmask ==
+			    cd->sc_dk.dk_openmask) {
+				error =  scsipi_prevent(cd->sc_link, PR_ALLOW,
+				    SCSI_IGNORE_NOT_READY);
+				if (error)
+					return (error);
+			} else {
+				return (EBUSY); 
+			}
+		}
+		/* FALLTHROUGH */
+	case CDIOCEJECT: /* FALLTHROUGH */
+	case ODIOCEJECT:
 		return (scsipi_start(cd->sc_link, SSS_STOP|SSS_LOEJ, 0));
 	case CDIOCALLOW:
 		return (scsipi_prevent(cd->sc_link, PR_ALLOW, 0));
@@ -994,7 +1014,7 @@
 	}
 
 	default:
-		if (CDPART(dev) != RAW_PART)
+		if (part != RAW_PART)
 			return (ENOTTY);
 		return (scsipi_do_ioctl(cd->sc_link, dev, cmd, addr, flag, p));
 	}
diff -ubr sys.old/dev/scsipi/sd.c sys/dev/scsipi/sd.c
--- sys.old/dev/scsipi/sd.c	Fri Jan 29 12:17:59 1999
+++ sys/dev/scsipi/sd.c	Tue Feb  2 22:04:17 1999
@@ -744,6 +744,7 @@
 	struct proc *p;
 {
 	struct sd_softc *sd = sd_cd.cd_devs[SDUNIT(dev)];
+	int part = SDPART(dev);
 	int error;
 
 	SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdioctl 0x%lx ", cmd));
@@ -757,11 +758,12 @@
 		case DIOCWLABEL:
 		case DIOCLOCK:
 		case DIOCEJECT:
+		case ODIOCEJECT:
 		case SCIOCIDENTIFY:
 		case OSCIOCIDENTIFY:
 		case SCIOCCOMMAND:
 		case SCIOCDEBUG:
-			if (SDPART(dev) == RAW_PART)
+			if (part == RAW_PART)
 				break;
 		/* FALLTHROUGH */
 		default:
@@ -780,7 +782,7 @@
 	case DIOCGPART:
 		((struct partinfo *)addr)->disklab = sd->sc_dk.dk_label;
 		((struct partinfo *)addr)->part =
-		    &sd->sc_dk.dk_label->d_partitions[SDPART(dev)];
+		    &sd->sc_dk.dk_label->d_partitions[part];
 		return (0);
 
 	case DIOCWDINFO:
@@ -820,6 +822,26 @@
 		    (*(int *)addr) ? PR_PREVENT : PR_ALLOW, 0));
 
 	case DIOCEJECT:
+		if ((sd->sc_link->flags & SDEV_REMOVABLE) == 0)
+			return (ENOTTY);
+		if (*(int *)addr == 0) {
+			/*
+			 * Don't force eject: check that we are the only
+			 * partition open. If so, unlock it.
+			 */
+			if ((sd->sc_dk.dk_openmask & ~(1 << part)) == 0 &&
+			    sd->sc_dk.dk_bopenmask + sd->sc_dk.dk_copenmask ==
+			    sd->sc_dk.dk_openmask) {
+				error =  scsipi_prevent(sd->sc_link, PR_ALLOW,
+				    SCSI_IGNORE_NOT_READY);
+				if (error)
+					return (error);
+			} else {
+				return (EBUSY);
+			}
+		}
+		/* FALLTHROUGH */
+	case ODIOCEJECT:
 		return ((sd->sc_link->flags & SDEV_REMOVABLE) == 0 ? ENOTTY :
 		    scsipi_start(sd->sc_link, SSS_STOP|SSS_LOEJ, 0));
 
@@ -828,7 +850,7 @@
 		return (0);
 
 	default:
-		if (SDPART(dev) != RAW_PART)
+		if (part != RAW_PART)
 			return (ENOTTY);
 		return (scsipi_do_ioctl(sd->sc_link, dev, cmd, addr, flag, p));
 	}
diff -ubr sys.old/sys/dkio.h sys/sys/dkio.h
--- sys.old/sys/dkio.h	Fri Oct 17 20:39:38 1997
+++ sys/sys/dkio.h	Tue Feb  2 21:22:50 1999
@@ -56,7 +56,8 @@
 #define DIOCWLABEL	_IOW('d', 109, int)	/* write en/disable label */
 
 #define DIOCSBAD	_IOW('d', 110, struct dkbad)	/* set kernel dkbad */
-#define DIOCEJECT	_IO('d', 112)		/* eject removable disk */
+#define DIOCEJECT	_IOW('d', 112, int)	/* eject removable disk */
+#define ODIOCEJECT	_IO('d', 112)		/* eject removable disk */
 #define DIOCLOCK	_IOW('d', 113, int)	/* lock/unlock pack */
 
 		/* get default label, clear label */

-----End of forwarded message-----

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
--