Module Name:    src
Committed By:   mlelstv
Date:           Sat May 14 10:52:29 UTC 2016

Modified Files:
        src/sys/dev/usb: ucom.c

Log Message:
All com devices have an issue that they sleep in the final close
when they signal a hangup while still using the device. This allows
a concurrent open to succeed without proper locking because it
only checks the state of the tty layer.

This issue triggers an assertion in ucom due to a reused USB xfer,
but it can also cause misbehaviour in other com devices.

For now in ucom:
- make open block while close is in progress
- also serialize close operations


To generate a diff of this commit:
cvs rdiff -u -r1.112 -r1.113 src/sys/dev/usb/ucom.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/ucom.c
diff -u src/sys/dev/usb/ucom.c:1.112 src/sys/dev/usb/ucom.c:1.113
--- src/sys/dev/usb/ucom.c:1.112	Tue May 10 10:40:33 2016
+++ src/sys/dev/usb/ucom.c	Sat May 14 10:52:29 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ucom.c,v 1.112 2016/05/10 10:40:33 skrll Exp $	*/
+/*	$NetBSD: ucom.c,v 1.113 2016/05/14 10:52:29 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.112 2016/05/10 10:40:33 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.113 2016/05/14 10:52:29 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -174,6 +174,7 @@ struct ucom_softc {
 	int			sc_swflags;
 
 	u_char			sc_opening;	/* lock during open */
+	u_char			sc_closing;	/* lock during close */
 	int			sc_refcnt;
 	u_char			sc_dying;	/* disconnecting */
 
@@ -282,6 +283,7 @@ ucom_attach(device_t parent, device_t se
 	sc->sc_tx_stopped = 0;
 	sc->sc_swflags = 0;
 	sc->sc_opening = 0;
+	sc->sc_closing = 0;
 	sc->sc_refcnt = 0;
 	sc->sc_dying = 0;
 
@@ -542,9 +544,10 @@ ucomopen(dev_t dev, int flag, int mode, 
 	}
 
 	/*
-	 * Do the following iff this is a first open.
+	 * Wait while the device is initialized by the
+	 * first opener or cleaned up by the last closer.
 	 */
-	while (sc->sc_opening) {
+	while (sc->sc_opening || sc->sc_closing) {
 		error = cv_wait_sig(&sc->sc_opencv, &sc->sc_lock);
 
 		if (error) {
@@ -681,6 +684,10 @@ ucomclose(dev_t dev, int flag, int mode,
 	mutex_enter(&sc->sc_lock);
 	tp = sc->sc_tty;
 
+	while (sc->sc_closing)
+		cv_wait(&sc->sc_opencv, &sc->sc_lock);
+	sc->sc_closing = 1;
+
 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
 		goto out;
 	}
@@ -706,6 +713,9 @@ ucomclose(dev_t dev, int flag, int mode,
 		usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
 
 out:
+	sc->sc_closing = 0;
+	cv_signal(&sc->sc_opencv);
+
 	mutex_exit(&sc->sc_lock);
 
 	return 0;

Reply via email to