From 654edeace8256b43d92d62f989435dbcc1dd7f0f Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 4 Sep 1991 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1991-09-04 --- pc/bbmalloc.c | 84 ++- pc/devuart.c | 5 +- pc/io.h | 2 +- pc/kbd.c | 23 +- pc/l.s | 60 ++- pc/trap.c | 28 +- pc/vga.c | 5 +- port/devmnt.c | 1314 ++++++++++++++++++++++++++++------------------- port/devnonet.c | 3 +- port/stream.c | 1 + port/sysfile.c | 6 +- 11 files changed, 875 insertions(+), 656 deletions(-) diff --git a/pc/bbmalloc.c b/pc/bbmalloc.c index c7cb9b55d868e6cb0a1a97a419a0262e666c0b38..aab0ef2586cb78bf247a5d6cc47eada9d292ecca 100644 --- a/pc/bbmalloc.c +++ b/pc/bbmalloc.c @@ -3,77 +3,51 @@ #include "mem.h" #include "dat.h" #include "fns.h" -#include "io.h" -/* - * Allocate memory for use in kernel bitblts. - * The allocated memory must have a flushed instruction - * cache, and the data cache must be flushed by bbdflush(). - * To avoid the need for frequent cache flushes, the memory - * is allocated out of an arena, and the i-cache is only - * flushed when it has to be reused. By returning an - * address in non-cached space, the need for flushing the - * d-cache is avoided. - * - * On the safari, all this is unnecessary, since the - * only icache is a miniscule prefetch buffer. - * - * Currently, the only kernel users of bitblt are devbit, - * print, and the cursor stuff in devbit. The cursor - * can get drawn at clock interrupt time, so it might need - * to bbmalloc while another bitblt is going on. - * - * This code will have to be interlocked if we ever get - * a multiprocessor with a bitmapped display. - */ +static char bbarena[10000]; +static char bbused[10]; -/* a 0->3 bitblt can take 900 words */ -enum { - nbbarena=8192 /* number of words in an arena */ -}; - -static ulong bbarena[nbbarena]; -static ulong *bbcur = bbarena; -static ulong *bblast = 0; - -void * -bbmalloc(int nbytes) +void* +bbmalloc(int n) { - int nw; - int s; - ulong *ans; + char *a; + int s, i; - nw = nbytes/sizeof(long); s = splhi(); - if(bbcur + nw > &bbarena[nbbarena]) - ans = bbarena; - else - ans = bbcur; - bbcur = ans + nw; + a = memchr(bbused, 0, sizeof(bbused)); + if(a) { + i = a - bbused; + a = bbarena + i*n; + if(a+n <= bbarena+sizeof(bbarena)) { + bbused[i] = 1; + splx(s); + return a; + } + } splx(s); -/* - if(ans == bbarena) - icflush(ans, sizeof(bbarena)); -*/ - bblast = ans; - ans = (void *)ans; - return ans; + print("too many bbmallocs\n"); + return bbarena; } void -bbfree(void *p, int n) +bbfree(void *va, int n) { - ulong *up; - int s; + int s, i; s = splhi(); - if(p == bblast) - bbcur = (ulong *)(((char *)bblast) + n); + i = ((char*)va - bbarena) /n; + if(i >= 0 && i < sizeof(bbused) && bbused[i]){ + bbused[i] = 0; + splx(s); + return; + } splx(s); + print("sanity bbfree\n"); } -void * +void* bbdflush(void *p, int n) { return p; } + diff --git a/pc/devuart.c b/pc/devuart.c index eb4c03c4fb18c479631f9fc0d8718a56cc01af54..ff3d5f26a104963e9241c7c5613e89940a868ce2 100644 --- a/pc/devuart.c +++ b/pc/devuart.c @@ -259,7 +259,7 @@ uartintr(Uart *up) break; case 0: /* modem status */ - l = uartrdreg(up, Mstat); + uartrdreg(up, Mstat); break; default: @@ -529,6 +529,9 @@ uartkproc(void *a) int n; ulong frame, overrun; + frame = 0; + overrun = 0; + if(waserror()) print("uartkproc got an error\n"); diff --git a/pc/io.h b/pc/io.h index 79f47af1415da2b59b61c1e9520d642eee1d4620..11d4200bcb4807dbef786e499ea91ec86cdb77c8 100644 --- a/pc/io.h +++ b/pc/io.h @@ -4,7 +4,7 @@ enum { Faultvec= 14, /* page fault */ - Int0vec= 16, /* first 8259 */ + Int0vec= 24, /* first 8259 */ Clockvec= Int0vec+0, /* clock interrupts */ Kbdvec= Int0vec+1, /* keyboard interrupts */ Uart1vec= Int0vec+3, /* modem line */ diff --git a/pc/kbd.c b/pc/kbd.c index cd253bca97616d1fcdc859cbfd571b948fa5c931..5855a632b74b2f1db4229fa8315f8abbb08f4e90 100644 --- a/pc/kbd.c +++ b/pc/kbd.c @@ -277,16 +277,19 @@ mousecmd(int cmd) unsigned int c; int tries; - for(tries=0; tries < 10; tries++){ - if(outready() < 0) - return -1; - outb(Cmd, 0xD4); - if(outready() < 0) - return -1; - outb(Data, cmd); - if(inready() < 0) - return -1; - c = inb(Data); + c = 0; + do{ + for(tries=0; tries < 10; tries++){ + if(outready() < 0) + return -1; + outb(Cmd, 0xD4); + if(outready() < 0) + return -1; + outb(Data, cmd); + if(inready() < 0) + return -1; + c = inb(Data); + } } while(c == 0xFE); if(c != 0xFA) return -1; diff --git a/pc/l.s b/pc/l.s index b1aa2dbb587326f89caa8c1e0c8db3815977eba7..5bc192e8e541bccf577316dab4bebb59f70e4e31 100644 --- a/pc/l.s +++ b/pc/l.s @@ -343,34 +343,6 @@ TEXT intr16(SB),$0 PUSHL $0 PUSHL $16 JMP intrcommon -TEXT intr17(SB),$0 - PUSHL $0 - PUSHL $17 - JMP intrcommon -TEXT intr18(SB),$0 - PUSHL $0 - PUSHL $18 - JMP intrcommon -TEXT intr19(SB),$0 - PUSHL $0 - PUSHL $19 - JMP intrcommon -TEXT intr20(SB),$0 - PUSHL $0 - PUSHL $20 - JMP intrcommon -TEXT intr21(SB),$0 - PUSHL $0 - PUSHL $21 - JMP intrcommon -TEXT intr22(SB),$0 - PUSHL $0 - PUSHL $22 - JMP intrcommon -TEXT intr23(SB),$0 - PUSHL $0 - PUSHL $23 - JMP intrcommon TEXT intr24(SB),$0 PUSHL $0 PUSHL $24 @@ -403,6 +375,38 @@ TEXT intr31(SB),$0 PUSHL $0 PUSHL $31 JMP intrcommon +TEXT intr32(SB),$0 + PUSHL $0 + PUSHL $16 + JMP intrcommon +TEXT intr33(SB),$0 + PUSHL $0 + PUSHL $33 + JMP intrcommon +TEXT intr34(SB),$0 + PUSHL $0 + PUSHL $34 + JMP intrcommon +TEXT intr35(SB),$0 + PUSHL $0 + PUSHL $35 + JMP intrcommon +TEXT intr36(SB),$0 + PUSHL $0 + PUSHL $36 + JMP intrcommon +TEXT intr37(SB),$0 + PUSHL $0 + PUSHL $37 + JMP intrcommon +TEXT intr38(SB),$0 + PUSHL $0 + PUSHL $38 + JMP intrcommon +TEXT intr39(SB),$0 + PUSHL $0 + PUSHL $39 + JMP intrcommon TEXT intr64(SB),$0 PUSHL $0 PUSHL $64 diff --git a/pc/trap.c b/pc/trap.c index 67a5ba150d50b871b14a6a5301154e76f8466792..f8ac71d68ce5d61c1c31d8fb7310215d64cc57a3 100644 --- a/pc/trap.c +++ b/pc/trap.c @@ -14,10 +14,11 @@ void intr0(void), intr1(void), intr2(void), intr3(void); void intr4(void), intr5(void), intr6(void), intr7(void); void intr8(void), intr9(void), intr10(void), intr11(void); void intr12(void), intr13(void), intr14(void), intr15(void); -void intr16(void), intr17(void), intr18(void), intr19(void); -void intr20(void), intr21(void), intr22(void), intr23(void); +void intr16(void); void intr24(void), intr25(void), intr26(void), intr27(void); void intr28(void), intr29(void), intr30(void), intr31(void); +void intr32(void), intr33(void), intr34(void), intr35(void); +void intr36(void), intr37(void), intr38(void), intr39(void); void intr64(void); void intrbad(void); @@ -78,11 +79,11 @@ trapinit(void) /* * set all interrupts to panics */ - for(i = 32; i < 256; i++) + for(i = 0; i < 256; i++) sethvec(i, intrbad, SEGTG, 0); /* - * set the standard traps + * 80386 processor (and coprocessor) traps */ sethvec(0, intr0, SEGTG, 0); sethvec(1, intr1, SEGTG, 0); @@ -100,18 +101,11 @@ trapinit(void) sethvec(13, intr13, SEGTG, 0); sethvec(14, intr14, SEGTG, 0); sethvec(15, intr15, SEGTG, 0); + sethvec(16, intr16, SEGTG, 0); /* - * set the standard devices + * device interrupts */ - sethvec(16, intr16, SEGIG, 0); - sethvec(17, intr17, SEGIG, 0); - sethvec(18, intr18, SEGIG, 0); - sethvec(19, intr19, SEGIG, 0); - sethvec(20, intr20, SEGIG, 0); - sethvec(21, intr21, SEGIG, 0); - sethvec(22, intr22, SEGIG, 0); - sethvec(23, intr23, SEGIG, 0); sethvec(24, intr24, SEGIG, 0); sethvec(25, intr25, SEGIG, 0); sethvec(26, intr26, SEGIG, 0); @@ -120,6 +114,14 @@ trapinit(void) sethvec(29, intr29, SEGIG, 0); sethvec(30, intr30, SEGIG, 0); sethvec(31, intr31, SEGIG, 0); + sethvec(32, intr32, SEGIG, 0); + sethvec(33, intr33, SEGIG, 0); + sethvec(34, intr34, SEGIG, 0); + sethvec(35, intr35, SEGIG, 0); + sethvec(36, intr36, SEGIG, 0); + sethvec(37, intr37, SEGIG, 0); + sethvec(38, intr38, SEGIG, 0); + sethvec(39, intr39, SEGIG, 0); /* * system calls diff --git a/pc/vga.c b/pc/vga.c index 418aa852bb0c78cd2dff50157c2dbc31bbc02c0f..78df35888ddb0d59e776ada61f019b57dddf7266 100644 --- a/pc/vga.c +++ b/pc/vga.c @@ -148,13 +148,10 @@ munch(void) void screeninit(void) { - uchar *display; int i, j, k; int c; ulong *l; - display = (uchar *)SCREENMEM; - arout(Acpe, 0x0f); /* enable all planes */ arout(Amode, 0x01); /* graphics mode - 4 bit pixels */ grout(Gmisc, 0x01); /* graphics mode */ @@ -268,7 +265,7 @@ hwcursmove(int x, int y) } void -mouseclock(void) /* called splhi */ +mouseclock(void) { mouseupdate(1); } diff --git a/port/devmnt.c b/port/devmnt.c index 78f2045ba7a83f80c890cc86865b95c637b43c6b..3e74e67453072c0100579bdd0a2fa7fa28a120be 100644 --- a/port/devmnt.c +++ b/port/devmnt.c @@ -4,108 +4,268 @@ #include "dat.h" #include "fns.h" #include "errno.h" + #include "devtab.h" + #include "fcall.h" -typedef struct Mntrpc Mntrpc; -typedef struct Mnt Mnt; - -struct Mntrpc -{ - Mntrpc *list; /* Free/pending list */ - Fcall request; /* Outgoing file system protocol message */ - Fcall reply; /* Incoming reply */ - Mnt *m; /* Mount device during rpc */ - Rendez r; /* Place to hang out */ - char *rpc; /* I/O Data buffer */ - char done; /* Rpc completed */ - char bfree; /* Buffer may be freed after flush */ - char flushed; /* Flush was sent */ - ushort flushtag; /* Tag to send flush on */ - ushort flushbase; /* Base tag of flush window for this buffer */ - char flush[MAXMSG]; /* Somewhere to build flush */ -}; +#define NTAG 65536 /* 1 <= tag < NTAG */ + +typedef struct Mnt Mnt; +typedef struct Mnthdr Mnthdr; +typedef struct MntQ MntQ; struct Mnt { - Ref; /* Count of attached channels */ - Chan *c; /* Channel to file service */ - Proc *rip; /* Reader in progress */ - Mntrpc *queue; /* Queue of pending requests on this channel */ - int id; /* Multiplexor id for channel check */ - Mnt *list; /* Free list */ - char mux; /* Set if the device aleady does the multiplexing */ + Ref; /* for number of chans, incl. mntpt but not msg */ + ulong mntid; /* serial # */ + Chan *mntpt; /* channel in user's name space */ + MntQ *q; +}; + +struct MntQ +{ + Ref; + QLock; /* for access */ + MntQ *next; /* for allocation */ + Chan *msg; /* for reading and writing messages */ + Proc *reader; /* process reading response */ + Mnthdr *writer; /* queue of headers of written messages */ +}; + +#define BITROUND 256 +#define BUFSIZE (MAXFDATA+MAXMSG) +typedef struct Mntbuf Mntbuf; +struct Mntbuf +{ + Mntbuf *next; + char buf[BUFSIZE+BITROUND]; /* BUG */ }; -struct Mntalloc +struct { Lock; - Mnt *mntfree; - Mnt *mntarena; - Mntrpc *rpcfree; - int id; -}mntalloc; - -#define BITBOTCH 256 -#define MAXRPC (MAXFDATA+MAXMSG+BITBOTCH) -#define limit(n, max) (n > max ? max : n) - -Chan *mattach(Mnt*, char*, char*); -Mntrpc *mntralloc(void); -void mntfree(Mntrpc*); -int rpcattn(Mntrpc*); -void mountrpc(Mnt*, Mntrpc*); -void mountio(Mnt*, Mntrpc*); -Mnt *mntchk(Chan*); -void mountmux(Mnt*, Mntrpc*); -long mntrdwr(int , Chan*, void*,long , ulong); -int mntflush(Mnt*, Mntrpc*); -void mntqrm(Mnt*, Mntrpc*); -void mntdirfix(uchar*, Chan*); -void mntgate(Mnt*); -void mntrpcread(Mnt*, Mntrpc*); - -enum -{ - Tagspace = 1, - Flushspace = 64, - Flushtag = 512, + Mntbuf *free; +}mntbufalloc; + +struct Mnthdr +{ + Mnthdr *next; /* in free list or writers list */ + Mnthdr *prev; /* in writers list only */ + char active; + char flushing; /* a Tflush has been sent */ + short seq; + Fcall thdr; + Fcall rhdr; + Rendez r; + Proc *p; + Mntbuf *mbr; + int readreply; /* true if we are reader or our reply has come */ }; +struct +{ + Lock; + Mnthdr *arena; + Mnthdr *head; + Mnthdr *tail; +}mnthdralloc; + +struct +{ + Lock; + QLock; + MntQ *arena; + MntQ *free; +}mntqalloc; + +struct +{ + Lock; + long id; +}mntid; + +Mnt *mnt; +void mntxmit(Mnt*, Mnthdr*); + +Mntbuf* +mballoc(void) +{ + Mntbuf *mb; + +loop: + lock(&mntbufalloc); + if(mb = mntbufalloc.free){ /* assign = */ + mntbufalloc.free = mb->next; + unlock(&mntbufalloc); + return mb; + } + unlock(&mntbufalloc); + print("no mntbufs\n"); + if(u == 0) + panic("mballoc"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +mbfree(Mntbuf *mb) +{ + lock(&mntbufalloc); + mb->next = mntbufalloc.free; + mntbufalloc.free = mb; + unlock(&mntbufalloc); +} + +Mnthdr* +mhalloc(Mnt *m) +{ + Mnthdr *mh; + int seq; + +loop: + lock(&mnthdralloc); + if(mh = mnthdralloc.head){ /* assign = */ + mnthdralloc.head = mh->next; + if(mnthdralloc.head) + mnthdralloc.head->prev = 0; + else + mnthdralloc.tail = 0; + unlock(&mnthdralloc); + mh->mbr = 0; + seq = ++mh->seq; + if(seq == (1<<7)){ + mh->seq = 1; + seq = 1; + } + mh->thdr.tag = (((mh-mnthdralloc.arena)<<7)|seq) & (NTAG-1); + return mh; + } + unlock(&mnthdralloc); + print("no mnthdrs\n"); + if(u == 0) + panic("mhalloc"); + u->p->state = Wakeme; + alarm(1000, wakeme, u->p); + sched(); + goto loop; +} + +void +mhfree(Mnthdr *mh) +{ + if(mh->flushing) + return; + lock(&mnthdralloc); + mh->active = 0; + mh->thdr.tag = 0; + mh->next = 0; + mh->prev = mnthdralloc.tail; + if(mnthdralloc.tail) + mnthdralloc.tail->next = mh; + else + mnthdralloc.head = mh; + mnthdralloc.tail = mh; + unlock(&mnthdralloc); +} + +MntQ* +mqalloc(Chan *msg) /* mntqalloc is qlocked */ +{ + MntQ *q; + + if(q = mntqalloc.free){ /* assign = */ + mntqalloc.free = q->next; + lock(q); + q->ref = 1; + q->msg = msg; + unlock(q); + incref(msg); + q->writer = 0; + q->reader = 0; + return q; + } + panic("no mntqs\n"); /* there MUST be enough */ +} + +void +mqfree(MntQ *mq) +{ + Chan *msg = 0; + + lock(mq); + if(--mq->ref == 0){ + msg = mq->msg; + mq->msg = 0; + lock(&mntqalloc); + mq->next = mntqalloc.free; + mntqalloc.free = mq; + unlock(&mntqalloc); + } + unlock(mq); + if(msg) /* after locks are down */ + close(msg); +} + +Mnt* +mntdev(Chan *c, int noerr) +{ + Mnt *m; + int i; + + m = &mnt[c->mntindex]; + if(m->mntid==c->dev && m->q!=0) + return m; + if(noerr) + return 0; + print("mntdev shutdown %d %d %d %lux\n", c->dev, c->mntindex, + m->mntid, m->q); + error(Eshutdown); +} + void mntreset(void) { - Mnt *me, *md; - Mntrpc *re, *rd; - ushort tag, ftag; - - mntalloc.mntarena = ialloc(conf.nmntdev*sizeof(Mnt), 0); - mntalloc.mntfree = mntalloc.mntarena; - me = &mntalloc.mntfree[conf.nmntdev]; - for(md = mntalloc.mntfree; md < me; md++) - md->list = md+1; - me[-1].list = 0; - - if(conf.nmntbuf > Flushtag) { - print("devmnt: buffers limited to %d\n", Flushtag); - conf.nmntbuf = Flushtag; - } - - tag = Tagspace; - ftag = Flushtag; - mntalloc.rpcfree = ialloc(conf.nmntbuf*sizeof(Mntrpc), 0); - re = &mntalloc.rpcfree[conf.nmntbuf]; - for(rd = mntalloc.rpcfree; rd < re; rd++) { - rd->list = rd+1; - rd->request.tag = tag++; - rd->flushbase = ftag; - rd->flushtag = ftag; - ftag += Flushspace; - rd->rpc = ialloc(MAXRPC, 0); - } - re[-1].list = 0; - - mntalloc.id = 1; + int i; + Mntbuf *mb; + Mnthdr *mh; + MntQ *mq; + + if(conf.nmnthdr > 512){ + print("conf.nmnthdr is %d set to 512\n", conf.nmnthdr); + conf.nmnthdr = 512; + } + mnt = ialloc(conf.nmntdev*sizeof(Mnt), 0); + + mb = ialloc(conf.nmntbuf*sizeof(Mntbuf), 0); + mntbufalloc.free = mb; + for(i=0; inext = mb+1; + --mb; + mb->next = 0; + + mh = ialloc(conf.nmnthdr*sizeof(Mnthdr), 0); + mnthdralloc.arena = mh; + mnthdralloc.head = mh; + for(i=0; iseq = 0; + mh->next = mh+1; + mh->prev = mh-1; + } + --mh; + mnthdralloc.tail = mh; + mh->next = 0; + mnthdralloc.head->prev = 0; + + mq = ialloc(conf.nmntdev*sizeof(MntQ), 0); + mntqalloc.arena = mq; + mntqalloc.free = mq; + for(i=0; inext = mq+1; + --mq; + mq->next = 0; } void @@ -114,86 +274,79 @@ mntinit(void) } Chan* -mntattach(char *muxattach) +mntattach(char *crud) { - Mnt *m, *e; + int i; + Mnt *m, *mm; + Mnthdr *mh; + MntQ *q; + Chan *c, *cm; struct bogus{ Chan *chan; char *spec; char *auth; }bogus; - bogus = *((struct bogus *)muxattach); - e = &mntalloc.mntarena[conf.nmntdev]; - for(m = mntalloc.mntarena; m < e; m++) { - if(m->c == bogus.chan && m->id) { - lock(m); - if(m->ref > 0 && m->id && m->c == bogus.chan) { - m->ref++; - unlock(m); - return mattach(m, bogus.spec, bogus.auth); - } - unlock(m); - } - } - lock(&mntalloc); - if(mntalloc.mntfree == 0) { - unlock(&mntalloc); - error(Enomntdev); + bogus = *((struct bogus *)crud); + + m = mnt; + for(i=0; iref == 0) + goto Found; + unlock(m); } - m = mntalloc.mntfree; - mntalloc.mntfree = m->list; - m->id = mntalloc.id++; - lock(m); - unlock(&mntalloc); + error(Enomntdev); + + Found: m->ref = 1; - m->queue = 0; - m->rip = 0; - m->c = bogus.chan; - - switch(devchar[m->c->type]) { - case 'H': /* Hotrod */ - case '3': /* BIT3 */ - m->mux = 1; - break; - default: - m->mux = 0; - } - incref(m->c); unlock(m); + lock(&mntid); + m->mntid = ++mntid.id; + unlock(&mntid); + c = devattach('M', bogus.spec); + c->dev = m->mntid; + c->mntindex = m-mnt; + m->mntpt = c; + cm = bogus.chan; + + /* + * Look for queue to same msg channel + */ + q = mntqalloc.arena; + qlock(&mntqalloc); + for(i=0; imsg==cm){ + lock(q); + if(q->ref && q->msg==cm){ + m->q = q; + q->ref++; + unlock(q); + goto out; + } + unlock(q); + } + m->q = mqalloc(cm); - return mattach(m, bogus.spec, bogus.auth); -} - -Chan * -mattach(Mnt *m, char *spec, char *auth) -{ - Chan *c; - Mntrpc *r; - - r = mntralloc(); - - c = devattach('M', spec); - c->dev = m->id; - c->mntindex = m-mntalloc.mntarena; - + out: + qunlock(&mntqalloc); + mh = mhalloc(m); if(waserror()){ - mntfree(r); + mhfree(mh); close(c); nexterror(); } - r->request.type = Tattach; - r->request.fid = c->fid; - memmove(r->request.uname, u->p->pgrp->user, NAMELEN); - strncpy(r->request.aname, spec, NAMELEN); - strncpy(r->request.auth, auth, NAMELEN); - mountrpc(m, r); - - c->qid = r->reply.qid; - c->mchan = m->c; + mh->thdr.type = Tattach; + mh->thdr.fid = c->fid; + memmove(mh->thdr.uname, u->p->pgrp->user, NAMELEN); + strcpy(mh->thdr.aname, bogus.spec); + strcpy(mh->thdr.auth, bogus.auth); + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + c->mchan = m->q->msg; c->mqid = c->qid; + mhfree(mh); poperror(); - mntfree(r); return c; } @@ -201,27 +354,28 @@ Chan* mntclone(Chan *c, Chan *nc) { Mnt *m; - Mntrpc *r; - int alloc = 0; + Mnthdr *mh; + int new; - m = mntchk(c); - r = mntralloc(); - if(nc == 0) { + new = 0; + if(nc == 0){ nc = newchan(); - alloc = 1; + new = 1; + if(waserror()){ + close(nc); + nexterror(); + } } + m = mntdev(c, 0); + mh = mhalloc(m); if(waserror()){ - mntfree(r); - if(alloc) - close(nc); + mhfree(mh); nexterror(); } - - r->request.type = Tclone; - r->request.fid = c->fid; - r->request.newfid = nc->fid; - mountrpc(m, r); - + mh->thdr.type = Tclone; + mh->thdr.fid = c->fid; + mh->thdr.newfid = nc->fid; + mntxmit(m, mh); nc->type = c->type; nc->dev = c->dev; nc->qid = c->qid; @@ -231,12 +385,14 @@ mntclone(Chan *c, Chan *nc) nc->mnt = c->mnt; nc->mountid = c->mountid; nc->aux = c->aux; + nc->mntindex = c->mntindex; nc->mchan = c->mchan; nc->mqid = c->qid; - incref(m); - + mhfree(mh); poperror(); - mntfree(r); + if(new) + poperror(); + incref(m); return nc; } @@ -244,71 +400,73 @@ int mntwalk(Chan *c, char *name) { Mnt *m; - Mntrpc *r; - - m = mntchk(c); - r = mntralloc(); - if(waserror()) { - mntfree(r); - return 0; + Mnthdr *mh; + int found; + + found = 1; + m = mntdev(c, 0); + mh = mhalloc(m); + mh->thdr.type = Twalk; + mh->thdr.fid = c->fid; + strcpy(mh->thdr.name, name); + if(waserror()){ /* BUG: can check type of error? */ + found = 0; + goto Out; } - r->request.type = Twalk; - r->request.fid = c->fid; - strncpy(r->request.name, name, NAMELEN); - mountrpc(m, r); - - c->qid = r->reply.qid; - + mntxmit(m, mh); + c->qid = mh->rhdr.qid; poperror(); - mntfree(r); - return 1; + Out: + mhfree(mh); + return found; } void mntstat(Chan *c, char *dp) { Mnt *m; - Mntrpc *r; + Mnthdr *mh; - m = mntchk(c); - r = mntralloc(); - if(waserror()) { - mntfree(r); + m = mntdev(c, 0); + mh = mhalloc(m); + if(waserror()){ + mhfree(mh); nexterror(); } - r->request.type = Tstat; - r->request.fid = c->fid; - mountrpc(m, r); - - memmove(dp, r->reply.stat, DIRLEN); - mntdirfix((uchar*)dp, c); + mh->thdr.type = Tstat; + mh->thdr.fid = c->fid; + mntxmit(m, mh); + memmove(dp, mh->rhdr.stat, DIRLEN); + dp[DIRLEN-4] = devchar[c->type]; + dp[DIRLEN-3] = 0; + dp[DIRLEN-2] = c->dev; + dp[DIRLEN-1] = c->dev>>8; + mhfree(mh); poperror(); - mntfree(r); } Chan* mntopen(Chan *c, int omode) { Mnt *m; - Mntrpc *r; + Mnthdr *mh; - m = mntchk(c); - r = mntralloc(); - if(waserror()) { - mntfree(r); + m = mntdev(c, 0); + mh = mhalloc(m); + if(waserror()){ + mhfree(mh); nexterror(); } - r->request.type = Topen; - r->request.fid = c->fid; - r->request.mode = omode; - mountrpc(m, r); - - c->qid = r->reply.qid; + mh->thdr.type = Topen; + mh->thdr.fid = c->fid; + mh->thdr.mode = omode; + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + mhfree(mh); + poperror(); c->offset = 0; c->mode = openmode(omode); c->flag |= COPEN; - poperror(); - mntfree(r); return c; } @@ -316,58 +474,60 @@ void mntcreate(Chan *c, char *name, int omode, ulong perm) { Mnt *m; - Mntrpc *r; + Mnthdr *mh; - m = mntchk(c); - r = mntralloc(); - if(waserror()) { - mntfree(r); + m = mntdev(c, 0); + mh = mhalloc(m); + if(waserror()){ + mhfree(mh); nexterror(); } - r->request.type = Tcreate; - r->request.fid = c->fid; - r->request.mode = omode; - r->request.perm = perm; - strncpy(r->request.name, name, NAMELEN); - mountrpc(m, r); - - c->qid = r->reply.qid; + mh->thdr.type = Tcreate; + mh->thdr.fid = c->fid; + strcpy(mh->thdr.name, name); + mh->thdr.mode = omode; + mh->thdr.perm = perm; + mntxmit(m, mh); + c->qid = mh->rhdr.qid; + mhfree(mh); + poperror(); c->flag |= COPEN; c->mode = openmode(omode); - poperror(); - mntfree(r); + c->qid = mh->rhdr.qid; } void mntclunk(Chan *c, int t) { Mnt *m; - Mntrpc *r, *n, *q; - - m = mntchk(c); - r = mntralloc(); - if(waserror()){ - mntfree(r); - if(decref(m) == 0) { - for(q = m->queue; q; q = r) { - r = q->list; - q->flushed = 0; - mntfree(q); - } - m->id = 0; - close(m->c); - lock(&mntalloc); - m->list = mntalloc.mntfree; - mntalloc.mntfree = m; - unlock(&mntalloc); - } - return; - } - - r->request.type = t; - r->request.fid = c->fid; - mountrpc(m, r); - nexterror(); + Mnthdr *mh; + MntQ *q; + int waserr; + + m = mntdev(c, 0); + mh = mhalloc(m); + mh->thdr.type = t; + mh->thdr.fid = c->fid; + waserr = 0; + if(waserror()) /* gotta clean up as if there wasn't */ + waserr = 1; + else + mntxmit(m, mh); + mhfree(mh); + if(c == m->mntpt) + m->mntpt = 0; + lock(m); + if(--m->ref == 0){ /* BUG: need to hang up all pending i/o */ + q = m->q; + m->q = 0; + m->mntid = 0; + unlock(m); /* mqfree can take time */ + mqfree(q); + }else + unlock(m); + if(waserr) + nexterror(); + poperror(); } void @@ -376,357 +536,433 @@ mntclose(Chan *c) mntclunk(c, Tclunk); } -void -mntremove(Chan *c) -{ - mntclunk(c, Tremove); -} - -void -mntwstat(Chan *c, char *dp) +long +mntreadwrite(Chan *c, void *vbuf, long n, int type, ulong offset) { Mnt *m; - Mntrpc *r; - - m = mntchk(c); - r = mntralloc(); - if(waserror()) { - mntfree(r); + Mnthdr *mh; + long nt, nr, count; + char *buf; + + buf = vbuf; + count = 0; + m = mntdev(c, 0); + mh = mhalloc(m); + if(waserror()){ + mhfree(mh); nexterror(); } - r->request.type = Twstat; - r->request.fid = c->fid; - memmove(r->request.stat, dp, DIRLEN); - mountrpc(m, r); + mh->thdr.type = type; + mh->thdr.fid = c->fid; + Loop: + nt = n; + if(nt > MAXFDATA) + nt = MAXFDATA; + mh->thdr.offset = offset; + mh->thdr.count = nt; + mh->thdr.data = buf; + mntxmit(m, mh); + nr = mh->rhdr.count; + offset += nr; + count += nr; + buf += nr; + n -= nr; + if(n && nr==nt) + goto Loop; + mhfree(mh); poperror(); - mntfree(r); + return count; } long mntread(Chan *c, void *buf, long n, ulong offset) { - uchar *p, *e; - - n = mntrdwr(Tread, c, buf, n, offset); - if(c->qid.path & CHDIR) - for(p = (uchar*)buf, e = &p[n]; p < e; p += DIRLEN) - mntdirfix(p, c); - + long i; + uchar *b; + + n = mntreadwrite(c, buf, n, Tread, offset); + if(c->qid.path & CHDIR){ + b = (uchar*)buf; + for(i=n-DIRLEN; i>=0; i-=DIRLEN){ + b[DIRLEN-4] = devchar[c->type]; + b[DIRLEN-3] = 0; + b[DIRLEN-2] = c->dev; + b[DIRLEN-1] = c->dev>>8; + b += DIRLEN; + } + } return n; } long mntwrite(Chan *c, void *buf, long n, ulong offset) { - return mntrdwr(Twrite, c, buf, n, offset); + return mntreadwrite(c, buf, n, Twrite, offset); } -long -mntrdwr(int type, Chan *c, void *buf, long n, ulong offset) +void +mntremove(Chan *c) +{ + mntclunk(c, Tremove); +} + +void +mntwstat(Chan *c, char *dp) { Mnt *m; - Mntrpc *r; - ulong cnt, nr; - char *uba; - - r = mntralloc(); - m = mntchk(c); - if(waserror()) { - mntfree(r); + Mnthdr *mh; + + m = mntdev(c, 0); + mh = mhalloc(m); + if(waserror()){ + mhfree(mh); nexterror(); } - r->request.type = type; - r->request.fid = c->fid; - r->request.offset = offset; - uba = buf; - for(cnt = 0; n; n -= nr) { - r->request.data = uba; - r->request.count = limit(n, MAXFDATA); - mountrpc(m, r); - nr = r->reply.count; - if(type == Tread) - memmove(uba, r->reply.data, nr); - r->request.offset += nr; - uba += nr; - cnt += nr; - if(nr != r->request.count) - break; - } + mh->thdr.type = Twstat; + mh->thdr.fid = c->fid; + memmove(mh->thdr.stat, dp, DIRLEN); + mntxmit(m, mh); + mhfree(mh); poperror(); - mntfree(r); - return cnt; } void -mountrpc(Mnt *m, Mntrpc *r) -{ - mountio(m, r); - if(r->reply.type == Rerror) - errors(r->reply.ename); - if(r->reply.type != r->request.type+1) { - print("devmnt: mismatched reply T%d R%d tags req %d fls %d rep %d\n", - r->request.type, r->reply.type, r->request.tag, r->flushtag, r->reply.tag); errors("protocol error"); +mntwunlink(MntQ *q, Mnthdr *w) /* queue is locked and w is a writer */ +{ + if(w->next) + w->next->prev = w->prev; + if(w->prev) + w->prev->next = w->next; + else{ + q->writer = w->next; + if(q->writer) + q->writer->prev = 0; } } +/* + * m->q is unlocked. Send Tflush message to flush omh->tag. + * Cut off all errors. Caller will free omh + */ void -mountio(Mnt *m, Mntrpc *r) +mntflush(Mnt *m, Mnthdr *omh) /* queue is unlocked */ { - int n; + Mnthdr *mh; - lock(m); - r->m = m; - r->list = m->queue; - m->queue = r; - unlock(m); - - /* Transmit a file system rpc */ - n = convS2M(&r->request, r->rpc); - if(waserror()) { - mntqrm(m, r); - nexterror(); - } - if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n) - error(Eshortmsg); - poperror(); - - if(m->mux) { - mntrpcread(m, r); + if(omh->thdr.type == Tflush){ + omh->flushing = 0; return; } - /* Gate readers onto the mount point one at a time */ - for(;;) { - lock(m); - if(m->rip == 0) - break; - unlock(m); - if(waserror()) { - if(mntflush(m, r) == 0) - nexterror(); - continue; - } - sleep(&r->r, rpcattn, r); - poperror(); - if(r->done) - return; - } - m->rip = u->p; - unlock(m); - - while(r->done == 0) { - mntrpcread(m, r); - mountmux(m, r); + mh = mhalloc(m); + if(waserror()){ + omh->flushing = 0; + mhfree(mh); + return; /* no more errors please */ } - mntgate(m); + mh->thdr.type = Tflush; + mh->thdr.oldtag = omh->thdr.tag; + mntxmit(m, mh); + omh->flushing = 0; + mhfree(mh); + poperror(); } void -mntrpcread(Mnt *m, Mntrpc *r) -{ - int n; - - for(;;) { - if(waserror()) { - if(mntflush(m, r) == 0) { - if(m->mux == 0) - mntgate(m); - nexterror(); - } - continue; +mnterrdequeue(Mnt *m, Mnthdr *mh) /* queue is unlocked */ +{ + Mnthdr *w; + MntQ *q; + + mh->flushing = 1; + q = m->q; + qlock(q); + mh->readreply = 0; + /* take self from queue if necessary */ + if(q->reader == u->p){ /* advance a writer to reader */ + w = q->writer; + if(w){ + mntwunlink(q, w); + q->reader = w->p; + wakeup(&w->r); + }else{ + q->reader = 0; + q->writer = 0; } - n = (*devtab[m->c->type].read)(m->c, r->rpc, MAXRPC, 0); - poperror(); - if(n == 0) - continue; - if(convM2S(r->rpc, &r->reply, n) != 0) - break; - } + }else + mntwunlink(q, mh); + qunlock(q); + mntflush(m, mh); } -void -mntgate(Mnt *m) +int +mntreadreply(void *a) { - Mntrpc *q; - - lock(m); - m->rip = 0; - for(q = m->queue; q; q = q->list) - if(q->done == 0) { - lock(&q->r); - if(q->r.p) { - unlock(&q->r); - unlock(m); - wakeup(&q->r); - return; - } - unlock(&q->r); - } - unlock(m); + return ((Mnthdr *)a)->readreply; } void -mountmux(Mnt *m, Mntrpc *r) -{ - Mntrpc **l, *q; - int done; - char *dp; - - lock(m); - l = &m->queue; - for(q = *l; q; q = q->list) { - if(q->request.tag == r->reply.tag) { - if(q->flushed == 0) - *l = q->list; - q->done = 1; - unlock(m); - goto dispatch; +mntxmit(Mnt *m, Mnthdr *mh) +{ + ulong n; + Mntbuf *mbw; + Mnthdr *w, *ow, *h; + MntQ *q; + int qlocked, tag, written; + + if(&qlocked); /* force qlocked not to be registerized */ + mh->mbr = 0; + mbw = mballoc(); + if(waserror()){ /* 1 */ + if(mh->mbr){ + mbfree(mh->mbr); + mh->mbr = 0; } - if(q->flushtag == r->reply.tag) { - *l = q->list; - q->flushed = 0; - done = q->done; - q->done = 1; - unlock(m); - if(done == 0) { - r->reply.type = Rerror; - strcpy(r->reply.ename, errstrtab[Eintr]); - goto dispatch; - } - if(q->bfree) - mntfree(q); - return; - } - l = &q->list; + mbfree(mbw); + nexterror(); } - unlock(m); - return; - -dispatch: - if(q != r) { /* Completed someone else */ - dp = q->rpc; - q->rpc = r->rpc; - r->rpc = dp; - memmove(&q->reply, &r->reply, sizeof(Fcall)); - wakeup(&q->r); + n = convS2M(&mh->thdr, mbw->buf); + q = m->q; + if(q == 0) + error(Eshutdown); +#ifdef BIT3 + /* + * Bit3 and Hotrod do their own multiplexing. (Well, the file server does.) + * The code is different enough that it's broken out separately here. + */ + if(devchar[q->msg->type]!='3' && devchar[q->msg->type]!='H') + goto Normal; + + incref(q); + if(waserror()){ /* 2 */ + mqfree(q); + nexterror(); } - -} - -int -mntflush(Mnt *m, Mntrpc *r) -{ - Fcall flush; - int n; - - r->flushtag++; - if((r->flushtag-r->flushbase) == Flushspace) - r->flushtag -= Flushspace; - - flush.type = Tflush; - flush.tag = r->flushtag; - flush.oldtag = r->request.tag; - n = convS2M(&flush, r->flush); - - if(waserror()) { - if(strcmp(u->error, errstrtab[Eintr]) == 0) - return 1; - mntqrm(m, r); - return 0; + if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n, 0) != n){ + print("short write in mntxmit\n"); + error(Eshortmsg); } - (*devtab[m->c->type].write)(m->c, r->flush, n, 0); - poperror(); - lock(m); - if(!r->done) - r->flushed = 1; - unlock(m); - return 1; -} - -Mntrpc * -mntralloc(void) -{ - Mntrpc *new; - for(;;) { - lock(&mntalloc); - if(new = mntalloc.rpcfree) { - mntalloc.rpcfree = new->list; - unlock(&mntalloc); - new->done = 0; - new->bfree = 0; - return new; - } - unlock(&mntalloc); - resrcwait("no mount buffers"); + /* + * Read response + */ + if(waserror()){ /* 3 */ + mntflush(m, mh); + nexterror(); + } + mh->mbr = mballoc(); + n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE, 0); + poperror(); /* 3 */ + mqfree(q); + poperror(); /* 2 */ + + if(convM2S(mh->mbr->buf, &mh->rhdr, n) == 0){ + print("format error in mntxmit\n"); + error(Ebadmsg); } -} - -void -mntfree(Mntrpc *r) -{ - Mntrpc *q; - Mnt *m, *e; - int i; - - r->bfree = 1; - if(r->flushed) - return; - lock(&mntalloc); - r->list = mntalloc.rpcfree; - mntalloc.rpcfree = r; - unlock(&mntalloc); -} + /* + * Various checks + */ + if(mh->rhdr.tag != mh->thdr.tag){ + print("tag mismatch %d %d\n", mh->rhdr.tag, mh->thdr.tag); + error(Ebadmsg); + } + if(mh->rhdr.type == Rerror){ + if(m->mntpt) + errors(mh->rhdr.ename); + error(Eshutdown); + } + if(mh->rhdr.type != mh->thdr.type+1){ + print("type mismatch %d %d\n", mh->rhdr.type, mh->thdr.type+1); + error(Ebadmsg); + } + if(mh->rhdr.fid != mh->thdr.fid){ + print("fid mismatch %d %d type %d\n", mh->rhdr.fid, mh->thdr.fid, mh->rhdr.type); + error(Ebadmsg); + } -void -mntqrm(Mnt *m, Mntrpc *r) -{ - Mntrpc **l, *f; + /* + * Copy out on read + */ + if(mh->thdr.type == Tread) + memmove(mh->thdr.data, mh->rhdr.data, mh->rhdr.count); + mbfree(mh->mbr); + mh->mbr = 0; + mbfree(mbw); + poperror(); /* 1 */ + return; - lock(m); - r->done = 1; - r->flushed = 0; - - l = &m->queue; - for(f = *l; f; f = f->list) { - if(f == r) { - *l = r->list; - break; + Normal: +#endif + incref(q); + qlock(q); + qlocked = 1; + if(waserror()){ /* 2 */ + if(qlocked) + qunlock(q); + mqfree(q); + nexterror(); + } + mh->readreply = 0; + mh->active = 1; + if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n, 0) != n){ + print("short write in mntxmit\n"); + error(Eshortmsg); + } + if(q->reader == 0){ /* i will read */ + q->reader = u->p; + Read: + USED(qlocked); + qunlock(q); + qlocked = 0; + if(waserror()){ /* 3 */ + mnterrdequeue(m, mh); + nexterror(); + } + mh->mbr = mballoc(); + do{ + n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE, 0); + }while(n == 0); + poperror(); /* 3 */ + if(convM2S(mh->mbr->buf, &mh->rhdr, n) == 0){ + /* BUG? IS THIS RIGHT? IGNORE AND RETRY */ + print(" MR "); + qlock(q); + qlocked = 1; + goto FreeRead; + } + /* + * Response might not be mine + */ + USED(qlocked); + qlock(q); + qlocked = 1; + tag = mh->rhdr.tag; + if(tag == mh->thdr.tag){ /* it's mine */ + if(mh->rhdr.type != Rerror) + if(mh->rhdr.type != mh->thdr.type+1){ + print("mail rob: '%s xxT(%d)%c %d %d'\n", u->p->text, + tag, devchar[m->q->msg->type], + mh->rhdr.type, mh->thdr.type+1); + goto FreeRead; + } + q->reader = 0; + if(w = q->writer){ /* advance a writer to reader */ + mntwunlink(q, w); + q->reader = w->p; + w->readreply = 1; + wakeup(&w->r); + } + mh->active = 0; + USED(qlocked); + qunlock(q); + qlocked = 0; + goto Respond; + } + /* + * Hand response to correct recipient + */ + if(tag==0 || tag>=NTAG){ + print("unknown tag %d\n", tag); + FreeRead: + mbfree(mh->mbr); + mh->mbr = 0; + goto Read; + } + /* + * Find writer in queue + */ + for(w=q->writer; w; w=w->next) + if(w->thdr.tag == tag) + goto Inqueue; + goto FreeRead; + Inqueue: + if(w->flushing || !w->active) /* nothing to do; mntflush will clean up */ + goto FreeRead; + if(mh->rhdr.type != Rerror) + if(mh->rhdr.type != w->thdr.type+1){ + print("mail rob: '%s xxw(%d)%c %d %d'\n", + u->p->text, tag, devchar[m->q->msg->type], + mh->rhdr.type, w->thdr.type+1); + goto FreeRead; } - l = &f->list; + w->mbr = mh->mbr; + mh->mbr = 0; + memmove(&w->rhdr, &mh->rhdr, sizeof mh->rhdr); + mntwunlink(q, w); + w->readreply = 1; + wakeup(&w->r); + goto Read; + }else{ + mh->p = u->p; + /* put self in queue */ + mh->next = q->writer; + mh->prev = 0; + if(q->writer) + q->writer->prev = mh; + q->writer = mh; + qunlock(q); + qlocked = 0; + if(waserror()){ /* interrupted sleep */ + mnterrdequeue(m, mh); + nexterror(); + } + sleep(&mh->r, mntreadreply, mh); + poperror(); + USED(qlocked); + qlock(q); + qlocked = 1; + mh->readreply = 0; + if(q->reader == u->p) /* i got promoted */ + goto Read; + mh->active = 0; + USED(qlocked); + qunlock(q); + qlocked = 0; + goto Respond; } - unlock(m); -} - -Mnt * -mntchk(Chan *c) -{ - Mnt *m; - m = &mntalloc.mntarena[c->mntindex]; - if(m->id != c->dev) + Respond: + mqfree(q); + poperror(); /* 2 */ + if(mh->rhdr.type == Rerror){ + if(m->mntpt) + errors(mh->rhdr.ename); error(Eshutdown); - return m; -} - -void -mntdirfix(uchar *dirbuf, Chan *c) -{ - dirbuf[DIRLEN-4] = devchar[c->type]; - dirbuf[DIRLEN-3] = 0; - dirbuf[DIRLEN-2] = c->dev; - dirbuf[DIRLEN-1] = c->dev>>8; -} - -int -rpcattn(Mntrpc *r) -{ - return r->done || r->m->rip == 0; + } + /* + * Copy out on read + */ + if(mh->thdr.type == Tread){ + if(mh->rhdr.count > mh->thdr.count) + error(Ebadcnt); + memmove(mh->thdr.data, mh->rhdr.data, mh->rhdr.count); + } + mbfree(mh->mbr); + mh->mbr = 0; + mbfree(mbw); + USED(qlocked); + poperror(); /* 1 */ } void mntdump(void) { -} + int i; + MntQ *q; + Mnthdr *h; + Proc *p; + for(i=0; imsg) + continue; + p = q->reader; + print("q rdr %d wrtr ", p? p->pid : 0); + for(h=q->writer; h; h=h->next) + print("(%lux %lux %d %d)", h, &h->r, h->thdr.tag, + (p=h->p)? p->pid : 0); + print("\n"); + } +} diff --git a/port/devnonet.c b/port/devnonet.c index bd8da4c3ce43f39b8bd082732080bea3bbffc633..0f12ebbed26d61e86c1d0525420fd6c5d56f4b61 100644 --- a/port/devnonet.c +++ b/port/devnonet.c @@ -948,7 +948,8 @@ norack(Noconv *cp, int mid) cp->rexmit = 0; cp->lastacked = mid; mp->acked = 1; - freeb(mp->first); + if(mp->first) + freeb(mp->first); mp->first = 0; /* diff --git a/port/stream.c b/port/stream.c index d6ca3cd68f47ce4438ecc44c2ee880abdf81e85e..b9a2833e24b3924d22cfb3daf198d19278d787b1 100644 --- a/port/stream.c +++ b/port/stream.c @@ -1095,6 +1095,7 @@ streamread(Chan *c, void *vbuf, long n) left = n; qlock(&s->rdlock); tofree = 0; + q = 0; if(waserror()){ /* * put any partially read message back into the diff --git a/port/sysfile.c b/port/sysfile.c index 8ee95baf8bb9ed394380a4c34976fbb6501dae70..5dba76531ebdda3e1c792ec9275f0fe9909fca61 100644 --- a/port/sysfile.c +++ b/port/sysfile.c @@ -34,7 +34,7 @@ fdtochan(int fd, int mode) { Chan *c; - USED(c); + c = 0; if(fd<0 || NFD<=fd || (c = u->p->fgrp->fd[fd])==0) error(Ebadfd); if(mode<0 || c->mode==ORDWR) @@ -183,9 +183,7 @@ fdclose(int fd, int flag) long sysclose(ulong *arg) { - Chan *c; - - c = fdtochan(arg[0], -1); + fdtochan(arg[0], -1); fdclose(arg[0], 0); return 0;