diff --git a/sys/geom/geom_event.c b/sys/geom/geom_event.c index 3c2ee494f5f65..812e55ea129b0 100644 --- a/sys/geom/geom_event.c +++ b/sys/geom/geom_event.c @@ -159,6 +159,7 @@ g_attr_changed(struct g_provider *pp, const char *attr, int flag) void g_orphan_provider(struct g_provider *pp, int error) { + struct mtx *mtxp; /* G_VALID_PROVIDER(pp) We likely lack topology lock */ g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", @@ -166,8 +167,9 @@ g_orphan_provider(struct g_provider *pp, int error) KASSERT(error != 0, ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", pp, pp->name)); - + mtxp = g_lock_provider(pp); pp->error = error; + g_unlock_provider(pp, mtxp); mtx_lock(&g_eventlock); KASSERT(!(pp->flags & G_PF_ORPHAN), ("g_orphan_provider(%p(%s)), already an orphan", pp, pp->name)); @@ -232,13 +234,18 @@ g_orphan_register(struct g_provider *pp) static int one_event(void) { + struct mtx *mtxp; struct g_event *ep; struct g_provider *pp; + bool found; g_topology_assert(); mtx_lock(&g_eventlock); TAILQ_FOREACH(pp, &g_doorstep, orphan) { - if (pp->nstart == pp->nend) + mtxp = g_lock_provider(pp); + found = (pp->nstart == pp->nend); + g_unlock_provider(pp, mtxp); + if (found) break; } if (pp != NULL) { diff --git a/sys/geom/geom_int.h b/sys/geom/geom_int.h index d5af866e44565..d4ed902fce73c 100644 --- a/sys/geom/geom_int.h +++ b/sys/geom/geom_int.h @@ -83,3 +83,30 @@ extern int g_notaste; /* geom_ctl.c */ void g_ctl_init(void); + +/* + * The lock used to ensure consistency of provider parameters + * set or examined in the I/O path. Those parameters include: + * - stat + * - nstart + * - nend + * - error + */ +static inline struct mtx * +g_lock_provider(struct g_provider *pp) +{ + struct mtx *mtxp; + + mtxp = mtx_pool_find(mtxpool_sleep, pp); + mtx_lock(mtxp); + return (mtxp); +} + +static inline void +g_unlock_provider(struct g_provider *pp, struct mtx *mtxp) +{ + + KASSERT(mtx_pool_find(mtxpool_sleep, pp) == mtxp, + ("%s: lock does not match provider", __func__)); + mtx_unlock(mtxp); +} diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c index e192f67d94d4e..659757809dc85 100644 --- a/sys/geom/geom_io.c +++ b/sys/geom/geom_io.c @@ -360,6 +360,7 @@ g_io_flush(struct g_consumer *cp) static int g_io_check(struct bio *bp) { + struct mtx *mtxp; struct g_consumer *cp; struct g_provider *pp; off_t excess; @@ -394,9 +395,16 @@ g_io_check(struct bio *bp) default: return (EPERM); } - /* if provider is marked for error, don't disturb. */ - if (pp->error) - return (pp->error); + + /* + * If provider is marked for error, don't disturb. + * Use the lock to ensure that we see the actual state. + */ + mtxp = g_lock_provider(pp); + error = pp->error; + g_unlock_provider(pp, mtxp); + if (error != 0) + return (error); if (cp->flags & G_CF_ORPHAN) return (ENXIO); @@ -611,15 +619,14 @@ g_io_request(struct bio *bp, struct g_consumer *cp) * can not update one instance of the statistics from more * than one thread at a time, so grab the lock first. */ - mtxp = mtx_pool_find(mtxpool_sleep, pp); - mtx_lock(mtxp); + mtxp = g_lock_provider(pp); if (g_collectstats & G_STATS_PROVIDERS) devstat_start_transaction(pp->stat, &bp->bio_t0); if (g_collectstats & G_STATS_CONSUMERS) devstat_start_transaction(cp->stat, &bp->bio_t0); pp->nstart++; cp->nstart++; - mtx_unlock(mtxp); + g_unlock_provider(pp, mtxp); if (direct) { error = g_io_check(bp); @@ -722,15 +729,14 @@ g_io_deliver(struct bio *bp, int error) if ((g_collectstats & G_STATS_CONSUMERS) != 0 || ((g_collectstats & G_STATS_PROVIDERS) != 0 && pp->stat != NULL)) binuptime(&now); - mtxp = mtx_pool_find(mtxpool_sleep, cp); - mtx_lock(mtxp); + mtxp = g_lock_provider(pp); if (g_collectstats & G_STATS_PROVIDERS) devstat_end_transaction_bio_bt(pp->stat, bp, &now); if (g_collectstats & G_STATS_CONSUMERS) devstat_end_transaction_bio_bt(cp->stat, bp, &now); cp->nend++; pp->nend++; - mtx_unlock(mtxp); + g_unlock_provider(pp, mtxp); if (error != ENOMEM) { bp->bio_error = error; diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c index bb8bb3ceffe87..bf6c1b08a88ed 100644 --- a/sys/geom/geom_subr.c +++ b/sys/geom/geom_subr.c @@ -635,9 +635,12 @@ g_renew_provider(struct g_provider *pp) void g_error_provider(struct g_provider *pp, int error) { + struct mtx *mtxp; /* G_VALID_PROVIDER(pp); We may not have g_topology */ + mtxp = g_lock_provider(pp); pp->error = error; + g_unlock_provider(pp, mtxp); } static void