kern/104079: [fdc] kldunload fdc.ko leads to panic: mutex
Giant owned
Jaakko Heinonen
jh at saunalahti.fi
Tue Nov 11 08:10:06 PST 2008
The following reply was made to PR kern/104079; it has been noted by GNATS.
From: Jaakko Heinonen <jh at saunalahti.fi>
To: bug-followup at FreeBSD.org, lynx.ripe at gmail.com
Cc:
Subject: Re: kern/104079: [fdc] kldunload fdc.ko leads to panic: mutex
Giant owned
Date: Tue, 11 Nov 2008 18:08:30 +0200
On module unload fd_detach() is called with Giant held. The problem is
that fd_detach() tries to acquire the GEOM topology lock (sx lock).
This is not allowed under Giant.
There are also other bugs related to loading/unloading the fdc module:
* Return value from g_modevent() is ignored. fdc_modevent() always
returns success even if g_modevent() fails.
* g_wither_geom() races against module unload. Withering is not
guaranteed to finish in finite time. If withering doesn't finish
before g_modevent() call the module unload fails. Combined with
g_modevent() return value ignorance the result is a panic in g_event
thread.
(Looks like g_wither_geom() race against module unload is a common
problem with many geom classes. atapicd is affected for sure.)
* When loading the module fdc_attach() must be completed before
fd_attach(). However fd_attach() runs before fdc_attach().
Following patch works around some of the problems. We can do withering
as geom event to avoid calling g_wither_geom() under Giant. The makefile
hack is to change the order of fd_attach() and fdc_attach(). If someone
knows better way to change ordering I am happy to hear.
(DRIVER_MODULE() macro doesn't take order (SI_ORDER_*) as argument.)
The patch doesn't address g_wither_geom() race (except checking
g_modevent() return value may prevent a panic in some cases).
%%%
Index: sys/modules/fdc/Makefile
===================================================================
--- sys/modules/fdc/Makefile (revision 184512)
+++ sys/modules/fdc/Makefile (working copy)
@@ -7,11 +7,12 @@ KMOD= fdc
SRCS= fdc.c fdc_cbus.c
.else
.PATH: ${.CURDIR}/../../dev/fdc
-SRCS= fdc.c fdc_isa.c fdc_pccard.c
+SRCS= fdc_isa.c fdc_pccard.c
.if ${MACHINE} == "i386" || ${MACHINE} == "amd64"
CFLAGS+= -I${.CURDIR}/../../contrib/dev/acpica
SRCS+= opt_acpi.h acpi_if.h fdc_acpi.c
.endif
+SRCS+= fdc.c
.endif
SRCS+= opt_fdc.h bus_if.h card_if.h device_if.h \
Index: sys/dev/fdc/fdc.c
===================================================================
--- sys/dev/fdc/fdc.c (revision 184512)
+++ sys/dev/fdc/fdc.c (working copy)
@@ -2012,15 +2012,22 @@ fd_attach(device_t dev)
return (0);
}
+static void
+fd_detach_geom(void *arg, int flag)
+{
+ struct fd_data *fd = arg;
+
+ g_topology_assert();
+ g_wither_geom(fd->fd_geom, ENXIO);
+}
+
static int
fd_detach(device_t dev)
{
struct fd_data *fd;
fd = device_get_softc(dev);
- g_topology_lock();
- g_wither_geom(fd->fd_geom, ENXIO);
- g_topology_unlock();
+ g_waitfor_event(fd_detach_geom, fd, M_WAITOK, NULL);
while (device_get_state(dev) == DS_BUSY)
tsleep(fd, PZERO, "fdd", hz/10);
callout_drain(&fd->toffhandle);
@@ -2049,8 +2056,7 @@ static int
fdc_modevent(module_t mod, int type, void *data)
{
- g_modevent(NULL, type, &g_fd_class);
- return (0);
+ return (g_modevent(NULL, type, &g_fd_class));
}
DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, fdc_modevent, 0);
%%%
--
Jaakko
More information about the freebsd-bugs
mailing list