From 4527e1db7923906ab174dcc930abcb5d96d01b64 Mon Sep 17 00:00:00 2001 From: longpanda Date: Tue, 23 Jan 2024 09:08:23 +0800 Subject: [PATCH] Add support for FreeBSD 14.0 --- INSTALL/ventoy/ventoy_unix.cpio | Bin 130560 -> 131584 bytes .../geom_ventoy_ko/14.x/32/geom_ventoy.ko.xz | Bin 8124 -> 8656 bytes .../geom_ventoy_ko/14.x/64/geom_ventoy.ko.xz | Bin 7908 -> 7900 bytes .../14.x/sys/geom/ventoy/g_ventoy.c | 1243 +++++++++++++++++ .../14.x/sys/geom/ventoy/g_ventoy.h | 147 ++ .../sys/modules/geom/geom_ventoy/Makefile | 8 + 6 files changed, 1398 insertions(+) create mode 100644 Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.c create mode 100644 Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.h create mode 100644 Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/modules/geom/geom_ventoy/Makefile diff --git a/INSTALL/ventoy/ventoy_unix.cpio b/INSTALL/ventoy/ventoy_unix.cpio index 7583906586c5f4463396ea2a8a6b9d1758e1e895..630a5af643c6fcadbd7c816c06d4b1f9092bdc82 100644 GIT binary patch delta 19313 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 V&3_qd>p@G11`v#N`^yI?>;WcrcK!eW delta 18235 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 literal 8124 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 diff --git a/Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/14.x/64/geom_ventoy.ko.xz b/Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/14.x/64/geom_ventoy.ko.xz index cdcdd12e5bc57a51b554589546d5ef70ab646bf5..69a736705be619a0db624f161040be70f4b1debd 100644 GIT binary patch literal 7900 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 G0a;p)e?{*A literal 7908 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 + * Copyright (c) 2004-2005 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +FEATURE(geom_ventoy, "GEOM ventoy support"); + +static MALLOC_DEFINE(M_VENTOY, "ventoy_data", "GEOM_VENTOY Data"); + +SYSCTL_DECL(_kern_geom); +static SYSCTL_NODE(_kern_geom, OID_AUTO, ventoy, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, + "GEOM_VENTOY stuff"); +static u_int g_ventoy_debug = 0; +SYSCTL_UINT(_kern_geom_ventoy, OID_AUTO, debug, CTLFLAG_RWTUN, &g_ventoy_debug, 0, + "Debug level"); + +extern int resource_string_value(const char *name, int unit, const char *resname, const char **result); +extern int resource_int_value(const char *name, int unit, const char *resname, int *result); + +static int g_ventoy_destroy(struct g_ventoy_softc *sc, boolean_t force); +static int g_ventoy_destroy_geom(struct gctl_req *req, struct g_class *mp, + struct g_geom *gp); + +static g_taste_t g_ventoy_taste; +static g_ctl_req_t g_ventoy_config; +static g_dumpconf_t g_ventoy_dumpconf; + +static char g_ventoy_disk_uuid[64]; +static bool g_ventoy_tasted = false; +static off_t g_ventoy_disk_size = 0; +static off_t g_disk_map_start = 0; +static off_t g_disk_map_end = 0; +static int g_ventoy_remount = 0; + +struct g_ventoy_map g_ventoy_map_data __attribute__((aligned (4096))) = +{ + { VENTOY_UNIX_SEG_MAGIC0, VENTOY_UNIX_SEG_MAGIC1, VENTOY_UNIX_SEG_MAGIC2, VENTOY_UNIX_SEG_MAGIC3 }, + { 0, 0, 0, 0 }, + 0, 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { { 0, 0 } }, + { VENTOY_UNIX_SEG_MAGIC0, VENTOY_UNIX_SEG_MAGIC1, VENTOY_UNIX_SEG_MAGIC2, VENTOY_UNIX_SEG_MAGIC3 } +}; + +struct g_class g_ventoy_class = { + .name = G_VENTOY_CLASS_NAME, + .version = G_VERSION, + .ctlreq = g_ventoy_config, + .taste = g_ventoy_taste, + .destroy_geom = g_ventoy_destroy_geom +}; + + +/* + * Greatest Common Divisor. + */ +static u_int +gcd(u_int a, u_int b) +{ + u_int c; + + while (b != 0) { + c = a; + a = b; + b = (c % b); + } + return (a); +} + +/* + * Least Common Multiple. + */ +static u_int +lcm(u_int a, u_int b) +{ + + return ((a * b) / gcd(a, b)); +} + +/* + * Return the number of valid disks. + */ +static u_int +g_ventoy_nvalid(struct g_ventoy_softc *sc) +{ + u_int no; + struct g_ventoy_disk *disk; + + sx_assert(&sc->sc_disks_lock, SA_LOCKED); + + no = 0; + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + if (disk->d_consumer != NULL) + no++; + } + + return (no); +} + +static void +g_ventoy_remove_disk(struct g_ventoy_disk *disk) +{ + struct g_consumer *cp; + struct g_ventoy_softc *sc; + + g_topology_assert(); + KASSERT(disk->d_consumer != NULL, ("Non-valid disk in %s.", __func__)); + sc = disk->d_softc; + cp = disk->d_consumer; + + if (!disk->d_removed) { + G_VENTOY_DEBUG(0, "Disk %s removed from %s.", + cp->provider->name, sc->sc_name); + disk->d_removed = 1; + } + + if (sc->sc_provider != NULL) { + G_VENTOY_DEBUG(0, "Device %s deactivated.", + sc->sc_provider->name); + g_wither_provider(sc->sc_provider, ENXIO); + sc->sc_provider = NULL; + } + + if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) + return; + disk->d_consumer = NULL; + g_detach(cp); + g_destroy_consumer(cp); + /* If there are no valid disks anymore, remove device. */ + if (LIST_EMPTY(&sc->sc_geom->consumer)) + g_ventoy_destroy(sc, 1); +} + +static void +g_ventoy_orphan(struct g_consumer *cp) +{ + struct g_ventoy_softc *sc; + struct g_ventoy_disk *disk; + struct g_geom *gp; + + g_topology_assert(); + gp = cp->geom; + sc = gp->softc; + if (sc == NULL) + return; + + disk = cp->private; + if (disk == NULL) /* Possible? */ + return; + g_ventoy_remove_disk(disk); +} + +static int +g_ventoy_access(struct g_provider *pp, int dr, int dw, int de) +{ + struct g_consumer *cp1, *cp2, *tmp; + struct g_ventoy_disk *disk; + struct g_geom *gp; + struct g_ventoy_softc *sc; + int error; + + if (dw > 0) /* readonly */ + return (EPERM); + + g_topology_assert(); + gp = pp->geom; + sc = gp->softc; + + if (g_ventoy_remount) + { + de = 0; + } + else + { + /* On first open, grab an extra "exclusive" bit */ + if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) + de++; + /* ... and let go of it on last close */ + if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && (pp->ace + de) == 0) + de--; + } + + sx_slock(&sc->sc_disks_lock); + LIST_FOREACH_SAFE(cp1, &gp->consumer, consumer, tmp) { + error = g_access(cp1, dr, dw, de); + if (error != 0) + goto fail; + disk = cp1->private; + if (cp1->acr == 0 && cp1->acw == 0 && cp1->ace == 0 && + disk->d_removed) { + g_ventoy_remove_disk(disk); /* May destroy geom. */ + } + } + sx_sunlock(&sc->sc_disks_lock); + return (0); + +fail: + sx_sunlock(&sc->sc_disks_lock); + LIST_FOREACH(cp2, &gp->consumer, consumer) { + if (cp1 == cp2) + break; + g_access(cp2, -dr, -dw, -de); + } + return (error); +} + +static void +g_ventoy_candelete(struct bio *bp) +{ + struct g_ventoy_softc *sc; + struct g_ventoy_disk *disk; + int val; + + sc = bp->bio_to->geom->softc; + sx_assert(&sc->sc_disks_lock, SX_LOCKED); + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + if (!disk->d_removed && disk->d_candelete) + break; + } + val = disk != NULL; + g_handleattr(bp, "GEOM::candelete", &val, sizeof(val)); +} + +static void +g_ventoy_kernel_dump(struct bio *bp) +{ + struct g_ventoy_softc *sc; + struct g_ventoy_disk *disk; + struct bio *cbp; + struct g_kerneldump *gkd; + + sc = bp->bio_to->geom->softc; + gkd = (struct g_kerneldump *)bp->bio_data; + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + if (disk->d_start <= gkd->offset && + disk->d_end > gkd->offset) + break; + } + if (disk == NULL) { + g_io_deliver(bp, EOPNOTSUPP); + return; + } + + gkd->offset -= disk->d_start; + if (gkd->length > disk->d_end - disk->d_start - gkd->offset) + gkd->length = disk->d_end - disk->d_start - gkd->offset; + cbp = g_clone_bio(bp); + if (cbp == NULL) { + g_io_deliver(bp, ENOMEM); + return; + } + cbp->bio_done = g_std_done; + g_io_request(cbp, disk->d_consumer); + G_VENTOY_DEBUG(1, "Kernel dump will go to %s.", + disk->d_consumer->provider->name); +} + +static void +g_ventoy_done(struct bio *bp) +{ + struct g_ventoy_softc *sc; + struct bio *pbp; + + pbp = bp->bio_parent; + sc = pbp->bio_to->geom->softc; + mtx_lock(&sc->sc_completion_lock); + if (pbp->bio_error == 0) + pbp->bio_error = bp->bio_error; + pbp->bio_completed += bp->bio_completed; + pbp->bio_inbed++; + if (pbp->bio_children == pbp->bio_inbed) { + mtx_unlock(&sc->sc_completion_lock); + g_io_deliver(pbp, pbp->bio_error); + } else + mtx_unlock(&sc->sc_completion_lock); + g_destroy_bio(bp); +} + +static void +g_ventoy_flush(struct g_ventoy_softc *sc, struct bio *bp) +{ + struct bio_queue_head queue; + struct g_consumer *cp; + struct bio *cbp; + struct g_ventoy_disk *disk; + + sx_assert(&sc->sc_disks_lock, SX_LOCKED); + + bioq_init(&queue); + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + cbp = g_clone_bio(bp); + if (cbp == NULL) { + while ((cbp = bioq_takefirst(&queue)) != NULL) + g_destroy_bio(cbp); + if (bp->bio_error == 0) + bp->bio_error = ENOMEM; + g_io_deliver(bp, bp->bio_error); + return; + } + bioq_insert_tail(&queue, cbp); + cbp->bio_done = g_ventoy_done; + cbp->bio_caller1 = disk->d_consumer; + cbp->bio_to = disk->d_consumer->provider; + } + while ((cbp = bioq_takefirst(&queue)) != NULL) { + G_VENTOY_LOGREQ(cbp, "Sending request."); + cp = cbp->bio_caller1; + cbp->bio_caller1 = NULL; + g_io_request(cbp, cp); + } +} + +static void +g_ventoy_start(struct bio *bp) +{ + struct bio_queue_head queue; + struct g_ventoy_softc *sc; + struct g_ventoy_disk *disk; + struct g_provider *pp; + off_t offset, end, length, off, len; + struct bio *cbp; + char *addr; + + pp = bp->bio_to; + sc = pp->geom->softc; + /* + * If sc == NULL, provider's error should be set and g_ventoy_start() + * should not be called at all. + */ + KASSERT(sc != NULL, + ("Provider's error should be set (error=%d)(device=%s).", + bp->bio_to->error, bp->bio_to->name)); + + G_VENTOY_LOGREQ(bp, "Request received."); + sx_slock(&sc->sc_disks_lock); + + switch (bp->bio_cmd) { + case BIO_READ: + case BIO_WRITE: + case BIO_DELETE: + break; + case BIO_SPEEDUP: + case BIO_FLUSH: + g_ventoy_flush(sc, bp); + goto end; + case BIO_GETATTR: + if (strcmp("GEOM::kerneldump", bp->bio_attribute) == 0) { + g_ventoy_kernel_dump(bp); + goto end; + } else if (strcmp("GEOM::candelete", bp->bio_attribute) == 0) { + g_ventoy_candelete(bp); + goto end; + } + /* To which provider it should be delivered? */ + /* FALLTHROUGH */ + default: + g_io_deliver(bp, EOPNOTSUPP); + goto end; + } + + offset = bp->bio_offset; + length = bp->bio_length; + if ((bp->bio_flags & BIO_UNMAPPED) != 0) + addr = NULL; + else + addr = bp->bio_data; + end = offset + length; + + bioq_init(&queue); + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + if (disk->d_end <= offset) + continue; + if (disk->d_start >= end) + break; + + off = offset - disk->d_start; + len = MIN(length, disk->d_end - offset); + length -= len; + offset += len; + + cbp = g_clone_bio(bp); + if (cbp == NULL) { + while ((cbp = bioq_takefirst(&queue)) != NULL) + g_destroy_bio(cbp); + if (bp->bio_error == 0) + bp->bio_error = ENOMEM; + g_io_deliver(bp, bp->bio_error); + goto end; + } + bioq_insert_tail(&queue, cbp); + /* + * Fill in the component buf structure. + */ + if (len == bp->bio_length) + cbp->bio_done = g_std_done; + else + cbp->bio_done = g_ventoy_done; + cbp->bio_offset = off + disk->d_map_start; + cbp->bio_length = len; + if ((bp->bio_flags & BIO_UNMAPPED) != 0) { + cbp->bio_ma_offset += (uintptr_t)addr; + cbp->bio_ma += cbp->bio_ma_offset / PAGE_SIZE; + cbp->bio_ma_offset %= PAGE_SIZE; + cbp->bio_ma_n = round_page(cbp->bio_ma_offset + + cbp->bio_length) / PAGE_SIZE; + } else + cbp->bio_data = addr; + addr += len; + cbp->bio_to = disk->d_consumer->provider; + cbp->bio_caller1 = disk; + + if (length == 0) + break; + } + KASSERT(length == 0, + ("Length is still greater than 0 (class=%s, name=%s).", + bp->bio_to->geom->class->name, bp->bio_to->geom->name)); + while ((cbp = bioq_takefirst(&queue)) != NULL) { + G_VENTOY_LOGREQ(cbp, "Sending request."); + disk = cbp->bio_caller1; + cbp->bio_caller1 = NULL; + g_io_request(cbp, disk->d_consumer); + } +end: + sx_sunlock(&sc->sc_disks_lock); +} + +static void +g_ventoy_check_and_run(struct g_ventoy_softc *sc) +{ + struct g_ventoy_disk *disk; + struct g_provider *dp, *pp; + u_int sectorsize = 0; + off_t start; + int error; + + g_topology_assert(); + if (g_ventoy_nvalid(sc) != sc->sc_ndisks) + return; + + pp = g_new_providerf(sc->sc_geom, "ventoy/%s", sc->sc_name); + pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE | + G_PF_ACCEPT_UNMAPPED; + start = 0; + TAILQ_FOREACH(disk, &sc->sc_disks, d_next) { + dp = disk->d_consumer->provider; + disk->d_start = start; + disk->d_end = disk->d_start + (disk->d_map_end - disk->d_map_start); + if (sc->sc_type == G_VENTOY_TYPE_AUTOMATIC) + disk->d_end -= dp->sectorsize; + start = disk->d_end; + error = g_access(disk->d_consumer, 1, 0, 0); + if (error == 0) { + error = g_getattr("GEOM::candelete", disk->d_consumer, + &disk->d_candelete); + if (error != 0) + disk->d_candelete = 0; + (void)g_access(disk->d_consumer, -1, 0, 0); + } else + G_VENTOY_DEBUG(1, "Failed to access disk %s, error %d.", + dp->name, error); + if (disk == TAILQ_FIRST(&sc->sc_disks)) + sectorsize = dp->sectorsize; + else + sectorsize = lcm(sectorsize, dp->sectorsize); + + /* A provider underneath us doesn't support unmapped */ + if ((dp->flags & G_PF_ACCEPT_UNMAPPED) == 0) { + G_VENTOY_DEBUG(1, "Cancelling unmapped " + "because of %s.", dp->name); + pp->flags &= ~G_PF_ACCEPT_UNMAPPED; + } + } + pp->sectorsize = sectorsize; + /* We have sc->sc_disks[sc->sc_ndisks - 1].d_end in 'start'. */ + pp->mediasize = start; + dp = TAILQ_FIRST(&sc->sc_disks)->d_consumer->provider; + pp->stripesize = dp->stripesize; + pp->stripeoffset = dp->stripeoffset; + sc->sc_provider = pp; + g_error_provider(pp, 0); + + G_VENTOY_DEBUG(0, "Device %s activated.", sc->sc_provider->name); +} + +static int +g_ventoy_read_metadata(struct g_consumer *cp, struct g_ventoy_metadata *md) +{ + struct g_provider *pp; + u_char *buf; + int error; + + g_topology_assert(); + + error = g_access(cp, 1, 0, 0); + if (error != 0) + return (error); + pp = cp->provider; + g_topology_unlock(); + buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, + &error); + g_topology_lock(); + g_access(cp, -1, 0, 0); + if (buf == NULL) + return (error); + + /* Decode metadata. */ + ventoy_metadata_decode(buf, md); + g_free(buf); + + return (0); +} + +/* + * Add disk to given device. + */ +static int +g_ventoy_add_disk(struct g_ventoy_softc *sc, struct g_provider *pp, u_int no) +{ + struct g_ventoy_disk *disk; + struct g_consumer *cp, *fcp; + struct g_geom *gp; + int error; + + g_topology_assert(); + + sx_slock(&sc->sc_disks_lock); + + /* Metadata corrupted? */ + if (no >= sc->sc_ndisks) { + sx_sunlock(&sc->sc_disks_lock); + return (EINVAL); + } + + for (disk = TAILQ_FIRST(&sc->sc_disks); no > 0; no--) { + disk = TAILQ_NEXT(disk, d_next); + } + + /* Check if disk is not already attached. */ + if (disk->d_consumer != NULL) { + sx_sunlock(&sc->sc_disks_lock); + return (EEXIST); + } + + gp = sc->sc_geom; + 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) { + sx_sunlock(&sc->sc_disks_lock); + g_destroy_consumer(cp); + return (error); + } + + if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) { + error = g_access(cp, fcp->acr, fcp->acw, fcp->ace); + if (error != 0) { + sx_sunlock(&sc->sc_disks_lock); + g_detach(cp); + g_destroy_consumer(cp); + return (error); + } + } + if (sc->sc_type == G_VENTOY_TYPE_AUTOMATIC) { + struct g_ventoy_metadata md; + + // temporarily give up the lock to avoid lock order violation + // due to topology unlock in g_concat_read_metadata + sx_sunlock(&sc->sc_disks_lock); + /* Re-read metadata. */ + error = g_ventoy_read_metadata(cp, &md); + sx_slock(&sc->sc_disks_lock); + + if (error != 0) + goto fail; + + if (strcmp(md.md_magic, G_VENTOY_MAGIC) != 0 || + strcmp(md.md_name, sc->sc_name) != 0 || + md.md_id != sc->sc_id) { + G_VENTOY_DEBUG(0, "Metadata on %s changed.", pp->name); + goto fail; + } + + disk->d_hardcoded = md.md_provider[0] != '\0'; + } else { + disk->d_hardcoded = false; + } + + cp->private = disk; + disk->d_consumer = cp; + disk->d_softc = sc; + disk->d_start = 0; /* not yet */ + disk->d_end = 0; /* not yet */ + disk->d_removed = 0; + + disk->d_map_start = g_disk_map_start; + disk->d_map_end = g_disk_map_end; + + G_VENTOY_DEBUG(0, "Disk %s attached to %s.", pp->name, sc->sc_name); + + g_ventoy_check_and_run(sc); + sx_sunlock(&sc->sc_disks_lock); // need lock for check_and_run + + return (0); +fail: + sx_sunlock(&sc->sc_disks_lock); // need lock for check_and_run + if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) + g_access(cp, -fcp->acr, -fcp->acw, -fcp->ace); + g_detach(cp); + g_destroy_consumer(cp); + return (error); +} + +static struct g_geom * +g_ventoy_create(struct g_class *mp, const struct g_ventoy_metadata *md, + u_int type) +{ + struct g_ventoy_softc *sc; + struct g_ventoy_disk *disk; + struct g_geom *gp; + u_int no; + + G_VENTOY_DEBUG(1, "Creating device %s (id=%u).", md->md_name, + md->md_id); + + /* One disks is minimum. */ + if (md->md_all < 1) + return (NULL); + + /* Check for duplicate unit */ + LIST_FOREACH(gp, &mp->geom, geom) { + sc = gp->softc; + if (sc != NULL && strcmp(sc->sc_name, md->md_name) == 0) { + G_VENTOY_DEBUG(0, "Device %s already configured.", + gp->name); + return (NULL); + } + } + gp = g_new_geomf(mp, "%s", md->md_name); + sc = malloc(sizeof(*sc), M_VENTOY, M_WAITOK | M_ZERO); + gp->start = g_ventoy_start; + gp->spoiled = g_ventoy_orphan; + gp->orphan = g_ventoy_orphan; + gp->access = g_ventoy_access; + gp->dumpconf = g_ventoy_dumpconf; + + sc->sc_id = md->md_id; + sc->sc_ndisks = md->md_all; + TAILQ_INIT(&sc->sc_disks); + for (no = 0; no < sc->sc_ndisks; no++) { + disk = malloc(sizeof(*disk), M_VENTOY, M_WAITOK | M_ZERO); + TAILQ_INSERT_TAIL(&sc->sc_disks, disk, d_next); + } + sc->sc_type = type; + mtx_init(&sc->sc_completion_lock, "gventoy lock", NULL, MTX_DEF); + sx_init(&sc->sc_disks_lock, "gventoy append lock"); + + gp->softc = sc; + sc->sc_geom = gp; + sc->sc_provider = NULL; + + G_VENTOY_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id); + + return (gp); +} + +static int +g_ventoy_destroy(struct g_ventoy_softc *sc, boolean_t force) +{ + struct g_provider *pp; + struct g_consumer *cp, *cp1; + struct g_geom *gp; + struct g_ventoy_disk *disk; + + g_topology_assert(); + + if (sc == NULL) + return (ENXIO); + + pp = sc->sc_provider; + if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { + if (force) { + G_VENTOY_DEBUG(0, "Device %s is still open, so it " + "can't be definitely removed.", pp->name); + } else { + G_VENTOY_DEBUG(1, + "Device %s is still open (r%dw%de%d).", pp->name, + pp->acr, pp->acw, pp->ace); + return (EBUSY); + } + } + + gp = sc->sc_geom; + LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { + g_ventoy_remove_disk(cp->private); + if (cp1 == NULL) + return (0); /* Recursion happened. */ + } + if (!LIST_EMPTY(&gp->consumer)) + return (EINPROGRESS); + + gp->softc = NULL; + KASSERT(sc->sc_provider == NULL, ("Provider still exists? (device=%s)", + gp->name)); + while ((disk = TAILQ_FIRST(&sc->sc_disks)) != NULL) { + TAILQ_REMOVE(&sc->sc_disks, disk, d_next); + free(disk, M_VENTOY); + } + mtx_destroy(&sc->sc_completion_lock); + sx_destroy(&sc->sc_disks_lock); + free(sc, M_VENTOY); + + G_VENTOY_DEBUG(0, "Device %s destroyed.", gp->name); + g_wither_geom(gp, ENXIO); + return (0); +} + +static int +g_ventoy_destroy_geom(struct gctl_req *req __unused, + struct g_class *mp __unused, struct g_geom *gp) +{ + struct g_ventoy_softc *sc; + + sc = gp->softc; + return (g_ventoy_destroy(sc, 0)); +} + +static bool g_vtoy_check_disk(struct g_class *mp, struct g_provider *pp) +{ + int i; + int vlnk = 0; + bool ret = true; + uint8_t *buf; + char uuid[64]; + const char *value; + struct g_consumer *cp; + struct g_geom *gp; + uint8_t mbrdata[] = { + 0xEB, 0x63, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x54, 0x00, 0x47, 0x65, 0x00, 0x48, 0x44, 0x00, 0x52, 0x64, 0x00, 0x20, 0x45, 0x72, 0x0D, + }; + + if (g_ventoy_disk_size == 0) + { + if (VENTOY_MAP_VALID(g_ventoy_map_data.magic2)) + { + G_DEBUG("ventoy map data is valid. [OK]\n"); + + for (i = 0; i < 16; i++) + { + sprintf(uuid + i * 2, "%02x", g_ventoy_map_data.diskuuid[i]); + } + snprintf(g_ventoy_disk_uuid, sizeof(g_ventoy_disk_uuid), "%s", uuid); + g_ventoy_disk_size = g_ventoy_map_data.disksize; + + G_DEBUG("ventoy.disksize: %llu\n", (unsigned long long)g_ventoy_disk_size); + G_DEBUG("ventoy.diskuuid: <%s>\n", g_ventoy_disk_uuid); + } + else + { + G_DEBUG("ventoy map data is invalid, get from resource\n"); + + if (resource_string_value("ventoy", 0, "disksize", &value) == 0) + { + G_DEBUG("ventoy.disksize: %s\n", value); + g_ventoy_disk_size = strtouq(value, NULL, 0); + } + + if (resource_string_value("ventoy", 0, "diskuuid", &value) == 0) + { + snprintf(g_ventoy_disk_uuid, sizeof(g_ventoy_disk_uuid), "%s", value); + G_DEBUG("ventoy.diskuuid: <%s>\n", value); + } + } + } + + if (g_ventoy_disk_size != pp->mediasize) + { + return false; + } + + if (strncmp(pp->name, "cd", 2) == 0 || strchr(pp->name, '/')) + { + return false; + } + + /* read UUID from disk */ + gp = g_new_geomf(mp, "ventoy:taste"); + gp->start = NULL; + gp->access = g_ventoy_access; + gp->orphan = g_ventoy_orphan; + cp = g_new_consumer(gp); + cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; + g_attach(cp, pp); + + g_access(cp, 1, 0, 0); + g_topology_unlock(); + buf = g_read_data(cp, 0, pp->sectorsize, NULL); + g_topology_lock(); + g_access(cp, -1, 0, 0); + + g_detach(cp); + g_destroy_consumer(cp); + g_destroy_geom(gp); + gp = NULL; + + if (!buf) + { + return false; + } + + for (i = 0; i < 16; i++) + { + sprintf(uuid + i * 2, "%02x", buf[0x180 + i]); + } + + if (strncmp(g_ventoy_disk_uuid, uuid, 32)) + { + ret = false; + } + + if (resource_int_value("ventoy", 0, "vlnk", &vlnk) || (vlnk != 1)) + { + if (memcmp(mbrdata, buf, 0x30) || memcmp(mbrdata + 0x30, buf + 0x190, 16)) + { + ret = false; + } + } + + g_free(buf); + + if (ret) + { + G_DEBUG("ventoy disk check OK\n"); + } + + return ret; +} + +static struct g_geom * +g_ventoy_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) +{ + int i; + int error; + int disknum; + int remount = 0; + char *endpos; + const char *value; + const char *alias = NULL; + struct g_geom *gp; + struct g_ventoy_metadata md; + struct g_ventoy_softc *sc; + + if (g_ventoy_tasted) + { + return NULL; + } + + G_DEBUG("%s(%s, %s)\n", __func__, mp->name, pp->name); + g_topology_assert(); + + /* Skip providers that are already open for writing. */ + if (pp->acw > 0) + return (NULL); + + if (!g_vtoy_check_disk(mp, pp)) + { + return NULL; + } + + g_ventoy_tasted = true; + + G_DEBUG("###### ventoy disk <%s> ######\n", pp->name); + + /* hint.ventoy.0.remount=1 */ + if (resource_int_value("ventoy", 0, "remount", &remount) == 0 && remount == 1) + { + g_ventoy_remount = 1; + G_DEBUG("###### ventoy remount enabled ######\n"); + } + + /* hint.ventoy.0.alias=xxx */ + if (resource_string_value("ventoy", 0, "alias", &alias) == 0) + { + G_DEBUG("###### ventoy alias <%s> ######\n", alias); + } + else + { + alias = NULL; + } + + if (VENTOY_MAP_VALID(g_ventoy_map_data.magic2)) + { + disknum = (int)g_ventoy_map_data.segnum; + G_DEBUG("segnum from map data is:<%d>\n", disknum); + } + else + { + resource_int_value("ventoy", 0, "segnum", &disknum); + G_DEBUG("segnum from resource is:<%d>\n", disknum); + } + + strlcpy(md.md_magic, G_VENTOY_MAGIC, sizeof(md.md_magic)); + md.md_version = G_VENTOY_VERSION; + strlcpy(md.md_name, "IMAGE", sizeof(md.md_name)); + md.md_id = arc4random(); + md.md_no = 0; + md.md_all = (uint16_t)disknum; + bzero(md.md_provider, sizeof(md.md_provider)); + /* This field is not important here. */ + md.md_provsize = 0; + + gp = g_ventoy_create(mp, &md, G_VENTOY_TYPE_MANUAL); + if (gp == NULL) { + G_VENTOY_DEBUG(0, "Cannot create device %s.", + md.md_name); + return (NULL); + } + sc = gp->softc; + + for (i = 0; i < disknum; i ++) + { + if (VENTOY_MAP_VALID(g_ventoy_map_data.magic2)) + { + G_DEBUG("[map] ventoy segment%d: 0x%llx@0x%llx\n", i, + (long long)g_ventoy_map_data.seglist[i].seg_start_bytes, + (long long)g_ventoy_map_data.seglist[i].seg_end_bytes); + + g_disk_map_start = (off_t)g_ventoy_map_data.seglist[i].seg_start_bytes; + g_disk_map_end = (off_t)g_ventoy_map_data.seglist[i].seg_end_bytes; + } + else + { + if (resource_string_value("ventoy", i, "seg", &value) == 0) + { + g_disk_map_start = strtouq(value, &endpos, 0); + g_disk_map_end = strtouq(endpos + 1, NULL, 0); + } + else + { + printf("Failed to parse ventoy seg %d\n", i); + continue; + } + G_DEBUG("[resource] ventoy segment%d: %s\n", i, value); + } + + G_VENTOY_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); + error = g_ventoy_add_disk(sc, pp, i); + if (error != 0) { + G_VENTOY_DEBUG(0, + "Cannot add disk %s to %s (error=%d).", pp->name, + gp->name, error); + g_ventoy_destroy(sc, 1); + return (NULL); + } + + g_disk_map_start = 0; + g_disk_map_end = 0; + } + + if (alias && sc && sc->sc_provider) + { + g_provider_add_alias(sc->sc_provider, "%s", alias); + } + + return (gp); +} + +static void +g_ventoy_ctl_create(struct gctl_req *req, struct g_class *mp) +{ + u_int attached, no; + struct g_ventoy_metadata md; + struct g_provider *pp; + struct g_ventoy_softc *sc; + struct g_geom *gp; + struct sbuf *sb; + const char *name; + char param[16]; + int *nargs; + + g_topology_assert(); + nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); + if (nargs == NULL) { + gctl_error(req, "No '%s' argument.", "nargs"); + return; + } + if (*nargs < 2) { + gctl_error(req, "Too few arguments."); + return; + } + + bzero(&md, sizeof(md)); + strlcpy(md.md_magic, G_VENTOY_MAGIC, sizeof(md.md_magic)); + md.md_version = G_VENTOY_VERSION; + name = gctl_get_asciiparam(req, "arg0"); + if (name == NULL) { + gctl_error(req, "No 'arg%u' argument.", 0); + return; + } + strlcpy(md.md_name, name, sizeof(md.md_name)); + md.md_id = arc4random(); + md.md_no = 0; + md.md_all = *nargs - 1; + /* This field is not important here. */ + md.md_provsize = 0; + + /* Check all providers are valid */ + for (no = 1; no < *nargs; no++) { + snprintf(param, sizeof(param), "arg%u", no); + pp = gctl_get_provider(req, param); + if (pp == NULL) + return; + } + + gp = g_ventoy_create(mp, &md, G_VENTOY_TYPE_MANUAL); + if (gp == NULL) { + gctl_error(req, "Can't configure %s.", md.md_name); + return; + } + + sc = gp->softc; + sb = sbuf_new_auto(); + sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name); + for (attached = 0, no = 1; no < *nargs; no++) { + snprintf(param, sizeof(param), "arg%u", no); + pp = gctl_get_provider(req, param); + if (pp == NULL) { + name = gctl_get_asciiparam(req, param); + MPASS(name != NULL); + sbuf_printf(sb, " %s", name); + continue; + } + if (g_ventoy_add_disk(sc, pp, no - 1) != 0) { + G_VENTOY_DEBUG(1, "Disk %u (%s) not attached to %s.", + no, pp->name, gp->name); + sbuf_printf(sb, " %s", pp->name); + continue; + } + attached++; + } + sbuf_finish(sb); + if (md.md_all != attached) { + g_ventoy_destroy(gp->softc, 1); + gctl_error(req, "%s", sbuf_data(sb)); + } + sbuf_delete(sb); +} + +static struct g_ventoy_softc * +g_ventoy_find_device(struct g_class *mp, const char *name) +{ + struct g_ventoy_softc *sc; + struct g_geom *gp; + + if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) + name += strlen(_PATH_DEV); + + LIST_FOREACH(gp, &mp->geom, geom) { + sc = gp->softc; + if (sc == NULL) + continue; + if (strcmp(sc->sc_name, name) == 0) + return (sc); + } + return (NULL); +} + +static void +g_ventoy_ctl_destroy(struct gctl_req *req, struct g_class *mp) +{ + struct g_ventoy_softc *sc; + int *force, *nargs, error; + const char *name; + char param[16]; + u_int i; + + g_topology_assert(); + + nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); + if (nargs == NULL) { + gctl_error(req, "No '%s' argument.", "nargs"); + return; + } + if (*nargs <= 0) { + gctl_error(req, "Missing device(s)."); + return; + } + force = gctl_get_paraml(req, "force", sizeof(*force)); + if (force == NULL) { + gctl_error(req, "No '%s' argument.", "force"); + return; + } + + for (i = 0; i < (u_int)*nargs; i++) { + snprintf(param, sizeof(param), "arg%u", i); + name = gctl_get_asciiparam(req, param); + if (name == NULL) { + gctl_error(req, "No 'arg%u' argument.", i); + return; + } + sc = g_ventoy_find_device(mp, name); + if (sc == NULL) { + gctl_error(req, "No such device: %s.", name); + return; + } + error = g_ventoy_destroy(sc, *force); + if (error != 0) { + gctl_error(req, "Cannot destroy device %s (error=%d).", + sc->sc_name, error); + return; + } + } +} + +static void +g_ventoy_config(struct gctl_req *req, struct g_class *mp, const char *verb) +{ + uint32_t *version; + + return; + + g_topology_assert(); + + version = gctl_get_paraml(req, "version", sizeof(*version)); + if (version == NULL) { + gctl_error(req, "No '%s' argument.", "version"); + return; + } + if (*version != G_VENTOY_VERSION) { + gctl_error(req, "Userland and kernel parts are out of sync."); + return; + } + + if (strcmp(verb, "create") == 0) { + g_ventoy_ctl_create(req, mp); + return; + } else if (strcmp(verb, "destroy") == 0 || + strcmp(verb, "stop") == 0) { + g_ventoy_ctl_destroy(req, mp); + return; + } + gctl_error(req, "Unknown verb."); +} + +static void +g_ventoy_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, + struct g_consumer *cp, struct g_provider *pp) +{ + struct g_ventoy_softc *sc; + + g_topology_assert(); + sc = gp->softc; + if (sc == NULL) + return; + sx_slock(&sc->sc_disks_lock); + if (pp != NULL) { + /* Nothing here. */ + } else if (cp != NULL) { + struct g_ventoy_disk *disk; + + disk = cp->private; + if (disk == NULL) + goto end; + sbuf_printf(sb, "%s%jd\n", indent, + (intmax_t)disk->d_end); + sbuf_printf(sb, "%s%jd\n", indent, + (intmax_t)disk->d_start); + } else { + sbuf_printf(sb, "%s%u\n", indent, (u_int)sc->sc_id); + sbuf_printf(sb, "%s", indent); + switch (sc->sc_type) { + case G_VENTOY_TYPE_AUTOMATIC: + sbuf_cat(sb, "AUTOMATIC"); + break; + case G_VENTOY_TYPE_MANUAL: + sbuf_cat(sb, "MANUAL"); + break; + default: + sbuf_cat(sb, "UNKNOWN"); + break; + } + sbuf_cat(sb, "\n"); + sbuf_printf(sb, "%sTotal=%u, Online=%u\n", + indent, sc->sc_ndisks, g_ventoy_nvalid(sc)); + sbuf_printf(sb, "%s", indent); + if (sc->sc_provider != NULL && sc->sc_provider->error == 0) + sbuf_cat(sb, "UP"); + else + sbuf_cat(sb, "DOWN"); + sbuf_cat(sb, "\n"); + } +end: + sx_sunlock(&sc->sc_disks_lock); +} + +DECLARE_GEOM_CLASS(g_ventoy_class, g_ventoy); +//MODULE_VERSION(geom_ventoy, 0); diff --git a/Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.h b/Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.h new file mode 100644 index 00000000..ad5961ae --- /dev/null +++ b/Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/geom/ventoy/g_ventoy.h @@ -0,0 +1,147 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 longpanda + * Copyright (c) 2004-2005 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _G_VENTOY_H_ +#define _G_VENTOY_H_ + +#include + +#define G_VENTOY_CLASS_NAME "VENTOY" + +#define G_VENTOY_MAGIC "GEOM::VENTOY" +/* + * Version history: + * 1 - Initial version number. + * 2 - Added 'stop' command to gconcat(8). + * 3 - Added md_provider field to metadata and '-h' option to gconcat(8). + * 4 - Added md_provsize field to metadata. + */ +#define G_VENTOY_VERSION 4 + +#ifdef _KERNEL +#define G_VENTOY_TYPE_MANUAL 0 +#define G_VENTOY_TYPE_AUTOMATIC 1 + +#define G_DEBUG(...) if (bootverbose) printf(__VA_ARGS__) +#define G_VENTOY_DEBUG(lvl, ...) if (g_ventoy_debug) printf(__VA_ARGS__) +#define G_VENTOY_LOGREQ(bp, ...) if (g_ventoy_debug) printf(__VA_ARGS__) + +struct g_ventoy_disk { + TAILQ_ENTRY(g_ventoy_disk) d_next; + struct g_consumer *d_consumer; + struct g_ventoy_softc *d_softc; + off_t d_start; + off_t d_end; + off_t d_map_start; + off_t d_map_end; + int d_candelete; + int d_removed; + bool d_hardcoded; +}; + +struct g_ventoy_softc { + u_int sc_type; /* provider type */ + struct g_geom *sc_geom; + struct g_provider *sc_provider; + uint32_t sc_id; /* concat unique ID */ + + uint16_t sc_ndisks; + TAILQ_HEAD(g_ventoy_disks, g_ventoy_disk) sc_disks; + struct mtx sc_completion_lock; /* synchronizes cross-boundary IOs */ + struct sx sc_disks_lock; /* synchronizes modification of sc_disks */ +}; +#define sc_name sc_geom->name + + +#pragma pack(1) +#define VENTOY_UNIX_SEG_MAGIC0 0x11223344 +#define VENTOY_UNIX_SEG_MAGIC1 0x55667788 +#define VENTOY_UNIX_SEG_MAGIC2 0x99aabbcc +#define VENTOY_UNIX_SEG_MAGIC3 0xddeeff00 +#define VENTOY_UNIX_MAX_SEGNUM 40960 +struct g_ventoy_seg { + uint64_t seg_start_bytes; + uint64_t seg_end_bytes; +}; + +struct g_ventoy_map{ + uint32_t magic1[4]; + uint32_t magic2[4]; + uint64_t segnum; + uint64_t disksize; + uint8_t diskuuid[16]; + struct g_ventoy_seg seglist[VENTOY_UNIX_MAX_SEGNUM]; + uint32_t magic3[4]; +}; +#pragma pack() + +#define VENTOY_MAP_VALID(magic2) \ + (magic2[0] == VENTOY_UNIX_SEG_MAGIC0 && magic2[1] == VENTOY_UNIX_SEG_MAGIC1 && magic2[2] == VENTOY_UNIX_SEG_MAGIC2 && magic2[3] == VENTOY_UNIX_SEG_MAGIC3) + +#endif /* _KERNEL */ + +struct g_ventoy_metadata { + char md_magic[16]; /* Magic value. */ + uint32_t md_version; /* Version number. */ + char md_name[16]; /* Concat name. */ + uint32_t md_id; /* Unique ID. */ + uint16_t md_no; /* Disk number. */ + uint16_t md_all; /* Number of all disks. */ + char md_provider[16]; /* Hardcoded provider. */ + uint64_t md_provsize; /* Provider's size. */ +}; +static __inline void +ventoy_metadata_encode(const struct g_ventoy_metadata *md, u_char *data) +{ + + bcopy(md->md_magic, data, sizeof(md->md_magic)); + le32enc(data + 16, md->md_version); + bcopy(md->md_name, data + 20, sizeof(md->md_name)); + le32enc(data + 36, md->md_id); + le16enc(data + 40, md->md_no); + le16enc(data + 42, md->md_all); + bcopy(md->md_provider, data + 44, sizeof(md->md_provider)); + le64enc(data + 60, md->md_provsize); +} +static __inline void +ventoy_metadata_decode(const u_char *data, struct g_ventoy_metadata *md) +{ + + bcopy(data, md->md_magic, sizeof(md->md_magic)); + md->md_version = le32dec(data + 16); + bcopy(data + 20, md->md_name, sizeof(md->md_name)); + md->md_id = le32dec(data + 36); + md->md_no = le16dec(data + 40); + md->md_all = le16dec(data + 42); + bcopy(data + 44, md->md_provider, sizeof(md->md_provider)); + md->md_provsize = le64dec(data + 60); +} +#endif /* _G_VENTOY_H_ */ diff --git a/Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/modules/geom/geom_ventoy/Makefile b/Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/modules/geom/geom_ventoy/Makefile new file mode 100644 index 00000000..165f1bdf --- /dev/null +++ b/Unix/ventoy_unix_src/FreeBSD/geom_ventoy_src/14.x/sys/modules/geom/geom_ventoy/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/geom/ventoy + +KMOD= geom_ventoy +SRCS= g_ventoy.c + +.include