| Commit | Line | Data |
|---|---|---|
| ba0cc1ab MD |
1 | /* |
| 2 | * Copyright (c) 2003-2007 The DragonFly Project. All rights reserved. | |
| 3 | * | |
| 4 | * This code is derived from software contributed to The DragonFly Project | |
| 5 | * by Matthew Dillon <dillon@backplane.com> | |
| 6 | * | |
| 7 | * Redistribution and use in source and binary forms, with or without | |
| 8 | * modification, are permitted provided that the following conditions | |
| 9 | * are met: | |
| 10 | * | |
| 11 | * 1. Redistributions of source code must retain the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer in | |
| 15 | * the documentation and/or other materials provided with the | |
| 16 | * distribution. | |
| 17 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 18 | * contributors may be used to endorse or promote products derived | |
| 19 | * from this software without specific, prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 25 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 26 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 32 | * SUCH DAMAGE. | |
| 33 | * | |
| 34 | * ---------------------------------------------------------------------------- | |
| 35 | * "THE BEER-WARE LICENSE" (Revision 42): | |
| 36 | * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you | |
| 37 | * can do whatever you want with this stuff. If we meet some day, and you think | |
| 38 | * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp | |
| 39 | * ---------------------------------------------------------------------------- | |
| 40 | * | |
| 41 | * Copyright (c) 1982, 1986, 1988, 1993 | |
| 42 | * The Regents of the University of California. All rights reserved. | |
| 43 | * (c) UNIX System Laboratories, Inc. | |
| 44 | * All or some portions of this file are derived from material licensed | |
| 45 | * to the University of California by American Telephone and Telegraph | |
| 46 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
| 47 | * the permission of UNIX System Laboratories, Inc. | |
| 48 | * | |
| 49 | * Copyright (c) 1994 Bruce D. Evans. | |
| 50 | * All rights reserved. | |
| 51 | * | |
| 52 | * Copyright (c) 1990 The Regents of the University of California. | |
| 53 | * All rights reserved. | |
| 54 | * | |
| 55 | * This code is derived from software contributed to Berkeley by | |
| 56 | * William Jolitz. | |
| 57 | * | |
| 58 | * Copyright (c) 1982, 1986, 1988 Regents of the University of California. | |
| 59 | * All rights reserved. | |
| 60 | * | |
| 61 | * Redistribution and use in source and binary forms, with or without | |
| 62 | * modification, are permitted provided that the following conditions | |
| 63 | * are met: | |
| 64 | * 1. Redistributions of source code must retain the above copyright | |
| 65 | * notice, this list of conditions and the following disclaimer. | |
| 66 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 67 | * notice, this list of conditions and the following disclaimer in the | |
| 68 | * documentation and/or other materials provided with the distribution. | |
| 69 | * 3. All advertising materials mentioning features or use of this software | |
| 70 | * must display the following acknowledgement: | |
| 71 | * This product includes software developed by the University of | |
| 72 | * California, Berkeley and its contributors. | |
| 73 | * 4. Neither the name of the University nor the names of its contributors | |
| 74 | * may be used to endorse or promote products derived from this software | |
| 75 | * without specific prior written permission. | |
| 76 | * | |
| 77 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 78 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 79 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 80 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 81 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 82 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 83 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 84 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 85 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 86 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 87 | * SUCH DAMAGE. | |
| 88 | * | |
| 89 | * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 | |
| 90 | * $FreeBSD: src/sys/kern/subr_disk.c,v 1.20.2.6 2001/10/05 07:14:57 peter Exp $ | |
| 91 | * $FreeBSD: src/sys/ufs/ufs/ufs_disksubr.c,v 1.44.2.3 2001/03/05 05:42:19 obrien Exp $ | |
| 18cb7add | 92 | * $DragonFly: src/sys/kern/subr_disklabel32.c,v 1.4 2007/06/19 06:07:57 dillon Exp $ |
| ba0cc1ab MD |
93 | */ |
| 94 | ||
| 95 | #include <sys/param.h> | |
| 96 | #include <sys/systm.h> | |
| 97 | #include <sys/kernel.h> | |
| 98 | #include <sys/proc.h> | |
| 99 | #include <sys/sysctl.h> | |
| 100 | #include <sys/buf.h> | |
| 101 | #include <sys/conf.h> | |
| 102 | #include <sys/disklabel.h> | |
| 2b961883 | 103 | #include <sys/disklabel32.h> |
| ba0cc1ab MD |
104 | #include <sys/diskslice.h> |
| 105 | #include <sys/disk.h> | |
| 106 | #include <sys/dtype.h> /* DTYPE_* constants */ | |
| 107 | #include <sys/sysctl.h> | |
| 108 | #include <machine/md_var.h> | |
| 109 | #include <sys/ctype.h> | |
| 110 | #include <sys/syslog.h> | |
| 111 | #include <sys/device.h> | |
| 112 | #include <sys/msgport.h> | |
| 113 | #include <sys/msgport2.h> | |
| 114 | #include <sys/buf2.h> | |
| 115 | ||
| 116 | #include <vfs/ufs/dinode.h> /* XXX used only for fs.h */ | |
| 117 | #include <vfs/ufs/fs.h> /* XXX used only to get BBSIZE/SBSIZE */ | |
| 118 | ||
| 2b961883 | 119 | static void partition_info(const char *sname, int part, struct partition32 *pp); |
| ba0cc1ab | 120 | static void slice_info(const char *sname, struct diskslice *sp); |
| 2b961883 MD |
121 | static const char *l32_fixlabel(const char *sname, struct diskslice *sp, |
| 122 | disklabel_t lpx, int writeflag); | |
| ba0cc1ab MD |
123 | |
| 124 | /* | |
| 125 | * Retrieve the partition start and extent, in blocks. Return 0 on success, | |
| 126 | * EINVAL on error. | |
| 127 | */ | |
| 2b961883 | 128 | static int |
| 0ffe40b3 | 129 | l32_getpartbounds(struct diskslices *ssp, disklabel_t lp, u_int32_t part, |
| 2b961883 | 130 | u_int64_t *start, u_int64_t *blocks) |
| ba0cc1ab | 131 | { |
| 2b961883 | 132 | struct partition32 *pp; |
| ba0cc1ab | 133 | |
| 2b961883 | 134 | if (part >= lp.lab32->d_npartitions) |
| ba0cc1ab | 135 | return (EINVAL); |
| 2b961883 | 136 | pp = &lp.lab32->d_partitions[part]; |
| ba0cc1ab | 137 | *start = pp->p_offset; |
| 0ffe40b3 | 138 | *blocks = pp->p_size; |
| ba0cc1ab MD |
139 | return(0); |
| 140 | } | |
| 141 | ||
| 18cb7add MD |
142 | static void |
| 143 | l32_loadpartinfo(disklabel_t lp, u_int32_t part, struct partinfo *dpart) | |
| ba0cc1ab | 144 | { |
| 2b961883 | 145 | struct partition32 *pp; |
| 18cb7add | 146 | const size_t uuid_size = sizeof(struct uuid); |
| ba0cc1ab | 147 | |
| 18cb7add MD |
148 | bzero(&dpart->fstype_uuid, uuid_size); |
| 149 | bzero(&dpart->storage_uuid, uuid_size); | |
| 150 | if (part < lp.lab32->d_npartitions) { | |
| 151 | pp = &lp.lab32->d_partitions[part]; | |
| 152 | dpart->fstype = pp->p_fstype; | |
| 153 | } else { | |
| 154 | dpart->fstype = 0; | |
| 155 | } | |
| ba0cc1ab MD |
156 | } |
| 157 | ||
| 2b961883 MD |
158 | static u_int32_t |
| 159 | l32_getnumparts(disklabel_t lp) | |
| ba0cc1ab | 160 | { |
| 2b961883 | 161 | return(lp.lab32->d_npartitions); |
| ba0cc1ab MD |
162 | } |
| 163 | ||
| 164 | /* | |
| 0ffe40b3 MD |
165 | * Attempt to read a disk label from a device. |
| 166 | * | |
| 167 | * Returns NULL on sucess, and an error string on failure | |
| ba0cc1ab | 168 | */ |
| 2b961883 MD |
169 | static const char * |
| 170 | l32_readdisklabel(cdev_t dev, struct diskslice *sp, disklabel_t *lpp, | |
| 171 | struct disk_info *info) | |
| ba0cc1ab | 172 | { |
| 2b961883 | 173 | disklabel_t lpx; |
| ba0cc1ab | 174 | struct buf *bp; |
| 2b961883 MD |
175 | struct disklabel32 *dlp; |
| 176 | const char *msg = NULL; | |
| 177 | int secsize = info->d_media_blksize; | |
| ba0cc1ab | 178 | |
| 2b961883 MD |
179 | bp = geteblk(secsize); |
| 180 | bp->b_bio1.bio_offset = (off_t)LABELSECTOR32 * secsize; | |
| 181 | bp->b_bcount = secsize; | |
| ba0cc1ab MD |
182 | bp->b_flags &= ~B_INVAL; |
| 183 | bp->b_cmd = BUF_CMD_READ; | |
| 184 | dev_dstrategy(dev, &bp->b_bio1); | |
| 185 | if (biowait(bp)) | |
| 186 | msg = "I/O error"; | |
| 2b961883 MD |
187 | else for (dlp = (struct disklabel32 *)bp->b_data; |
| 188 | dlp <= (struct disklabel32 *)((char *)bp->b_data + | |
| 189 | secsize - sizeof(*dlp)); | |
| 190 | dlp = (struct disklabel32 *)((char *)dlp + sizeof(long))) { | |
| 191 | if (dlp->d_magic != DISKMAGIC32 || | |
| 192 | dlp->d_magic2 != DISKMAGIC32) { | |
| 0ffe40b3 MD |
193 | /* |
| 194 | * NOTE! dsreadandsetlabel() does a strcmp() on | |
| 195 | * this string. | |
| 196 | */ | |
| 197 | if (msg == NULL) | |
| ba0cc1ab | 198 | msg = "no disk label"; |
| 0ffe40b3 | 199 | } else if (dlp->d_npartitions > MAXPARTITIONS32 || |
| 2b961883 | 200 | dkcksum32(dlp) != 0) { |
| ba0cc1ab | 201 | msg = "disk label corrupted"; |
| 2b961883 MD |
202 | } else { |
| 203 | lpx.lab32 = dlp; | |
| 204 | msg = l32_fixlabel(NULL, sp, lpx, FALSE); | |
| 205 | if (msg == NULL) { | |
| 206 | (*lpp).lab32 = kmalloc(sizeof(*dlp), | |
| 207 | M_DEVBUF, M_WAITOK|M_ZERO); | |
| 208 | *(*lpp).lab32 = *dlp; | |
| 209 | } | |
| ba0cc1ab MD |
210 | break; |
| 211 | } | |
| 212 | } | |
| 213 | bp->b_flags |= B_INVAL | B_AGE; | |
| 214 | brelse(bp); | |
| 215 | return (msg); | |
| 216 | } | |
| 217 | ||
| 218 | /* | |
| 219 | * Check new disk label for sensibility before setting it. | |
| 220 | */ | |
| 2b961883 | 221 | static int |
| 0ffe40b3 | 222 | l32_setdisklabel(disklabel_t olpx, disklabel_t nlpx, struct diskslices *ssp, |
| 2b961883 | 223 | struct diskslice *sp, u_int32_t *openmask) |
| ba0cc1ab | 224 | { |
| 2b961883 MD |
225 | struct disklabel32 *olp, *nlp; |
| 226 | struct partition32 *opp, *npp; | |
| ba0cc1ab MD |
227 | int part; |
| 228 | int i; | |
| 229 | ||
| 2b961883 MD |
230 | olp = olpx.lab32; |
| 231 | nlp = nlpx.lab32; | |
| 232 | ||
| ba0cc1ab MD |
233 | /* |
| 234 | * Check it is actually a disklabel we are looking at. | |
| 235 | */ | |
| 2b961883 MD |
236 | if (nlp->d_magic != DISKMAGIC32 || nlp->d_magic2 != DISKMAGIC32 || |
| 237 | dkcksum32(nlp) != 0) | |
| ba0cc1ab MD |
238 | return (EINVAL); |
| 239 | ||
| 240 | /* | |
| 241 | * For each partition that we think is open, check the new disklabel | |
| 242 | * for compatibility. Ignore special partitions (>= 128). | |
| 243 | */ | |
| 244 | i = 0; | |
| 245 | while (i < 128) { | |
| 246 | if (openmask[i >> 5] == 0) { | |
| 247 | i += 32; | |
| 248 | continue; | |
| 249 | } | |
| 250 | if ((openmask[i >> 5] & (1 << (i & 31))) == 0) { | |
| 251 | ++i; | |
| 252 | continue; | |
| 253 | } | |
| 254 | if (nlp->d_npartitions <= i) | |
| 255 | return (EBUSY); | |
| 256 | opp = &olp->d_partitions[i]; | |
| 257 | npp = &nlp->d_partitions[i]; | |
| 258 | if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) | |
| 259 | return (EBUSY); | |
| 260 | /* | |
| 261 | * Copy internally-set partition information | |
| 262 | * if new label doesn't include it. XXX | |
| 263 | * (If we are using it then we had better stay the same type) | |
| 264 | * This is possibly dubious, as someone else noted (XXX) | |
| 265 | */ | |
| 266 | if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { | |
| 267 | npp->p_fstype = opp->p_fstype; | |
| 268 | npp->p_fsize = opp->p_fsize; | |
| 269 | npp->p_frag = opp->p_frag; | |
| 270 | npp->p_cpg = opp->p_cpg; | |
| 271 | } | |
| 272 | ++i; | |
| 273 | } | |
| 274 | nlp->d_checksum = 0; | |
| 2b961883 | 275 | nlp->d_checksum = dkcksum32(nlp); |
| ba0cc1ab MD |
276 | *olp = *nlp; |
| 277 | ||
| 278 | if (olp->d_partitions[RAW_PART].p_offset) | |
| 279 | return (EXDEV); | |
| 280 | if (olp->d_secperunit > sp->ds_size) | |
| 281 | return (ENOSPC); | |
| 282 | for (part = 0; part < olp->d_npartitions; ++part) { | |
| 283 | if (olp->d_partitions[part].p_size > sp->ds_size) | |
| 284 | return(ENOSPC); | |
| 285 | } | |
| 286 | return (0); | |
| 287 | } | |
| 288 | ||
| 289 | /* | |
| 290 | * Write disk label back to device after modification. | |
| 291 | */ | |
| 2b961883 | 292 | static int |
| 0ffe40b3 MD |
293 | l32_writedisklabel(cdev_t dev, struct diskslices *ssp, struct diskslice *sp, |
| 294 | disklabel_t lpx) | |
| ba0cc1ab | 295 | { |
| 2b961883 MD |
296 | struct disklabel32 *lp; |
| 297 | struct disklabel32 *dlp; | |
| ba0cc1ab | 298 | struct buf *bp; |
| 2b961883 | 299 | const char *msg; |
| ba0cc1ab MD |
300 | int error = 0; |
| 301 | ||
| 2b961883 MD |
302 | lp = lpx.lab32; |
| 303 | ||
| ba0cc1ab MD |
304 | if (lp->d_partitions[RAW_PART].p_offset != 0) |
| 305 | return (EXDEV); /* not quite right */ | |
| 306 | bp = geteblk((int)lp->d_secsize); | |
| 2b961883 | 307 | bp->b_bio1.bio_offset = (off_t)LABELSECTOR32 * lp->d_secsize; |
| ba0cc1ab MD |
308 | bp->b_bcount = lp->d_secsize; |
| 309 | #if 1 | |
| 310 | /* | |
| 311 | * We read the label first to see if it's there, | |
| 312 | * in which case we will put ours at the same offset into the block.. | |
| 313 | * (I think this is stupid [Julian]) | |
| 314 | * Note that you can't write a label out over a corrupted label! | |
| 315 | * (also stupid.. how do you write the first one? by raw writes?) | |
| 316 | */ | |
| 317 | bp->b_flags &= ~B_INVAL; | |
| 318 | bp->b_cmd = BUF_CMD_READ; | |
| 319 | dev_dstrategy(dkmodpart(dev, WHOLE_SLICE_PART), &bp->b_bio1); | |
| 320 | error = biowait(bp); | |
| 321 | if (error) | |
| 322 | goto done; | |
| 2b961883 MD |
323 | for (dlp = (struct disklabel32 *)bp->b_data; |
| 324 | dlp <= (struct disklabel32 *) | |
| ba0cc1ab | 325 | ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp)); |
| 2b961883 MD |
326 | dlp = (struct disklabel32 *)((char *)dlp + sizeof(long))) { |
| 327 | if (dlp->d_magic == DISKMAGIC32 && | |
| 328 | dlp->d_magic2 == DISKMAGIC32 && dkcksum32(dlp) == 0) { | |
| ba0cc1ab | 329 | *dlp = *lp; |
| 2b961883 MD |
330 | lpx.lab32 = dlp; |
| 331 | msg = l32_fixlabel(NULL, sp, lpx, TRUE); | |
| 332 | if (msg) { | |
| 333 | error = EINVAL; | |
| 334 | } else { | |
| 335 | bp->b_cmd = BUF_CMD_WRITE; | |
| 336 | dev_dstrategy(dkmodpart(dev, WHOLE_SLICE_PART), | |
| 337 | &bp->b_bio1); | |
| 338 | error = biowait(bp); | |
| 339 | } | |
| ba0cc1ab MD |
340 | goto done; |
| 341 | } | |
| 342 | } | |
| 343 | error = ESRCH; | |
| 344 | done: | |
| 345 | #else | |
| 346 | bzero(bp->b_data, lp->d_secsize); | |
| 2b961883 | 347 | dlp = (struct disklabel32 *)bp->b_data; |
| ba0cc1ab MD |
348 | *dlp = *lp; |
| 349 | bp->b_flags &= ~B_INVAL; | |
| 350 | bp->b_cmd = BUF_CMD_WRITE; | |
| 351 | BUF_STRATEGY(bp, 1); | |
| 352 | error = biowait(bp); | |
| 353 | #endif | |
| 354 | bp->b_flags |= B_INVAL | B_AGE; | |
| 355 | brelse(bp); | |
| 356 | return (error); | |
| 357 | } | |
| 358 | ||
| 359 | /* | |
| 360 | * Create a disklabel based on a disk_info structure, initializing | |
| 361 | * the appropriate fields and creating a raw partition that covers the | |
| 362 | * whole disk. | |
| 363 | * | |
| 364 | * If a diskslice is passed, the label is truncated to the slice | |
| 365 | */ | |
| 2b961883 MD |
366 | static disklabel_t |
| 367 | l32_clone_label(struct disk_info *info, struct diskslice *sp) | |
| ba0cc1ab | 368 | { |
| 2b961883 MD |
369 | struct disklabel32 *lp; |
| 370 | disklabel_t res; | |
| ba0cc1ab | 371 | |
| 2b961883 MD |
372 | lp = kmalloc(sizeof *lp, M_DEVBUF, M_WAITOK | M_ZERO); |
| 373 | lp->d_nsectors = info->d_secpertrack; | |
| 374 | lp->d_ntracks = info->d_nheads; | |
| 375 | lp->d_secpercyl = info->d_secpercyl; | |
| 376 | lp->d_secsize = info->d_media_blksize; | |
| ba0cc1ab MD |
377 | |
| 378 | if (sp) | |
| 2b961883 | 379 | lp->d_secperunit = (u_int)sp->ds_size; |
| ba0cc1ab | 380 | else |
| 2b961883 MD |
381 | lp->d_secperunit = (u_int)info->d_media_blocks; |
| 382 | ||
| 383 | if (lp->d_typename[0] == '\0') | |
| 384 | strncpy(lp->d_typename, "amnesiac", sizeof(lp->d_typename)); | |
| 385 | if (lp->d_packname[0] == '\0') | |
| 386 | strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); | |
| 387 | if (lp->d_nsectors == 0) | |
| 388 | lp->d_nsectors = 32; | |
| 389 | if (lp->d_ntracks == 0) | |
| 390 | lp->d_ntracks = 64; | |
| 391 | lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; | |
| 392 | lp->d_ncylinders = lp->d_secperunit / lp->d_secpercyl; | |
| 393 | if (lp->d_rpm == 0) | |
| 394 | lp->d_rpm = 3600; | |
| 395 | if (lp->d_interleave == 0) | |
| 396 | lp->d_interleave = 1; | |
| 397 | if (lp->d_npartitions < RAW_PART + 1) | |
| 0ffe40b3 | 398 | lp->d_npartitions = MAXPARTITIONS32; |
| 2b961883 MD |
399 | if (lp->d_bbsize == 0) |
| 400 | lp->d_bbsize = BBSIZE; | |
| 401 | if (lp->d_sbsize == 0) | |
| 402 | lp->d_sbsize = SBSIZE; | |
| ba0cc1ab MD |
403 | |
| 404 | /* | |
| 405 | * Used by various devices to create a compatibility slice which | |
| 406 | * allows us to mount root from devices which do not have a | |
| 407 | * disklabel. Particularly: CDs. | |
| 408 | */ | |
| 2b961883 | 409 | lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; |
| ba0cc1ab | 410 | if (info->d_dsflags & DSO_COMPATPARTA) { |
| 2b961883 MD |
411 | lp->d_partitions[0].p_size = lp->d_secperunit; |
| 412 | lp->d_partitions[0].p_fstype = FS_OTHER; | |
| ba0cc1ab | 413 | } |
| 2b961883 MD |
414 | lp->d_magic = DISKMAGIC32; |
| 415 | lp->d_magic2 = DISKMAGIC32; | |
| 416 | lp->d_checksum = dkcksum32(lp); | |
| 417 | res.lab32 = lp; | |
| 418 | return (res); | |
| ba0cc1ab MD |
419 | } |
| 420 | ||
| 2b961883 MD |
421 | static void |
| 422 | l32_makevirginlabel(disklabel_t lpx, struct diskslices *ssp, | |
| 423 | struct diskslice *sp, struct disk_info *info) | |
| ba0cc1ab | 424 | { |
| 2b961883 MD |
425 | struct disklabel32 *lp = lpx.lab32; |
| 426 | struct partition32 *pp; | |
| 0ffe40b3 MD |
427 | disklabel_t template; |
| 428 | ||
| 429 | template = l32_clone_label(info, NULL); | |
| 430 | bcopy(template.opaque, lp, sizeof(struct disklabel32)); | |
| ba0cc1ab | 431 | |
| 2b961883 MD |
432 | lp->d_magic = DISKMAGIC32; |
| 433 | lp->d_magic2 = DISKMAGIC32; | |
| ba0cc1ab | 434 | |
| 0ffe40b3 | 435 | lp->d_npartitions = MAXPARTITIONS32; |
| ba0cc1ab MD |
436 | if (lp->d_interleave == 0) |
| 437 | lp->d_interleave = 1; | |
| 438 | if (lp->d_rpm == 0) | |
| 439 | lp->d_rpm = 3600; | |
| 440 | if (lp->d_nsectors == 0) /* sectors per track */ | |
| 441 | lp->d_nsectors = 32; | |
| 442 | if (lp->d_ntracks == 0) /* heads */ | |
| 443 | lp->d_ntracks = 64; | |
| 444 | lp->d_ncylinders = 0; | |
| 445 | lp->d_bbsize = BBSIZE; | |
| 446 | lp->d_sbsize = SBSIZE; | |
| 447 | ||
| 448 | /* | |
| 449 | * If the slice or GPT partition is really small we could | |
| 450 | * wind up with an absurd calculation for ncylinders. | |
| 451 | */ | |
| 452 | while (lp->d_ncylinders < 4) { | |
| 453 | if (lp->d_ntracks > 1) | |
| 454 | lp->d_ntracks >>= 1; | |
| 455 | else if (lp->d_nsectors > 1) | |
| 456 | lp->d_nsectors >>= 1; | |
| 457 | else | |
| 458 | break; | |
| 459 | lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; | |
| 460 | lp->d_ncylinders = sp->ds_size / lp->d_secpercyl; | |
| 461 | } | |
| 462 | ||
| 463 | /* | |
| 464 | * Set or Modify the partition sizes to accomodate the slice, | |
| 465 | * since we started with a copy of the virgin label stored | |
| 466 | * in the whole-disk-slice and we are probably not a | |
| 467 | * whole-disk slice. | |
| 468 | */ | |
| 469 | lp->d_secperunit = sp->ds_size; | |
| 470 | pp = &lp->d_partitions[RAW_PART]; | |
| 471 | pp->p_offset = 0; | |
| 472 | pp->p_size = lp->d_secperunit; | |
| 473 | if (info->d_dsflags & DSO_COMPATPARTA) { | |
| 474 | pp = &lp->d_partitions[0]; | |
| 475 | pp->p_offset = 0; | |
| 476 | pp->p_size = lp->d_secperunit; | |
| 477 | pp->p_fstype = FS_OTHER; | |
| 478 | } | |
| 479 | lp->d_checksum = 0; | |
| 2b961883 | 480 | lp->d_checksum = dkcksum32(lp); |
| 0ffe40b3 MD |
481 | |
| 482 | kfree(template.opaque, M_DEVBUF); | |
| ba0cc1ab MD |
483 | } |
| 484 | ||
| 2b961883 MD |
485 | static const char * |
| 486 | l32_fixlabel(const char *sname, struct diskslice *sp, | |
| 487 | disklabel_t lpx, int writeflag) | |
| ba0cc1ab | 488 | { |
| 2b961883 MD |
489 | struct disklabel32 *lp; |
| 490 | struct partition32 *pp; | |
| ba0cc1ab MD |
491 | u_int64_t start; |
| 492 | u_int64_t end; | |
| 493 | u_int64_t offset; | |
| 494 | int part; | |
| ba0cc1ab MD |
495 | int warned; |
| 496 | ||
| 2b961883 MD |
497 | lp = lpx.lab32; |
| 498 | ||
| ba0cc1ab | 499 | /* These errors "can't happen" so don't bother reporting details. */ |
| 2b961883 | 500 | if (lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32) |
| ba0cc1ab | 501 | return ("fixlabel: invalid magic"); |
| 2b961883 | 502 | if (dkcksum32(lp) != 0) |
| ba0cc1ab MD |
503 | return ("fixlabel: invalid checksum"); |
| 504 | ||
| 505 | pp = &lp->d_partitions[RAW_PART]; | |
| 506 | ||
| 507 | /* | |
| 508 | * What a mess. For ages old backwards compatibility the disklabel | |
| 509 | * on-disk stores absolute offsets instead of slice-relative offsets. | |
| 510 | * So fix it up when reading, writing, or snooping. | |
| 511 | * | |
| 512 | * The in-core label is always slice-relative. | |
| 513 | */ | |
| 514 | if (writeflag) { | |
| 515 | start = 0; | |
| 516 | offset = sp->ds_offset; | |
| 517 | } else { | |
| 518 | start = sp->ds_offset; | |
| 519 | offset = -sp->ds_offset; | |
| 520 | } | |
| 521 | if (pp->p_offset != start) { | |
| 522 | if (sname != NULL) { | |
| 523 | kprintf( | |
| 524 | "%s: rejecting BSD label: raw partition offset != slice offset\n", | |
| 525 | sname); | |
| 526 | slice_info(sname, sp); | |
| 527 | partition_info(sname, RAW_PART, pp); | |
| 528 | } | |
| 529 | return ("fixlabel: raw partition offset != slice offset"); | |
| 530 | } | |
| 531 | if (pp->p_size != sp->ds_size) { | |
| 532 | if (sname != NULL) { | |
| 533 | kprintf("%s: raw partition size != slice size\n", sname); | |
| 534 | slice_info(sname, sp); | |
| 535 | partition_info(sname, RAW_PART, pp); | |
| 536 | } | |
| 537 | if (pp->p_size > sp->ds_size) { | |
| 538 | if (sname == NULL) | |
| 539 | return ("fixlabel: raw partition size > slice size"); | |
| 540 | kprintf("%s: truncating raw partition\n", sname); | |
| 541 | pp->p_size = sp->ds_size; | |
| 542 | } | |
| 543 | } | |
| 544 | end = start + sp->ds_size; | |
| 545 | if (start > end) | |
| 546 | return ("fixlabel: slice wraps"); | |
| 547 | if (lp->d_secpercyl <= 0) | |
| 548 | return ("fixlabel: d_secpercyl <= 0"); | |
| 549 | pp -= RAW_PART; | |
| 550 | warned = FALSE; | |
| 551 | for (part = 0; part < lp->d_npartitions; part++, pp++) { | |
| 552 | if (pp->p_offset != 0 || pp->p_size != 0) { | |
| 553 | if (pp->p_offset < start | |
| 554 | || pp->p_offset + pp->p_size > end | |
| 555 | || pp->p_offset + pp->p_size < pp->p_offset) { | |
| 556 | if (sname != NULL) { | |
| 557 | kprintf( | |
| 558 | "%s: rejecting partition in BSD label: it isn't entirely within the slice\n", | |
| 559 | sname); | |
| 560 | if (!warned) { | |
| 561 | slice_info(sname, sp); | |
| 562 | warned = TRUE; | |
| 563 | } | |
| 564 | partition_info(sname, part, pp); | |
| 565 | } | |
| 566 | /* XXX else silently discard junk. */ | |
| 567 | bzero(pp, sizeof *pp); | |
| 568 | } else { | |
| 569 | pp->p_offset += offset; | |
| 570 | } | |
| 571 | } | |
| 572 | } | |
| 573 | lp->d_ncylinders = sp->ds_size / lp->d_secpercyl; | |
| 574 | lp->d_secperunit = sp->ds_size; | |
| 575 | lp->d_checksum = 0; | |
| 2b961883 | 576 | lp->d_checksum = dkcksum32(lp); |
| ba0cc1ab MD |
577 | return (NULL); |
| 578 | } | |
| 579 | ||
| 0ffe40b3 MD |
580 | /* |
| 581 | * Set the number of blocks at the beginning of the slice which have | |
| 582 | * been reserved for label operations. This area will be write-protected | |
| 583 | * when accessed via the slice. | |
| 584 | */ | |
| 2b961883 MD |
585 | static void |
| 586 | l32_adjust_label_reserved(struct diskslices *ssp, int slice, | |
| 587 | struct diskslice *sp) | |
| ba0cc1ab | 588 | { |
| 0ffe40b3 MD |
589 | /*struct disklabel32 *lp = sp->ds_label.lab32;*/ |
| 590 | sp->ds_reserved = SBSIZE / ssp->dss_secsize; | |
| ba0cc1ab MD |
591 | } |
| 592 | ||
| 593 | static void | |
| 2b961883 | 594 | partition_info(const char *sname, int part, struct partition32 *pp) |
| ba0cc1ab MD |
595 | { |
| 596 | kprintf("%s%c: start %lu, end %lu, size %lu\n", sname, 'a' + part, | |
| 597 | (u_long)pp->p_offset, (u_long)(pp->p_offset + pp->p_size - 1), | |
| 598 | (u_long)pp->p_size); | |
| 599 | } | |
| 600 | ||
| 601 | static void | |
| 602 | slice_info(const char *sname, struct diskslice *sp) | |
| 603 | { | |
| 604 | kprintf("%s: start %llu, end %llu, size %llu\n", sname, | |
| 973c11b9 MD |
605 | (long long)sp->ds_offset, |
| 606 | (long long)sp->ds_offset + sp->ds_size - 1, | |
| 607 | (long long)sp->ds_size); | |
| ba0cc1ab MD |
608 | } |
| 609 | ||
| 2b961883 | 610 | struct disklabel_ops disklabel32_ops = { |
| 2b961883 MD |
611 | .labelsize = sizeof(struct disklabel32), |
| 612 | .op_readdisklabel = l32_readdisklabel, | |
| 613 | .op_setdisklabel = l32_setdisklabel, | |
| 614 | .op_writedisklabel = l32_writedisklabel, | |
| 615 | .op_clone_label = l32_clone_label, | |
| 616 | .op_adjust_label_reserved = l32_adjust_label_reserved, | |
| 617 | .op_getpartbounds = l32_getpartbounds, | |
| 18cb7add | 618 | .op_loadpartinfo = l32_loadpartinfo, |
| 2b961883 MD |
619 | .op_getnumparts = l32_getnumparts, |
| 620 | .op_makevirginlabel = l32_makevirginlabel | |
| 621 | }; | |
| 622 |