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:
parent
a388918d35
commit
6c87f8d5ea
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=115473
@ -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 */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user