]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/dossrv/iotrack.c
Import sources from 2011-03-30 iso image
[plan9front.git] / sys / src / cmd / dossrv / iotrack.c
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 *
23 getsect(Xfs *xf, long addr)
24 {
25         return getiosect(xf, addr, 1);
26 }
27
28 Iosect *
29 getosect(Xfs *xf, long addr)
30 {
31         return getiosect(xf, addr, 0);
32 }
33
34 Iosect *
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
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 *
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
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
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
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
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
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
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 *
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
310 freesect(Iosect *p)
311 {
312         mlock(&freelock);
313         p->next = freelist;
314         freelist = p;
315         unmlock(&freelock);
316 }