first cut for new proc & user structs (still need to put in new vnode calling
[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 *
c6f5111d 7 * @(#)ufs_disksubr.c 7.15 (Berkeley) %G%
da7c5cc6 8 */
200a8f27 9
97934dfa
MK
10#include "param.h"
11#include "systm.h"
12#include "buf.h"
13#include "disklabel.h"
1ad7f5c8 14#include "syslog.h"
9573c71c 15
200a8f27 16/*
0d67fde4
BJ
17 * Seek sort for disks. We depend on the driver
18 * which calls us using b_resid as the current cylinder number.
19 *
20 * The argument dp structure holds a b_actf activity chain pointer
21 * on which we keep two queues, sorted in ascending cylinder order.
22 * The first queue holds those requests which are positioned after
23 * the current cylinder (in the first request); the second holds
24 * requests which came in after their cylinder number was passed.
25 * Thus we implement a one way scan, retracting after reaching the
26 * end of the drive to the first request on the second queue,
27 * at which time it becomes the first queue.
28 *
29 * A one-way scan is natural because of the way UNIX read-ahead
30 * blocks are allocated.
200a8f27
BJ
31 */
32
200a8f27
BJ
33#define b_cylin b_resid
34
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
MK
118/*
119 * Attempt to read a disk label from a device
120 * using the indicated stategy routine.
121 * The label must be partly set up before this:
122 * secpercyl and anything required in the strategy routine
123 * (e.g., sector size) must be filled in before calling us.
124 * Returns null on success and an error string on failure.
125 */
126char *
127readdisklabel(dev, strat, lp)
128 dev_t dev;
129 int (*strat)();
130 register struct disklabel *lp;
131{
132 register struct buf *bp;
133 struct disklabel *dlp;
134 char *msg = NULL;
135
136 if (lp->d_secperunit == 0)
137 lp->d_secperunit = 0x1fffffff;
138 lp->d_npartitions = 1;
139 if (lp->d_partitions[0].p_size == 0)
140 lp->d_partitions[0].p_size = 0x1fffffff;
141 lp->d_partitions[0].p_offset = 0;
142
d3633d66 143 bp = geteblk((int)lp->d_secsize);
9573c71c
MK
144 bp->b_dev = dev;
145 bp->b_blkno = LABELSECTOR;
cd6cd535 146 bp->b_bcount = lp->d_secsize;
9573c71c
MK
147 bp->b_flags = B_BUSY | B_READ;
148 bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
149 (*strat)(bp);
7188ac27 150 if (biowait(bp)) {
9573c71c 151 msg = "I/O error";
cd6cd535
MK
152 } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
153 dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
154 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
155 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
156 if (msg == NULL)
157 msg = "no disk label";
0328954d
KM
158 } else if (dlp->d_npartitions > MAXPARTITIONS ||
159 dkcksum(dlp) != 0)
9573c71c 160 msg = "disk label corrupted";
cd6cd535 161 else {
9573c71c 162 *lp = *dlp;
cd6cd535
MK
163 msg = NULL;
164 break;
165 }
9573c71c
MK
166 }
167 bp->b_flags = B_INVAL | B_AGE;
168 brelse(bp);
169 return (msg);
170}
171
667e5665
MK
172/*
173 * Check new disk label for sensibility
174 * before setting it.
175 */
176setdisklabel(olp, nlp, openmask)
177 register struct disklabel *olp, *nlp;
178 u_long openmask;
179{
180 register i;
181 register struct partition *opp, *npp;
182
183 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
184 dkcksum(nlp) != 0)
185 return (EINVAL);
5adcb337 186 while ((i = ffs((long)openmask)) != 0) {
667e5665
MK
187 i--;
188 openmask &= ~(1 << i);
189 if (nlp->d_npartitions <= i)
190 return (EBUSY);
191 opp = &olp->d_partitions[i];
192 npp = &nlp->d_partitions[i];
193 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
194 return (EBUSY);
195 /*
196 * Copy internally-set partition information
197 * if new label doesn't include it. XXX
198 */
199 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
200 npp->p_fstype = opp->p_fstype;
201 npp->p_fsize = opp->p_fsize;
202 npp->p_frag = opp->p_frag;
203 npp->p_cpg = opp->p_cpg;
204 }
205 }
d3633d66
MK
206 nlp->d_checksum = 0;
207 nlp->d_checksum = dkcksum(nlp);
667e5665
MK
208 *olp = *nlp;
209 return (0);
210}
211
212/* encoding of disk minor numbers, should be elsewhere... */
213#define dkunit(dev) (minor(dev) >> 3)
214#define dkpart(dev) (minor(dev) & 07)
215#define dkminor(unit, part) (((unit) << 3) | (part))
216
217/*
218 * Write disk label back to device after modification.
219 */
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 */
293diskerr(bp, dname, what, pri, blkdone, lp)
294 register struct buf *bp;
295 char *dname, *what;
296 int pri, blkdone;
297 register struct disklabel *lp;
298{
299 int unit = dkunit(bp->b_dev), part = dkpart(bp->b_dev);
300 register int (*pr)(), sn;
301 char partname = 'a' + part;
302 extern printf(), addlog();
303
304 if (pri != LOG_PRINTF) {
305 log(pri, "");
306 pr = addlog;
307 } else
308 pr = printf;
309 (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what,
310 bp->b_flags & B_READ ? "read" : "writ");
311 sn = bp->b_blkno;
312 if (bp->b_bcount <= DEV_BSIZE)
313 (*pr)("%d", sn);
314 else {
315 if (blkdone >= 0) {
316 sn += blkdone;
317 (*pr)("%d of ", sn);
318 }
319 (*pr)("%d-%d", bp->b_blkno,
320 bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE);
321 }
f2a9617b
MK
322 if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) {
323#ifdef tahoe
324 sn *= DEV_BSIZE / lp->d_secsize; /* XXX */
325#endif
1ad7f5c8 326 sn += lp->d_partitions[part].p_offset;
05de9101
MK
327 (*pr)(" (%s%d bn %d; cn %d", dname, unit, sn,
328 sn / lp->d_secpercyl);
329 sn %= lp->d_secpercyl;
9f79ca31 330 (*pr)(" tn %d sn %d)", sn / lp->d_nsectors, sn % lp->d_nsectors);
1ad7f5c8
MK
331 }
332}