diff options
author | trasz <trasz@FreeBSD.org> | 2015-03-02 22:48:11 +0000 |
---|---|---|
committer | trasz <trasz@FreeBSD.org> | 2015-03-02 22:48:11 +0000 |
commit | 3411f8c13d65531062240883887898f74f5ba291 (patch) | |
tree | fab9704c5c1c874f4910ca0b952316e84b4a88d4 /sys/cam | |
parent | 4a1b04f61d1472d75012d5db774436706efa6eaa (diff) | |
download | FreeBSD-src-3411f8c13d65531062240883887898f74f5ba291.zip FreeBSD-src-3411f8c13d65531062240883887898f74f5ba291.tar.gz |
Make periphdriver_register() take XPT lock when modifying the periph_drivers
array.
This fixes a panic that sometimes occured when kldloading ctl.ko.
Reviewed by: mav@
MFC after: 1 month
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/cam')
-rw-r--r-- | sys/cam/cam_periph.c | 13 | ||||
-rw-r--r-- | sys/cam/cam_xpt.c | 3 |
2 files changed, 14 insertions, 2 deletions
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index 2544d27..53454f8 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -108,9 +108,19 @@ periphdriver_register(void *data) struct periph_driver **newdrivers, **old; int ndrivers; +again: ndrivers = nperiph_drivers + 2; newdrivers = malloc(sizeof(*newdrivers) * ndrivers, M_CAMPERIPH, M_WAITOK); + xpt_lock_buses(); + if (ndrivers != nperiph_drivers + 2) { + /* + * Lost race against itself; go around. + */ + xpt_unlock_buses(); + free(newdrivers, M_CAMPERIPH); + goto again; + } if (periph_drivers) bcopy(periph_drivers, newdrivers, sizeof(*newdrivers) * nperiph_drivers); @@ -118,9 +128,10 @@ periphdriver_register(void *data) newdrivers[nperiph_drivers + 1] = NULL; old = periph_drivers; periph_drivers = newdrivers; + nperiph_drivers++; + xpt_unlock_buses(); if (old) free(old, M_CAMPERIPH); - nperiph_drivers++; /* If driver marked as early or it is late now, initialize it. */ if (((drv->flags & CAM_PERIPH_DRV_EARLY) != 0 && initialized > 0) || initialized > 1) diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 75d81e6..c8a9c37 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -151,6 +151,8 @@ typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg); /* Transport layer configuration information */ static struct xpt_softc xsoftc; +MTX_SYSINIT(xpt_topo_init, &xsoftc.xpt_topo_lock, "XPT topology lock", MTX_DEF); + SYSCTL_INT(_kern_cam, OID_AUTO, boot_delay, CTLFLAG_RDTUN, &xsoftc.boot_delay, 0, "Bus registration wait time"); SYSCTL_UINT(_kern_cam, OID_AUTO, xpt_generation, CTLFLAG_RD, @@ -850,7 +852,6 @@ xpt_init(void *dummy) mtx_init(&xsoftc.xpt_lock, "XPT lock", NULL, MTX_DEF); mtx_init(&xsoftc.xpt_highpower_lock, "XPT highpower lock", NULL, MTX_DEF); - mtx_init(&xsoftc.xpt_topo_lock, "XPT topology lock", NULL, MTX_DEF); xsoftc.xpt_taskq = taskqueue_create("CAM XPT task", M_WAITOK, taskqueue_thread_enqueue, /*context*/&xsoftc.xpt_taskq); |