xref: /plan9-contrib/sys/src/cmd/dossrv/iotrack.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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)) : 0)
19 
20 #define	TOFRONT(h, p)	((h)->next  != (p) ? (UNLINK(p, next, prev), LINK(h,p, next, prev)) : 0)
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 			unlock(&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 	unlock(&t->lock);
63 	lock(&p->lock);
64 	return p;
65 }
66 
67 void
68 putsect(Iosect *p)
69 {
70 	Iotrack *t;
71 
72 	if(canlock(&p->lock))
73 		panic("putsect");
74 	t = p->t;
75 	lock(&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 	unlock(&t->lock);
85 	unlock(&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 	lock(&hp->lock);
109 	for(p=hp->hnext; p != hp; p=p->hnext){
110 		if(p->addr != addr || p->xf != xf)
111 			continue;
112 		unlock(&hp->lock);
113 		lock(&p->lock);
114 		if(p->addr == addr && p->xf == xf)
115 			goto out;
116 		unlock(&p->lock);
117 		goto loop;
118 	}
119 	unlock(&hp->lock);
120 /*
121  * not found
122  * take oldest unref'd entry
123  */
124 	lock(&mp->lock);
125 	for(p=mp->prev; p != mp; p=p->prev)
126 		if(p->ref == 0 && canlock(&p->lock)){
127 			if(p->ref == 0)
128 				break;
129 			unlock(&p->lock);
130 		}
131 	unlock(&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 		unlock(&p->lock);
140 		goto loop;
141 	}
142 	purgetrack(p);
143 	p->addr = addr;
144 	p->xf = xf;
145 	p->flags = BSTALE;
146 out:
147 	lock(&hp->lock); HTOFRONT(hp, p); unlock(&hp->lock);
148 	lock(&mp->lock); TOFRONT(mp, p); unlock(&mp->lock);
149 	return p;
150 }
151 
152 void
153 purgetrack(Iotrack *t)
154 {
155 	int i, ref = Sect2trk;
156 	Iosect *p;
157 
158 	for(i=0; i<Sect2trk; i++){
159 		p = t->tp->p[i];
160 		if(p == 0){
161 			--ref;
162 			continue;
163 		}
164 		if(canlock(&p->lock)){
165 			freesect(p);
166 			--ref;
167 			t->tp->p[i] = 0;
168 		}
169 	}
170 	if(t->ref != ref)
171 		panic("purgetrack");
172 }
173 
174 int
175 twrite(Iotrack *t)
176 {
177 	int i, ref;
178 
179 	chat("[twrite %d...", t->addr);
180 	if(t->flags & BSTALE){
181 		for(ref=0,i=0; i<Sect2trk; i++)
182 			if(t->tp->p[i])
183 				++ref;
184 		if(ref < Sect2trk){
185 			if(tread(t) < 0){
186 				chat("error]");
187 				return -1;
188 			}
189 		}else
190 			t->flags &= ~BSTALE;
191 	}
192 	if(devwrite(t->xf, t->addr, t->tp->buf, Trksize) < 0){
193 		chat("error]");
194 		return -1;
195 	}
196 	chat(" done]");
197 	return 0;
198 }
199 
200 int
201 tread(Iotrack *t)
202 {
203 	int i, ref = 0;
204 	uchar buf[Sect2trk][Sectorsize];
205 
206 	for(i=0; i<Sect2trk; i++)
207 		if(t->tp->p[i])
208 			++ref;
209 	chat("[tread %d...", t->addr);
210 	if(ref == 0){
211 		if(devread(t->xf, t->addr, t->tp->buf, Trksize) < 0){
212 			chat("error]");
213 			return -1;
214 		}
215 		chat("done]");
216 		t->flags &= ~BSTALE;
217 		return 0;
218 	}
219 	if(devread(t->xf, t->addr, buf, Trksize) < 0){
220 		chat("error]");
221 		return -1;
222 	}
223 	for(i=0; i<Sect2trk; i++)
224 		if(t->tp->p[i] == 0){
225 			memmove(t->tp->buf[i], buf[i], Sectorsize);
226 			chat("%d ", i);
227 		}
228 	chat("done]");
229 	t->flags &= ~BSTALE;
230 	return 0;
231 }
232 
233 void
234 purgebuf(Xfs *xf)
235 {
236 	Iotrack *p;
237 
238 	for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){
239 		if(p->xf != xf)
240 			continue;
241 		lock(&p->lock);
242 		if(p->xf == xf){
243 			if(p->flags & BMOD)
244 				twrite(p);
245 			p->flags = BSTALE;
246 			purgetrack(p);
247 		}
248 		unlock(&p->lock);
249 	}
250 }
251 
252 void
253 sync(void)
254 {
255 	Iotrack *p;
256 
257 	for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++){
258 		if(!(p->flags & BMOD))
259 			continue;
260 		lock(&p->lock);
261 		if(p->flags & BMOD){
262 			twrite(p);
263 			p->flags &= ~(BMOD|BIMM);
264 		}
265 		unlock(&p->lock);
266 	}
267 }
268 
269 void
270 iotrack_init(void)
271 {
272 	Iotrack *mp, *p;
273 
274 	for (mp=&hiob[0]; mp<&hiob[HIOB]; mp++)
275 		mp->hprev = mp->hnext = mp;
276 	mp->prev = mp->next = mp;
277 
278 	for (p=&iobuf[0]; p<&iobuf[NIOBUF]; p++) {
279 		p->hprev = p->hnext = p;
280 		p->prev = p->next = p;
281 		TOFRONT(mp, p);
282 		p->tp = sbrk(sizeof(Track));
283 		memset(p->tp->p, 0, sizeof p->tp->p);
284 	}
285 }
286 
287 static Lock	freelock;
288 static Iosect *	freelist;
289 
290 Iosect *
291 newsect(void)
292 {
293 	Iosect *p;
294 
295 	lock(&freelock);
296 	if(p = freelist)	/* assign = */
297 		freelist = p->next;
298 	else
299 		p = malloc(sizeof(Iosect));
300 	unlock(&freelock);
301 	p->next = 0;
302 	return p;
303 }
304 
305 void
306 freesect(Iosect *p)
307 {
308 	lock(&freelock);
309 	p->next = freelist;
310 	freelist = p;
311 	unlock(&freelock);
312 }
313