diff options
author | phk <phk@FreeBSD.org> | 2003-05-31 18:13:07 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2003-05-31 18:13:07 +0000 |
commit | 3325608f8fa53330fcc9b5026fa2c3b75952fb2b (patch) | |
tree | 3f90e7d4dfd582f7fd53c28d5179880e31ba2090 /sys | |
parent | b96117501d4c56f42bb3d80d9841e97999192258 (diff) | |
download | FreeBSD-src-3325608f8fa53330fcc9b5026fa2c3b75952fb2b.zip FreeBSD-src-3325608f8fa53330fcc9b5026fa2c3b75952fb2b.tar.gz |
Introduce a init and fini member functions on a class.
Use ->init() and ->fini() to handle the mutex in geom_disk.c
Remove the g_add_class() function and replace it with a standardized
g_modevent() function.
This adds the basic infrastructure for loading/unloading GEOM classes
Diffstat (limited to 'sys')
-rw-r--r-- | sys/geom/geom.h | 25 | ||||
-rw-r--r-- | sys/geom/geom_disk.c | 19 | ||||
-rw-r--r-- | sys/geom/geom_subr.c | 122 |
3 files changed, 126 insertions, 40 deletions
diff --git a/sys/geom/geom.h b/sys/geom/geom.h index 73121edb..15c253b 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -44,6 +44,7 @@ #include <sys/queue.h> #include <sys/ioccom.h> #include <sys/sbuf.h> +#include <sys/module.h> struct g_class; struct g_geom; @@ -60,6 +61,8 @@ typedef int g_config_t (struct g_configargs *ca); typedef int g_ctl_create_geom_t (struct gctl_req *, struct g_class *cp, struct g_provider *pp); typedef int g_ctl_destroy_geom_t (struct gctl_req *, struct g_class *cp, struct g_geom *gp); typedef int g_ctl_config_geom_t (struct gctl_req *, struct g_geom *gp, const char *verb); +typedef void g_init_t (struct g_class *mp); +typedef void g_fini_t (struct g_class *mp); typedef struct g_geom * g_taste_t (struct g_class *, struct g_provider *, int flags); #define G_TF_NORMAL 0 @@ -85,6 +88,8 @@ struct g_class { const char *name; g_taste_t *taste; g_config_t *config; + g_init_t *init; + g_fini_t *fini; g_ctl_create_geom_t *create_geom; g_ctl_destroy_geom_t *destroy_geom; g_ctl_config_geom_t *config_geom; @@ -193,7 +198,6 @@ void g_waitidle(void); /* geom_subr.c */ int g_access_abs(struct g_consumer *cp, int nread, int nwrite, int nexcl); int g_access_rel(struct g_consumer *cp, int nread, int nwrite, int nexcl); -void g_add_class(struct g_class *mp); int g_attach(struct g_consumer *cp, struct g_provider *pp); void g_destroy_consumer(struct g_consumer *cp); void g_destroy_geom(struct g_geom *pp); @@ -215,6 +219,8 @@ void g_std_done(struct bio *bp); void g_std_spoiled(struct g_consumer *cp); void g_wither_geom(struct g_geom *gp, int error); +int g_modevent(module_t, int, void *); + /* geom_io.c */ struct bio * g_clone_bio(struct bio *); void g_destroy_bio(struct bio *); @@ -289,18 +295,11 @@ extern struct sx topology_lock; sx_assert(&topology_lock, SX_XLOCKED); \ } while (0) -#define DECLARE_GEOM_CLASS_INIT(class, name, init) \ - SYSINIT(name, SI_SUB_DRIVERS, SI_ORDER_FIRST, init, NULL); - -#define DECLARE_GEOM_CLASS(class, name) \ - static void \ - name##init(void) \ - { \ - mtx_unlock(&Giant); \ - g_add_class(&class); \ - mtx_lock(&Giant); \ - } \ - DECLARE_GEOM_CLASS_INIT(class, name, name##init); +#define DECLARE_GEOM_CLASS(class, name) \ + static moduledata_t name##_mod = { \ + #name, g_modevent, &class \ + }; \ + DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); #endif /* _KERNEL */ diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c index a6ce15e..5bbb56d 100644 --- a/sys/geom/geom_disk.c +++ b/sys/geom/geom_disk.c @@ -58,21 +58,30 @@ static struct mtx g_disk_done_mtx; static g_access_t g_disk_access; +static g_init_t g_disk_init; +static g_fini_t g_disk_fini; struct g_class g_disk_class = { .name = "DISK", + .init = g_disk_init, + .fini = g_disk_fini, }; static void -g_disk_init(void) +g_disk_init(struct g_class *mp __unused) { - mtx_unlock(&Giant); - g_add_class(&g_disk_class); + mtx_init(&g_disk_done_mtx, "g_disk_done", MTX_DEF, 0); - mtx_lock(&Giant); } -DECLARE_GEOM_CLASS_INIT(g_disk_class, g_disk, g_disk_init); +static void +g_disk_fini(struct g_class *mp __unused) +{ + + mtx_destroy(&g_disk_done_mtx); +} + +DECLARE_GEOM_CLASS(g_disk_class, g_disk); static void __inline g_disk_lock_giant(struct disk *dp) diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c index d45dd2b..d23105e 100644 --- a/sys/geom/geom_subr.c +++ b/sys/geom/geom_subr.c @@ -55,58 +55,138 @@ struct class_list_head g_classes = LIST_HEAD_INITIALIZER(g_classes); static struct g_tailq_head geoms = TAILQ_HEAD_INITIALIZER(geoms); -static int g_nproviders; char *g_wait_event, *g_wait_up, *g_wait_down, *g_wait_sim; -static int g_ignition; +struct g_hh00 { + struct g_class *mp; + int error; +}; /* * This event offers a new class a chance to taste all preexisting providers. */ static void -g_new_class_event(void *arg, int flag) +g_load_class(void *arg, int flag) { + struct g_hh00 *hh; struct g_class *mp2, *mp; struct g_geom *gp; struct g_provider *pp; g_topology_assert(); - if (flag == EV_CANCEL) + if (flag == EV_CANCEL) /* XXX: can't happen ? */ return; if (g_shutdown) return; - mp2 = arg; - if (mp2->taste == NULL) + + hh = arg; + mp = hh->mp; + g_free(hh); + g_trace(G_T_TOPOLOGY, "g_load_class(%s)", mp->name); + + if (mp->init != NULL) + mp->init(mp); + LIST_INIT(&mp->geom); + LIST_INSERT_HEAD(&g_classes, mp, class); + if (mp->taste == NULL) return; - LIST_FOREACH(mp, &g_classes, class) { - if (mp2 == mp) + LIST_FOREACH(mp2, &g_classes, class) { + if (mp == mp2) continue; - LIST_FOREACH(gp, &mp->geom, geom) { + LIST_FOREACH(gp, &mp2->geom, geom) { LIST_FOREACH(pp, &gp->provider, provider) { - mp2->taste(mp2, pp, 0); + mp->taste(mp, pp, 0); g_topology_assert(); } } } } -void -g_add_class(struct g_class *mp) +static void +g_unload_class(void *arg, int flag) { + struct g_hh00 *hh; + struct g_class *mp; + struct g_geom *gp; + struct g_provider *pp; + struct g_consumer *cp; + int error; + + g_topology_assert(); + hh = arg; + mp = hh->mp; + g_trace(G_T_TOPOLOGY, "g_unload_class(%s)", mp->name); + if (mp->destroy_geom == NULL) { + hh->error = EOPNOTSUPP; + return; + } + + /* We refuse to unload if anything is open */ + LIST_FOREACH(gp, &mp->geom, geom) { + LIST_FOREACH(pp, &gp->provider, provider) + if (pp->acr || pp->acw || pp->ace) { + hh->error = EBUSY; + return; + } + LIST_FOREACH(cp, &gp->consumer, consumer) + if (cp->acr || cp->acw || cp->ace) { + hh->error = EBUSY; + return; + } + } + + /* Bar new entries */ + mp->taste = NULL; + mp->config = NULL; + + error = 0; + LIST_FOREACH(gp, &mp->geom, geom) { + error = mp->destroy_geom(NULL, mp, gp); + if (error != 0) + break; + } + if (error == 0) { + LIST_REMOVE(mp, class); + if (mp->fini != NULL) + mp->fini(mp); + } + hh->error = error; + return; +} + +int +g_modevent(module_t mod, int type, void *data) +{ + struct g_hh00 *hh; + int error; + static int g_ignition; if (!g_ignition) { g_ignition++; g_init(); } - mp->protect = 0x020016600; - g_topology_lock(); - g_trace(G_T_TOPOLOGY, "g_add_class(%s)", mp->name); - LIST_INIT(&mp->geom); - LIST_INSERT_HEAD(&g_classes, mp, class); - if (g_nproviders > 0 && mp->taste != NULL) - g_post_event(g_new_class_event, mp, M_WAITOK, mp, NULL); - g_topology_unlock(); + hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO); + hh->mp = data; + error = EOPNOTSUPP; + switch (type) { + case MOD_LOAD: + g_trace(G_T_TOPOLOGY, "g_modevent(%s, LOAD)", hh->mp->name); + g_post_event(g_load_class, hh, M_WAITOK, NULL); + error = 0; + break; + case MOD_UNLOAD: + g_trace(G_T_TOPOLOGY, "g_modevent(%s, UNLOAD)", hh->mp->name); + error = g_waitfor_event(g_unload_class, hh, M_WAITOK, NULL); + if (error == 0) + error = hh->error; + g_waitidle(); + KASSERT(LIST_EMPTY(&hh->mp->geom), + ("Unloaded class (%s) still has geom", hh->mp->name)); + g_free(hh); + break; + } + return (error); } struct g_geom * @@ -283,7 +363,6 @@ g_new_providerf(struct g_geom *gp, const char *fmt, ...) pp->stat = devstat_new_entry(pp, -1, 0, DEVSTAT_ALL_SUPPORTED, DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX); LIST_INSERT_HEAD(&gp->provider, pp, provider); - g_nproviders++; g_post_event(g_new_provider_event, pp, M_WAITOK, pp, NULL); return (pp); } @@ -308,7 +387,6 @@ g_destroy_provider(struct g_provider *pp) KASSERT (pp->acw == 0, ("g_destroy_provider with acw")); KASSERT (pp->acw == 0, ("g_destroy_provider with ace")); g_cancel_event(pp); - g_nproviders--; LIST_REMOVE(pp, provider); gp = pp->geom; devstat_remove_entry(pp->stat); |