- Fixed theoretical memory leak in g_modevent() function. - Fix deadlock. When requests were canceled, the g_pending_events counter wasn't decresed. Because of that g_waitidle() will wait forever. - Detect deadlock situations when g_waitfor_event() function is called recursively. - Improve taste mechanism by adding flags for taste event: + G_TA_TASTE - this is a taste event, + G_TA_RETASTE - this is a retaste event (called after spoiled event), + G_TA_FIRST - this is first disk introduced for tasting, + G_TA_LAST - this is last disk introduced for tasting, + G_TA_ALLMASK - mask for all available flags. - Detect registration of class without a name. - Detect new provider creation when its geom has no 'start' field defined. - Don't allow creating new consumer when its geom is being withered. - Don't allow creating new provider when its geom is being withered. - Don't allow provider's error changes when its geom is being withered. - Return EPERM when someone is trying to attach to a provider and provider's geom is being withered. - Added missing '\n' in printf(9). diff -rup geom.orig/geom.h geom/geom.h --- geom.orig/geom.h Fri Jan 23 16:54:52 2004 +++ geom/geom.h Fri Jan 23 16:58:53 2004 @@ -64,6 +64,11 @@ typedef int g_ctl_destroy_geom_t (struct 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); +#define G_TA_TASTE 0x0001 +#define G_TA_RETASTE 0x0002 +#define G_TA_FIRST 0x0004 +#define G_TA_LAST 0x0008 +#define G_TA_ALLMASK 0x000f typedef struct g_geom * g_taste_t (struct g_class *, struct g_provider *, int flags); typedef int g_ioctl_t(struct g_provider *pp, u_long cmd, void *data, struct thread *td); #define G_TF_NORMAL 0 diff -rup geom.orig/geom_dev.c geom/geom_dev.c --- geom.orig/geom_dev.c Fri Jan 23 16:54:52 2004 +++ geom/geom_dev.c Fri Jan 23 17:01:39 2004 @@ -255,7 +255,7 @@ g_dev_close(dev_t dev, int flags, int fm i += hz / 10; } if (cp->acr == 0 && cp->acw == 0 && cp->nstart != cp->nend) { - printf("WARNING: Final close of geom_dev(%s) %s %s", + printf("WARNING: Final close of geom_dev(%s) %s %s\n", gp->name, "still has outstanding I/O after 10 seconds.", "Completing close anyway, panic may happen later."); diff -rup geom.orig/geom_event.c geom/geom_event.c --- geom.orig/geom_event.c Fri Jan 23 16:54:52 2004 +++ geom/geom_event.c Fri Jan 23 18:51:51 2004 @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD: src/sys/geom/geom_ev #include #include #include +#include #include #include #include @@ -242,6 +243,9 @@ g_cancel_event(void *ref) } else { g_free(ep); } + g_pending_events--; + if (g_pending_events == 0) + wakeup(&g_pending_events); break; } } @@ -309,6 +313,13 @@ g_waitfor_event(g_event_t *func, void *a va_list ap; struct g_event *ep; int error; +#ifdef INVARIANTS + /* + * This variable is used for deadlock prevention when we're waiting here + * for function which is calling g_waitfor_event() function. + */ + static int waiting_for_function = 0; +#endif /* g_topology_assert_not(); */ KASSERT(flag == M_WAITOK || flag == M_NOWAIT, @@ -318,9 +329,14 @@ g_waitfor_event(g_event_t *func, void *a va_end(ap); if (error) return (error); + KASSERT(atomic_cmpset_int(&waiting_for_function, 0, 1) == 1, + ("wait-for-event request called recursively")); do tsleep(ep, PRIBIO, "g_waitfor_event", hz); while (!(ep->flag & EV_DONE)); +#ifdef INVARIANTS + atomic_store_rel_int(&waiting_for_function, 0); +#endif if (ep->flag & EV_CANCELED) error = EAGAIN; g_free(ep); diff -rup geom.orig/geom_subr.c geom/geom_subr.c --- geom.orig/geom_subr.c Fri Jan 23 16:54:52 2004 +++ geom/geom_subr.c Fri Jan 23 18:52:06 2004 @@ -59,10 +59,14 @@ char *g_wait_event, *g_wait_up, *g_wait_ static int g_valid_obj(void const *ptr); -struct g_hh00 { +struct g_hh00_class { struct g_class *mp; int error; }; +struct g_hh00_provider { + struct g_provider *provider; + int flags; +}; /* * This event offers a new class a chance to taste all preexisting providers. @@ -70,10 +74,11 @@ struct g_hh00 { static void g_load_class(void *arg, int flag) { - struct g_hh00 *hh; + struct g_hh00_class *hh; struct g_class *mp2, *mp; struct g_geom *gp; - struct g_provider *pp; + struct g_provider *pp, *pp2; + int tflags; g_topology_assert(); if (flag == EV_CANCEL) /* XXX: can't happen ? */ @@ -84,6 +89,7 @@ g_load_class(void *arg, int flag) hh = arg; mp = hh->mp; g_free(hh); + KASSERT(mp->name != NULL, ("Cannot load class without a name")); g_trace(G_T_TOPOLOGY, "g_load_class(%s)", mp->name); LIST_FOREACH(mp2, &g_classes, class) { KASSERT(mp2 != mp, @@ -98,22 +104,34 @@ g_load_class(void *arg, int flag) mp->init(mp); if (mp->taste == NULL) return; + pp = NULL; + tflags = G_TA_TASTE | G_TA_FIRST; LIST_FOREACH(mp2, &g_classes, class) { if (mp == mp2) continue; LIST_FOREACH(gp, &mp2->geom, geom) { - LIST_FOREACH(pp, &gp->provider, provider) { - mp->taste(mp, pp, 0); - g_topology_assert(); + LIST_FOREACH(pp2, &gp->provider, provider) { + if (pp != NULL) { + mp->taste(mp, pp, tflags); + g_topology_assert(); + if ((tflags & G_TA_FIRST) != 0) + tflags &= ~G_TA_FIRST; + } + pp = pp2; } } } + if (pp != NULL) { + tflags |= G_TA_LAST; + mp->taste(mp, pp, tflags); + g_topology_assert(); + } } static void g_unload_class(void *arg, int flag) { - struct g_hh00 *hh; + struct g_hh00_class *hh; struct g_class *mp; struct g_geom *gp; struct g_provider *pp; @@ -165,7 +183,7 @@ g_unload_class(void *arg, int flag) int g_modevent(module_t mod, int type, void *data) { - struct g_hh00 *hh; + struct g_hh00_class *hh; int error; static int g_ignition; @@ -194,6 +212,8 @@ g_modevent(module_t mod, int type, void } g_free(hh); break; + default: + g_free(hh); } return (error); } @@ -288,6 +308,9 @@ g_new_consumer(struct g_geom *gp) struct g_consumer *cp; g_topology_assert(); + KASSERT(!(gp->flags & G_GEOM_WITHER), + ("g_new_consumer called on geom(%s) with WITHER flag set (class %s)", + gp->name, gp->class->name)); KASSERT(gp->orphan != NULL, ("g_new_consumer on geom(%s) (class %s) without orphan", gp->name, gp->class->name)); @@ -323,17 +346,28 @@ g_destroy_consumer(struct g_consumer *cp static void g_new_provider_event(void *arg, int flag) { + struct g_hh00_provider *hh; struct g_class *mp; struct g_provider *pp; struct g_consumer *cp; - int i; + int i, tflags; g_topology_assert(); if (flag == EV_CANCEL) return; if (g_shutdown) return; - pp = arg; + hh = arg; + pp = hh->provider; + tflags = hh->flags; + g_free(hh); + KASSERT((tflags & ~G_TA_ALLMASK) == 0, ("Wrong flags for taste event")); + KASSERT(tflags != 0, ("Wrong flags for taste event")); +/* We need logical XOR operation for a moment. */ +#define LXOR(a, b) (!(a) != !(b)) + KASSERT(LXOR((tflags & G_TA_TASTE) != 0, (tflags & G_TA_RETASTE) != 0), + ("Wrong flags for taste event")); +#undef LXOR LIST_FOREACH(mp, &g_classes, class) { if (mp->taste == NULL) continue; @@ -343,7 +377,7 @@ g_new_provider_event(void *arg, int flag i = 0; if (!i) continue; - mp->taste(mp, pp, 0); + mp->taste(mp, pp, tflags); g_topology_assert(); /* * XXX: Bandaid for 5.2-RELEASE @@ -360,11 +394,19 @@ g_new_provider_event(void *arg, int flag struct g_provider * g_new_providerf(struct g_geom *gp, const char *fmt, ...) { + struct g_hh00_provider *hh; struct g_provider *pp; struct sbuf *sb; va_list ap; g_topology_assert(); + KASSERT(gp->start != NULL, + ("g_new_providerf on geom(%s) (class %s) without start", + gp->name, gp->class->name)); + KASSERT(!(gp->flags & G_GEOM_WITHER), + ("g_new_providerf called on geom(%s) with WITHER flag set (class %s)", + gp->name, gp->class->name)); + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); va_start(ap, fmt); sbuf_vprintf(sb, fmt, ap); @@ -380,7 +422,10 @@ g_new_providerf(struct g_geom *gp, const 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_post_event(g_new_provider_event, pp, M_WAITOK, pp, NULL); + hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO); + hh->provider = pp; + hh->flags = G_TA_TASTE | G_TA_FIRST | G_TA_LAST; + g_post_event(g_new_provider_event, hh, M_WAITOK, hh, NULL); return (pp); } @@ -388,6 +433,9 @@ void g_error_provider(struct g_provider *pp, int error) { + KASSERT(!(pp->geom->flags & G_GEOM_WITHER), + ("error change for provider(%s) on geom(%s) with WITHER flag set (class %s)", + pp->name, pp->geom->name, pp->geom->class->name)); pp->error = error; } @@ -504,6 +552,8 @@ g_attach(struct g_consumer *cp, struct g g_topology_assert(); KASSERT(cp->provider == NULL, ("attach but attached")); + if (pp->geom->flags & G_GEOM_WITHER) + return (EPERM); /* XXX: ENXIO? pp->error? */ cp->provider = pp; LIST_INSERT_HEAD(&pp->consumers, cp, consumers); error = redo_rank(cp->geom); @@ -634,9 +684,15 @@ g_access_rel(struct g_consumer *cp, int if (pp->acw == 0 && dcw != 0) g_spoil(pp, cp); else if (pp->acw != 0 && pp->acw == -dcw && - !(pp->geom->flags & G_GEOM_WITHER)) - g_post_event(g_new_provider_event, pp, M_WAITOK, - pp, NULL); + !(pp->geom->flags & G_GEOM_WITHER)) { + struct g_hh00_provider *hh; + + hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO); + hh->provider = pp; + hh->flags = G_TA_RETASTE | G_TA_FIRST | G_TA_LAST; + g_post_event(g_new_provider_event, hh, M_WAITOK, + hh, NULL); + } pp->acr += dcr; pp->acw += dcw;