geom_sunlabel.c revision 219029
1170613Sbms/*- 2189592Sbms * Copyright (c) 2002 Poul-Henning Kamp 3170613Sbms * Copyright (c) 2002 Networks Associates Technology, Inc. 4170613Sbms * All rights reserved. 5170613Sbms * 6170613Sbms * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7170613Sbms * and NAI Labs, the Security Research Division of Network Associates, Inc. 8170613Sbms * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9170613Sbms * DARPA CHATS research program. 10170613Sbms * 11170613Sbms * Redistribution and use in source and binary forms, with or without 12170613Sbms * modification, are permitted provided that the following conditions 13170613Sbms * are met: 14170613Sbms * 1. Redistributions of source code must retain the above copyright 15170613Sbms * notice, this list of conditions and the following disclaimer. 16170613Sbms * 2. Redistributions in binary form must reproduce the above copyright 17170613Sbms * notice, this list of conditions and the following disclaimer in the 18170613Sbms * documentation and/or other materials provided with the distribution. 19170613Sbms * 3. The names of the authors may not be used to endorse or promote 20170613Sbms * products derived from this software without specific prior written 21170613Sbms * permission. 22170613Sbms * 23170613Sbms * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24170613Sbms * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25170613Sbms * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26170613Sbms * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27170613Sbms * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28170613Sbms * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29170613Sbms * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30170613Sbms * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31170613Sbms * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32170613Sbms * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33170613Sbms * SUCH DAMAGE. 34170613Sbms */ 35170613Sbms 36170613Sbms#include <sys/cdefs.h> 37170613Sbms__FBSDID("$FreeBSD: head/sys/geom/geom_sunlabel.c 219029 2011-02-25 10:24:35Z netchild $"); 38170613Sbms 39170613Sbms#include <sys/param.h> 40170613Sbms#include <sys/endian.h> 41170613Sbms#include <sys/systm.h> 42170613Sbms#include <sys/sysctl.h> 43171746Scsjp#include <sys/kernel.h> 44170613Sbms#include <sys/conf.h> 45170613Sbms#include <sys/bio.h> 46189592Sbms#include <sys/malloc.h> 47170613Sbms#include <sys/lock.h> 48181803Sbz#include <sys/mutex.h> 49189592Sbms#include <sys/md5.h> 50189592Sbms#include <sys/sun_disklabel.h> 51170613Sbms#include <geom/geom.h> 52170613Sbms#include <geom/geom_slice.h> 53170613Sbms#include <machine/endian.h> 54170613Sbms 55185571SbzFEATURE(geom_sunlabel, "GEOM Sun/Solaris partitioning support"); 56170613Sbms 57170613Sbms#define SUNLABEL_CLASS_NAME "SUN" 58170613Sbms 59170613Sbmsstruct g_sunlabel_softc { 60170613Sbms int sectorsize; 61170613Sbms int nheads; 62170613Sbms int nsects; 63185571Sbz int nalt; 64170613Sbms u_char labelsum[16]; 65189592Sbms}; 66191659Sbms 67189592Sbmsstatic int 68189592Sbmsg_sunlabel_modify(struct g_geom *gp, struct g_sunlabel_softc *ms, u_char *sec0) 69170613Sbms{ 70170613Sbms int i, error; 71170613Sbms u_int u, v, csize; 72170613Sbms struct sun_disklabel sl; 73170613Sbms MD5_CTX md5sum; 74170613Sbms 75170613Sbms error = sunlabel_dec(sec0, &sl); 76170613Sbms if (error) 77170613Sbms return (error); 78170613Sbms 79170613Sbms csize = sl.sl_ntracks * sl.sl_nsectors; 80189592Sbms 81189592Sbms for (i = 0; i < SUN_NPART; i++) { 82170613Sbms v = sl.sl_part[i].sdkp_cyloffset; 83170613Sbms u = sl.sl_part[i].sdkp_nsectors; 84189592Sbms error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 85189592Sbms ((off_t)v * csize) << 9ULL, 86170613Sbms ((off_t)u) << 9ULL, 87189592Sbms ms->sectorsize, 88189592Sbms "%s%c", gp->name, 'a' + i); 89189592Sbms if (error) 90189592Sbms return (error); 91170613Sbms } 92189592Sbms for (i = 0; i < SUN_NPART; i++) { 93189592Sbms v = sl.sl_part[i].sdkp_cyloffset; 94189592Sbms u = sl.sl_part[i].sdkp_nsectors; 95189592Sbms g_slice_config(gp, i, G_SLICE_CONFIG_SET, 96189592Sbms ((off_t)v * csize) << 9ULL, 97189592Sbms ((off_t)u) << 9ULL, 98189592Sbms ms->sectorsize, 99189592Sbms "%s%c", gp->name, 'a' + i); 100189592Sbms } 101170613Sbms ms->nalt = sl.sl_acylinders; 102170613Sbms ms->nheads = sl.sl_ntracks; 103189592Sbms ms->nsects = sl.sl_nsectors; 104170613Sbms 105170613Sbms /* 106170613Sbms * Calculate MD5 from the first sector and use it for avoiding 107170613Sbms * recursive labels creation. 108189592Sbms */ 109170613Sbms MD5Init(&md5sum); 110170613Sbms MD5Update(&md5sum, sec0, ms->sectorsize); 111189592Sbms MD5Final(ms->labelsum, &md5sum); 112189592Sbms 113189592Sbms return (0); 114189592Sbms} 115170613Sbms 116170613Sbmsstatic void 117170613Sbmsg_sunlabel_hotwrite(void *arg, int flag) 118170613Sbms{ 119189592Sbms struct bio *bp; 120189592Sbms struct g_geom *gp; 121189592Sbms struct g_slicer *gsp; 122170613Sbms struct g_slice *gsl; 123189592Sbms struct g_sunlabel_softc *ms; 124189592Sbms u_char *p; 125189592Sbms int error; 126189592Sbms 127189592Sbms KASSERT(flag != EV_CANCEL, ("g_sunlabel_hotwrite cancelled")); 128189592Sbms bp = arg; 129189592Sbms gp = bp->bio_to->geom; 130189592Sbms gsp = gp->softc; 131189592Sbms ms = gsp->softc; 132189592Sbms gsl = &gsp->slices[bp->bio_to->index]; 133189592Sbms /* 134189592Sbms * XXX: For all practical purposes, this whould be equvivalent to 135170613Sbms * XXX: "p = (u_char *)bp->bio_data;" because the label is always 136189592Sbms * XXX: in the first sector and we refuse sectors smaller than the 137189592Sbms * XXX: label. 138189592Sbms */ 139189592Sbms p = (u_char *)bp->bio_data - (bp->bio_offset + gsl->offset); 140189592Sbms 141189592Sbms error = g_sunlabel_modify(gp, ms, p); 142189592Sbms if (error) { 143189592Sbms g_io_deliver(bp, EPERM); 144189592Sbms return; 145189592Sbms } 146189592Sbms g_slice_finish_hot(bp); 147189592Sbms} 148189592Sbms 149189592Sbmsstatic void 150189592Sbmsg_sunlabel_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) 151170613Sbms{ 152170613Sbms struct g_slicer *gsp; 153170613Sbms struct g_sunlabel_softc *ms; 154170613Sbms 155170613Sbms gsp = gp->softc; 156189592Sbms ms = gsp->softc; 157189592Sbms g_slice_dumpconf(sb, indent, gp, cp, pp); 158189592Sbms if (indent == NULL) { 159189592Sbms sbuf_printf(sb, " sc %u hd %u alt %u", 160170613Sbms ms->nsects, ms->nheads, ms->nalt); 161170613Sbms } 162189592Sbms} 163170613Sbms 164189357Sbmsstruct g_hh01 { 165189357Sbms struct g_geom *gp; 166189592Sbms struct g_sunlabel_softc *ms; 167189592Sbms u_char *label; 168189592Sbms int error; 169189592Sbms}; 170189592Sbms 171189592Sbmsstatic void 172189592Sbmsg_sunlabel_callconfig(void *arg, int flag) 173189592Sbms{ 174189592Sbms struct g_hh01 *hp; 175189592Sbms 176189592Sbms hp = arg; 177189592Sbms hp->error = g_sunlabel_modify(hp->gp, hp->ms, hp->label); 178189357Sbms if (!hp->error) 179189357Sbms hp->error = g_write_data(LIST_FIRST(&hp->gp->consumer), 180189357Sbms 0, hp->label, SUN_SIZE); 181189357Sbms} 182189357Sbms 183189592Sbms/* 184189592Sbms * NB! curthread is user process which GCTL'ed. 185189592Sbms */ 186189592Sbmsstatic void 187170613Sbmsg_sunlabel_config(struct gctl_req *req, struct g_class *mp, const char *verb) 188189592Sbms{ 189189592Sbms u_char *label; 190189592Sbms int error, i; 191189592Sbms struct g_hh01 h0h0; 192189592Sbms struct g_slicer *gsp; 193189592Sbms struct g_geom *gp; 194189592Sbms struct g_consumer *cp; 195189592Sbms 196189592Sbms g_topology_assert(); 197189592Sbms gp = gctl_get_geom(req, mp, "geom"); 198189592Sbms if (gp == NULL) 199189592Sbms return; 200189592Sbms cp = LIST_FIRST(&gp->consumer); 201189592Sbms gsp = gp->softc; 202189592Sbms if (!strcmp(verb, "write label")) { 203189592Sbms label = gctl_get_paraml(req, "label", SUN_SIZE); 204189592Sbms if (label == NULL) 205189592Sbms return; 206189592Sbms h0h0.gp = gp; 207189592Sbms h0h0.ms = gsp->softc; 208189592Sbms h0h0.label = label; 209189592Sbms h0h0.error = -1; 210189592Sbms /* XXX: Does this reference register with our selfdestruct code ? */ 211189592Sbms error = g_access(cp, 1, 1, 1); 212189592Sbms if (error) { 213189592Sbms gctl_error(req, "could not access consumer"); 214189592Sbms return; 215189592Sbms } 216189592Sbms g_sunlabel_callconfig(&h0h0, 0); 217189592Sbms g_access(cp, -1, -1, -1); 218189592Sbms } else if (!strcmp(verb, "write bootcode")) { 219189592Sbms label = gctl_get_paraml(req, "bootcode", SUN_BOOTSIZE); 220189592Sbms if (label == NULL) 221189592Sbms return; 222189592Sbms /* XXX: Does this reference register with our selfdestruct code ? */ 223189592Sbms error = g_access(cp, 1, 1, 1); 224170613Sbms if (error) { 225170613Sbms gctl_error(req, "could not access consumer"); 226170613Sbms return; 227170613Sbms } 228170613Sbms for (i = 0; i < SUN_NPART; i++) { 229170613Sbms if (gsp->slices[i].length <= SUN_BOOTSIZE) 230170613Sbms continue; 231170613Sbms g_write_data(cp, 232170613Sbms gsp->slices[i].offset + SUN_SIZE, label + SUN_SIZE, 233170613Sbms SUN_BOOTSIZE - SUN_SIZE); 234170613Sbms } 235170613Sbms g_access(cp, -1, -1, -1); 236170613Sbms } else { 237170613Sbms gctl_error(req, "Unknown verb parameter"); 238170613Sbms } 239170613Sbms} 240170613Sbms 241170613Sbmsstatic int 242170613Sbmsg_sunlabel_start(struct bio *bp) 243170613Sbms{ 244170613Sbms struct g_sunlabel_softc *mp; 245170613Sbms struct g_slicer *gsp; 246170613Sbms 247170613Sbms gsp = bp->bio_to->geom->softc; 248170613Sbms mp = gsp->softc; 249189592Sbms if (bp->bio_cmd == BIO_GETATTR) { 250170613Sbms if (g_handleattr(bp, "SUN::labelsum", mp->labelsum, 251170613Sbms sizeof(mp->labelsum))) 252170613Sbms return (1); 253189592Sbms } 254189592Sbms return (0); 255170613Sbms} 256170613Sbms 257170613Sbmsstatic struct g_geom * 258170613Sbmsg_sunlabel_taste(struct g_class *mp, struct g_provider *pp, int flags) 259170613Sbms{ 260170613Sbms struct g_geom *gp; 261170613Sbms struct g_consumer *cp; 262170613Sbms struct g_sunlabel_softc *ms; 263170613Sbms struct g_slicer *gsp; 264170613Sbms u_char *buf, hash[16]; 265170613Sbms MD5_CTX md5sum; 266189592Sbms int error; 267170613Sbms 268170613Sbms g_trace(G_T_TOPOLOGY, "g_sunlabel_taste(%s,%s)", mp->name, pp->name); 269170613Sbms g_topology_assert(); 270170613Sbms if (flags == G_TF_NORMAL && 271170613Sbms !strcmp(pp->geom->class->name, SUNLABEL_CLASS_NAME)) 272170613Sbms return (NULL); 273170613Sbms gp = g_slice_new(mp, 8, pp, &cp, &ms, sizeof *ms, g_sunlabel_start); 274170613Sbms if (gp == NULL) 275170613Sbms return (NULL); 276170613Sbms gsp = gp->softc; 277170613Sbms do { 278189592Sbms ms->sectorsize = cp->provider->sectorsize; 279189592Sbms if (ms->sectorsize < 512) 280189592Sbms break; 281170613Sbms g_topology_unlock(); 282189592Sbms buf = g_read_data(cp, 0, ms->sectorsize, NULL); 283170613Sbms g_topology_lock(); 284170613Sbms if (buf == NULL) 285170613Sbms break; 286170613Sbms 287189592Sbms /* 288170613Sbms * Calculate MD5 from the first sector and use it for avoiding 289170613Sbms * recursive labels creation. 290170613Sbms */ 291170613Sbms MD5Init(&md5sum); 292170613Sbms MD5Update(&md5sum, buf, ms->sectorsize); 293170613Sbms MD5Final(ms->labelsum, &md5sum); 294170613Sbms 295170613Sbms error = g_getattr("SUN::labelsum", cp, &hash); 296170613Sbms if (!error && !bcmp(ms->labelsum, hash, sizeof(hash))) { 297170613Sbms g_free(buf); 298170613Sbms break; 299189592Sbms } 300170613Sbms 301170613Sbms g_sunlabel_modify(gp, ms, buf); 302170613Sbms g_free(buf); 303170613Sbms 304170613Sbms break; 305170613Sbms } while (0); 306170613Sbms g_access(cp, -1, 0, 0); 307170613Sbms if (LIST_EMPTY(&gp->provider)) { 308170613Sbms g_slice_spoiled(cp); 309170613Sbms return (NULL); 310189592Sbms } 311170613Sbms g_slice_conf_hot(gp, 0, 0, SUN_SIZE, 312189592Sbms G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL); 313189592Sbms gsp->hot = g_sunlabel_hotwrite; 314189592Sbms return (gp); 315170613Sbms} 316189592Sbms 317189592Sbmsstatic struct g_class g_sunlabel_class = { 318189592Sbms .name = SUNLABEL_CLASS_NAME, 319170613Sbms .version = G_VERSION, 320189592Sbms .taste = g_sunlabel_taste, 321170613Sbms .ctlreq = g_sunlabel_config, 322189592Sbms .dumpconf = g_sunlabel_dumpconf, 323189592Sbms}; 324170613Sbms 325170613SbmsDECLARE_GEOM_CLASS(g_sunlabel_class, g_sunlabel); 326170613Sbms