]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/disk/kfs/sub.c
Add Erik Quanstrom's smart tool for ATA SMART.
[plan9front.git] / sys / src / cmd / disk / kfs / sub.c
1 #include        "all.h"
2
3 Lock wpathlock;
4
5 struct {
6         Lock    flock;
7         File*   ffree;          /* free file structures */
8         Wpath*  wfree;
9 } suballoc;
10
11 enum{
12         Finc=   128,    /* allocation chunksize for files */
13         Fmax=   10000,  /* maximum file structures to be allocated */
14         
15         Winc=   8*128,  /* allocation chunksize for wpath */
16         Wmax=   8*10000,        /* maximum wpath structures to be allocated */
17 };
18
19
20 Filsys*
21 fsstr(char *p)
22 {
23         Filsys *fs;
24
25         for(fs=filesys; fs->name; fs++)
26                 if(strcmp(fs->name, p) == 0)
27                         return fs;
28         return 0;
29 }
30
31 void
32 fileinit(Chan *cp)
33 {
34         File *f;
35         Tlock *t;
36
37 loop:
38         lock(&cp->flock);
39         f = cp->flist;
40         if(!f) {
41                 unlock(&cp->flock);
42                 return;
43         }
44         cp->flist = f->next;
45         unlock(&cp->flock);
46
47         qlock(f);
48         if(t = f->tlock) {
49                 t->time = 0;
50                 f->tlock = 0;
51         }
52         if(f->open & FREMOV)
53                 doremove(f, 0);
54         freewp(f->wpath);
55         f->open = 0;
56         f->cp = 0;
57         qunlock(f);
58
59         goto loop;
60 }
61
62 /*
63  * returns a locked file structure
64  */
65 File*
66 filep(Chan *cp, int fid, int flag)
67 {
68         File *f, *prev;
69
70         if(fid == NOF)
71                 return 0;
72
73 loop:
74         lock(&cp->flock);
75         for(prev=0,f=cp->flist; f; prev=f,f=f->next) {
76                 if(f->fid != fid)
77                         continue;
78                 if(prev) {
79                         prev->next = f->next;
80                         f->next = cp->flist;
81                         cp->flist = f;
82                 }
83                 goto out;
84         }
85         if(flag) {
86                 f = newfp(cp);
87                 if(f) {
88                         f->fid = fid;
89                         goto out;
90                 }
91         }
92 else print("cannot find %p.%ud (list=%p)\n", cp, fid, cp->flist);
93         unlock(&cp->flock);
94         return 0;
95
96 out:
97         unlock(&cp->flock);
98         qlock(f);
99         if(f->fid != fid) {
100                 qunlock(f);
101                 goto loop;
102         }
103         return f;
104 }
105
106 void
107 sublockinit(void)
108 {
109         lock(&suballoc.flock);
110         lock(&wpathlock);
111         conf.nfile = 0;
112         conf.nwpath = 0;
113         unlock(&suballoc.flock);
114         unlock(&wpathlock);
115 }       
116
117 /*
118  * always called with cp->flock locked
119  */
120 File*
121 newfp(Chan *cp)
122 {
123         File *f, *e;
124
125 retry:
126         lock(&suballoc.flock);
127         f = suballoc.ffree;
128         if(f != nil){
129                 suballoc.ffree = f->list;
130                 unlock(&suballoc.flock);
131                 f->list = 0;
132                 f->cp = cp;
133                 f->next = cp->flist;
134                 f->wpath = 0;
135                 f->tlock = 0;
136                 f->dslot = 0;
137                 f->doffset = 0;
138                 f->uid = 0;
139                 f->cuid = 0;
140                 cp->flist = f;
141                 return f;
142         }
143         unlock(&suballoc.flock);
144
145         if(conf.nfile > Fmax){
146                 print("%d: out of files\n", cp->chan);
147                 return 0;
148         }
149
150         /*
151          *  create a few new files
152          */
153         f = malloc(Finc*sizeof(*f));
154         memset(f, 0, Finc*sizeof(*f));
155         lock(&suballoc.flock);
156         for(e = f+Finc; f < e; f++){
157                 qlock(f);
158                 qunlock(f);
159                 f->list = suballoc.ffree;
160                 suballoc.ffree = f;
161         }
162         conf.nfile += Finc;
163         unlock(&suballoc.flock);
164         goto retry;
165 }
166
167 void
168 freefp(File *fp)
169 {
170         Chan *cp;
171         File *f, *prev;
172
173         if(!fp || !(cp = fp->cp))
174                 return;
175         authfree(fp);
176         lock(&cp->flock);
177         for(prev=0,f=cp->flist; f; prev=f,f=f->next) {
178                 if(f != fp)
179                         continue;
180                 if(prev)
181                         prev->next = f->next;
182                 else
183                         cp->flist = f->next;
184                 f->cp = 0;
185                 lock(&suballoc.flock);
186                 f->list = suballoc.ffree;
187                 suballoc.ffree = f;
188                 unlock(&suballoc.flock);
189                 break;
190         }
191         unlock(&cp->flock);
192 }
193
194 Wpath*
195 newwp(void)
196 {
197         Wpath *w, *e;
198
199 retry:
200         lock(&wpathlock);
201         w = suballoc.wfree;
202         if(w != nil){
203                 suballoc.wfree = w->list;
204                 unlock(&wpathlock);
205                 memset(w, 0, sizeof(*w));
206                 w->refs = 1;
207                 w->up = 0;
208                 return w;
209         }
210         unlock(&wpathlock);
211
212         if(conf.nwpath > Wmax){
213                 print("out of wpaths\n");
214                 return 0;
215         }
216
217         /*
218          *  create a few new wpaths
219          */
220         w = malloc(Winc*sizeof(*w));
221         memset(w, 0, Winc*sizeof(*w));
222         lock(&wpathlock);
223         for(e = w+Winc; w < e; w++){
224                 w->list = suballoc.wfree;
225                 suballoc.wfree = w;
226         }
227         conf.nwpath += Winc;
228         unlock(&wpathlock);
229         goto retry;
230 }
231
232 /*
233  *  increment the references for the whole path
234  */
235 Wpath*
236 getwp(Wpath *w)
237 {
238         Wpath *nw;
239
240         lock(&wpathlock);
241         for(nw = w; nw; nw=nw->up)
242                 nw->refs++;
243         unlock(&wpathlock);
244         return w;
245 }
246
247 /*
248  *  decrement the reference for each element of the path
249  */
250 void
251 freewp(Wpath *w)
252 {
253         lock(&wpathlock);
254         for(; w; w=w->up){
255                 w->refs--;
256                 if(w->refs == 0){
257                         w->list = suballoc.wfree;
258                         suballoc.wfree = w;
259                 }
260         }
261         unlock(&wpathlock);
262 }
263
264 /*
265  *  decrement the reference for just this element
266  */
267 void
268 putwp(Wpath *w)
269 {
270         lock(&wpathlock);
271         w->refs--;
272         if(w->refs == 0){
273                 w->list = suballoc.wfree;
274                 suballoc.wfree = w;
275         }
276         unlock(&wpathlock);
277 }
278
279 int
280 iaccess(File *f, Dentry *d, int m)
281 {
282         if(wstatallow)
283                 return 0;
284
285         /*
286          * owner is next
287          */
288         if(f->uid == d->uid)
289                 if((m<<6) & d->mode)
290                         return 0;
291         /*
292          * group membership is hard
293          */
294         if(ingroup(f->uid, d->gid))
295                 if((m<<3) & d->mode)
296                         return 0;
297         /*
298          * other access for everyone except members of group 9999
299          */
300         if(m & d->mode){
301                 /* 
302                  *  walk directories regardless.
303                  *  otherwise its impossible to get
304                  *  from the root to noworld's directories.
305                  */
306                 if((d->mode & DDIR) && (m == DEXEC))
307                         return 0;
308                 if(!ingroup(f->uid, 9999))
309                         return 0;
310         }
311         return 1;
312 }
313
314 Tlock*
315 tlocked(Iobuf *p, Dentry *d)
316 {
317         Tlock *t, *t1;
318         long qpath, tim;
319         Device dev;
320
321         tim = time(0);
322         qpath = d->qid.path;
323         dev = p->dev;
324         t1 = 0;
325         for(t=tlocks+NTLOCK-1; t>=tlocks; t--) {
326                 if(t->qpath == qpath)
327                 if(t->time >= tim)
328                 if(devcmp(t->dev, dev) == 0)
329                         return 0;               /* its locked */
330                 if(!t1 && t->time < tim)
331                         t1 = t;                 /* steal first lock */
332         }
333         if(t1) {
334                 t1->dev = dev;
335                 t1->qpath = qpath;
336                 t1->time = tim + TLOCK;
337         }
338         /* botch
339          * out of tlock nodes simulates
340          * a locked file
341          */
342         return t1;
343 }
344
345 Qid
346 newqid(Device dev)
347 {
348         Iobuf *p;
349         Superb *sb;
350         Qid qid;
351
352         p = getbuf(dev, superaddr(dev), Bread|Bmod);
353         if(!p || checktag(p, Tsuper, QPSUPER))
354                 panic("newqid: super block");
355         sb = (Superb*)p->iobuf;
356         sb->qidgen++;
357         qid.path = sb->qidgen;
358         qid.vers = 0;
359         qid.type = 0;
360         putbuf(p);
361         return qid;
362 }
363
364 /*
365  * what are legal characters in a name?
366  * only disallow control characters.
367  * a) utf avoids control characters.
368  * b) '/' may not be the separator
369  */
370 int
371 checkname(char *n)
372 {
373         int i, c;
374
375         for(i=0; i<NAMELEN; i++) {
376                 c = *n & 0xff;
377                 if(c == 0) {
378                         if(i == 0)
379                                 return 1;
380                         memset(n, 0, NAMELEN-i);
381                         return 0;
382                 }
383                 if(c <= 040)
384                         return 1;
385                 n++;
386         }
387         return 1;       /* too long */
388 }
389
390 void
391 bfree(Device dev, long addr, int d)
392 {
393         Iobuf *p;
394         long a;
395         int i;
396
397         if(!addr)
398                 return;
399         if(d > 0) {
400                 d--;
401                 p = getbuf(dev, addr, Bread);
402                 if(p) {
403                         for(i=INDPERBUF-1; i>=0; i--) {
404                                 a = ((long*)p->iobuf)[i];
405                                 bfree(dev, a, d);
406                         }
407                         putbuf(p);
408                 }
409         }
410         /*
411          * stop outstanding i/o
412          */
413         p = getbuf(dev, addr, Bprobe);
414         if(p) {
415                 p->flags &= ~(Bmod|Bimm);
416                 putbuf(p);
417         }
418         /*
419          * dont put written worm
420          * blocks into free list
421          */
422         if(nofree(dev, addr))
423                 return;
424         p = getbuf(dev, superaddr(dev), Bread|Bmod);
425         if(!p || checktag(p, Tsuper, QPSUPER))
426                 panic("bfree: super block");
427         addfree(dev, addr, (Superb*)p->iobuf);
428         putbuf(p);
429 }
430
431 long
432 balloc(Device dev, int tag, long qid)
433 {
434         Iobuf *bp, *p;
435         Superb *sb;
436         long a;
437         int n;
438
439         p = getbuf(dev, superaddr(dev), Bread|Bmod);
440         if(!p || checktag(p, Tsuper, QPSUPER))
441                 panic("balloc: super block");
442         sb = (Superb*)p->iobuf;
443
444 loop:
445         n = --sb->fbuf.nfree;
446         sb->tfree--;
447         if(n < 0 || n >= FEPERBUF)
448                 panic("balloc: bad freelist");
449         a = sb->fbuf.free[n];
450         if(n <= 0) {
451                 if(a == 0) {
452                         sb->tfree = 0;
453                         sb->fbuf.nfree = 1;
454                         if(devgrow(dev, sb))
455                                 goto loop;
456                         putbuf(p);
457                         return 0;
458                 }
459                 bp = getbuf(dev, a, Bread);
460                 if(!bp || checktag(bp, Tfree, QPNONE)) {
461                         if(bp)
462                                 putbuf(bp);
463                         putbuf(p);
464                         return 0;
465                 }
466                 memmove(&sb->fbuf, bp->iobuf, (FEPERBUF+1)*sizeof(long));
467                 putbuf(bp);
468         }
469         bp = getbuf(dev, a, Bmod);
470         memset(bp->iobuf, 0, RBUFSIZE);
471         settag(bp, tag, qid);
472         if(tag == Tind1 || tag == Tind2 || tag == Tdir)
473                 bp->flags |= Bimm;
474         putbuf(bp);
475         putbuf(p);
476         return a;
477 }
478
479 void
480 addfree(Device dev, long addr, Superb *sb)
481 {
482         int n;
483         Iobuf *p;
484
485         if(addr >= sb->fsize){
486                 print("addfree: bad addr %lux\n", addr);
487                 return;
488         }
489         n = sb->fbuf.nfree;
490         if(n < 0 || n > FEPERBUF)
491                 panic("addfree: bad freelist");
492         if(n >= FEPERBUF) {
493                 p = getbuf(dev, addr, Bmod);
494                 if(p == 0)
495                         panic("addfree: getbuf");
496                 memmove(p->iobuf, &sb->fbuf, (FEPERBUF+1)*sizeof(long));
497                 settag(p, Tfree, QPNONE);
498                 putbuf(p);
499                 n = 0;
500         }
501         sb->fbuf.free[n++] = addr;
502         sb->fbuf.nfree = n;
503         sb->tfree++;
504         if(addr >= sb->fsize)
505                 sb->fsize = addr+1;
506 }
507
508 int
509 Cfmt(Fmt *f1)
510 {
511         Chan *cp;
512
513         cp = va_arg(f1->args, Chan*);
514         return fmtprint(f1, "C%d.%.3d", cp->type, cp->chan);
515 }
516
517 int
518 Dfmt(Fmt *f1)
519 {
520         Device d;
521
522         d = va_arg(f1->args, Device);
523         return fmtprint(f1, "D%d.%d.%d.%d", d.type, d.ctrl, d.unit, d.part);
524 }
525
526 int
527 Afmt(Fmt *f1)
528 {
529         Filta a;
530
531         a = va_arg(f1->args, Filta);
532         return fmtprint(f1, "%6lud %6lud %6lud",
533                 fdf(a.f->filter[0], a.scale*60),
534                 fdf(a.f->filter[1], a.scale*600),
535                 fdf(a.f->filter[2], a.scale*6000));
536 }
537
538 int
539 Gfmt(Fmt *f1)
540 {
541         int t;
542
543         t = va_arg(f1->args, int);
544         if(t >= 0 && t < MAXTAG)
545                 return fmtstrcpy(f1, tagnames[t]);
546         else
547                 return fmtprint(f1, "<badtag %d>", t);
548 }
549
550 void
551 formatinit(void)
552 {
553
554         fmtinstall('C', Cfmt);  /* print channels */
555         fmtinstall('D', Dfmt);  /* print devices */
556         fmtinstall('A', Afmt);  /* print filters */
557         fmtinstall('G', Gfmt);  /* print tags */
558         fmtinstall('T', Tfmt);  /* print times */
559         fmtinstall('O', ofcallfmt);     /* print old fcalls */
560 }
561 int
562 devcmp(Device d1, Device d2)
563 {
564
565         if(d1.type == d2.type)
566         if(d1.ctrl == d2.ctrl)
567         if(d1.unit == d2.unit)
568         if(d1.part == d2.part)
569                 return 0;
570         return 1;
571 }
572
573 void
574 rootream(Device dev, long addr)
575 {
576         Iobuf *p;
577         Dentry *d;
578
579         p = getbuf(dev, addr, Bmod|Bimm);
580         memset(p->iobuf, 0, RBUFSIZE);
581         settag(p, Tdir, QPROOT);
582         d = getdir(p, 0);
583         strcpy(d->name, "/");
584         d->uid = -1;
585         d->gid = -1;
586         d->mode = DALLOC | DDIR |
587                 ((DREAD|DWRITE|DEXEC) << 6) |
588                 ((DREAD|DWRITE|DEXEC) << 3) |
589                 ((DREAD|DWRITE|DEXEC) << 0);
590         d->qid = QID9P1(QPROOT|QPDIR,0);
591         d->atime = time(0);
592         d->mtime = d->atime;
593         putbuf(p);
594 }
595
596 int
597 superok(Device dev, long addr, int set)
598 {
599         Iobuf *p;
600         Superb *s;
601         int ok;
602
603         p = getbuf(dev, addr, Bread|Bmod|Bimm);
604         s = (Superb*)p->iobuf;
605         ok = s->fsok;
606         s->fsok = set;
607         putbuf(p);
608         return ok;
609 }
610
611 void
612 superream(Device dev, long addr)
613 {
614         Iobuf *p;
615         Superb *s;
616         long i;
617
618         p = getbuf(dev, addr, Bmod|Bimm);
619         memset(p->iobuf, 0, RBUFSIZE);
620         settag(p, Tsuper, QPSUPER);
621
622         s = (Superb*)p->iobuf;
623         s->fstart = 1;
624         s->fsize = devsize(dev);
625         s->fbuf.nfree = 1;
626         s->qidgen = 10;
627         for(i=s->fsize-1; i>=addr+2; i--)
628                 addfree(dev, i, s);
629         putbuf(p);
630 }
631
632 /*
633  * returns 1 if n is prime
634  * used for adjusting lengths
635  * of hashing things.
636  * there is no need to be clever
637  */
638 int
639 prime(long n)
640 {
641         long i;
642
643         if((n%2) == 0)
644                 return 0;
645         for(i=3;; i+=2) {
646                 if((n%i) == 0)
647                         return 0;
648                 if(i*i >= n)
649                         return 1;
650         }
651 }
652
653 void
654 hexdump(void *a, int n)
655 {
656         char s1[30], s2[4];
657         uchar *p;
658         int i;
659
660         p = a;
661         s1[0] = 0;
662         for(i=0; i<n; i++) {
663                 sprint(s2, " %.2ux", p[i]);
664                 strcat(s1, s2);
665                 if((i&7) == 7) {
666                         print("%s\n", s1);
667                         s1[0] = 0;
668                 }
669         }
670         if(s1[0])
671                 print("%s\n", s1);
672 }
673
674 long
675 qidpathgen(Device *dev)
676 {
677         Iobuf *p;
678         Superb *sb;
679         long path;
680
681         p = getbuf(*dev, superaddr((*dev)), Bread|Bmod);
682         if(!p || checktag(p, Tsuper, QPSUPER))
683                 panic("newqid: super block");
684         sb = (Superb*)p->iobuf;
685         sb->qidgen++;
686         path = sb->qidgen;
687         putbuf(p);
688         return path;
689 }
690