xref: /plan9/sys/src/cmd/cwfs/iobuf.c (revision 223a035810d484657ee1a815f68faa8211009d6d)
1 #include	"all.h"
2 #include	"io.h"
3 
4 enum { DEBUG = 0 };
5 
6 extern	long nhiob;
7 extern	Hiob *hiob;
8 
9 Iobuf*
getbuf(Device * d,Off addr,int flag)10 getbuf(Device *d, Off addr, int flag)
11 {
12 	Iobuf *p, *s;
13 	Hiob *hp;
14 	Off h;
15 
16 	if(DEBUG)
17 		print("getbuf %Z(%lld) f=%x\n", d, (Wideoff)addr, flag);
18 	h = addr + (Off)(uintptr)d*1009;
19 	if(h < 0)
20 		h = ~h;
21 	h %= nhiob;
22 	hp = &hiob[h];
23 
24 loop:
25 	lock(hp);
26 
27 /*
28  * look for it in the active list
29  */
30 	s = hp->link;
31 	for(p=s;;) {
32 		if(p->addr == addr && p->dev == d) {
33 			if(p != s) {
34 				p->back->fore = p->fore;
35 				p->fore->back = p->back;
36 				p->fore = s;
37 				p->back = s->back;
38 				s->back = p;
39 				p->back->fore = p;
40 				hp->link = p;
41 			}
42 			unlock(hp);
43 			qlock(p);
44 			if(p->addr != addr || p->dev != d || iobufmap(p) == 0) {
45 				qunlock(p);
46 				goto loop;
47 			}
48 			p->flags |= flag;
49 			return p;
50 		}
51 		p = p->fore;
52 		if(p == s)
53 			break;
54 	}
55 	if(flag & Bprobe) {
56 		unlock(hp);
57 		return 0;
58 	}
59 
60 /*
61  * not found
62  * take oldest unlocked entry in this queue
63  */
64 xloop:
65 	p = s->back;
66 	if(!canqlock(p)) {
67 		if(p == hp->link) {
68 			unlock(hp);
69 			print("iobuf all locked\n");
70 			goto loop;
71 		}
72 		s = p;
73 		goto xloop;
74 	}
75 
76 	/*
77 	 * its dangerous to flush the pseudo
78 	 * devices since they recursively call
79 	 * getbuf/putbuf. deadlock!
80 	 */
81 	if(p->flags & Bres) {
82 		qunlock(p);
83 		if(p == hp->link) {
84 			unlock(hp);
85 			print("iobuf all reserved\n");
86 			goto loop;
87 		}
88 		s = p;
89 		goto xloop;
90 	}
91 	if(p->flags & Bmod) {
92 		unlock(hp);
93 		if(iobufmap(p)) {
94 			if(!devwrite(p->dev, p->addr, p->iobuf))
95 				p->flags &= ~(Bimm|Bmod);
96 			iobufunmap(p);
97 		}
98 		qunlock(p);
99 		goto loop;
100 	}
101 	hp->link = p;
102 	p->addr = addr;
103 	p->dev = d;
104 	p->flags = flag;
105 //	p->pc = getcallerpc(&d);
106 	unlock(hp);
107 	if(iobufmap(p))
108 		if(flag & Brd) {
109 			if(!devread(p->dev, p->addr, p->iobuf))
110 				return p;
111 			iobufunmap(p);
112 		} else
113 			return p;
114 	else
115 		print("iobuf cant map buffer\n");
116 	p->flags = 0;
117 	p->dev = devnone;
118 	p->addr = -1;
119 	qunlock(p);
120 	return 0;
121 }
122 
123 /*
124  * syncblock tries to put out a block per hashline
125  * returns 0 all done,
126  * returns 1 if it missed something
127  */
128 int
syncblock(void)129 syncblock(void)
130 {
131 	Iobuf *p, *s, *q;
132 	Hiob *hp;
133 	long h;
134 	int flag;
135 
136 	flag = 0;
137 	for(h=0; h<nhiob; h++) {
138 		q = 0;
139 		hp = &hiob[h];
140 		lock(hp);
141 		s = hp->link;
142 		for(p=s;;) {
143 			if(p->flags & Bmod) {
144 				if(q)
145 					flag = 1;	/* more than 1 mod/line */
146 				q = p;
147 			}
148 			p = p->fore;
149 			if(p == s)
150 				break;
151 		}
152 		unlock(hp);
153 		if(q) {
154 			if(!canqlock(q)) {
155 				flag = 1;		/* missed -- was locked */
156 				continue;
157 			}
158 			if(!(q->flags & Bmod)) {
159 				qunlock(q);
160 				continue;
161 			}
162 			if(iobufmap(q)) {
163 				if(!devwrite(q->dev, q->addr, q->iobuf))
164 					q->flags &= ~(Bmod|Bimm);
165 				iobufunmap(q);
166 			} else
167 				flag = 1;
168 			qunlock(q);
169 		}
170 	}
171 	return flag;
172 }
173 
174 void
sync(char * reason)175 sync(char *reason)
176 {
177 	long i;
178 
179 	print("sync: %s\n", reason);
180 	for(i=10*nhiob; i>0; i--)
181 		if(!syncblock())
182 			return;
183 	print("sync shorted\n");
184 }
185 
186 void
putbuf(Iobuf * p)187 putbuf(Iobuf *p)
188 {
189 
190 	if(canqlock(p))
191 		print("buffer not locked %Z(%lld)\n", p->dev, (Wideoff)p->addr);
192 	if(p->flags & Bimm) {
193 		if(!(p->flags & Bmod))
194 			print("imm and no mod %Z(%lld)\n",
195 				p->dev, (Wideoff)p->addr);
196 		if(!devwrite(p->dev, p->addr, p->iobuf))
197 			p->flags &= ~(Bmod|Bimm);
198 	}
199 	iobufunmap(p);
200 	qunlock(p);
201 }
202 
203 int
checktag(Iobuf * p,int tag,Off qpath)204 checktag(Iobuf *p, int tag, Off qpath)
205 {
206 	Tag *t;
207 	static Off lastaddr;
208 
209 	t = (Tag*)(p->iobuf+BUFSIZE);
210 	if(t->tag != tag) {
211 		if(p->flags & Bmod) {
212 			print("\ttag = %d/%llud; expected %lld/%d -- not flushed\n",
213 				t->tag, (Wideoff)t->path, (Wideoff)qpath, tag);
214 			return 2;
215 		}
216 		if(p->dev != nil && p->dev->type == Devcw)
217 			cwfree(p->dev, p->addr);
218 		if(p->addr != lastaddr)
219 			print("\ttag = %G/%llud; expected %G/%lld -- flushed (%lld)\n",
220 				t->tag, (Wideoff)t->path, tag, (Wideoff)qpath,
221 				(Wideoff)p->addr);
222 		lastaddr = p->addr;
223 		p->dev = devnone;
224 		p->addr = -1;
225 		p->flags = 0;
226 		return 2;
227 	}
228 	if(qpath != QPNONE) {
229 		if((qpath ^ t->path) & ~QPDIR) {
230 			if(1 || CHAT(0))
231 				print("\ttag/path = %llud; expected %d/%llux\n",
232 					(Wideoff)t->path, tag, (Wideoff)qpath);
233 			return 0;
234 		}
235 	}
236 	return 0;
237 }
238 
239 void
settag(Iobuf * p,int tag,long qpath)240 settag(Iobuf *p, int tag, long qpath)
241 {
242 	Tag *t;
243 
244 	t = (Tag*)(p->iobuf+BUFSIZE);
245 	t->tag = tag;
246 	if(qpath != QPNONE)
247 		t->path = qpath & ~QPDIR;
248 	p->flags |= Bmod;
249 }
250 
251 int
qlmatch(QLock * q1,QLock * q2)252 qlmatch(QLock *q1, QLock *q2)
253 {
254 
255 	return q1 == q2;
256 }
257 
258 int
iobufql(QLock * q)259 iobufql(QLock *q)
260 {
261 	Iobuf *p, *s;
262 	Hiob *hp;
263 	Tag *t;
264 	long h;
265 	int tag;
266 
267 	for(h=0; h<nhiob; h++) {
268 		hp = &hiob[h];
269 		lock(hp);
270 		s = hp->link;
271 		for(p=s;;) {
272 			if(qlmatch(q, p)) {
273 				t = (Tag*)(p->iobuf+BUFSIZE);
274 				tag = t->tag;
275 				if(tag < 0 || tag >= MAXTAG)
276 					tag = Tnone;
277 				print("\tIobuf %Z(%lld) t=%s\n",
278 					p->dev, (Wideoff)p->addr, tagnames[tag]);
279 				unlock(hp);
280 				return 1;
281 			}
282 			p = p->fore;
283 			if(p == s)
284 				break;
285 		}
286 		unlock(hp);
287 	}
288 	return 0;
289 }
290