xref: /plan9/sys/src/cmd/dossrv/iotrack.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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