1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The names of the authors may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 *
| 1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The names of the authors may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 *
|
35 * $FreeBSD: head/sys/geom/geom_bsd.c 105542 2002-10-20 19:18:07Z phk $
| 35 * $FreeBSD: head/sys/geom/geom_bsd.c 105551 2002-10-20 20:28:24Z phk $
|
36 * 37 * This is the method for dealing with BSD disklabels. It has been 38 * extensively (by my standards at least) commented, in the vain hope that 39 * it will server as the source in future copy&paste operations. 40 */ 41 42#include <sys/param.h> 43#ifndef _KERNEL 44#include <stdio.h> 45#include <string.h> 46#include <stdlib.h> 47#include <signal.h> 48#include <err.h> 49#else 50#include <sys/systm.h> 51#include <sys/kernel.h> 52#include <sys/conf.h> 53#include <sys/bio.h> 54#include <sys/malloc.h> 55#include <sys/lock.h> 56#include <sys/mutex.h> 57#endif 58#include <sys/stdint.h> 59#include <sys/errno.h> 60#include <sys/disklabel.h> 61#include <geom/geom.h> 62#include <geom/geom_slice.h> 63 64#define BSD_CLASS_NAME "BSD" 65 66/* 67 * Our private data about one instance. All the rest is handled by the 68 * slice code and stored in its softc, so this is just the stuff 69 * specific to BSD disklabels. 70 */ 71struct g_bsd_softc { 72 off_t labeloffset; 73 off_t rawoffset; 74 struct disklabel ondisk; 75 struct disklabel inram; 76}; 77 78/* 79 * The next 4 functions isolate us from how the compiler lays out and pads 80 * "struct disklabel". We treat what we read from disk as a bytestream and 81 * explicitly convert it into a struct disklabel. This makes us compiler- 82 * endianness- and wordsize- agnostic. 83 * For now we only have little-endian formats to deal with. 84 */ 85 86static void 87g_bsd_ledec_partition(u_char *ptr, struct partition *d) 88{ 89 d->p_size = g_dec_le4(ptr + 0); 90 d->p_offset = g_dec_le4(ptr + 4); 91 d->p_fsize = g_dec_le4(ptr + 8); 92 d->p_fstype = ptr[12]; 93 d->p_frag = ptr[13]; 94 d->p_cpg = g_dec_le2(ptr + 14); 95} 96 97static void 98g_bsd_ledec_disklabel(u_char *ptr, struct disklabel *d) 99{ 100 int i; 101 102 d->d_magic = g_dec_le4(ptr + 0); 103 d->d_type = g_dec_le2(ptr + 4); 104 d->d_subtype = g_dec_le2(ptr + 6); 105 bcopy(ptr + 8, d->d_typename, 16); 106 bcopy(ptr + 24, d->d_packname, 16); 107 d->d_secsize = g_dec_le4(ptr + 40); 108 d->d_nsectors = g_dec_le4(ptr + 44); 109 d->d_ntracks = g_dec_le4(ptr + 48); 110 d->d_ncylinders = g_dec_le4(ptr + 52); 111 d->d_secpercyl = g_dec_le4(ptr + 56); 112 d->d_secperunit = g_dec_le4(ptr + 60); 113 d->d_sparespertrack = g_dec_le2(ptr + 64); 114 d->d_sparespercyl = g_dec_le2(ptr + 66); 115 d->d_acylinders = g_dec_le4(ptr + 68); 116 d->d_rpm = g_dec_le2(ptr + 72); 117 d->d_interleave = g_dec_le2(ptr + 74); 118 d->d_trackskew = g_dec_le2(ptr + 76); 119 d->d_cylskew = g_dec_le2(ptr + 78); 120 d->d_headswitch = g_dec_le4(ptr + 80); 121 d->d_trkseek = g_dec_le4(ptr + 84); 122 d->d_flags = g_dec_le4(ptr + 88); 123 d->d_drivedata[0] = g_dec_le4(ptr + 92); 124 d->d_drivedata[1] = g_dec_le4(ptr + 96); 125 d->d_drivedata[2] = g_dec_le4(ptr + 100); 126 d->d_drivedata[3] = g_dec_le4(ptr + 104); 127 d->d_drivedata[4] = g_dec_le4(ptr + 108); 128 d->d_spare[0] = g_dec_le4(ptr + 112); 129 d->d_spare[1] = g_dec_le4(ptr + 116); 130 d->d_spare[2] = g_dec_le4(ptr + 120); 131 d->d_spare[3] = g_dec_le4(ptr + 124); 132 d->d_spare[4] = g_dec_le4(ptr + 128); 133 d->d_magic2 = g_dec_le4(ptr + 132); 134 d->d_checksum = g_dec_le2(ptr + 136); 135 d->d_npartitions = g_dec_le2(ptr + 138); 136 d->d_bbsize = g_dec_le4(ptr + 140); 137 d->d_sbsize = g_dec_le4(ptr + 144); 138 for (i = 0; i < MAXPARTITIONS; i++) 139 g_bsd_ledec_partition(ptr + 148 + 16 * i, &d->d_partitions[i]); 140} 141 142static void 143g_bsd_leenc_partition(u_char *ptr, struct partition *d) 144{ 145 g_enc_le4(ptr + 0, d->p_size); 146 g_enc_le4(ptr + 4, d->p_offset); 147 g_enc_le4(ptr + 8, d->p_fsize); 148 ptr[12] = d->p_fstype; 149 ptr[13] = d->p_frag; 150 g_enc_le2(ptr + 14, d->p_cpg); 151} 152 153static void 154g_bsd_leenc_disklabel(u_char *ptr, struct disklabel *d) 155{ 156 int i; 157 158 g_enc_le4(ptr + 0, d->d_magic); 159 g_enc_le2(ptr + 4, d->d_type); 160 g_enc_le2(ptr + 6, d->d_subtype); 161 bcopy(d->d_typename, ptr + 8, 16); 162 bcopy(d->d_packname, ptr + 24, 16); 163 g_enc_le4(ptr + 40, d->d_secsize); 164 g_enc_le4(ptr + 44, d->d_nsectors); 165 g_enc_le4(ptr + 48, d->d_ntracks); 166 g_enc_le4(ptr + 52, d->d_ncylinders); 167 g_enc_le4(ptr + 56, d->d_secpercyl); 168 g_enc_le4(ptr + 60, d->d_secperunit); 169 g_enc_le2(ptr + 64, d->d_sparespertrack); 170 g_enc_le2(ptr + 66, d->d_sparespercyl); 171 g_enc_le4(ptr + 68, d->d_acylinders); 172 g_enc_le2(ptr + 72, d->d_rpm); 173 g_enc_le2(ptr + 74, d->d_interleave); 174 g_enc_le2(ptr + 76, d->d_trackskew); 175 g_enc_le2(ptr + 78, d->d_cylskew); 176 g_enc_le4(ptr + 80, d->d_headswitch); 177 g_enc_le4(ptr + 84, d->d_trkseek); 178 g_enc_le4(ptr + 88, d->d_flags); 179 g_enc_le4(ptr + 92, d->d_drivedata[0]); 180 g_enc_le4(ptr + 96, d->d_drivedata[1]); 181 g_enc_le4(ptr + 100, d->d_drivedata[2]); 182 g_enc_le4(ptr + 104, d->d_drivedata[3]); 183 g_enc_le4(ptr + 108, d->d_drivedata[4]); 184 g_enc_le4(ptr + 112, d->d_spare[0]); 185 g_enc_le4(ptr + 116, d->d_spare[1]); 186 g_enc_le4(ptr + 120, d->d_spare[2]); 187 g_enc_le4(ptr + 124, d->d_spare[3]); 188 g_enc_le4(ptr + 128, d->d_spare[4]); 189 g_enc_le4(ptr + 132, d->d_magic2); 190 g_enc_le2(ptr + 136, d->d_checksum); 191 g_enc_le2(ptr + 138, d->d_npartitions); 192 g_enc_le4(ptr + 140, d->d_bbsize); 193 g_enc_le4(ptr + 144, d->d_sbsize); 194 for (i = 0; i < MAXPARTITIONS; i++) 195 g_bsd_leenc_partition(ptr + 148 + 16 * i, &d->d_partitions[i]); 196} 197 198/* 199 * For reasons which were valid and just in their days, FreeBSD/i386 uses 200 * absolute disk-addresses in disklabels. The way it works is that the 201 * p_offset field of all partitions have the first sector number of the 202 * disk slice added to them. This was hidden kernel-magic, userland did 203 * not see these offsets. These two functions subtract and add them 204 * while converting from the "ondisk" to the "inram" labels and vice 205 * versa. 206 */ 207static void 208ondisk2inram(struct g_bsd_softc *sc) 209{ 210 struct partition *ppp; 211 struct disklabel *dl; 212 int i; 213 214 sc->inram = sc->ondisk; 215 dl = &sc->inram; 216 217 /* Basic sanity-check needed to avoid mistakes. */ 218 if (dl->d_magic != DISKMAGIC || dl->d_magic2 != DISKMAGIC) 219 return; 220 if (dl->d_npartitions > MAXPARTITIONS) 221 return; 222 223 sc->rawoffset = dl->d_partitions[RAW_PART].p_offset; 224 for (i = 0; i < dl->d_npartitions; i++) { 225 ppp = &dl->d_partitions[i]; 226 if (ppp->p_size != 0 && ppp->p_offset < sc->rawoffset) 227 sc->rawoffset = 0; 228 } 229 if (sc->rawoffset > 0) { 230 231 if (dl->d_partitions[RAW_PART].p_size + 232 sc->rawoffset == dl->d_secperunit) { 233 } 234 for (i = 0; i < dl->d_npartitions; i++) { 235 ppp = &dl->d_partitions[i]; 236 ppp->p_offset -= sc->rawoffset; 237 } 238 } 239 dl->d_checksum = 0; 240 dl->d_checksum = dkcksum(&sc->inram); 241} 242 243static void 244inram2ondisk(struct g_bsd_softc *sc) 245{ 246 struct partition *ppp; 247 int i; 248 249 sc->ondisk = sc->inram; 250 if (sc->rawoffset != 0) { 251 for (i = 0; i < sc->inram.d_npartitions; i++) { 252 ppp = &sc->ondisk.d_partitions[i]; 253 ppp->p_offset += sc->rawoffset; 254 } 255 } 256 sc->ondisk.d_checksum = 0; 257 sc->ondisk.d_checksum = dkcksum(&sc->ondisk); 258} 259 260/* 261 * Check that this looks like a valid disklabel, but be prepared 262 * to get any kind of junk. The checksum must be checked only 263 * after this function returns success to prevent a bogus d_npartitions 264 * value from tripping us up. 265 */ 266static int 267g_bsd_checklabel(struct disklabel *dl) 268{ 269 struct partition *ppp; 270 int i; 271 272 if (dl->d_magic != DISKMAGIC || dl->d_magic2 != DISKMAGIC) 273 return (EINVAL); 274 /* 275 * If the label specifies more partitions than we can handle 276 * we have to reject it: If people updated the label they would 277 * trash it, and that would break the checksum. 278 */ 279 if (dl->d_npartitions > MAXPARTITIONS) 280 return (EINVAL); 281 282 for (i = 0; i < dl->d_npartitions; i++) { 283 ppp = &dl->d_partitions[i]; 284 /* Cannot extend past unit. */ 285 if (ppp->p_size != 0 && 286 ppp->p_offset + ppp->p_size > dl->d_secperunit) { 287 return (EINVAL); 288 } 289 } 290 return (0); 291} 292 293/* 294 * Modify our slicer to match proposed disklabel, if possible. 295 * First carry out all the simple checks, then lock topology 296 * and check that no open providers are affected negatively 297 * then carry out all the changes. 298 * 299 * NB: Returns with topology held only if successful return. 300 */ 301static int 302g_bsd_modify(struct g_geom *gp, struct disklabel *dl) 303{ 304 int i, error; 305 struct partition *ppp; 306 struct g_slicer *gsp; 307 struct g_consumer *cp; 308 u_int secsize; 309 off_t mediasize; 310 311 /* Basic check that this is indeed a disklabel. */ 312 error = g_bsd_checklabel(dl); 313 if (error) 314 return (error); 315 316 /* Make sure the checksum is OK. */ 317 if (dkcksum(dl) != 0) 318 return (EINVAL); 319 320 /* Get dimensions of our device. */ 321 cp = LIST_FIRST(&gp->consumer);
| 36 * 37 * This is the method for dealing with BSD disklabels. It has been 38 * extensively (by my standards at least) commented, in the vain hope that 39 * it will server as the source in future copy&paste operations. 40 */ 41 42#include <sys/param.h> 43#ifndef _KERNEL 44#include <stdio.h> 45#include <string.h> 46#include <stdlib.h> 47#include <signal.h> 48#include <err.h> 49#else 50#include <sys/systm.h> 51#include <sys/kernel.h> 52#include <sys/conf.h> 53#include <sys/bio.h> 54#include <sys/malloc.h> 55#include <sys/lock.h> 56#include <sys/mutex.h> 57#endif 58#include <sys/stdint.h> 59#include <sys/errno.h> 60#include <sys/disklabel.h> 61#include <geom/geom.h> 62#include <geom/geom_slice.h> 63 64#define BSD_CLASS_NAME "BSD" 65 66/* 67 * Our private data about one instance. All the rest is handled by the 68 * slice code and stored in its softc, so this is just the stuff 69 * specific to BSD disklabels. 70 */ 71struct g_bsd_softc { 72 off_t labeloffset; 73 off_t rawoffset; 74 struct disklabel ondisk; 75 struct disklabel inram; 76}; 77 78/* 79 * The next 4 functions isolate us from how the compiler lays out and pads 80 * "struct disklabel". We treat what we read from disk as a bytestream and 81 * explicitly convert it into a struct disklabel. This makes us compiler- 82 * endianness- and wordsize- agnostic. 83 * For now we only have little-endian formats to deal with. 84 */ 85 86static void 87g_bsd_ledec_partition(u_char *ptr, struct partition *d) 88{ 89 d->p_size = g_dec_le4(ptr + 0); 90 d->p_offset = g_dec_le4(ptr + 4); 91 d->p_fsize = g_dec_le4(ptr + 8); 92 d->p_fstype = ptr[12]; 93 d->p_frag = ptr[13]; 94 d->p_cpg = g_dec_le2(ptr + 14); 95} 96 97static void 98g_bsd_ledec_disklabel(u_char *ptr, struct disklabel *d) 99{ 100 int i; 101 102 d->d_magic = g_dec_le4(ptr + 0); 103 d->d_type = g_dec_le2(ptr + 4); 104 d->d_subtype = g_dec_le2(ptr + 6); 105 bcopy(ptr + 8, d->d_typename, 16); 106 bcopy(ptr + 24, d->d_packname, 16); 107 d->d_secsize = g_dec_le4(ptr + 40); 108 d->d_nsectors = g_dec_le4(ptr + 44); 109 d->d_ntracks = g_dec_le4(ptr + 48); 110 d->d_ncylinders = g_dec_le4(ptr + 52); 111 d->d_secpercyl = g_dec_le4(ptr + 56); 112 d->d_secperunit = g_dec_le4(ptr + 60); 113 d->d_sparespertrack = g_dec_le2(ptr + 64); 114 d->d_sparespercyl = g_dec_le2(ptr + 66); 115 d->d_acylinders = g_dec_le4(ptr + 68); 116 d->d_rpm = g_dec_le2(ptr + 72); 117 d->d_interleave = g_dec_le2(ptr + 74); 118 d->d_trackskew = g_dec_le2(ptr + 76); 119 d->d_cylskew = g_dec_le2(ptr + 78); 120 d->d_headswitch = g_dec_le4(ptr + 80); 121 d->d_trkseek = g_dec_le4(ptr + 84); 122 d->d_flags = g_dec_le4(ptr + 88); 123 d->d_drivedata[0] = g_dec_le4(ptr + 92); 124 d->d_drivedata[1] = g_dec_le4(ptr + 96); 125 d->d_drivedata[2] = g_dec_le4(ptr + 100); 126 d->d_drivedata[3] = g_dec_le4(ptr + 104); 127 d->d_drivedata[4] = g_dec_le4(ptr + 108); 128 d->d_spare[0] = g_dec_le4(ptr + 112); 129 d->d_spare[1] = g_dec_le4(ptr + 116); 130 d->d_spare[2] = g_dec_le4(ptr + 120); 131 d->d_spare[3] = g_dec_le4(ptr + 124); 132 d->d_spare[4] = g_dec_le4(ptr + 128); 133 d->d_magic2 = g_dec_le4(ptr + 132); 134 d->d_checksum = g_dec_le2(ptr + 136); 135 d->d_npartitions = g_dec_le2(ptr + 138); 136 d->d_bbsize = g_dec_le4(ptr + 140); 137 d->d_sbsize = g_dec_le4(ptr + 144); 138 for (i = 0; i < MAXPARTITIONS; i++) 139 g_bsd_ledec_partition(ptr + 148 + 16 * i, &d->d_partitions[i]); 140} 141 142static void 143g_bsd_leenc_partition(u_char *ptr, struct partition *d) 144{ 145 g_enc_le4(ptr + 0, d->p_size); 146 g_enc_le4(ptr + 4, d->p_offset); 147 g_enc_le4(ptr + 8, d->p_fsize); 148 ptr[12] = d->p_fstype; 149 ptr[13] = d->p_frag; 150 g_enc_le2(ptr + 14, d->p_cpg); 151} 152 153static void 154g_bsd_leenc_disklabel(u_char *ptr, struct disklabel *d) 155{ 156 int i; 157 158 g_enc_le4(ptr + 0, d->d_magic); 159 g_enc_le2(ptr + 4, d->d_type); 160 g_enc_le2(ptr + 6, d->d_subtype); 161 bcopy(d->d_typename, ptr + 8, 16); 162 bcopy(d->d_packname, ptr + 24, 16); 163 g_enc_le4(ptr + 40, d->d_secsize); 164 g_enc_le4(ptr + 44, d->d_nsectors); 165 g_enc_le4(ptr + 48, d->d_ntracks); 166 g_enc_le4(ptr + 52, d->d_ncylinders); 167 g_enc_le4(ptr + 56, d->d_secpercyl); 168 g_enc_le4(ptr + 60, d->d_secperunit); 169 g_enc_le2(ptr + 64, d->d_sparespertrack); 170 g_enc_le2(ptr + 66, d->d_sparespercyl); 171 g_enc_le4(ptr + 68, d->d_acylinders); 172 g_enc_le2(ptr + 72, d->d_rpm); 173 g_enc_le2(ptr + 74, d->d_interleave); 174 g_enc_le2(ptr + 76, d->d_trackskew); 175 g_enc_le2(ptr + 78, d->d_cylskew); 176 g_enc_le4(ptr + 80, d->d_headswitch); 177 g_enc_le4(ptr + 84, d->d_trkseek); 178 g_enc_le4(ptr + 88, d->d_flags); 179 g_enc_le4(ptr + 92, d->d_drivedata[0]); 180 g_enc_le4(ptr + 96, d->d_drivedata[1]); 181 g_enc_le4(ptr + 100, d->d_drivedata[2]); 182 g_enc_le4(ptr + 104, d->d_drivedata[3]); 183 g_enc_le4(ptr + 108, d->d_drivedata[4]); 184 g_enc_le4(ptr + 112, d->d_spare[0]); 185 g_enc_le4(ptr + 116, d->d_spare[1]); 186 g_enc_le4(ptr + 120, d->d_spare[2]); 187 g_enc_le4(ptr + 124, d->d_spare[3]); 188 g_enc_le4(ptr + 128, d->d_spare[4]); 189 g_enc_le4(ptr + 132, d->d_magic2); 190 g_enc_le2(ptr + 136, d->d_checksum); 191 g_enc_le2(ptr + 138, d->d_npartitions); 192 g_enc_le4(ptr + 140, d->d_bbsize); 193 g_enc_le4(ptr + 144, d->d_sbsize); 194 for (i = 0; i < MAXPARTITIONS; i++) 195 g_bsd_leenc_partition(ptr + 148 + 16 * i, &d->d_partitions[i]); 196} 197 198/* 199 * For reasons which were valid and just in their days, FreeBSD/i386 uses 200 * absolute disk-addresses in disklabels. The way it works is that the 201 * p_offset field of all partitions have the first sector number of the 202 * disk slice added to them. This was hidden kernel-magic, userland did 203 * not see these offsets. These two functions subtract and add them 204 * while converting from the "ondisk" to the "inram" labels and vice 205 * versa. 206 */ 207static void 208ondisk2inram(struct g_bsd_softc *sc) 209{ 210 struct partition *ppp; 211 struct disklabel *dl; 212 int i; 213 214 sc->inram = sc->ondisk; 215 dl = &sc->inram; 216 217 /* Basic sanity-check needed to avoid mistakes. */ 218 if (dl->d_magic != DISKMAGIC || dl->d_magic2 != DISKMAGIC) 219 return; 220 if (dl->d_npartitions > MAXPARTITIONS) 221 return; 222 223 sc->rawoffset = dl->d_partitions[RAW_PART].p_offset; 224 for (i = 0; i < dl->d_npartitions; i++) { 225 ppp = &dl->d_partitions[i]; 226 if (ppp->p_size != 0 && ppp->p_offset < sc->rawoffset) 227 sc->rawoffset = 0; 228 } 229 if (sc->rawoffset > 0) { 230 231 if (dl->d_partitions[RAW_PART].p_size + 232 sc->rawoffset == dl->d_secperunit) { 233 } 234 for (i = 0; i < dl->d_npartitions; i++) { 235 ppp = &dl->d_partitions[i]; 236 ppp->p_offset -= sc->rawoffset; 237 } 238 } 239 dl->d_checksum = 0; 240 dl->d_checksum = dkcksum(&sc->inram); 241} 242 243static void 244inram2ondisk(struct g_bsd_softc *sc) 245{ 246 struct partition *ppp; 247 int i; 248 249 sc->ondisk = sc->inram; 250 if (sc->rawoffset != 0) { 251 for (i = 0; i < sc->inram.d_npartitions; i++) { 252 ppp = &sc->ondisk.d_partitions[i]; 253 ppp->p_offset += sc->rawoffset; 254 } 255 } 256 sc->ondisk.d_checksum = 0; 257 sc->ondisk.d_checksum = dkcksum(&sc->ondisk); 258} 259 260/* 261 * Check that this looks like a valid disklabel, but be prepared 262 * to get any kind of junk. The checksum must be checked only 263 * after this function returns success to prevent a bogus d_npartitions 264 * value from tripping us up. 265 */ 266static int 267g_bsd_checklabel(struct disklabel *dl) 268{ 269 struct partition *ppp; 270 int i; 271 272 if (dl->d_magic != DISKMAGIC || dl->d_magic2 != DISKMAGIC) 273 return (EINVAL); 274 /* 275 * If the label specifies more partitions than we can handle 276 * we have to reject it: If people updated the label they would 277 * trash it, and that would break the checksum. 278 */ 279 if (dl->d_npartitions > MAXPARTITIONS) 280 return (EINVAL); 281 282 for (i = 0; i < dl->d_npartitions; i++) { 283 ppp = &dl->d_partitions[i]; 284 /* Cannot extend past unit. */ 285 if (ppp->p_size != 0 && 286 ppp->p_offset + ppp->p_size > dl->d_secperunit) { 287 return (EINVAL); 288 } 289 } 290 return (0); 291} 292 293/* 294 * Modify our slicer to match proposed disklabel, if possible. 295 * First carry out all the simple checks, then lock topology 296 * and check that no open providers are affected negatively 297 * then carry out all the changes. 298 * 299 * NB: Returns with topology held only if successful return. 300 */ 301static int 302g_bsd_modify(struct g_geom *gp, struct disklabel *dl) 303{ 304 int i, error; 305 struct partition *ppp; 306 struct g_slicer *gsp; 307 struct g_consumer *cp; 308 u_int secsize; 309 off_t mediasize; 310 311 /* Basic check that this is indeed a disklabel. */ 312 error = g_bsd_checklabel(dl); 313 if (error) 314 return (error); 315 316 /* Make sure the checksum is OK. */ 317 if (dkcksum(dl) != 0) 318 return (EINVAL); 319 320 /* Get dimensions of our device. */ 321 cp = LIST_FIRST(&gp->consumer);
|
322 error = g_getattr("GEOM::sectorsize", cp, &secsize); 323 if (error) 324 return (error); 325 error = g_getattr("GEOM::mediasize", cp, &mediasize); 326 if (error) 327 return (error);
| 322 secsize = cp->provider->sectorsize; 323 mediasize = cp->provider->mediasize;
|
328 329#ifdef nolonger 330 /* 331 * The raw-partition must start at zero. We do not check that the 332 * size == mediasize because this is overly restrictive. We have 333 * already tested in g_bsd_checklabel() that it is not longer. 334 * XXX: RAW_PART is archaic anyway, and we should drop it. 335 */ 336 if (dl->d_partitions[RAW_PART].p_offset != 0) 337 return (EINVAL); 338#endif 339 340#ifdef notyet 341 /* 342 * Indications are that the d_secperunit is not correctly 343 * initialized in many cases, and since we don't need it 344 * for anything, we dont strictly need this test. 345 * Preemptive action to avoid confusing people in disklabel(8) 346 * may be in order. 347 */ 348 /* The label cannot claim a larger size than the media. */ 349 if ((off_t)dl->d_secperunit * dl->d_secsize > mediasize) 350 return (EINVAL); 351#endif 352 353 354 /* ... or a smaller sector size. */ 355 if (dl->d_secsize < secsize) 356 return (EINVAL); 357 358 /* ... or a non-multiple sector size. */ 359 if (dl->d_secsize % secsize != 0) 360 return (EINVAL); 361 362 g_topology_lock(); 363 364 /* Don't munge open partitions. */ 365 gsp = gp->softc; 366 for (i = 0; i < dl->d_npartitions; i++) { 367 ppp = &dl->d_partitions[i]; 368 369 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 370 (off_t)ppp->p_offset * dl->d_secsize, 371 (off_t)ppp->p_size * dl->d_secsize, 372 dl->d_secsize, 373 "%s%c", gp->name, 'a' + i); 374 if (error) { 375 g_topology_unlock(); 376 return (error); 377 } 378 } 379 380 /* Look good, go for it... */ 381 for (i = 0; i < gsp->nslice; i++) { 382 ppp = &dl->d_partitions[i]; 383 g_slice_config(gp, i, G_SLICE_CONFIG_SET, 384 (off_t)ppp->p_offset * dl->d_secsize, 385 (off_t)ppp->p_size * dl->d_secsize, 386 dl->d_secsize, 387 "%s%c", gp->name, 'a' + i); 388 } 389 return (0); 390} 391 392/* 393 * Calculate a disklabel checksum for a little-endian byte-stream. 394 * We need access to the decoded disklabel because the checksum only 395 * covers the partition data for the first d_npartitions. 396 */ 397static int 398g_bsd_lesum(struct disklabel *dl, u_char *p) 399{ 400 u_char *pe; 401 uint16_t sum; 402 403 pe = p + 148 + 16 * dl->d_npartitions; 404 sum = 0; 405 while (p < pe) { 406 sum ^= g_dec_le2(p); 407 p += 2; 408 } 409 return (sum); 410} 411 412/* 413 * This is an internal helper function, called multiple times from the taste 414 * function to try to locate a disklabel on the disk. More civilized formats 415 * will not need this, as there is only one possible place on disk to look 416 * for the magic spot. 417 */ 418 419static int 420g_bsd_try(struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset) 421{ 422 int error; 423 u_char *buf; 424 struct disklabel *dl; 425 off_t secoff; 426 427 /* 428 * We need to read entire aligned sectors, and we assume that the 429 * disklabel does not span sectors, so one sector is enough. 430 */ 431 error = 0; 432 secoff = offset % secsize; 433 buf = g_read_data(cp, offset - secoff, secsize, &error); 434 if (buf == NULL || error != 0) 435 return (ENOENT); 436 437 /* Decode into our native format. */ 438 dl = &ms->ondisk; 439 g_bsd_ledec_disklabel(buf + secoff, dl); 440 441 ondisk2inram(ms); 442 443 dl = &ms->inram; 444 /* Does it look like a label at all? */ 445 if (g_bsd_checklabel(dl)) 446 error = ENOENT; 447 /* ... and does the raw data have a good checksum? */ 448 if (error == 0 && g_bsd_lesum(dl, buf + secoff) != 0) 449 error = ENOENT; 450 451 /* Remember to free the buffer g_read_data() gave us. */ 452 g_free(buf); 453 454 /* If we had a label, record it properly. */ 455 if (error == 0) { 456 gsp->frontstuff = 16 * secsize; /* XXX */ 457 ms->labeloffset = offset; 458 } 459 return (error); 460} 461 462/* 463 * Implement certain ioctls to modify disklabels with. This function 464 * is called by the event handler thread with topology locked as result 465 * of the g_call_me() in g_bsd_start(). It is not necessary to keep 466 * topology locked all the time but make sure to return with topology 467 * locked as well. 468 */ 469 470static void 471g_bsd_ioctl(void *arg) 472{ 473 struct bio *bp; 474 struct g_geom *gp; 475 struct g_slicer *gsp; 476 struct g_bsd_softc *ms; 477 struct disklabel *dl; 478 struct g_ioctl *gio; 479 struct g_consumer *cp; 480 u_char *buf; 481 off_t secoff; 482 u_int secsize; 483 int error; 484 485 /* We don't need topology for now. */ 486 g_topology_unlock(); 487 488 /* Get hold of the interesting bits from the bio. */ 489 bp = arg; 490 gp = bp->bio_to->geom; 491 gsp = gp->softc; 492 ms = gsp->softc; 493 gio = (struct g_ioctl *)bp->bio_data; 494 495 /* The disklabel to set is the ioctl argument. */ 496 dl = gio->data; 497 498 /* Validate and modify our slice instance to match. */ 499 error = g_bsd_modify(gp, dl); /* Picks up topology lock on success. */ 500 if (error) { 501 g_topology_lock(); 502 g_io_deliver(bp, error); 503 return; 504 } 505 /* Update our copy of the disklabel. */ 506 ms->inram = *dl; 507 inram2ondisk(ms); 508 509 if (gio->cmd == DIOCSDINFO) { 510 g_io_deliver(bp, 0); 511 return; 512 } 513 KASSERT(gio->cmd == DIOCWDINFO, ("Unknown ioctl in g_bsd_ioctl")); 514 cp = LIST_FIRST(&gp->consumer); 515 /* Get sector size, we need it to read data. */
| 324 325#ifdef nolonger 326 /* 327 * The raw-partition must start at zero. We do not check that the 328 * size == mediasize because this is overly restrictive. We have 329 * already tested in g_bsd_checklabel() that it is not longer. 330 * XXX: RAW_PART is archaic anyway, and we should drop it. 331 */ 332 if (dl->d_partitions[RAW_PART].p_offset != 0) 333 return (EINVAL); 334#endif 335 336#ifdef notyet 337 /* 338 * Indications are that the d_secperunit is not correctly 339 * initialized in many cases, and since we don't need it 340 * for anything, we dont strictly need this test. 341 * Preemptive action to avoid confusing people in disklabel(8) 342 * may be in order. 343 */ 344 /* The label cannot claim a larger size than the media. */ 345 if ((off_t)dl->d_secperunit * dl->d_secsize > mediasize) 346 return (EINVAL); 347#endif 348 349 350 /* ... or a smaller sector size. */ 351 if (dl->d_secsize < secsize) 352 return (EINVAL); 353 354 /* ... or a non-multiple sector size. */ 355 if (dl->d_secsize % secsize != 0) 356 return (EINVAL); 357 358 g_topology_lock(); 359 360 /* Don't munge open partitions. */ 361 gsp = gp->softc; 362 for (i = 0; i < dl->d_npartitions; i++) { 363 ppp = &dl->d_partitions[i]; 364 365 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 366 (off_t)ppp->p_offset * dl->d_secsize, 367 (off_t)ppp->p_size * dl->d_secsize, 368 dl->d_secsize, 369 "%s%c", gp->name, 'a' + i); 370 if (error) { 371 g_topology_unlock(); 372 return (error); 373 } 374 } 375 376 /* Look good, go for it... */ 377 for (i = 0; i < gsp->nslice; i++) { 378 ppp = &dl->d_partitions[i]; 379 g_slice_config(gp, i, G_SLICE_CONFIG_SET, 380 (off_t)ppp->p_offset * dl->d_secsize, 381 (off_t)ppp->p_size * dl->d_secsize, 382 dl->d_secsize, 383 "%s%c", gp->name, 'a' + i); 384 } 385 return (0); 386} 387 388/* 389 * Calculate a disklabel checksum for a little-endian byte-stream. 390 * We need access to the decoded disklabel because the checksum only 391 * covers the partition data for the first d_npartitions. 392 */ 393static int 394g_bsd_lesum(struct disklabel *dl, u_char *p) 395{ 396 u_char *pe; 397 uint16_t sum; 398 399 pe = p + 148 + 16 * dl->d_npartitions; 400 sum = 0; 401 while (p < pe) { 402 sum ^= g_dec_le2(p); 403 p += 2; 404 } 405 return (sum); 406} 407 408/* 409 * This is an internal helper function, called multiple times from the taste 410 * function to try to locate a disklabel on the disk. More civilized formats 411 * will not need this, as there is only one possible place on disk to look 412 * for the magic spot. 413 */ 414 415static int 416g_bsd_try(struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset) 417{ 418 int error; 419 u_char *buf; 420 struct disklabel *dl; 421 off_t secoff; 422 423 /* 424 * We need to read entire aligned sectors, and we assume that the 425 * disklabel does not span sectors, so one sector is enough. 426 */ 427 error = 0; 428 secoff = offset % secsize; 429 buf = g_read_data(cp, offset - secoff, secsize, &error); 430 if (buf == NULL || error != 0) 431 return (ENOENT); 432 433 /* Decode into our native format. */ 434 dl = &ms->ondisk; 435 g_bsd_ledec_disklabel(buf + secoff, dl); 436 437 ondisk2inram(ms); 438 439 dl = &ms->inram; 440 /* Does it look like a label at all? */ 441 if (g_bsd_checklabel(dl)) 442 error = ENOENT; 443 /* ... and does the raw data have a good checksum? */ 444 if (error == 0 && g_bsd_lesum(dl, buf + secoff) != 0) 445 error = ENOENT; 446 447 /* Remember to free the buffer g_read_data() gave us. */ 448 g_free(buf); 449 450 /* If we had a label, record it properly. */ 451 if (error == 0) { 452 gsp->frontstuff = 16 * secsize; /* XXX */ 453 ms->labeloffset = offset; 454 } 455 return (error); 456} 457 458/* 459 * Implement certain ioctls to modify disklabels with. This function 460 * is called by the event handler thread with topology locked as result 461 * of the g_call_me() in g_bsd_start(). It is not necessary to keep 462 * topology locked all the time but make sure to return with topology 463 * locked as well. 464 */ 465 466static void 467g_bsd_ioctl(void *arg) 468{ 469 struct bio *bp; 470 struct g_geom *gp; 471 struct g_slicer *gsp; 472 struct g_bsd_softc *ms; 473 struct disklabel *dl; 474 struct g_ioctl *gio; 475 struct g_consumer *cp; 476 u_char *buf; 477 off_t secoff; 478 u_int secsize; 479 int error; 480 481 /* We don't need topology for now. */ 482 g_topology_unlock(); 483 484 /* Get hold of the interesting bits from the bio. */ 485 bp = arg; 486 gp = bp->bio_to->geom; 487 gsp = gp->softc; 488 ms = gsp->softc; 489 gio = (struct g_ioctl *)bp->bio_data; 490 491 /* The disklabel to set is the ioctl argument. */ 492 dl = gio->data; 493 494 /* Validate and modify our slice instance to match. */ 495 error = g_bsd_modify(gp, dl); /* Picks up topology lock on success. */ 496 if (error) { 497 g_topology_lock(); 498 g_io_deliver(bp, error); 499 return; 500 } 501 /* Update our copy of the disklabel. */ 502 ms->inram = *dl; 503 inram2ondisk(ms); 504 505 if (gio->cmd == DIOCSDINFO) { 506 g_io_deliver(bp, 0); 507 return; 508 } 509 KASSERT(gio->cmd == DIOCWDINFO, ("Unknown ioctl in g_bsd_ioctl")); 510 cp = LIST_FIRST(&gp->consumer); 511 /* Get sector size, we need it to read data. */
|
516 error = g_getattr("GEOM::sectorsize", cp, &secsize); 517 if (error || secsize < 512) { 518 g_io_deliver(bp, error); 519 return; 520 }
| 512 secsize = cp->provider->sectorsize;
|
521 secoff = ms->labeloffset % secsize; 522 buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error); 523 if (buf == NULL || error != 0) { 524 g_io_deliver(bp, error); 525 return; 526 } 527 dl = &ms->ondisk; 528 g_bsd_leenc_disklabel(buf + secoff, dl); 529 error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize); 530 g_free(buf); 531 g_io_deliver(bp, error); 532} 533 534/*- 535 * This start routine is only called for non-trivial requests, all the 536 * trivial ones are handled autonomously by the slice code. 537 * For requests we handle here, we must call the g_io_deliver() on the 538 * bio, and return non-zero to indicate to the slice code that we did so. 539 * This code executes in the "DOWN" I/O path, this means: 540 * * No sleeping. 541 * * Don't grab the topology lock. 542 * * Don't call biowait, g_getattr(), g_setattr() or g_read_data() 543 */ 544 545static int 546g_bsd_start(struct bio *bp) 547{ 548 struct g_geom *gp; 549 struct g_bsd_softc *ms; 550 struct g_slicer *gsp; 551 struct g_ioctl *gio; 552 int error; 553 554 gp = bp->bio_to->geom; 555 gsp = gp->softc; 556 ms = gsp->softc; 557 558 /* We only handle ioctl(2) requests of the right format. */ 559 if (strcmp(bp->bio_attribute, "GEOM::ioctl")) 560 return (0); 561 else if (bp->bio_length != sizeof(*gio)) 562 return (0); 563 564 /* Get hold of the ioctl parameters. */ 565 gio = (struct g_ioctl *)bp->bio_data; 566 567 switch (gio->cmd) { 568 case DIOCGDINFO: 569 /* Return a copy of the disklabel to userland. */ 570 bcopy(&ms->inram, gio->data, sizeof(ms->inram)); 571 g_io_deliver(bp, 0); 572 return (1); 573 case DIOCSDINFO: 574 case DIOCWDINFO: 575 /* 576 * These we cannot do without the topology lock and some 577 * some I/O requests. Ask the event-handler to schedule 578 * us in a less restricted environment. 579 */ 580 error = g_call_me(g_bsd_ioctl, bp); 581 if (error) 582 g_io_deliver(bp, error); 583 /* 584 * We must return non-zero to indicate that we will deal 585 * with this bio, even though we have not done so yet. 586 */ 587 return (1); 588 default: 589 return (0); 590 } 591} 592 593/* 594 * Dump configuration information in XML format. 595 * Notice that the function is called once for the geom and once for each 596 * consumer and provider. We let g_slice_dumpconf() do most of the work. 597 */ 598static void 599g_bsd_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp) 600{ 601 struct g_bsd_softc *ms; 602 struct g_slicer *gsp; 603 604 gsp = gp->softc; 605 ms = gsp->softc; 606 if (pp == NULL && cp == NULL) { 607 sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n", 608 indent, (intmax_t)ms->labeloffset); 609 } 610 g_slice_dumpconf(sb, indent, gp, cp, pp); 611} 612 613/* 614 * The taste function is called from the event-handler, with the topology 615 * lock already held and a provider to examine. The flags are unused. 616 * 617 * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and 618 * if we find valid, consistent magic on it, build a geom on it. 619 * any magic bits which indicate that we should automatically put a BSD 620 * geom on it. 621 * 622 * There may be cases where the operator would like to put a BSD-geom on 623 * providers which do not meet all of the requirements. This can be done 624 * by instead passing the G_TF_INSIST flag, which will override these 625 * checks. 626 * 627 * The final flags value is G_TF_TRANSPARENT, which instructs the method 628 * to put a geom on top of the provider and configure it to be as transparent 629 * as possible. This is not really relevant to the BSD method and therefore 630 * not implemented here. 631 */ 632 633static struct g_geom * 634g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) 635{ 636 struct g_geom *gp; 637 struct g_consumer *cp; 638 int error, i; 639 struct g_bsd_softc *ms; 640 struct disklabel *dl; 641 u_int secsize; 642 struct g_slicer *gsp; 643 644 g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name); 645 g_topology_assert(); 646 647 /* We don't implement transparent inserts. */ 648 if (flags == G_TF_TRANSPARENT) 649 return (NULL); 650 651 /* 652 * The BSD-method will not automatically configure itself recursively 653 * Note that it is legal to examine the class-name of our provider, 654 * nothing else should ever be examined inside the provider. 655 */ 656 if (flags == G_TF_NORMAL && 657 !strcmp(pp->geom->class->name, BSD_CLASS_NAME)) 658 return (NULL); 659 660 /* 661 * BSD labels are a subclass of the general "slicing" topology so 662 * a lot of the work can be done by the common "slice" code. 663 * Create a geom with space for MAXPARTITIONS providers, one consumer 664 * and a softc structure for us. Specify the provider to attach 665 * the consumer to and our "start" routine for special requests. 666 * The provider is opened with mode (1,0,0) so we can do reads 667 * from it. 668 */ 669 gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms, 670 sizeof(*ms), g_bsd_start); 671 if (gp == NULL) 672 return (NULL); 673 674 /* 675 * Now that we have attached to and opened our provider, we do 676 * not need the topology lock until we change the topology again 677 * next time. 678 */ 679 g_topology_unlock(); 680 681 /* 682 * Fill in the optional details, in our case we have a dumpconf 683 * routine which the "slice" code should call at the right time 684 */ 685 gp->dumpconf = g_bsd_dumpconf; 686 687 /* Get the geom_slicer softc from the geom. */ 688 gsp = gp->softc; 689 690 /* 691 * The do...while loop here allows us to have multiple escapes 692 * using a simple "break". This improves code clarity without 693 * ending up in deep nesting and without using goto or come from. 694 */ 695 do { 696 /* 697 * If the provider is an MBR we will only auto attach 698 * to type 165 slices in the G_TF_NORMAL case. We will 699 * attach to any other type (BSD was handles above) 700 */ 701 error = g_getattr("MBR::type", cp, &i); 702 if (!error && i != 165 && flags == G_TF_NORMAL) 703 break; 704 705 /* Get sector size, we need it to read data. */
| 513 secoff = ms->labeloffset % secsize; 514 buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error); 515 if (buf == NULL || error != 0) { 516 g_io_deliver(bp, error); 517 return; 518 } 519 dl = &ms->ondisk; 520 g_bsd_leenc_disklabel(buf + secoff, dl); 521 error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize); 522 g_free(buf); 523 g_io_deliver(bp, error); 524} 525 526/*- 527 * This start routine is only called for non-trivial requests, all the 528 * trivial ones are handled autonomously by the slice code. 529 * For requests we handle here, we must call the g_io_deliver() on the 530 * bio, and return non-zero to indicate to the slice code that we did so. 531 * This code executes in the "DOWN" I/O path, this means: 532 * * No sleeping. 533 * * Don't grab the topology lock. 534 * * Don't call biowait, g_getattr(), g_setattr() or g_read_data() 535 */ 536 537static int 538g_bsd_start(struct bio *bp) 539{ 540 struct g_geom *gp; 541 struct g_bsd_softc *ms; 542 struct g_slicer *gsp; 543 struct g_ioctl *gio; 544 int error; 545 546 gp = bp->bio_to->geom; 547 gsp = gp->softc; 548 ms = gsp->softc; 549 550 /* We only handle ioctl(2) requests of the right format. */ 551 if (strcmp(bp->bio_attribute, "GEOM::ioctl")) 552 return (0); 553 else if (bp->bio_length != sizeof(*gio)) 554 return (0); 555 556 /* Get hold of the ioctl parameters. */ 557 gio = (struct g_ioctl *)bp->bio_data; 558 559 switch (gio->cmd) { 560 case DIOCGDINFO: 561 /* Return a copy of the disklabel to userland. */ 562 bcopy(&ms->inram, gio->data, sizeof(ms->inram)); 563 g_io_deliver(bp, 0); 564 return (1); 565 case DIOCSDINFO: 566 case DIOCWDINFO: 567 /* 568 * These we cannot do without the topology lock and some 569 * some I/O requests. Ask the event-handler to schedule 570 * us in a less restricted environment. 571 */ 572 error = g_call_me(g_bsd_ioctl, bp); 573 if (error) 574 g_io_deliver(bp, error); 575 /* 576 * We must return non-zero to indicate that we will deal 577 * with this bio, even though we have not done so yet. 578 */ 579 return (1); 580 default: 581 return (0); 582 } 583} 584 585/* 586 * Dump configuration information in XML format. 587 * Notice that the function is called once for the geom and once for each 588 * consumer and provider. We let g_slice_dumpconf() do most of the work. 589 */ 590static void 591g_bsd_dumpconf(struct sbuf *sb, char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp) 592{ 593 struct g_bsd_softc *ms; 594 struct g_slicer *gsp; 595 596 gsp = gp->softc; 597 ms = gsp->softc; 598 if (pp == NULL && cp == NULL) { 599 sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n", 600 indent, (intmax_t)ms->labeloffset); 601 } 602 g_slice_dumpconf(sb, indent, gp, cp, pp); 603} 604 605/* 606 * The taste function is called from the event-handler, with the topology 607 * lock already held and a provider to examine. The flags are unused. 608 * 609 * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and 610 * if we find valid, consistent magic on it, build a geom on it. 611 * any magic bits which indicate that we should automatically put a BSD 612 * geom on it. 613 * 614 * There may be cases where the operator would like to put a BSD-geom on 615 * providers which do not meet all of the requirements. This can be done 616 * by instead passing the G_TF_INSIST flag, which will override these 617 * checks. 618 * 619 * The final flags value is G_TF_TRANSPARENT, which instructs the method 620 * to put a geom on top of the provider and configure it to be as transparent 621 * as possible. This is not really relevant to the BSD method and therefore 622 * not implemented here. 623 */ 624 625static struct g_geom * 626g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) 627{ 628 struct g_geom *gp; 629 struct g_consumer *cp; 630 int error, i; 631 struct g_bsd_softc *ms; 632 struct disklabel *dl; 633 u_int secsize; 634 struct g_slicer *gsp; 635 636 g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name); 637 g_topology_assert(); 638 639 /* We don't implement transparent inserts. */ 640 if (flags == G_TF_TRANSPARENT) 641 return (NULL); 642 643 /* 644 * The BSD-method will not automatically configure itself recursively 645 * Note that it is legal to examine the class-name of our provider, 646 * nothing else should ever be examined inside the provider. 647 */ 648 if (flags == G_TF_NORMAL && 649 !strcmp(pp->geom->class->name, BSD_CLASS_NAME)) 650 return (NULL); 651 652 /* 653 * BSD labels are a subclass of the general "slicing" topology so 654 * a lot of the work can be done by the common "slice" code. 655 * Create a geom with space for MAXPARTITIONS providers, one consumer 656 * and a softc structure for us. Specify the provider to attach 657 * the consumer to and our "start" routine for special requests. 658 * The provider is opened with mode (1,0,0) so we can do reads 659 * from it. 660 */ 661 gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms, 662 sizeof(*ms), g_bsd_start); 663 if (gp == NULL) 664 return (NULL); 665 666 /* 667 * Now that we have attached to and opened our provider, we do 668 * not need the topology lock until we change the topology again 669 * next time. 670 */ 671 g_topology_unlock(); 672 673 /* 674 * Fill in the optional details, in our case we have a dumpconf 675 * routine which the "slice" code should call at the right time 676 */ 677 gp->dumpconf = g_bsd_dumpconf; 678 679 /* Get the geom_slicer softc from the geom. */ 680 gsp = gp->softc; 681 682 /* 683 * The do...while loop here allows us to have multiple escapes 684 * using a simple "break". This improves code clarity without 685 * ending up in deep nesting and without using goto or come from. 686 */ 687 do { 688 /* 689 * If the provider is an MBR we will only auto attach 690 * to type 165 slices in the G_TF_NORMAL case. We will 691 * attach to any other type (BSD was handles above) 692 */ 693 error = g_getattr("MBR::type", cp, &i); 694 if (!error && i != 165 && flags == G_TF_NORMAL) 695 break; 696 697 /* Get sector size, we need it to read data. */
|
706 error = g_getattr("GEOM::sectorsize", cp, &secsize); 707 if (error || secsize < 512)
| 698 secsize = cp->provider->sectorsize; 699 if (secsize < 512)
|
708 break; 709 710 /* First look for a label at the start of the second sector. */ 711 error = g_bsd_try(gsp, cp, secsize, ms, secsize); 712 713 /* Next, look for it 64 bytes into the first sector. */ 714 if (error) 715 error = g_bsd_try(gsp, cp, secsize, ms, 64); 716 717 /* If we didn't find a label, punt. */ 718 if (error) 719 break; 720 721 /* 722 * Process the found disklabel, and modify our "slice" 723 * instance to match it, if possible. 724 */ 725 dl = &ms->inram; 726 error = g_bsd_modify(gp, dl); /* Picks up topology lock. */ 727 if (!error) 728 g_topology_unlock(); 729 break; 730 } while (0); 731 732 /* Success of failure, we can close our provider now. */ 733 g_topology_lock(); 734 error = g_access_rel(cp, -1, 0, 0); 735 736 /* If we have configured any providers, return the new geom. */ 737 if (gsp->nprovider > 0) 738 return (gp); 739 /* 740 * ...else push the "self-destruct" button, by spoiling our own 741 * consumer. This triggers a call to g_std_spoiled which will 742 * dismantle what was setup. 743 */ 744 g_std_spoiled(cp); 745 return (NULL); 746} 747 748/* Finally, register with GEOM infrastructure. */ 749static struct g_class g_bsd_class = { 750 BSD_CLASS_NAME, 751 g_bsd_taste, 752 NULL, 753 G_CLASS_INITIALIZER 754}; 755 756DECLARE_GEOM_CLASS(g_bsd_class, g_bsd);
| 700 break; 701 702 /* First look for a label at the start of the second sector. */ 703 error = g_bsd_try(gsp, cp, secsize, ms, secsize); 704 705 /* Next, look for it 64 bytes into the first sector. */ 706 if (error) 707 error = g_bsd_try(gsp, cp, secsize, ms, 64); 708 709 /* If we didn't find a label, punt. */ 710 if (error) 711 break; 712 713 /* 714 * Process the found disklabel, and modify our "slice" 715 * instance to match it, if possible. 716 */ 717 dl = &ms->inram; 718 error = g_bsd_modify(gp, dl); /* Picks up topology lock. */ 719 if (!error) 720 g_topology_unlock(); 721 break; 722 } while (0); 723 724 /* Success of failure, we can close our provider now. */ 725 g_topology_lock(); 726 error = g_access_rel(cp, -1, 0, 0); 727 728 /* If we have configured any providers, return the new geom. */ 729 if (gsp->nprovider > 0) 730 return (gp); 731 /* 732 * ...else push the "self-destruct" button, by spoiling our own 733 * consumer. This triggers a call to g_std_spoiled which will 734 * dismantle what was setup. 735 */ 736 g_std_spoiled(cp); 737 return (NULL); 738} 739 740/* Finally, register with GEOM infrastructure. */ 741static struct g_class g_bsd_class = { 742 BSD_CLASS_NAME, 743 g_bsd_taste, 744 NULL, 745 G_CLASS_INITIALIZER 746}; 747 748DECLARE_GEOM_CLASS(g_bsd_class, g_bsd);
|