xref: /plan9/sys/src/cmd/cwfs/sub.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1 #include "all.h"
2 #include "io.h"
3 
4 enum {
5 	Slop = 256,	/* room at the start of a message buf for proto hdrs */
6 };
7 
8 Filsys*
9 fsstr(char *p)
10 {
11 	Filsys *fs;
12 
13 	for(fs=filsys; fs->name; fs++)
14 		if(strcmp(fs->name, p) == 0)
15 			return fs;
16 	return 0;
17 }
18 
19 Filsys*
20 dev2fs(Device *dev)
21 {
22 	Filsys *fs;
23 
24 	for(fs=filsys; fs->name; fs++)
25 		if(fs->dev == dev)
26 			return fs;
27 	return 0;
28 }
29 
30 /*
31  * allocate 'count' contiguous channels
32  * of type 'type' and return pointer to base
33  */
34 Chan*
35 fs_chaninit(int type, int count, int data)
36 {
37 	uchar *p;
38 	Chan *cp, *icp;
39 	int i;
40 
41 	p = malloc(count * (sizeof(Chan)+data));
42 	icp = (Chan*)p;
43 	for(i = 0; i < count; i++) {
44 		cp = (Chan*)p;
45 		cp->next = chans;
46 		chans = cp;
47 		cp->type = type;
48 		cp->chan = cons.chano;
49 		cons.chano++;
50 		strncpy(cp->whoname, "<none>", sizeof cp->whoname);
51 		wlock(&cp->reflock);
52 		wunlock(&cp->reflock);
53 		rlock(&cp->reflock);
54 		runlock(&cp->reflock);
55 
56 		p += sizeof(Chan);
57 		if(data){
58 			cp->pdata = p;
59 			p += data;
60 		}
61 	}
62 	return icp;
63 }
64 
65 void
66 fileinit(Chan *cp)
67 {
68 	File *f, *prev;
69 	Tlock *t;
70 	int h;
71 
72 loop:
73 	lock(&flock);
74 	for (h=0; h < nelem(flist); h++)
75 		for (prev=0, f = flist[h]; f; prev=f, f=f->next) {
76 			if(f->cp != cp)
77 				continue;
78 			if(prev) {
79 				prev->next = f->next;
80 				f->next = flist[h];
81 				flist[h] = f;
82 			}
83 			flist[h] = f->next;
84 			unlock(&flock);
85 
86 			qlock(f);
87 			if(t = f->tlock) {
88 				if(t->file == f)
89 					t->time = 0;	/* free the lock */
90 				f->tlock = 0;
91 			}
92 			if(f->open & FREMOV)
93 				doremove(f, 0);
94 			freewp(f->wpath);
95 			f->open = 0;
96 			authfree(f->auth);
97 			f->auth = 0;
98 			f->cp = 0;
99 			qunlock(f);
100 			goto loop;
101 		}
102 	unlock(&flock);
103 }
104 
105 enum { NOFID = (ulong)~0 };
106 
107 /*
108  * returns a locked file structure
109  */
110 File*
111 filep(Chan *cp, ulong fid, int flag)
112 {
113 	File *f;
114 	int h;
115 
116 	if(fid == NOFID)
117 		return 0;
118 
119 	h = (long)(uintptr)cp + fid;
120 	if(h < 0)
121 		h = ~h;
122 	h %= nelem(flist);
123 
124 loop:
125 	lock(&flock);
126 	for(f=flist[h]; f; f=f->next)
127 		if(f->fid == fid && f->cp == cp){
128 			/*
129 			 * Already in use is an error
130 			 * when called from attach or clone (walk
131 			 * in 9P2000). The console uses FID[12] and
132 			 * never clunks them so catch that case.
133 			 */
134 			if(flag == 0 || cp == cons.chan)
135 				goto out;
136 			unlock(&flock);
137 			return 0;
138 		}
139 
140 	if(flag) {
141 		f = newfp();
142 		if(f) {
143 			f->fid = fid;
144 			f->cp = cp;
145 			f->wpath = 0;
146 			f->tlock = 0;
147 			f->doffset = 0;
148 			f->dslot = 0;
149 			f->auth = 0;
150 			f->next = flist[h];
151 			flist[h] = f;
152 			goto out;
153 		}
154 	}
155 	unlock(&flock);
156 	return 0;
157 
158 out:
159 	unlock(&flock);
160 	qlock(f);
161 	if(f->fid == fid && f->cp == cp)
162 		return f;
163 	qunlock(f);
164 	goto loop;
165 }
166 
167 /*
168  * always called with flock locked
169  */
170 File*
171 newfp(void)
172 {
173 	static int first;
174 	File *f;
175 	int start, i;
176 
177 	i = first;
178 	start = i;
179 	do {
180 		f = &files[i];
181 		i++;
182 		if(i >= conf.nfile)
183 			i = 0;
184 		if(f->cp)
185 			continue;
186 		first = i;
187 		return f;
188 	} while(i != start);
189 
190 	print("out of files\n");
191 	return 0;
192 }
193 
194 void
195 freefp(File *fp)
196 {
197 	Chan *cp;
198 	File *f, *prev;
199 	int h;
200 
201 	if(!fp || !(cp = fp->cp))
202 		return;
203 
204 	h = (long)(uintptr)cp + fp->fid;
205 	if(h < 0)
206 		h = ~h;
207 	h %= nelem(flist);
208 
209 	lock(&flock);
210 	for(prev=0,f=flist[h]; f; prev=f,f=f->next)
211 		if(f == fp) {
212 			if(prev)
213 				prev->next = f->next;
214 			else
215 				flist[h] = f->next;
216 			break;
217 		}
218 	fp->cp = 0;
219 	unlock(&flock);
220 }
221 
222 int
223 iaccess(File *f, Dentry *d, int m)
224 {
225 	/* uid none gets only other permissions */
226 	if(f->uid != 0) {
227 		/*
228 		 * owner
229 		 */
230 		if(f->uid == d->uid)
231 			if((m<<6) & d->mode)
232 				return 0;
233 		/*
234 		 * group membership
235 		 */
236 		if(ingroup(f->uid, d->gid))
237 			if((m<<3) & d->mode)
238 				return 0;
239 	}
240 
241 	/*
242 	 * other
243 	 */
244 	if(m & d->mode) {
245 		if((d->mode & DDIR) && (m == DEXEC))
246 			return 0;
247 		if(!ingroup(f->uid, 9999))
248 			return 0;
249 	}
250 
251 	/*
252 	 * various forms of superuser
253 	 */
254 	if(wstatallow)
255 		return 0;
256 	if(duallow != 0 && duallow == f->uid)
257 		if((d->mode & DDIR) && (m == DREAD || m == DEXEC))
258 			return 0;
259 
260 	return 1;
261 }
262 
263 Tlock*
264 tlocked(Iobuf *p, Dentry *d)
265 {
266 	Tlock *t, *t1;
267 	Off qpath;
268 	Timet tim;
269 	Device *dev;
270 
271 	tim = toytime();
272 	qpath = d->qid.path;
273 	dev = p->dev;
274 
275 again:
276 	t1 = 0;
277 	for(t=tlocks+NTLOCK-1; t>=tlocks; t--) {
278 		if(t->qpath == qpath)
279 		if(t->time >= tim)
280 		if(t->dev == dev)
281 			return nil;		/* its locked */
282 		if(t1 != nil && t->time == 0)
283 			t1 = t;			/* remember free lock */
284 	}
285 	if(t1 == 0) {
286 		// reclaim old locks
287 		lock(&tlocklock);
288 		for(t=tlocks+NTLOCK-1; t>=tlocks; t--)
289 			if(t->time < tim) {
290 				t->time = 0;
291 				t1 = t;
292 			}
293 		unlock(&tlocklock);
294 	}
295 	if(t1) {
296 		lock(&tlocklock);
297 		if(t1->time != 0) {
298 			unlock(&tlocklock);
299 			goto again;
300 		}
301 		t1->dev = dev;
302 		t1->qpath = qpath;
303 		t1->time = tim + TLOCK;
304 		unlock(&tlocklock);
305 	}
306 	/* botch
307 	 * out of tlock nodes simulates
308 	 * a locked file
309 	 */
310 	return t1;
311 }
312 
313 Wpath*
314 newwp(void)
315 {
316 	static int si = 0;
317 	int i;
318 	Wpath *w, *sw, *ew;
319 
320 	i = si + 1;
321 	if(i < 0 || i >= conf.nwpath)
322 		i = 0;
323 	si = i;
324 	sw = &wpaths[i];
325 	ew = &wpaths[conf.nwpath];
326 	for(w=sw;;) {
327 		w++;
328 		if(w >= ew)
329 			w = &wpaths[0];
330 		if(w == sw) {
331 			print("out of wpaths\n");
332 			return 0;
333 		}
334 		if(w->refs)
335 			continue;
336 		lock(&wpathlock);
337 		if(w->refs) {
338 			unlock(&wpathlock);
339 			continue;
340 		}
341 		w->refs = 1;
342 		w->up = 0;
343 		unlock(&wpathlock);
344 		return w;
345 	}
346 
347 }
348 
349 void
350 freewp(Wpath *w)
351 {
352 	lock(&wpathlock);
353 	for(; w; w=w->up)
354 		w->refs--;
355 	unlock(&wpathlock);
356 }
357 
358 Off
359 qidpathgen(Device *dev)
360 {
361 	Iobuf *p;
362 	Superb *sb;
363 	Off path;
364 
365 	p = getbuf(dev, superaddr(dev), Brd|Bmod);
366 	if(!p || checktag(p, Tsuper, QPSUPER))
367 		panic("newqid: super block");
368 	sb = (Superb*)p->iobuf;
369 	sb->qidgen++;
370 	path = sb->qidgen;
371 	putbuf(p);
372 	return path;
373 }
374 
375 /* truncating to length > 0 */
376 static void
377 truncfree(Truncstate *ts, Device *dev, int d, Iobuf *p, int i)
378 {
379 	int pastlast;
380 	Off a;
381 
382 	pastlast = ts->pastlast;
383 	a = ((Off *)p->iobuf)[i];
384 	if (d > 0 || pastlast)
385 		buffree(dev, a, d, ts);
386 	if (pastlast) {
387 		((Off *)p->iobuf)[i] = 0;
388 		p->flags |= Bmod|Bimm;
389 	} else if (d == 0 && ts->relblk == ts->lastblk)
390 		ts->pastlast = 1;
391 	if (d == 0)
392 		ts->relblk++;
393 }
394 
395 /*
396  * free the block at `addr' on dev.
397  * if it's an indirect block (d [depth] > 0),
398  * first recursively free all the blocks it names.
399  *
400  * ts->relblk is the block number within the file of this
401  * block (or the first data block eventually pointed to via
402  * this indirect block).
403  */
404 void
405 buffree(Device *dev, Off addr, int d, Truncstate *ts)
406 {
407 	Iobuf *p;
408 	Off a;
409 	int i, pastlast;
410 
411 	if(!addr)
412 		return;
413 	pastlast = (ts == nil? 1: ts->pastlast);
414 	/*
415 	 * if this is an indirect block, recurse and free any
416 	 * suitable blocks within it (possibly via further indirect blocks).
417 	 */
418 	if(d > 0) {
419 		d--;
420 		p = getbuf(dev, addr, Brd);
421 		if(p) {
422 			if (ts == nil)		/* common case: create */
423 				for(i=INDPERBUF-1; i>=0; i--) {
424 					a = ((Off *)p->iobuf)[i];
425 					buffree(dev, a, d, nil);
426 				}
427 			else			/* wstat truncation */
428 				for (i = 0; i < INDPERBUF; i++)
429 					truncfree(ts, dev, d, p, i);
430 			putbuf(p);
431 		}
432 	}
433 	if (!pastlast)
434 		return;
435 	/*
436 	 * having zeroed the pointer to this block, add it to the free list.
437 	 * stop outstanding i/o
438 	 */
439 	p = getbuf(dev, addr, Bprobe);
440 	if(p) {
441 		p->flags &= ~(Bmod|Bimm);
442 		putbuf(p);
443 	}
444 	/*
445 	 * dont put written worm
446 	 * blocks into free list
447 	 */
448 	if(dev->type == Devcw) {
449 		i = cwfree(dev, addr);
450 		if(i)
451 			return;
452 	}
453 	p = getbuf(dev, superaddr(dev), Brd|Bmod);
454 	if(!p || checktag(p, Tsuper, QPSUPER))
455 		panic("buffree: super block");
456 	addfree(dev, addr, (Superb*)p->iobuf);
457 	putbuf(p);
458 }
459 
460 Off
461 bufalloc(Device *dev, int tag, long qid, int uid)
462 {
463 	Iobuf *bp, *p;
464 	Superb *sb;
465 	Off a, n;
466 
467 	p = getbuf(dev, superaddr(dev), Brd|Bmod);
468 	if(!p || checktag(p, Tsuper, QPSUPER)) {
469 		print("bufalloc: super block\n");
470 		if(p)
471 			putbuf(p);
472 		return 0;
473 	}
474 	sb = (Superb*)p->iobuf;
475 
476 loop:
477 	n = --sb->fbuf.nfree;
478 	sb->tfree--;
479 	if(n < 0 || n >= FEPERBUF) {
480 		print("bufalloc: %Z: bad freelist\n", dev);
481 		n = 0;
482 		sb->fbuf.free[0] = 0;
483 	}
484 	a = sb->fbuf.free[n];
485 	if(n <= 0) {
486 		if(a == 0) {
487 			sb->tfree = 0;
488 			sb->fbuf.nfree = 1;
489 			if(dev->type == Devcw) {
490 				n = uid;
491 				if(n < 0 || n >= nelem(growacct))
492 					n = 0;
493 				growacct[n]++;
494 				if(cwgrow(dev, sb, uid))
495 					goto loop;
496 			}
497 			putbuf(p);
498 			print("fs %Z full uid=%d\n", dev, uid);
499 			return 0;
500 		}
501 		bp = getbuf(dev, a, Brd);
502 		if(!bp || checktag(bp, Tfree, QPNONE)) {
503 			if(bp)
504 				putbuf(bp);
505 			putbuf(p);
506 			return 0;
507 		}
508 		sb->fbuf = *(Fbuf*)bp->iobuf;
509 		putbuf(bp);
510 	}
511 
512 	bp = getbuf(dev, a, Bmod);
513 	memset(bp->iobuf, 0, RBUFSIZE);
514 	settag(bp, tag, qid);
515 	if(tag == Tind1 || tag == Tind2 || tag == Tdir)
516 		bp->flags |= Bimm;
517 	putbuf(bp);
518 	putbuf(p);
519 	return a;
520 }
521 
522 /*
523  * what are legal characters in a name?
524  * only disallow control characters.
525  * a) utf avoids control characters.
526  * b) '/' may not be the separator
527  */
528 int
529 checkname(char *n)
530 {
531 	int i, c;
532 
533 	for(i=0; i<NAMELEN; i++) {
534 		c = *n & 0xff;
535 		if(c == 0) {
536 			if(i == 0)
537 				return 1;
538 			memset(n, 0, NAMELEN-i);
539 			return 0;
540 		}
541 		if(c <= 040)
542 			return 1;
543 		n++;
544 	}
545 	return 1;	/* too long */
546 }
547 
548 void
549 addfree(Device *dev, Off addr, Superb *sb)
550 {
551 	int n;
552 	Iobuf *p;
553 
554 	n = sb->fbuf.nfree;
555 	if(n < 0 || n > FEPERBUF)
556 		panic("addfree: bad freelist");
557 	if(n >= FEPERBUF) {
558 		p = getbuf(dev, addr, Bmod|Bimm);
559 		if(p == 0)
560 			panic("addfree: getbuf");
561 		*(Fbuf*)p->iobuf = sb->fbuf;
562 		settag(p, Tfree, QPNONE);
563 		putbuf(p);
564 		n = 0;
565 	}
566 	sb->fbuf.free[n++] = addr;
567 	sb->fbuf.nfree = n;
568 	sb->tfree++;
569 	if(addr >= sb->fsize)
570 		sb->fsize = addr+1;
571 }
572 
573 /*
574 static int
575 Yfmt(Fmt* fmt)
576 {
577 	Chan *cp;
578 	char s[20];
579 
580 	cp = va_arg(fmt->args, Chan*);
581 	sprint(s, "C%d.%.3d", cp->type, cp->chan);
582 	return fmtstrcpy(fmt, s);
583 }
584  */
585 
586 static int
587 Zfmt(Fmt* fmt)
588 {
589 	Device *d;
590 	int c, c1;
591 	char s[100];
592 
593 	d = va_arg(fmt->args, Device*);
594 	if(d == nil) {
595 		sprint(s, "Z***");
596 		goto out;
597 	}
598 	c = c1 = '\0';
599 	switch(d->type) {
600 	default:
601 		sprint(s, "D%d", d->type);
602 		break;
603 	case Devwren:
604 		c = 'w';
605 		/* fallthrough */
606 	case Devworm:
607 		if (c == '\0')
608 			c = 'r';
609 		/* fallthrough */
610 	case Devlworm:
611 		if (c == '\0')
612 			c = 'l';
613 		if(d->wren.ctrl == 0 && d->wren.lun == 0)
614 			sprint(s, "%c%d", c, d->wren.targ);
615 		else
616 			sprint(s, "%c%d.%d.%d", c, d->wren.ctrl, d->wren.targ,
617 				d->wren.lun);
618 		break;
619 	case Devmcat:
620 		c = '(';
621 		c1 = ')';
622 		/* fallthrough */
623 	case Devmlev:
624 		if (c == '\0') {
625 			c = '[';
626 			c1 = ']';
627 		}
628 		/* fallthrough */
629 	case Devmirr:
630 		if (c == '\0') {
631 			c = '{';
632 			c1 = '}';
633 		}
634 		if(d->cat.first == d->cat.last)
635 			sprint(s, "%c%Z%c", c, d->cat.first, c1);
636 		else if(d->cat.first->link == d->cat.last)
637 			sprint(s, "%c%Z%Z%c", c, d->cat.first, d->cat.last, c1);
638 		else
639 			sprint(s, "%c%Z-%Z%c", c, d->cat.first, d->cat.last, c1);
640 		break;
641 	case Devro:
642 		sprint(s, "o%Z%Z", d->ro.parent->cw.c, d->ro.parent->cw.w);
643 		break;
644 	case Devcw:
645 		sprint(s, "c%Z%Z", d->cw.c, d->cw.w);
646 		break;
647 	case Devjuke:
648 		sprint(s, "j%Z%Z", d->j.j, d->j.m);
649 		break;
650 	case Devfworm:
651 		sprint(s, "f%Z", d->fw.fw);
652 		break;
653 	case Devpart:
654 		sprint(s, "p(%Z)%ld.%ld", d->part.d, d->part.base, d->part.size);
655 		break;
656 	case Devswab:
657 		sprint(s, "x%Z", d->swab.d);
658 		break;
659 	case Devnone:
660 		sprint(s, "n");
661 		break;
662 	}
663 out:
664 	return fmtstrcpy(fmt, s);
665 }
666 
667 static int
668 Gfmt(Fmt* fmt)
669 {
670 	int t;
671 	char *s;
672 
673 	t = va_arg(fmt->args, int);
674 	s = "<badtag>";
675 	if(t >= 0 && t < MAXTAG)
676 		s = tagnames[t];
677 	return fmtstrcpy(fmt, s);
678 }
679 
680 void
681 formatinit(void)
682 {
683 	quotefmtinstall();
684 //	fmtinstall('Y', Yfmt);	/* print channels */
685 	fmtinstall('Z', Zfmt);	/* print devices */
686 	fmtinstall('G', Gfmt);	/* print tags */
687 	fmtinstall('T', Tfmt);	/* print times */
688 //	fmtinstall('E', eipfmt);	/* print ether addresses */
689 	fmtinstall('I', eipfmt);	/* print ip addresses */
690 }
691 
692 void
693 rootream(Device *dev, Off addr)
694 {
695 	Iobuf *p;
696 	Dentry *d;
697 
698 	p = getbuf(dev, addr, Bmod|Bimm);
699 	memset(p->iobuf, 0, RBUFSIZE);
700 	settag(p, Tdir, QPROOT);
701 	d = getdir(p, 0);
702 	strcpy(d->name, "/");
703 	d->uid = -1;
704 	d->gid = -1;
705 	d->mode = DALLOC | DDIR |
706 		((DREAD|DEXEC) << 6) |
707 		((DREAD|DEXEC) << 3) |
708 		((DREAD|DEXEC) << 0);
709 	d->qid = QID9P1(QPROOT|QPDIR,0);
710 	d->atime = time(nil);
711 	d->mtime = d->atime;
712 	d->muid = 0;
713 	putbuf(p);
714 }
715 
716 void
717 superream(Device *dev, Off addr)
718 {
719 	Iobuf *p;
720 	Superb *s;
721 	Off i;
722 
723 	p = getbuf(dev, addr, Bmod|Bimm);
724 	memset(p->iobuf, 0, RBUFSIZE);
725 	settag(p, Tsuper, QPSUPER);
726 
727 	s = (Superb*)p->iobuf;
728 	s->fstart = 2;
729 	s->fsize = devsize(dev);
730 	s->fbuf.nfree = 1;
731 	s->qidgen = 10;
732 	for(i = s->fsize-1; i >= addr+2; i--)
733 		addfree(dev, i, s);
734 	putbuf(p);
735 }
736 
737 struct
738 {
739 	Lock;
740 	Msgbuf	*smsgbuf;
741 	Msgbuf	*lmsgbuf;
742 } msgalloc;
743 
744 /*
745  * pre-allocate some message buffers at boot time.
746  * if this supply is exhausted, more will be allocated as needed.
747  */
748 void
749 mbinit(void)
750 {
751 	Msgbuf *mb;
752 	Rabuf *rb;
753 	int i;
754 
755 	lock(&msgalloc);
756 	unlock(&msgalloc);
757 	msgalloc.lmsgbuf = 0;
758 	msgalloc.smsgbuf = 0;
759 	for(i=0; i<conf.nlgmsg; i++) {
760 		mb = malloc(sizeof(Msgbuf));
761 		mb->magic = Mbmagic;
762 		mb->xdata = malloc(LARGEBUF+Slop);
763 		mb->flags = LARGE;
764 		mbfree(mb);
765 		cons.nlarge++;
766 	}
767 	for(i=0; i<conf.nsmmsg; i++) {
768 		mb = malloc(sizeof(Msgbuf));
769 		mb->magic = Mbmagic;
770 		mb->xdata = malloc(SMALLBUF+Slop);
771 		mb->flags = 0;
772 		mbfree(mb);
773 		cons.nsmall++;
774 	}
775 	memset(mballocs, 0, sizeof(mballocs));
776 
777 	lock(&rabuflock);
778 	unlock(&rabuflock);
779 	rabuffree = 0;
780 	for(i=0; i<1000; i++) {
781 		rb = malloc(sizeof(*rb));
782 		rb->link = rabuffree;
783 		rabuffree = rb;
784 	}
785 }
786 
787 Msgbuf*
788 mballoc(int count, Chan *cp, int category)
789 {
790 	Msgbuf *mb;
791 
792 	lock(&msgalloc);
793 	if(count > SMALLBUF) {
794 		if(count > LARGEBUF)
795 			panic("msgbuf count");
796 		mb = msgalloc.lmsgbuf;
797 		if(mb == nil) {
798 			mb = malloc(sizeof(Msgbuf));
799 			mb->xdata = malloc(LARGEBUF+Slop);
800 			cons.nlarge++;
801 		} else
802 			msgalloc.lmsgbuf = mb->next;
803 		mb->flags = LARGE;
804 	} else {
805 		mb = msgalloc.smsgbuf;
806 		if(mb == nil) {
807 			mb = malloc(sizeof(Msgbuf));
808 			mb->xdata = malloc(SMALLBUF+Slop);
809 			cons.nsmall++;
810 		} else
811 			msgalloc.smsgbuf = mb->next;
812 		mb->flags = 0;
813 	}
814 	mballocs[category]++;
815 	unlock(&msgalloc);
816 	mb->magic = Mbmagic;
817 	mb->count = count;
818 	mb->chan = cp;
819 	mb->next = 0;
820 	mb->param = 0;
821 	mb->category = category;
822 	mb->data = mb->xdata+Slop;
823 	return mb;
824 }
825 
826 void
827 mbfree(Msgbuf *mb)
828 {
829 	if(mb == nil)
830 		return;
831 	assert(mb->magic == Mbmagic);
832 	if (mb->magic != Mbmagic)
833 		panic("mbfree: bad magic 0x%lux", mb->magic);
834 	if(mb->flags & BTRACE)
835 		print("mbfree: BTRACE cat=%d flags=%ux, caller %#p\n",
836 			mb->category, mb->flags, getcallerpc(&mb));
837 
838 	if(mb->flags & FREE)
839 		panic("mbfree already free");
840 
841 	lock(&msgalloc);
842 	mballocs[mb->category]--;
843 	mb->flags |= FREE;
844 	if(mb->flags & LARGE) {
845 		mb->next = msgalloc.lmsgbuf;
846 		msgalloc.lmsgbuf = mb;
847 	} else {
848 		mb->next = msgalloc.smsgbuf;
849 		msgalloc.smsgbuf = mb;
850 	}
851 	mb->data = 0;
852 	mb->magic = 0;
853 	unlock(&msgalloc);
854 }
855 
856 /*
857  * returns 1 if n is prime
858  * used for adjusting lengths
859  * of hashing things.
860  * there is no need to be clever
861  */
862 int
863 prime(vlong n)
864 {
865 	long i;
866 
867 	if((n%2) == 0)
868 		return 0;
869 	for(i=3;; i+=2) {
870 		if((n%i) == 0)
871 			return 0;
872 		if((vlong)i*i >= n)
873 			return 1;
874 	}
875 }
876 
877 char*
878 getwrd(char *word, char *line)
879 {
880 	int c, n;
881 
882 	while(isascii(*line) && isspace(*line) && *line != '\n')
883 		line++;
884 	for(n = 0; n < Maxword; n++) {
885 		c = *line;
886 		if(c == '\0' || isascii(c) && isspace(c))
887 			break;
888 		line++;
889 		*word++ = c;
890 	}
891 	*word = 0;
892 	return line;
893 }
894 
895 void
896 hexdump(void *a, int n)
897 {
898 	char s1[30], s2[4];
899 	uchar *p;
900 	int i;
901 
902 	p = a;
903 	s1[0] = 0;
904 	for(i = 0; i < n; i++) {
905 		sprint(s2, " %.2ux", p[i]);
906 		strcat(s1, s2);
907 		if((i&7) == 7) {
908 			print("%s\n", s1);
909 			s1[0] = 0;
910 		}
911 	}
912 	if(s1[0])
913 		print("%s\n", s1);
914 }
915 
916 void*
917 fs_recv(Queue *q, int)
918 {
919 	void *a;
920 	int i, c;
921 
922 	if(q == nil)
923 		panic("recv null q");
924 	qlock(q);
925 	q->waitedfor = 1;
926 	while((c = q->count) <= 0)
927 		rsleep(&q->empty);
928 	i = q->loc;
929 	a = q->args[i];
930 	i++;
931 	if(i >= q->size)
932 		i = 0;
933 	q->loc = i;
934 	q->count = c-1;
935 	rwakeup(&q->full);			/* no longer full */
936 	qunlock(q);
937 	return a;
938 }
939 
940 void
941 fs_send(Queue *q, void *a)
942 {
943 	int i, c;
944 
945 	if(q == nil)
946 		panic("send null q");
947 	if(!q->waitedfor) {
948 		for (i = 0; i < 5 && !q->waitedfor; i++)
949 			sleep(1000);
950 		if(!q->waitedfor) {
951 			/* likely a bug; don't wait forever */
952 			print("no readers yet for %s q\n", q->name);
953 			abort();
954 		}
955 	}
956 	qlock(q);
957 	while((c = q->count) >= q->size)
958 		rsleep(&q->full);
959 	i = q->loc + c;
960 	if(i >= q->size)
961 		i -= q->size;
962 	q->args[i] = a;
963 	q->count = c+1;
964 	rwakeup(&q->empty);			/* no longer empty */
965 	qunlock(q);
966 }
967 
968 Queue*
969 newqueue(int size, char *name)
970 {
971 	Queue *q;
972 
973 	q = malloc(sizeof(Queue) + (size-1)*sizeof(void*));
974 	q->size = size;
975 	q->full.l = q->empty.l = &q->QLock;
976 	q->name = name;
977 	return q;
978 }
979 
980 int
981 devread(Device *d, Off b, void *c)
982 {
983 	int e;
984 
985 	for (;;)
986 		switch(d->type) {
987 		case Devcw:
988 			return cwread(d, b, c);
989 
990 		case Devjuke:
991 			d = d->j.m;
992 			break;
993 
994 		case Devro:
995 			return roread(d, b, c);
996 
997 		case Devwren:
998 			return wrenread(d, b, c);
999 
1000 		case Devworm:
1001 		case Devlworm:
1002 			return wormread(d, b, c);
1003 
1004 		case Devfworm:
1005 			return fwormread(d, b, c);
1006 
1007 		case Devmcat:
1008 			return mcatread(d, b, c);
1009 
1010 		case Devmlev:
1011 			return mlevread(d, b, c);
1012 
1013 		case Devmirr:
1014 			return mirrread(d, b, c);
1015 
1016 		case Devpart:
1017 			return partread(d, b, c);
1018 
1019 		case Devswab:
1020 			e = devread(d->swab.d, b, c);
1021 			if(e == 0)
1022 				swab(c, 0);
1023 			return e;
1024 
1025 		case Devnone:
1026 			print("read from device none(%lld)\n", (Wideoff)b);
1027 			return 1;
1028 		default:
1029 			panic("illegal device in devread: %Z %lld",
1030 				d, (Wideoff)b);
1031 			return 1;
1032 		}
1033 }
1034 
1035 int
1036 devwrite(Device *d, Off b, void *c)
1037 {
1038 	int e;
1039 
1040 	/*
1041 	 * set readonly to non-0 to prevent all writes;
1042 	 * mainly for trying dangerous experiments.
1043 	 */
1044 	if (readonly)
1045 		return 0;
1046 	for (;;)
1047 		switch(d->type) {
1048 		case Devcw:
1049 			return cwwrite(d, b, c);
1050 
1051 		case Devjuke:
1052 			d = d->j.m;
1053 			break;
1054 
1055 		case Devro:
1056 			print("write to ro device %Z(%lld)\n", d, (Wideoff)b);
1057 			return 1;
1058 
1059 		case Devwren:
1060 			return wrenwrite(d, b, c);
1061 
1062 		case Devworm:
1063 		case Devlworm:
1064 			return wormwrite(d, b, c);
1065 
1066 		case Devfworm:
1067 			return fwormwrite(d, b, c);
1068 
1069 		case Devmcat:
1070 			return mcatwrite(d, b, c);
1071 
1072 		case Devmlev:
1073 			return mlevwrite(d, b, c);
1074 
1075 		case Devmirr:
1076 			return mirrwrite(d, b, c);
1077 
1078 		case Devpart:
1079 			return partwrite(d, b, c);
1080 
1081 		case Devswab:
1082 			swab(c, 1);
1083 			e = devwrite(d->swab.d, b, c);
1084 			swab(c, 0);
1085 			return e;
1086 
1087 		case Devnone:
1088 			/* checktag() can generate blocks with type devnone */
1089 			return 0;
1090 		default:
1091 			panic("illegal device in devwrite: %Z %lld",
1092 				d, (Wideoff)b);
1093 			return 1;
1094 		}
1095 }
1096 
1097 Devsize
1098 devsize(Device *d)
1099 {
1100 	for (;;)
1101 		switch(d->type) {
1102 		case Devcw:
1103 		case Devro:
1104 			return cwsize(d);
1105 
1106 		case Devjuke:
1107 			d = d->j.m;
1108 			break;
1109 
1110 		case Devwren:
1111 			return wrensize(d);
1112 
1113 		case Devworm:
1114 		case Devlworm:
1115 			return wormsize(d);
1116 
1117 		case Devfworm:
1118 			return fwormsize(d);
1119 
1120 		case Devmcat:
1121 			return mcatsize(d);
1122 
1123 		case Devmlev:
1124 			return mlevsize(d);
1125 
1126 		case Devmirr:
1127 			return mirrsize(d);
1128 
1129 		case Devpart:
1130 			return partsize(d);
1131 
1132 		case Devswab:
1133 			d = d->swab.d;
1134 			break;
1135 		default:
1136 			panic("illegal device in devsize: %Z", d);
1137 			return 0;
1138 		}
1139 }
1140 
1141 /* result is malloced */
1142 char *
1143 sdof(Device *d)
1144 {
1145 	static char name[256];
1146 
1147 	for (;;)
1148 		switch(d->type) {
1149 		case Devjuke:
1150 			d = d->j.j;		/* robotics */
1151 			break;
1152 		case Devwren:
1153 			snprint(name, sizeof name, "/dev/sd%d%d", d->wren.ctrl,
1154 				d->wren.targ);
1155 			return strdup(name);
1156 		case Devswab:
1157 			d = d->swab.d;
1158 			break;
1159 		default:
1160 			panic("illegal device in sdof: %Z", d);
1161 			return nil;
1162 		}
1163 }
1164 
1165 Off
1166 superaddr(Device *d)
1167 {
1168 	for (;;)
1169 		switch(d->type) {
1170 		default:
1171 			return SUPER_ADDR;
1172 		case Devcw:
1173 		case Devro:
1174 			return cwsaddr(d);
1175 		case Devswab:
1176 			d = d->swab.d;
1177 			break;
1178 		}
1179 }
1180 
1181 Off
1182 getraddr(Device *d)
1183 {
1184 	for (;;)
1185 		switch(d->type) {
1186 		default:
1187 			return ROOT_ADDR;
1188 		case Devcw:
1189 		case Devro:
1190 			return cwraddr(d);
1191 		case Devswab:
1192 			d = d->swab.d;
1193 			break;
1194 		}
1195 }
1196 
1197 void
1198 devream(Device *d, int top)
1199 {
1200 	Device *l;
1201 
1202 loop:
1203 	print("\tdevream: %Z %d\n", d, top);
1204 	switch(d->type) {
1205 	default:
1206 		print("ream: unknown dev type %Z\n", d);
1207 		return;
1208 
1209 	case Devcw:
1210 		devream(d->cw.w, 0);
1211 		devream(d->cw.c, 0);
1212 		if(top) {
1213 			wlock(&mainlock);
1214 			cwream(d);
1215 			wunlock(&mainlock);
1216 		}
1217 		devinit(d);
1218 		return;
1219 
1220 	case Devfworm:
1221 		devream(d->fw.fw, 0);
1222 		fwormream(d);
1223 		break;
1224 
1225 	case Devpart:
1226 		devream(d->part.d, 0);
1227 		break;
1228 
1229 	case Devmlev:
1230 	case Devmcat:
1231 	case Devmirr:
1232 		for(l=d->cat.first; l; l=l->link)
1233 			devream(l, 0);
1234 		break;
1235 
1236 	case Devjuke:
1237 	case Devworm:
1238 	case Devlworm:
1239 	case Devwren:
1240 		break;
1241 
1242 	case Devswab:
1243 		d = d->swab.d;
1244 		goto loop;
1245 	}
1246 	devinit(d);
1247 	if(top) {
1248 		wlock(&mainlock);
1249 		rootream(d, ROOT_ADDR);
1250 		superream(d, SUPER_ADDR);
1251 		wunlock(&mainlock);
1252 	}
1253 }
1254 
1255 void
1256 devrecover(Device *d)
1257 {
1258 	for (;;) {
1259 		print("recover: %Z\n", d);
1260 		switch(d->type) {
1261 		default:
1262 			print("recover: unknown dev type %Z\n", d);
1263 			return;
1264 
1265 		case Devcw:
1266 			wlock(&mainlock);	/* recover */
1267 			cwrecover(d);
1268 			wunlock(&mainlock);
1269 			return;
1270 
1271 		case Devswab:
1272 			d = d->swab.d;
1273 			break;
1274 		}
1275 	}
1276 }
1277 
1278 void
1279 devinit(Device *d)
1280 {
1281 	for (;;) {
1282 		if(d->init)
1283 			return;
1284 		d->init = 1;
1285 		print("\tdevinit %Z\n", d);
1286 		switch(d->type) {
1287 		default:
1288 			print("devinit unknown device %Z\n", d);
1289 			return;
1290 
1291 		case Devro:
1292 			cwinit(d->ro.parent);
1293 			return;
1294 
1295 		case Devcw:
1296 			cwinit(d);
1297 			return;
1298 
1299 		case Devjuke:
1300 			jukeinit(d);
1301 			return;
1302 
1303 		case Devwren:
1304 			wreninit(d);
1305 			return;
1306 
1307 		case Devworm:
1308 		case Devlworm:
1309 			return;
1310 
1311 		case Devfworm:
1312 			fworminit(d);
1313 			return;
1314 
1315 		case Devmcat:
1316 			mcatinit(d);
1317 			return;
1318 
1319 		case Devmlev:
1320 			mlevinit(d);
1321 			return;
1322 
1323 		case Devmirr:
1324 			mirrinit(d);
1325 			return;
1326 
1327 		case Devpart:
1328 			partinit(d);
1329 			return;
1330 
1331 		case Devswab:
1332 			d = d->swab.d;
1333 			break;
1334 
1335 		case Devnone:
1336 			print("devinit of Devnone\n");
1337 			return;
1338 		}
1339 	}
1340 }
1341 
1342 void
1343 swab2(void *c)
1344 {
1345 	uchar *p;
1346 	int t;
1347 
1348 	p = c;
1349 
1350 	t = p[0];
1351 	p[0] = p[1];
1352 	p[1] = t;
1353 }
1354 
1355 void
1356 swab4(void *c)
1357 {
1358 	uchar *p;
1359 	int t;
1360 
1361 	p = c;
1362 
1363 	t = p[0];
1364 	p[0] = p[3];
1365 	p[3] = t;
1366 
1367 	t = p[1];
1368 	p[1] = p[2];
1369 	p[2] = t;
1370 }
1371 
1372 void
1373 swab8(void *c)
1374 {
1375 	uchar *p;
1376 	int t;
1377 
1378 	p = c;
1379 
1380 	t = p[0];
1381 	p[0] = p[7];
1382 	p[7] = t;
1383 
1384 	t = p[1];
1385 	p[1] = p[6];
1386 	p[6] = t;
1387 
1388 	t = p[2];
1389 	p[2] = p[5];
1390 	p[5] = t;
1391 
1392 	t = p[3];
1393 	p[3] = p[4];
1394 	p[4] = t;
1395 }
1396 
1397 /*
1398  * swab a block
1399  *	flag = 0 -- convert from foreign to native
1400  *	flag = 1 -- convert from native to foreign
1401  */
1402 void
1403 swab(void *c, int flag)
1404 {
1405 	uchar *p;
1406 	Tag *t;
1407 	int i, j;
1408 	Dentry *d;
1409 	Cache *h;
1410 	Bucket *b;
1411 	Superb *s;
1412 	Fbuf *f;
1413 	Off *l;
1414 
1415 	/* swab the tag */
1416 	p = (uchar*)c;
1417 	t = (Tag*)(p + BUFSIZE);
1418 	if(!flag) {
1419 		swab2(&t->pad);
1420 		swab2(&t->tag);
1421 		swaboff(&t->path);
1422 	}
1423 
1424 	/* swab each block type */
1425 	switch(t->tag) {
1426 
1427 	default:
1428 		print("no swab for tag=%G rw=%d\n", t->tag, flag);
1429 		for(j=0; j<16; j++)
1430 			print(" %.2x", p[BUFSIZE+j]);
1431 		print("\n");
1432 		for(i=0; i<16; i++) {
1433 			print("%.4x", i*16);
1434 			for(j=0; j<16; j++)
1435 				print(" %.2x", p[i*16+j]);
1436 			print("\n");
1437 		}
1438 		panic("swab");
1439 		break;
1440 
1441 	case Tsuper:
1442 		s = (Superb*)p;
1443 		swaboff(&s->fbuf.nfree);
1444 		for(i=0; i<FEPERBUF; i++)
1445 			swaboff(&s->fbuf.free[i]);
1446 		swaboff(&s->fstart);
1447 		swaboff(&s->fsize);
1448 		swaboff(&s->tfree);
1449 		swaboff(&s->qidgen);
1450 		swaboff(&s->cwraddr);
1451 		swaboff(&s->roraddr);
1452 		swaboff(&s->last);
1453 		swaboff(&s->next);
1454 		break;
1455 
1456 	case Tdir:
1457 		for(i=0; i<DIRPERBUF; i++) {
1458 			d = (Dentry*)p + i;
1459 			swab2(&d->uid);
1460 			swab2(&d->gid);
1461 			swab2(&d->mode);
1462 			swab2(&d->muid);
1463 			swaboff(&d->qid.path);
1464 			swab4(&d->qid.version);
1465 			swaboff(&d->size);
1466 			for(j=0; j<NDBLOCK; j++)
1467 				swaboff(&d->dblock[j]);
1468 			for (j = 0; j < NIBLOCK; j++)
1469 				swaboff(&d->iblocks[j]);
1470 			swab4(&d->atime);
1471 			swab4(&d->mtime);
1472 		}
1473 		break;
1474 
1475 	case Tind1:
1476 	case Tind2:
1477 #ifndef COMPAT32
1478 	case Tind3:
1479 	case Tind4:
1480 	/* add more Tind tags here ... */
1481 #endif
1482 		l = (Off *)p;
1483 		for(i=0; i<INDPERBUF; i++) {
1484 			swaboff(l);
1485 			l++;
1486 		}
1487 		break;
1488 
1489 	case Tfree:
1490 		f = (Fbuf*)p;
1491 		swaboff(&f->nfree);
1492 		for(i=0; i<FEPERBUF; i++)
1493 			swaboff(&f->free[i]);
1494 		break;
1495 
1496 	case Tbuck:
1497 		for(i=0; i<BKPERBLK; i++) {
1498 			b = (Bucket*)p + i;
1499 			swab4(&b->agegen);
1500 			for(j=0; j<CEPERBK; j++) {
1501 				swab2(&b->entry[j].age);
1502 				swab2(&b->entry[j].state);
1503 				swaboff(&b->entry[j].waddr);
1504 			}
1505 		}
1506 		break;
1507 
1508 	case Tcache:
1509 		h = (Cache*)p;
1510 		swaboff(&h->maddr);
1511 		swaboff(&h->msize);
1512 		swaboff(&h->caddr);
1513 		swaboff(&h->csize);
1514 		swaboff(&h->fsize);
1515 		swaboff(&h->wsize);
1516 		swaboff(&h->wmax);
1517 		swaboff(&h->sbaddr);
1518 		swaboff(&h->cwraddr);
1519 		swaboff(&h->roraddr);
1520 		swab4(&h->toytime);
1521 		swab4(&h->time);
1522 		break;
1523 
1524 	case Tnone:	// unitialized
1525 	case Tfile:	// someone elses problem
1526 	case Tvirgo:	// bit map -- all bytes
1527 	case Tconfig:	// configuration string -- all bytes
1528 		break;
1529 	}
1530 
1531 	/* swab the tag */
1532 	if(flag) {
1533 		swab2(&t->pad);
1534 		swab2(&t->tag);
1535 		swaboff(&t->path);
1536 	}
1537 }
1538