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