xref: /original-bsd/sys/ufs/ufs/ufs_disksubr.c (revision fbc8b8c6)
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