summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2003-05-31 18:13:07 +0000
committerphk <phk@FreeBSD.org>2003-05-31 18:13:07 +0000
commit3325608f8fa53330fcc9b5026fa2c3b75952fb2b (patch)
tree3f90e7d4dfd582f7fd53c28d5179880e31ba2090 /sys
parentb96117501d4c56f42bb3d80d9841e97999192258 (diff)
downloadFreeBSD-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.h25
-rw-r--r--sys/geom/geom_disk.c19
-rw-r--r--sys/geom/geom_subr.c122
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);
OpenPOWER on IntegriCloud