summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authormlelstv <mlelstv@NetBSD.org>2016-05-14 10:52:29 +0000
committermlelstv <mlelstv@NetBSD.org>2016-05-14 10:52:29 +0000
commitb5591bf79f52b982d1ea31656375f1600263c3d7 (patch)
treeaa154a994a4dfa6991ae1db73dfbc1d25fe869a9 /sys
parentb0a83de7d06ac932ec20cb5c08e2e8e3c4988be7 (diff)
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
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/ucom.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/sys/dev/usb/ucom.c b/sys/dev/usb/ucom.c
index c68b83cb515..93d82c96f80 100644
--- a/sys/dev/usb/ucom.c
+++ b/sys/dev/usb/ucom.c
@@ -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 self, void *aux)
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, struct lwp *l)
}
/*
- * 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, struct lwp *l)
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, struct lwp *l)
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;