1 /* 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)ufs_disksubr.c 7.12 (Berkeley) 05/09/89 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "buf.h" 23 #include "disklabel.h" 24 #include "syslog.h" 25 #include "user.h" 26 27 /* 28 * Seek sort for disks. We depend on the driver 29 * which calls us using b_resid as the current cylinder number. 30 * 31 * The argument dp structure holds a b_actf activity chain pointer 32 * on which we keep two queues, sorted in ascending cylinder order. 33 * The first queue holds those requests which are positioned after 34 * the current cylinder (in the first request); the second holds 35 * requests which came in after their cylinder number was passed. 36 * Thus we implement a one way scan, retracting after reaching the 37 * end of the drive to the first request on the second queue, 38 * at which time it becomes the first queue. 39 * 40 * A one-way scan is natural because of the way UNIX read-ahead 41 * blocks are allocated. 42 */ 43 44 #define b_cylin b_resid 45 46 disksort(dp, bp) 47 register struct buf *dp, *bp; 48 { 49 register struct buf *ap; 50 51 /* 52 * If nothing on the activity queue, then 53 * we become the only thing. 54 */ 55 ap = dp->b_actf; 56 if(ap == NULL) { 57 dp->b_actf = bp; 58 dp->b_actl = bp; 59 bp->av_forw = NULL; 60 return; 61 } 62 /* 63 * If we lie after the first (currently active) 64 * request, then we must locate the second request list 65 * and add ourselves to it. 66 */ 67 if (bp->b_cylin < ap->b_cylin) { 68 while (ap->av_forw) { 69 /* 70 * Check for an ``inversion'' in the 71 * normally ascending cylinder numbers, 72 * indicating the start of the second request list. 73 */ 74 if (ap->av_forw->b_cylin < ap->b_cylin) { 75 /* 76 * Search the second request list 77 * for the first request at a larger 78 * cylinder number. We go before that; 79 * if there is no such request, we go at end. 80 */ 81 do { 82 if (bp->b_cylin < ap->av_forw->b_cylin) 83 goto insert; 84 if (bp->b_cylin == ap->av_forw->b_cylin && 85 bp->b_blkno < ap->av_forw->b_blkno) 86 goto insert; 87 ap = ap->av_forw; 88 } while (ap->av_forw); 89 goto insert; /* after last */ 90 } 91 ap = ap->av_forw; 92 } 93 /* 94 * No inversions... we will go after the last, and 95 * be the first request in the second request list. 96 */ 97 goto insert; 98 } 99 /* 100 * Request is at/after the current request... 101 * sort in the first request list. 102 */ 103 while (ap->av_forw) { 104 /* 105 * We want to go after the current request 106 * if there is an inversion after it (i.e. it is 107 * the end of the first request list), or if 108 * the next request is a larger cylinder than our request. 109 */ 110 if (ap->av_forw->b_cylin < ap->b_cylin || 111 bp->b_cylin < ap->av_forw->b_cylin || 112 (bp->b_cylin == ap->av_forw->b_cylin && 113 bp->b_blkno < ap->av_forw->b_blkno)) 114 goto insert; 115 ap = ap->av_forw; 116 } 117 /* 118 * Neither a second list nor a larger 119 * request... we go at the end of the first list, 120 * which is the same as the end of the whole schebang. 121 */ 122 insert: 123 bp->av_forw = ap->av_forw; 124 ap->av_forw = bp; 125 if (ap == dp->b_actl) 126 dp->b_actl = bp; 127 } 128 129 /* 130 * Attempt to read a disk label from a device 131 * using the indicated stategy routine. 132 * The label must be partly set up before this: 133 * secpercyl and anything required in the strategy routine 134 * (e.g., sector size) must be filled in before calling us. 135 * Returns null on success and an error string on failure. 136 */ 137 char * 138 readdisklabel(dev, strat, lp) 139 dev_t dev; 140 int (*strat)(); 141 register struct disklabel *lp; 142 { 143 register struct buf *bp; 144 struct disklabel *dlp; 145 char *msg = NULL; 146 147 if (lp->d_secperunit == 0) 148 lp->d_secperunit = 0x1fffffff; 149 lp->d_npartitions = 1; 150 if (lp->d_partitions[0].p_size == 0) 151 lp->d_partitions[0].p_size = 0x1fffffff; 152 lp->d_partitions[0].p_offset = 0; 153 154 bp = geteblk((int)lp->d_secsize); 155 bp->b_dev = dev; 156 bp->b_blkno = LABELSECTOR; 157 bp->b_bcount = lp->d_secsize; 158 bp->b_flags = B_BUSY | B_READ; 159 bp->b_cylin = LABELSECTOR / lp->d_secpercyl; 160 (*strat)(bp); 161 if (biowait(bp)) { 162 msg = "I/O error"; 163 } else for (dlp = (struct disklabel *)bp->b_un.b_addr; 164 dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp)); 165 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 166 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { 167 if (msg == NULL) 168 msg = "no disk label"; 169 } else if (dkcksum(dlp) != 0) 170 msg = "disk label corrupted"; 171 else { 172 *lp = *dlp; 173 msg = NULL; 174 break; 175 } 176 } 177 if (lp->d_npartitions > MAXPARTITIONS) 178 lp->d_npartitions = MAXPARTITIONS; 179 bp->b_flags = B_INVAL | B_AGE; 180 brelse(bp); 181 return (msg); 182 } 183 184 /* 185 * Check new disk label for sensibility 186 * before setting it. 187 */ 188 setdisklabel(olp, nlp, openmask) 189 register struct disklabel *olp, *nlp; 190 u_long openmask; 191 { 192 register i; 193 register struct partition *opp, *npp; 194 195 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 196 dkcksum(nlp) != 0) 197 return (EINVAL); 198 while ((i = ffs((long)openmask)) != 0) { 199 i--; 200 openmask &= ~(1 << i); 201 if (nlp->d_npartitions <= i) 202 return (EBUSY); 203 opp = &olp->d_partitions[i]; 204 npp = &nlp->d_partitions[i]; 205 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 206 return (EBUSY); 207 /* 208 * Copy internally-set partition information 209 * if new label doesn't include it. XXX 210 */ 211 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 212 npp->p_fstype = opp->p_fstype; 213 npp->p_fsize = opp->p_fsize; 214 npp->p_frag = opp->p_frag; 215 npp->p_cpg = opp->p_cpg; 216 } 217 } 218 nlp->d_checksum = 0; 219 nlp->d_checksum = dkcksum(nlp); 220 *olp = *nlp; 221 return (0); 222 } 223 224 /* encoding of disk minor numbers, should be elsewhere... */ 225 #define dkunit(dev) (minor(dev) >> 3) 226 #define dkpart(dev) (minor(dev) & 07) 227 #define dkminor(unit, part) (((unit) << 3) | (part)) 228 229 /* 230 * Write disk label back to device after modification. 231 */ 232 writedisklabel(dev, strat, lp) 233 dev_t dev; 234 int (*strat)(); 235 register struct disklabel *lp; 236 { 237 struct buf *bp; 238 struct disklabel *dlp; 239 int labelpart; 240 int error = 0; 241 242 labelpart = dkpart(dev); 243 if (lp->d_partitions[labelpart].p_offset != 0) { 244 if (lp->d_partitions[0].p_offset != 0) 245 return (EXDEV); /* not quite right */ 246 labelpart = 0; 247 } 248 bp = geteblk((int)lp->d_secsize); 249 bp->b_dev = makedev(major(dev), dkminor(dkunit(dev), labelpart)); 250 bp->b_blkno = LABELSECTOR; 251 bp->b_bcount = lp->d_secsize; 252 bp->b_flags = B_READ; 253 (*strat)(bp); 254 if (error = biowait(bp)) 255 goto done; 256 for (dlp = (struct disklabel *)bp->b_un.b_addr; 257 dlp <= (struct disklabel *) 258 (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp)); 259 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 260 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 261 dkcksum(dlp) == 0) { 262 *dlp = *lp; 263 bp->b_flags = B_WRITE; 264 (*strat)(bp); 265 error = biowait(bp); 266 goto done; 267 } 268 } 269 error = ESRCH; 270 done: 271 brelse(bp); 272 return (error); 273 } 274 275 /* 276 * Compute checksum for disk label. 277 */ 278 dkcksum(lp) 279 register struct disklabel *lp; 280 { 281 register u_short *start, *end; 282 register u_short sum = 0; 283 284 start = (u_short *)lp; 285 end = (u_short *)&lp->d_partitions[lp->d_npartitions]; 286 while (start < end) 287 sum ^= *start++; 288 return (sum); 289 } 290 291 /* 292 * Disk error is the preface to plaintive error messages 293 * about failing disk transfers. It prints messages of the form 294 295 hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d) 296 297 * if the offset of the error in the transfer and a disk label 298 * are both available. blkdone should be -1 if the position of the error 299 * is unknown; the disklabel pointer may be null from drivers that have not 300 * been converted to use them. The message is printed with printf 301 * if pri is LOG_PRINTF, otherwise it uses log at the specified priority. 302 * The message should be completed (with at least a newline) with printf 303 * or addlog, respectively. There is no trailing space. 304 */ 305 diskerr(bp, dname, what, pri, blkdone, lp) 306 register struct buf *bp; 307 char *dname, *what; 308 int pri, blkdone; 309 register struct disklabel *lp; 310 { 311 int unit = dkunit(bp->b_dev), part = dkpart(bp->b_dev); 312 register int (*pr)(), sn; 313 char partname = 'a' + part; 314 extern printf(), addlog(); 315 316 if (pri != LOG_PRINTF) { 317 log(pri, ""); 318 pr = addlog; 319 } else 320 pr = printf; 321 (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what, 322 bp->b_flags & B_READ ? "read" : "writ"); 323 sn = bp->b_blkno; 324 if (bp->b_bcount <= DEV_BSIZE) 325 (*pr)("%d", sn); 326 else { 327 if (blkdone >= 0) { 328 sn += blkdone; 329 (*pr)("%d of ", sn); 330 } 331 (*pr)("%d-%d", bp->b_blkno, 332 bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE); 333 } 334 if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) { 335 #ifdef tahoe 336 sn *= DEV_BSIZE / lp->d_secsize; /* XXX */ 337 #endif 338 sn += lp->d_partitions[part].p_offset; 339 (*pr)(" (%s%d bn %d; cn %d", dname, unit, sn, 340 sn / lp->d_secpercyl); 341 sn %= lp->d_secpercyl; 342 (*pr)(" tn %d sn %d)", sn / lp->d_nsectors, sn % lp->d_nsectors); 343 } 344 } 345