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