xref: /plan9/sys/src/cmd/disk/kfs/sub.c (revision 2bef681aed9a53ac1dc6db418047b00f7a5ce209)
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*
fsstr(char * p)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
fileinit(Chan * cp)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*
filep(Chan * cp,int fid,int flag)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.%d (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
sublockinit(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*
newfp(Chan * cp)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
freefp(File * fp)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*
newwp(void)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*
getwp(Wpath * w)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
freewp(Wpath * w)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
putwp(Wpath * w)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
iaccess(File * f,Dentry * d,int m)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*
tlocked(Iobuf * p,Dentry * d)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
newqid(Device dev)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
checkname(char * n)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
bfree(Device dev,long addr,int d)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
balloc(Device dev,int tag,long qid)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
addfree(Device dev,long addr,Superb * sb)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
Cfmt(Fmt * f1)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
Dfmt(Fmt * f1)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
Afmt(Fmt * f1)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
Gfmt(Fmt * f1)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
formatinit(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
devcmp(Device d1,Device d2)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
rootream(Device dev,long addr)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
superok(Device dev,long addr,int set)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
superream(Device dev,long addr)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
prime(long n)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
hexdump(void * a,int n)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
qidpathgen(Device * dev)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 
691