DF-4753 / fix.diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | --- a/sys/dev/video/cxm/cxm.h +++ b/sys/dev/video/cxm/cxm.h @@ -37,6 +37,7 @@ */ #include <sys/event.h> +#include <sys/lock.h> #include "pcidevs.h" @@ -254,6 +255,7 @@ device_t dev; /* bus attachment */ cdev_t cxm_dev_t; /* control device */ + struct lock cxm_lock; /* serializes cdev entry vs detach */ int is_opened; int mpeg; --- a/sys/dev/video/cxm/cxm.c +++ b/sys/dev/video/cxm/cxm.c @@ -1880,6 +1880,7 @@ sc->source = cxm_tuner_source; + lockinit(&sc->cxm_lock, "cxm", 0, 0); /* make the device entries */ sc->cxm_dev_t = make_dev(&cxm_ops, unit, @@ -1957,6 +1958,14 @@ dev_ops_remove_minor(&cxm_ops, /*0, */device_get_unit(dev)); /* + * Drain any in-flight cdev operations (ioctls can sleep for + * ~0.5 s in the audio/video lock waits) before tearing down + * the softc they dereference. + */ + lockmgr(&sc->cxm_lock, LK_EXCLUSIVE); + lockmgr(&sc->cxm_lock, LK_RELEASE); + + /* * Deallocate scatter / gather list and buffers. */ bus_dmamap_unload(sc->enc_sg.dmat, sc->enc_sg.dmamap); @@ -2000,6 +2009,8 @@ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); bus_release_resource(dev, SYS_RES_MEMORY, CXM_RID, sc->mem_res); + lockuninit(&sc->cxm_lock); + return 0; } @@ -2155,11 +2166,15 @@ return ENXIO; } - if (sc->is_opened) + lockmgr(&sc->cxm_lock, LK_EXCLUSIVE); + if (sc->is_opened) { + lockmgr(&sc->cxm_lock, LK_RELEASE); return EBUSY; + } sc->is_opened = 1; sc->mpeg = 1; + lockmgr(&sc->cxm_lock, LK_RELEASE); /* Record that the device is now busy */ device_busy(devclass_get_device(cxm_devclass, unit)); @@ -2187,8 +2202,12 @@ return ENXIO; } - if (cxm_stop_encoder(sc) < 0) + lockmgr(&sc->cxm_lock, LK_EXCLUSIVE); + + if (cxm_stop_encoder(sc) < 0) { + lockmgr(&sc->cxm_lock, LK_RELEASE); return ENXIO; + } sc->enc_pool.offset = 0; sc->enc_pool.read = 0; @@ -2201,6 +2220,8 @@ sc->is_opened = 0; + lockmgr(&sc->cxm_lock, LK_RELEASE); + return 0; } @@ -2305,7 +2326,33 @@ static int cxm_ioctl(struct dev_ioctl_args *ap) { - cdev_t dev = ap->a_head.a_dev; + int unit; + struct cxm_softc *sc; + int error; + + unit = UNIT(minor(ap->a_head.a_dev)); + + /* Get the device data */ + sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit); + if (sc == NULL) { + /* the device is no longer valid/functioning */ + return ENXIO; + } + + /* + * Serialize against cxm_detach: the ioctl body may sleep + * (audio/video lock waits) while dereferencing sc. + */ + lockmgr(&sc->cxm_lock, LK_EXCLUSIVE); + error = cxm_ioctl_locked(ap, sc); + lockmgr(&sc->cxm_lock, LK_RELEASE); + + return error; +} + +static int +cxm_ioctl_locked(struct dev_ioctl_args *ap, struct cxm_softc *sc) +{ int brightness; int chroma_saturation; int contrast; @@ -2313,24 +2360,13 @@ int hue; int result; int status; - int unit; unsigned int i; unsigned int sig; unsigned long freq; - struct cxm_softc *sc; enum cxm_source source; struct bktr_capture_area *cap; struct bktr_remote *remote; - unit = UNIT(minor(dev)); - - /* Get the device data */ - sc = (struct cxm_softc*)devclass_get_softc(cxm_devclass, unit); - if (sc == NULL) { - /* the device is no longer valid/functioning */ - return ENXIO; - } - switch (ap->a_cmd) { case BT848_GAUDIO: switch (cxm_msp_selected_source(sc)) { |