Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}