]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hjfs/buf.c
grep: error if sbrk fails
[plan9front.git] / sys / src / cmd / hjfs / buf.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 Channel *getb, *putb, *syncb;
8 Buf bfree;
9 BufReq *freereq, *freereqlast;
10
11 static void
12 markbusy(Buf *b)
13 {
14         b->busy = 1;
15         if(b->fnext != nil){
16                 b->fnext->fprev = b->fprev;
17                 b->fprev->fnext = b->fnext;
18                 b->fnext = b->fprev = nil;
19         }
20 }
21
22 static void
23 markfree(Buf *b)
24 {
25         b->busy = 0;
26         b->fnext = &bfree;
27         b->fprev = bfree.fprev;
28         b->fnext->fprev = b;
29         b->fprev->fnext = b;
30 }
31
32 static void
33 changedev(Buf *b, Dev *d, uvlong off)
34 {
35         if(b->dnext != nil){
36                 b->dnext->dprev = b->dprev;
37                 b->dprev->dnext = b->dnext;
38                 b->dprev = nil;
39                 b->dnext = nil;
40         }
41         b->off = off;
42         b->d = d;
43         if(d != nil){
44                 b->dnext = &d->buf[b->off & BUFHASH];
45                 b->dprev = b->dnext->dprev;
46                 b->dnext->dprev = b;
47                 b->dprev->dnext = b;
48         }
49 }
50
51 static void
52 delayreq(BufReq req, BufReq **first, BufReq **last)
53 {
54         BufReq *r;
55
56         r = emalloc(sizeof(*r));
57         *r = req;
58         r->next = nil;
59         if(*first == nil)
60                 *first = r;
61         else
62                 (*last)->next = r;
63         *last = r;
64 }
65
66 static BufReq
67 undelayreq(BufReq **first, BufReq **last)
68 {
69         BufReq r;
70         
71         r = **first;
72         free(*first);
73         *first = r.next;
74         if(r.next == nil)
75                 *last = nil;
76         return r;
77 }
78
79 static void
80 work(Dev *d, Buf *b)
81 {
82         qlock(&d->workl);
83         b->wnext = &d->work;
84         b->wprev = b->wnext->wprev;
85         b->wnext->wprev = b;
86         b->wprev->wnext = b;
87         rwakeup(&d->workr);
88         qunlock(&d->workl);
89 }
90
91 static void
92 givebuf(BufReq req, Buf *b)
93 {
94         Buf *c, *l;
95
96 again:
97         if(req.d == b->d && req.off == b->off){
98                 markbusy(b);
99                 send(req.resp, &b);
100                 return;
101         }
102         l = &req.d->buf[req.off & BUFHASH];
103         for(c = l->dnext; c != l; c = c->dnext)
104                 if(c->off == req.off){
105                         if(c->busy)
106                                 delayreq(req, &c->next, &c->last);
107                         else{
108                                 markbusy(c);
109                                 send(req.resp, &c);
110                         }
111                         if(b->next == nil)
112                                 return;
113                         req = undelayreq(&b->next, &b->last);
114                         goto again;
115                 }
116         if(b->next != nil){
117                 givebuf(undelayreq(&b->next, &b->last), b);
118                 b = bfree.fnext;
119         }
120         if(b == &bfree){
121                 delayreq(req, &freereq, &freereqlast);
122                 return;
123         }
124         markbusy(b);
125         if(b->d != nil && b->op & BDELWRI){
126                 delayreq(req, &b->next, &b->last);
127                 b->op &= ~BDELWRI;
128                 b->op |= BWRITE;
129                 b->resp = putb;
130                 work(b->d, b);
131                 return;
132         }
133         changedev(b, req.d, req.off);
134         b->op &= ~(BWRITE|BDELWRI|BWRIM);
135         if(req.nodata)
136                 send(req.resp, &b);
137         else{
138                 b->resp = req.resp;
139                 work(b->d, b);
140         }
141 }
142
143 static void
144 handleget(BufReq req)
145 {
146         givebuf(req, bfree.fnext);
147 }
148
149 static void
150 handleput(Buf *b)
151 {
152         if(b->op & BWRIM){
153                 b->op &= ~(BWRIM | BDELWRI);
154                 b->op |= BWRITE;
155                 b->resp = putb;
156                 work(b->d, b);
157                 return;
158         }
159         if(b->error != nil){
160                 b->error = nil;
161                 b->op &= ~BDELWRI;
162                 changedev(b, nil, -1);
163         }
164         b->op &= ~BWRITE;
165         markfree(b);
166         if(b->next != nil)
167                 givebuf(undelayreq(&b->next, &b->last), b);
168         else if(freereq != nil)
169                 givebuf(undelayreq(&freereq, &freereqlast), b);
170 }
171
172 static void
173 handlesync(Channel *resp)
174 {
175         Buf *b, *c;
176
177         for(b = bfree.fnext; b != &bfree; b = c){
178                 c = b->fnext;
179                 if(b->d != nil && b->op & BDELWRI){
180                         markbusy(b);
181                         b->resp = putb;
182                         b->op &= ~BDELWRI;
183                         b->op |= BWRITE;
184                         work(b->d, b);
185                 }
186         }
187         if(resp != nil)
188                 sendp(resp, nil);
189 }
190
191 static void
192 bufproc(void *)
193 {
194         BufReq req;
195         Buf *buf;
196         Channel *r;
197         Alt a[] = {{getb, &req, CHANRCV}, {putb, &buf, CHANRCV}, {syncb, &r, CHANRCV}, {nil, nil, CHANEND}};
198
199         workerinit();
200         for(;;)
201                 switch(alt(a)){
202                 case 0:
203                         handleget(req);
204                         break;
205                 case 1:
206                         handleput(buf);
207                         break;
208                 case 2:
209                         handlesync(r);
210                         break;
211                 case -1:
212                         sysfatal("alt: %r");
213                 }
214 }
215
216 static char *
217 typenames[] = {
218         [TRAW] "raw",
219         [TSUPERBLOCK] "superblock",
220         [TDENTRY] "dentry",
221         [TINDIR] "indir",
222         [TREF] "ref",
223         nil
224 };
225
226 static int
227 Tfmt(Fmt *f)
228 {
229         int t;
230         
231         t = va_arg(f->args, uint);
232         if(t >= nelem(typenames) || typenames[t] == nil)
233                 return fmtprint(f, "??? (%d)", t);
234         return fmtstrcpy(f, typenames[t]);
235 }
236
237 void
238 bufinit(int nbuf)
239 {
240         Buf *b;
241
242         fmtinstall('T', Tfmt);
243         b = emalloc(sizeof(*b) * nbuf);
244         bfree.fnext = bfree.fprev = &bfree;
245         while(nbuf--)
246                 markfree(b++);
247         getb = chancreate(sizeof(BufReq), 0);
248         putb = chancreate(sizeof(Buf *), 32);
249         syncb = chancreate(sizeof(void*), 0);
250         proccreate(bufproc, nil, mainstacksize);
251 }
252
253 Buf *
254 getbuf(Dev *d, uvlong off, int type, int nodata)
255 {
256         ThrData *th;
257         BufReq req;
258         Buf *b;
259
260         if(off >= d->size)
261                 abort();
262         th = getthrdata();
263         req.d = d;
264         req.off = off;
265         req.resp = th->resp;
266         req.nodata = nodata;
267         send(getb, &req);
268         recv(th->resp, &b);
269         if(b->error != nil){
270                 werrstr("%s", b->error);
271                 putbuf(b);
272                 return nil;
273         }
274         if(nodata)
275                 b->type = type;
276         if(b->type != type && type != TDONTCARE){
277                 dprint("type mismatch, dev %s, block %lld, got %T, want %T, caller %#p\n",
278                         d->name, off, b->type, type, getcallerpc(&d));
279                 werrstr("phase error -- type mismatch");
280                 putbuf(b);
281                 return nil;
282         }
283         b->callerpc = getcallerpc(&d);
284         return b;
285 }
286
287 void
288 putbuf(Buf *b)
289 {
290         send(putb, &b);
291 }
292
293 void
294 sync(int wait)
295 {
296         Channel *r;
297         Dev *d;
298         Buf b;
299
300         r = nil;
301         if(wait)
302                 r = getthrdata()->resp;
303         sendp(syncb, r);
304         memset(&b, 0, sizeof(Buf));
305         if(wait){
306                 recvp(r);
307                 for(d = devs; d != nil; d = d->next){
308                         b.d = nil;
309                         b.resp = r;
310                         b.busy = 1;
311                         work(d, &b);
312                         recvp(r);
313                 }
314         }
315 }