113328753SAndrew Thompson /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni *
413328753SAndrew Thompson * Copyright (c) 2008 Andrew Thompson <thompsa@FreeBSD.org>
513328753SAndrew Thompson * All rights reserved.
613328753SAndrew Thompson *
713328753SAndrew Thompson * Redistribution and use in source and binary forms, with or without
813328753SAndrew Thompson * modification, are permitted provided that the following conditions
913328753SAndrew Thompson * are met:
1013328753SAndrew Thompson * 1. Redistributions of source code must retain the above copyright
1113328753SAndrew Thompson * notice, this list of conditions and the following disclaimer.
1213328753SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright
1313328753SAndrew Thompson * notice, this list of conditions and the following disclaimer in the
1413328753SAndrew Thompson * documentation and/or other materials provided with the distribution.
1513328753SAndrew Thompson *
1613328753SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1713328753SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1813328753SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1913328753SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2013328753SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2113328753SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2213328753SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2313328753SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2413328753SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2513328753SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2613328753SAndrew Thompson * SUCH DAMAGE.
2713328753SAndrew Thompson */
2813328753SAndrew Thompson
2913328753SAndrew Thompson #include <sys/cdefs.h>
3013328753SAndrew Thompson #include <sys/ctype.h>
3113328753SAndrew Thompson #include <sys/param.h>
3213328753SAndrew Thompson #include <sys/bio.h>
3313328753SAndrew Thompson #include <sys/kernel.h>
3413328753SAndrew Thompson #include <sys/limits.h>
3513328753SAndrew Thompson #include <sys/malloc.h>
3613328753SAndrew Thompson #include <sys/queue.h>
3713328753SAndrew Thompson #include <sys/sysctl.h>
3813328753SAndrew Thompson #include <sys/systm.h>
3913328753SAndrew Thompson
4013328753SAndrew Thompson #include <geom/geom.h>
41ac03832eSConrad Meyer #include <geom/geom_dbg.h>
4213328753SAndrew Thompson #include <sys/endian.h>
4313328753SAndrew Thompson
4413328753SAndrew Thompson #include <geom/linux_lvm/g_linux_lvm.h>
4513328753SAndrew Thompson
46cb08c2ccSAlexander Leidinger FEATURE(geom_linux_lvm, "GEOM Linux LVM partitioning support");
47cb08c2ccSAlexander Leidinger
4813328753SAndrew Thompson /* Declare malloc(9) label */
4913328753SAndrew Thompson static MALLOC_DEFINE(M_GLLVM, "gllvm", "GEOM_LINUX_LVM Data");
5013328753SAndrew Thompson
5113328753SAndrew Thompson /* GEOM class methods */
5213328753SAndrew Thompson static g_access_t g_llvm_access;
5313328753SAndrew Thompson static g_init_t g_llvm_init;
5413328753SAndrew Thompson static g_orphan_t g_llvm_orphan;
5513328753SAndrew Thompson static g_orphan_t g_llvm_taste_orphan;
5613328753SAndrew Thompson static g_start_t g_llvm_start;
5713328753SAndrew Thompson static g_taste_t g_llvm_taste;
5813328753SAndrew Thompson static g_ctl_destroy_geom_t g_llvm_destroy_geom;
5913328753SAndrew Thompson
6013328753SAndrew Thompson static void g_llvm_done(struct bio *);
6113328753SAndrew Thompson static void g_llvm_remove_disk(struct g_llvm_vg *, struct g_consumer *);
6213328753SAndrew Thompson static int g_llvm_activate_lv(struct g_llvm_vg *, struct g_llvm_lv *);
6313328753SAndrew Thompson static int g_llvm_add_disk(struct g_llvm_vg *, struct g_provider *, char *);
6413328753SAndrew Thompson static void g_llvm_free_vg(struct g_llvm_vg *);
6513328753SAndrew Thompson static int g_llvm_destroy(struct g_llvm_vg *, int);
6613328753SAndrew Thompson static int g_llvm_read_label(struct g_consumer *, struct g_llvm_label *);
6713328753SAndrew Thompson static int g_llvm_read_md(struct g_consumer *, struct g_llvm_metadata *,
6813328753SAndrew Thompson struct g_llvm_label *);
6913328753SAndrew Thompson
70c941b82eSZhenlei Huang static int llvm_label_decode(const u_char *, struct g_llvm_label *,
71c941b82eSZhenlei Huang int, u_int);
7213328753SAndrew Thompson static int llvm_md_decode(const u_char *, struct g_llvm_metadata *,
7313328753SAndrew Thompson struct g_llvm_label *);
7413328753SAndrew Thompson static int llvm_textconf_decode(u_char *, int,
7513328753SAndrew Thompson struct g_llvm_metadata *);
7613328753SAndrew Thompson static int llvm_textconf_decode_pv(char **, char *, struct g_llvm_vg *);
7713328753SAndrew Thompson static int llvm_textconf_decode_lv(char **, char *, struct g_llvm_vg *);
7813328753SAndrew Thompson static int llvm_textconf_decode_sg(char **, char *, struct g_llvm_lv *);
7913328753SAndrew Thompson
8013328753SAndrew Thompson SYSCTL_DECL(_kern_geom);
817029da5cSPawel Biernacki SYSCTL_NODE(_kern_geom, OID_AUTO, linux_lvm, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
8213328753SAndrew Thompson "GEOM_LINUX_LVM stuff");
8313328753SAndrew Thompson static u_int g_llvm_debug = 0;
84af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_geom_linux_lvm, OID_AUTO, debug, CTLFLAG_RWTUN, &g_llvm_debug, 0,
8513328753SAndrew Thompson "Debug level");
8613328753SAndrew Thompson
8713328753SAndrew Thompson LIST_HEAD(, g_llvm_vg) vg_list;
8813328753SAndrew Thompson
8913328753SAndrew Thompson /*
9013328753SAndrew Thompson * Called to notify geom when it's been opened, and for what intent
9113328753SAndrew Thompson */
9213328753SAndrew Thompson static int
g_llvm_access(struct g_provider * pp,int dr,int dw,int de)9313328753SAndrew Thompson g_llvm_access(struct g_provider *pp, int dr, int dw, int de)
9413328753SAndrew Thompson {
9513328753SAndrew Thompson struct g_consumer *c;
9613328753SAndrew Thompson struct g_llvm_vg *vg;
9713328753SAndrew Thompson struct g_geom *gp;
9813328753SAndrew Thompson int error;
9913328753SAndrew Thompson
10013328753SAndrew Thompson KASSERT(pp != NULL, ("%s: NULL provider", __func__));
10113328753SAndrew Thompson gp = pp->geom;
10213328753SAndrew Thompson KASSERT(gp != NULL, ("%s: NULL geom", __func__));
10313328753SAndrew Thompson vg = gp->softc;
10413328753SAndrew Thompson
10513328753SAndrew Thompson if (vg == NULL) {
10613328753SAndrew Thompson /* It seems that .access can be called with negative dr,dw,dx
10713328753SAndrew Thompson * in this case but I want to check for myself */
10813328753SAndrew Thompson G_LLVM_DEBUG(0, "access(%d, %d, %d) for %s",
10913328753SAndrew Thompson dr, dw, de, pp->name);
11013328753SAndrew Thompson
11113328753SAndrew Thompson /* This should only happen when geom is withered so
11213328753SAndrew Thompson * allow only negative requests */
11313328753SAndrew Thompson KASSERT(dr <= 0 && dw <= 0 && de <= 0,
11413328753SAndrew Thompson ("%s: Positive access for %s", __func__, pp->name));
11513328753SAndrew Thompson if (pp->acr + dr == 0 && pp->acw + dw == 0 && pp->ace + de == 0)
11613328753SAndrew Thompson G_LLVM_DEBUG(0,
11713328753SAndrew Thompson "Device %s definitely destroyed", pp->name);
11813328753SAndrew Thompson return (0);
11913328753SAndrew Thompson }
12013328753SAndrew Thompson
12113328753SAndrew Thompson /* Grab an exclusive bit to propagate on our consumers on first open */
12213328753SAndrew Thompson if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)
12313328753SAndrew Thompson de++;
12413328753SAndrew Thompson /* ... drop it on close */
12513328753SAndrew Thompson if (pp->acr + dr == 0 && pp->acw + dw == 0 && pp->ace + de == 0)
12613328753SAndrew Thompson de--;
12713328753SAndrew Thompson
12813328753SAndrew Thompson error = ENXIO;
12913328753SAndrew Thompson LIST_FOREACH(c, &gp->consumer, consumer) {
13013328753SAndrew Thompson KASSERT(c != NULL, ("%s: consumer is NULL", __func__));
13113328753SAndrew Thompson error = g_access(c, dr, dw, de);
13213328753SAndrew Thompson if (error != 0) {
13313328753SAndrew Thompson struct g_consumer *c2;
13413328753SAndrew Thompson
13513328753SAndrew Thompson /* Backout earlier changes */
13613328753SAndrew Thompson LIST_FOREACH(c2, &gp->consumer, consumer) {
13713328753SAndrew Thompson if (c2 == c) /* all eariler components fixed */
13813328753SAndrew Thompson return (error);
13913328753SAndrew Thompson g_access(c2, -dr, -dw, -de);
14013328753SAndrew Thompson }
14113328753SAndrew Thompson }
14213328753SAndrew Thompson }
14313328753SAndrew Thompson
14413328753SAndrew Thompson return (error);
14513328753SAndrew Thompson }
14613328753SAndrew Thompson
14713328753SAndrew Thompson /*
14813328753SAndrew Thompson * Dismantle bio_queue and destroy its components
14913328753SAndrew Thompson */
15013328753SAndrew Thompson static void
bioq_dismantle(struct bio_queue_head * bq)15113328753SAndrew Thompson bioq_dismantle(struct bio_queue_head *bq)
15213328753SAndrew Thompson {
15313328753SAndrew Thompson struct bio *b;
15413328753SAndrew Thompson
15513328753SAndrew Thompson for (b = bioq_first(bq); b != NULL; b = bioq_first(bq)) {
15613328753SAndrew Thompson bioq_remove(bq, b);
15713328753SAndrew Thompson g_destroy_bio(b);
15813328753SAndrew Thompson }
15913328753SAndrew Thompson }
16013328753SAndrew Thompson
16113328753SAndrew Thompson /*
16213328753SAndrew Thompson * GEOM .done handler
16313328753SAndrew Thompson * Can't use standard handler because one requested IO may
16413328753SAndrew Thompson * fork into additional data IOs
16513328753SAndrew Thompson */
16613328753SAndrew Thompson static void
g_llvm_done(struct bio * b)16713328753SAndrew Thompson g_llvm_done(struct bio *b)
16813328753SAndrew Thompson {
16913328753SAndrew Thompson struct bio *parent_b;
17013328753SAndrew Thompson
17113328753SAndrew Thompson parent_b = b->bio_parent;
17213328753SAndrew Thompson
17313328753SAndrew Thompson if (b->bio_error != 0) {
17413328753SAndrew Thompson G_LLVM_DEBUG(0, "Error %d for offset=%ju, length=%ju on %s",
17513328753SAndrew Thompson b->bio_error, b->bio_offset, b->bio_length,
17613328753SAndrew Thompson b->bio_to->name);
17713328753SAndrew Thompson if (parent_b->bio_error == 0)
17813328753SAndrew Thompson parent_b->bio_error = b->bio_error;
17913328753SAndrew Thompson }
18013328753SAndrew Thompson
18113328753SAndrew Thompson parent_b->bio_inbed++;
18213328753SAndrew Thompson parent_b->bio_completed += b->bio_completed;
18313328753SAndrew Thompson
18413328753SAndrew Thompson if (parent_b->bio_children == parent_b->bio_inbed) {
18513328753SAndrew Thompson parent_b->bio_completed = parent_b->bio_length;
18613328753SAndrew Thompson g_io_deliver(parent_b, parent_b->bio_error);
18713328753SAndrew Thompson }
18813328753SAndrew Thompson g_destroy_bio(b);
18913328753SAndrew Thompson }
19013328753SAndrew Thompson
19113328753SAndrew Thompson static void
g_llvm_start(struct bio * bp)19213328753SAndrew Thompson g_llvm_start(struct bio *bp)
19313328753SAndrew Thompson {
19413328753SAndrew Thompson struct g_provider *pp;
19513328753SAndrew Thompson struct g_llvm_vg *vg;
19613328753SAndrew Thompson struct g_llvm_pv *pv;
19713328753SAndrew Thompson struct g_llvm_lv *lv;
19813328753SAndrew Thompson struct g_llvm_segment *sg;
19913328753SAndrew Thompson struct bio *cb;
20013328753SAndrew Thompson struct bio_queue_head bq;
20113328753SAndrew Thompson size_t chunk_size;
20213328753SAndrew Thompson off_t offset, length;
20313328753SAndrew Thompson char *addr;
20413328753SAndrew Thompson u_int count;
20513328753SAndrew Thompson
20613328753SAndrew Thompson pp = bp->bio_to;
20713328753SAndrew Thompson lv = pp->private;
20813328753SAndrew Thompson vg = pp->geom->softc;
20913328753SAndrew Thompson
21013328753SAndrew Thompson switch (bp->bio_cmd) {
21113328753SAndrew Thompson case BIO_READ:
21213328753SAndrew Thompson case BIO_WRITE:
21313328753SAndrew Thompson case BIO_DELETE:
21413328753SAndrew Thompson /* XXX BIO_GETATTR allowed? */
21513328753SAndrew Thompson break;
21613328753SAndrew Thompson default:
2178b522bdaSWarner Losh /*
2188b522bdaSWarner Losh * BIO_SPEEDUP and BIO_FLUSH should pass through to all sg
2198b522bdaSWarner Losh * elements, but aren't.
2208b522bdaSWarner Losh */
22113328753SAndrew Thompson g_io_deliver(bp, EOPNOTSUPP);
22213328753SAndrew Thompson return;
22313328753SAndrew Thompson }
22413328753SAndrew Thompson
22513328753SAndrew Thompson bioq_init(&bq);
22613328753SAndrew Thompson
22713328753SAndrew Thompson chunk_size = vg->vg_extentsize;
22813328753SAndrew Thompson addr = bp->bio_data;
22913328753SAndrew Thompson offset = bp->bio_offset; /* virtual offset and length */
23013328753SAndrew Thompson length = bp->bio_length;
23113328753SAndrew Thompson
23213328753SAndrew Thompson while (length > 0) {
23313328753SAndrew Thompson size_t chunk_index, in_chunk_offset, in_chunk_length;
23413328753SAndrew Thompson
23513328753SAndrew Thompson pv = NULL;
23613328753SAndrew Thompson cb = g_clone_bio(bp);
23713328753SAndrew Thompson if (cb == NULL) {
23813328753SAndrew Thompson bioq_dismantle(&bq);
23913328753SAndrew Thompson if (bp->bio_error == 0)
24013328753SAndrew Thompson bp->bio_error = ENOMEM;
24113328753SAndrew Thompson g_io_deliver(bp, bp->bio_error);
24213328753SAndrew Thompson return;
24313328753SAndrew Thompson }
24413328753SAndrew Thompson
24513328753SAndrew Thompson /* get the segment and the pv */
24613328753SAndrew Thompson if (lv->lv_sgcount == 1) {
24713328753SAndrew Thompson /* skip much of the calculations for a single sg */
24813328753SAndrew Thompson chunk_index = 0;
24913328753SAndrew Thompson in_chunk_offset = 0;
25013328753SAndrew Thompson in_chunk_length = length;
25113328753SAndrew Thompson sg = lv->lv_firstsg;
25213328753SAndrew Thompson pv = sg->sg_pv;
25313328753SAndrew Thompson cb->bio_offset = offset + sg->sg_pvoffset;
25413328753SAndrew Thompson } else {
25513328753SAndrew Thompson chunk_index = offset / chunk_size; /* round downwards */
25613328753SAndrew Thompson in_chunk_offset = offset % chunk_size;
25713328753SAndrew Thompson in_chunk_length =
25813328753SAndrew Thompson min(length, chunk_size - in_chunk_offset);
25913328753SAndrew Thompson
26013328753SAndrew Thompson /* XXX could be faster */
26113328753SAndrew Thompson LIST_FOREACH(sg, &lv->lv_segs, sg_next) {
26213328753SAndrew Thompson if (chunk_index >= sg->sg_start &&
26313328753SAndrew Thompson chunk_index <= sg->sg_end) {
26413328753SAndrew Thompson /* adjust chunk index for sg start */
26513328753SAndrew Thompson chunk_index -= sg->sg_start;
26613328753SAndrew Thompson pv = sg->sg_pv;
26713328753SAndrew Thompson break;
26813328753SAndrew Thompson }
26913328753SAndrew Thompson }
27013328753SAndrew Thompson cb->bio_offset =
27113328753SAndrew Thompson (off_t)chunk_index * (off_t)chunk_size
27213328753SAndrew Thompson + in_chunk_offset + sg->sg_pvoffset;
27313328753SAndrew Thompson }
27413328753SAndrew Thompson
27513328753SAndrew Thompson KASSERT(pv != NULL, ("Can't find PV for chunk %zu",
27613328753SAndrew Thompson chunk_index));
27713328753SAndrew Thompson
27813328753SAndrew Thompson cb->bio_to = pv->pv_gprov;
27913328753SAndrew Thompson cb->bio_done = g_llvm_done;
28013328753SAndrew Thompson cb->bio_length = in_chunk_length;
28113328753SAndrew Thompson cb->bio_data = addr;
28213328753SAndrew Thompson cb->bio_caller1 = pv;
28313328753SAndrew Thompson bioq_disksort(&bq, cb);
28413328753SAndrew Thompson
28513328753SAndrew Thompson G_LLVM_DEBUG(5,
28613328753SAndrew Thompson "Mapped %s(%ju, %ju) on %s to %zu(%zu,%zu) @ %s:%ju",
28713328753SAndrew Thompson bp->bio_cmd == BIO_READ ? "R" : "W",
28813328753SAndrew Thompson offset, length, lv->lv_name,
28913328753SAndrew Thompson chunk_index, in_chunk_offset, in_chunk_length,
29013328753SAndrew Thompson pv->pv_name, cb->bio_offset);
29113328753SAndrew Thompson
29213328753SAndrew Thompson addr += in_chunk_length;
29313328753SAndrew Thompson length -= in_chunk_length;
29413328753SAndrew Thompson offset += in_chunk_length;
29513328753SAndrew Thompson }
29613328753SAndrew Thompson
29713328753SAndrew Thompson /* Fire off bio's here */
29813328753SAndrew Thompson count = 0;
29913328753SAndrew Thompson for (cb = bioq_first(&bq); cb != NULL; cb = bioq_first(&bq)) {
30013328753SAndrew Thompson bioq_remove(&bq, cb);
30113328753SAndrew Thompson pv = cb->bio_caller1;
30213328753SAndrew Thompson cb->bio_caller1 = NULL;
30313328753SAndrew Thompson G_LLVM_DEBUG(6, "firing bio to %s, offset=%ju, length=%ju",
30413328753SAndrew Thompson cb->bio_to->name, cb->bio_offset, cb->bio_length);
30513328753SAndrew Thompson g_io_request(cb, pv->pv_gcons);
30613328753SAndrew Thompson count++;
30713328753SAndrew Thompson }
30813328753SAndrew Thompson if (count == 0) { /* We handled everything locally */
30913328753SAndrew Thompson bp->bio_completed = bp->bio_length;
31013328753SAndrew Thompson g_io_deliver(bp, 0);
31113328753SAndrew Thompson }
31213328753SAndrew Thompson }
31313328753SAndrew Thompson
31413328753SAndrew Thompson static void
g_llvm_remove_disk(struct g_llvm_vg * vg,struct g_consumer * cp)31513328753SAndrew Thompson g_llvm_remove_disk(struct g_llvm_vg *vg, struct g_consumer *cp)
31613328753SAndrew Thompson {
31713328753SAndrew Thompson struct g_llvm_pv *pv;
31813328753SAndrew Thompson struct g_llvm_lv *lv;
31913328753SAndrew Thompson struct g_llvm_segment *sg;
32013328753SAndrew Thompson int found;
32113328753SAndrew Thompson
32213328753SAndrew Thompson KASSERT(cp != NULL, ("Non-valid disk in %s.", __func__));
32313328753SAndrew Thompson pv = (struct g_llvm_pv *)cp->private;
32413328753SAndrew Thompson
32513328753SAndrew Thompson G_LLVM_DEBUG(0, "Disk %s removed from %s.", cp->provider->name,
32613328753SAndrew Thompson pv->pv_name);
32713328753SAndrew Thompson
32813328753SAndrew Thompson LIST_FOREACH(lv, &vg->vg_lvs, lv_next) {
32913328753SAndrew Thompson /* Find segments that map to this disk */
33013328753SAndrew Thompson found = 0;
33113328753SAndrew Thompson LIST_FOREACH(sg, &lv->lv_segs, sg_next) {
33213328753SAndrew Thompson if (sg->sg_pv == pv) {
33313328753SAndrew Thompson sg->sg_pv = NULL;
33413328753SAndrew Thompson lv->lv_sgactive--;
33513328753SAndrew Thompson found = 1;
33613328753SAndrew Thompson break;
33713328753SAndrew Thompson }
33813328753SAndrew Thompson }
33913328753SAndrew Thompson if (found) {
34013328753SAndrew Thompson G_LLVM_DEBUG(0, "Device %s removed.",
34113328753SAndrew Thompson lv->lv_gprov->name);
3428b64f3caSAlexander Motin g_wither_provider(lv->lv_gprov, ENXIO);
34313328753SAndrew Thompson lv->lv_gprov = NULL;
34413328753SAndrew Thompson }
34513328753SAndrew Thompson }
34613328753SAndrew Thompson
34713328753SAndrew Thompson if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
34813328753SAndrew Thompson g_access(cp, -cp->acr, -cp->acw, -cp->ace);
34913328753SAndrew Thompson g_detach(cp);
35013328753SAndrew Thompson g_destroy_consumer(cp);
35113328753SAndrew Thompson }
35213328753SAndrew Thompson
35313328753SAndrew Thompson static void
g_llvm_orphan(struct g_consumer * cp)35413328753SAndrew Thompson g_llvm_orphan(struct g_consumer *cp)
35513328753SAndrew Thompson {
35613328753SAndrew Thompson struct g_llvm_vg *vg;
35713328753SAndrew Thompson struct g_geom *gp;
35813328753SAndrew Thompson
35913328753SAndrew Thompson g_topology_assert();
36013328753SAndrew Thompson gp = cp->geom;
36113328753SAndrew Thompson vg = gp->softc;
36213328753SAndrew Thompson if (vg == NULL)
36313328753SAndrew Thompson return;
36413328753SAndrew Thompson
36513328753SAndrew Thompson g_llvm_remove_disk(vg, cp);
36613328753SAndrew Thompson g_llvm_destroy(vg, 1);
36713328753SAndrew Thompson }
36813328753SAndrew Thompson
36913328753SAndrew Thompson static int
g_llvm_activate_lv(struct g_llvm_vg * vg,struct g_llvm_lv * lv)37013328753SAndrew Thompson g_llvm_activate_lv(struct g_llvm_vg *vg, struct g_llvm_lv *lv)
37113328753SAndrew Thompson {
37213328753SAndrew Thompson struct g_geom *gp;
37313328753SAndrew Thompson struct g_provider *pp;
37413328753SAndrew Thompson
37513328753SAndrew Thompson g_topology_assert();
37613328753SAndrew Thompson
37713328753SAndrew Thompson KASSERT(lv->lv_sgactive == lv->lv_sgcount, ("segment missing"));
37813328753SAndrew Thompson
37913328753SAndrew Thompson gp = vg->vg_geom;
38013328753SAndrew Thompson pp = g_new_providerf(gp, "linux_lvm/%s-%s", vg->vg_name, lv->lv_name);
38113328753SAndrew Thompson pp->mediasize = vg->vg_extentsize * (off_t)lv->lv_extentcount;
38213328753SAndrew Thompson pp->sectorsize = vg->vg_sectorsize;
38313328753SAndrew Thompson g_error_provider(pp, 0);
38413328753SAndrew Thompson lv->lv_gprov = pp;
38513328753SAndrew Thompson pp->private = lv;
38613328753SAndrew Thompson
38713328753SAndrew Thompson G_LLVM_DEBUG(1, "Created %s, %juM", pp->name,
38813328753SAndrew Thompson pp->mediasize / (1024*1024));
38913328753SAndrew Thompson
39013328753SAndrew Thompson return (0);
39113328753SAndrew Thompson }
39213328753SAndrew Thompson
39313328753SAndrew Thompson static int
g_llvm_add_disk(struct g_llvm_vg * vg,struct g_provider * pp,char * uuid)39413328753SAndrew Thompson g_llvm_add_disk(struct g_llvm_vg *vg, struct g_provider *pp, char *uuid)
39513328753SAndrew Thompson {
39613328753SAndrew Thompson struct g_geom *gp;
39713328753SAndrew Thompson struct g_consumer *cp, *fcp;
39813328753SAndrew Thompson struct g_llvm_pv *pv;
39913328753SAndrew Thompson struct g_llvm_lv *lv;
40013328753SAndrew Thompson struct g_llvm_segment *sg;
40113328753SAndrew Thompson int error;
40213328753SAndrew Thompson
40313328753SAndrew Thompson g_topology_assert();
40413328753SAndrew Thompson
40513328753SAndrew Thompson LIST_FOREACH(pv, &vg->vg_pvs, pv_next) {
40613328753SAndrew Thompson if (strcmp(pv->pv_uuid, uuid) == 0)
40713328753SAndrew Thompson break; /* found it */
40813328753SAndrew Thompson }
40913328753SAndrew Thompson if (pv == NULL) {
41013328753SAndrew Thompson G_LLVM_DEBUG(3, "uuid %s not found in pv list", uuid);
41113328753SAndrew Thompson return (ENOENT);
41213328753SAndrew Thompson }
41313328753SAndrew Thompson if (pv->pv_gprov != NULL) {
41413328753SAndrew Thompson G_LLVM_DEBUG(0, "disk %s already initialised in %s",
41513328753SAndrew Thompson pv->pv_name, vg->vg_name);
41613328753SAndrew Thompson return (EEXIST);
41713328753SAndrew Thompson }
41813328753SAndrew Thompson
41913328753SAndrew Thompson pv->pv_start *= vg->vg_sectorsize;
42013328753SAndrew Thompson gp = vg->vg_geom;
42113328753SAndrew Thompson fcp = LIST_FIRST(&gp->consumer);
42213328753SAndrew Thompson
42313328753SAndrew Thompson cp = g_new_consumer(gp);
42413328753SAndrew Thompson error = g_attach(cp, pp);
42513328753SAndrew Thompson G_LLVM_DEBUG(1, "Attached %s to %s at offset %ju",
42613328753SAndrew Thompson pp->name, pv->pv_name, pv->pv_start);
42713328753SAndrew Thompson
42813328753SAndrew Thompson if (error != 0) {
42913328753SAndrew Thompson G_LLVM_DEBUG(0, "cannot attach %s to %s",
43013328753SAndrew Thompson pp->name, vg->vg_name);
43113328753SAndrew Thompson g_destroy_consumer(cp);
43213328753SAndrew Thompson return (error);
43313328753SAndrew Thompson }
43413328753SAndrew Thompson
43513328753SAndrew Thompson if (fcp != NULL) {
43613328753SAndrew Thompson if (fcp->provider->sectorsize != pp->sectorsize) {
43713328753SAndrew Thompson G_LLVM_DEBUG(0, "Provider %s of %s has invalid "
43813328753SAndrew Thompson "sector size (%d)", pp->name, vg->vg_name,
43913328753SAndrew Thompson pp->sectorsize);
44013328753SAndrew Thompson return (EINVAL);
44113328753SAndrew Thompson }
44213328753SAndrew Thompson if (fcp->acr > 0 || fcp->acw || fcp->ace > 0) {
44313328753SAndrew Thompson /* Replicate access permissions from first "live"
44413328753SAndrew Thompson * consumer to the new one */
44513328753SAndrew Thompson error = g_access(cp, fcp->acr, fcp->acw, fcp->ace);
44613328753SAndrew Thompson if (error != 0) {
44713328753SAndrew Thompson g_detach(cp);
44813328753SAndrew Thompson g_destroy_consumer(cp);
44913328753SAndrew Thompson return (error);
45013328753SAndrew Thompson }
45113328753SAndrew Thompson }
45213328753SAndrew Thompson }
45313328753SAndrew Thompson
45413328753SAndrew Thompson cp->private = pv;
45513328753SAndrew Thompson pv->pv_gcons = cp;
45613328753SAndrew Thompson pv->pv_gprov = pp;
45713328753SAndrew Thompson
45813328753SAndrew Thompson LIST_FOREACH(lv, &vg->vg_lvs, lv_next) {
45913328753SAndrew Thompson /* Find segments that map to this disk */
46013328753SAndrew Thompson LIST_FOREACH(sg, &lv->lv_segs, sg_next) {
46113328753SAndrew Thompson if (strcmp(sg->sg_pvname, pv->pv_name) == 0) {
46213328753SAndrew Thompson /* avtivate the segment */
46313328753SAndrew Thompson KASSERT(sg->sg_pv == NULL,
46413328753SAndrew Thompson ("segment already mapped"));
46513328753SAndrew Thompson sg->sg_pvoffset =
46613328753SAndrew Thompson (off_t)sg->sg_pvstart * vg->vg_extentsize
46713328753SAndrew Thompson + pv->pv_start;
46813328753SAndrew Thompson sg->sg_pv = pv;
46913328753SAndrew Thompson lv->lv_sgactive++;
47013328753SAndrew Thompson
47113328753SAndrew Thompson G_LLVM_DEBUG(2, "%s: %d to %d @ %s:%d"
47213328753SAndrew Thompson " offset %ju sector %ju",
47313328753SAndrew Thompson lv->lv_name, sg->sg_start, sg->sg_end,
47413328753SAndrew Thompson sg->sg_pvname, sg->sg_pvstart,
47513328753SAndrew Thompson sg->sg_pvoffset,
47613328753SAndrew Thompson sg->sg_pvoffset / vg->vg_sectorsize);
47713328753SAndrew Thompson }
47813328753SAndrew Thompson }
47913328753SAndrew Thompson /* Activate any lvs waiting on this disk */
48013328753SAndrew Thompson if (lv->lv_gprov == NULL && lv->lv_sgactive == lv->lv_sgcount) {
48113328753SAndrew Thompson error = g_llvm_activate_lv(vg, lv);
48213328753SAndrew Thompson if (error)
48313328753SAndrew Thompson break;
48413328753SAndrew Thompson }
48513328753SAndrew Thompson }
48613328753SAndrew Thompson return (error);
48713328753SAndrew Thompson }
48813328753SAndrew Thompson
48913328753SAndrew Thompson static void
g_llvm_init(struct g_class * mp)49013328753SAndrew Thompson g_llvm_init(struct g_class *mp)
49113328753SAndrew Thompson {
49213328753SAndrew Thompson LIST_INIT(&vg_list);
49313328753SAndrew Thompson }
49413328753SAndrew Thompson
49513328753SAndrew Thompson static void
g_llvm_free_vg(struct g_llvm_vg * vg)49613328753SAndrew Thompson g_llvm_free_vg(struct g_llvm_vg *vg)
49713328753SAndrew Thompson {
49813328753SAndrew Thompson struct g_llvm_pv *pv;
49913328753SAndrew Thompson struct g_llvm_lv *lv;
50013328753SAndrew Thompson struct g_llvm_segment *sg;
50113328753SAndrew Thompson
50213328753SAndrew Thompson /* Free all the structures */
50313328753SAndrew Thompson while ((pv = LIST_FIRST(&vg->vg_pvs)) != NULL) {
50413328753SAndrew Thompson LIST_REMOVE(pv, pv_next);
50513328753SAndrew Thompson free(pv, M_GLLVM);
50613328753SAndrew Thompson }
50713328753SAndrew Thompson while ((lv = LIST_FIRST(&vg->vg_lvs)) != NULL) {
50813328753SAndrew Thompson while ((sg = LIST_FIRST(&lv->lv_segs)) != NULL) {
50913328753SAndrew Thompson LIST_REMOVE(sg, sg_next);
51013328753SAndrew Thompson free(sg, M_GLLVM);
51113328753SAndrew Thompson }
51213328753SAndrew Thompson LIST_REMOVE(lv, lv_next);
51313328753SAndrew Thompson free(lv, M_GLLVM);
51413328753SAndrew Thompson }
51513328753SAndrew Thompson free(vg, M_GLLVM);
51613328753SAndrew Thompson }
51713328753SAndrew Thompson
51813328753SAndrew Thompson static void
g_llvm_taste_orphan(struct g_consumer * cp)51913328753SAndrew Thompson g_llvm_taste_orphan(struct g_consumer *cp)
52013328753SAndrew Thompson {
52113328753SAndrew Thompson
52213328753SAndrew Thompson KASSERT(1 == 0, ("%s called while tasting %s.", __func__,
52313328753SAndrew Thompson cp->provider->name));
52413328753SAndrew Thompson }
52513328753SAndrew Thompson
52613328753SAndrew Thompson static struct g_geom *
g_llvm_taste(struct g_class * mp,struct g_provider * pp,int flags __unused)52713328753SAndrew Thompson g_llvm_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
52813328753SAndrew Thompson {
52913328753SAndrew Thompson struct g_consumer *cp;
53013328753SAndrew Thompson struct g_geom *gp;
53113328753SAndrew Thompson struct g_llvm_label ll;
53213328753SAndrew Thompson struct g_llvm_metadata md;
53313328753SAndrew Thompson struct g_llvm_vg *vg;
53413328753SAndrew Thompson int error;
53513328753SAndrew Thompson
53613328753SAndrew Thompson bzero(&md, sizeof(md));
53713328753SAndrew Thompson
53813328753SAndrew Thompson g_topology_assert();
53913328753SAndrew Thompson g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
54013328753SAndrew Thompson gp = g_new_geomf(mp, "linux_lvm:taste");
54113328753SAndrew Thompson /* This orphan function should be never called. */
54213328753SAndrew Thompson gp->orphan = g_llvm_taste_orphan;
54313328753SAndrew Thompson cp = g_new_consumer(gp);
54410ae42ccSAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
545d22ff249SEdward Tomasz Napierala error = g_attach(cp, pp);
546d22ff249SEdward Tomasz Napierala if (error == 0) {
54713328753SAndrew Thompson error = g_llvm_read_label(cp, &ll);
548d22ff249SEdward Tomasz Napierala if (error == 0)
54913328753SAndrew Thompson error = g_llvm_read_md(cp, &md, &ll);
55013328753SAndrew Thompson g_detach(cp);
551d22ff249SEdward Tomasz Napierala }
55213328753SAndrew Thompson g_destroy_consumer(cp);
55313328753SAndrew Thompson g_destroy_geom(gp);
55413328753SAndrew Thompson if (error != 0)
55513328753SAndrew Thompson return (NULL);
55613328753SAndrew Thompson
55713328753SAndrew Thompson vg = md.md_vg;
55813328753SAndrew Thompson if (vg->vg_geom == NULL) {
55913328753SAndrew Thompson /* new volume group */
56013328753SAndrew Thompson gp = g_new_geomf(mp, "%s", vg->vg_name);
56113328753SAndrew Thompson gp->start = g_llvm_start;
56213328753SAndrew Thompson gp->spoiled = g_llvm_orphan;
56313328753SAndrew Thompson gp->orphan = g_llvm_orphan;
56413328753SAndrew Thompson gp->access = g_llvm_access;
56513328753SAndrew Thompson vg->vg_sectorsize = pp->sectorsize;
56613328753SAndrew Thompson vg->vg_extentsize *= vg->vg_sectorsize;
56713328753SAndrew Thompson vg->vg_geom = gp;
56813328753SAndrew Thompson gp->softc = vg;
56913328753SAndrew Thompson G_LLVM_DEBUG(1, "Created volume %s, extent size %zuK",
57013328753SAndrew Thompson vg->vg_name, vg->vg_extentsize / 1024);
57113328753SAndrew Thompson }
57213328753SAndrew Thompson
57313328753SAndrew Thompson /* initialise this disk in the volume group */
57413328753SAndrew Thompson g_llvm_add_disk(vg, pp, ll.ll_uuid);
57513328753SAndrew Thompson return (vg->vg_geom);
57613328753SAndrew Thompson }
57713328753SAndrew Thompson
57813328753SAndrew Thompson static int
g_llvm_destroy(struct g_llvm_vg * vg,int force)57913328753SAndrew Thompson g_llvm_destroy(struct g_llvm_vg *vg, int force)
58013328753SAndrew Thompson {
58113328753SAndrew Thompson struct g_provider *pp;
58213328753SAndrew Thompson struct g_geom *gp;
58313328753SAndrew Thompson
58413328753SAndrew Thompson g_topology_assert();
58513328753SAndrew Thompson if (vg == NULL)
58613328753SAndrew Thompson return (ENXIO);
58713328753SAndrew Thompson gp = vg->vg_geom;
58813328753SAndrew Thompson
58913328753SAndrew Thompson LIST_FOREACH(pp, &gp->provider, provider) {
59013328753SAndrew Thompson if (pp->acr != 0 || pp->acw != 0 || pp->ace != 0) {
59113328753SAndrew Thompson G_LLVM_DEBUG(1, "Device %s is still open (r%dw%de%d)",
59213328753SAndrew Thompson pp->name, pp->acr, pp->acw, pp->ace);
59313328753SAndrew Thompson if (!force)
59413328753SAndrew Thompson return (EBUSY);
59513328753SAndrew Thompson }
59613328753SAndrew Thompson }
59713328753SAndrew Thompson
598*56279238SMark Johnston LIST_REMOVE(vg, vg_next);
599*56279238SMark Johnston g_llvm_free_vg(vg);
60013328753SAndrew Thompson gp->softc = NULL;
60113328753SAndrew Thompson g_wither_geom(gp, ENXIO);
60213328753SAndrew Thompson return (0);
60313328753SAndrew Thompson }
60413328753SAndrew Thompson
60513328753SAndrew Thompson static int
g_llvm_destroy_geom(struct gctl_req * req __unused,struct g_class * mp __unused,struct g_geom * gp)60613328753SAndrew Thompson g_llvm_destroy_geom(struct gctl_req *req __unused, struct g_class *mp __unused,
60713328753SAndrew Thompson struct g_geom *gp)
60813328753SAndrew Thompson {
60913328753SAndrew Thompson struct g_llvm_vg *vg;
61013328753SAndrew Thompson
61113328753SAndrew Thompson vg = gp->softc;
61213328753SAndrew Thompson return (g_llvm_destroy(vg, 0));
61313328753SAndrew Thompson }
61413328753SAndrew Thompson
61513328753SAndrew Thompson int
g_llvm_read_label(struct g_consumer * cp,struct g_llvm_label * ll)61613328753SAndrew Thompson g_llvm_read_label(struct g_consumer *cp, struct g_llvm_label *ll)
61713328753SAndrew Thompson {
61813328753SAndrew Thompson struct g_provider *pp;
61913328753SAndrew Thompson u_char *buf;
62013328753SAndrew Thompson int i, error = 0;
62113328753SAndrew Thompson
62213328753SAndrew Thompson g_topology_assert();
62313328753SAndrew Thompson
62413328753SAndrew Thompson /* The LVM label is stored on the first four sectors */
62513328753SAndrew Thompson error = g_access(cp, 1, 0, 0);
62613328753SAndrew Thompson if (error != 0)
62713328753SAndrew Thompson return (error);
62813328753SAndrew Thompson pp = cp->provider;
62913328753SAndrew Thompson g_topology_unlock();
63013328753SAndrew Thompson buf = g_read_data(cp, 0, pp->sectorsize * 4, &error);
63113328753SAndrew Thompson g_topology_lock();
63213328753SAndrew Thompson g_access(cp, -1, 0, 0);
63313328753SAndrew Thompson if (buf == NULL) {
63413328753SAndrew Thompson G_LLVM_DEBUG(1, "Cannot read metadata from %s (error=%d)",
63513328753SAndrew Thompson pp->name, error);
63613328753SAndrew Thompson return (error);
63713328753SAndrew Thompson }
63813328753SAndrew Thompson
63913328753SAndrew Thompson /* Search the four sectors for the LVM label. */
64013328753SAndrew Thompson for (i = 0; i < 4; i++) {
641c941b82eSZhenlei Huang error = llvm_label_decode(&buf[i * pp->sectorsize], ll, i,
642c941b82eSZhenlei Huang pp->sectorsize);
64313328753SAndrew Thompson if (error == 0)
64413328753SAndrew Thompson break; /* found it */
64513328753SAndrew Thompson }
64613328753SAndrew Thompson g_free(buf);
64713328753SAndrew Thompson return (error);
64813328753SAndrew Thompson }
64913328753SAndrew Thompson
65013328753SAndrew Thompson int
g_llvm_read_md(struct g_consumer * cp,struct g_llvm_metadata * md,struct g_llvm_label * ll)65113328753SAndrew Thompson g_llvm_read_md(struct g_consumer *cp, struct g_llvm_metadata *md,
65213328753SAndrew Thompson struct g_llvm_label *ll)
65313328753SAndrew Thompson {
65413328753SAndrew Thompson struct g_provider *pp;
65513328753SAndrew Thompson u_char *buf;
65613328753SAndrew Thompson int error;
65713328753SAndrew Thompson int size;
65813328753SAndrew Thompson
65913328753SAndrew Thompson g_topology_assert();
66013328753SAndrew Thompson
66113328753SAndrew Thompson error = g_access(cp, 1, 0, 0);
66213328753SAndrew Thompson if (error != 0)
66313328753SAndrew Thompson return (error);
66413328753SAndrew Thompson pp = cp->provider;
66513328753SAndrew Thompson g_topology_unlock();
66613328753SAndrew Thompson buf = g_read_data(cp, ll->ll_md_offset, pp->sectorsize, &error);
66713328753SAndrew Thompson g_topology_lock();
66813328753SAndrew Thompson g_access(cp, -1, 0, 0);
66913328753SAndrew Thompson if (buf == NULL) {
67013328753SAndrew Thompson G_LLVM_DEBUG(0, "Cannot read metadata from %s (error=%d)",
67113328753SAndrew Thompson cp->provider->name, error);
67213328753SAndrew Thompson return (error);
67313328753SAndrew Thompson }
67413328753SAndrew Thompson
67513328753SAndrew Thompson error = llvm_md_decode(buf, md, ll);
67613328753SAndrew Thompson g_free(buf);
67713328753SAndrew Thompson if (error != 0) {
67813328753SAndrew Thompson return (error);
67913328753SAndrew Thompson }
68013328753SAndrew Thompson
68113328753SAndrew Thompson G_LLVM_DEBUG(1, "reading LVM2 config @ %s:%ju", pp->name,
68213328753SAndrew Thompson ll->ll_md_offset + md->md_reloffset);
68313328753SAndrew Thompson error = g_access(cp, 1, 0, 0);
68413328753SAndrew Thompson if (error != 0)
68513328753SAndrew Thompson return (error);
68613328753SAndrew Thompson pp = cp->provider;
68713328753SAndrew Thompson g_topology_unlock();
68813328753SAndrew Thompson /* round up to the nearest sector */
68913328753SAndrew Thompson size = md->md_relsize +
69013328753SAndrew Thompson (pp->sectorsize - md->md_relsize % pp->sectorsize);
69113328753SAndrew Thompson buf = g_read_data(cp, ll->ll_md_offset + md->md_reloffset, size, &error);
69213328753SAndrew Thompson g_topology_lock();
69313328753SAndrew Thompson g_access(cp, -1, 0, 0);
69413328753SAndrew Thompson if (buf == NULL) {
69513328753SAndrew Thompson G_LLVM_DEBUG(0, "Cannot read LVM2 config from %s (error=%d)",
69613328753SAndrew Thompson pp->name, error);
69713328753SAndrew Thompson return (error);
69813328753SAndrew Thompson }
69913328753SAndrew Thompson buf[md->md_relsize] = '\0';
70013328753SAndrew Thompson G_LLVM_DEBUG(10, "LVM config:\n%s\n", buf);
70113328753SAndrew Thompson error = llvm_textconf_decode(buf, md->md_relsize, md);
70213328753SAndrew Thompson g_free(buf);
70313328753SAndrew Thompson
70413328753SAndrew Thompson return (error);
70513328753SAndrew Thompson }
70613328753SAndrew Thompson
70713328753SAndrew Thompson static int
llvm_label_decode(const u_char * data,struct g_llvm_label * ll,int sector,u_int sectorsize)708c941b82eSZhenlei Huang llvm_label_decode(const u_char *data, struct g_llvm_label *ll, int sector,
709c941b82eSZhenlei Huang u_int sectorsize)
71013328753SAndrew Thompson {
71113328753SAndrew Thompson uint64_t off;
71213328753SAndrew Thompson char *uuid;
71313328753SAndrew Thompson
71413328753SAndrew Thompson /* Magic string */
71513328753SAndrew Thompson if (bcmp("LABELONE", data , 8) != 0)
71613328753SAndrew Thompson return (EINVAL);
71713328753SAndrew Thompson
71813328753SAndrew Thompson /* We only support LVM2 text format */
71913328753SAndrew Thompson if (bcmp("LVM2 001", data + 24, 8) != 0) {
72013328753SAndrew Thompson G_LLVM_DEBUG(0, "Unsupported LVM format");
72113328753SAndrew Thompson return (EINVAL);
72213328753SAndrew Thompson }
72313328753SAndrew Thompson
72413328753SAndrew Thompson ll->ll_sector = le64dec(data + 8);
72513328753SAndrew Thompson ll->ll_crc = le32dec(data + 16);
72613328753SAndrew Thompson ll->ll_offset = le32dec(data + 20);
72713328753SAndrew Thompson
72813328753SAndrew Thompson if (ll->ll_sector != sector) {
72913328753SAndrew Thompson G_LLVM_DEBUG(0, "Expected sector %ju, found at %d",
73013328753SAndrew Thompson ll->ll_sector, sector);
73113328753SAndrew Thompson return (EINVAL);
73213328753SAndrew Thompson }
73313328753SAndrew Thompson
734c941b82eSZhenlei Huang /* XXX The minimal possible size of physical volume header is 88 */
735c941b82eSZhenlei Huang if (ll->ll_offset < 32 || ll->ll_offset > sectorsize - 88) {
736c941b82eSZhenlei Huang G_LLVM_DEBUG(0, "Invalid physical volume header offset %u",
737c941b82eSZhenlei Huang ll->ll_offset);
738c941b82eSZhenlei Huang return (EINVAL);
739c941b82eSZhenlei Huang }
740c941b82eSZhenlei Huang
74113328753SAndrew Thompson off = ll->ll_offset;
74213328753SAndrew Thompson /*
74313328753SAndrew Thompson * convert the binary uuid to string format, the format is
74413328753SAndrew Thompson * xxxxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxxxx (6-4-4-4-4-4-6)
74513328753SAndrew Thompson */
74613328753SAndrew Thompson uuid = ll->ll_uuid;
74713328753SAndrew Thompson bcopy(data + off, uuid, 6);
74813328753SAndrew Thompson off += 6;
74913328753SAndrew Thompson uuid += 6;
75013328753SAndrew Thompson *uuid++ = '-';
75113328753SAndrew Thompson for (int i = 0; i < 5; i++) {
75213328753SAndrew Thompson bcopy(data + off, uuid, 4);
75313328753SAndrew Thompson off += 4;
75413328753SAndrew Thompson uuid += 4;
75513328753SAndrew Thompson *uuid++ = '-';
75613328753SAndrew Thompson }
75713328753SAndrew Thompson bcopy(data + off, uuid, 6);
75813328753SAndrew Thompson off += 6;
75913328753SAndrew Thompson uuid += 6;
76013328753SAndrew Thompson *uuid++ = '\0';
76113328753SAndrew Thompson
76213328753SAndrew Thompson ll->ll_size = le64dec(data + off);
76313328753SAndrew Thompson off += 8;
76413328753SAndrew Thompson ll->ll_pestart = le64dec(data + off);
76513328753SAndrew Thompson off += 16;
76613328753SAndrew Thompson
76713328753SAndrew Thompson /* Only one data section is supported */
76813328753SAndrew Thompson if (le64dec(data + off) != 0) {
76913328753SAndrew Thompson G_LLVM_DEBUG(0, "Only one data section supported");
77013328753SAndrew Thompson return (EINVAL);
77113328753SAndrew Thompson }
77213328753SAndrew Thompson
77313328753SAndrew Thompson off += 16;
77413328753SAndrew Thompson ll->ll_md_offset = le64dec(data + off);
77513328753SAndrew Thompson off += 8;
77613328753SAndrew Thompson ll->ll_md_size = le64dec(data + off);
77713328753SAndrew Thompson off += 8;
77813328753SAndrew Thompson
77913328753SAndrew Thompson G_LLVM_DEBUG(1, "LVM metadata: offset=%ju, size=%ju", ll->ll_md_offset,
78013328753SAndrew Thompson ll->ll_md_size);
78113328753SAndrew Thompson
78213328753SAndrew Thompson /* Only one data section is supported */
78313328753SAndrew Thompson if (le64dec(data + off) != 0) {
78413328753SAndrew Thompson G_LLVM_DEBUG(0, "Only one metadata section supported");
78513328753SAndrew Thompson return (EINVAL);
78613328753SAndrew Thompson }
78713328753SAndrew Thompson
78813328753SAndrew Thompson G_LLVM_DEBUG(2, "label uuid=%s", ll->ll_uuid);
78913328753SAndrew Thompson G_LLVM_DEBUG(2, "sector=%ju, crc=%u, offset=%u, size=%ju, pestart=%ju",
79013328753SAndrew Thompson ll->ll_sector, ll->ll_crc, ll->ll_offset, ll->ll_size,
79113328753SAndrew Thompson ll->ll_pestart);
79213328753SAndrew Thompson
79313328753SAndrew Thompson return (0);
79413328753SAndrew Thompson }
79513328753SAndrew Thompson
79613328753SAndrew Thompson static int
llvm_md_decode(const u_char * data,struct g_llvm_metadata * md,struct g_llvm_label * ll)79713328753SAndrew Thompson llvm_md_decode(const u_char *data, struct g_llvm_metadata *md,
79813328753SAndrew Thompson struct g_llvm_label *ll)
79913328753SAndrew Thompson {
80013328753SAndrew Thompson uint64_t off;
80113328753SAndrew Thompson char magic[16];
80213328753SAndrew Thompson
80313328753SAndrew Thompson off = 0;
80413328753SAndrew Thompson md->md_csum = le32dec(data + off);
80513328753SAndrew Thompson off += 4;
80613328753SAndrew Thompson bcopy(data + off, magic, 16);
80713328753SAndrew Thompson off += 16;
80813328753SAndrew Thompson md->md_version = le32dec(data + off);
80913328753SAndrew Thompson off += 4;
81013328753SAndrew Thompson md->md_start = le64dec(data + off);
81113328753SAndrew Thompson off += 8;
81213328753SAndrew Thompson md->md_size = le64dec(data + off);
81313328753SAndrew Thompson off += 8;
81413328753SAndrew Thompson
81513328753SAndrew Thompson if (bcmp(G_LLVM_MAGIC, magic, 16) != 0) {
81613328753SAndrew Thompson G_LLVM_DEBUG(0, "Incorrect md magic number");
81713328753SAndrew Thompson return (EINVAL);
81813328753SAndrew Thompson }
81913328753SAndrew Thompson if (md->md_version != 1) {
82013328753SAndrew Thompson G_LLVM_DEBUG(0, "Incorrect md version number (%u)",
82113328753SAndrew Thompson md->md_version);
82213328753SAndrew Thompson return (EINVAL);
82313328753SAndrew Thompson }
82413328753SAndrew Thompson if (md->md_start != ll->ll_md_offset) {
82513328753SAndrew Thompson G_LLVM_DEBUG(0, "Incorrect md offset (%ju)", md->md_start);
82613328753SAndrew Thompson return (EINVAL);
82713328753SAndrew Thompson }
82813328753SAndrew Thompson
82913328753SAndrew Thompson /* Aparently only one is ever returned */
83013328753SAndrew Thompson md->md_reloffset = le64dec(data + off);
83113328753SAndrew Thompson off += 8;
83213328753SAndrew Thompson md->md_relsize = le64dec(data + off);
83313328753SAndrew Thompson off += 16; /* XXX skipped checksum */
83413328753SAndrew Thompson
83513328753SAndrew Thompson if (le64dec(data + off) != 0) {
83613328753SAndrew Thompson G_LLVM_DEBUG(0, "Only one reloc supported");
83713328753SAndrew Thompson return (EINVAL);
83813328753SAndrew Thompson }
83913328753SAndrew Thompson
84013328753SAndrew Thompson G_LLVM_DEBUG(3, "reloc: offset=%ju, size=%ju",
84113328753SAndrew Thompson md->md_reloffset, md->md_relsize);
84213328753SAndrew Thompson G_LLVM_DEBUG(3, "md: version=%u, start=%ju, size=%ju",
84313328753SAndrew Thompson md->md_version, md->md_start, md->md_size);
84413328753SAndrew Thompson
84513328753SAndrew Thompson return (0);
84613328753SAndrew Thompson }
84713328753SAndrew Thompson
84813328753SAndrew Thompson #define GRAB_INT(key, tok1, tok2, v) \
84913328753SAndrew Thompson if (tok1 && tok2 && strncmp(tok1, key, sizeof(key)) == 0) { \
85013328753SAndrew Thompson v = strtol(tok2, &tok1, 10); \
85113328753SAndrew Thompson if (tok1 == tok2) \
85213328753SAndrew Thompson /* strtol did not eat any of the buffer */ \
85313328753SAndrew Thompson goto bad; \
85413328753SAndrew Thompson continue; \
85513328753SAndrew Thompson }
85613328753SAndrew Thompson
85713328753SAndrew Thompson #define GRAB_STR(key, tok1, tok2, v, len) \
85813328753SAndrew Thompson if (tok1 && tok2 && strncmp(tok1, key, sizeof(key)) == 0) { \
85913328753SAndrew Thompson strsep(&tok2, "\""); \
86013328753SAndrew Thompson if (tok2 == NULL) \
86113328753SAndrew Thompson continue; \
86213328753SAndrew Thompson tok1 = strsep(&tok2, "\""); \
86313328753SAndrew Thompson if (tok2 == NULL) \
86413328753SAndrew Thompson continue; \
86513328753SAndrew Thompson strncpy(v, tok1, len); \
86613328753SAndrew Thompson continue; \
86713328753SAndrew Thompson }
86813328753SAndrew Thompson
86913328753SAndrew Thompson #define SPLIT(key, value, str) \
87013328753SAndrew Thompson key = strsep(&value, str); \
87113328753SAndrew Thompson /* strip trailing whitespace on the key */ \
87213328753SAndrew Thompson for (char *t = key; *t != '\0'; t++) \
87313328753SAndrew Thompson if (isspace(*t)) { \
87413328753SAndrew Thompson *t = '\0'; \
87513328753SAndrew Thompson break; \
87613328753SAndrew Thompson }
87713328753SAndrew Thompson
878ac2a008eSUlf Lilleengen static size_t
llvm_grab_name(char * name,const char * tok)879ac2a008eSUlf Lilleengen llvm_grab_name(char *name, const char *tok)
880ac2a008eSUlf Lilleengen {
881ac2a008eSUlf Lilleengen size_t len;
882ac2a008eSUlf Lilleengen
883ac2a008eSUlf Lilleengen len = 0;
884ac2a008eSUlf Lilleengen if (tok == NULL)
885ac2a008eSUlf Lilleengen return (0);
886ac2a008eSUlf Lilleengen if (tok[0] == '-')
887ac2a008eSUlf Lilleengen return (0);
888ac2a008eSUlf Lilleengen if (strcmp(tok, ".") == 0 || strcmp(tok, "..") == 0)
889ac2a008eSUlf Lilleengen return (0);
890ac2a008eSUlf Lilleengen while (tok[len] && (isalpha(tok[len]) || isdigit(tok[len]) ||
891ac2a008eSUlf Lilleengen tok[len] == '.' || tok[len] == '_' || tok[len] == '-' ||
892ac2a008eSUlf Lilleengen tok[len] == '+') && len < G_LLVM_NAMELEN - 1)
893ac2a008eSUlf Lilleengen len++;
894ac2a008eSUlf Lilleengen bcopy(tok, name, len);
895ac2a008eSUlf Lilleengen name[len] = '\0';
896ac2a008eSUlf Lilleengen return (len);
897ac2a008eSUlf Lilleengen }
898ac2a008eSUlf Lilleengen
89913328753SAndrew Thompson static int
llvm_textconf_decode(u_char * data,int buflen,struct g_llvm_metadata * md)90013328753SAndrew Thompson llvm_textconf_decode(u_char *data, int buflen, struct g_llvm_metadata *md)
90113328753SAndrew Thompson {
90213328753SAndrew Thompson struct g_llvm_vg *vg;
90313328753SAndrew Thompson char *buf = data;
90413328753SAndrew Thompson char *tok, *v;
90513328753SAndrew Thompson char name[G_LLVM_NAMELEN];
90613328753SAndrew Thompson char uuid[G_LLVM_UUIDLEN];
907ac2a008eSUlf Lilleengen size_t len;
90813328753SAndrew Thompson
90913328753SAndrew Thompson if (buf == NULL || *buf == '\0')
91013328753SAndrew Thompson return (EINVAL);
91113328753SAndrew Thompson
91213328753SAndrew Thompson tok = strsep(&buf, "\n");
91313328753SAndrew Thompson if (tok == NULL)
91413328753SAndrew Thompson return (EINVAL);
915ac2a008eSUlf Lilleengen len = llvm_grab_name(name, tok);
91613328753SAndrew Thompson if (len == 0)
91713328753SAndrew Thompson return (EINVAL);
91813328753SAndrew Thompson
91913328753SAndrew Thompson /* check too see if the vg has already been loaded off another disk */
92013328753SAndrew Thompson LIST_FOREACH(vg, &vg_list, vg_next) {
92113328753SAndrew Thompson if (strcmp(vg->vg_name, name) == 0) {
92213328753SAndrew Thompson uuid[0] = '\0';
92313328753SAndrew Thompson /* grab the volume group uuid */
92413328753SAndrew Thompson while ((tok = strsep(&buf, "\n")) != NULL) {
92513328753SAndrew Thompson if (strstr(tok, "{"))
92613328753SAndrew Thompson break;
92713328753SAndrew Thompson if (strstr(tok, "=")) {
92813328753SAndrew Thompson SPLIT(v, tok, "=");
92913328753SAndrew Thompson GRAB_STR("id", v, tok, uuid,
93013328753SAndrew Thompson sizeof(uuid));
93113328753SAndrew Thompson }
93213328753SAndrew Thompson }
93313328753SAndrew Thompson if (strcmp(vg->vg_uuid, uuid) == 0) {
93413328753SAndrew Thompson /* existing vg */
93513328753SAndrew Thompson md->md_vg = vg;
93613328753SAndrew Thompson return (0);
93713328753SAndrew Thompson }
93813328753SAndrew Thompson /* XXX different volume group with name clash! */
93913328753SAndrew Thompson G_LLVM_DEBUG(0,
94013328753SAndrew Thompson "%s already exists, volume group not loaded", name);
94113328753SAndrew Thompson return (EINVAL);
94213328753SAndrew Thompson }
94313328753SAndrew Thompson }
94413328753SAndrew Thompson
94513328753SAndrew Thompson vg = malloc(sizeof(*vg), M_GLLVM, M_NOWAIT|M_ZERO);
94613328753SAndrew Thompson if (vg == NULL)
94713328753SAndrew Thompson return (ENOMEM);
94813328753SAndrew Thompson
94913328753SAndrew Thompson strncpy(vg->vg_name, name, sizeof(vg->vg_name));
95013328753SAndrew Thompson LIST_INIT(&vg->vg_pvs);
95113328753SAndrew Thompson LIST_INIT(&vg->vg_lvs);
95213328753SAndrew Thompson
95313328753SAndrew Thompson #define VOL_FOREACH(func, tok, buf, p) \
95413328753SAndrew Thompson while ((tok = strsep(buf, "\n")) != NULL) { \
95513328753SAndrew Thompson if (strstr(tok, "{")) { \
95613328753SAndrew Thompson func(buf, tok, p); \
95713328753SAndrew Thompson continue; \
95813328753SAndrew Thompson } \
95913328753SAndrew Thompson if (strstr(tok, "}")) \
96013328753SAndrew Thompson break; \
96113328753SAndrew Thompson }
96213328753SAndrew Thompson
96313328753SAndrew Thompson while ((tok = strsep(&buf, "\n")) != NULL) {
96413328753SAndrew Thompson if (strcmp(tok, "physical_volumes {") == 0) {
96513328753SAndrew Thompson VOL_FOREACH(llvm_textconf_decode_pv, tok, &buf, vg);
96613328753SAndrew Thompson continue;
96713328753SAndrew Thompson }
96813328753SAndrew Thompson if (strcmp(tok, "logical_volumes {") == 0) {
96913328753SAndrew Thompson VOL_FOREACH(llvm_textconf_decode_lv, tok, &buf, vg);
97013328753SAndrew Thompson continue;
97113328753SAndrew Thompson }
97213328753SAndrew Thompson if (strstr(tok, "{")) {
97313328753SAndrew Thompson G_LLVM_DEBUG(2, "unknown section %s", tok);
97413328753SAndrew Thompson continue;
97513328753SAndrew Thompson }
97613328753SAndrew Thompson
97713328753SAndrew Thompson /* parse 'key = value' lines */
97813328753SAndrew Thompson if (strstr(tok, "=")) {
97913328753SAndrew Thompson SPLIT(v, tok, "=");
98013328753SAndrew Thompson GRAB_STR("id", v, tok, vg->vg_uuid, sizeof(vg->vg_uuid));
98113328753SAndrew Thompson GRAB_INT("extent_size", v, tok, vg->vg_extentsize);
98213328753SAndrew Thompson continue;
98313328753SAndrew Thompson }
98413328753SAndrew Thompson }
98513328753SAndrew Thompson /* basic checking */
98613328753SAndrew Thompson if (vg->vg_extentsize == 0)
98713328753SAndrew Thompson goto bad;
98813328753SAndrew Thompson
98913328753SAndrew Thompson md->md_vg = vg;
99013328753SAndrew Thompson LIST_INSERT_HEAD(&vg_list, vg, vg_next);
99113328753SAndrew Thompson G_LLVM_DEBUG(3, "vg: name=%s uuid=%s", vg->vg_name, vg->vg_uuid);
99213328753SAndrew Thompson return(0);
99313328753SAndrew Thompson
99413328753SAndrew Thompson bad:
99513328753SAndrew Thompson g_llvm_free_vg(vg);
99613328753SAndrew Thompson return (-1);
99713328753SAndrew Thompson }
99813328753SAndrew Thompson #undef VOL_FOREACH
99913328753SAndrew Thompson
100013328753SAndrew Thompson static int
llvm_textconf_decode_pv(char ** buf,char * tok,struct g_llvm_vg * vg)100113328753SAndrew Thompson llvm_textconf_decode_pv(char **buf, char *tok, struct g_llvm_vg *vg)
100213328753SAndrew Thompson {
100313328753SAndrew Thompson struct g_llvm_pv *pv;
100413328753SAndrew Thompson char *v;
1005ac2a008eSUlf Lilleengen size_t len;
100613328753SAndrew Thompson
100713328753SAndrew Thompson if (*buf == NULL || **buf == '\0')
100813328753SAndrew Thompson return (EINVAL);
100913328753SAndrew Thompson
101013328753SAndrew Thompson pv = malloc(sizeof(*pv), M_GLLVM, M_NOWAIT|M_ZERO);
101113328753SAndrew Thompson if (pv == NULL)
101213328753SAndrew Thompson return (ENOMEM);
101313328753SAndrew Thompson
101413328753SAndrew Thompson pv->pv_vg = vg;
101513328753SAndrew Thompson len = 0;
101613328753SAndrew Thompson if (tok == NULL)
101713328753SAndrew Thompson goto bad;
1018ac2a008eSUlf Lilleengen len = llvm_grab_name(pv->pv_name, tok);
101913328753SAndrew Thompson if (len == 0)
102013328753SAndrew Thompson goto bad;
102113328753SAndrew Thompson
102213328753SAndrew Thompson while ((tok = strsep(buf, "\n")) != NULL) {
102313328753SAndrew Thompson if (strstr(tok, "{"))
102413328753SAndrew Thompson goto bad;
102513328753SAndrew Thompson
102613328753SAndrew Thompson if (strstr(tok, "}"))
102713328753SAndrew Thompson break;
102813328753SAndrew Thompson
102913328753SAndrew Thompson /* parse 'key = value' lines */
103013328753SAndrew Thompson if (strstr(tok, "=")) {
103113328753SAndrew Thompson SPLIT(v, tok, "=");
103213328753SAndrew Thompson GRAB_STR("id", v, tok, pv->pv_uuid, sizeof(pv->pv_uuid));
103313328753SAndrew Thompson GRAB_INT("pe_start", v, tok, pv->pv_start);
103413328753SAndrew Thompson GRAB_INT("pe_count", v, tok, pv->pv_count);
103513328753SAndrew Thompson continue;
103613328753SAndrew Thompson }
103713328753SAndrew Thompson }
103813328753SAndrew Thompson if (tok == NULL)
103913328753SAndrew Thompson goto bad;
104013328753SAndrew Thompson /* basic checking */
104113328753SAndrew Thompson if (pv->pv_count == 0)
104213328753SAndrew Thompson goto bad;
104313328753SAndrew Thompson
104413328753SAndrew Thompson LIST_INSERT_HEAD(&vg->vg_pvs, pv, pv_next);
104513328753SAndrew Thompson G_LLVM_DEBUG(3, "pv: name=%s uuid=%s", pv->pv_name, pv->pv_uuid);
104613328753SAndrew Thompson
104713328753SAndrew Thompson return (0);
104813328753SAndrew Thompson bad:
104913328753SAndrew Thompson free(pv, M_GLLVM);
105013328753SAndrew Thompson return (-1);
105113328753SAndrew Thompson }
105213328753SAndrew Thompson
105313328753SAndrew Thompson static int
llvm_textconf_decode_lv(char ** buf,char * tok,struct g_llvm_vg * vg)105413328753SAndrew Thompson llvm_textconf_decode_lv(char **buf, char *tok, struct g_llvm_vg *vg)
105513328753SAndrew Thompson {
105613328753SAndrew Thompson struct g_llvm_lv *lv;
105713328753SAndrew Thompson struct g_llvm_segment *sg;
105813328753SAndrew Thompson char *v;
1059ac2a008eSUlf Lilleengen size_t len;
106013328753SAndrew Thompson
106113328753SAndrew Thompson if (*buf == NULL || **buf == '\0')
106213328753SAndrew Thompson return (EINVAL);
106313328753SAndrew Thompson
106413328753SAndrew Thompson lv = malloc(sizeof(*lv), M_GLLVM, M_NOWAIT|M_ZERO);
106513328753SAndrew Thompson if (lv == NULL)
106613328753SAndrew Thompson return (ENOMEM);
106713328753SAndrew Thompson
106813328753SAndrew Thompson lv->lv_vg = vg;
106913328753SAndrew Thompson LIST_INIT(&lv->lv_segs);
107013328753SAndrew Thompson
107113328753SAndrew Thompson if (tok == NULL)
107213328753SAndrew Thompson goto bad;
1073ac2a008eSUlf Lilleengen len = llvm_grab_name(lv->lv_name, tok);
107413328753SAndrew Thompson if (len == 0)
107513328753SAndrew Thompson goto bad;
107613328753SAndrew Thompson
107713328753SAndrew Thompson while ((tok = strsep(buf, "\n")) != NULL) {
107813328753SAndrew Thompson if (strstr(tok, "{")) {
107913328753SAndrew Thompson if (strstr(tok, "segment")) {
108013328753SAndrew Thompson llvm_textconf_decode_sg(buf, tok, lv);
108113328753SAndrew Thompson continue;
108213328753SAndrew Thompson } else
108313328753SAndrew Thompson /* unexpected section */
108413328753SAndrew Thompson goto bad;
108513328753SAndrew Thompson }
108613328753SAndrew Thompson
108713328753SAndrew Thompson if (strstr(tok, "}"))
108813328753SAndrew Thompson break;
108913328753SAndrew Thompson
109013328753SAndrew Thompson /* parse 'key = value' lines */
109113328753SAndrew Thompson if (strstr(tok, "=")) {
109213328753SAndrew Thompson SPLIT(v, tok, "=");
109313328753SAndrew Thompson GRAB_STR("id", v, tok, lv->lv_uuid, sizeof(lv->lv_uuid));
109413328753SAndrew Thompson GRAB_INT("segment_count", v, tok, lv->lv_sgcount);
109513328753SAndrew Thompson continue;
109613328753SAndrew Thompson }
109713328753SAndrew Thompson }
109813328753SAndrew Thompson if (tok == NULL)
109913328753SAndrew Thompson goto bad;
110013328753SAndrew Thompson if (lv->lv_sgcount == 0 || lv->lv_sgcount != lv->lv_numsegs)
110113328753SAndrew Thompson /* zero or incomplete segment list */
110213328753SAndrew Thompson goto bad;
110313328753SAndrew Thompson
110413328753SAndrew Thompson /* Optimize for only one segment on the pv */
110513328753SAndrew Thompson lv->lv_firstsg = LIST_FIRST(&lv->lv_segs);
110613328753SAndrew Thompson LIST_INSERT_HEAD(&vg->vg_lvs, lv, lv_next);
110713328753SAndrew Thompson G_LLVM_DEBUG(3, "lv: name=%s uuid=%s", lv->lv_name, lv->lv_uuid);
110813328753SAndrew Thompson
110913328753SAndrew Thompson return (0);
111013328753SAndrew Thompson bad:
111113328753SAndrew Thompson while ((sg = LIST_FIRST(&lv->lv_segs)) != NULL) {
111213328753SAndrew Thompson LIST_REMOVE(sg, sg_next);
111313328753SAndrew Thompson free(sg, M_GLLVM);
111413328753SAndrew Thompson }
111513328753SAndrew Thompson free(lv, M_GLLVM);
111613328753SAndrew Thompson return (-1);
111713328753SAndrew Thompson }
111813328753SAndrew Thompson
111913328753SAndrew Thompson static int
llvm_textconf_decode_sg(char ** buf,char * tok,struct g_llvm_lv * lv)112013328753SAndrew Thompson llvm_textconf_decode_sg(char **buf, char *tok, struct g_llvm_lv *lv)
112113328753SAndrew Thompson {
112213328753SAndrew Thompson struct g_llvm_segment *sg;
112313328753SAndrew Thompson char *v;
112413328753SAndrew Thompson int count = 0;
112513328753SAndrew Thompson
112613328753SAndrew Thompson if (*buf == NULL || **buf == '\0')
112713328753SAndrew Thompson return (EINVAL);
112813328753SAndrew Thompson
112913328753SAndrew Thompson sg = malloc(sizeof(*sg), M_GLLVM, M_NOWAIT|M_ZERO);
113013328753SAndrew Thompson if (sg == NULL)
113113328753SAndrew Thompson return (ENOMEM);
113213328753SAndrew Thompson
113313328753SAndrew Thompson while ((tok = strsep(buf, "\n")) != NULL) {
113413328753SAndrew Thompson /* only a single linear stripe is supported */
113513328753SAndrew Thompson if (strstr(tok, "stripe_count")) {
113613328753SAndrew Thompson SPLIT(v, tok, "=");
113713328753SAndrew Thompson GRAB_INT("stripe_count", v, tok, count);
113813328753SAndrew Thompson if (count != 1)
113913328753SAndrew Thompson goto bad;
114013328753SAndrew Thompson }
114113328753SAndrew Thompson
114213328753SAndrew Thompson if (strstr(tok, "{"))
114313328753SAndrew Thompson goto bad;
114413328753SAndrew Thompson
114513328753SAndrew Thompson if (strstr(tok, "}"))
114613328753SAndrew Thompson break;
114713328753SAndrew Thompson
114813328753SAndrew Thompson if (strcmp(tok, "stripes = [") == 0) {
114913328753SAndrew Thompson tok = strsep(buf, "\n");
115013328753SAndrew Thompson if (tok == NULL)
115113328753SAndrew Thompson goto bad;
115213328753SAndrew Thompson
115313328753SAndrew Thompson strsep(&tok, "\"");
115413328753SAndrew Thompson if (tok == NULL)
115513328753SAndrew Thompson goto bad; /* missing open quotes */
115613328753SAndrew Thompson v = strsep(&tok, "\"");
115713328753SAndrew Thompson if (tok == NULL)
115813328753SAndrew Thompson goto bad; /* missing close quotes */
115913328753SAndrew Thompson strncpy(sg->sg_pvname, v, sizeof(sg->sg_pvname));
116013328753SAndrew Thompson if (*tok != ',')
116113328753SAndrew Thompson goto bad; /* missing comma for stripe */
116213328753SAndrew Thompson tok++;
116313328753SAndrew Thompson
116413328753SAndrew Thompson sg->sg_pvstart = strtol(tok, &v, 10);
116513328753SAndrew Thompson if (v == tok)
116613328753SAndrew Thompson /* strtol did not eat any of the buffer */
116713328753SAndrew Thompson goto bad;
116813328753SAndrew Thompson
116913328753SAndrew Thompson continue;
117013328753SAndrew Thompson }
117113328753SAndrew Thompson
117213328753SAndrew Thompson /* parse 'key = value' lines */
117313328753SAndrew Thompson if (strstr(tok, "=")) {
117413328753SAndrew Thompson SPLIT(v, tok, "=");
117513328753SAndrew Thompson GRAB_INT("start_extent", v, tok, sg->sg_start);
117613328753SAndrew Thompson GRAB_INT("extent_count", v, tok, sg->sg_count);
117713328753SAndrew Thompson continue;
117813328753SAndrew Thompson }
117913328753SAndrew Thompson }
118013328753SAndrew Thompson if (tok == NULL)
118113328753SAndrew Thompson goto bad;
118213328753SAndrew Thompson /* basic checking */
118313328753SAndrew Thompson if (count != 1 || sg->sg_count == 0)
118413328753SAndrew Thompson goto bad;
118513328753SAndrew Thompson
118613328753SAndrew Thompson sg->sg_end = sg->sg_start + sg->sg_count - 1;
118713328753SAndrew Thompson lv->lv_numsegs++;
118813328753SAndrew Thompson lv->lv_extentcount += sg->sg_count;
118913328753SAndrew Thompson LIST_INSERT_HEAD(&lv->lv_segs, sg, sg_next);
119013328753SAndrew Thompson
119113328753SAndrew Thompson return (0);
119213328753SAndrew Thompson bad:
119313328753SAndrew Thompson free(sg, M_GLLVM);
119413328753SAndrew Thompson return (-1);
119513328753SAndrew Thompson }
119613328753SAndrew Thompson #undef GRAB_INT
119713328753SAndrew Thompson #undef GRAB_STR
119813328753SAndrew Thompson #undef SPLIT
119913328753SAndrew Thompson
120013328753SAndrew Thompson static struct g_class g_llvm_class = {
120113328753SAndrew Thompson .name = G_LLVM_CLASS_NAME,
120213328753SAndrew Thompson .version = G_VERSION,
120313328753SAndrew Thompson .init = g_llvm_init,
120413328753SAndrew Thompson .taste = g_llvm_taste,
120513328753SAndrew Thompson .destroy_geom = g_llvm_destroy_geom
120613328753SAndrew Thompson };
120713328753SAndrew Thompson
120813328753SAndrew Thompson DECLARE_GEOM_CLASS(g_llvm_class, g_linux_lvm);
120974d6c131SKyle Evans MODULE_VERSION(geom_linux_lvm, 0);
1210