From 444b91868b5294e3a2151fffa3b063763a562448 Mon Sep 17 00:00:00 2001 From: Attilio Rao Date: Sun, 2 Aug 2009 14:28:40 +0000 Subject: Make the newbus subsystem Giant free by adding the new newbus sxlock. The newbus lock is responsible for protecting newbus internIal structures, device states and devclass flags. It is necessary to hold it when all such datas are accessed. For the other operations, softc locking should ensure enough protection to avoid races. Newbus lock is automatically held when virtual operations on the device and bus are invoked when loading the driver or when the suspend/resume take place. For other 'spourious' operations trying to access/modify the newbus topology, newbus lock needs to be automatically acquired and dropped. For the moment Giant is also acquired in some key point (modules subsystem) in order to avoid problems before the 8.0 release as module handlers could make assumptions about it. This Giant locking should go just after the release happens. Please keep in mind that the public interface can be expanded in order to provide more support, if there are really necessities at some point and also some bugs could arise as long as the patch needs a bit of further testing. Bump __FreeBSD_version in order to reflect the newbus lock introduction. Reviewed by: ed, hps, jhb, imp, mav, scottl No answer by: ariff, thompsa, yongari Tested by: pho, G. Trematerra , Brandon Gooch Sponsored by: Yahoo! Incorporated Approved by: re (ksmith) --- sys/dev/aac/aac.c | 8 +-- sys/dev/acpica/acpi.c | 14 +----- sys/dev/acpica/acpi_battery.c | 15 ++++++ sys/dev/acpica/acpi_cpu.c | 2 + sys/dev/acpica/acpi_dock.c | 8 +-- sys/dev/acpica/acpi_thermal.c | 3 ++ sys/dev/adb/adb_bus.c | 2 + sys/dev/amdtemp/amdtemp.c | 2 + sys/dev/amr/amr.c | 23 ++++++++- sys/dev/ata/ata-all.c | 34 +++++++------ sys/dev/atkbdc/psm.c | 4 ++ sys/dev/bktr/bktr_os.c | 11 +++- sys/dev/drm/drm_drv.c | 8 +++ sys/dev/ips/ips_pci.c | 2 + sys/dev/mfi/mfi.c | 20 +++++--- sys/dev/mlx/mlx.c | 2 + sys/dev/mmc/mmc.c | 2 + sys/dev/pccbb/pccbb.c | 11 +--- sys/dev/pst/pst-iop.c | 2 + sys/dev/rp/rp.c | 4 ++ sys/dev/sound/pci/hda/hdac.c | 2 + sys/dev/twe/twe.c | 6 +++ sys/dev/usb/controller/usb_controller.c | 30 ++++------- sys/dev/usb/input/ukbd.c | 13 +++-- sys/dev/usb/net/usb_ethernet.c | 11 ++-- sys/dev/usb/usb_compat_linux.c | 27 +++------- sys/dev/usb/usb_dev.c | 6 +++ sys/dev/usb/usb_handle_request.c | 12 ++--- sys/dev/usb/usb_hub.c | 19 +++++-- sys/dev/usb/wlan/if_upgt.c | 4 +- sys/dev/xen/blkback/blkback.c | 4 +- sys/dev/xen/netback/netback.c | 4 +- sys/i386/acpica/acpi_machdep.c | 6 +++ sys/i386/bios/smapi.c | 2 + sys/i386/bios/smbios.c | 2 + sys/i386/bios/vpd.c | 2 + sys/kern/subr_bus.c | 89 ++++++++++++++++++++++++++++++--- sys/pc98/cbus/fdc.c | 6 +++ sys/sys/bus.h | 8 +++ sys/sys/param.h | 2 +- sys/xen/xenbus/xenbus_probe.c | 4 ++ 41 files changed, 304 insertions(+), 132 deletions(-) (limited to 'sys') diff --git a/sys/dev/aac/aac.c b/sys/dev/aac/aac.c index f3d931aaf06b..c576a3584e5a 100644 --- a/sys/dev/aac/aac.c +++ b/sys/dev/aac/aac.c @@ -3270,10 +3270,10 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) while (co != NULL) { if (co->co_found == 0) { mtx_unlock(&sc->aac_io_lock); - mtx_lock(&Giant); + newbus_xlock(); device_delete_child(sc->aac_dev, co->co_disk); - mtx_unlock(&Giant); + newbus_xunlock(); mtx_lock(&sc->aac_io_lock); co_next = TAILQ_NEXT(co, co_link); mtx_lock(&sc->aac_container_lock); @@ -3291,9 +3291,9 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) /* Attach the newly created containers */ if (added) { mtx_unlock(&sc->aac_io_lock); - mtx_lock(&Giant); + newbus_xlock(); bus_generic_attach(sc->aac_dev); - mtx_unlock(&Giant); + newbus_xunlock(); mtx_lock(&sc->aac_io_lock); } diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 63f95d3eb2c8..c3e4e521379a 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -675,8 +675,6 @@ acpi_suspend(device_t dev) device_t child, *devlist; int error, i, numdevs, pstate; - GIANT_REQUIRED; - /* First give child devices a chance to suspend. */ error = bus_generic_suspend(dev); if (error) @@ -719,8 +717,6 @@ acpi_resume(device_t dev) int i, numdevs, error; device_t child, *devlist; - GIANT_REQUIRED; - /* * Put all devices in D0 before resuming them. Call _S0D on each one * since some systems expect this. @@ -745,8 +741,6 @@ static int acpi_shutdown(device_t dev) { - GIANT_REQUIRED; - /* Allow children to shutdown first. */ bus_generic_shutdown(dev); @@ -2534,11 +2528,7 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state) thread_unlock(curthread); #endif - /* - * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE - * drivers need this. - */ - mtx_lock(&Giant); + newbus_xlock(); slp_state = ACPI_SS_NONE; @@ -2611,7 +2601,7 @@ backout: if (slp_state >= ACPI_SS_SLEPT) acpi_enable_fixed_events(sc); - mtx_unlock(&Giant); + newbus_xunlock(); #ifdef SMP thread_lock(curthread); diff --git a/sys/dev/acpica/acpi_battery.c b/sys/dev/acpica/acpi_battery.c index dd2b3fa20808..1ec1413d2264 100644 --- a/sys/dev/acpica/acpi_battery.c +++ b/sys/dev/acpica/acpi_battery.c @@ -329,6 +329,7 @@ acpi_battery_find_dev(u_int logical_unit) dev = NULL; found_unit = 0; + newbus_slock(); batt_dc = devclass_find("battery"); maxunit = devclass_get_maxunit(batt_dc); for (i = 0; i < maxunit; i++) { @@ -340,6 +341,7 @@ acpi_battery_find_dev(u_int logical_unit) found_unit++; dev = NULL; } + newbus_sunlock(); return (dev); } @@ -369,13 +371,17 @@ acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg) */ switch (cmd) { case ACPIIO_BATT_GET_UNITS: + newbus_slock(); *(int *)addr = acpi_battery_get_units(); + newbus_sunlock(); error = 0; break; case ACPIIO_BATT_GET_BATTINFO: if (dev != NULL || unit == ACPI_BATTERY_ALL_UNITS) { bzero(&ioctl_arg->battinfo, sizeof(ioctl_arg->battinfo)); + newbus_slock(); error = acpi_battery_get_battinfo(dev, &ioctl_arg->battinfo); + newbus_sunlock(); } break; case ACPIIO_BATT_GET_BIF: @@ -416,6 +422,11 @@ acpi_battery_sysctl(SYSCTL_HANDLER_ARGS) { int val, error; + /* + * Tolerate a race here because newbus lock can't be acquired before + * acpi_battery_get_battinfo() as it can create a LOR with the sysctl + * lock. + */ acpi_battery_get_battinfo(NULL, &acpi_battery_battinfo); val = *(u_int *)oidp->oid_arg1; error = sysctl_handle_int(oidp, &val, 0, req); @@ -427,6 +438,10 @@ acpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS) { int count, error; + /* + * Tolerate a race here in order to avoid a LOR between sysctl lock + * and newbus lock. + */ count = acpi_battery_get_units(); error = sysctl_handle_int(oidp, &count, 0, req); return (error); diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c index 5d8ad535998f..37134e23bf98 100644 --- a/sys/dev/acpica/acpi_cpu.c +++ b/sys/dev/acpica/acpi_cpu.c @@ -732,7 +732,9 @@ acpi_cpu_startup(void *arg) int i; /* Get set of CPU devices */ + newbus_slock(); devclass_get_devices(acpi_cpu_devclass, &cpu_devices, &cpu_ndevices); + newbus_sunlock(); /* * Setup any quirks that might necessary now that we have probed diff --git a/sys/dev/acpica/acpi_dock.c b/sys/dev/acpica/acpi_dock.c index b7d2e3e444a4..95b9faec1576 100644 --- a/sys/dev/acpica/acpi_dock.c +++ b/sys/dev/acpica/acpi_dock.c @@ -188,12 +188,12 @@ acpi_dock_attach_later(void *context) dev = (device_t)context; + newbus_xlock(); if (!device_is_enabled(dev)) device_enable(dev); - mtx_lock(&Giant); device_probe_and_attach(dev); - mtx_unlock(&Giant); + newbus_xunlock(); } static ACPI_STATUS @@ -299,11 +299,11 @@ acpi_dock_eject_child(ACPI_HANDLE handle, UINT32 level, void *context, "ejecting device for %s\n", acpi_name(handle)); dev = acpi_get_device(handle); + newbus_xlock(); if (dev != NULL && device_is_attached(dev)) { - mtx_lock(&Giant); device_detach(dev); - mtx_unlock(&Giant); } + newbus_xunlock(); acpi_SetInteger(handle, "_EJ0", 0); out: diff --git a/sys/dev/acpica/acpi_thermal.c b/sys/dev/acpica/acpi_thermal.c index 962fdb7e9388..1e58d529fd0c 100644 --- a/sys/dev/acpica/acpi_thermal.c +++ b/sys/dev/acpica/acpi_thermal.c @@ -936,6 +936,8 @@ acpi_tz_thread(void *arg) sc = NULL; for (;;) { + newbus_slock(); + /* If the number of devices has changed, re-evaluate. */ if (devclass_get_count(acpi_tz_devclass) != devcount) { if (devs != NULL) { @@ -948,6 +950,7 @@ acpi_tz_thread(void *arg) for (i = 0; i < devcount; i++) sc[i] = device_get_softc(devs[i]); } + newbus_sunlock(); /* Check for temperature events and act on them. */ for (i = 0; i < devcount; i++) { diff --git a/sys/dev/adb/adb_bus.c b/sys/dev/adb/adb_bus.c index faab048b52c9..c4a9c96ae9e8 100644 --- a/sys/dev/adb/adb_bus.c +++ b/sys/dev/adb/adb_bus.c @@ -113,6 +113,7 @@ adb_bus_enumerate(void *xdev) uint8_t i, next_free; uint16_t r3; + newbus_xlock(); sc->sc_dev = dev; sc->parent = device_get_parent(dev); @@ -187,6 +188,7 @@ adb_bus_enumerate(void *xdev) } bus_generic_attach(dev); + newbus_xunlock(); config_intrhook_disestablish(&sc->enum_hook); } diff --git a/sys/dev/amdtemp/amdtemp.c b/sys/dev/amdtemp/amdtemp.c index fdf087533c5f..ba7436aa57d2 100644 --- a/sys/dev/amdtemp/amdtemp.c +++ b/sys/dev/amdtemp/amdtemp.c @@ -269,6 +269,7 @@ amdtemp_intrhook(void *arg) /* * dev.cpu.N.temperature. */ + newbus_xlock(); nexus = device_find_child(root_bus, "nexus", 0); acpi = device_find_child(nexus, "acpi", 0); @@ -285,6 +286,7 @@ amdtemp_intrhook(void *arg) "Max of sensor 0 / 1"); } } + newbus_xunlock(); config_intrhook_disestablish(&sc->sc_ich); } diff --git a/sys/dev/amr/amr.c b/sys/dev/amr/amr.c index 2061fcc801f9..688b2df63ad7 100644 --- a/sys/dev/amr/amr.c +++ b/sys/dev/amr/amr.c @@ -90,6 +90,10 @@ __FBSDID("$FreeBSD$"); SYSCTL_NODE(_hw, OID_AUTO, amr, CTLFLAG_RD, 0, "AMR driver parameters"); +/* + * In order to get rid of Giant, amr_state should be protected by + * a proper softc lock for the cdev operations. + */ static d_open_t amr_open; static d_close_t amr_close; static d_ioctl_t amr_ioctl; @@ -312,9 +316,11 @@ amr_startup(void *arg) config_intrhook_disestablish(&sc->amr_ich); sc->amr_ich.ich_func = NULL; + newbus_xlock(); /* get up-to-date drive information */ if (amr_query_controller(sc)) { device_printf(sc->amr_dev, "can't scan controller for drives\n"); + newbus_xunlock(); return; } @@ -347,6 +353,7 @@ amr_startup(void *arg) /* interrupts will be enabled before we do anything more */ sc->amr_state |= AMR_STATE_INTEN; + newbus_xunlock(); /* * Start the timeout routine. @@ -434,7 +441,11 @@ static int amr_open(struct cdev *dev, int flags, int fmt, struct thread *td) { int unit = dev2unit(dev); - struct amr_softc *sc = devclass_get_softc(devclass_find("amr"), unit); + struct amr_softc *sc; + + newbus_slock(); + sc = devclass_get_softc(devclass_find("amr"), unit); + newbus_sunlock(); debug_called(1); @@ -490,7 +501,11 @@ static int amr_close(struct cdev *dev, int flags, int fmt, struct thread *td) { int unit = dev2unit(dev); - struct amr_softc *sc = devclass_get_softc(devclass_find("amr"), unit); + struct amr_softc *sc; + + newbus_slock(); + sc = devclass_get_softc(devclass_find("amr"), unit); + newbus_sunlock(); debug_called(1); @@ -507,6 +522,7 @@ amr_rescan_drives(struct cdev *dev) struct amr_softc *sc = (struct amr_softc *)dev->si_drv1; int i, error = 0; + newbus_xlock(); sc->amr_state |= AMR_STATE_REMAP_LD; while (sc->amr_busyslots) { device_printf(sc->amr_dev, "idle controller\n"); @@ -530,6 +546,7 @@ amr_rescan_drives(struct cdev *dev) sc->amr_drive[i].al_disk = 0; } } + newbus_xunlock(); shutdown_out: amr_startup(sc); @@ -805,7 +822,9 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, struct threa struct amr_linux_ioctl ali; int adapter, error; + newbus_slock(); devclass = devclass_find("amr"); + newbus_sunlock(); if (devclass == NULL) return (ENOENT); diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 1460a2117d4f..6696f0cff0c8 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$"); static d_ioctl_t ata_ioctl; static struct cdevsw ata_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, /* we need this as newbus isn't mpsafe */ .d_ioctl = ata_ioctl, .d_name = "ata", }; @@ -204,7 +203,9 @@ ata_conn_event(void *context, int dummy) { device_t dev = (device_t)context; + newbus_xlock(); ata_reinit(dev); + newbus_xunlock(); } int @@ -246,7 +247,6 @@ ata_reinit(device_t dev) /* reinit the children and delete any that fails */ if (!device_get_children(dev, &children, &nchildren)) { - mtx_lock(&Giant); /* newbus suckage it needs Giant */ for (i = 0; i < nchildren; i++) { /* did any children go missing ? */ if (children[i] && device_is_attached(children[i]) && @@ -269,7 +269,6 @@ ata_reinit(device_t dev) } } free(children, M_TEMP); - mtx_unlock(&Giant); /* newbus suckage dealt with, release Giant */ } /* if we still have a good request put it on the queue again */ @@ -395,6 +394,7 @@ ata_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int *value = (int *)data; int i, nchildren, error = ENOTTY; + newbus_xlock(); switch (cmd) { case IOCATAGMAXCHANNEL: /* In case we have channel 0..n this will return n+1. */ @@ -405,32 +405,40 @@ ata_ioctl(struct cdev *dev, u_long cmd, caddr_t data, case IOCATAREINIT: if (*value >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, *value)) || - !device_is_attached(device)) + !device_is_attached(device)) { + newbus_xunlock(); return ENXIO; + } error = ata_reinit(device); break; case IOCATAATTACH: if (*value >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, *value)) || - !device_is_attached(device)) + !device_is_attached(device)) { + newbus_xunlock(); return ENXIO; + } error = DEVICE_ATTACH(device); break; case IOCATADETACH: if (*value >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, *value)) || - !device_is_attached(device)) + !device_is_attached(device)) { + newbus_xunlock(); return ENXIO; + } error = DEVICE_DETACH(device); break; case IOCATADEVICES: if (devices->channel >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, devices->channel)) || - !device_is_attached(device)) + !device_is_attached(device)) { + newbus_xunlock(); return ENXIO; + } bzero(devices->name[0], 32); bzero(&devices->params[0], sizeof(struct ata_params)); bzero(devices->name[1], 32); @@ -465,6 +473,7 @@ ata_ioctl(struct cdev *dev, u_long cmd, caddr_t data, if (ata_raid_ioctl_func) error = ata_raid_ioctl_func(cmd, data); } + newbus_xunlock(); return error; } @@ -572,7 +581,7 @@ ata_boot_attach(void) struct ata_channel *ch; int ctlr; - mtx_lock(&Giant); /* newbus suckage it needs Giant */ + newbus_xlock(); /* kick of probe and attach on all channels */ for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) { @@ -587,8 +596,7 @@ ata_boot_attach(void) free(ata_delayed_attach, M_TEMP); ata_delayed_attach = NULL; } - - mtx_unlock(&Giant); /* newbus suckage dealt with, release Giant */ + newbus_xunlock(); } @@ -717,7 +725,6 @@ ata_identify(device_t dev) if (bootverbose) device_printf(dev, "Identifying devices: %08x\n", ch->devices); - mtx_lock(&Giant); /* Skip existing devices. */ if (!device_get_children(dev, &children, &nchildren)) { for (i = 0; i < nchildren; i++) { @@ -729,10 +736,8 @@ ata_identify(device_t dev) /* Create new devices. */ if (bootverbose) device_printf(dev, "New devices: %08x\n", n); - if (n == 0) { - mtx_unlock(&Giant); + if (n == 0) return (0); - } for (i = 0; i < ATA_PM; ++i) { if (n & (((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << i))) { int unit = -1; @@ -775,7 +780,6 @@ ata_identify(device_t dev) } bus_generic_probe(dev); bus_generic_attach(dev); - mtx_unlock(&Giant); return 0; } diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c index 93c9acb7a9c4..1fbdee76e25a 100644 --- a/sys/dev/atkbdc/psm.c +++ b/sys/dev/atkbdc/psm.c @@ -1488,7 +1488,9 @@ psmopen(struct cdev *dev, int flag, int fmt, struct thread *td) if (sc->state & PSM_OPEN) return (EBUSY); + newbus_xlock(); device_busy(devclass_get_device(psm_devclass, unit)); + newbus_xunlock(); /* Initialize state */ sc->mode.level = sc->dflt_mode.level; @@ -1643,7 +1645,9 @@ psmclose(struct cdev *dev, int flag, int fmt, struct thread *td) /* close is almost always successful */ sc->state &= ~PSM_OPEN; kbdc_lock(sc->kbdc, FALSE); + newbus_xlock(); device_unbusy(devclass_get_device(psm_devclass, unit)); + newbus_xunlock(); return (0); } diff --git a/sys/dev/bktr/bktr_os.c b/sys/dev/bktr/bktr_os.c index 327c4bbdb959..1fd458cd3c10 100644 --- a/sys/dev/bktr/bktr_os.c +++ b/sys/dev/bktr/bktr_os.c @@ -597,7 +597,9 @@ bktr_open( struct cdev *dev, int flags, int fmt, struct thread *td ) return( ENXIO ); /* Record that the device is now busy */ + newbus_xlock(); device_busy(devclass_get_device(bktr_devclass, unit)); + newbus_xunlock(); if (bt848_card != -1) { @@ -668,8 +670,11 @@ bktr_open( struct cdev *dev, int flags, int fmt, struct thread *td ) } /* If there was an error opening the device, undo the busy status */ - if (result != 0) + if (result != 0) { + newbus_xlock(); device_unbusy(devclass_get_device(bktr_devclass, unit)); + newbus_xunlock(); + } return( result ); } @@ -689,6 +694,7 @@ bktr_close( struct cdev *dev, int flags, int fmt, struct thread *td ) /* Get the device data */ bktr = (struct bktr_softc*)devclass_get_softc(bktr_devclass, unit); if (bktr == NULL) { + /* the device is no longer valid/functioning */ return (ENXIO); } @@ -705,10 +711,11 @@ bktr_close( struct cdev *dev, int flags, int fmt, struct thread *td ) break; default: return (ENXIO); - break; } + newbus_xlock(); device_unbusy(devclass_get_device(bktr_devclass, unit)); + newbus_xunlock(); return( result ); } diff --git a/sys/dev/drm/drm_drv.c b/sys/dev/drm/drm_drv.c index 561afd5e8fb9..e12f8cdfa92d 100644 --- a/sys/dev/drm/drm_drv.c +++ b/sys/dev/drm/drm_drv.c @@ -614,11 +614,13 @@ int drm_open(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p) if (!retcode) { atomic_inc(&dev->counts[_DRM_STAT_OPENS]); + newbus_xlock(); DRM_LOCK(); device_busy(dev->device); if (!dev->open_count++) retcode = drm_firstopen(dev); DRM_UNLOCK(); + newbus_xunlock(); } return retcode; @@ -632,6 +634,11 @@ void drm_close(void *data) DRM_DEBUG("open_count = %d\n", dev->open_count); + /* + * We require to lock newbus here for handling device_unbusy() and + * avoid a LOR with DRM_LOCK. + */ + newbus_xlock(); DRM_LOCK(); if (dev->driver->preclose != NULL) @@ -708,6 +715,7 @@ void drm_close(void *data) } DRM_UNLOCK(); + newbus_xunlock(); } /* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. diff --git a/sys/dev/ips/ips_pci.c b/sys/dev/ips/ips_pci.c index 9ccaf373b3e2..70e7d3be068c 100644 --- a/sys/dev/ips/ips_pci.c +++ b/sys/dev/ips/ips_pci.c @@ -173,10 +173,12 @@ ips_intrhook(void *arg) struct ips_softc *sc = (struct ips_softc *)arg; config_intrhook_disestablish(&sc->ips_ich); + newbus_xlock(); if (ips_adapter_init(sc)) ips_pci_free(sc); else sc->configured = 1; + newbus_xunlock(); } static int ips_pci_free(ips_softc_t *sc) diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c index eb18ffe4ce35..0ae585e892df 100644 --- a/sys/dev/mfi/mfi.c +++ b/sys/dev/mfi/mfi.c @@ -1327,11 +1327,11 @@ mfi_add_ld_complete(struct mfi_command *cm) mfi_release_command(cm); mtx_unlock(&sc->mfi_io_lock); - mtx_lock(&Giant); + newbus_xlock(); if ((child = device_add_child(sc->mfi_dev, "mfid", -1)) == NULL) { device_printf(sc->mfi_dev, "Failed to add logical disk\n"); free(ld_info, M_MFIBUF); - mtx_unlock(&Giant); + newbus_xunlock(); mtx_lock(&sc->mfi_io_lock); return; } @@ -1339,7 +1339,7 @@ mfi_add_ld_complete(struct mfi_command *cm) device_set_ivars(child, ld_info); device_set_desc(child, "MFI Logical Disk"); bus_generic_attach(sc->mfi_dev); - mtx_unlock(&Giant); + newbus_xunlock(); mtx_lock(&sc->mfi_io_lock); } @@ -1805,9 +1805,9 @@ mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) KASSERT(ld != NULL, ("volume dissappeared")); if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { mtx_unlock(&sc->mfi_io_lock); - mtx_lock(&Giant); + newbus_xlock(); device_delete_child(sc->mfi_dev, ld->ld_dev); - mtx_unlock(&Giant); + newbus_xunlock(); mtx_lock(&sc->mfi_io_lock); } else mfi_disk_enable(ld); @@ -1815,11 +1815,11 @@ mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) case MFI_DCMD_CFG_CLEAR: if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) { mtx_unlock(&sc->mfi_io_lock); - mtx_lock(&Giant); + newbus_xlock(); TAILQ_FOREACH_SAFE(ld, &sc->mfi_ld_tqh, ld_link, ldn) { device_delete_child(sc->mfi_dev, ld->ld_dev); } - mtx_unlock(&Giant); + newbus_xunlock(); mtx_lock(&sc->mfi_io_lock); } else { TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) @@ -1985,7 +1985,9 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td adapter = ioc->mfi_adapter_no; if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) { + newbus_slock(); devclass = devclass_find("mfi"); + newbus_sunlock(); sc = devclass_get_softc(devclass, adapter); } mtx_lock(&sc->mfi_io_lock); @@ -2173,7 +2175,9 @@ out: struct mfi_linux_ioc_packet l_ioc; int adapter; + newbus_slock(); devclass = devclass_find("mfi"); + newbus_sunlock(); if (devclass == NULL) return (ENOENT); @@ -2194,7 +2198,9 @@ out: struct mfi_linux_ioc_aen l_aen; int adapter; + newbus_slock(); devclass = devclass_find("mfi"); + newbus_sunlock(); if (devclass == NULL) return (ENOENT); diff --git a/sys/dev/mlx/mlx.c b/sys/dev/mlx/mlx.c index 6087216901fd..9e74f6245733 100644 --- a/sys/dev/mlx/mlx.c +++ b/sys/dev/mlx/mlx.c @@ -772,7 +772,9 @@ mlx_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, struct threa * Scan the controller to see whether new drives have appeared. */ case MLX_RESCAN_DRIVES: + newbus_xlock(); mlx_startup(sc); + newbus_xunlock(); return(0); /* diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c index 68726675f81c..0fd424dbaf48 100644 --- a/sys/dev/mmc/mmc.c +++ b/sys/dev/mmc/mmc.c @@ -1496,7 +1496,9 @@ mmc_delayed_attach(void *xsc) { struct mmc_softc *sc = xsc; + newbus_xlock(); mmc_scan(sc); + newbus_xunlock(); config_intrhook_disestablish(&sc->config_intrhook); } diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c index a0585b00b8ea..f60118528ff8 100644 --- a/sys/dev/pccbb/pccbb.c +++ b/sys/dev/pccbb/pccbb.c @@ -464,14 +464,7 @@ cbb_event_thread(void *arg) sc->flags |= CBB_KTHREAD_RUNNING; while ((sc->flags & CBB_KTHREAD_DONE) == 0) { mtx_unlock(&sc->mtx); - /* - * We take out Giant here because we need it deep, - * down in the bowels of the vm system for mapping the - * memory we need to read the CIS. In addition, since - * we are adding/deleting devices from the dev tree, - * and that code isn't MP safe, we have to hold Giant. - */ - mtx_lock(&Giant); + newbus_xlock(); status = cbb_get(sc, CBB_SOCKET_STATE); DPRINTF(("Status is 0x%x\n", status)); if (!CBB_CARD_PRESENT(status)) { @@ -497,7 +490,7 @@ cbb_event_thread(void *arg) not_a_card = 0; /* We know card type */ cbb_insert(sc); } - mtx_unlock(&Giant); + newbus_xunlock(); /* * First time through we need to tell mountroot that we're diff --git a/sys/dev/pst/pst-iop.c b/sys/dev/pst/pst-iop.c index d4e83f01ecbe..3fa37fdbfd31 100644 --- a/sys/dev/pst/pst-iop.c +++ b/sys/dev/pst/pst-iop.c @@ -152,7 +152,9 @@ iop_attach(void *arg) break; case I2O_CLASS_RANDOM_BLOCK_STORAGE: + newbus_xlock(); pst_add_raid(sc, &sc->lct[i]); + newbus_xunlock(); break; } } diff --git a/sys/dev/rp/rp.c b/sys/dev/rp/rp.c index 520ca80f9301..45f59d37304b 100644 --- a/sys/dev/rp/rp.c +++ b/sys/dev/rp/rp.c @@ -903,7 +903,9 @@ rpopen(struct tty *tp) rp_callout_handle = timeout(rp_do_poll, (void *)NULL, POLL_INTERVAL); + newbus_xlock(); device_busy(rp->rp_ctlp->dev); + newbus_xunlock(); return(0); } @@ -914,7 +916,9 @@ rpclose(struct tty *tp) rp = tty_softc(tp); rphardclose(tp); + newbus_xlock(); device_unbusy(rp->rp_ctlp->dev); + newbus_xunlock(); } static void diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c index 9f4264d98ec0..bf99d54ea1f9 100644 --- a/sys/dev/sound/pci/hda/hdac.c +++ b/sys/dev/sound/pci/hda/hdac.c @@ -7435,6 +7435,7 @@ hdac_attach2(void *arg) quirks_on, quirks_off); ); + newbus_xlock(); hdac_lock(sc); /* Remove ourselves from the config hooks */ @@ -7674,6 +7675,7 @@ hdac_attach2(void *arg) SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), sysctl_hdac_pindump, "I", "Dump pin states/data"); + newbus_xunlock(); } /**************************************************************************** diff --git a/sys/dev/twe/twe.c b/sys/dev/twe/twe.c index 59b5027adac9..2641fae5e852 100644 --- a/sys/dev/twe/twe.c +++ b/sys/dev/twe/twe.c @@ -294,8 +294,10 @@ twe_init(struct twe_softc *sc) /* * Scan for drives */ + newbus_xlock(); for (i = 0; i < TWE_MAX_UNITS; i++) twe_add_unit(sc, i); + newbus_xunlock(); /* * Initialise connection with controller. @@ -621,11 +623,15 @@ twe_ioctl(struct twe_softc *sc, int ioctlcmd, void *addr) break; case TWEIO_ADD_UNIT: + newbus_xlock(); error = twe_add_unit(sc, td->td_unit); + newbus_xunlock(); break; case TWEIO_DEL_UNIT: + newbus_xlock(); error = twe_del_unit(sc, td->td_unit); + newbus_xunlock(); break; /* XXX implement ATA PASSTHROUGH */ diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c index 7a019dcaa7ac..f6776f01a4c5 100644 --- a/sys/dev/usb/controller/usb_controller.c +++ b/sys/dev/usb/controller/usb_controller.c @@ -143,9 +143,7 @@ usb_attach(device_t dev) } if (usb_post_init_called) { - mtx_lock(&Giant); usb_attach_sub(dev, bus); - mtx_unlock(&Giant); usb_needs_explore(bus, 1); } return (0); /* return success */ @@ -228,20 +226,13 @@ usb_bus_explore(struct usb_proc_msg *pm) } USB_BUS_UNLOCK(bus); - mtx_lock(&Giant); - /* * First update the USB power state! */ usb_bus_powerd(bus); - /* - * Explore the Root USB HUB. This call can sleep, - * exiting Giant, which is actually Giant. - */ - (udev->hub->explore) (udev); - - mtx_unlock(&Giant); + /* Explore the Root USB HUB. */ + (udev->hub->explore) (udev); USB_BUS_LOCK(bus); } if (bus->bus_roothold != NULL) { @@ -269,7 +260,7 @@ usb_bus_detach(struct usb_proc_msg *pm) device_set_softc(dev, NULL); USB_BUS_UNLOCK(bus); - mtx_lock(&Giant); + newbus_xlock(); /* detach children first */ bus_generic_detach(dev); @@ -281,7 +272,7 @@ usb_bus_detach(struct usb_proc_msg *pm) usb_free_device(udev, USB_UNCFG_FLAG_FREE_EP0); - mtx_unlock(&Giant); + newbus_xunlock(); USB_BUS_LOCK(bus); /* clear bdev variable last */ bus->bdev = NULL; @@ -350,7 +341,7 @@ usb_bus_attach(struct usb_proc_msg *pm) } USB_BUS_UNLOCK(bus); - mtx_lock(&Giant); /* XXX not required by USB */ + newbus_xlock(); /* default power_mask value */ bus->hw_power_state = @@ -383,7 +374,7 @@ usb_bus_attach(struct usb_proc_msg *pm) err = USB_ERR_NOMEM; } - mtx_unlock(&Giant); + newbus_xunlock(); USB_BUS_LOCK(bus); if (err) { @@ -472,7 +463,7 @@ usb_post_init(void *arg) int max; int n; - mtx_lock(&Giant); + newbus_xlock(); usb_devclass_ptr = devclass_find("usbus"); @@ -483,11 +474,8 @@ usb_post_init(void *arg) dev = devclass_get_device(dc, n); if (dev && device_is_attached(dev)) { bus = device_get_ivars(dev); - if (bus) { - mtx_lock(&Giant); + if (bus) usb_attach_sub(dev, bus); - mtx_unlock(&Giant); - } } } } else { @@ -499,7 +487,7 @@ usb_post_init(void *arg) usb_needs_explore_all(); - mtx_unlock(&Giant); + newbus_xunlock(); } SYSINIT(usb_post_init, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, usb_post_init, NULL); diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c index 0d09ad43783a..2170b3700160 100644 --- a/sys/dev/usb/input/ukbd.c +++ b/sys/dev/usb/input/ukbd.c @@ -745,7 +745,7 @@ ukbd_attach(device_t dev) uint16_t n; uint16_t hid_len; - mtx_assert(&Giant, MA_OWNED); + mtx_lock(&Giant); kbd_init_struct(kbd, UKBD_DRIVER_NAME, KB_OTHER, unit, 0, 0, 0); @@ -854,9 +854,6 @@ ukbd_attach(device_t dev) if (bootverbose) { genkbd_diag(kbd, bootverbose); } - /* lock keyboard mutex */ - - mtx_lock(&Giant); /* start the keyboard */ @@ -879,7 +876,7 @@ ukbd_detach(device_t dev) struct ukbd_softc *sc = device_get_softc(dev); int error; - mtx_assert(&Giant, MA_OWNED); + mtx_lock(&Giant); DPRINTF("\n"); @@ -916,6 +913,8 @@ ukbd_detach(device_t dev) usb_callout_drain(&sc->sc_callout); + mtx_unlock(&Giant); + DPRINTF("%s: disconnected\n", device_get_nameunit(dev)); @@ -927,9 +926,9 @@ ukbd_resume(device_t dev) { struct ukbd_softc *sc = device_get_softc(dev); - mtx_assert(&Giant, MA_OWNED); - + mtx_lock(&Giant); ukbd_clear_state(&sc->sc_kbd); + mtx_unlock(&Giant); return (0); } diff --git a/sys/dev/usb/net/usb_ethernet.c b/sys/dev/usb/net/usb_ethernet.c index 6cf446016e75..427137a92f26 100644 --- a/sys/dev/usb/net/usb_ethernet.c +++ b/sys/dev/usb/net/usb_ethernet.c @@ -221,10 +221,10 @@ ue_attach_post_task(struct usb_proc_msg *_task) if (ue->ue_methods->ue_mii_upd != NULL && ue->ue_methods->ue_mii_sts != NULL) { - mtx_lock(&Giant); /* device_xxx() depends on this */ + newbus_xlock(); error = mii_phy_probe(ue->ue_dev, &ue->ue_miibus, ue_ifmedia_upd, ue->ue_methods->ue_mii_sts); - mtx_unlock(&Giant); + newbus_xunlock(); if (error) { device_printf(ue->ue_dev, "MII without any PHY\n"); goto error; @@ -279,9 +279,12 @@ uether_ifdetach(struct usb_ether *ue) /* detach miibus */ if (ue->ue_miibus != NULL) { - mtx_lock(&Giant); /* device_xxx() depends on this */ + + /* + * It is up to the callers to provide the correct + * newbus locking. + */ device_delete_child(ue->ue_dev, ue->ue_miibus); - mtx_unlock(&Giant); } /* detach ethernet */ diff --git a/sys/dev/usb/usb_compat_linux.c b/sys/dev/usb/usb_compat_linux.c index 604ac4d88458..00fc86bdc988 100644 --- a/sys/dev/usb/usb_compat_linux.c +++ b/sys/dev/usb/usb_compat_linux.c @@ -215,14 +215,12 @@ usb_linux_probe(device_t dev) if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } - mtx_lock(&Giant); LIST_FOREACH(udrv, &usb_linux_driver_list, linux_driver_list) { if (usb_linux_lookup_id(udrv->id_table, uaa)) { err = 0; break; } } - mtx_unlock(&Giant); return (err); } @@ -239,9 +237,7 @@ usb_linux_get_usb_driver(struct usb_linux_softc *sc) { struct usb_driver *udrv; - mtx_lock(&Giant); udrv = sc->sc_udrv; - mtx_unlock(&Giant); return (udrv); } @@ -260,13 +256,11 @@ usb_linux_attach(device_t dev) struct usb_driver *udrv; const struct usb_device_id *id = NULL; - mtx_lock(&Giant); LIST_FOREACH(udrv, &usb_linux_driver_list, linux_driver_list) { id = usb_linux_lookup_id(udrv->id_table, uaa); if (id) break; } - mtx_unlock(&Giant); if (id == NULL) { return (ENXIO); @@ -287,9 +281,7 @@ usb_linux_attach(device_t dev) return (ENXIO); } } - mtx_lock(&Giant); LIST_INSERT_HEAD(&usb_linux_attached_list, sc, sc_attached_list); - mtx_unlock(&Giant); /* success */ return (0); @@ -307,14 +299,12 @@ usb_linux_detach(device_t dev) struct usb_linux_softc *sc = device_get_softc(dev); struct usb_driver *udrv = NULL; - mtx_lock(&Giant); if (sc->sc_attached_list.le_prev) { LIST_REMOVE(sc, sc_attached_list); sc->sc_attached_list.le_prev = NULL; udrv = sc->sc_udrv; sc->sc_udrv = NULL; } - mtx_unlock(&Giant); if (udrv && udrv->disconnect) { (udrv->disconnect) (sc->sc_ui); @@ -474,13 +464,10 @@ usb_unlink_bsd(struct usb_xfer *xfer, if (!usbd_transfer_pending(xfer)) return; if (xfer->priv_fifo == (void *)urb) { - if (drain) { - mtx_unlock(&Giant); + if (drain) usbd_transfer_drain(xfer); - mtx_lock(&Giant); - } else { + else usbd_transfer_stop(xfer); - } usbd_transfer_start(xfer); } } @@ -1148,9 +1135,9 @@ usb_linux_register(void *arg) { struct usb_driver *drv = arg; - mtx_lock(&Giant); + newbus_xlock(); LIST_INSERT_HEAD(&usb_linux_driver_list, drv, linux_driver_list); - mtx_unlock(&Giant); + newbus_xunlock(); usb_needs_explore_all(); } @@ -1172,16 +1159,16 @@ usb_linux_deregister(void *arg) struct usb_linux_softc *sc; repeat: - mtx_lock(&Giant); + newbus_xlock(); LIST_FOREACH(sc, &usb_linux_attached_list, sc_attached_list) { if (sc->sc_udrv == drv) { - mtx_unlock(&Giant); device_detach(sc->sc_fbsd_dev); + newbus_xunlock(); goto repeat; } } LIST_REMOVE(drv, linux_driver_list); - mtx_unlock(&Giant); + newbus_xunlock(); } /*------------------------------------------------------------------------* diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index cba8919255c8..b7c6553db75c 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -1040,9 +1040,14 @@ usb_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int fflag, struct thread* * Performance optimisation: We try to check for IOCTL's that * don't need the USB reference first. Then we grab the USB * reference if we need it! + * Note that some ioctl_post handlers would need to run with the + * newbus lock held. It cannot be acquired later because it can + * introduce a LOR, so acquire it here. */ + newbus_xlock(); err = usb_ref_device(cpd, &refs, 0 /* no uref */ ); if (err) { + newbus_xunlock(); return (ENXIO); } fflags = cpd->fflags; @@ -1076,6 +1081,7 @@ usb_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int fflag, struct thread* } done: usb_unref_device(cpd, &refs); + newbus_xunlock(); return (err); } diff --git a/sys/dev/usb/usb_handle_request.c b/sys/dev/usb/usb_handle_request.c index a720919b7d80..2bc3eefd210e 100644 --- a/sys/dev/usb/usb_handle_request.c +++ b/sys/dev/usb/usb_handle_request.c @@ -152,7 +152,7 @@ usb_handle_set_config(struct usb_xfer *xfer, uint8_t conf_no) * attach: */ USB_XFER_UNLOCK(xfer); - mtx_lock(&Giant); /* XXX */ + newbus_xlock(); sx_xlock(udev->default_sx + 1); if (conf_no == USB_UNCONFIG_NO) { @@ -176,8 +176,8 @@ usb_handle_set_config(struct usb_xfer *xfer, uint8_t conf_no) goto done; } done: - mtx_unlock(&Giant); /* XXX */ sx_unlock(udev->default_sx + 1); + newbus_xunlock(); USB_XFER_LOCK(xfer); return (err); } @@ -236,7 +236,7 @@ usb_handle_iface_request(struct usb_xfer *xfer, * attach: */ USB_XFER_UNLOCK(xfer); - mtx_lock(&Giant); /* XXX */ + newbus_xlock(); sx_xlock(udev->default_sx + 1); error = ENXIO; @@ -353,20 +353,20 @@ tr_repeat: goto tr_stalled; } tr_valid: - mtx_unlock(&Giant); sx_unlock(udev->default_sx + 1); + newbus_xunlock(); USB_XFER_LOCK(xfer); return (0); tr_short: - mtx_unlock(&Giant); sx_unlock(udev->default_sx + 1); + newbus_xunlock(); USB_XFER_LOCK(xfer); return (USB_ERR_SHORT_XFER); tr_stalled: - mtx_unlock(&Giant); sx_unlock(udev->default_sx + 1); + newbus_xunlock(); USB_XFER_LOCK(xfer); return (USB_ERR_STALLED); } diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c index 0defc97c30c9..a09be96b8e4b 100644 --- a/sys/dev/usb/usb_hub.c +++ b/sys/dev/usb/usb_hub.c @@ -234,8 +234,10 @@ uhub_explore_sub(struct uhub_softc *sc, struct usb_port *up) if (child->driver_added_refcount != refcount) { child->driver_added_refcount = refcount; + newbus_xlock(); err = usb_probe_and_attach(child, USB_IFACE_INDEX_ANY); + newbus_xunlock(); if (err) { goto done; } @@ -318,9 +320,11 @@ repeat: /* detach any existing devices */ if (child) { + newbus_xlock(); usb_free_device(child, USB_UNCFG_FLAG_FREE_SUBDEV | USB_UNCFG_FLAG_FREE_EP0); + newbus_xunlock(); child = NULL; } /* get fresh status */ @@ -428,9 +432,10 @@ repeat: mode = USB_MODE_HOST; /* need to create a new child */ - + newbus_xlock(); child = usb_alloc_device(sc->sc_dev, udev->bus, udev, udev->depth + 1, portno - 1, portno, speed, mode); + newbus_xunlock(); if (child == NULL) { DPRINTFN(0, "could not allocate new device!\n"); goto error; @@ -439,9 +444,11 @@ repeat: error: if (child) { + newbus_xlock(); usb_free_device(child, USB_UNCFG_FLAG_FREE_SUBDEV | USB_UNCFG_FLAG_FREE_EP0); + newbus_xunlock(); child = NULL; } if (err == 0) { @@ -980,7 +987,6 @@ uhub_child_location_string(device_t parent, device_t child, struct usb_hub *hub = sc->sc_udev->hub; struct hub_result res; - mtx_lock(&Giant); uhub_find_iface_index(hub, child, &res); if (!res.udev) { DPRINTF("device not on hub\n"); @@ -992,7 +998,6 @@ uhub_child_location_string(device_t parent, device_t child, snprintf(buf, buflen, "port=%u interface=%u", res.portno, res.iface_index); done: - mtx_unlock(&Giant); return (0); } @@ -1006,7 +1011,6 @@ uhub_child_pnpinfo_string(device_t parent, device_t child, struct usb_interface *iface; struct hub_result res; - mtx_lock(&Giant); uhub_find_iface_index(hub, child, &res); if (!res.udev) { DPRINTF("device not on hub\n"); @@ -1037,7 +1041,6 @@ uhub_child_pnpinfo_string(device_t parent, device_t child, goto done; } done: - mtx_unlock(&Giant); return (0); } @@ -1775,10 +1778,13 @@ usb_dev_resume_peer(struct usb_device *udev) /* always update hardware power! */ (bus->methods->set_hw_power) (bus); } + newbus_xlock(); sx_xlock(udev->default_sx + 1); + /* notify all sub-devices about resume */ err = usb_suspend_resume(udev, 0); sx_unlock(udev->default_sx + 1); + newbus_xunlock(); /* check if peer has wakeup capability */ if (usb_peer_can_wakeup(udev)) { @@ -1844,10 +1850,13 @@ repeat: } } + newbus_xlock(); sx_xlock(udev->default_sx + 1); + /* notify all sub-devices about suspend */ err = usb_suspend_resume(udev, 1); sx_unlock(udev->default_sx + 1); + newbus_xunlock(); if (usb_peer_can_wakeup(udev)) { /* allow device to do remote wakeup */ diff --git a/sys/dev/usb/wlan/if_upgt.c b/sys/dev/usb/wlan/if_upgt.c index ff3220b716fd..8714645450e3 100644 --- a/sys/dev/usb/wlan/if_upgt.c +++ b/sys/dev/usb/wlan/if_upgt.c @@ -465,7 +465,7 @@ upgt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) switch (cmd) { case SIOCSIFFLAGS: - mtx_lock(&Giant); + newbus_xlock(); if (ifp->if_flags & IFF_UP) { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { if ((ifp->if_flags ^ sc->sc_if_flags) & @@ -482,7 +482,7 @@ upgt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) sc->sc_if_flags = ifp->if_flags; if (startall) ieee80211_start_all(ic); - mtx_unlock(&Giant); + newbus_xunlock(); break; case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); diff --git a/sys/dev/xen/blkback/blkback.c b/sys/dev/xen/blkback/blkback.c index 259f2f6c0418..535b1e078bc0 100644 --- a/sys/dev/xen/blkback/blkback.c +++ b/sys/dev/xen/blkback/blkback.c @@ -1156,7 +1156,7 @@ vbd_add_dev(struct xenbus_device *xdev) devclass_t dc; int err = 0; - mtx_lock(&Giant); + newbus_xlock(); /* We will add a vbd device as a child of nexus0 (for now) */ if (!(dc = devclass_find("nexus")) || @@ -1183,7 +1183,7 @@ vbd_add_dev(struct xenbus_device *xdev) done: - mtx_unlock(&Giant); + newbus_xunlock(); return err; } diff --git a/sys/dev/xen/netback/netback.c b/sys/dev/xen/netback/netback.c index a6111e265f58..cabc4ab72414 100644 --- a/sys/dev/xen/netback/netback.c +++ b/sys/dev/xen/netback/netback.c @@ -1388,7 +1388,7 @@ vif_add_dev(struct xenbus_device *xdev) devclass_t dc; int err = 0; - mtx_lock(&Giant); + newbus_xlock(); /* We will add a vif device as a child of nexus0 (for now) */ if (!(dc = devclass_find("nexus")) || @@ -1415,7 +1415,7 @@ vif_add_dev(struct xenbus_device *xdev) done: - mtx_unlock(&Giant); + newbus_xunlock(); return err; } diff --git a/sys/i386/acpica/acpi_machdep.c b/sys/i386/acpica/acpi_machdep.c index e26cce9a7297..456867123b17 100644 --- a/sys/i386/acpica/acpi_machdep.c +++ b/sys/i386/acpica/acpi_machdep.c @@ -164,6 +164,7 @@ acpi_capm_get_info(apm_info_t aip) else aip->ai_acline = acline; /* on/off */ + newbus_slock(); if (acpi_battery_get_battinfo(NULL, &batt) != 0) { aip->ai_batt_stat = APM_UNKNOWN; aip->ai_batt_life = APM_UNKNOWN; @@ -175,6 +176,7 @@ acpi_capm_get_info(apm_info_t aip) aip->ai_batt_time = (batt.min == -1) ? -1 : batt.min * 60; aip->ai_batteries = acpi_battery_get_units(); } + newbus_sunlock(); return (0); } @@ -190,6 +192,7 @@ acpi_capm_get_pwstatus(apm_pwstatus_t app) (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) return (1); + newbus_slock(); if (app->ap_device == PMDV_ALLDEV) error = acpi_battery_get_battinfo(NULL, &batt); else { @@ -200,6 +203,7 @@ acpi_capm_get_pwstatus(apm_pwstatus_t app) else error = ENXIO; } + newbus_sunlock(); if (error) return (1); @@ -283,7 +287,9 @@ apmopen(struct cdev *dev, int flag, int fmt, struct thread *td) struct acpi_softc *acpi_sc; struct apm_clone_data *clone; + newbus_slock(); acpi_sc = devclass_get_softc(devclass_find("acpi"), 0); + newbus_sunlock(); clone = apm_create_clone(dev, acpi_sc); dev->si_drv1 = clone; diff --git a/sys/i386/bios/smapi.c b/sys/i386/bios/smapi.c index e572664e2aca..74cf612182ae 100644 --- a/sys/i386/bios/smapi.c +++ b/sys/i386/bios/smapi.c @@ -288,10 +288,12 @@ smapi_modevent (module_t mod, int what, void *arg) case MOD_LOAD: break; case MOD_UNLOAD: + newbus_xlock(); devclass_get_devices(smapi_devclass, &devs, &count); for (i = 0; i < count; i++) { device_delete_child(device_get_parent(devs[i]), devs[i]); } + newbus_xunlock(); break; default: break; diff --git a/sys/i386/bios/smbios.c b/sys/i386/bios/smbios.c index f38d98573993..37a3b2cd092f 100644 --- a/sys/i386/bios/smbios.c +++ b/sys/i386/bios/smbios.c @@ -230,10 +230,12 @@ smbios_modevent (mod, what, arg) case MOD_LOAD: break; case MOD_UNLOAD: + newbus_xlock(); devclass_get_devices(smbios_devclass, &devs, &count); for (i = 0; i < count; i++) { device_delete_child(device_get_parent(devs[i]), devs[i]); } + newbus_xunlock(); break; default: break; diff --git a/sys/i386/bios/vpd.c b/sys/i386/bios/vpd.c index 246b76d35702..f816121260fe 100644 --- a/sys/i386/bios/vpd.c +++ b/sys/i386/bios/vpd.c @@ -248,10 +248,12 @@ vpd_modevent (mod, what, arg) case MOD_LOAD: break; case MOD_UNLOAD: + newbus_xlock(); devclass_get_devices(vpd_devclass, &devs, &count); for (i = 0; i < count; i++) { device_delete_child(device_get_parent(devs[i]), devs[i]); } + newbus_xunlock(); break; default: break; diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index 2964b8c1a225..67f09182d5f1 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -191,6 +192,54 @@ void print_devclass_list(void); #define print_devclass_list() /* nop */ #endif +/* + * Newbus locking facilities. + */ +static struct sx newbus_lock; + +#define NBL_LOCK_INIT() sx_init(&newbus_lock, "newbus") +#define NBL_LOCK_DESTROY() sx_destroy(&newbus_lock) +#define NBL_XLOCK() sx_xlock(&newbus_lock) +#define NBL_SLOCK() sx_slock(&newbus_lock) +#define NBL_XUNLOCK() sx_xunlock(&newbus_lock) +#define NBL_SUNLOCK() sx_sunlock(&newbus_lock) +#ifdef INVARIANTS +#define NBL_ASSERT(what) do { \ + if (cold == 0) \ + sx_assert(&newbus_lock, (what)); \ +} while (0) +#else +#define NBL_ASSERT(what) +#endif + +void +newbus_xlock() +{ + + NBL_XLOCK(); +} + +void +newbus_slock() +{ + + NBL_SLOCK(); +} + +void +newbus_xunlock() +{ + + NBL_XUNLOCK(); +} + +void +newbus_sunlock() +{ + + NBL_SUNLOCK(); +} + /* * dev sysctl tree */ @@ -364,7 +413,6 @@ static d_poll_t devpoll; static struct cdevsw dev_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = devopen, .d_close = devclose, .d_read = devread, @@ -1061,6 +1109,7 @@ devclass_delete_driver(devclass_t busclass, driver_t *driver) int i; int error; + NBL_ASSERT(SA_XLOCKED); PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass))); if (!dc) @@ -1759,6 +1808,7 @@ device_delete_child(device_t dev, device_t child) int error; device_t grandchild; + NBL_ASSERT(SA_XLOCKED); PDEBUG(("%s from %s", DEVICENAME(child), DEVICENAME(dev))); /* remove children first */ @@ -1857,7 +1907,7 @@ device_probe_child(device_t dev, device_t child) int result, pri = 0; int hasclass = (child->devclass != NULL); - GIANT_REQUIRED; + NBL_ASSERT(SA_XLOCKED); dc = dev->devclass; if (!dc) @@ -2508,7 +2558,7 @@ device_probe(device_t dev) { int error; - GIANT_REQUIRED; + NBL_ASSERT(SA_XLOCKED); if (dev->state >= DS_ALIVE && (dev->flags & DF_REBID) == 0) return (-1); @@ -2542,7 +2592,7 @@ device_probe_and_attach(device_t dev) { int error; - GIANT_REQUIRED; + NBL_ASSERT(SA_XLOCKED); error = device_probe(dev); if (error == -1) @@ -2576,6 +2626,8 @@ device_attach(device_t dev) { int error; + NBL_ASSERT(SA_XLOCKED); + device_sysctl_init(dev); if (!device_is_quiet(dev)) device_print_child(dev->parent, dev); @@ -2617,7 +2669,7 @@ device_detach(device_t dev) { int error; - GIANT_REQUIRED; + NBL_ASSERT(SA_XLOCKED); PDEBUG(("%s", DEVICENAME(dev))); if (dev->state == DS_BUSY) @@ -2661,6 +2713,8 @@ int device_quiesce(device_t dev) { + NBL_ASSERT(SA_XLOCKED); + PDEBUG(("%s", DEVICENAME(dev))); if (dev->state == DS_BUSY) return (EBUSY); @@ -2681,6 +2735,7 @@ device_quiesce(device_t dev) int device_shutdown(device_t dev) { + if (dev->state < DS_ATTACHED) return (0); return (DEVICE_SHUTDOWN(dev)); @@ -3096,6 +3151,8 @@ bus_generic_attach(device_t dev) { device_t child; + NBL_ASSERT(SA_XLOCKED); + TAILQ_FOREACH(child, &dev->children, link) { device_probe_and_attach(child); } @@ -3116,6 +3173,8 @@ bus_generic_detach(device_t dev) device_t child; int error; + NBL_ASSERT(SA_XLOCKED); + if (dev->state != DS_ATTACHED) return (EBUSY); @@ -3996,6 +4055,7 @@ root_bus_module_handler(module_t mod, int what, void* arg) switch (what) { case MOD_LOAD: TAILQ_INIT(&bus_data_devices); + NBL_LOCK_INIT(); kobj_class_compile((kobj_class_t) &root_driver); root_bus = make_device(NULL, "root", 0); root_bus->desc = "System root bus"; @@ -4055,14 +4115,28 @@ driver_module_handler(module_t mod, int what, void *arg) kobj_class_t driver; int error, pass; + error = 0; dmd = (struct driver_module_data *)arg; + + /* + * If MOD_SHUTDOWN is passed, return immediately in order to + * avoid unnecessary locking and a LOR with the modules sx lock. + */ + if (what == MOD_SHUTDOWN) + return (EOPNOTSUPP); + NBL_XLOCK(); bus_devclass = devclass_find_internal(dmd->dmd_busname, NULL, TRUE); - error = 0; + if (bus_devclass == NULL) { + NBL_XUNLOCK(); + return (ENOMEM); + } - switch (what) { + switch (what) { case MOD_LOAD: if (dmd->dmd_chainevh) error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); + if (error != 0) + break; pass = dmd->dmd_pass; driver = dmd->dmd_driver; @@ -4115,6 +4189,7 @@ driver_module_handler(module_t mod, int what, void *arg) error = EOPNOTSUPP; break; } + NBL_XUNLOCK(); return (error); } diff --git a/sys/pc98/cbus/fdc.c b/sys/pc98/cbus/fdc.c index 8373f45163c5..294711787a9f 100644 --- a/sys/pc98/cbus/fdc.c +++ b/sys/pc98/cbus/fdc.c @@ -1499,7 +1499,9 @@ fdstrategy(struct bio *bp) bioq_disksort(&fdc->head, bp); untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */ devstat_start_transaction_bio(fd->device_stats, bp); + newbus_xlock(); device_busy(fd->dev); + newbus_xunlock(); fdstart(fdc); splx(s); return; @@ -2178,7 +2180,9 @@ fdstate(fdc_p fdc) fd->skip = 0; bp->bio_resid = 0; fdc->bp = NULL; + newbus_xlock(); device_unbusy(fd->dev); + newbus_xunlock(); biofinish(bp, fd->device_stats, 0); fdc->fd = (fd_p) 0; fdc->fdu = -1; @@ -2339,7 +2343,9 @@ retrier(struct fdc_data *fdc) bp->bio_resid = 0; fdc->bp = NULL; fdc->fd->skip = 0; + newbus_xlock(); device_unbusy(fd->dev); + newbus_xunlock(); biofinish(bp, fdc->fd->device_stats, 0); fdc->state = FINDWORK; fdc->flags |= FDC_NEEDS_RESET; diff --git a/sys/sys/bus.h b/sys/sys/bus.h index 2362041dad26..7ed06f4fed91 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -478,6 +478,14 @@ int resource_set_string(const char *name, int unit, const char *resname, int bus_data_generation_check(int generation); void bus_data_generation_update(void); +/* + * Exported locking facilities. + */ +void newbus_xlock(void); +void newbus_slock(void); +void newbus_xunlock(void); +void newbus_sunlock(void); + /** * Some convenience defines for probe routines to return. These are just * suggested values, and there's nothing magical about them. diff --git a/sys/sys/param.h b/sys/sys/param.h index 1570900d1106..10a1a9a79f94 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 800106 /* Master, propagated to newvers */ +#define __FreeBSD_version 800107 /* Master, propagated to newvers */ #ifndef LOCORE #include diff --git a/sys/xen/xenbus/xenbus_probe.c b/sys/xen/xenbus/xenbus_probe.c index f04f8eca4638..f930c8ff71b9 100644 --- a/sys/xen/xenbus/xenbus_probe.c +++ b/sys/xen/xenbus/xenbus_probe.c @@ -348,7 +348,9 @@ xenbus_devices_changed(struct xenbus_watch *watch, if (p) *p = 0; + newbus_xlock(); xenbus_add_device(dev, bus, type, id); + newbus_xunlock(); taskqueue_enqueue(taskqueue_thread, &sc->xs_probechildren); out: free(node, M_DEVBUF); @@ -361,7 +363,9 @@ xenbus_attach_deferred(void *arg) struct xenbus_softc *sc = device_get_softc(dev); int error; + newbus_xlock(); error = xenbus_enumerate_bus(dev, "device"); + newbus_xunlock(); if (error) return; xenbus_probe_children(dev); -- cgit v1.2.3