1 /* $NetBSD: subr_disk_4bsd.c,v 1.4 2026/08/09 16:10:00 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: subr_disk_4bsd.c,v 1.4 2026/08/09 16:10:00 thorpej Exp $"); 41 42 #define __SUBR_DISK_4BSD_PRIVATE 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/buf.h> 47 #include <sys/disk.h> 48 #include <sys/disklabel.h> 49 50 /* 51 * Implementation of readdisklabel() and writedisklabel() for the simple 52 * "basic scheme from 4BSD". 53 */ 54 55 /* 56 * We prefer the platform's "native" label sector / offset. Look for 57 * it there first. Otherwise, scan the first 3 disk sectors for the 58 * label. When updating a label, we will write it to where we found 59 * it. If writing a new label from scratch, we will write it to the 60 * "native" location. 61 */ 62 static int label_sectors[] = { LABELSECTOR, 0, 1, 2 }; 63 static int label_offsets[] = { LABELOFFSET, -1, -1, -1 }; 64 65 #define DISKLABEL_SIZE(x) \ 66 (offsetof(struct disklabel, d_partitions) + \ 67 (sizeof(struct partition) * (x))) 68 69 /* Smallest 4.4BSD disklabel that was ever in use. */ 70 #define DISKLABEL_MINSIZE DISKLABEL_SIZE(8) 71 72 static bool 73 taste_label(const struct disklabel *lp, void *buf, size_t secsize) 74 { 75 uint16_t npartitions; 76 77 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) { 78 return false; 79 } 80 81 npartitions = lp->d_npartitions; 82 83 if ((uintptr_t)lp + DISKLABEL_SIZE(npartitions) > 84 (uintptr_t)buf + secsize) { 85 /* doesn't fit in the sector. */ 86 return false; 87 } 88 89 if (npartitions > MAXPARTITIONS || dkcksum(lp)) { 90 /* disklabel is corrupted. */ 91 return false; 92 } 93 94 return true; 95 } 96 97 static struct disklabel * 98 find_label_in_sector(void *buf, size_t secsize, int offs) 99 { 100 struct disklabel *lp = buf; 101 uintptr_t lp_lim = ((uintptr_t)buf + secsize - DISKLABEL_MINSIZE); 102 103 if (offs != -1) { 104 lp = (void *)((uintptr_t)lp + offs); 105 return taste_label(lp, buf, secsize) ? lp : NULL; 106 } 107 108 for (;; lp = (void *)((uintptr_t)lp + sizeof(uint32_t))) { 109 if ((uintptr_t)lp > lp_lim) { 110 /* Not found in this sector. */ 111 return NULL; 112 } 113 if (taste_label(lp, buf, secsize)) { 114 return lp; 115 } 116 } 117 } 118 119 __weak_alias(readdisklabel, readdisklabel_4bsd); 120 __weak_alias(writedisklabel, writedisklabel_4bsd); 121 122 /* 123 * Attempt to read a disk label from a device using the indicated strategy 124 * routine. The label must be partly set up before this: secpercyl and 125 * anything required in the strategy routine (e.g., sector size) must be 126 * filled in before calling us. Returns null on success and an error 127 * string on failure. 128 */ 129 const char * 130 readdisklabel_4bsd(dev_t dev, void (*strat)(struct buf *), 131 struct disklabel *lp, struct cpu_disklabel *osdep) 132 { 133 struct buf *bp; 134 struct disklabel *dlp; 135 const char *msg = NULL; 136 int i; 137 138 if (lp->d_secsize == 0) 139 lp->d_secsize = DEV_BSIZE; 140 if (lp->d_secperunit == 0) 141 lp->d_secperunit = 0x1fffffff; 142 if (lp->d_npartitions < RAW_PART + 1) 143 lp->d_npartitions = RAW_PART + 1; 144 for (i = 0; i < RAW_PART; i++) { 145 lp->d_partitions[i].p_size = 0; 146 lp->d_partitions[i].p_offset = 0; 147 } 148 if (lp->d_partitions[RAW_PART].p_size == 0) 149 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; 150 lp->d_partitions[RAW_PART].p_offset = 0; 151 152 lp->d_partitions[0].p_size = lp->d_partitions[RAW_PART].p_size; 153 lp->d_partitions[0].p_fstype = FS_BSDFFS; 154 155 bp = geteblk((int)lp->d_secsize); 156 bp->b_dev = dev; 157 158 for (i = 0; i < __arraycount(label_sectors); i++) { 159 if (disk_read_sectors(strat, lp, bp, label_sectors[i], 1)) { 160 msg = "I/O error"; 161 goto done; 162 } 163 164 dlp = find_label_in_sector(bp->b_data, DEV_BSIZE, 165 label_offsets[i]); 166 if (dlp != NULL) { 167 *lp = *dlp; 168 msg = NULL; 169 break; 170 } 171 } 172 done: 173 brelse(bp, 0); 174 return msg; 175 } 176 177 /* 178 * Write disk label back to device after modification. 179 */ 180 int 181 writedisklabel_4bsd(dev_t dev, void (*strat)(struct buf *), 182 struct disklabel *lp, struct cpu_disklabel *osdep) 183 { 184 struct buf *bp; 185 struct disklabel *dlp; 186 int labelpart; 187 int i, error = 0; 188 189 labelpart = DISKPART(dev); 190 if (lp->d_partitions[labelpart].p_offset != 0) { 191 if (lp->d_partitions[0].p_offset != 0) 192 return EXDEV; /* not quite right */ 193 labelpart = 0; 194 } 195 bp = geteblk((int)lp->d_secsize); 196 bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart); 197 198 for (i = 0; i < __arraycount(label_sectors); i++) { 199 if ((error = disk_read_sectors(strat, lp, bp, 200 label_sectors[i], 1)) != 0) { 201 goto done; 202 } 203 204 dlp = find_label_in_sector(bp->b_data, DEV_BSIZE, 205 label_offsets[i]); 206 if (dlp != NULL) { 207 *dlp = *lp; 208 bp->b_oflags &= ~(BO_DONE); 209 bp->b_flags &= ~(B_READ); 210 bp->b_flags |= B_WRITE; 211 (*strat)(bp); 212 error = biowait(bp); 213 goto done; 214 } 215 } 216 error = ESRCH; 217 done: 218 brelse(bp, 0); 219 return error; 220 } 221