diff options
Diffstat (limited to 'sys/geom/geom_subr.c')
-rw-r--r-- | sys/geom/geom_subr.c | 95 |
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"); } } |