192108Sphk/*- 292108Sphk * Copyright (c) 2002 Poul-Henning Kamp 392108Sphk * Copyright (c) 2002 Networks Associates Technology, Inc. 492108Sphk * All rights reserved. 592108Sphk * 692108Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp 792108Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc. 892108Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 992108Sphk * DARPA CHATS research program. 1092108Sphk * 1192108Sphk * Redistribution and use in source and binary forms, with or without 1292108Sphk * modification, are permitted provided that the following conditions 1392108Sphk * are met: 1492108Sphk * 1. Redistributions of source code must retain the above copyright 1592108Sphk * notice, this list of conditions and the following disclaimer. 1692108Sphk * 2. Redistributions in binary form must reproduce the above copyright 1792108Sphk * notice, this list of conditions and the following disclaimer in the 1892108Sphk * documentation and/or other materials provided with the distribution. 1992108Sphk * 3. The names of the authors may not be used to endorse or promote 2092108Sphk * products derived from this software without specific prior written 2192108Sphk * permission. 2292108Sphk * 2392108Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2492108Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2592108Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2692108Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2792108Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2892108Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2992108Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3092108Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3192108Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3292108Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3392108Sphk * SUCH DAMAGE. 34139778Simp */ 35139778Simp 36139778Simp/* 37104065Sphk * This is the method for dealing with BSD disklabels. It has been 38104065Sphk * extensively (by my standards at least) commented, in the vain hope that 39108819Sphk * it will serve as the source in future copy&paste operations. 4092108Sphk */ 4192108Sphk 42116196Sobrien#include <sys/cdefs.h> 43116196Sobrien__FBSDID("$FreeBSD: stable/10/sys/geom/geom_bsd.c 322860 2017-08-24 21:44:23Z mckusick $"); 44116196Sobrien 4592108Sphk#include <sys/param.h> 46113011Sphk#include <sys/endian.h> 4792108Sphk#include <sys/systm.h> 48219029Snetchild#include <sys/sysctl.h> 4992108Sphk#include <sys/kernel.h> 50138732Sphk#include <sys/fcntl.h> 5192108Sphk#include <sys/conf.h> 5292108Sphk#include <sys/bio.h> 5392108Sphk#include <sys/malloc.h> 5492108Sphk#include <sys/lock.h> 5592108Sphk#include <sys/mutex.h> 56108819Sphk#include <sys/md5.h> 5792108Sphk#include <sys/errno.h> 5892108Sphk#include <sys/disklabel.h> 59174347Sjhb#include <sys/gpt.h> 60230643Sattilio#include <sys/proc.h> 61223921Sae#include <sys/sbuf.h> 62174347Sjhb#include <sys/uuid.h> 6392108Sphk#include <geom/geom.h> 6492108Sphk#include <geom/geom_slice.h> 6592108Sphk 66219029SnetchildFEATURE(geom_bsd, "GEOM BSD disklabels support"); 67219029Snetchild 68105505Sphk#define BSD_CLASS_NAME "BSD" 6992108Sphk 70106634Sphk#define ALPHA_LABEL_OFFSET 64 71152972Ssobomax#define HISTORIC_LABEL_OFFSET 512 72106634Sphk 73114556Sphk#define LABELSIZE (148 + 16 * MAXPARTITIONS) 74114556Sphk 75113713Sphkstatic void g_bsd_hotwrite(void *arg, int flag); 76104065Sphk/* 77104065Sphk * Our private data about one instance. All the rest is handled by the 78105505Sphk * slice code and stored in its softc, so this is just the stuff 79104065Sphk * specific to BSD disklabels. 80104065Sphk */ 8192108Sphkstruct g_bsd_softc { 8295323Sphk off_t labeloffset; 83106076Sphk off_t mbroffset; 84104065Sphk off_t rawoffset; 8592108Sphk struct disklabel ondisk; 86114556Sphk u_char label[LABELSIZE]; 87108819Sphk u_char labelsum[16]; 8892108Sphk}; 8992108Sphk 90104065Sphk/* 91104065Sphk * Modify our slicer to match proposed disklabel, if possible. 92114556Sphk * This is where we make sure we don't do something stupid. 93104065Sphk */ 94104065Sphkstatic int 95114556Sphkg_bsd_modify(struct g_geom *gp, u_char *label) 96104065Sphk{ 97104065Sphk int i, error; 98104065Sphk struct partition *ppp; 99104065Sphk struct g_slicer *gsp; 100104065Sphk struct g_consumer *cp; 101113713Sphk struct g_bsd_softc *ms; 102107953Sphk u_int secsize, u; 103115509Sphk off_t rawoffset, o; 104114556Sphk struct disklabel dl; 105114556Sphk MD5_CTX md5sum; 106104065Sphk 107114556Sphk g_topology_assert(); 108114556Sphk gsp = gp->softc; 109114556Sphk ms = gsp->softc; 110114556Sphk 111114556Sphk error = bsd_disklabel_le_dec(label, &dl, MAXPARTITIONS); 112114556Sphk if (error) { 113105505Sphk return (error); 114114556Sphk } 115104065Sphk 116105505Sphk /* Get dimensions of our device. */ 117104065Sphk cp = LIST_FIRST(&gp->consumer); 118105551Sphk secsize = cp->provider->sectorsize; 119104065Sphk 120105505Sphk /* ... or a smaller sector size. */ 121114556Sphk if (dl.d_secsize < secsize) { 122104065Sphk return (EINVAL); 123114556Sphk } 124104065Sphk 125105505Sphk /* ... or a non-multiple sector size. */ 126114556Sphk if (dl.d_secsize % secsize != 0) { 127104065Sphk return (EINVAL); 128114556Sphk } 129104065Sphk 130114556Sphk /* Historical braindamage... */ 131114556Sphk rawoffset = (off_t)dl.d_partitions[RAW_PART].p_offset * dl.d_secsize; 132114672Sphk 133114556Sphk for (i = 0; i < dl.d_npartitions; i++) { 134114556Sphk ppp = &dl.d_partitions[i]; 135114556Sphk if (ppp->p_size == 0) 136114556Sphk continue; 137114556Sphk o = (off_t)ppp->p_offset * dl.d_secsize; 138104065Sphk 139114556Sphk if (o < rawoffset) 140114556Sphk rawoffset = 0; 141114556Sphk } 142114705Sphk 143114785Sphk if (rawoffset != 0 && (off_t)rawoffset != ms->mbroffset) 144185518Sivoras printf("WARNING: %s expected rawoffset %jd, found %jd\n", 145185518Sivoras gp->name, 146114705Sphk (intmax_t)ms->mbroffset/dl.d_secsize, 147114785Sphk (intmax_t)rawoffset/dl.d_secsize); 148114556Sphk 149105505Sphk /* Don't munge open partitions. */ 150114556Sphk for (i = 0; i < dl.d_npartitions; i++) { 151114556Sphk ppp = &dl.d_partitions[i]; 152104065Sphk 153114556Sphk o = (off_t)ppp->p_offset * dl.d_secsize; 154114556Sphk if (o == 0) 155114556Sphk o = rawoffset; 156104065Sphk error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 157114556Sphk o - rawoffset, 158114556Sphk (off_t)ppp->p_size * dl.d_secsize, 159114556Sphk dl.d_secsize, 160104065Sphk "%s%c", gp->name, 'a' + i); 161114556Sphk if (error) 162104065Sphk return (error); 163104065Sphk } 164104065Sphk 165104065Sphk /* Look good, go for it... */ 166107953Sphk for (u = 0; u < gsp->nslice; u++) { 167114556Sphk ppp = &dl.d_partitions[u]; 168114556Sphk o = (off_t)ppp->p_offset * dl.d_secsize; 169114556Sphk if (o == 0) 170114556Sphk o = rawoffset; 171107953Sphk g_slice_config(gp, u, G_SLICE_CONFIG_SET, 172114556Sphk o - rawoffset, 173114556Sphk (off_t)ppp->p_size * dl.d_secsize, 174114556Sphk dl.d_secsize, 175107953Sphk "%s%c", gp->name, 'a' + u); 176104065Sphk } 177104065Sphk 178114556Sphk /* Update our softc */ 179114556Sphk ms->ondisk = dl; 180114556Sphk if (label != ms->label) 181114556Sphk bcopy(label, ms->label, LABELSIZE); 182114556Sphk ms->rawoffset = rawoffset; 18393097Sphk 184114556Sphk /* 185114556Sphk * In order to avoid recursively attaching to the same 186114556Sphk * on-disk label (it's usually visible through the 'c' 187114556Sphk * partition) we calculate an MD5 and ask if other BSD's 188114556Sphk * below us love that label. If they do, we don't. 189114556Sphk */ 190114556Sphk MD5Init(&md5sum); 191114556Sphk MD5Update(&md5sum, ms->label, sizeof(ms->label)); 192114556Sphk MD5Final(ms->labelsum, &md5sum); 193114556Sphk 194114556Sphk return (0); 19593097Sphk} 19693097Sphk 197104065Sphk/* 198104065Sphk * This is an internal helper function, called multiple times from the taste 199104065Sphk * function to try to locate a disklabel on the disk. More civilized formats 200104065Sphk * will not need this, as there is only one possible place on disk to look 201104065Sphk * for the magic spot. 202104065Sphk */ 203104065Sphk 20493097Sphkstatic int 205107526Sphkg_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset) 20693097Sphk{ 20793097Sphk int error; 20893097Sphk u_char *buf; 20995323Sphk struct disklabel *dl; 21096953Sphk off_t secoff; 21193097Sphk 212104065Sphk /* 213104065Sphk * We need to read entire aligned sectors, and we assume that the 214104065Sphk * disklabel does not span sectors, so one sector is enough. 215104065Sphk */ 21696953Sphk secoff = offset % secsize; 217152971Ssobomax buf = g_read_data(cp, offset - secoff, secsize, NULL); 218152967Ssobomax if (buf == NULL) 219105505Sphk return (ENOENT); 220104065Sphk 221105505Sphk /* Decode into our native format. */ 222104065Sphk dl = &ms->ondisk; 223114556Sphk error = bsd_disklabel_le_dec(buf + secoff, dl, MAXPARTITIONS); 224114556Sphk if (!error) 225114556Sphk bcopy(buf + secoff, ms->label, LABELSIZE); 226104065Sphk 227105505Sphk /* Remember to free the buffer g_read_data() gave us. */ 22893097Sphk g_free(buf); 229104065Sphk 230113713Sphk ms->labeloffset = offset; 231105505Sphk return (error); 23293097Sphk} 23393097Sphk 234104065Sphk/* 235114568Sphk * This function writes the current label to disk, possibly updating 236114568Sphk * the alpha SRM checksum. 237114568Sphk */ 238114568Sphk 239114568Sphkstatic int 240114568Sphkg_bsd_writelabel(struct g_geom *gp, u_char *bootcode) 241114568Sphk{ 242114568Sphk off_t secoff; 243114568Sphk u_int secsize; 244114568Sphk struct g_consumer *cp; 245114568Sphk struct g_slicer *gsp; 246114568Sphk struct g_bsd_softc *ms; 247114568Sphk u_char *buf; 248114568Sphk uint64_t sum; 249114568Sphk int error, i; 250114568Sphk 251114568Sphk gsp = gp->softc; 252114568Sphk ms = gsp->softc; 253114568Sphk cp = LIST_FIRST(&gp->consumer); 254114568Sphk /* Get sector size, we need it to read data. */ 255114568Sphk secsize = cp->provider->sectorsize; 256114568Sphk secoff = ms->labeloffset % secsize; 257114568Sphk if (bootcode == NULL) { 258114568Sphk buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error); 259152967Ssobomax if (buf == NULL) 260114568Sphk return (error); 261114568Sphk bcopy(ms->label, buf + secoff, sizeof(ms->label)); 262114568Sphk } else { 263114568Sphk buf = bootcode; 264114568Sphk bcopy(ms->label, buf + ms->labeloffset, sizeof(ms->label)); 265114568Sphk } 266114568Sphk if (ms->labeloffset == ALPHA_LABEL_OFFSET) { 267114568Sphk sum = 0; 268114568Sphk for (i = 0; i < 63; i++) 269114568Sphk sum += le64dec(buf + i * 8); 270114568Sphk le64enc(buf + 504, sum); 271114568Sphk } 272114568Sphk if (bootcode == NULL) { 273114568Sphk error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize); 274114568Sphk g_free(buf); 275114568Sphk } else { 276114568Sphk error = g_write_data(cp, 0, bootcode, BBSIZE); 277114568Sphk } 278114568Sphk return(error); 279114568Sphk} 280114568Sphk 281114568Sphk/* 282107526Sphk * If the user tries to overwrite our disklabel through an open partition 283107526Sphk * or via a magicwrite config call, we end up here and try to prevent 284107526Sphk * footshooting as best we can. 285107526Sphk */ 286107526Sphkstatic void 287112989Sphkg_bsd_hotwrite(void *arg, int flag) 288107526Sphk{ 289107526Sphk struct bio *bp; 290107526Sphk struct g_geom *gp; 291107526Sphk struct g_slicer *gsp; 292107832Sphk struct g_slice *gsl; 293107526Sphk struct g_bsd_softc *ms; 294107526Sphk u_char *p; 295107526Sphk int error; 296107526Sphk 297114556Sphk g_topology_assert(); 298113713Sphk /* 299113713Sphk * We should never get canceled, because that would amount to a removal 300113713Sphk * of the geom while there was outstanding I/O requests. 301113713Sphk */ 302112989Sphk KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled")); 303107526Sphk bp = arg; 304107526Sphk gp = bp->bio_to->geom; 305107526Sphk gsp = gp->softc; 306107526Sphk ms = gsp->softc; 307107832Sphk gsl = &gsp->slices[bp->bio_to->index]; 308322860Smckusick p = (u_char*)bp->bio_data + ms->labeloffset - 309322860Smckusick (bp->bio_offset + gsl->offset); 310114556Sphk error = g_bsd_modify(gp, p); 311107526Sphk if (error) { 312107526Sphk g_io_deliver(bp, EPERM); 313107526Sphk return; 314107526Sphk } 315107526Sphk g_slice_finish_hot(bp); 316107526Sphk} 317107526Sphk 31893097Sphkstatic int 319119660Sphkg_bsd_start(struct bio *bp) 320119660Sphk{ 321119660Sphk struct g_geom *gp; 322119660Sphk struct g_bsd_softc *ms; 323119660Sphk struct g_slicer *gsp; 324119660Sphk 325119660Sphk gp = bp->bio_to->geom; 326119660Sphk gsp = gp->softc; 327119660Sphk ms = gsp->softc; 328119660Sphk if (bp->bio_cmd == BIO_GETATTR) { 329119660Sphk if (g_handleattr(bp, "BSD::labelsum", ms->labelsum, 330119660Sphk sizeof(ms->labelsum))) 331119660Sphk return (1); 332119660Sphk } 333119660Sphk return (0); 334119660Sphk} 335119660Sphk 336104065Sphk/* 337104065Sphk * Dump configuration information in XML format. 338104065Sphk * Notice that the function is called once for the geom and once for each 339104065Sphk * consumer and provider. We let g_slice_dumpconf() do most of the work. 340104065Sphk */ 34192108Sphkstatic void 342107953Sphkg_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp) 34392108Sphk{ 34495323Sphk struct g_bsd_softc *ms; 34592108Sphk struct g_slicer *gsp; 34692108Sphk 34792108Sphk gsp = gp->softc; 34892108Sphk ms = gsp->softc; 349106076Sphk g_slice_dumpconf(sb, indent, gp, cp, pp); 350106076Sphk if (indent != NULL && pp == NULL && cp == NULL) { 351103284Sphk sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n", 352103284Sphk indent, (intmax_t)ms->labeloffset); 353106076Sphk sbuf_printf(sb, "%s<rawoffset>%jd</rawoffset>\n", 354106076Sphk indent, (intmax_t)ms->rawoffset); 355106076Sphk sbuf_printf(sb, "%s<mbroffset>%jd</mbroffset>\n", 356106076Sphk indent, (intmax_t)ms->mbroffset); 357109081Sjhb } else if (pp != NULL) { 358109081Sjhb if (indent == NULL) 359109081Sjhb sbuf_printf(sb, " ty %d", 360114556Sphk ms->ondisk.d_partitions[pp->index].p_fstype); 361109081Sjhb else 362109081Sjhb sbuf_printf(sb, "%s<type>%d</type>\n", indent, 363114556Sphk ms->ondisk.d_partitions[pp->index].p_fstype); 36492108Sphk } 36592108Sphk} 36692108Sphk 367104065Sphk/* 368104065Sphk * The taste function is called from the event-handler, with the topology 369104065Sphk * lock already held and a provider to examine. The flags are unused. 370104065Sphk * 371104065Sphk * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and 372104065Sphk * if we find valid, consistent magic on it, build a geom on it. 373104065Sphk * 374104065Sphk * There may be cases where the operator would like to put a BSD-geom on 375104065Sphk * providers which do not meet all of the requirements. This can be done 376104065Sphk * by instead passing the G_TF_INSIST flag, which will override these 377104065Sphk * checks. 378104065Sphk * 379104065Sphk * The final flags value is G_TF_TRANSPARENT, which instructs the method 380104065Sphk * to put a geom on top of the provider and configure it to be as transparent 381104065Sphk * as possible. This is not really relevant to the BSD method and therefore 382104065Sphk * not implemented here. 383104065Sphk */ 384104065Sphk 385174347Sjhbstatic struct uuid freebsd_slice = GPT_ENT_TYPE_FREEBSD; 386174347Sjhb 38792108Sphkstatic struct g_geom * 38893250Sphkg_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) 38992108Sphk{ 39092108Sphk struct g_geom *gp; 39192108Sphk struct g_consumer *cp; 392104065Sphk int error, i; 39392108Sphk struct g_bsd_softc *ms; 39492108Sphk u_int secsize; 39594287Sphk struct g_slicer *gsp; 396114556Sphk u_char hash[16]; 397108819Sphk MD5_CTX md5sum; 398174347Sjhb struct uuid uuid; 39992108Sphk 40092108Sphk g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name); 40192108Sphk g_topology_assert(); 402104065Sphk 403105505Sphk /* We don't implement transparent inserts. */ 404104065Sphk if (flags == G_TF_TRANSPARENT) 405104065Sphk return (NULL); 406104065Sphk 407104065Sphk /* 408104065Sphk * BSD labels are a subclass of the general "slicing" topology so 409104065Sphk * a lot of the work can be done by the common "slice" code. 410104065Sphk * Create a geom with space for MAXPARTITIONS providers, one consumer 411104065Sphk * and a softc structure for us. Specify the provider to attach 412104065Sphk * the consumer to and our "start" routine for special requests. 413104065Sphk * The provider is opened with mode (1,0,0) so we can do reads 414104065Sphk * from it. 415104065Sphk */ 416104065Sphk gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms, 417105505Sphk sizeof(*ms), g_bsd_start); 41892108Sphk if (gp == NULL) 41992108Sphk return (NULL); 420104065Sphk 421105505Sphk /* Get the geom_slicer softc from the geom. */ 422104065Sphk gsp = gp->softc; 423105505Sphk 424104065Sphk /* 425104065Sphk * The do...while loop here allows us to have multiple escapes 426104065Sphk * using a simple "break". This improves code clarity without 427104065Sphk * ending up in deep nesting and without using goto or come from. 428104065Sphk */ 429104065Sphk do { 430104065Sphk /* 431104065Sphk * If the provider is an MBR we will only auto attach 432104065Sphk * to type 165 slices in the G_TF_NORMAL case. We will 433108819Sphk * attach to any other type. 434104065Sphk */ 43594287Sphk error = g_getattr("MBR::type", cp, &i); 436107526Sphk if (!error) { 437107526Sphk if (i != 165 && flags == G_TF_NORMAL) 438107526Sphk break; 439107526Sphk error = g_getattr("MBR::offset", cp, &ms->mbroffset); 440107526Sphk if (error) 441107526Sphk break; 442107526Sphk } 443104065Sphk 444107526Sphk /* Same thing if we are inside a PC98 */ 445106559Snyan error = g_getattr("PC98::type", cp, &i); 446107526Sphk if (!error) { 447107526Sphk if (i != 0xc494 && flags == G_TF_NORMAL) 448107526Sphk break; 449107526Sphk error = g_getattr("PC98::offset", cp, &ms->mbroffset); 450107526Sphk if (error) 451107526Sphk break; 452107526Sphk } 453106559Snyan 454174347Sjhb /* Same thing if we are inside a GPT */ 455174347Sjhb error = g_getattr("GPT::type", cp, &uuid); 456174347Sjhb if (!error) { 457174347Sjhb if (memcmp(&uuid, &freebsd_slice, sizeof(uuid)) != 0 && 458174347Sjhb flags == G_TF_NORMAL) 459174347Sjhb break; 460174347Sjhb } 461174347Sjhb 462104065Sphk /* Get sector size, we need it to read data. */ 463105551Sphk secsize = cp->provider->sectorsize; 464105551Sphk if (secsize < 512) 465104065Sphk break; 466104065Sphk 467105505Sphk /* First look for a label at the start of the second sector. */ 468107526Sphk error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize); 469104065Sphk 470152972Ssobomax /* 471152972Ssobomax * If sector size is not 512 the label still can be at 472152972Ssobomax * offset 512, not at the start of the second sector. At least 473152972Ssobomax * it's true for labels created by the FreeBSD's bsdlabel(8). 474152972Ssobomax */ 475152972Ssobomax if (error && secsize != HISTORIC_LABEL_OFFSET) 476152972Ssobomax error = g_bsd_try(gp, gsp, cp, secsize, ms, 477152972Ssobomax HISTORIC_LABEL_OFFSET); 478152972Ssobomax 479106634Sphk /* Next, look for alpha labels */ 480103009Sphk if (error) 481107526Sphk error = g_bsd_try(gp, gsp, cp, secsize, ms, 482106634Sphk ALPHA_LABEL_OFFSET); 483104065Sphk 484105505Sphk /* If we didn't find a label, punt. */ 48593097Sphk if (error) 48692108Sphk break; 487104065Sphk 488104065Sphk /* 489108819Sphk * In order to avoid recursively attaching to the same 490108819Sphk * on-disk label (it's usually visible through the 'c' 491108819Sphk * partition) we calculate an MD5 and ask if other BSD's 492108819Sphk * below us love that label. If they do, we don't. 493108819Sphk */ 494108819Sphk MD5Init(&md5sum); 495114556Sphk MD5Update(&md5sum, ms->label, sizeof(ms->label)); 496108819Sphk MD5Final(ms->labelsum, &md5sum); 497108819Sphk 498108819Sphk error = g_getattr("BSD::labelsum", cp, &hash); 499115611Sphk if (!error && !bcmp(ms->labelsum, hash, sizeof(hash))) 500108819Sphk break; 501108819Sphk 502108819Sphk /* 503105505Sphk * Process the found disklabel, and modify our "slice" 504104065Sphk * instance to match it, if possible. 505104065Sphk */ 506114556Sphk error = g_bsd_modify(gp, ms->label); 507104065Sphk } while (0); 508104065Sphk 509109169Sphk /* Success or failure, we can close our provider now. */ 510125803Sphk g_access(cp, -1, 0, 0); 511104065Sphk 512104065Sphk /* If we have configured any providers, return the new geom. */ 513114556Sphk if (gsp->nprovider > 0) { 514114556Sphk g_slice_conf_hot(gp, 0, ms->labeloffset, LABELSIZE, 515114556Sphk G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL); 516114556Sphk gsp->hot = g_bsd_hotwrite; 51792108Sphk return (gp); 518114556Sphk } 519104065Sphk /* 520104065Sphk * ...else push the "self-destruct" button, by spoiling our own 521114506Sphk * consumer. This triggers a call to g_slice_spoiled which will 522104065Sphk * dismantle what was setup. 523104065Sphk */ 524114506Sphk g_slice_spoiled(cp); 52592108Sphk return (NULL); 52692108Sphk} 52792108Sphk 528114568Sphkstruct h0h0 { 529114568Sphk struct g_geom *gp; 530114568Sphk struct g_bsd_softc *ms; 531114568Sphk u_char *label; 532114568Sphk int error; 533114568Sphk}; 534114568Sphk 535114568Sphkstatic void 536114568Sphkg_bsd_callconfig(void *arg, int flag) 537114568Sphk{ 538114568Sphk struct h0h0 *hp; 539114568Sphk 540114568Sphk hp = arg; 541114568Sphk hp->error = g_bsd_modify(hp->gp, hp->label); 542114568Sphk if (!hp->error) 543114568Sphk hp->error = g_bsd_writelabel(hp->gp, NULL); 544114568Sphk} 545114568Sphk 546114568Sphk/* 547114568Sphk * NB! curthread is user process which GCTL'ed. 548114568Sphk */ 549115624Sphkstatic void 550115624Sphkg_bsd_config(struct gctl_req *req, struct g_class *mp, char const *verb) 551114568Sphk{ 552114568Sphk u_char *label; 553115509Sphk int error; 554114568Sphk struct h0h0 h0h0; 555115624Sphk struct g_geom *gp; 556114568Sphk struct g_slicer *gsp; 557114568Sphk struct g_consumer *cp; 558114671Sphk struct g_bsd_softc *ms; 559114568Sphk 560114568Sphk g_topology_assert(); 561115624Sphk gp = gctl_get_geom(req, mp, "geom"); 562115624Sphk if (gp == NULL) 563115624Sphk return; 564114568Sphk cp = LIST_FIRST(&gp->consumer); 565114568Sphk gsp = gp->softc; 566114671Sphk ms = gsp->softc; 567114671Sphk if (!strcmp(verb, "read mbroffset")) { 568157581Smarcel gctl_set_param_err(req, "mbroffset", &ms->mbroffset, 569157581Smarcel sizeof(ms->mbroffset)); 570115624Sphk return; 571114671Sphk } else if (!strcmp(verb, "write label")) { 572114568Sphk label = gctl_get_paraml(req, "label", LABELSIZE); 573114568Sphk if (label == NULL) 574115624Sphk return; 575114568Sphk h0h0.gp = gp; 576114568Sphk h0h0.ms = gsp->softc; 577114568Sphk h0h0.label = label; 578114568Sphk h0h0.error = -1; 579114568Sphk /* XXX: Does this reference register with our selfdestruct code ? */ 580125755Sphk error = g_access(cp, 1, 1, 1); 581114568Sphk if (error) { 582115624Sphk gctl_error(req, "could not access consumer"); 583115624Sphk return; 584114568Sphk } 585115624Sphk g_bsd_callconfig(&h0h0, 0); 586114568Sphk error = h0h0.error; 587125755Sphk g_access(cp, -1, -1, -1); 588114568Sphk } else if (!strcmp(verb, "write bootcode")) { 589114568Sphk label = gctl_get_paraml(req, "bootcode", BBSIZE); 590114568Sphk if (label == NULL) 591115624Sphk return; 592114568Sphk /* XXX: Does this reference register with our selfdestruct code ? */ 593125755Sphk error = g_access(cp, 1, 1, 1); 594114568Sphk if (error) { 595115624Sphk gctl_error(req, "could not access consumer"); 596115624Sphk return; 597114568Sphk } 598114568Sphk error = g_bsd_writelabel(gp, label); 599125755Sphk g_access(cp, -1, -1, -1); 600114568Sphk } else { 601115624Sphk gctl_error(req, "Unknown verb parameter"); 602114568Sphk } 603114568Sphk 604115624Sphk return; 605114568Sphk} 606114568Sphk 607105505Sphk/* Finally, register with GEOM infrastructure. */ 608104065Sphkstatic struct g_class g_bsd_class = { 609112552Sphk .name = BSD_CLASS_NAME, 610133318Sphk .version = G_VERSION, 611112552Sphk .taste = g_bsd_taste, 612115624Sphk .ctlreq = g_bsd_config, 613133314Sphk .dumpconf = g_bsd_dumpconf, 61492108Sphk}; 61592108Sphk 61693248SphkDECLARE_GEOM_CLASS(g_bsd_class, g_bsd); 617