diff options
-rw-r--r-- | sys/geom/gate/g_gate.c | 140 |
1 files changed, 63 insertions, 77 deletions
diff --git a/sys/geom/gate/g_gate.c b/sys/geom/gate/g_gate.c index b3c09df..7282ac9 100644 --- a/sys/geom/gate/g_gate.c +++ b/sys/geom/gate/g_gate.c @@ -470,6 +470,44 @@ g_gate_create(struct g_gate_ctl_create *ggio) return (EINVAL); } + sc = malloc(sizeof(*sc), M_GATE, M_WAITOK | M_ZERO); + sc->sc_flags = (ggio->gctl_flags & G_GATE_USERFLAGS); + strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info)); + sc->sc_seq = 1; + bioq_init(&sc->sc_inqueue); + bioq_init(&sc->sc_outqueue); + mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF); + sc->sc_queue_count = 0; + sc->sc_queue_size = ggio->gctl_maxcount; + if (sc->sc_queue_size > G_GATE_MAX_QUEUE_SIZE) + sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE; + sc->sc_timeout = ggio->gctl_timeout; + callout_init(&sc->sc_callout, CALLOUT_MPSAFE); + + mtx_lock(&g_gate_units_lock); + sc->sc_unit = g_gate_getunit(ggio->gctl_unit, &error); + if (sc->sc_unit < 0) + goto fail1; + if (ggio->gctl_unit == G_GATE_NAME_GIVEN) + snprintf(name, sizeof(name), "%s", ggio->gctl_name); + else { + snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME, + sc->sc_unit); + } + /* Check for name collision. */ + for (unit = 0; unit < g_gate_maxunits; unit++) { + if (g_gate_units[unit] == NULL) + continue; + if (strcmp(name, g_gate_units[unit]->sc_name) != 0) + continue; + error = EEXIST; + goto fail1; + } + sc->sc_name = name; + g_gate_units[sc->sc_unit] = sc; + g_gate_nunits++; + mtx_unlock(&g_gate_units_lock); + g_topology_lock(); if (ggio->gctl_readprov[0] == '\0') { @@ -477,38 +515,24 @@ g_gate_create(struct g_gate_ctl_create *ggio) } else { ropp = g_provider_by_name(ggio->gctl_readprov); if (ropp == NULL) { - g_topology_unlock(); G_GATE_DEBUG(1, "Provider %s doesn't exist.", ggio->gctl_readprov); - return (EINVAL); + error = EINVAL; + goto fail2; } if ((ggio->gctl_readoffset % ggio->gctl_sectorsize) != 0) { - g_topology_unlock(); G_GATE_DEBUG(1, "Invalid read offset."); - return (EINVAL); + error = EINVAL; + goto fail2; } if (ggio->gctl_mediasize + ggio->gctl_readoffset > ropp->mediasize) { - g_topology_unlock(); G_GATE_DEBUG(1, "Invalid read offset or media size."); - return (EINVAL); + error = EINVAL; + goto fail2; } } - sc = malloc(sizeof(*sc), M_GATE, M_WAITOK | M_ZERO); - sc->sc_flags = (ggio->gctl_flags & G_GATE_USERFLAGS); - strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info)); - sc->sc_seq = 1; - bioq_init(&sc->sc_inqueue); - bioq_init(&sc->sc_outqueue); - mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF); - sc->sc_queue_count = 0; - sc->sc_queue_size = ggio->gctl_maxcount; - if (sc->sc_queue_size > G_GATE_MAX_QUEUE_SIZE) - sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE; - sc->sc_timeout = ggio->gctl_timeout; - callout_init(&sc->sc_callout, CALLOUT_MPSAFE); - gp = g_new_geomf(&g_gate_class, "%s", name); gp->start = g_gate_start; gp->access = g_gate_access; @@ -521,70 +545,18 @@ g_gate_create(struct g_gate_ctl_create *ggio) error = g_attach(cp, ropp); if (error != 0) { G_GATE_DEBUG(1, "Unable to attach to %s.", ropp->name); - } else { - error = g_access(cp, 1, 0, 0); - if (error != 0) { - G_GATE_DEBUG(1, "Unable to access %s.", - ropp->name); - g_detach(cp); - } + goto fail3; } + error = g_access(cp, 1, 0, 0); if (error != 0) { - g_destroy_consumer(cp); - g_destroy_geom(gp); - g_topology_unlock(); - mtx_destroy(&sc->sc_queue_mtx); - free(sc, M_GATE); - return (error); + G_GATE_DEBUG(1, "Unable to access %s.", ropp->name); + g_detach(cp); + goto fail3; } sc->sc_readcons = cp; sc->sc_readoffset = ggio->gctl_readoffset; } - mtx_lock(&g_gate_units_lock); - sc->sc_unit = g_gate_getunit(ggio->gctl_unit, &error); - if (sc->sc_unit < 0) { - mtx_unlock(&g_gate_units_lock); - if (sc->sc_readcons != NULL) { - (void)g_access(sc->sc_readcons, -1, 0, 0); - g_detach(sc->sc_readcons); - g_destroy_consumer(sc->sc_readcons); - } - g_destroy_geom(gp); - g_topology_unlock(); - mtx_destroy(&sc->sc_queue_mtx); - free(sc, M_GATE); - return (error); - } - if (ggio->gctl_unit == G_GATE_NAME_GIVEN) - snprintf(name, sizeof(name), "%s", ggio->gctl_name); - else { - snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME, - sc->sc_unit); - } - /* Check for name collision. */ - for (unit = 0; unit < g_gate_maxunits; unit++) { - if (g_gate_units[unit] == NULL) - continue; - if (strcmp(name, g_gate_units[unit]->sc_name) != 0) - continue; - mtx_unlock(&g_gate_units_lock); - if (sc->sc_readcons != NULL) { - (void)g_access(sc->sc_readcons, -1, 0, 0); - g_detach(sc->sc_readcons); - g_destroy_consumer(sc->sc_readcons); - } - g_destroy_geom(gp); - g_topology_unlock(); - mtx_destroy(&sc->sc_queue_mtx); - free(sc, M_GATE); - return (EEXIST); - } - sc->sc_name = name; - g_gate_units[sc->sc_unit] = sc; - g_gate_nunits++; - mtx_unlock(&g_gate_units_lock); - ggio->gctl_unit = sc->sc_unit; pp = g_new_providerf(gp, "%s", name); @@ -604,6 +576,20 @@ g_gate_create(struct g_gate_ctl_create *ggio) g_gate_guard, sc); } return (0); +fail3: + g_destroy_consumer(cp); + g_destroy_geom(gp); +fail2: + g_topology_unlock(); + mtx_lock(&g_gate_units_lock); + g_gate_units[sc->sc_unit] = NULL; + KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?")); + g_gate_nunits--; +fail1: + mtx_unlock(&g_gate_units_lock); + mtx_destroy(&sc->sc_queue_mtx); + free(sc, M_GATE); + return (error); } static int |