xref: /plan9/sys/src/cmd/disk/kfs/iobuf.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include	"all.h"
2 
3 #define	DEBUG	0
4 
5 long	niob;
6 long	nhiob;
7 Hiob	*hiob;
8 
9 Iobuf*
getbuf(Device dev,long addr,int flag)10 getbuf(Device dev, long addr, int flag)
11 {
12 	Iobuf *p, *s;
13 	Hiob *hp;
14 	long h;
15 
16 	if(DEBUG)
17 		print("getbuf %D(%ld) f=%x\n", dev, addr, flag);
18 	h = addr +
19 		dev.type*1009L +
20 		dev.ctrl*10007L +
21 		dev.unit*100003L +
22 		dev.part*1000003L;
23 	if(h < 0)
24 		h = ~h;
25 	h %= nhiob;
26 	hp = &hiob[h];
27 
28 loop:
29 	lock(hp);
30 
31 /*
32  * look for it in the active list
33  */
34 	s = hp->link;
35 	for(p=s;;) {
36 		if(p->addr == addr && !devcmp(p->dev, dev)) {
37 			if(p != s) {
38 				p->back->fore = p->fore;
39 				p->fore->back = p->back;
40 				p->fore = s;
41 				p->back = s->back;
42 				s->back = p;
43 				p->back->fore = p;
44 				hp->link = p;
45 			}
46 			unlock(hp);
47 			qlock(p);
48 			if(p->addr != addr || devcmp(p->dev, dev)) {
49 				qunlock(p);
50 				goto loop;
51 			}
52 			p->flags |= flag;
53 			cons.bhit.count++;
54 			p->iobuf = p->xiobuf;
55 			return p;
56 		}
57 		p = p->fore;
58 		if(p == s)
59 			break;
60 	}
61 	if(flag & Bprobe) {
62 		unlock(hp);
63 		return 0;
64 	}
65 
66 /*
67  * not found
68  * take oldest unlocked entry in this queue
69  */
70 xloop:
71 	p = s->back;
72 	if(!canqlock(p)) {
73 		if(p == hp->link) {
74 			unlock(hp);
75 			print("iobuf all locked\n");
76 			goto loop;
77 		}
78 		s = p;
79 		goto xloop;
80 	}
81 	/*
82 	 * its dangerous to flush the pseudo
83 	 * devices since they recursively call
84 	 * getbuf/putbuf. deadlock!
85 	 */
86 	if(p->flags & Bres) {
87 		qunlock(p);
88 		if(p == hp->link) {
89 			unlock(hp);
90 			print("iobuf all resed\n");
91 			goto loop;
92 		}
93 		s = p;
94 		goto xloop;
95 	}
96 	if(p->flags & Bmod) {
97 		unlock(hp);
98 		if(!devwrite(p->dev, p->addr, p->xiobuf))
99 			p->flags &= ~(Bimm|Bmod);
100 		qunlock(p);
101 		goto loop;
102 	}
103 	hp->link = p;
104 	p->addr = addr;
105 	p->dev = dev;
106 	p->flags = flag;
107 	unlock(hp);
108 	p->iobuf = p->xiobuf;
109 	if(flag & Bread) {
110 		if(devread(p->dev, p->addr, p->iobuf)) {
111 			p->flags = 0;
112 			p->dev = devnone;
113 			p->addr = -1;
114 			p->iobuf = (char*)-1;
115 			qunlock(p);
116 			return 0;
117 		}
118 		cons.bread.count++;
119 		return p;
120 	}
121 	cons.binit.count++;
122 	return p;
123 }
124 
125 /*
126  * syncblock tries to put out a block per hashline
127  * returns 0 all done,
128  * returns 1 if it missed something
129  */
130 int
syncblock(void)131 syncblock(void)
132 {
133 	Iobuf *p, *s, *q;
134 	Hiob *hp;
135 	long h;
136 	int flag;
137 
138 	flag = 0;
139 	for(h=0; h<nhiob; h++) {
140 		q = 0;
141 		hp = &hiob[h];
142 		lock(hp);
143 		s = hp->link;
144 		for(p=s;;) {
145 			if(p->flags & Bmod) {
146 				if(q)
147 					flag = 1;	/* more than 1 mod/line */
148 				q = p;
149 			}
150 			p = p->fore;
151 			if(p == s)
152 				break;
153 		}
154 		unlock(hp);
155 		if(q) {
156 			if(!canqlock(q)) {
157 				flag = 1;		/* missed -- was locked */
158 				continue;
159 			}
160 			if(!(q->flags & Bmod)) {
161 				qunlock(q);
162 				continue;
163 			}
164 			if(!devwrite(q->dev, q->addr, q->xiobuf))
165 				q->flags &= ~(Bmod|Bimm);
166 			qunlock(q);
167 		}
168 	}
169 	return flag;
170 }
171 
172 void
sync(char * reason)173 sync(char *reason)
174 {
175 	long i;
176 
177 	print("sync: %s\n", reason);
178 	for(i=10*nhiob; i>0; i--)
179 		if(!syncblock())
180 			return;
181 	print("sync shorted\n");
182 }
183 
184 void
putbuf(Iobuf * p)185 putbuf(Iobuf *p)
186 {
187 	if(canqlock(p))
188 		print("buffer not locked %D(%ld)\n", p->dev, p->addr);
189 	if(p->flags & Bimm) {
190 		if(!(p->flags & Bmod))
191 			print("imm and no mod %D(%ld)\n", p->dev, p->addr);
192 		if(!devwrite(p->dev, p->addr, p->iobuf))
193 			p->flags &= ~(Bmod|Bimm);
194 	}
195 	p->iobuf = (char*)-1;
196 	qunlock(p);
197 }
198 
199 int
checktag(Iobuf * p,int tag,long qpath)200 checktag(Iobuf *p, int tag, long qpath)
201 {
202 	Tag *t;
203 
204 	t = (Tag*)(p->iobuf+BUFSIZE);
205 	if(t->tag != tag) {
206 		if(1 || CHAT(0))
207 			print("	tag = %G; expected %G; addr = %lud\n",
208 				t->tag, tag, p->addr);
209 		return 2;
210 	}
211 	if(qpath != QPNONE) {
212 		qpath &= ~QPDIR;
213 		if(qpath != t->path) {
214 			if(qpath == (t->path&~QPDIR))	/* old bug */
215 				return 0;
216 			if(1 || CHAT(0))
217 				print("	tag/path = %lux; expected %G/%lux\n",
218 					t->path, tag, qpath);
219 			return 1;
220 		}
221 	}
222 	return 0;
223 }
224 
225 void
settag(Iobuf * p,int tag,long qpath)226 settag(Iobuf *p, int tag, long qpath)
227 {
228 	Tag *t;
229 
230 	t = (Tag*)(p->iobuf+BUFSIZE);
231 	t->tag = tag;
232 	if(qpath != QPNONE)
233 		t->path = qpath & ~QPDIR;
234 	p->flags |= Bmod;
235 }
236