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