]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/exportfs/io.c
exportfs: make -d log to stderr
[plan9front.git] / sys / src / cmd / exportfs / io.c
1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #define Extern
5 #include "exportfs.h"
6
7 #define QIDPATH ((1LL<<48)-1)
8 vlong newqid = 0;
9
10 void (*fcalls[])(Fsrpc*) =
11 {
12         [Tversion]      Xversion,
13         [Tauth] Xauth,
14         [Tflush]        Xflush,
15         [Tattach]       Xattach,
16         [Twalk]         Xwalk,
17         [Topen]         slave,
18         [Tcreate]       Xcreate,
19         [Tclunk]        Xclunk,
20         [Tread]         slave,
21         [Twrite]        slave,
22         [Tremove]       Xremove,
23         [Tstat]         Xstat,
24         [Twstat]        Xwstat,
25 };
26
27 /* accounting and debugging counters */
28 int     filecnt;
29 int     freecnt;
30 int     qidcnt;
31 int     qfreecnt;
32 int     ncollision;
33
34
35 /*
36  * Start serving file requests from the network
37  */
38 void
39 io(void)
40 {
41         Fsrpc *r;
42         int n;
43
44         for(;;) {
45                 r = getsbuf();
46                 n = read9pmsg(0, r->buf, messagesize);
47                 if(n <= 0)
48                         fatal(nil);
49                 if(convM2S(r->buf, n, &r->work) != n)
50                         fatal("convM2S format error");
51
52                 DEBUG(2, "%F\n", &r->work);
53                 (fcalls[r->work.type])(r);
54         }
55 }
56
57 void
58 reply(Fcall *r, Fcall *t, char *err)
59 {
60         uchar *data;
61         int n;
62
63         t->tag = r->tag;
64         t->fid = r->fid;
65         if(err != nil) {
66                 t->type = Rerror;
67                 t->ename = err;
68         }
69         else 
70                 t->type = r->type + 1;
71
72         DEBUG(2, "\t%F\n", t);
73
74         data = malloc(messagesize);     /* not mallocz; no need to clear */
75         if(data == nil)
76                 fatal(Enomem);
77         n = convS2M(t, data, messagesize);
78         if(write(1, data, n) != n){
79                 /* not fatal, might have got a note due to flush */
80                 fprint(2, "exportfs: short write in reply: %r\n");
81         }
82         free(data);
83 }
84
85 void
86 mounterror(char *err)
87 {
88         Fsrpc *r;
89         int n;
90
91         r = getsbuf();
92         r->work.tag = NOTAG;
93         r->work.fid = NOFID;
94         r->work.type = Rerror;
95         r->work.ename = err;
96         n = convS2M(&r->work, r->buf, messagesize);
97         write(1, r->buf, n);
98         exits(err);
99 }
100
101 Fid *
102 getfid(int nr)
103 {
104         Fid *f;
105
106         for(f = fidhash(nr); f != nil; f = f->next)
107                 if(f->nr == nr)
108                         return f;
109
110         return nil;
111 }
112
113 int
114 freefid(int nr)
115 {
116         Fid *f, **l;
117         char buf[128];
118
119         l = &fidhash(nr);
120         for(f = *l; f != nil; f = f->next) {
121                 if(f->nr == nr) {
122                         if(f->mid) {
123                                 snprint(buf, sizeof(buf), "/mnt/exportfs/%d", f->mid);
124                                 unmount(0, buf);
125                                 psmap[f->mid] = 0;
126                         }
127                         if(f->f != nil) {
128                                 freefile(f->f);
129                                 f->f = nil;
130                         }
131                         if(f->dir != nil){
132                                 free(f->dir);
133                                 f->dir = nil;
134                         }
135                         *l = f->next;
136                         f->next = fidfree;
137                         fidfree = f;
138                         return 1;
139                 }
140                 l = &f->next;
141         }
142
143         return 0;       
144 }
145
146 Fid *
147 newfid(int nr)
148 {
149         Fid *new, **l;
150         int i;
151
152         l = &fidhash(nr);
153         for(new = *l; new != nil; new = new->next)
154                 if(new->nr == nr)
155                         return nil;
156
157         if(fidfree == nil) {
158                 fidfree = emallocz(sizeof(Fid) * Fidchunk);
159
160                 for(i = 0; i < Fidchunk-1; i++)
161                         fidfree[i].next = &fidfree[i+1];
162
163                 fidfree[Fidchunk-1].next = nil;
164         }
165
166         new = fidfree;
167         fidfree = new->next;
168
169         memset(new, 0, sizeof(Fid));
170         new->next = *l;
171         *l = new;
172         new->nr = nr;
173         new->fid = -1;
174         new->mid = 0;
175
176         return new;     
177 }
178
179 static struct {
180         Lock;
181         Fsrpc   *free;
182
183         /* statistics */
184         int     nalloc;
185         int     nfree;
186 }       sbufalloc;
187
188 Fsrpc *
189 getsbuf(void)
190 {
191         Fsrpc *w;
192
193         lock(&sbufalloc);
194         w = sbufalloc.free;
195         if(w != nil){
196                 sbufalloc.free = w->next;
197                 w->next = nil;
198                 sbufalloc.nfree--;
199                 unlock(&sbufalloc);
200         } else {
201                 sbufalloc.nalloc++;
202                 unlock(&sbufalloc);
203                 w = emallocz(sizeof(*w) + messagesize);
204         }
205         w->flushtag = NOTAG;
206         return w;
207 }
208
209 void
210 putsbuf(Fsrpc *w)
211 {
212         w->flushtag = NOTAG;
213         lock(&sbufalloc);
214         w->next = sbufalloc.free;
215         sbufalloc.free = w;
216         sbufalloc.nfree++;
217         unlock(&sbufalloc);
218 }
219
220 void
221 freefile(File *f)
222 {
223         File *parent, *child;
224
225         while(--f->ref == 0){
226                 freecnt++;
227                 DEBUG(2, "free %s\n", f->name);
228                 /* delete from parent */
229                 parent = f->parent;
230                 if(parent->child == f)
231                         parent->child = f->childlist;
232                 else{
233                         for(child = parent->child; child->childlist != f; child = child->childlist) {
234                                 if(child->childlist == nil)
235                                         fatal("bad child list");
236                         }
237                         child->childlist = f->childlist;
238                 }
239                 freeqid(f->qidt);
240                 free(f->name);
241                 free(f);
242                 f = parent;
243         }
244 }
245
246 File *
247 file(File *parent, char *name)
248 {
249         Dir *dir;
250         char *path;
251         File *f;
252
253         DEBUG(2, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
254
255         path = makepath(parent, name);
256         if(patternfile != nil && excludefile(path)){
257                 free(path);
258                 return nil;
259         }
260         dir = dirstat(path);
261         free(path);
262         if(dir == nil)
263                 return nil;
264
265         for(f = parent->child; f != nil; f = f->childlist)
266                 if(strcmp(name, f->name) == 0)
267                         break;
268
269         if(f == nil){
270                 f = emallocz(sizeof(File));
271                 f->name = estrdup(name);
272
273                 f->parent = parent;
274                 f->childlist = parent->child;
275                 parent->child = f;
276                 parent->ref++;
277                 f->ref = 0;
278                 filecnt++;
279         }
280         f->ref++;
281         f->qid.type = dir->qid.type;
282         f->qid.vers = dir->qid.vers;
283         f->qidt = uniqueqid(dir);
284         f->qid.path = f->qidt->uniqpath;
285
286         f->inval = 0;
287
288         free(dir);
289
290         return f;
291 }
292
293 void
294 initroot(void)
295 {
296         Dir *dir;
297
298         root = emallocz(sizeof(File));
299         root->name = estrdup(".");
300
301         dir = dirstat(root->name);
302         if(dir == nil)
303                 fatal("root stat");
304
305         root->ref = 1;
306         root->qid.vers = dir->qid.vers;
307         root->qidt = uniqueqid(dir);
308         root->qid.path = root->qidt->uniqpath;
309         root->qid.type = QTDIR;
310         free(dir);
311
312         psmpt = emallocz(sizeof(File));
313         psmpt->name = estrdup("/");
314
315         dir = dirstat(psmpt->name);
316         if(dir == nil)
317                 return;
318
319         psmpt->ref = 1;
320         psmpt->qid.vers = dir->qid.vers;
321         psmpt->qidt = uniqueqid(dir);
322         psmpt->qid.path = psmpt->qidt->uniqpath;
323         free(dir);
324
325         psmpt = file(psmpt, "mnt");
326         if(psmpt == nil)
327                 return;
328         psmpt = file(psmpt, "exportfs");
329 }
330
331 char*
332 makepath(File *p, char *name)
333 {
334         int i, n;
335         char *c, *s, *path, *seg[256];
336
337         seg[0] = name;
338         n = strlen(name)+2;
339         for(i = 1; i < 256 && p; i++, p = p->parent){
340                 seg[i] = p->name;
341                 n += strlen(p->name)+1;
342         }
343         path = emallocz(n);
344         s = path;
345
346         while(i--) {
347                 for(c = seg[i]; *c; c++)
348                         *s++ = *c;
349                 *s++ = '/';
350         }
351         while(s[-1] == '/')
352                 s--;
353         *s = '\0';
354
355         return path;
356 }
357
358 int
359 qidhash(vlong path)
360 {
361         int h, n;
362
363         h = 0;
364         for(n=0; n<64; n+=Nqidbits){
365                 h ^= path;
366                 path >>= Nqidbits;
367         }
368         return h & (Nqidtab-1);
369 }
370
371 void
372 freeqid(Qidtab *q)
373 {
374         ulong h;
375         Qidtab *l;
376
377         if(--q->ref)
378                 return;
379         qfreecnt++;
380         h = qidhash(q->path);
381         if(qidtab[h] == q)
382                 qidtab[h] = q->next;
383         else{
384                 for(l=qidtab[h]; l->next!=q; l=l->next)
385                         if(l->next == nil)
386                                 fatal("bad qid list");
387                 l->next = q->next;
388         }
389         free(q);
390 }
391
392 Qidtab*
393 qidlookup(Dir *d)
394 {
395         ulong h;
396         Qidtab *q;
397
398         h = qidhash(d->qid.path);
399         for(q=qidtab[h]; q!=nil; q=q->next)
400                 if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path)
401                         return q;
402         return nil;
403 }
404
405 int
406 qidexists(vlong path)
407 {
408         int h;
409         Qidtab *q;
410
411         for(h=0; h<Nqidtab; h++)
412                 for(q=qidtab[h]; q!=nil; q=q->next)
413                         if(q->uniqpath == path)
414                                 return 1;
415         return 0;
416 }
417
418 Qidtab*
419 uniqueqid(Dir *d)
420 {
421         ulong h;
422         vlong path;
423         Qidtab *q;
424
425         q = qidlookup(d);
426         if(q != nil){
427                 q->ref++;
428                 return q;
429         }
430         path = d->qid.path;
431         while(qidexists(path)){
432                 DEBUG(2, "collision on %s\n", d->name);
433                 /* collision: find a new one */
434                 ncollision++;
435                 path &= QIDPATH;
436                 ++newqid;
437                 if(newqid >= (1<<16)){
438                         DEBUG(2, "collision wraparound\n");
439                         newqid = 1;
440                 }
441                 path |= newqid<<48;
442                 DEBUG(2, "assign qid %.16llux\n", path);
443         }
444         qidcnt++;
445         q = emallocz(sizeof(Qidtab));
446         q->ref = 1;
447         q->type = d->type;
448         q->dev = d->dev;
449         q->path = d->qid.path;
450         q->uniqpath = path;
451         h = qidhash(d->qid.path);
452         q->next = qidtab[h];
453         qidtab[h] = q;
454         return q;
455 }
456
457 void
458 fatal(char *s, ...)
459 {
460         char buf[ERRMAX];
461         va_list arg;
462         Proc *m;
463
464         if(s != nil) {
465                 va_start(arg, s);
466                 vsnprint(buf, ERRMAX, s, arg);
467                 va_end(arg);
468         }
469
470         /* Clear away the slave children */
471         for(m = Proclist; m != nil; m = m->next)
472                 postnote(PNPROC, m->pid, "kill");
473
474         if(s != nil) {
475                 DEBUG(2, "%s\n", buf);
476                 sysfatal("%s", buf);    /* caution: buf could contain '%' */
477         } else
478                 exits(nil);
479 }
480
481 void*
482 emallocz(uint n)
483 {
484         void *p;
485
486         p = mallocz(n, 1);
487         if(p == nil)
488                 fatal(Enomem);
489         setmalloctag(p, getcallerpc(&n));
490         return p;
491 }
492
493 char*
494 estrdup(char *s)
495 {
496         char *t;
497
498         t = strdup(s);
499         if(t == nil)
500                 fatal(Enomem);
501         setmalloctag(t, getcallerpc(&s));
502         return t;
503 }