--- a/sys/dev/agp/agppriv.h +++ b/sys/dev/agp/agppriv.h @@ -89,7 +89,7 @@ void agp_set_aperture_resource(device_t dev, int rid); int agp_generic_attach(device_t dev); -void agp_free_cdev(device_t dev); +int agp_free_cdev(device_t dev); void agp_free_res(device_t dev); int agp_generic_detach(device_t dev); --- a/sys/dev/agp/agp.c +++ b/sys/dev/agp/agp.c @@ -245,13 +245,27 @@ agp_generic_attach(device_t dev) return 0; } +/* + * Tear down the userland /dev/agpgart node. + * + * - Refuse while a client still has the device open: the cdev would + * outlive the softc and si_drv1 would point into freed memory + * (open fds keep their cdev reference across destroy_dev). + * - Destroy the node we actually made (minor 0, name "agpgart") via + * the stored as_devnode handle; dev_ops_remove_minor() matches by + * minor, not by device unit, so using device_get_unit() is wrong for + * any unit != 0 and would leave a dangling /dev/agpgart behind. + */ int -agp_free_cdev(device_t dev) +agp_free_cdev(device_t dev) { - dev_ops_remove_minor(&agp_ops, device_get_unit(dev)); + struct agp_softc *sc = device_get_softc(dev); + + if (sc->as_isopen) + return (EBUSY); + if (sc->as_devnode != NULL) { + destroy_dev(sc->as_devnode); + sc->as_devnode = NULL; + } + return (0); } void @@ -262,8 +276,11 @@ agp_free_res(device_t dev) int agp_generic_detach(device_t dev) { - agp_free_cdev(dev); + int error; + + if ((error = agp_free_cdev(dev)) != 0) + return (error); agp_free_res(dev); return 0; } --- a/sys/dev/agp/agp_via.c +++ b/sys/dev/agp/agp_via.c @@ -223,7 +223,8 @@ agp_via_detach(device_t dev) struct agp_via_softc *sc = device_get_softc(dev); - agp_free_cdev(dev); + if (agp_free_cdev(dev) != 0) + return (EBUSY); pci_write_config(dev, sc->regs[REG_GARTCTRL], 0, 4); --- a/sys/dev/agp/agp_sis.c +++ b/sys/dev/agp/agp_sis.c @@ -169,7 +169,8 @@ agp_sis_detach(device_t dev) struct agp_sis_softc *sc = device_get_softc(dev); - agp_free_cdev(dev); + if (agp_free_cdev(dev) != 0) + return (EBUSY); /* Disable the aperture.. */ --- a/sys/dev/agp/agp_amd64.c +++ b/sys/dev/agp/agp_amd64.c @@ -248,7 +248,8 @@ agp_amd64_detach(device_t dev) int i; - agp_free_cdev(dev); + if (agp_free_cdev(dev) != 0) + return (EBUSY); for (i = 0; i < sc->n_mctrl; i++) --- a/sys/dev/agp/intel-gtt.c +++ b/sys/dev/agp/intel-gtt.c @@ -911,7 +911,8 @@ agp_i810_detach(device_t dev) sc = device_get_softc(dev); - agp_free_cdev(dev); + if (agp_free_cdev(dev) != 0) + return (EBUSY); /* Clear the GATT base. */