From nobody Tue Sep 01 15:49:50 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hZ9KV4kBBz6r3t3 for ; Tue, 01 Sep 2026 15:49:50 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hZ9KV4B5qz47Qs for ; Tue, 01 Sep 2026 15:49:50 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788277790; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=zfpuVeN/PGL+ilelJB+UB9x5koDb6Y/b5Pq6fEH82Mw=; b=M4o6lLdbn945rNVnbdKgylm5dc3a6Ris0XUafaDWJX3zusqvNZGOuULsvDezb9Ad+itICk 8hli74Gu+DfFf9aFgPRyEUd9HBmvZRTl7Az6PxBZ8SEVkKwEoDfvI8jchiJMQb5iRtP6KJ 7SMZkpe8MFofz1Y4ubfNwH3fU7hvQva4LI6Wr1K0GFQGegHTWqr0nnvhKasYAoefXlOoLm rrzEqpdEH7oBTVzemdjuo8faqHCEFSkjBATfe7nunFSNVH8Kxu1iT3dkkhefn68/UmJgCO lirKg3Z3rtq0QGAAGFqfPgmNVZ1rpeOruXLHDCfq+nyUiu4A/m8WYX7rd91VOw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1788277790; a=rsa-sha256; cv=none; b=FK9fGuSGIJNWSwLwKYD1s+Fxazv0Ltz/ev6gvPjz/feCVdnuFdFvtucndC2VVdDPaV08Ef wwqTbztvXeG7NxMc86rdph5bsEGh94KiUUn3bwsw/SKzVM++0Qpnhpl45T3DAQbV0v/3UA EUi534UzW2UxYZWAVT3SwMtTwXsX5421HjNfG1qVU2bTYHGd37Dtlzs2RBXolUb/oeQNYJ UGtqFZVm2ejMDDRIiY4jLJkWrRohoemFxdB1dz8x5jrAI7+wh0qwhDsq/5bx90OGuAe9Zz QNHzAEy9ivzDZeEhKLnFw/TOCg9JPerchxPbdUUlnQUu+lv+WrgFFz2fN5TLMA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788277790; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=zfpuVeN/PGL+ilelJB+UB9x5koDb6Y/b5Pq6fEH82Mw=; b=g+0CQuC66KmrrptWYACdg2I+AUw3X+DBC/2sq4Ok6pHEzYQOnJn/uprIBsk8BYI+efJWOa cUro2ud7At/+e+POQLPXgY/WetU8M2oQqJsew6m5AnVIG1m1yuZ7P+aypNE+KYE4c4FnAj fk/K5YwMQkseA9iyz6dRWblzy286krbFcBFEjFAI41ZzJkP5keShQLQzdHNGZ3+VgdMwTL PCl2xcYKqf6RwrbFtoc3sDELvdfBZ74xRu4CpambR2jlWpBLFW8rWcLWIcxnOirOs23hsP xZLKQeiJjNl5oALnh46oKmvWX/egyuRydP6WcLPdmEFFSJWrqvoTQEi3MqjhuA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hZ9KV31HGz141Z for ; Tue, 01 Sep 2026 15:49:50 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 302bd by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 01 Sep 2026 15:49:50 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alexander Motin Subject: git: b55783976945 - main - gvirstor: Modernize the I/O path List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mav X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: b55783976945e900889d7ce9d5055a069de7441f Auto-Submitted: auto-generated Date: Tue, 01 Sep 2026 15:49:50 +0000 Message-Id: <6a96f41e.302bd.776d0147@gitrepo.freebsd.org> The branch main has been updated by mav: URL: https://cgit.FreeBSD.org/src/commit/?id=b55783976945e900889d7ce9d5055a069de7441f commit b55783976945e900889d7ce9d5055a069de7441f Author: Alexander Motin AuthorDate: 2026-09-01 15:39:13 +0000 Commit: Alexander Motin CommitDate: 2026-09-01 15:48:55 +0000 gvirstor: Modernize the I/O path - Add unmapped I/O support. The only case when the code needs data access is BIO_READ returning zeroes for unallocated space. - Add BIO_FLUSH support. Just send it to all allocated components. - Add BIO_DELETE support. While current design does not allow freeing allocated blocks, at least pass it to underlying providers. - Add direct I/O completion support. - Add rotation rate reporting. - Fix few minor issues. --- sys/geom/virstor/g_virstor.c | 306 ++++++++++++++++++++++++++++++++++++------- sys/geom/virstor/g_virstor.h | 3 + 2 files changed, 262 insertions(+), 47 deletions(-) diff --git a/sys/geom/virstor/g_virstor.c b/sys/geom/virstor/g_virstor.c index 1490ed103329..46c5216f66c1 100644 --- a/sys/geom/virstor/g_virstor.c +++ b/sys/geom/virstor/g_virstor.c @@ -46,9 +46,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include #include #include @@ -131,6 +135,9 @@ static void fill_metadata(struct g_virstor_softc *, struct g_virstor_metadata *, static void g_virstor_orphan(struct g_consumer *); static int g_virstor_access(struct g_provider *, int, int, int); +static void g_virstor_passdown(struct g_virstor_softc *, struct bio *); +static void g_virstor_candelete(struct g_virstor_softc *, struct bio *); +static void g_virstor_rotation_rate(struct g_virstor_softc *, struct bio *); static void g_virstor_start(struct bio *); static void g_virstor_dumpconf(struct sbuf *, const char *, struct g_geom *, struct g_consumer *, struct g_provider *); @@ -303,6 +310,10 @@ virstor_ctl_add(struct gctl_req *req, struct g_class *cp) gctl_error(req, "Virstor %s is incomplete", sc->geom->name); return; } + if (sc->provider == NULL) { + gctl_error(req, "Virstor %s is not running", sc->geom->name); + return; + } fcp = sc->components[0].gcons; added = 0; @@ -312,6 +323,8 @@ virstor_ctl_add(struct gctl_req *req, struct g_class *cp) char aname[8]; struct g_provider *pp; struct g_consumer *cp; + uint16_t rr; + int cd; u_int nc; u_int j; @@ -327,12 +340,33 @@ virstor_ctl_add(struct gctl_req *req, struct g_class *cp) g_topology_unlock(); return; } + if (fcp->provider->sectorsize != pp->sectorsize) { + gctl_error(req, "Sector size doesn't fit for %s", + pp->name); + g_topology_unlock(); + return; + } + if (pp->mediasize / sc->chunk_size < 4) { + gctl_error(req, "Provider too small: %s", pp->name); + g_topology_unlock(); + return; + } + for (j = 0; j < sc->n_components; j++) { + if (strcmp(sc->components[j].gcons->provider->name, + pp->name) == 0) { + gctl_error(req, "Component %s already in %s", + pp->name, sc->geom->name); + g_topology_unlock(); + return; + } + } cp = g_new_consumer(sc->geom); if (cp == NULL) { gctl_error(req, "Cannot create consumer"); g_topology_unlock(); return; } + cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; error = g_attach(cp, pp); if (error != 0) { gctl_error(req, "Cannot attach a consumer to %s", @@ -341,28 +375,22 @@ virstor_ctl_add(struct gctl_req *req, struct g_class *cp) g_topology_unlock(); return; } + /* Cascade candelete and rotation rate. */ + cd = 0; + rr = DISK_RR_UNKNOWN; + if (g_access(cp, 1, 0, 0) == 0) { + if (g_getattr("GEOM::candelete", cp, &cd) != 0) + cd = 0; + if (g_getattr("GEOM::rotation_rate", cp, &rr) != 0) + rr = DISK_RR_UNKNOWN; + g_access(cp, -1, 0, 0); + } if (fcp->acr != 0 || fcp->acw != 0 || fcp->ace != 0) { error = g_access(cp, fcp->acr, fcp->acw, fcp->ace); if (error != 0) { gctl_error(req, "Access request failed for %s", pp->name); - g_destroy_consumer(cp); - g_topology_unlock(); - return; - } - } - if (fcp->provider->sectorsize != pp->sectorsize) { - gctl_error(req, "Sector size doesn't fit for %s", - pp->name); - g_destroy_consumer(cp); - g_topology_unlock(); - return; - } - for (j = 0; j < sc->n_components; j++) { - if (strcmp(sc->components[j].gcons->provider->name, - pp->name) == 0) { - gctl_error(req, "Component %s already in %s", - pp->name, sc->geom->name); + g_detach(cp); g_destroy_consumer(cp); g_topology_unlock(); return; @@ -380,13 +408,15 @@ virstor_ctl_add(struct gctl_req *req, struct g_class *cp) sc->chunk_size; sc->components[nc].chunk_next = 0; sc->components[nc].chunk_reserved = 0; + sc->components[nc].flags = 0; + sc->components[nc].candelete = cd; + sc->components[nc].rotation_rate = rr; - if (sc->components[nc].chunk_count < 4) { - gctl_error(req, "Provider too small: %s", - cp->provider->name); - g_destroy_consumer(cp); - g_topology_unlock(); - return; + /* A provider underneath us doesn't support unmapped. */ + if ((pp->flags & G_PF_ACCEPT_UNMAPPED) == 0) { + LOG_MSG(LVL_INFO, "Cancelling unmapped because of %s", + pp->name); + sc->provider->flags &= ~G_PF_ACCEPT_UNMAPPED; } fill_metadata(sc, &md, nc, *hardcode); write_metadata(cp, &md); @@ -697,7 +727,7 @@ g_virstor_destroy_geom(struct gctl_req *req __unused, struct g_class *mp, "table for %s", sc->geom->name); count = 0; for (n = 0; n < sc->chunk_count; n++) { - if (sc->map[n].flags || VIRSTOR_MAP_ALLOCATED != 0) + if ((sc->map[n].flags & VIRSTOR_MAP_ALLOCATED) != 0) count++; } LOG_MSG(LVL_INFO, "Device %s has %d allocated chunks", @@ -956,6 +986,7 @@ virstor_geom_destroy(struct g_virstor_softc *sc, boolean_t force, } mtx_unlock(&sc->delayed_bio_q_mtx); mtx_destroy(&sc->delayed_bio_q_mtx); + mtx_destroy(&sc->completion_mtx); free(sc->map, M_GVIRSTOR); free(sc->components, M_GVIRSTOR); @@ -1104,6 +1135,8 @@ create_virstor_geom(struct g_class *mp, struct g_virstor_metadata *md) STAILQ_INIT(&sc->delayed_bio_q); mtx_init(&sc->delayed_bio_q_mtx, "gvirstor_delayed_bio_q_mtx", "gvirstor", MTX_DEF | MTX_RECURSE); + mtx_init(&sc->completion_mtx, "gvirstor_completion_mtx", "gvirstor", + MTX_DEF); sc->geom = gp; sc->provider = NULL; /* virstor_check_and_run will create it */ @@ -1138,6 +1171,7 @@ add_provider_to_geom(struct g_virstor_softc *sc, struct g_provider *pp, fcp = LIST_FIRST(&gp->consumer); cp = g_new_consumer(gp); + cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; error = g_attach(cp, pp); if (error != 0) { @@ -1145,12 +1179,27 @@ add_provider_to_geom(struct g_virstor_softc *sc, struct g_provider *pp, return (error); } + /* Cascade candelete and rotation rate. */ + component->candelete = 0; + component->rotation_rate = DISK_RR_UNKNOWN; + if (g_access(cp, 1, 0, 0) == 0) { + if (g_getattr("GEOM::candelete", cp, + &component->candelete) != 0) + component->candelete = 0; + if (g_getattr("GEOM::rotation_rate", cp, + &component->rotation_rate) != 0) + component->rotation_rate = DISK_RR_UNKNOWN; + g_access(cp, -1, 0, 0); + } + if (fcp != NULL) { if (fcp->provider->sectorsize != pp->sectorsize) { /* TODO: this can be made to work */ LOG_MSG(LVL_ERROR, "Provider %s of %s has invalid " "sector size (%d)", pp->name, sc->geom->name, pp->sectorsize); + g_detach(cp); + g_destroy_consumer(cp); return (EINVAL); } if (fcp->acr > 0 || fcp->acw || fcp->ace > 0) { @@ -1193,6 +1242,7 @@ virstor_check_and_run(struct g_virstor_softc *sc) size_t n, count; int index; int error; + bool unmapped; if (virstor_valid_components(sc) != sc->n_components) return; @@ -1221,8 +1271,19 @@ virstor_check_and_run(struct g_virstor_softc *sc) sc->map_sectors = sc->map_size / sc->sectorsize; count = 0; - for (n = 0; n < sc->n_components; n++) + unmapped = true; + for (n = 0; n < sc->n_components; n++) { + struct g_provider *cpp; + count += sc->components[n].chunk_count; + /* A provider underneath us doesn't support unmapped. */ + cpp = sc->components[n].gcons->provider; + if ((cpp->flags & G_PF_ACCEPT_UNMAPPED) == 0) { + LOG_MSG(LVL_INFO, "Cancelling unmapped because of %s", + cpp->name); + unmapped = false; + } + } LOG_MSG(LVL_INFO, "Device %s has %zu physical chunks and %zu virtual " "(%zu KB chunks)", sc->geom->name, count, sc->chunk_count, sc->chunk_size / 1024); @@ -1340,6 +1401,9 @@ virstor_check_and_run(struct g_virstor_softc *sc) sc->provider = g_new_providerf(sc->geom, "virstor/%s", sc->geom->name); + sc->provider->flags |= G_PF_DIRECT_SEND; + if (unmapped) + sc->provider->flags |= G_PF_ACCEPT_UNMAPPED; sc->provider->sectorsize = sc->sectorsize; sc->provider->mediasize = sc->virsize; g_error_provider(sc->provider, 0); @@ -1476,41 +1540,39 @@ g_virstor_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, indent, comp->chunk_reserved); sbuf_printf(sb, "%s%u%%\n", indent, - comp->chunk_next > 0 ? 100 - - ((comp->chunk_next + comp->chunk_reserved) * 100) / - comp->chunk_count : 100); + 100 - (u_int)((uint64_t)comp->chunk_next * 100 / + comp->chunk_count)); } else { /* For the whole thing */ - u_int count, used, i; - off_t size; + off_t count, used, size; + u_int pfree, i; count = used = size = 0; for (i = 0; i < sc->n_components; i++) { if (sc->components[i].gcons != NULL) { count += sc->components[i].chunk_count; - used += sc->components[i].chunk_next + - sc->components[i].chunk_reserved; + used += sc->components[i].chunk_next; size += sc->components[i].gcons-> provider->mediasize; } } + pfree = count > 0 ? 100 - (u_int)(used * 100 / count) : 100; sbuf_printf(sb, "%s" "Components=%u, Online=%u\n", indent, sc->n_components, virstor_valid_components(sc)); sbuf_printf(sb, "%s%u%% physical free\n", - indent, 100-(used * 100) / count); + indent, pfree); sbuf_printf(sb, "%s%zu\n", indent, sc->chunk_size); sbuf_printf(sb, "%s%u%%\n", - indent, used > 0 ? 100 - (used * 100) / count : 100); - sbuf_printf(sb, "%s%u\n", + indent, pfree); + sbuf_printf(sb, "%s%jd\n", indent, count); sbuf_printf(sb, "%s%zu\n", indent, sc->chunk_count); - sbuf_printf(sb, "%s%zu%%\n", - indent, - (count * 100) / sc->chunk_count); + sbuf_printf(sb, "%s%jd%%\n", + indent, count * 100 / (off_t)sc->chunk_count); sbuf_printf(sb, "%s%jd\n", indent, size); sbuf_printf(sb, "%s%jd\n", indent, @@ -1526,28 +1588,142 @@ g_virstor_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, static void g_virstor_done(struct bio *b) { + struct g_virstor_softc *sc; struct bio *parent_b; parent_b = b->bio_parent; + sc = parent_b->bio_to->geom->softc; if (b->bio_error != 0) { LOG_MSG(LVL_ERROR, "Error %d for offset=%ju, length=%ju, %s", b->bio_error, b->bio_offset, b->bio_length, b->bio_to->name); - if (parent_b->bio_error == 0) - parent_b->bio_error = b->bio_error; } + mtx_lock(&sc->completion_mtx); + if (parent_b->bio_error == 0) + parent_b->bio_error = b->bio_error; parent_b->bio_inbed++; parent_b->bio_completed += b->bio_completed; - if (parent_b->bio_children == parent_b->bio_inbed) { + mtx_unlock(&sc->completion_mtx); parent_b->bio_completed = parent_b->bio_length; g_io_deliver(parent_b, parent_b->bio_error); - } + } else + mtx_unlock(&sc->completion_mtx); g_destroy_bio(b); } +/* + * Pass the request down to every allocated component. A chunk may be + * allocated on any of them, so all have to be covered. Components without + * any allocated chunks never received a data write, so they are skipped. + */ +static void +g_virstor_passdown(struct g_virstor_softc *sc, struct bio *b) +{ + struct bio_queue_head bq; + struct g_virstor_component *comp; + struct bio *cb; + u_int n; + + bioq_init(&bq); + for (n = 0; n < sc->n_components; n++) { + comp = &sc->components[n]; + if (comp->gcons == NULL || + (comp->flags & VIRSTOR_PROVIDER_ALLOCATED) == 0) + continue; + cb = g_clone_bio(b); + if (cb == NULL) { + bioq_dismantle(&bq); + if (b->bio_error == 0) + b->bio_error = ENOMEM; + g_io_deliver(b, b->bio_error); + return; + } + cb->bio_done = g_virstor_done; + cb->bio_to = comp->gcons->provider; + cb->bio_caller1 = comp; + bioq_insert_tail(&bq, cb); + } + KASSERT(bioq_first(&bq) != NULL, + ("%s: No allocated components in %s", __func__, sc->geom->name)); + while ((cb = bioq_takefirst(&bq)) != NULL) { + comp = cb->bio_caller1; + cb->bio_caller1 = NULL; + LOG_REQ(LVL_MOREDEBUG, cb, "Firing request"); + g_io_request(cb, comp->gcons); + } +} + +/* + * Report BIO_DELETE support if any of the components supports it. + */ +static void +g_virstor_candelete(struct g_virstor_softc *sc, struct bio *b) +{ + int val; + u_int n; + + for (n = 0; n < sc->n_components; n++) { + if (sc->components[n].gcons != NULL && + sc->components[n].candelete) + break; + } + val = n < sc->n_components; + g_handleattr(b, "GEOM::candelete", &val, sizeof(val)); +} + +/* + * Report the rotation rate of the components, if they all agree on it. + */ +static void +g_virstor_rotation_rate(struct g_virstor_softc *sc, struct bio *b) +{ + uint16_t rr = DISK_RR_UNKNOWN; + bool first = true; + u_int n; + + for (n = 0; n < sc->n_components; n++) { + if (sc->components[n].gcons == NULL) + continue; + if (first) + rr = sc->components[n].rotation_rate; + else if (rr != sc->components[n].rotation_rate) { + rr = DISK_RR_UNKNOWN; + break; + } + first = false; + } + g_handleattr(b, "GEOM::rotation_rate", &rr, sizeof(rr)); +} + +/* + * Zero a part of the request's buffer. For unmapped requests addr is not a + * pointer, but an offset from the beginning of the buffer. + */ +static void +g_virstor_zero(struct bio *b, char *addr, size_t length) +{ + vm_page_t *ma; + size_t moff, len; + + if ((b->bio_flags & BIO_UNMAPPED) == 0) { + bzero(addr, length); + return; + } + moff = b->bio_ma_offset + (uintptr_t)addr; + ma = b->bio_ma + moff / PAGE_SIZE; + moff %= PAGE_SIZE; + while (length > 0) { + len = MIN(PAGE_SIZE - moff, length); + pmap_zero_page_area(*ma, moff, len); + ma++; + moff = 0; + length -= len; + } +} + /* * I/O starts here * Called in g_down thread @@ -1577,6 +1753,20 @@ g_virstor_start(struct bio *b) case BIO_WRITE: case BIO_DELETE: break; + case BIO_FLUSH: + g_virstor_passdown(sc, b); + return; + case BIO_GETATTR: + if (strcmp(b->bio_attribute, "GEOM::candelete") == 0) { + g_virstor_candelete(sc, b); + return; + } + if (strcmp(b->bio_attribute, "GEOM::rotation_rate") == 0) { + g_virstor_rotation_rate(sc, b); + return; + } + /* To which component should it be delivered? */ + /* FALLTHROUGH */ default: g_io_deliver(b, EOPNOTSUPP); return; @@ -1586,7 +1776,10 @@ g_virstor_start(struct bio *b) bioq_init(&bq); chunk_size = sc->chunk_size; - addr = b->bio_data; + if ((b->bio_flags & BIO_UNMAPPED) != 0) + addr = NULL; + else + addr = b->bio_data; offset = b->bio_offset; /* virtual offset and length */ length = b->bio_length; @@ -1608,7 +1801,8 @@ g_virstor_start(struct bio *b) /* Reads from unallocated chunks return zeroed * buffers */ if (b->bio_cmd == BIO_READ) - bzero(addr, in_chunk_length); + g_virstor_zero(b, addr, + in_chunk_length); } else { comp = &sc->components[me->provider_no]; @@ -1626,7 +1820,16 @@ g_virstor_start(struct bio *b) (off_t)me->provider_chunk * (off_t)chunk_size + in_chunk_offset; cb->bio_length = in_chunk_length; - cb->bio_data = addr; + if ((b->bio_flags & BIO_UNMAPPED) != 0) { + cb->bio_ma_offset += (uintptr_t)addr; + cb->bio_ma += cb->bio_ma_offset / + PAGE_SIZE; + cb->bio_ma_offset %= PAGE_SIZE; + cb->bio_ma_n = round_page( + cb->bio_ma_offset + + cb->bio_length) / PAGE_SIZE; + } else + cb->bio_data = addr; cb->bio_caller1 = comp; bioq_disksort(&bq, cb); } @@ -1716,6 +1919,7 @@ g_virstor_start(struct bio *b) cb->bio_done = g_virstor_done; cb->bio_offset = s_offset; cb->bio_data = (char *)data_me; + cb->bio_flags &= ~BIO_UNMAPPED; cb->bio_length = sc->sectorsize; cb->bio_caller1 = &sc->components[0]; bioq_disksort(&bq, cb); @@ -1736,11 +1940,19 @@ g_virstor_start(struct bio *b) cb->bio_offset = (off_t)me->provider_chunk*(off_t)chunk_size + in_chunk_offset; cb->bio_length = in_chunk_length; - cb->bio_data = addr; + if ((b->bio_flags & BIO_UNMAPPED) != 0) { + cb->bio_ma_offset += (uintptr_t)addr; + cb->bio_ma += cb->bio_ma_offset / PAGE_SIZE; + cb->bio_ma_offset %= PAGE_SIZE; + cb->bio_ma_n = round_page(cb->bio_ma_offset + + cb->bio_length) / PAGE_SIZE; + } else + cb->bio_data = addr; cb->bio_caller1 = comp; bioq_disksort(&bq, cb); } - addr += in_chunk_length; + if (b->bio_cmd != BIO_DELETE) + addr += in_chunk_length; length -= in_chunk_length; offset += in_chunk_length; } diff --git a/sys/geom/virstor/g_virstor.h b/sys/geom/virstor/g_virstor.h index a7f81b6bea9b..38e84612b3e0 100644 --- a/sys/geom/virstor/g_virstor.h +++ b/sys/geom/virstor/g_virstor.h @@ -76,6 +76,8 @@ struct g_virstor_component { unsigned int chunk_next; unsigned int chunk_reserved; unsigned int flags; + int candelete; + uint16_t rotation_rate; }; /* Internal geom instance data */ @@ -96,6 +98,7 @@ struct g_virstor_softc { size_t me_per_sector; /* # map entries in a sector */ STAILQ_HEAD(, g_virstor_bio_q) delayed_bio_q; /* Queue of delayed BIOs */ struct mtx delayed_bio_q_mtx; + struct mtx completion_mtx; /* Synchronizes completions */ }; /* "delayed BIOs" Queue element */