1 #include <u.h>
2 #include <libc.h>
3 #include "iotrack.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 #define HIOB 31 /* a prime */
8 #define NIOBUF 80
9
10 static Iotrack hiob[HIOB+1]; /* hash buckets + lru list */
11 static Iotrack iobuf[NIOBUF]; /* the real ones */
12
13 #define UNLINK(p, nx, pr) ((p)->pr->nx = (p)->nx, (p)->nx->pr = (p)->pr)
14
15 #define LINK(h, p, nx, pr) ((p)->nx = (h)->nx, (p)->pr = (h), \
16 (h)->nx->pr = (p), (h)->nx = (p))
17
18 #define HTOFRONT(h, p) ((h)->hnext != (p) && (UNLINK(p,hnext,hprev), LINK(h,p,hnext,hprev)))
19
20 #define TOFRONT(h, p) ((h)->next != (p) && (UNLINK(p, next, prev), LINK(h,p, next, prev)))
21
22 Iosect *
getsect(Xfs * xf,long addr)23 getsect(Xfs *xf, long addr)
24 {
25 return getiosect(xf, addr, 1);
26 }
27
28 Iosect *
getosect(Xfs * xf,long addr)29 getosect(Xfs *xf, long addr)
30 {
31 return getiosect(xf, addr, 0);
32 }
33
34 Iosect *
getiosect(Xfs * xf,long addr,int rflag)35 getiosect(Xfs *xf, long addr, int rflag)
36 {
37 Iotrack *t;
38 long taddr;
39 int toff;
40 Iosect *p;
41
42 toff = addr % Sect2trk;
43 taddr = addr - toff;
44 t = getiotrack(xf, taddr);
45 if(rflag && (t->flags&BSTALE)){
46 if(tread(t) < 0){
47 unmlock(&t->lock);
48 return 0;
49 }
50 t->flags &= ~BSTALE;
51 }
52 t->ref++;
53 p = t->tp->p[toff];
54 if(p == 0){
55 p = newsect();
56 t->tp->p[toff] = p;
57 p->flags = t->flags&BSTALE;
58 p->lock.key = 0;
59 p->t = t;
60 p->iobuf = t->tp->buf[toff];
61 }
62 unmlock(&t->lock);
63 mlock(&p->lock);
64 return p;
65 }
66
67 void
putsect(Iosect * p)68 putsect(Iosect *p)
69 {
70 Iotrack *t;
71
72 if(canmlock(&p->lock))
73 panic("putsect");
74 t = p->t;
75 mlock(&t->lock);
76 t->flags |= p->flags;
77 p->flags = 0;
78 t->ref--;
79 if(t->flags & BIMM){
80 if(t->flags & BMOD)
81 twrite(t);
82 t->flags &= ~(BMOD|BIMM);
83 }
84 unmlock(&t->lock);
85 unmlock(&p->lock);
86 }
87
88 Iotrack *
getiotrack(Xfs * xf,long addr)89 getiotrack(Xfs *xf, long addr)
90 {
91 Iotrack *hp, *p;
92 Iotrack *mp = &hiob[HIOB];
93 long h;
94 /*
95 * chat("iotrack %d,%d...", dev, addr);
96 */
97 h = (xf->dev<<24) ^ addr;
98 if(h < 0)
99 h = ~h;
100 h %= HIOB;
101 hp = &hiob[h];
102
103 loop:
104
105 /*
106 * look for it in the active list
107 */
108 mlock(&hp->lock);
109 for(p=hp->hnext; p != hp; p=p->hnext){
110 if(p->addr != addr || p->xf != xf)
111 continue;
112 unmlock(&hp->lock);
113 mlock(&p->lock);
114 if(p->addr == addr && p->xf == xf)
115 goto out;
116 unmlock(&p->lock);
117 goto loop;
118 }
119 unmlock(&hp->lock);
120 /*
121 * not found
122 * take oldest unref'd entry
123 */
124 mlock(&mp->lock);
125 for(p=mp->prev; p != mp; p=p->prev)
126 if(p->ref == 0 && canmlock(&p->lock)){
127 if(p->ref == 0)
128 break;
129 unmlock(&p->lock);
130 }
131 unmlock(&mp->lock);
132 if(p == mp){
133 print("iotrack all ref'd\n");
134 goto loop;
135 }
136 if(p->flags & BMOD){
137 twrite(p);
138 p->flags &= ~(BMOD|BIMM);
139 unmlock(&p->lock);
140 goto loop;
141 }
142 purgetrack(p);
143 p->addr = addr;
144 p->xf = xf;
145 p->flags = BSTALE;
146 out:
147 mlock(&hp->lock);
148 HTOFRONT(hp, p);
149 unmlock(&hp->lock);
150 mlock(&mp->lock);
151 TOFRONT(mp, p);
152 unmlock(&mp->lock);
153 return p;
154 }
155
156 void
purgetrack(Iotrack * t)157 purgetrack(Iotrack *t)
158 {
159 int i, ref = Sect2trk;
160 Iosect *p;
161
162 for(i=0; i<Sect2trk; i++){
163 p = t->tp->p[i];
164 if(p == 0){
165 --ref;
166 continue;
167 }
168 if(canmlock(&p->lock)){
169 freesect(p);
170 --ref;
171 t->tp->p[i] = 0;
172 }
173 }
174 if(t->ref != ref)
175 panic("purgetrack");
176 }
177
178 int
twrite(Iotrack * t)179 twrite(Iotrack *t)
180 {
181 int i, ref;
182
183 chat("[twrite %ld...", t->addr);
184 if(t->flags & BSTALE){
185 for(ref=0,i=0; i<Sect2trk; i++)
186 if(t->tp->p[i])
187 ++ref;
188 if(ref < Sect2trk){
189 if(tread(t) < 0){
190 chat("error]");
191 return -1;
192 }
193 }else
194 t->flags &= ~BSTALE;
195 }
196 if(devwrite(t->xf, t->addr, t->tp->buf, Trksize) < 0){
197 chat("error]");
198 return -1;
199 }
200 chat(" done]");
201 return 0;
202 }
203
204 int
tread(Iotrack * t)205 tread(Iotrack *t)
206 {
207 int i, ref = 0;
208 uchar buf[Sect2trk][Sectorsize];
209
210 for(i=0; i<Sect2trk; i++)
211 if(t->tp->p[i])
212 ++ref;
213 chat("[tread %ld+%ld...", t->addr, t->xf->offset);
214 if(ref == 0){
215 if(devread(t->xf, t->addr, t->tp->buf, Trksize) < 0){
216 chat("error]");
217 return -1;
218 }
219 chat("done]");
220 t->flags &= ~BSTALE;
221 return 0;
222 }
223 if(devread(t->xf, t->addr, buf, Trksize) < 0){
224 chat("error]");
225 return -1;
226 }
227 for(i=0; i<Sect2trk; i++)
228 if(t->tp->p[i] == 0){
229 memmove(t->tp->buf[i], buf[i], Sectorsize);
230 chat("%d ", i);
231 }
232 chat("done]");
233 t->flags &= ~BSTALE;
234 return 0;
235 }
236
237 void
purgebuf(Xfs * xf)238 purgebuf(Xfs *xf)
239 {
240 Iotrack *p;
241
242 for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){
243 if(p->xf != xf)
244 continue;
245 mlock(&p->lock);
246 if(p->xf == xf){
247 if(p->flags & BMOD)
248 twrite(p);
249 p->flags = BSTALE;
250 purgetrack(p);
251 }
252 unmlock(&p->lock);
253 }
254 }
255
256 void
sync(void)257 sync(void)
258 {
259 Iotrack *p;
260
261 for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){
262 if(!(p->flags & BMOD))
263 continue;
264 mlock(&p->lock);
265 if(p->flags & BMOD){
266 twrite(p);
267 p->flags &= ~(BMOD|BIMM);
268 }
269 unmlock(&p->lock);
270 }
271 }
272
273 void
iotrack_init(void)274 iotrack_init(void)
275 {
276 Iotrack *mp, *p;
277
278 for (mp=&hiob[0]; mp<&hiob[HIOB]; mp++)
279 mp->hprev = mp->hnext = mp;
280 mp->prev = mp->next = mp;
281
282 for (p=&iobuf[0]; p<&iobuf[NIOBUF]; p++) {
283 p->hprev = p->hnext = p;
284 p->prev = p->next = p;
285 TOFRONT(mp, p);
286 p->tp = sbrk(sizeof(Track));
287 memset(p->tp->p, 0, sizeof p->tp->p);
288 }
289 }
290
291 static MLock freelock;
292 static Iosect * freelist;
293
294 Iosect *
newsect(void)295 newsect(void)
296 {
297 Iosect *p;
298
299 mlock(&freelock);
300 if(p = freelist) /* assign = */
301 freelist = p->next;
302 else
303 p = malloc(sizeof(Iosect));
304 unmlock(&freelock);
305 p->next = 0;
306 return p;
307 }
308
309 void
freesect(Iosect * p)310 freesect(Iosect *p)
311 {
312 mlock(&freelock);
313 p->next = freelist;
314 freelist = p;
315 unmlock(&freelock);
316 }
317