diff options
author | ae <ae@FreeBSD.org> | 2012-03-23 07:26:17 +0000 |
---|---|---|
committer | ae <ae@FreeBSD.org> | 2012-03-23 07:26:17 +0000 |
commit | 7232ff0e78421583cf9e318f6bd91ffc989814d8 (patch) | |
tree | b6b5059b14da14efba13514f0fa38e18deec3a02 /sys/geom | |
parent | 7ee779f903c60ebc793239495287ca0e2f912f2f (diff) | |
download | FreeBSD-src-7232ff0e78421583cf9e318f6bd91ffc989814d8.zip FreeBSD-src-7232ff0e78421583cf9e318f6bd91ffc989814d8.tar.gz |
Check that scheme is not already registered. This may happens when a
KLD is preloaded with loader(8) and leads to infinity loops.
Also do not return EEXIST error code from MOD_LOAD handler, because
we have undocumented(?) ability replace kernel's module with preloaded one.
And if we have so, then preloaded module will be initialized first.
Thus error in MOD_LOAD handler will be triggered for the kernel.
PR: kern/165573
MFC after: 3 weeks
Diffstat (limited to 'sys/geom')
-rw-r--r-- | sys/geom/part/g_part.c | 23 |
1 files changed, 16 insertions, 7 deletions
diff --git a/sys/geom/part/g_part.c b/sys/geom/part/g_part.c index 4fdc482..fb0739d 100644 --- a/sys/geom/part/g_part.c +++ b/sys/geom/part/g_part.c @@ -2211,23 +2211,32 @@ g_part_unload_event(void *arg, int flag) int g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme) { + struct g_part_scheme *iter; uintptr_t arg; int error; + error = 0; switch (type) { case MOD_LOAD: - TAILQ_INSERT_TAIL(&g_part_schemes, scheme, scheme_list); - - error = g_retaste(&g_part_class); - if (error) - TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list); + TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) { + if (scheme == iter) { + printf("GEOM_PART: scheme %s is already " + "registered!\n", scheme->name); + break; + } + } + if (iter == NULL) { + TAILQ_INSERT_TAIL(&g_part_schemes, scheme, + scheme_list); + g_retaste(&g_part_class); + } break; case MOD_UNLOAD: arg = (uintptr_t)scheme; error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK, NULL); - if (!error) - error = (arg == (uintptr_t)scheme) ? EDOOFUS : arg; + if (error == 0) + error = arg; break; default: error = EOPNOTSUPP; |