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