mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
uvideo: fix close/detach race on streaming teardown
detach() stopped streaming and called uvideo_vs_close() before destroy_dev(), so a concurrent close() could race the teardown and call uvideo_vs_close() a second time (double usbd_transfer_unsetup), and mtx_destroy() could race a close still holding sc_mtx. sc_streaming was also read without the lock in both paths. Reorder detach() to call destroy_dev() first so all in-flight cdev methods drain before any teardown. Read sc_streaming under sc_mtx in both detach() and the last-close safety net.
This commit is contained in:
1 parent
2120f3e5ec
commit
12b4a02bd8
1 file changed
+11
-11
+11
-11
@@ -960,21 +960,20 @@ uvideo_detach(device_t dev)
|
||||
|
||||
sc->sc_dying = 1;
|
||||
|
||||
/* Stop any active streaming */
|
||||
if (sc->sc_streaming) {
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
sc->sc_streaming = 0;
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
uvideo_vs_close(sc);
|
||||
}
|
||||
|
||||
/* Destroy character device */
|
||||
if (sc->sc_cdev != NULL) {
|
||||
destroy_dev(sc->sc_cdev);
|
||||
sc->sc_cdev = NULL;
|
||||
}
|
||||
|
||||
/* Unit number is implicitly freed when the cdev is destroyed */
|
||||
/* Stop streaming if still active (e.g. detached while idle). */
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
if (sc->sc_streaming) {
|
||||
sc->sc_streaming = 0;
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
uvideo_vs_close(sc);
|
||||
} else
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
/* Free frame buffers */
|
||||
uvideo_vs_free_frame(sc);
|
||||
@@ -2911,12 +2910,13 @@ uvideo_cdev_close(struct cdev *dev, int flags, int fmt, struct thread *td)
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
/* Last close: stop streaming if still active (safety net) */
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
if (sc->sc_streaming) {
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
sc->sc_streaming = 0;
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
uvideo_vs_close(sc);
|
||||
}
|
||||
} else
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
uvideo_vs_free_frame(sc);
|
||||
|
||||
|
||||
Reference in new issue
Block a user