summaryrefslogtreecommitdiffstats
path: root/sys/geom/geom_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/geom/geom_subr.c')
-rw-r--r--sys/geom/geom_subr.c95
1 files changed, 76 insertions, 19 deletions
diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c
index 6f009f0..4d8623f 100644
--- a/sys/geom/geom_subr.c
+++ b/sys/geom/geom_subr.c
@@ -262,10 +262,11 @@ g_modevent(module_t mod, int type, void *data)
static void
g_retaste_event(void *arg, int flag)
{
- struct g_class *cp, *mp;
- struct g_geom *gp, *gp2;
+ struct g_class *mp, *mp2;
+ struct g_geom *gp;
struct g_hh00 *hh;
struct g_provider *pp;
+ struct g_consumer *cp;
g_topology_assert();
if (flag == EV_CANCEL) /* XXX: can't happen ? */
@@ -282,17 +283,20 @@ g_retaste_event(void *arg, int flag)
}
g_trace(G_T_TOPOLOGY, "g_retaste(%s)", mp->name);
- LIST_FOREACH(cp, &g_classes, class) {
- LIST_FOREACH(gp, &cp->geom, geom) {
+ LIST_FOREACH(mp2, &g_classes, class) {
+ LIST_FOREACH(gp, &mp2->geom, geom) {
LIST_FOREACH(pp, &gp->provider, provider) {
if (pp->acr || pp->acw || pp->ace)
continue;
- LIST_FOREACH(gp2, &mp->geom, geom) {
- if (!strcmp(pp->name, gp2->name))
+ LIST_FOREACH(cp, &pp->consumers, consumers) {
+ if (cp->geom->class == mp &&
+ (cp->flags & G_CF_ORPHAN) == 0)
break;
}
- if (gp2 != NULL)
- g_wither_geom(gp2, ENXIO);
+ if (cp != NULL) {
+ cp->flags |= G_CF_ORPHAN;
+ g_wither_geom(cp->geom, ENXIO);
+ }
mp->taste(mp, pp, 0);
g_topology_assert();
}
@@ -534,7 +538,7 @@ g_new_provider_event(void *arg, int flag)
{
struct g_class *mp;
struct g_provider *pp;
- struct g_consumer *cp;
+ struct g_consumer *cp, *next_cp;
g_topology_assert();
if (flag == EV_CANCEL)
@@ -545,11 +549,17 @@ g_new_provider_event(void *arg, int flag)
G_VALID_PROVIDER(pp);
KASSERT(!(pp->flags & G_PF_WITHER),
("g_new_provider_event but withered"));
+ LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, next_cp) {
+ if ((cp->flags & G_CF_ORPHAN) == 0 &&
+ cp->geom->attrchanged != NULL)
+ cp->geom->attrchanged(cp, "GEOM::media");
+ }
LIST_FOREACH(mp, &g_classes, class) {
if (mp->taste == NULL)
continue;
LIST_FOREACH(cp, &pp->consumers, consumers)
- if (cp->geom->class == mp)
+ if (cp->geom->class == mp &&
+ (cp->flags & G_CF_ORPHAN) == 0)
break;
if (cp != NULL)
continue;
@@ -628,8 +638,10 @@ g_resize_provider_event(void *arg, int flag)
LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, cp2) {
gp = cp->geom;
- if (gp->resize == NULL && size < pp->mediasize)
+ if (gp->resize == NULL && size < pp->mediasize) {
+ cp->flags |= G_CF_ORPHAN;
cp->geom->orphan(cp);
+ }
}
pp->mediasize = size;
@@ -648,7 +660,8 @@ g_resize_provider_event(void *arg, int flag)
if (mp->taste == NULL)
continue;
LIST_FOREACH(cp, &pp->consumers, consumers)
- if (cp->geom->class == mp)
+ if (cp->geom->class == mp &&
+ (cp->flags & G_CF_ORPHAN) == 0)
break;
if (cp != NULL)
continue;
@@ -867,7 +880,7 @@ g_access(struct g_consumer *cp, int dcr, int dcw, int dce)
* are probably just ahead of the event telling us that. Fail
* now rather than having to unravel this later.
*/
- if (cp->geom->spoiled != NULL && cp->spoiled &&
+ if (cp->geom->spoiled != NULL && (cp->flags & G_CF_SPOILED) &&
(dcr > 0 || dcw > 0 || dce > 0))
return (ENXIO);
@@ -1017,6 +1030,7 @@ g_std_spoiled(struct g_consumer *cp)
g_topology_assert();
G_VALID_CONSUMER(cp);
g_trace(G_T_TOPOLOGY, "g_std_spoiled(%p)", cp);
+ cp->flags |= G_CF_ORPHAN;
g_detach(cp);
gp = cp->geom;
LIST_FOREACH(pp, &gp->provider, provider)
@@ -1052,9 +1066,9 @@ g_spoil_event(void *arg, int flag)
G_VALID_PROVIDER(pp);
for (cp = LIST_FIRST(&pp->consumers); cp != NULL; cp = cp2) {
cp2 = LIST_NEXT(cp, consumers);
- if (!cp->spoiled)
+ if ((cp->flags & G_CF_SPOILED) == 0)
continue;
- cp->spoiled = 0;
+ cp->flags &= ~G_CF_SPOILED;
if (cp->geom->spoiled == NULL)
continue;
cp->geom->spoiled(cp);
@@ -1079,11 +1093,54 @@ g_spoil(struct g_provider *pp, struct g_consumer *cp)
KASSERT(cp2->acw == 0, ("spoiling cp->acw = %d", cp2->acw));
*/
KASSERT(cp2->ace == 0, ("spoiling cp->ace = %d", cp2->ace));
- cp2->spoiled++;
+ cp2->flags |= G_CF_SPOILED;
}
g_post_event(g_spoil_event, pp, M_WAITOK, pp, NULL);
}
+static void
+g_media_changed_event(void *arg, int flag)
+{
+ struct g_provider *pp;
+ int retaste;
+
+ g_topology_assert();
+ if (flag == EV_CANCEL)
+ return;
+ pp = arg;
+ G_VALID_PROVIDER(pp);
+
+ /*
+ * If provider was not open for writing, queue retaste after spoiling.
+ * If it was, retaste will happen automatically on close.
+ */
+ retaste = (pp->acw == 0 && pp->error == 0 &&
+ !(pp->geom->flags & G_GEOM_WITHER));
+ g_spoil_event(arg, flag);
+ if (retaste)
+ g_post_event(g_new_provider_event, pp, M_WAITOK, pp, NULL);
+}
+
+int
+g_media_changed(struct g_provider *pp, int flag)
+{
+ struct g_consumer *cp;
+
+ LIST_FOREACH(cp, &pp->consumers, consumers)
+ cp->flags |= G_CF_SPOILED;
+ return (g_post_event(g_media_changed_event, pp, flag, pp, NULL));
+}
+
+int
+g_media_gone(struct g_provider *pp, int flag)
+{
+ struct g_consumer *cp;
+
+ LIST_FOREACH(cp, &pp->consumers, consumers)
+ cp->flags |= G_CF_SPOILED;
+ return (g_post_event(g_spoil_event, pp, flag, pp, NULL));
+}
+
int
g_getattr__(const char *attr, struct g_consumer *cp, void *var, int len)
{
@@ -1239,15 +1296,15 @@ db_show_geom_consumer(int indent, struct g_consumer *cp)
cp->provider);
}
gprintln(" access: r%dw%de%d", cp->acr, cp->acw, cp->ace);
- gprintln(" spoiled: %d", cp->spoiled);
+ gprintln(" flags: 0x%04x", cp->flags);
gprintln(" nstart: %u", cp->nstart);
gprintln(" nend: %u", cp->nend);
} else {
gprintf("consumer: %p (%s), access=r%dw%de%d", cp,
cp->provider != NULL ? cp->provider->name : "none",
cp->acr, cp->acw, cp->ace);
- if (cp->spoiled)
- db_printf(", spoiled=%d", cp->spoiled);
+ if (cp->flags)
+ db_printf(", flags=0x%04x", cp->flags);
db_printf("\n");
}
}
OpenPOWER on IntegriCloud