diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-11-07 22:20:10 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-11-07 22:20:10 +0100 |
commit | a54d1cd95e19dc6685c1a6a5c22d6fdf6f0068eb (patch) | |
tree | 1139d07f225ad15ee602501373a976f716a766ff /sys/src/9/port | |
parent | 23d217afb45b6b74c151a91f12695c553721c4f1 (diff) |
kernel/qio: big cleanup of qio functions
remove bl2mem(), it is broken. a fault while copying to memory
yields a partially freed block list. it can be simply replaced
by readblist() and freeblist(), which we also use for qcopy()
now.
remove mem2bl(), and handle putting back remainer from a short
read internally (splitblock()) avoiding the releasing and re-
acquiering of the ilock.
always attempt to free blocks outside of the ilock.
have qaddlist() return the number of bytes enqueued, which
avoids walking the block list twice.
Diffstat (limited to 'sys/src/9/port')
-rw-r--r-- | sys/src/9/port/devmnt.c | 9 | ||||
-rw-r--r-- | sys/src/9/port/portfns.h | 3 | ||||
-rw-r--r-- | sys/src/9/port/qio.c | 382 |
3 files changed, 135 insertions, 259 deletions
diff --git a/sys/src/9/port/devmnt.c b/sys/src/9/port/devmnt.c index 4f88e3832..095381d57 100644 --- a/sys/src/9/port/devmnt.c +++ b/sys/src/9/port/devmnt.c @@ -729,7 +729,7 @@ mntrdwr(int type, Chan *c, void *buf, long n, vlong off) if(nr > nreq) nr = nreq; if(type == Tread) - r->b = bl2mem((uchar*)uba, r->b, nr); + nr = readblist(r->b, (uchar*)uba, nr, 0); mntfree(r); poperror(); @@ -1076,13 +1076,8 @@ doread(Mnt *m, int len) while(qlen(m->q) < len){ b = devtab[m->c->type]->bread(m->c, m->msize, 0); - if(b == nil) + if(b == nil || qaddlist(m->q, b) == 0) return -1; - if(blocklen(b) == 0){ - freeblist(b); - return -1; - } - qaddlist(m->q, b); } return 0; } diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index cb69c24bb..e5e9f2c59 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -10,7 +10,6 @@ Block* allocb(int); int anyhigher(void); int anyready(void); Image* attachimage(int, Chan*, uintptr, ulong); -Block* bl2mem(uchar*, Block*, int); int blocklen(Block*); void bootlinks(void); void cachedel(Image*, uintptr); @@ -250,7 +249,7 @@ void putseg(Segment*); void putstrn(char*, int); void putswap(Page*); ulong pwait(Waitmsg*); -void qaddlist(Queue*, Block*); +int qaddlist(Queue*, Block*); Block* qbread(Queue*, int); long qbwrite(Queue*, Block*); Queue* qbypass(void (*)(void*, Block*), void*); diff --git a/sys/src/9/port/qio.c b/sys/src/9/port/qio.c index 6e9525b8e..bcfc573a0 100644 --- a/sys/src/9/port/qio.c +++ b/sys/src/9/port/qio.c @@ -78,6 +78,9 @@ padblock(Block *bp, int size) int n; Block *nbp; + if(bp->next != nil) + panic("padblock %#p", getcallerpc(&bp)); + QDEBUG checkb(bp, "padblock 1"); if(size >= 0){ if(bp->rp - bp->base >= size){ @@ -85,33 +88,25 @@ padblock(Block *bp, int size) return bp; } - if(bp->next != nil) - panic("padblock %#p", getcallerpc(&bp)); n = BLEN(bp); - padblockcnt++; nbp = allocb(size+n); nbp->rp += size; nbp->wp = nbp->rp; memmove(nbp->wp, bp->rp, n); nbp->wp += n; - freeb(bp); nbp->rp -= size; } else { size = -size; - - if(bp->next != nil) - panic("padblock %#p", getcallerpc(&bp)); - if(bp->lim - bp->wp >= size) return bp; n = BLEN(bp); - padblockcnt++; nbp = allocb(size+n); memmove(nbp->wp, bp->rp, n); nbp->wp += n; - freeb(bp); } + freeb(bp); + padblockcnt++; QDEBUG checkb(nbp, "padblock 1"); return nbp; } @@ -155,20 +150,21 @@ blockalloclen(Block *bp) Block* concatblock(Block *bp) { + Block *nb, *next; int len; - Block *nb, *f; if(bp->next == nil) return bp; nb = allocb(blocklen(bp)); - for(f = bp; f != nil; f = f->next) { - len = BLEN(f); - memmove(nb->wp, f->rp, len); + for(; bp != nil; bp = next) { + next = bp->next; + len = BLEN(bp); + memmove(nb->wp, bp->rp, len); nb->wp += len; + freeb(bp); } concatblockcnt += BLEN(nb); - freeblist(bp); QDEBUG checkb(nb, "concatblock 1"); return nb; } @@ -179,8 +175,8 @@ concatblock(Block *bp) Block* pullupblock(Block *bp, int n) { - int i; Block *nbp; + int i; /* * this should almost always be true, it's @@ -204,10 +200,10 @@ pullupblock(Block *bp, int n) */ n -= BLEN(bp); while((nbp = bp->next) != nil){ + pullupblockcnt++; i = BLEN(nbp); if(i > n) { memmove(bp->wp, nbp->rp, n); - pullupblockcnt++; bp->wp += n; nbp->rp += n; QDEBUG checkb(bp, "pullupblock 1"); @@ -220,7 +216,6 @@ pullupblock(Block *bp, int n) i = 0; } memmove(bp->wp, nbp->rp, i); - pullupblockcnt++; bp->wp += i; bp->next = nbp->next; nbp->next = nil; @@ -403,11 +398,11 @@ qget(Queue *q) iunlock(q); return nil; } + QDEBUG checkb(b, "qget"); q->bfirst = b->next; b->next = nil; q->len -= BALLOC(b); q->dlen -= BLEN(b); - QDEBUG checkb(b, "qget"); /* if writer flow controlled, restart */ if((q->state & Qflow) && q->len < q->limit/2){ @@ -430,7 +425,7 @@ qget(Queue *q) int qdiscard(Queue *q, int len) { - Block *b; + Block *b, *tofree = nil; int dowakeup, n, sofar; ilock(q); @@ -442,10 +437,12 @@ qdiscard(Queue *q, int len) n = BLEN(b); if(n <= len - sofar){ q->bfirst = b->next; - b->next = nil; q->len -= BALLOC(b); q->dlen -= BLEN(b); - freeb(b); + + /* remember to free this */ + b->next = tofree; + tofree = b; } else { n = len - sofar; b->rp += n; @@ -474,6 +471,9 @@ qdiscard(Queue *q, int len) if(dowakeup) wakeup(&q->wr); + if(tofree != nil) + freeblist(tofree); + return sofar; } @@ -483,10 +483,9 @@ qdiscard(Queue *q, int len) int qconsume(Queue *q, void *vp, int len) { - Block *b; + Block *b, *tofree = nil; int n, dowakeup; uchar *p = vp; - Block *tofree = nil; /* sync with qwrite */ ilock(q); @@ -495,8 +494,8 @@ qconsume(Queue *q, void *vp, int len) b = q->bfirst; if(b == nil){ q->state |= Qstarve; - iunlock(q); - return -1; + len = -1; + goto out; } QDEBUG checkb(b, "qconsume 1"); @@ -511,17 +510,16 @@ qconsume(Queue *q, void *vp, int len) tofree = b; }; + consumecnt += n; if(n < len) len = n; memmove(p, b->rp, len); - consumecnt += n; b->rp += len; q->dlen -= len; /* discard the block if we're done with it */ if((q->state & Qmsg) || len == n){ q->bfirst = b->next; - b->next = nil; q->len -= BALLOC(b); q->dlen -= BLEN(b); @@ -530,6 +528,7 @@ qconsume(Queue *q, void *vp, int len) tofree = b; } +out: /* if writer flow controlled, restart */ if((q->state & Qflow) && q->len < q->limit/2){ q->state &= ~Qflow; @@ -551,40 +550,23 @@ qconsume(Queue *q, void *vp, int len) int qpass(Queue *q, Block *b) { - int dlen, len, dowakeup; + int len, dowakeup; /* sync with qread */ dowakeup = 0; ilock(q); if(q->len >= q->limit){ - freeblist(b); iunlock(q); + freeblist(b); return -1; } if(q->state & Qclosed){ - len = BALLOC(b); - freeblist(b); iunlock(q); - return len; + freeblist(b); + return 0; } - /* add buffer to queue */ - if(q->bfirst != nil) - q->blast->next = b; - else - q->bfirst = b; - len = BALLOC(b); - dlen = BLEN(b); - QDEBUG checkb(b, "qpass"); - while(b->next != nil){ - b = b->next; - QDEBUG checkb(b, "qpass"); - len += BALLOC(b); - dlen += BLEN(b); - } - q->blast = b; - q->len += len; - q->dlen += dlen; + len = qaddlist(q, b); if(q->len >= q->limit/2) q->state |= Qflow; @@ -604,35 +586,19 @@ qpass(Queue *q, Block *b) int qpassnolim(Queue *q, Block *b) { - int dlen, len, dowakeup; + int len, dowakeup; /* sync with qread */ dowakeup = 0; ilock(q); if(q->state & Qclosed){ - freeblist(b); iunlock(q); - return BALLOC(b); + freeblist(b); + return 0; } - /* add buffer to queue */ - if(q->bfirst != nil) - q->blast->next = b; - else - q->bfirst = b; - len = BALLOC(b); - dlen = BLEN(b); - QDEBUG checkb(b, "qpass"); - while(b->next != nil){ - b = b->next; - QDEBUG checkb(b, "qpass"); - len += BALLOC(b); - dlen += BLEN(b); - } - q->blast = b; - q->len += len; - q->dlen += dlen; + len = qaddlist(q, b); if(q->len >= q->limit/2) q->state |= Qflow; @@ -680,6 +646,10 @@ qproduce(Queue *q, void *vp, int len) int dowakeup; uchar *p = vp; + b = iallocb(len); + if(b == nil) + return 0; + /* sync with qread */ dowakeup = 0; ilock(q); @@ -690,25 +660,12 @@ qproduce(Queue *q, void *vp, int len) iunlock(q); return -1; } + producecnt += len; /* save in buffer */ - b = iallocb(len); - if(b == nil){ - iunlock(q); - return 0; - } memmove(b->wp, p, len); - producecnt += len; b->wp += len; - if(q->bfirst != nil) - q->blast->next = b; - else - q->bfirst = b; - q->blast = b; - /* b->next = 0; done by iallocb() */ - q->len += BALLOC(b); - q->dlen += BLEN(b); - QDEBUG checkb(b, "qproduce"); + qaddlist(q, b); if(q->state & Qstarve){ q->state &= ~Qstarve; @@ -731,49 +688,13 @@ qproduce(Queue *q, void *vp, int len) Block* qcopy(Queue *q, int len, ulong offset) { - int sofar; - int n; - Block *b, *nb; - uchar *p; - - nb = allocb(len); + Block *b; + b = allocb(len); ilock(q); - - /* go to offset */ - b = q->bfirst; - for(sofar = 0; ; sofar += n){ - if(b == nil){ - iunlock(q); - return nb; - } - n = BLEN(b); - if(sofar + n > offset){ - p = b->rp + offset - sofar; - n -= offset - sofar; - break; - } - QDEBUG checkb(b, "qcopy"); - b = b->next; - } - - /* copy bytes from there */ - for(sofar = 0; sofar < len;){ - if(n > len - sofar) - n = len - sofar; - memmove(nb->wp, p, n); - qcopycnt += n; - sofar += n; - nb->wp += n; - b = b->next; - if(b == nil) - break; - n = BLEN(b); - p = b->rp; - } + b->wp += readblist(q->bfirst, b->wp, len, offset); iunlock(q); - - return nb; + return b; } /* @@ -855,21 +776,34 @@ qwait(Queue *q) } /* - * add a block list to a queue + * add a block list to a queue, return bytes added */ -void +int qaddlist(Queue *q, Block *b) { + int len, dlen; + + QDEBUG checkb(b, "qaddlist 1"); + /* queue the block */ if(q->bfirst != nil) q->blast->next = b; else q->bfirst = b; - q->len += blockalloclen(b); - q->dlen += blocklen(b); - while(b->next != nil) + + len = BALLOC(b); + dlen = BLEN(b); + while(b->next != nil){ b = b->next; + QDEBUG checkb(b, "qaddlist 2"); + + len += BALLOC(b); + dlen += BLEN(b); + } q->blast = b; + q->len += len; + q->dlen += dlen; + return dlen; } /* @@ -883,11 +817,11 @@ qremove(Queue *q) b = q->bfirst; if(b == nil) return nil; + QDEBUG checkb(b, "qremove"); q->bfirst = b->next; b->next = nil; q->dlen -= BLEN(b); q->len -= BALLOC(b); - QDEBUG checkb(b, "qremove"); return b; } @@ -922,68 +856,6 @@ readblist(Block *b, uchar *p, long n, long o) } /* - * copy the contents of a string of blocks into - * memory. emptied blocks are freed. return - * pointer to first unconsumed block. - */ -Block* -bl2mem(uchar *p, Block *b, int n) -{ - int i; - Block *next; - - for(; b != nil; b = next){ - i = BLEN(b); - if(i > n){ - memmove(p, b->rp, n); - b->rp += n; - return b; - } - memmove(p, b->rp, i); - n -= i; - p += i; - b->rp += i; - next = b->next; - freeb(b); - } - return nil; -} - -/* - * copy the contents of memory into a string of blocks. - * return nil on error. - */ -Block* -mem2bl(uchar *p, int len) -{ - int n; - Block *b, *first, **l; - - first = nil; - l = &first; - if(waserror()){ - freeblist(first); - nexterror(); - } - do { - n = len; - if(n > Maxatomic) - n = Maxatomic; - - *l = b = allocb(n); - setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]); - memmove(b->wp, p, n); - b->wp += n; - p += n; - len -= n; - l = &b->next; - } while(len > 0); - poperror(); - - return first; -} - -/* * put a block back to the front of the queue * called with q ilocked */ @@ -999,6 +871,35 @@ qputback(Queue *q, Block *b) } /* + * cut off n bytes from the end of *h. return a new + * block with the tail and change *h to refer to the + * head. + */ +static Block* +splitblock(Block **h, int n) +{ + Block *a, *b; + int m; + + a = *h; + m = BLEN(a) - n; + if(m < n){ + b = allocb(m); + memmove(b->wp, a->rp, m); + b->wp += m; + a->rp += m; + *h = b; + return a; + } else { + b = allocb(n); + a->wp -= n; + memmove(b->wp, a->wp, n); + b->wp += n; + return b; + } +} + +/* * flow control, get producer going again * called with q ilocked */ @@ -1029,7 +930,7 @@ qwakeup_iunlock(Queue *q) Block* qbread(Queue *q, int len) { - Block *b, *nb; + Block *b; int n; eqlock(&q->rlock); @@ -1057,24 +958,21 @@ qbread(Queue *q, int len) n = BLEN(b); /* split block if it's too big and this is not a message queue */ - nb = b; if(n > len){ - if((q->state&Qmsg) == 0){ - n -= len; - b = allocb(n); - memmove(b->wp, nb->rp+len, n); - b->wp += n; - qputback(q, b); - } - nb->wp = nb->rp + len; + n -= len; + if((q->state & Qmsg) == 0) + qputback(q, splitblock(&b, n)); + else + b->wp -= n; } /* restart producer */ qwakeup_iunlock(q); - poperror(); qunlock(&q->rlock); - return nb; + poperror(); + + return b; } /* @@ -1084,7 +982,7 @@ qbread(Queue *q, int len) long qread(Queue *q, void *vp, int len) { - Block *b, *first, **l; + Block *b, *first, **last; int m, n; eqlock(&q->rlock); @@ -1109,6 +1007,7 @@ again: } /* if we get here, there's at least one block in the queue */ + last = &first; if(q->state & Qcoalesce){ /* when coalescing, 0 length blocks just go away */ b = q->bfirst; @@ -1123,13 +1022,13 @@ again: * fit in the read. */ n = 0; - l = &first; for(;;) { - *l = qremove(q); - l = &b->next; + *last = qremove(q); n += m; - if(n >= len || (b = q->bfirst) == nil) + if(n >= len || q->bfirst == nil) break; + last = &b->next; + b = q->bfirst; m = BLEN(b); } } else { @@ -1137,25 +1036,24 @@ again: n = BLEN(first); } - /* copy to user space outside of the ilock */ - iunlock(q); - b = bl2mem(vp, first, len); - ilock(q); - - /* take care of any left over partial block */ - if(b != nil){ - n -= BLEN(b); - if(q->state & Qmsg) - freeb(b); - else - qputback(q, b); - } + /* split last block if it's too big and this is not a message queue */ + if(n > len && (q->state & Qmsg) == 0) + qputback(q, splitblock(last, n - len)); /* restart producer */ qwakeup_iunlock(q); - poperror(); qunlock(&q->rlock); + poperror(); + + if(waserror()){ + freeblist(first); + nexterror(); + } + n = readblist(first, vp, len, 0); + freeblist(first); + poperror(); + return n; } @@ -1198,19 +1096,18 @@ qflow(Queue *q) long qbwrite(Queue *q, Block *b) { - int n, dowakeup; + int len, dowakeup; Proc *p; - n = BLEN(b); - if(q->bypass != nil){ + len = blocklen(b); (*q->bypass)(q->arg, b); - return n; + return len; } dowakeup = 0; if(waserror()){ - freeb(b); + freeblist(b); nexterror(); } ilock(q); @@ -1224,21 +1121,13 @@ qbwrite(Queue *q, Block *b) /* don't queue over the limit */ if(q->len >= q->limit && q->noblock){ iunlock(q); - freeb(b); poperror(); - return n; + len = blocklen(b); + freeblist(b); + return len; } - /* queue the block */ - if(q->bfirst != nil) - q->blast->next = b; - else - q->bfirst = b; - q->blast = b; - b->next = nil; - q->len += BALLOC(b); - q->dlen += n; - QDEBUG checkb(b, "qbwrite"); + len = qaddlist(q, b); /* make sure other end gets awakened */ if(q->state & Qstarve){ @@ -1270,7 +1159,7 @@ qbwrite(Queue *q, Block *b) */ qflow(q); - return n; + return len; } /* @@ -1359,14 +1248,7 @@ qiwrite(Queue *q, void *vp, int len) break; } - QDEBUG checkb(b, "qiwrite"); - if(q->bfirst != nil) - q->blast->next = b; - else - q->bfirst = b; - q->blast = b; - q->len += BALLOC(b); - q->dlen += n; + qaddlist(q, b); if(q->state & Qstarve){ q->state &= ~Qstarve; |