1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-18 15:30:21 +00:00

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
This commit is contained in:
Poul-Henning Kamp 2003-05-31 18:13:07 +00:00
parent a388918d35
commit 6c87f8d5ea
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=115473
3 changed files with 126 additions and 40 deletions

View File

@ -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 */

View File

@ -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)

View File

@ -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);