xref: /plan9/sys/src/cmd/disk/kfs/sub.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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.%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
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 	putbuf(p);
360 	return qid;
361 }
362 
363 /*
364  * what are legal characters in a name?
365  * only disallow control characters.
366  * a) utf avoids control characters.
367  * b) '/' may not be the separator
368  */
369 int
370 checkname(char *n)
371 {
372 	int i, c;
373 
374 	for(i=0; i<NAMELEN; i++) {
375 		c = *n & 0xff;
376 		if(c == 0) {
377 			if(i == 0)
378 				return 1;
379 			memset(n, 0, NAMELEN-i);
380 			return 0;
381 		}
382 		if(c <= 040)
383 			return 1;
384 		n++;
385 	}
386 	return 1;	/* too long */
387 }
388 
389 void
390 bfree(Device dev, long addr, int d)
391 {
392 	Iobuf *p;
393 	long a;
394 	int i;
395 
396 	if(!addr)
397 		return;
398 	if(d > 0) {
399 		d--;
400 		p = getbuf(dev, addr, Bread);
401 		if(p) {
402 			for(i=INDPERBUF-1; i>=0; i--) {
403 				a = ((long*)p->iobuf)[i];
404 				bfree(dev, a, d);
405 			}
406 			putbuf(p);
407 		}
408 	}
409 	/*
410 	 * stop outstanding i/o
411 	 */
412 	p = getbuf(dev, addr, Bprobe);
413 	if(p) {
414 		p->flags &= ~(Bmod|Bimm);
415 		putbuf(p);
416 	}
417 	/*
418 	 * dont put written worm
419 	 * blocks into free list
420 	 */
421 	if(nofree(dev, addr))
422 		return;
423 	p = getbuf(dev, superaddr(dev), Bread|Bmod);
424 	if(!p || checktag(p, Tsuper, QPSUPER))
425 		panic("bfree: super block");
426 	addfree(dev, addr, (Superb*)p->iobuf);
427 	putbuf(p);
428 }
429 
430 long
431 balloc(Device dev, int tag, long qid)
432 {
433 	Iobuf *bp, *p;
434 	Superb *sb;
435 	long a;
436 	int n;
437 
438 	p = getbuf(dev, superaddr(dev), Bread|Bmod);
439 	if(!p || checktag(p, Tsuper, QPSUPER))
440 		panic("balloc: super block");
441 	sb = (Superb*)p->iobuf;
442 
443 loop:
444 	n = --sb->fbuf.nfree;
445 	sb->tfree--;
446 	if(n < 0 || n >= FEPERBUF)
447 		panic("balloc: bad freelist");
448 	a = sb->fbuf.free[n];
449 	if(n <= 0) {
450 		if(a == 0) {
451 			sb->tfree = 0;
452 			sb->fbuf.nfree = 1;
453 			if(devgrow(dev, sb))
454 				goto loop;
455 			putbuf(p);
456 			return 0;
457 		}
458 		bp = getbuf(dev, a, Bread);
459 		if(!bp || checktag(bp, Tfree, QPNONE)) {
460 			if(bp)
461 				putbuf(bp);
462 			putbuf(p);
463 			return 0;
464 		}
465 		memmove(&sb->fbuf, bp->iobuf, (FEPERBUF+1)*sizeof(long));
466 		putbuf(bp);
467 	}
468 	bp = getbuf(dev, a, Bmod);
469 	memset(bp->iobuf, 0, RBUFSIZE);
470 	settag(bp, tag, qid);
471 	if(tag == Tind1 || tag == Tind2 || tag == Tdir)
472 		bp->flags |= Bimm;
473 	putbuf(bp);
474 	putbuf(p);
475 	return a;
476 }
477 
478 void
479 addfree(Device dev, long addr, Superb *sb)
480 {
481 	int n;
482 	Iobuf *p;
483 
484 	if(addr >= sb->fsize){
485 		print("addfree: bad addr %lux\n", addr);
486 		return;
487 	}
488 	n = sb->fbuf.nfree;
489 	if(n < 0 || n > FEPERBUF)
490 		panic("addfree: bad freelist");
491 	if(n >= FEPERBUF) {
492 		p = getbuf(dev, addr, Bmod);
493 		if(p == 0)
494 			panic("addfree: getbuf");
495 		memmove(p->iobuf, &sb->fbuf, (FEPERBUF+1)*sizeof(long));
496 		settag(p, Tfree, QPNONE);
497 		putbuf(p);
498 		n = 0;
499 	}
500 	sb->fbuf.free[n++] = addr;
501 	sb->fbuf.nfree = n;
502 	sb->tfree++;
503 	if(addr >= sb->fsize)
504 		sb->fsize = addr+1;
505 }
506 
507 int
508 Cfmt(Fmt *f1)
509 {
510 	Chan *cp;
511 
512 	cp = va_arg(f1->args, Chan*);
513 	return fmtprint(f1, "C%d.%.3d", cp->type, cp->chan);
514 }
515 
516 int
517 Dfmt(Fmt *f1)
518 {
519 	Device d;
520 
521 	d = va_arg(f1->args, Device);
522 	return fmtprint(f1, "D%d.%d.%d.%d", d.type, d.ctrl, d.unit, d.part);
523 }
524 
525 int
526 Afmt(Fmt *f1)
527 {
528 	Filta a;
529 
530 	a = va_arg(f1->args, Filta);
531 	return fmtprint(f1, "%6lud %6lud %6lud",
532 		fdf(a.f->filter[0], a.scale*60),
533 		fdf(a.f->filter[1], a.scale*600),
534 		fdf(a.f->filter[2], a.scale*6000));
535 }
536 
537 int
538 Gfmt(Fmt *f1)
539 {
540 	int t;
541 
542 	t = va_arg(f1->args, int);
543 	if(t >= 0 && t < MAXTAG)
544 		return fmtstrcpy(f1, tagnames[t]);
545 	else
546 		return fmtprint(f1, "<badtag %d>", t);
547 }
548 
549 void
550 formatinit(void)
551 {
552 
553 	fmtinstall('C', Cfmt);	/* print channels */
554 	fmtinstall('D', Dfmt);	/* print devices */
555 	fmtinstall('A', Afmt);	/* print filters */
556 	fmtinstall('G', Gfmt);	/* print tags */
557 	fmtinstall('T', Tfmt);	/* print times */
558 	fmtinstall('O', ofcallfmt);	/* print old fcalls */
559 }
560 int
561 devcmp(Device d1, Device d2)
562 {
563 
564 	if(d1.type == d2.type)
565 	if(d1.ctrl == d2.ctrl)
566 	if(d1.unit == d2.unit)
567 	if(d1.part == d2.part)
568 		return 0;
569 	return 1;
570 }
571 
572 void
573 rootream(Device dev, long addr)
574 {
575 	Iobuf *p;
576 	Dentry *d;
577 
578 	p = getbuf(dev, addr, Bmod|Bimm);
579 	memset(p->iobuf, 0, RBUFSIZE);
580 	settag(p, Tdir, QPROOT);
581 	d = getdir(p, 0);
582 	strcpy(d->name, "/");
583 	d->uid = -1;
584 	d->gid = -1;
585 	d->mode = DALLOC | DDIR |
586 		((DREAD|DWRITE|DEXEC) << 6) |
587 		((DREAD|DWRITE|DEXEC) << 3) |
588 		((DREAD|DWRITE|DEXEC) << 0);
589 	d->qid = QID9P1(QPROOT|QPDIR,0);
590 	d->atime = time(0);
591 	d->mtime = d->atime;
592 	putbuf(p);
593 }
594 
595 int
596 superok(Device dev, long addr, int set)
597 {
598 	Iobuf *p;
599 	Superb *s;
600 	int ok;
601 
602 	p = getbuf(dev, addr, Bread|Bmod|Bimm);
603 	s = (Superb*)p->iobuf;
604 	ok = s->fsok;
605 	s->fsok = set;
606 	putbuf(p);
607 	return ok;
608 }
609 
610 void
611 superream(Device dev, long addr)
612 {
613 	Iobuf *p;
614 	Superb *s;
615 	long i;
616 
617 	p = getbuf(dev, addr, Bmod|Bimm);
618 	memset(p->iobuf, 0, RBUFSIZE);
619 	settag(p, Tsuper, QPSUPER);
620 
621 	s = (Superb*)p->iobuf;
622 	s->fstart = 1;
623 	s->fsize = devsize(dev);
624 	s->fbuf.nfree = 1;
625 	s->qidgen = 10;
626 	for(i=s->fsize-1; i>=addr+2; i--)
627 		addfree(dev, i, s);
628 	putbuf(p);
629 }
630 
631 /*
632  * returns 1 if n is prime
633  * used for adjusting lengths
634  * of hashing things.
635  * there is no need to be clever
636  */
637 int
638 prime(long n)
639 {
640 	long i;
641 
642 	if((n%2) == 0)
643 		return 0;
644 	for(i=3;; i+=2) {
645 		if((n%i) == 0)
646 			return 0;
647 		if(i*i >= n)
648 			return 1;
649 	}
650 }
651 
652 void
653 hexdump(void *a, int n)
654 {
655 	char s1[30], s2[4];
656 	uchar *p;
657 	int i;
658 
659 	p = a;
660 	s1[0] = 0;
661 	for(i=0; i<n; i++) {
662 		sprint(s2, " %.2ux", p[i]);
663 		strcat(s1, s2);
664 		if((i&7) == 7) {
665 			print("%s\n", s1);
666 			s1[0] = 0;
667 		}
668 	}
669 	if(s1[0])
670 		print("%s\n", s1);
671 }
672 
673 long
674 qidpathgen(Device *dev)
675 {
676 	Iobuf *p;
677 	Superb *sb;
678 	long path;
679 
680 	p = getbuf(*dev, superaddr((*dev)), Bread|Bmod);
681 	if(!p || checktag(p, Tsuper, QPSUPER))
682 		panic("newqid: super block");
683 	sb = (Superb*)p->iobuf;
684 	sb->qidgen++;
685 	path = sb->qidgen;
686 	putbuf(p);
687 	return path;
688 }
689 
690