]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hjfs/buf.c
hjfs: disable shutdown when listening on network connections
[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         memcpy(r, &req, sizeof(*r));
58         r->next = nil;
59         if(*first == nil)
60                 *first = *last = r;
61         else{
62                 (*last)->next = r;
63                 *last = r;
64         }
65 }
66
67 static void
68 work(Dev *d, Buf *b)
69 {
70         qlock(&d->workl);
71         b->wnext = &d->work;
72         b->wprev = b->wnext->wprev;
73         b->wnext->wprev = b;
74         b->wprev->wnext = b;
75         rwakeup(&d->workr);
76         qunlock(&d->workl);
77 }
78
79 static void
80 givebuf(BufReq req, Buf *b)
81 {
82         Buf *c, *l;
83
84         markbusy(b);
85         if(req.d == b->d && req.off == b->off){
86                 send(req.resp, &b);
87                 return;
88         }
89         if(b->op & BDELWRI){
90                 b->op &= ~BDELWRI;
91                 b->op |= BWRITE;
92                 delayreq(req, &b->next, &b->last);
93                 b->resp = putb;
94                 work(b->d, b);
95                 return;
96         }
97         l = &req.d->buf[req.off & BUFHASH];
98         for(c = l->dnext; c != l; c = c->dnext)
99                 if(c->off == req.off)
100                         abort();
101         changedev(b, req.d, req.off);
102         b->op &= ~(BWRITE|BDELWRI|BWRIM);
103         if(req.nodata)
104                 send(req.resp, &b);
105         else{
106                 b->resp = req.resp;
107                 work(b->d, b);
108         }
109 }
110
111 static void
112 undelayreq(Buf *b, BufReq **first, BufReq **last)
113 {
114         BufReq *r;
115         
116         r = *first;
117         *first = r->next;
118         if(*last == r)
119                 *last = nil;
120         givebuf(*r, b);
121         free(r);
122 }
123
124 static void
125 handleget(BufReq req)
126 {
127         Buf *b, *l;
128         Dev *d;
129         
130         d = req.d;
131         l = &d->buf[req.off & BUFHASH];
132         for(b = l->dnext; b != l; b = b->dnext)
133                 if(b->off == req.off){
134                         if(b->busy){
135                                 delayreq(req, &b->next, &b->last);
136                                 return;
137                         }
138                         givebuf(req, b);
139                         return;
140                 }
141         if(bfree.fnext == &bfree){
142                 delayreq(req, &freereq, &freereqlast);
143                 return;
144         }
145         b = bfree.fnext;
146         givebuf(req, b);
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                 undelayreq(b, &b->next, &b->last);
168         else if(freereq != nil)
169                 undelayreq(b, &freereq, &freereqlast);
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(ulong), 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 != -1){
277                 dprint("hjfs: 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 }