diff options
| author | mlelstv <mlelstv@NetBSD.org> | 2016-05-14 10:52:29 +0000 |
|---|---|---|
| committer | mlelstv <mlelstv@NetBSD.org> | 2016-05-14 10:52:29 +0000 |
| commit | b5591bf79f52b982d1ea31656375f1600263c3d7 (patch) | |
| tree | aa154a994a4dfa6991ae1db73dfbc1d25fe869a9 /sys | |
| parent | b0a83de7d06ac932ec20cb5c08e2e8e3c4988be7 (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.c | 18 |
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; |
