From 5ec26afdbaa0cc7d7464cdae45ddbb39394e4723 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sun, 11 Aug 1991 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1991-08-11 --- pc/devfloppy.c | 12 +- pc/devhard.c | 399 +++++++++++++++++++++++++++++++++---------------- pc/io.h | 2 +- port/devmnt.c | 26 +++- port/stream.c | 34 +++-- 5 files changed, 321 insertions(+), 152 deletions(-) diff --git a/pc/devfloppy.c b/pc/devfloppy.c index aace35e043443eb7293aa03d767c04ff355fb4c4..7f30b7e21a06b85f933206c8b166b5ee280cdf2a 100644 --- a/pc/devfloppy.c +++ b/pc/devfloppy.c @@ -172,7 +172,7 @@ Dirtab floppydir[]={ "fd3data", {Qdata + 3}, 0, 0600, "fd3struct", {Qstruct + 3}, 8, 0600, }; -#define NFDIR (sizeof(floppydir)/sizeof(Dirtab)) +#define NFDIR 2 /* directory entries/drive */ #define k64(x) (((ulong)(x))>>16) void @@ -201,7 +201,7 @@ floppyreset(void) for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ dp->dev = dp - floppy.d; dp->t = &floppytype[0]; /* default type */ - floppydir[2*dp->dev].length = dp->t->cap; + floppydir[NFDIR*dp->dev].length = dp->t->cap; dp->motoron = 1; dp->cyl = -1; /* because we don't know */ motoroff(dp); @@ -244,19 +244,19 @@ floppyclone(Chan *c, Chan *nc) int floppywalk(Chan *c, char *name) { - return devwalk(c, name, floppydir, NFDIR, devgen); + return devwalk(c, name, floppydir, conf.nfloppy*NFDIR, devgen); } void floppystat(Chan *c, char *dp) { - devstat(c, dp, floppydir, NFDIR, devgen); + devstat(c, dp, floppydir, conf.nfloppy*NFDIR, devgen); } Chan* floppyopen(Chan *c, int omode) { - return devopen(c, omode, floppydir, NFDIR, devgen); + return devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen); } void @@ -304,7 +304,7 @@ floppyread(Chan *c, void *a, long n) uchar *aa = a; if(c->qid.path == CHDIR) - return devdirread(c, a, n, floppydir, NFDIR, devgen); + return devdirread(c, a, n, floppydir, conf.nfloppy*NFDIR, devgen); rv = 0; dp = &floppy.d[c->qid.path & ~Qmask]; diff --git a/pc/devhard.c b/pc/devhard.c index 7fa303ff41fd7a447ba1f74bf2cb38eb826629c6..8e17f4949031999bcfa4522d31a7e124666c6677 100644 --- a/pc/devhard.c +++ b/pc/devhard.c @@ -14,31 +14,35 @@ enum { /* ports */ Pbase= 0x1F0, - Pdata= Pbase+0, /* data port (16 bits) */ - Perror= Pbase+1, /* error port */ - Pcount= Pbase+2, /* sector count port */ - Psector= Pbase+3, /* sector number port */ - Pcyllsb= Pbase+4, /* least significant byte cylinder # */ - Pcylmsb= Pbase+5, /* most significant byte cylinder # */ - Pdh= Pbase+6, /* drive/head port */ - Pstatus= Pbase+7, /* status port */ + Pdata= 0, /* data port (16 bits) */ + Perror= 1, /* error port (read) */ + Pbmode= 1, /* buffer mode port (write) */ + Pcount= 2, /* sector count port */ + Psector= 3, /* sector number port */ + Pcyllsb= 4, /* least significant byte cylinder # */ + Pcylmsb= 5, /* most significant byte cylinder # */ + Pdh= 6, /* drive/head port */ + Pstatus= 7, /* status port (read) */ Sbusy= (1<<7), Sready= (1<<6), Sdrq= (1<<5), Serr= (1<<0), - Pcmd= Pbase+7, /* cmd port */ + Pcmd= 7, /* cmd port (write) */ /* commands */ Crecal= 0x10, Cread= 0x20, Cwrite= 0x30, Cident= 0xEC, + Csetbuf= 0xEF, /* file types */ Qdir= 0, - Qdata= (1<<1), - Qstruct= (2<<1), - Qmask= (3<<1), + Qdata= (1<<4), + Qstruct= (2<<4), + Qmask= (3<<4), + + Maxxfer= 4*1024, /* maximum transfer size/cmd */ }; /* @@ -84,7 +88,8 @@ struct Ident */ struct Drive { - int dev; + Controller *cp; + int drive; int confused; /* needs to be recalibrated (or worse) */ int online; @@ -94,10 +99,7 @@ struct Drive int heads; /* heads/cyl */ long cyl; /* cylinders/drive */ - int tcyl; /* target cylinder */ - int thead; /* target head */ - int tsec; /* target sector */ - long len; /* size of xfer */ + Ident id; /* disk properties */ }; /* @@ -107,67 +109,109 @@ struct Controller { QLock; /* exclusive access to the drive */ - int intr; /* true if interrupt occured */ - int status; /* status of last interupt */ - Rendez r; /* wait here for command termination */ int confused; /* needs to be recalibrated (or worse) */ + int pbase; /* base port */ - Drive *d; - Ident id; + /* + * current operation + */ + int cmd; /* current command */ + Rendez r; /* wait here for command termination */ + char *buf; /* xfer buffer */ + int tcyl; /* target cylinder */ + int thead; /* target head */ + int tsec; /* target sector */ + int tbyte; /* target byte */ + int len; /* length of transfer (bytes) */ + int secs; /* sectors to be xferred */ + int sofar; /* bytes transferred so far */ + int status; + int error; + Drive *dp; /* drive being accessed */ }; -Controller hard; - -Dirtab harddir[]={ - "hddata", {Qdata}, 0, 0600, - "hdstruct", {Qstruct}, 8, 0600, -}; -#define NHDIR (sizeof(harddir)/sizeof(Dirtab)) +Controller *hardc; +Drive *hard; +Dirtab *harddir; +#define NHDIR 2 /* directory entries/drive */ static void hardintr(Ureg*); static long hardxfer(Drive*, int, void*, long, long); static long hardident(Drive*); -static void hardpos(Drive*, long); +static void hardsetbuf(Drive*, int); +/* + * we assume drives 0 and 1 are on the first controller, 2 and 3 on the + * second, etc. + */ void hardreset(void) { Drive *dp; - - hard.d = ialloc(conf.nhard * sizeof(Drive), 0); - for(dp = hard.d; dp < &hard.d[conf.nhard]; dp++){ - dp->dev = dp - hard.d; + Controller *cp; + int drive; + Dirtab *dir; + + hard = ialloc(conf.nhard * sizeof(Drive), 0); + hardc = ialloc(((conf.nhard+1)/2 + 1) * sizeof(Controller), 0); + dir = harddir = ialloc(NHDIR * conf.nhard * sizeof(Dirtab), 0); + + for(drive = 0; drive < conf.nhard; drive++){ + dp = &hard[drive]; + cp = &hardc[drive/2]; + dp->drive = drive&1; dp->online = 0; + dp->cp = cp; + if((drive&1) == 0){ + cp->buf = ialloc(Maxxfer, 0); + cp->cmd = 0; + cp->pbase = Pbase + (cp-hardc)*8; /* BUG!! guessing */ + setvec(Hardvec + (cp-hardc)*8, hardintr); /* BUG!! guessing */ + } + sprint(harddir[drive*2].name, "hd%ddata", drive); + dir->length = 0; + dir->qid.path = Qdata + drive; + dir->perm = 0600; + dir++; + sprint(dir->name, "hd%dstruct", drive); + dir->length = 8; + dir->qid.path = Qstruct + drive; + dir->perm = 0600; + dir++; } - - setvec(Hardvec, hardintr); } void hardinit(void) { - qunlock(&hard); } +/* + * Get the characteristics of each drive. Mark unresponsive ones + * off line. + */ Chan* hardattach(char *spec) { Drive *dp; - qlock(&hard); - for(dp = hard.d; dp < &hard.d[conf.nhard]; dp++){ + for(dp = hard; dp < &hard[conf.nhard]; dp++){ if(!waserror()){ + hardsetbuf(dp, 1); hardident(dp); - dp->cyl = hard.id.lcyls; - dp->heads = hard.id.lheads; - dp->sectors = hard.id.ls2t; + dp->cyl = dp->id.lcyls; + dp->heads = dp->id.lheads; + dp->sectors = dp->id.ls2t; dp->bytes = 512; dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; + harddir[NHDIR*dp->drive].length = dp->cap; +print("drive %d online\n", dp - hard); dp->online = 1; poperror(); - } + } else + dp->online = 0; } - qunlock(&hard); + return devattach('h', spec); } @@ -180,19 +224,19 @@ hardclone(Chan *c, Chan *nc) int hardwalk(Chan *c, char *name) { - return devwalk(c, name, harddir, NHDIR, devgen); + return devwalk(c, name, harddir, conf.nhard*NHDIR, devgen); } void hardstat(Chan *c, char *dp) { - devstat(c, dp, harddir, NHDIR, devgen); + devstat(c, dp, harddir, conf.nhard*NHDIR, devgen); } Chan* hardopen(Chan *c, int omode) { - return devopen(c, omode, harddir, NHDIR, devgen); + return devopen(c, omode, harddir, conf.nhard*NHDIR, devgen); } void @@ -235,10 +279,10 @@ hardread(Chan *c, void *a, long n) uchar *aa = a; if(c->qid.path == CHDIR) - return devdirread(c, a, n, harddir, NHDIR, devgen); + return devdirread(c, a, n, harddir, conf.nhard*NHDIR, devgen); rv = 0; - dp = &hard.d[c->qid.path & ~Qmask]; + dp = &hard[c->qid.path & ~Qmask]; switch ((int)(c->qid.path & Qmask)) { case Qdata: for(rv = 0; rv < n; rv += i){ @@ -270,7 +314,7 @@ hardwrite(Chan *c, void *a, long n) uchar *aa = a; rv = 0; - dp = &hard.d[c->qid.path & ~Qmask]; + dp = &hard[c->qid.path & ~Qmask]; switch ((int)(c->qid.path & Qmask)) { case Qdata: for(rv = 0; rv < n; rv += i){ @@ -292,113 +336,212 @@ hardwrite(Chan *c, void *a, long n) * did an interrupt happen? */ static int -interrupted(void *a) +cmddone(void *a) { - return hard.intr; + Controller *cp; + + return cp->cmd == 0; } /* - * get parameters from the drive + * start a disk transfer. hardintr will performa all the iterative + * parts. */ -static long -hardident(Drive *dp) -{ - hard.intr = 0; - outb(Pdh, dp->dev<<4); - outb(Pcmd, Cident); - sleep(&hard.r, interrupted, 0); - inss(Pdata, &hard.id, 512/2); -} - static long hardxfer(Drive *dp, int cmd, void *va, long off, long len) { - int secs; - int i; - uchar *aa = va; + Controller *cp; + int err; + int lsec; + int cyl; - if(off % dp->bytes) - errors("bad offset"); + if(dp->online == 0) + errors("disk offline"); if(len % dp->bytes) - errors("bad length"); + errors("bad length"); /* BUG - this shouldn't be a problem */ + if(off % dp->bytes) + errors("bad offset"); /* BUG - this shouldn't be a problem */ + cp = dp->cp; + qlock(cp); if(waserror()){ - qunlock(&hard); + qunlock(cp); nexterror(); } - qlock(&hard); - dp->len = len; - hardpos(dp, off); - secs = dp->len/dp->bytes; - - outb(Pcount, secs); - outb(Psector, dp->tsec); - outb(Pdh, (1<<5) | (dp->dev<<4) | dp->thead); - outb(Pcyllsb, dp->tcyl); - outb(Pcylmsb, dp->tcyl>>8); - outb(Pcmd, cmd); - - if(cmd == Cwrite) - outss(Pdata, aa, dp->bytes/2); - for(i = 0; i < secs; i++){ - hard.intr = 0; - sleep(&hard.r, interrupted, 0); - if(hard.status & Serr) - errors("disk error"); - if(cmd == Cread){ - if((hard.status & Sdrq) == 0) - panic("disk read"); - inss(Pdata, aa + i*dp->bytes, dp->bytes/2); - } else { - if((hard.status & Sdrq) == 0){ - if(i+1 != secs) - panic("disk write"); - } else - outss(Pdata, aa + (i+1)*dp->bytes, dp->bytes/2); - } + + /* + * calculate the physical address of off + */ + lsec = off/dp->bytes; + cp->tcyl = lsec/(dp->sectors*dp->heads); + cp->tsec = (lsec % dp->sectors) + 1; + cp->thead = (lsec/dp->sectors) % dp->heads; + + /* + * can't xfer across cylinder boundaries. + */ + lsec = (off+len)/dp->bytes; + cyl = lsec/(dp->sectors*dp->heads); + if(cyl == cp->tcyl) + cp->len = len; + else + cp->len = cyl*dp->sectors*dp->heads*dp->bytes - off; + + /* + * wait for the controller to accept commands + */ + while(inb(cp->pbase+Pstatus) & Sbusy) + ; + + /* + * start the transfer + */ + cp->secs = cp->len/dp->bytes; + cp->sofar = 0; + cp->cmd = cmd; + outb(cp->pbase+Pcount, cp->secs); + outb(cp->pbase+Psector, cp->tsec); + outb(cp->pbase+Pdh, (1<<5) | (dp->drive<<4) | cp->thead); + outb(cp->pbase+Pcyllsb, cp->tcyl); + outb(cp->pbase+Pcylmsb, cp->tcyl>>8); + outb(cp->pbase+Pcmd, cmd); + + if(cmd == Cwrite){ + memmove(cp->buf, va, cp->len); + outss(Pdata, cp->buf, dp->bytes/2); } - qunlock(&hard); + sleep(&cp->r, cmddone, cp); + if(cp->status & Serr){ +print("hd%d err: status %lux, err %lux\n", dp-hard, cp->status, cp->error); +print("\ttcyl %d, tsec %d, thead %d\n", cp->tcyl, cp->tsec, cp->thead); +print("\tsecs %d, sofar %d\n", cp->secs, cp->sofar); + errors("disk I/O error"); + } + if(cmd == Cread) + memmove(va, cp->buf, cp->len); + + poperror(); + qunlock(cp); + return cp->len; } /* - * take/clear a disk interrupt + * set read ahead mode (1 == on, 0 == off) */ static void -hardintr(Ureg *ur) +hardsetbuf(Drive *dp, int on) { - hard.status = inb(Pstatus); - if(hard.status & Sbusy) - panic("disk busy"); - hard.intr = 1; - wakeup(&hard.r); + Controller *cp = dp->cp; + + qlock(cp); + if(waserror()){ + qunlock(cp); + nexterror(); + } + + outb(cp->pbase+Pbmode, on ? 0xAA : 0x55); + outb(cp->pbase+Pdh, (1<<5) | dp->drive<<4); + outb(cp->pbase+Pcmd, Csetbuf); + + poperror(); + qunlock(cp); } /* - * calculate physical address of a logical byte offset into the disk - * - * truncate dp->len if it crosses a cylinder boundary + * get parameters from the drive */ -static void -hardpos(Drive *dp, long off) +static long +hardident(Drive *dp) { - int lsec; - int end; - int cyl; + Controller *cp; - lsec = off/dp->bytes; - dp->tcyl = lsec/(dp->sectors*dp->heads); - dp->tsec = (lsec % dp->sectors) + 1; - dp->thead = (lsec/dp->sectors) % dp->heads; + cp = dp->cp; + qlock(cp); + if(waserror()){ + qunlock(cp); + nexterror(); + } + + cp->len = 512; + cp->secs = 1; + cp->sofar = 0; + cp->cmd = Cident; + outb(cp->pbase+Pdh, (1<<5) | dp->drive<<4); + outb(cp->pbase+Pcmd, Cident); + sleep(&cp->r, cmddone, cp); + if(cp->status & Serr){ +print("bad disk magic\n"); + errors("disk I/O error"); + } + memmove(&dp->id, cp->buf, cp->len); + + if(dp->id.magic != 0xA5A){ +print("bad disk magic\n"); + errors("bad disk magic"); + } + +if((dp->id.interface & 0x4000) == 0) + print("lookaheads disabled\n"); + + poperror(); + qunlock(cp); +} + +/* + * we get an interrupt for every sector transferred + */ +static void +hardintr(Ureg *ur) +{ + Controller *cp; /* - * can't read across cylinder boundaries. - * if so, decrement the bytes to be read. + * BUG!! if there is ever more than one controller, we need a way to + * distinguish which interrupted */ - lsec = (off+dp->len)/dp->bytes; - cyl = lsec/(dp->sectors*dp->heads); - if(cyl != dp->tcyl){ - dp->len -= (lsec % dp->sectors)*dp->bytes; - dp->len -= ((lsec/dp->sectors) % dp->heads)*dp->bytes*dp->sectors; + cp = &hardc[0]; + + cp->status = inb(cp->pbase+Pstatus); + switch(cp->cmd){ + case Cwrite: + if(cp->status & Serr){ + cp->cmd = 0; + cp->error = inb(cp->pbase+Perror); + wakeup(&cp->r); + return; + } + cp->sofar++; + if(cp->sofar != cp->secs){ + while((inb(cp->pbase+Pstatus) & Sdrq) == 0) + ; + outss(cp->pbase+Pdata, &cp->buf[cp->sofar*cp->dp->bytes], + cp->dp->bytes/2); + } else{ + cp->cmd = 0; + wakeup(&cp->r); + } + break; + case Cread: + case Cident: + if(cp->status & Serr){ + cp->cmd = 0; + cp->error = inb(cp->pbase+Perror); + wakeup(&cp->r); + return; + } + while((inb(cp->pbase+Pstatus) & Sdrq) == 0) + ; + inss(cp->pbase+Pdata, &cp->buf[cp->sofar*cp->dp->bytes], + cp->dp->bytes/2); + cp->sofar++; + if(cp->sofar == cp->secs){ + cp->cmd = 0; + wakeup(&cp->r); + } + break; + default: + print("wierd disk interrupt\n"); + break; } + wakeup(&cp->r); } - diff --git a/pc/io.h b/pc/io.h index b3467bcfce4fcc8f5f1594da5a49bffb97542938..79f47af1415da2b59b61c1e9520d642eee1d4620 100644 --- a/pc/io.h +++ b/pc/io.h @@ -7,8 +7,8 @@ enum Int0vec= 16, /* first 8259 */ Clockvec= Int0vec+0, /* clock interrupts */ Kbdvec= Int0vec+1, /* keyboard interrupts */ - Uart0vec= Int0vec+4, /* serial line */ Uart1vec= Int0vec+3, /* modem line */ + Uart0vec= Int0vec+4, /* serial line */ Floppyvec= Int0vec+6, /* floppy interrupts */ Int1vec= Int0vec+8, /* second 8259 */ Mousevec= Int1vec+4, /* mouse interrupt */ diff --git a/port/devmnt.c b/port/devmnt.c index f19ef2f6ed62d391f66a72e5068aba3782c1c7fe..390700d9f350bf137c46ecdf1f9c85b4c4b1a8b5 100644 --- a/port/devmnt.c +++ b/port/devmnt.c @@ -37,6 +37,7 @@ typedef struct Mntbuf Mntbuf; struct Mntbuf { Mntbuf *next; +int pid; char buf[BUFSIZE+BITROUND]; /* BUG */ }; @@ -50,6 +51,7 @@ struct Mnthdr { Mnthdr *next; /* in free list or writers list */ Mnthdr *prev; /* in writers list only */ +int pid; short active; short flushing; /* a Tflush has been sent */ Fcall thdr; @@ -93,6 +95,7 @@ loop: lock(&mntbufalloc); if(mb = mntbufalloc.free){ /* assign = */ mntbufalloc.free = mb->next; +mb->pid = u->p->pid; unlock(&mntbufalloc); return mb; } @@ -109,6 +112,7 @@ loop: void mbfree(Mntbuf *mb) { +if(mb->pid != u->p->pid)print("mbfree pid\n"); lock(&mntbufalloc); mb->next = mntbufalloc.free; mntbufalloc.free = mb; @@ -127,7 +131,9 @@ loop: if(mh->active) print("mh->active\n"); if(mh->flushing) print("mh->flushing\n"); if(mh->mbr) print("mh->mbr\n"); +if(mh->readreply) print("mh->readreply\n"); mh->mbr = 0; +mh->pid = u->p->pid; unlock(&mnthdralloc); return mh; } @@ -144,6 +150,7 @@ if(mh->mbr) print("mh->mbr\n"); void mhfree(Mnthdr *mh) { +if(mh->pid != u->p->pid)print("mhfree pid %d\n", mh->flushing); if(mh->flushing) return; mh->active = 0; @@ -623,6 +630,7 @@ mntflush(Mnt *m, Mnthdr *omh) /* queue is unlocked */ Mnthdr *mh; if(omh->thdr.type == Tflush){ +print("flush flush\n"); omh->flushing = 0; return; } @@ -650,8 +658,10 @@ mnterrdequeue(Mnt *m, Mnthdr *mh) /* queue is unlocked */ 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 */ +{ Mnthdr *h; for(h=q->writer; h; h=h->next) if(h->p==u->p)print("reader and writer error\n"); } w = q->writer; if(w){ mntwunlink(q, w); @@ -686,9 +696,11 @@ mntxmit(Mnt *m, Mnthdr *mh) mbw = mballoc(); if(waserror()){ /* 1 */ if(mh->mbr){ +if(mh->mbr->pid != u->p->pid) print("top waserror\n"); mbfree(mh->mbr); mh->mbr = 0; } +if(mbw->pid != u->p->pid) print("top waserror mbw\n"); mbfree(mbw); nexterror(); } @@ -839,6 +851,7 @@ mntxmit(Mnt *m, Mnthdr *mh) if(tag<0 || tag>=conf.nmnthdr){ print("unknown tag %d\n", tag); FreeRead: +if(mh->mbr->pid != u->p->pid) print("FreeRead\n"); mbfree(mh->mbr); mh->mbr = 0; goto Read; @@ -848,7 +861,8 @@ mntxmit(Mnt *m, Mnthdr *mh) goto FreeRead; if(mh->rhdr.type != Rerror) if(mh->rhdr.type != w->thdr.type+1){ - print(" t%c ", devchar[m->q->msg->type]); + print(" t%c %d %d ", devchar[m->q->msg->type], + mh->rhdr.type, w->thdr.type+1); goto FreeRead; } w->mbr = mh->mbr; @@ -856,6 +870,9 @@ mntxmit(Mnt *m, Mnthdr *mh) memmove(&w->rhdr, &mh->rhdr, sizeof mh->rhdr); mntwunlink(q, w); w->readreply = 1; +lock(&w->r); +if(w->r.p) w->mbr->pid = w->p->pid; +unlock(&w->r); wakeup(&w->r); goto Read; }else{ @@ -877,8 +894,12 @@ mntxmit(Mnt *m, Mnthdr *mh) USED(qlocked); qlock(q); qlocked = 1; - if(q->reader == u->p) /* i got promoted */ + mh->readreply = 0; + if(q->reader == u->p){ /* i got promoted */ +{ Mnthdr *h; for(h=q->writer; h; h=h->next) if(h->p==u->p)print("reader and writer promotion\n"); } goto Read; +} +if(mh->mbr->pid != u->p->pid) print("after promotion %d\n", mh->thdr.type); mh->active = 0; USED(qlocked); qunlock(q); @@ -908,6 +929,7 @@ mntxmit(Mnt *m, Mnthdr *mh) error(Ebadcnt); memmove(mh->thdr.data, mh->rhdr.data, mh->rhdr.count); } +if(mh->mbr->pid != u->p->pid) print("tail\n"); mbfree(mh->mbr); mh->mbr = 0; mbfree(mbw); diff --git a/port/stream.c b/port/stream.c index 449532974d1fa47c57eea0b4a166242d6efdfd04..2c4eebd2d79f1d0e1799b80f6dd431755c36dbb3 100644 --- a/port/stream.c +++ b/port/stream.c @@ -1094,6 +1094,7 @@ long streamread(Chan *c, void *vbuf, long n) { Block *bp; + Block *tofree; Stream *s; Queue *q; int left, i; @@ -1108,13 +1109,18 @@ streamread(Chan *c, void *vbuf, long n) s = c->stream; left = n; qlock(&s->rdlock); + tofree = 0; if(waserror()){ /* - * notes will flush the rest of any partially - * read message. + * put any partially read message back into the + * queue */ - if(n != left) - s->flushmsg = 1; + while(tofree){ + bp = tofree; + tofree = bp->next; + bp->next = 0; + putbq(q, bp); + } qunlock(&s->rdlock); nexterror(); } @@ -1139,23 +1145,15 @@ streamread(Chan *c, void *vbuf, long n) continue; } - if(s->flushmsg){ - if(bp->flags & S_DELIM) - s->flushmsg = 0; - freeb(bp); - continue; - } - i = BLEN(bp); if(i <= left){ memmove(buf, bp->rptr, i); left -= i; buf += i; - if(bp->flags & S_DELIM){ - freeb(bp); + bp->next = tofree; + tofree = bp; + if(bp->flags & S_DELIM) break; - } else - freeb(bp); } else { memmove(buf, bp->rptr, left); bp->rptr += left; @@ -1164,6 +1162,12 @@ streamread(Chan *c, void *vbuf, long n) } } + /* + * free completely read blocks + */ + if(tofree) + freeb(tofree); + qunlock(&s->rdlock); poperror(); return n - left;