5 Slop = 256, /* room at the start of a message buf for proto hdrs */
13 for(fs=filsys; fs->name; fs++)
14 if(strcmp(fs->name, p) == 0)
24 for(fs=filsys; fs->name; fs++)
31 * allocate 'count' contiguous channels
32 * of type 'type' and return pointer to base
35 fs_chaninit(int type, int count, int data)
41 p = malloc(count * (sizeof(Chan)+data));
43 for(i = 0; i < count; i++) {
48 cp->chan = cons.chano;
50 strncpy(cp->whoname, "<none>", sizeof cp->whoname);
52 wunlock(&cp->reflock);
54 runlock(&cp->reflock);
74 for (h=0; h < nelem(flist); h++)
75 for (prev=0, f = flist[h]; f; prev=f, f=f->next) {
89 t->time = 0; /* free the lock */
105 enum { NOFID = (ulong)~0 };
108 * returns a locked file structure
111 filep(Chan *cp, ulong fid, int flag)
119 h = (long)(uintptr)cp + fid;
126 for(f=flist[h]; f; f=f->next)
127 if(f->fid == fid && f->cp == cp){
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.
134 if(flag == 0 || cp == cons.chan)
161 if(f->fid == fid && f->cp == cp)
168 * always called with flock locked
190 fprint(2, "out of files\n");
201 if(!fp || !(cp = fp->cp))
204 h = (long)(uintptr)cp + fp->fid;
210 for(prev=0,f=flist[h]; f; prev=f,f=f->next)
213 prev->next = f->next;
223 iaccess(File *f, Dentry *d, int m)
225 /* uid none gets only other permissions */
236 if(ingroup(f->uid, d->gid))
245 if((d->mode & DDIR) && (m == DEXEC))
247 if(!ingroup(f->uid, 9999))
252 * various forms of superuser
256 if(duallow != 0 && duallow == f->uid)
257 if((d->mode & DDIR) && (m == DREAD || m == DEXEC))
264 tlocked(Iobuf *p, Dentry *d)
277 for(t=tlocks+NTLOCK-1; t>=tlocks; t--) {
278 if(t->qpath == qpath)
281 return nil; /* its locked */
282 if(t1 != nil && t->time == 0)
283 t1 = t; /* remember free lock */
288 for(t=tlocks+NTLOCK-1; t>=tlocks; t--)
303 t1->time = tim + TLOCK;
307 * out of tlock nodes simulates
321 if(i < 0 || i >= conf.nwpath)
325 ew = &wpaths[conf.nwpath];
331 fprint(2, "out of wpaths\n");
359 qidpathgen(Device *dev)
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;
375 /* truncating to length > 0 */
377 truncfree(Truncstate *ts, Device *dev, int d, Iobuf *p, int i)
382 pastlast = ts->pastlast;
383 a = ((Off *)p->iobuf)[i];
384 if (d > 0 || pastlast)
385 buffree(dev, a, d, ts);
387 ((Off *)p->iobuf)[i] = 0;
388 p->flags |= Bmod|Bimm;
389 } else if (d == 0 && ts->relblk == ts->lastblk)
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.
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).
405 buffree(Device *dev, Off addr, int d, Truncstate *ts)
413 pastlast = (ts == nil? 1: ts->pastlast);
415 * if this is an indirect block, recurse and free any
416 * suitable blocks within it (possibly via further indirect blocks).
420 p = getbuf(dev, addr, Brd);
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);
427 else /* wstat truncation */
428 for (i = 0; i < INDPERBUF; i++)
429 truncfree(ts, dev, d, p, i);
436 * having zeroed the pointer to this block, add it to the free list.
437 * stop outstanding i/o
439 p = getbuf(dev, addr, Bprobe);
441 p->flags &= ~(Bmod|Bimm);
445 * dont put written worm
446 * blocks into free list
448 if(dev->type == Devcw) {
449 i = cwfree(dev, addr);
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);
461 bufalloc(Device *dev, int tag, long qid, int uid)
467 p = getbuf(dev, superaddr(dev), Brd|Bmod);
468 if(!p || checktag(p, Tsuper, QPSUPER)) {
469 fprint(2, "bufalloc: super block\n");
474 sb = (Superb*)p->iobuf;
477 n = --sb->fbuf.nfree;
479 if(n < 0 || n >= FEPERBUF) {
480 fprint(2, "bufalloc: %Z: bad freelist\n", dev);
482 sb->fbuf.free[0] = 0;
484 a = sb->fbuf.free[n];
489 if(dev->type == Devcw) {
491 if(n < 0 || n >= nelem(growacct))
494 if(cwgrow(dev, sb, uid))
498 fprint(2, "fs %Z full uid=%d\n", dev, uid);
501 bp = getbuf(dev, a, Brd);
502 if(!bp || checktag(bp, Tfree, QPNONE)) {
508 sb->fbuf = *(Fbuf*)bp->iobuf;
512 bp = getbuf(dev, a, Bmod);
513 memset(bp->iobuf, 0, RBUFSIZE);
514 settag(bp, tag, qid);
515 if(tag == Tind1 || tag == Tind2 ||
517 tag == Tind3 || tag == Tind4 || /* add more Tind tags here ... */
527 * what are legal characters in a name?
528 * only disallow control characters.
529 * a) utf avoids control characters.
530 * b) '/' may not be the separator
537 if(n == 0 || *n == 0)
539 if(*n == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)))
541 for(i=1; i<NAMELEN; i++) {
552 addfree(Device *dev, Off addr, Superb *sb)
558 if(n < 0 || n > FEPERBUF)
559 panic("addfree: bad freelist");
561 p = getbuf(dev, addr, Bmod|Bimm);
563 panic("addfree: getbuf");
564 *(Fbuf*)p->iobuf = sb->fbuf;
565 settag(p, Tfree, QPNONE);
569 sb->fbuf.free[n++] = addr;
572 if(addr >= sb->fsize)
583 cp = va_arg(fmt->args, Chan*);
584 sprint(s, "C%d.%.3d", cp->type, cp->chan);
585 return fmtstrcpy(fmt, s);
596 d = va_arg(fmt->args, Device*);
604 sprint(s, "D%d", d->type);
617 snprint(s, sizeof(s), "%c\"%s\"", c, d->wren.file);
618 else if(d->wren.ctrl == 0 && d->wren.lun == 0)
619 sprint(s, "%c%d", c, d->wren.targ);
621 sprint(s, "%c%d.%d.%d", c, d->wren.ctrl, d->wren.targ,
639 if(d->cat.first == d->cat.last)
640 sprint(s, "%c%Z%c", c, d->cat.first, c1);
641 else if(d->cat.first->link == d->cat.last)
642 sprint(s, "%c%Z%Z%c", c, d->cat.first, d->cat.last, c1);
644 sprint(s, "%c%Z-%Z%c", c, d->cat.first, d->cat.last, c1);
647 sprint(s, "o%Z%Z", d->ro.parent->cw.c, d->ro.parent->cw.w);
650 sprint(s, "c%Z%Z", d->cw.c, d->cw.w);
653 sprint(s, "j%Z%Z", d->j.j, d->j.m);
656 sprint(s, "f%Z", d->fw.fw);
659 sprint(s, "p(%Z)%ld.%ld", d->part.d, d->part.base, d->part.size);
662 sprint(s, "x%Z", d->swab.d);
669 return fmtstrcpy(fmt, s);
678 t = va_arg(fmt->args, int);
680 if(t >= 0 && t < MAXTAG)
682 return fmtstrcpy(fmt, s);
689 // fmtinstall('Y', Yfmt); /* print channels */
690 fmtinstall('Z', Zfmt); /* print devices */
691 fmtinstall('G', Gfmt); /* print tags */
692 fmtinstall('T', Tfmt); /* print times */
693 // fmtinstall('E', eipfmt); /* print ether addresses */
694 fmtinstall('I', eipfmt); /* print ip addresses */
698 rootream(Device *dev, Off addr)
703 p = getbuf(dev, addr, Bmod|Bimm);
704 memset(p->iobuf, 0, RBUFSIZE);
705 settag(p, Tdir, QPROOT);
707 strcpy(d->name, "/");
710 d->mode = DALLOC | DDIR |
711 ((DREAD|DEXEC) << 6) |
712 ((DREAD|DEXEC) << 3) |
713 ((DREAD|DEXEC) << 0);
714 d->qid = QID9P1(QPROOT|QPDIR,0);
715 d->atime = time(nil);
722 superream(Device *dev, Off addr)
728 p = getbuf(dev, addr, Bmod|Bimm);
729 memset(p->iobuf, 0, RBUFSIZE);
730 settag(p, Tsuper, QPSUPER);
732 s = (Superb*)p->iobuf;
734 s->fsize = devsize(dev);
737 for(i = s->fsize-1; i >= addr+2; i--)
750 * pre-allocate some message buffers at boot time.
751 * if this supply is exhausted, more will be allocated as needed.
762 msgalloc.lmsgbuf = 0;
763 msgalloc.smsgbuf = 0;
764 for(i=0; i<conf.nlgmsg; i++) {
765 mb = malloc(sizeof(Msgbuf));
767 mb->xdata = malloc(LARGEBUF+Slop);
772 for(i=0; i<conf.nsmmsg; i++) {
773 mb = malloc(sizeof(Msgbuf));
775 mb->xdata = malloc(SMALLBUF+Slop);
780 memset(mballocs, 0, sizeof(mballocs));
785 for(i=0; i<1000; i++) {
786 rb = malloc(sizeof(*rb));
787 rb->link = rabuffree;
793 mballoc(int count, Chan *cp, int category)
798 if(count > SMALLBUF) {
800 panic("msgbuf count");
801 mb = msgalloc.lmsgbuf;
803 mb = malloc(sizeof(Msgbuf));
804 mb->xdata = malloc(LARGEBUF+Slop);
807 msgalloc.lmsgbuf = mb->next;
810 mb = msgalloc.smsgbuf;
812 mb = malloc(sizeof(Msgbuf));
813 mb->xdata = malloc(SMALLBUF+Slop);
816 msgalloc.smsgbuf = mb->next;
819 mballocs[category]++;
826 mb->category = category;
827 mb->data = mb->xdata+Slop;
836 assert(mb->magic == Mbmagic);
837 if (mb->magic != Mbmagic)
838 panic("mbfree: bad magic 0x%lux", mb->magic);
839 if(mb->flags & BTRACE)
840 print("mbfree: BTRACE cat=%d flags=%ux, caller %#p\n",
841 mb->category, mb->flags, getcallerpc(&mb));
844 panic("mbfree already free");
847 mballocs[mb->category]--;
849 if(mb->flags & LARGE) {
850 mb->next = msgalloc.lmsgbuf;
851 msgalloc.lmsgbuf = mb;
853 mb->next = msgalloc.smsgbuf;
854 msgalloc.smsgbuf = mb;
862 * returns 1 if n is prime
863 * used for adjusting lengths
865 * there is no need to be clever
883 getwrd(char *word, char *line)
887 while(isascii(*line) && isspace(*line) && *line != '\n')
889 for(n = 0; n < Maxword; n++) {
891 if(c == '\0' || isascii(c) && isspace(c))
901 hexdump(void *a, int n)
909 for(i = 0; i < n; i++) {
910 sprint(s2, " %.2ux", p[i]);
922 fs_recv(Queue *q, int)
928 panic("recv null q");
930 while((c = q->count) <= 0)
939 rwakeup(&q->full); /* no longer full */
945 fs_send(Queue *q, void *a)
950 panic("send null q");
952 while((c = q->count) >= q->size)
959 rwakeup(&q->empty); /* no longer empty */
964 newqueue(int size, char *name)
968 q = malloc(sizeof(Queue) + (size-1)*sizeof(void*));
970 q->full.l = q->empty.l = &q->QLock;
976 devread(Device *d, Off b, void *c)
983 return cwread(d, b, c);
990 return roread(d, b, c);
993 return wrenread(d, b, c);
997 return wormread(d, b, c);
1000 return fwormread(d, b, c);
1003 return mcatread(d, b, c);
1006 return mlevread(d, b, c);
1009 return mirrread(d, b, c);
1012 return partread(d, b, c);
1015 e = devread(d->swab.d, b, c);
1021 fprint(2, "read from device none(%lld)\n", (Wideoff)b);
1024 panic("illegal device in devread: %Z %lld",
1031 devwrite(Device *d, Off b, void *c)
1036 * set readonly to non-0 to prevent all writes;
1037 * mainly for trying dangerous experiments.
1044 return cwwrite(d, b, c);
1051 fprint(2, "write to ro device %Z(%lld)\n", d, (Wideoff)b);
1055 return wrenwrite(d, b, c);
1059 return wormwrite(d, b, c);
1062 return fwormwrite(d, b, c);
1065 return mcatwrite(d, b, c);
1068 return mlevwrite(d, b, c);
1071 return mirrwrite(d, b, c);
1074 return partwrite(d, b, c);
1078 e = devwrite(d->swab.d, b, c);
1083 /* checktag() can generate blocks with type devnone */
1086 panic("illegal device in devwrite: %Z %lld",
1113 return fwormsize(d);
1131 panic("illegal device in devsize: %Z", d);
1136 /* result is malloced */
1140 static char name[256];
1145 d = d->j.j; /* robotics */
1148 snprint(name, sizeof name, "/dev/sd%d%d", d->wren.ctrl,
1150 return strdup(name);
1155 panic("illegal device in sdof: %Z", d);
1161 superaddr(Device *d)
1193 devream(Device *d, int top)
1199 print("\tdevream %Z %d\n", d, top);
1202 fprint(2, "devream: unknown dev type %Z\n", d);
1206 devream(d->cw.w, 0);
1207 devream(d->cw.c, 0);
1217 devream(d->fw.fw, 0);
1222 devream(d->part.d, 0);
1228 for(l=d->cat.first; l; l=l->link)
1245 rootream(d, ROOT_ADDR);
1246 superream(d, SUPER_ADDR);
1252 devrecover(Device *d)
1256 print("recover %Z\n", d);
1259 fprint(2, "devrecover: unknown dev type %Z\n", d);
1263 wlock(&mainlock); /* recover */
1283 print("\tdevinit %Z\n", d);
1286 fprint(2, "devinit: unknown device %Z\n", d);
1290 cwinit(d->ro.parent);
1396 * flag = 0 -- convert from foreign to native
1397 * flag = 1 -- convert from native to foreign
1400 swab(void *c, int flag)
1414 t = (Tag*)(p + BUFSIZE);
1421 /* swab each block type */
1424 fprint(2, "no swab for tag=%G rw=%d\n", t->tag, flag);
1431 swaboff(&s->fbuf.nfree);
1432 for(i=0; i<FEPERBUF; i++)
1433 swaboff(&s->fbuf.free[i]);
1434 swaboff(&s->fstart);
1437 swaboff(&s->qidgen);
1438 swaboff(&s->cwraddr);
1439 swaboff(&s->roraddr);
1445 for(i=0; i<DIRPERBUF; i++) {
1451 swaboff(&d->qid.path);
1452 swab4(&d->qid.version);
1454 for(j=0; j<NDBLOCK; j++)
1455 swaboff(&d->dblock[j]);
1456 for (j = 0; j < NIBLOCK; j++)
1457 swaboff(&d->iblocks[j]);
1468 /* add more Tind tags here ... */
1471 for(i=0; i<INDPERBUF; i++) {
1480 for(i=0; i<FEPERBUF; i++)
1481 swaboff(&f->free[i]);
1485 for(i=0; i<BKPERBLK; i++) {
1488 for(j=0; j<CEPERBK; j++) {
1489 swab2(&b->entry[j].age);
1490 swab2(&b->entry[j].state);
1491 swaboff(&b->entry[j].waddr);
1505 swaboff(&h->sbaddr);
1506 swaboff(&h->cwraddr);
1507 swaboff(&h->roraddr);
1512 case Tnone: // unitialized
1513 case Tfile: // someone elses problem
1514 case Tvirgo: // bit map -- all bytes
1515 case Tconfig: // configuration string -- all bytes