Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
cd6cd535 | 6 | * @(#)ufs_disksubr.c 7.4 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
200a8f27 | 8 | |
97934dfa MK |
9 | #include "param.h" |
10 | #include "systm.h" | |
11 | #include "buf.h" | |
12 | #include "disklabel.h" | |
13 | ||
9573c71c MK |
14 | #include "dir.h" |
15 | #include "user.h" | |
16 | ||
200a8f27 | 17 | /* |
0d67fde4 BJ |
18 | * Seek sort for disks. We depend on the driver |
19 | * which calls us using b_resid as the current cylinder number. | |
20 | * | |
21 | * The argument dp structure holds a b_actf activity chain pointer | |
22 | * on which we keep two queues, sorted in ascending cylinder order. | |
23 | * The first queue holds those requests which are positioned after | |
24 | * the current cylinder (in the first request); the second holds | |
25 | * requests which came in after their cylinder number was passed. | |
26 | * Thus we implement a one way scan, retracting after reaching the | |
27 | * end of the drive to the first request on the second queue, | |
28 | * at which time it becomes the first queue. | |
29 | * | |
30 | * A one-way scan is natural because of the way UNIX read-ahead | |
31 | * blocks are allocated. | |
200a8f27 BJ |
32 | */ |
33 | ||
200a8f27 BJ |
34 | #define b_cylin b_resid |
35 | ||
36 | disksort(dp, bp) | |
0d67fde4 | 37 | register struct buf *dp, *bp; |
200a8f27 BJ |
38 | { |
39 | register struct buf *ap; | |
200a8f27 | 40 | |
0d67fde4 BJ |
41 | /* |
42 | * If nothing on the activity queue, then | |
43 | * we become the only thing. | |
44 | */ | |
200a8f27 BJ |
45 | ap = dp->b_actf; |
46 | if(ap == NULL) { | |
47 | dp->b_actf = bp; | |
48 | dp->b_actl = bp; | |
49 | bp->av_forw = NULL; | |
50 | return; | |
51 | } | |
0d67fde4 BJ |
52 | /* |
53 | * If we lie after the first (currently active) | |
54 | * request, then we must locate the second request list | |
55 | * and add ourselves to it. | |
56 | */ | |
57 | if (bp->b_cylin < ap->b_cylin) { | |
58 | while (ap->av_forw) { | |
59 | /* | |
60 | * Check for an ``inversion'' in the | |
61 | * normally ascending cylinder numbers, | |
62 | * indicating the start of the second request list. | |
63 | */ | |
64 | if (ap->av_forw->b_cylin < ap->b_cylin) { | |
65 | /* | |
66 | * Search the second request list | |
67 | * for the first request at a larger | |
68 | * cylinder number. We go before that; | |
69 | * if there is no such request, we go at end. | |
70 | */ | |
71 | do { | |
72 | if (bp->b_cylin < ap->av_forw->b_cylin) | |
73 | goto insert; | |
74 | ap = ap->av_forw; | |
75 | } while (ap->av_forw); | |
76 | goto insert; /* after last */ | |
77 | } | |
78 | ap = ap->av_forw; | |
200a8f27 | 79 | } |
0d67fde4 BJ |
80 | /* |
81 | * No inversions... we will go after the last, and | |
82 | * be the first request in the second request list. | |
83 | */ | |
84 | goto insert; | |
200a8f27 | 85 | } |
0d67fde4 BJ |
86 | /* |
87 | * Request is at/after the current request... | |
88 | * sort in the first request list. | |
89 | */ | |
90 | while (ap->av_forw) { | |
91 | /* | |
92 | * We want to go after the current request | |
93 | * if there is an inversion after it (i.e. it is | |
94 | * the end of the first request list), or if | |
95 | * the next request is a larger cylinder than our request. | |
96 | */ | |
97 | if (ap->av_forw->b_cylin < ap->b_cylin || | |
98 | bp->b_cylin < ap->av_forw->b_cylin) | |
99 | goto insert; | |
100 | ap = ap->av_forw; | |
101 | } | |
102 | /* | |
103 | * Neither a second list nor a larger | |
104 | * request... we go at the end of the first list, | |
105 | * which is the same as the end of the whole schebang. | |
106 | */ | |
107 | insert: | |
108 | bp->av_forw = ap->av_forw; | |
109 | ap->av_forw = bp; | |
110 | if (ap == dp->b_actl) | |
200a8f27 BJ |
111 | dp->b_actl = bp; |
112 | } | |
97934dfa | 113 | |
9573c71c MK |
114 | /* |
115 | * Attempt to read a disk label from a device | |
116 | * using the indicated stategy routine. | |
117 | * The label must be partly set up before this: | |
118 | * secpercyl and anything required in the strategy routine | |
119 | * (e.g., sector size) must be filled in before calling us. | |
120 | * Returns null on success and an error string on failure. | |
121 | */ | |
122 | char * | |
123 | readdisklabel(dev, strat, lp) | |
124 | dev_t dev; | |
125 | int (*strat)(); | |
126 | register struct disklabel *lp; | |
127 | { | |
128 | register struct buf *bp; | |
129 | struct disklabel *dlp; | |
130 | char *msg = NULL; | |
131 | ||
132 | if (lp->d_secperunit == 0) | |
133 | lp->d_secperunit = 0x1fffffff; | |
134 | lp->d_npartitions = 1; | |
135 | if (lp->d_partitions[0].p_size == 0) | |
136 | lp->d_partitions[0].p_size = 0x1fffffff; | |
137 | lp->d_partitions[0].p_offset = 0; | |
138 | ||
cd6cd535 | 139 | bp = geteblk(lp->d_secsize); |
9573c71c MK |
140 | bp->b_dev = dev; |
141 | bp->b_blkno = LABELSECTOR; | |
cd6cd535 | 142 | bp->b_bcount = lp->d_secsize; |
9573c71c MK |
143 | bp->b_flags = B_BUSY | B_READ; |
144 | bp->b_cylin = LABELSECTOR / lp->d_secpercyl; | |
145 | (*strat)(bp); | |
146 | biowait(bp); | |
147 | if (bp->b_flags & B_ERROR) { | |
148 | u.u_error = 0; /* XXX */ | |
149 | msg = "I/O error"; | |
cd6cd535 MK |
150 | } else for (dlp = (struct disklabel *)bp->b_un.b_addr; |
151 | dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp)); | |
152 | dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { | |
153 | if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { | |
154 | if (msg == NULL) | |
155 | msg = "no disk label"; | |
156 | } else if (dkcksum(dlp) != 0) | |
9573c71c | 157 | msg = "disk label corrupted"; |
cd6cd535 | 158 | else { |
9573c71c | 159 | *lp = *dlp; |
cd6cd535 MK |
160 | msg = NULL; |
161 | break; | |
162 | } | |
9573c71c | 163 | } |
cd6cd535 MK |
164 | if (lp->d_npartitions > MAXPARTITIONS) |
165 | lp->d_npartitions = MAXPARTITIONS; | |
9573c71c MK |
166 | bp->b_flags = B_INVAL | B_AGE; |
167 | brelse(bp); | |
168 | return (msg); | |
169 | } | |
170 | ||
97934dfa MK |
171 | /* |
172 | * Compute checksum for disk label. | |
173 | */ | |
174 | dkcksum(lp) | |
175 | register struct disklabel *lp; | |
176 | { | |
177 | register u_short *start, *end; | |
178 | register u_short sum = 0; | |
179 | ||
180 | start = (u_short *)lp; | |
181 | end = (u_short *)&lp->d_partitions[lp->d_npartitions]; | |
182 | while (start < end) | |
183 | sum ^= *start++; | |
184 | return (sum); | |
185 | } |