diff options
| author | maxv <maxv@NetBSD.org> | 2019-09-14 15:24:23 +0000 |
|---|---|---|
| committer | maxv <maxv@NetBSD.org> | 2019-09-14 15:24:23 +0000 |
| commit | 94fe3c701a4db7ca85b85e166c6e4fa63db1c13c (patch) | |
| tree | d59f5f151c73b2e2fc58612c5bf75161a2bb9429 /sys/dev/usb | |
| parent | 650e6b8b71d2b7611cfe19d8f670b35ebf0a28b7 (diff) | |
Fix error handling, to prevent kernel crashes at detach time. The code is
slightly reorganized. Found via vHCI.
Diffstat (limited to 'sys/dev/usb')
| -rw-r--r-- | sys/dev/usb/udl.c | 86 | ||||
| -rw-r--r-- | sys/dev/usb/udl.h | 8 |
2 files changed, 57 insertions, 37 deletions
diff --git a/sys/dev/usb/udl.c b/sys/dev/usb/udl.c index c7ba7bdd365..e5a7d6724d3 100644 --- a/sys/dev/usb/udl.c +++ b/sys/dev/usb/udl.c @@ -1,4 +1,4 @@ -/* $NetBSD: udl.c,v 1.22 2018/09/03 16:29:34 riastradh Exp $ */ +/* $NetBSD: udl.c,v 1.23 2019/09/14 15:24:23 maxv Exp $ */ /*- * Copyright (c) 2009 FUKAUMI Naoki. @@ -53,7 +53,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: udl.c,v 1.22 2018/09/03 16:29:34 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udl.c,v 1.23 2019/09/14 15:24:23 maxv Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -369,6 +369,7 @@ udl_attach(device_t parent, device_t self, void *aux) sc->sc_dev = self; sc->sc_udev = uaa->uaa_device; + sc->sc_init_state = UDL_INIT_NONE; devinfop = usbd_devinfo_alloc(sc->sc_udev, 0); aprint_normal_dev(sc->sc_dev, "%s\n", devinfop); @@ -399,9 +400,6 @@ udl_attach(device_t parent, device_t self, void *aux) if (error != USBD_NORMAL_COMPLETION) return; - /* - * Allocate bulk command queue. - */ #ifdef UDL_EVENT_COUNTERS evcnt_attach_dynamic(&sc->sc_ev_cmdq_get, EVCNT_TYPE_MISC, NULL, device_xname(sc->sc_dev), "udl_cmdq_get"); @@ -412,13 +410,16 @@ udl_attach(device_t parent, device_t self, void *aux) evcnt_attach_dynamic(&sc->sc_ev_cmdq_timeout, EVCNT_TYPE_MISC, NULL, device_xname(sc->sc_dev), "udl_cmdq_timeout"); #endif + cv_init(&sc->sc_cv, device_xname(sc->sc_dev)); + mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_TTY); /* XXX for tty_lock */ + sc->sc_init_state = UDL_INIT_MIDWAY; + /* + * Allocate bulk command queue. + */ if (udl_cmdq_alloc(sc) != 0) return; - cv_init(&sc->sc_cv, device_xname(sc->sc_dev)); - mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_TTY); /* XXX for tty_lock */ - if ((sc->sc_cmd_cur = udl_cmdq_get(sc)) == NULL) return; UDL_CMD_BUFINIT(sc); @@ -483,6 +484,8 @@ udl_attach(device_t parent, device_t self, void *aux) sc->sc_thread_stop = true; kthread_create(PRI_BIO, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL, udl_update_thread, sc, &sc->sc_thread, "udlupd"); + + sc->sc_init_state = UDL_INIT_INITED; } static int @@ -497,11 +500,13 @@ udl_detach(device_t self, int flags) usbd_abort_pipe(sc->sc_tx_pipeh); } - /* - * Free command xfer buffers. - */ - udl_cmdq_flush(sc); - udl_cmdq_free(sc); + if (sc->sc_init_state >= UDL_INIT_MIDWAY) { + /* + * Free command xfer buffers. + */ + udl_cmdq_flush(sc); + udl_cmdq_free(sc); + } if (sc->sc_tx_pipeh != NULL) { usbd_close_pipe(sc->sc_tx_pipeh); @@ -512,36 +517,45 @@ udl_detach(device_t self, int flags) */ udl_comp_unload(sc); - /* - * Free framebuffer memory. - */ - udl_fbmem_free(sc); + if (sc->sc_init_state >= UDL_INIT_INITED) { + /* + * Free framebuffer memory. + */ + udl_fbmem_free(sc); - mutex_enter(&sc->sc_thread_mtx); - sc->sc_dying = true; - cv_broadcast(&sc->sc_thread_cv); - mutex_exit(&sc->sc_thread_mtx); - kthread_join(sc->sc_thread); + mutex_enter(&sc->sc_thread_mtx); + sc->sc_dying = true; + cv_broadcast(&sc->sc_thread_cv); + mutex_exit(&sc->sc_thread_mtx); + kthread_join(sc->sc_thread); + cv_destroy(&sc->sc_thread_cv); + mutex_destroy(&sc->sc_thread_mtx); + } - cv_destroy(&sc->sc_cv); - mutex_destroy(&sc->sc_mtx); - cv_destroy(&sc->sc_thread_cv); - mutex_destroy(&sc->sc_thread_mtx); + if (sc->sc_init_state >= UDL_INIT_MIDWAY) { + cv_destroy(&sc->sc_cv); + mutex_destroy(&sc->sc_mtx); + } - /* - * Detach wsdisplay. - */ - if (sc->sc_wsdisplay != NULL) - config_detach(sc->sc_wsdisplay, DETACH_FORCE); + if (sc->sc_init_state >= UDL_INIT_INITED) { + /* + * Detach wsdisplay. + */ + if (sc->sc_wsdisplay != NULL) + config_detach(sc->sc_wsdisplay, DETACH_FORCE); - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, + sc->sc_dev); + } + if (sc->sc_init_state >= UDL_INIT_MIDWAY) { #ifdef UDL_EVENT_COUNTERS - evcnt_detach(&sc->sc_ev_cmdq_get); - evcnt_detach(&sc->sc_ev_cmdq_put); - evcnt_detach(&sc->sc_ev_cmdq_wait); - evcnt_detach(&sc->sc_ev_cmdq_timeout); + evcnt_detach(&sc->sc_ev_cmdq_get); + evcnt_detach(&sc->sc_ev_cmdq_put); + evcnt_detach(&sc->sc_ev_cmdq_wait); + evcnt_detach(&sc->sc_ev_cmdq_timeout); #endif + } return 0; } diff --git a/sys/dev/usb/udl.h b/sys/dev/usb/udl.h index 01499a64aa5..2cb7aed5af4 100644 --- a/sys/dev/usb/udl.h +++ b/sys/dev/usb/udl.h @@ -1,4 +1,4 @@ -/* $NetBSD: udl.h,v 1.4 2016/10/18 20:17:37 nat Exp $ */ +/* $NetBSD: udl.h,v 1.5 2019/09/14 15:24:23 maxv Exp $ */ /*- * Copyright (c) 2009 FUKAUMI Naoki. @@ -81,6 +81,12 @@ struct udl_softc { struct usbd_interface * sc_iface; struct usbd_pipe * sc_tx_pipeh; + enum { + UDL_INIT_NONE, + UDL_INIT_MIDWAY, + UDL_INIT_INITED + } sc_init_state; + struct udl_cmdq sc_cmdq[UDL_NCMDQ]; TAILQ_HEAD(udl_cmdq_head, udl_cmdq) sc_freecmd, sc_xfercmd; |
