ref: 3b886fcd3ec063d39ad3f8a16cb7eb08576102ec
parent: 278bcb7edd5958d3bb83c0b13f0250446b7ed597
author: cinap_lenrek <[email protected]>
date: Sat Nov 12 10:54:14 EST 2016
kern: update qio and devmnt, remove mount cache stub
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -5,7 +5,6 @@
OFILES=\
alloc.$O\
allocb.$O\
- cache.$O\
chan.$O\
data.$O\
dev.$O\
--- a/kern/allocb.c
+++ b/kern/allocb.c
@@ -7,15 +7,10 @@
enum
{
Hdrspc = 64, /* leave room for high-level headers */
+ Tlrspc = 16, /* extra room at the end for pad/crc/mac */
Bdead = 0x51494F42, /* "QIOB" */
};
-struct
-{
- Lock lk;
- ulong bytes;
-} ialloc;
-
static Block*
_allocb(int size)
{
@@ -22,12 +17,13 @@
Block *b;
uintptr addr;
+ size += Tlrspc;
if((b = mallocz(sizeof(Block)+size+Hdrspc, 0)) == nil)
return nil;
b->next = nil;
b->list = nil;
- b->free = 0;
+ b->free = nil;
b->flag = 0;
/* align start of data portion by rounding up */
@@ -36,9 +32,9 @@
b->base = (uchar*)addr;
/* align end of data portion by rounding down */
- b->lim = ((uchar*)b) + sizeof(Block)+size+Hdrspc;
- addr = (uintptr)(b->lim);
- addr = addr & ~(BLOCKALIGN-1);
+ b->lim = (uchar*)b + sizeof(Block)+size+Hdrspc;
+ addr = (uintptr)b->lim;
+ addr &= ~(BLOCKALIGN-1);
b->lim = (uchar*)addr;
/* leave sluff at beginning for added headers */
@@ -57,13 +53,11 @@
/*
* Check in a process and wait until successful.
- * Can still error out of here, though.
*/
if(up == nil)
- panic("allocb without up: %p\n", getcallerpc(&size));
- if((b = _allocb(size)) == nil){
- panic("allocb: no memory for %d bytes\n", size);
- }
+ panic("allocb without up: %#p", getcallerpc(&size));
+ if((b = _allocb(size)) == nil)
+ panic("allocb: no memory for %d bytes", size);
setmalloctag(b, getcallerpc(&size));
return b;
@@ -73,28 +67,12 @@
iallocb(int size)
{
Block *b;
- static int m1, m2;
- if(ialloc.bytes > conf.ialloc){
- if((m1++%10000)==0)
- print("iallocb: limited %lud/%lud\n",
- ialloc.bytes, conf.ialloc);
- return 0;
- }
-
- if((b = _allocb(size)) == nil){
- if((m2++%10000)==0)
- print("iallocb: no memory %lud/%lud\n",
- ialloc.bytes, conf.ialloc);
- return nil;
- }
+ if((b = _allocb(size)) == nil)
+ panic("iallocb: no memory for %d bytes", size);
setmalloctag(b, getcallerpc(&size));
b->flag = BINTR;
- ilock(&ialloc.lk);
- ialloc.bytes += b->lim - b->base;
- iunlock(&ialloc.lk);
-
return b;
}
@@ -110,15 +88,10 @@
* drivers which perform non cache coherent DMA manage their own buffer
* pool of uncached buffers and provide their own free routine.
*/
- if(b->free) {
+ if(b->free != nil) {
b->free(b);
return;
}
- if(b->flag & BINTR) {
- ilock(&ialloc.lk);
- ialloc.bytes -= b->lim - b->base;
- iunlock(&ialloc.lk);
- }
/* poison the block in case someone is still holding onto it */
b->next = dead;
@@ -136,30 +109,23 @@
void *dead = (void*)Bdead;
if(b == dead)
- panic("checkb b %s %lux", msg, b);
+ panic("checkb b %s %#p", msg, b);
if(b->base == dead || b->lim == dead || b->next == dead
|| b->rp == dead || b->wp == dead){
- print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n",
+ print("checkb: base %#p lim %#p next %#p\n",
b->base, b->lim, b->next);
- print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp);
- panic("checkb dead: %s\n", msg);
+ print("checkb: rp %#p wp %#p\n", b->rp, b->wp);
+ panic("checkb dead: %s", msg);
}
if(b->base > b->lim)
- panic("checkb 0 %s %lux %lux", msg, b->base, b->lim);
+ panic("checkb 0 %s %#p %#p", msg, b->base, b->lim);
if(b->rp < b->base)
- panic("checkb 1 %s %lux %lux", msg, b->base, b->rp);
+ panic("checkb 1 %s %#p %#p", msg, b->base, b->rp);
if(b->wp < b->base)
- panic("checkb 2 %s %lux %lux", msg, b->base, b->wp);
+ panic("checkb 2 %s %#p %#p", msg, b->base, b->wp);
if(b->rp > b->lim)
- panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim);
+ panic("checkb 3 %s %#p %#p", msg, b->rp, b->lim);
if(b->wp > b->lim)
- panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim);
-
-}
-
-void
-iallocsummary(void)
-{
- print("ialloc %lud/%lud\n", ialloc.bytes, conf.ialloc);
+ panic("checkb 4 %s %#p %#p", msg, b->wp, b->lim);
}
--- a/kern/cache.c
+++ /dev/null
@@ -1,46 +1,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-
-void
-cinit(void)
-{
-}
-
-void
-copen(Chan *c)
-{
- USED(c);
-}
-
-int
-cread(Chan *c, uchar *buf, int len, vlong off)
-{
- USED(c);
- USED(buf);
- USED(len);
- USED(off);
-
- return 0;
-}
-
-void
-cupdate(Chan *c, uchar *buf, int len, vlong off)
-{
- USED(c);
- USED(buf);
- USED(len);
- USED(off);
-}
-
-void
-cwrite(Chan* c, uchar *buf, int len, vlong off)
-{
- USED(c);
- USED(buf);
- USED(len);
- USED(off);
-}
--- a/kern/devmnt.c
+++ b/kern/devmnt.c
@@ -24,15 +24,10 @@
Fcall request; /* Outgoing file system protocol message */
Fcall reply; /* Incoming reply */
Mnt* m; /* Mount device during rpc */
- Rendez r; /* Place to hang out */
- uchar* rpc; /* I/O Data buffer */
- uint rpclen; /* len of buffer */
- Block *b; /* reply blocks */
- char done; /* Rpc completed */
- uvlong stime; /* start time for mnt statistics */
- ulong reqlen; /* request length for mnt statistics */
- ulong replen; /* reply length for mnt statistics */
+ Rendez* z; /* Place to hang out */
+ Block* b; /* reply blocks */
Mntrpc* flushed; /* message this one flushes */
+ char done; /* Rpc completed */
};
enum
@@ -42,42 +37,38 @@
NMASK = (64*1024)>>TAGSHIFT,
};
-struct Mntalloc
+static struct Mntalloc
{
- Lock lk;
+ Lock lk;
Mnt* list; /* Mount devices in use */
Mnt* mntfree; /* Free list */
Mntrpc* rpcfree;
- int nrpcfree;
- int nrpcused;
+ ulong nrpcfree;
+ ulong nrpcused;
ulong id;
ulong tagmask[NMASK];
-}mntalloc;
+} mntalloc;
-void mattach(Mnt*, Chan*, char*);
-Mnt* mntchk(Chan*);
-void mntdirfix(uchar*, Chan*);
-Mntrpc* mntflushalloc(Mntrpc*, ulong);
-void mntflushfree(Mnt*, Mntrpc*);
-void mntfree(Mntrpc*);
-void mntgate(Mnt*);
-void mntpntfree(Mnt*);
-void mntqrm(Mnt*, Mntrpc*);
-Mntrpc* mntralloc(Chan*, ulong);
-long mntrdwr(int, Chan*, void*, long, vlong);
-int mntrpcread(Mnt*, Mntrpc*);
-void mountio(Mnt*, Mntrpc*);
-void mountmux(Mnt*, Mntrpc*);
-void mountrpc(Mnt*, Mntrpc*);
-int rpcattn(void*);
-Chan* mntchan(void);
+static Chan* mntchan(void);
+static Mnt* mntchk(Chan*);
+static void mntdirfix(uchar*, Chan*);
+static Mntrpc* mntflushalloc(Mntrpc*);
+static Mntrpc* mntflushfree(Mnt*, Mntrpc*);
+static void mntfree(Mntrpc*);
+static void mntgate(Mnt*);
+static void mntqrm(Mnt*, Mntrpc*);
+static Mntrpc* mntralloc(Chan*);
+static long mntrdwr(int, Chan*, void*, long, vlong);
+static int mntrpcread(Mnt*, Mntrpc*);
+static void mountio(Mnt*, Mntrpc*);
+static void mountmux(Mnt*, Mntrpc*);
+static void mountrpc(Mnt*, Mntrpc*);
+static int rpcattn(void*);
char Esbadstat[] = "invalid directory entry received from server";
-char Enoversion[] = "version not established for mount channel";
+char Enoversion[] = "version not established for mount channel";
-void (*mntstats)(int, Chan*, uvlong, ulong);
-
static void
mntreset(void)
{
@@ -87,14 +78,12 @@
fmtinstall('F', fcallfmt);
fmtinstall('D', dirfmt);
/* We can't install %M since eipfmt does and is used in the kernel [sape] */
-
- cinit();
}
/*
* Version is not multiplexed: message sent only once per connection.
*/
-long
+int
mntversion(Chan *c, char *version, int msize, int returnlen)
{
Fcall f;
@@ -101,6 +90,7 @@
uchar *msg;
Mnt *m;
char *v;
+ Queue *q;
long k, l;
uvlong oo;
char buf[128];
@@ -167,7 +157,6 @@
unlock(&c->ref.lk);
l = devtab[c->type]->write(c, msg, k, oo);
-
if(l < k){
lock(&c->ref.lk);
c->offset -= k - l;
@@ -176,14 +165,15 @@
}
/* message sent; receive and decode reply */
- k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
- if(k <= 0)
- error("EOF receiving fversion reply");
+ for(k = 0; k < BIT32SZ || (k < GBIT32(msg) && k < 8192+IOHDRSZ); k += l){
+ l = devtab[c->type]->read(c, msg+k, 8192+IOHDRSZ-k, c->offset);
+ if(l <= 0)
+ error("EOF receiving fversion reply");
+ lock(&c->ref.lk);
+ c->offset += l;
+ unlock(&c->ref.lk);
+ }
- lock(&c->ref.lk);
- c->offset += k;
- unlock(&c->ref.lk);
-
l = convM2S(msg, k, &f);
if(l != k)
error("bad fversion conversion on reply");
@@ -199,40 +189,49 @@
k = strlen(f.version);
if(strncmp(f.version, v, k) != 0)
error("bad 9P version returned from server");
+ if(returnlen > 0 && returnlen < k)
+ error(Eshort);
+ v = nil;
+ kstrdup(&v, f.version);
+ q = qopen(10*MAXRPC, 0, nil, nil);
+ if(q == nil){
+ free(v);
+ exhausted("mount queues");
+ }
+
/* now build Mnt associated with this connection */
lock(&mntalloc.lk);
m = mntalloc.mntfree;
- if(m != 0)
+ if(m != nil)
mntalloc.mntfree = m->list;
else {
+ unlock(&mntalloc.lk);
m = malloc(sizeof(Mnt));
- if(m == 0) {
- unlock(&mntalloc.lk);
+ if(m == nil) {
+ qfree(q);
+ free(v);
exhausted("mount devices");
}
+ lock(&mntalloc.lk);
}
m->list = mntalloc.list;
mntalloc.list = m;
- m->version = nil;
- kstrdup(&m->version, f.version);
+ m->version = v;
m->id = mntalloc.id++;
- m->q = qopen(10*MAXRPC, 0, 0, nil);
+ m->q = q;
m->msize = f.msize;
unlock(&mntalloc.lk);
- if(returnlen > 0){
- if(returnlen < k)
- error(Eshort);
- memmove(version, f.version, k);
- }
+ if(returnlen > 0)
+ memmove(version, f.version, k); /* length was checked above */
poperror(); /* msg */
free(msg);
lock(&m->lk);
- m->queue = 0;
- m->rip = 0;
+ m->queue = nil;
+ m->rip = nil;
c->flag |= CMSG;
c->mux = m;
@@ -252,9 +251,8 @@
Mntrpc *r;
m = c->mux;
-
if(m == nil){
- mntversion(c, VERSION9P, MAXRPC, 0);
+ mntversion(c, nil, 0, 0);
m = c->mux;
if(m == nil)
error(Enoversion);
@@ -269,8 +267,7 @@
nexterror();
}
- r = mntralloc(0, m->msize);
-
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -287,6 +284,7 @@
incref(&m->c->ref);
c->mqid = c->qid;
c->mode = ORDWR;
+ c->iounit = m->msize-IOHDRSZ;
poperror(); /* r */
mntfree(r);
@@ -297,24 +295,13 @@
}
-static Chan*
-mntattach(char *muxattach)
+Chan*
+mntattach(Chan *c, Chan *ac, char *spec, int flags)
{
Mnt *m;
- Chan *c;
Mntrpc *r;
- struct bogus{
- Chan *chan;
- Chan *authchan;
- char *spec;
- int flags;
- }bogus;
- bogus = *((struct bogus *)muxattach);
- c = bogus.chan;
-
m = c->mux;
-
if(m == nil){
mntversion(c, nil, 0, 0);
m = c->mux;
@@ -331,21 +318,19 @@
nexterror();
}
- r = mntralloc(0, m->msize);
-
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
}
-
r->request.type = Tattach;
r->request.fid = c->fid;
- if(bogus.authchan == nil)
+ if(ac == nil)
r->request.afid = NOFID;
else
- r->request.afid = bogus.authchan->fid;
+ r->request.afid = ac->fid;
r->request.uname = up->user;
- r->request.aname = bogus.spec;
+ r->request.aname = spec;
mountrpc(m, r);
c->qid = r->reply.qid;
@@ -358,12 +343,20 @@
poperror(); /* c */
- if(bogus.flags&MCACHE)
+ if(flags&MCACHE)
c->flag |= CCACHE;
return c;
}
-Chan*
+static Chan*
+noattach(char *s)
+{
+ USED(s);
+ error(Enoattach);
+ return nil;
+}
+
+static Chan*
mntchan(void)
{
Chan *c;
@@ -373,7 +366,7 @@
c->dev = mntalloc.id++;
unlock(&mntalloc.lk);
- if(c->mchan)
+ if(c->mchan != nil)
panic("mntchan non-zero %p", c->mchan);
return c;
}
@@ -401,7 +394,7 @@
alloc = 0;
m = mntchk(c);
- r = mntralloc(c, m->msize);
+ r = mntralloc(c);
if(nc == nil){
nc = devclone(c);
/*
@@ -409,6 +402,7 @@
* Therefore set type to 0 for now; rootclose is known to be safe.
*/
nc->type = 0;
+ nc->flag |= (c->flag & CCACHE);
alloc = 1;
}
wq->clone = nc;
@@ -468,7 +462,7 @@
if(n < BIT16SZ)
error(Eshortstat);
m = mntchk(c);
- r = mntralloc(c, m->msize);
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -477,28 +471,9 @@
r->request.fid = c->fid;
mountrpc(m, r);
-/* r->reply.nstat is 16 bits
- if(r->reply.nstat >= 1<<16)
- error("returned stat buffer count too large");
-*/
-
if(r->reply.nstat > n){
- /*
- * 12/31/2002 RSC
- *
- * This should be nstat-2, which is the first two
- * bytes of the stat buffer. But dirstat and dirfstat
- * depended on getting the full nstat (they didn't
- * add BIT16SZ themselves). I fixed dirstat and dirfstat
- * but am leaving this unchanged for now. After a
- * few months, once enough of the relevant binaries
- * have been recompiled for other reasons, we can
- * change this to nstat-2. Devstat gets this right
- * (via convD2M).
- */
- /* doesn't fit; just patch the count and return */
- PBIT16((uchar*)dp, r->reply.nstat);
n = BIT16SZ;
+ PBIT16((uchar*)dp, r->reply.nstat-2);
}else{
n = r->reply.nstat;
memmove(dp, r->reply.stat, n);
@@ -517,7 +492,7 @@
Mntrpc *r;
m = mntchk(c);
- r = mntralloc(c, m->msize);
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -541,9 +516,6 @@
poperror();
mntfree(r);
- if(c->flag & CCACHE)
- copen(c);
-
return c;
}
@@ -566,12 +538,11 @@
Mntrpc *r;
m = mntchk(c);
- r = mntralloc(c, m->msize);
- if(waserror()){
+ r = mntralloc(c);
+ if(waserror()) {
mntfree(r);
nexterror();
}
-
r->request.type = t;
r->request.fid = c->fid;
mountrpc(m, r);
@@ -582,27 +553,22 @@
void
muxclose(Mnt *m)
{
- Mntrpc *q, *r;
+ Mnt *f, **l;
+ Mntrpc *r;
- for(q = m->queue; q; q = r) {
- r = q->list;
- mntfree(q);
+ while((r = m->queue) != nil){
+ m->queue = r->list;
+ mntfree(r);
}
m->id = 0;
free(m->version);
m->version = nil;
- mntpntfree(m);
-}
+ qfree(m->q);
+ m->q = nil;
-void
-mntpntfree(Mnt *m)
-{
- Mnt *f, **l;
- Queue *q;
-
lock(&mntalloc.lk);
l = &mntalloc.list;
- for(f = *l; f; f = f->list) {
+ for(f = *l; f != nil; f = f->list) {
if(f == m) {
*l = m->list;
break;
@@ -611,10 +577,7 @@
}
m->list = mntalloc.mntfree;
mntalloc.mntfree = m;
- q = m->q;
unlock(&mntalloc.lk);
-
- qfree(q);
}
static void
@@ -636,7 +599,7 @@
Mntrpc *r;
m = mntchk(c);
- r = mntralloc(c, m->msize);
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -655,32 +618,11 @@
mntread(Chan *c, void *buf, long n, vlong off)
{
uchar *p, *e;
- int nc, cache, isdir, dirlen;
+ int dirlen;
- isdir = 0;
- cache = c->flag & CCACHE;
- if(c->qid.type & QTDIR) {
- cache = 0;
- isdir = 1;
- }
-
p = buf;
- if(cache) {
- nc = cread(c, buf, n, off);
- if(nc > 0) {
- n -= nc;
- if(n == 0)
- return nc;
- p += nc;
- off += nc;
- }
- n = mntrdwr(Tread, c, p, n, off);
- cupdate(c, p, n, off);
- return n + nc;
- }
-
- n = mntrdwr(Tread, c, buf, n, off);
- if(isdir) {
+ n = mntrdwr(Tread, c, p, n, off);
+ if(c->qid.type & QTDIR) {
for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
dirlen = BIT16SZ+GBIT16(p);
if(p+dirlen > e)
@@ -700,23 +642,24 @@
return mntrdwr(Twrite, c, buf, n, off);
}
-long
+static long
mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
{
Mnt *m;
Mntrpc *r;
char *uba;
- int cache;
ulong cnt, nr, nreq;
m = mntchk(c);
uba = buf;
cnt = 0;
- cache = c->flag & CCACHE;
- if(c->qid.type & QTDIR)
- cache = 0;
+
for(;;) {
- r = mntralloc(c, m->msize);
+ nreq = n;
+ if(nreq > c->iounit)
+ nreq = c->iounit;
+
+ r = mntralloc(c);
if(waserror()) {
mntfree(r);
nexterror();
@@ -725,23 +668,16 @@
r->request.fid = c->fid;
r->request.offset = off;
r->request.data = uba;
- nr = n;
- if(nr > m->msize-IOHDRSZ)
- nr = m->msize-IOHDRSZ;
- r->request.count = nr;
+ r->request.count = nreq;
mountrpc(m, r);
- nreq = r->request.count;
nr = r->reply.count;
if(nr > nreq)
nr = nreq;
-
if(type == Tread)
- r->b = bl2mem((uchar*)uba, r->b, nr);
- else if(cache)
- cwrite(c, (uchar*)uba, nr, off);
-
- poperror();
+ nr = readblist(r->b, (uchar*)uba, nr, 0);
mntfree(r);
+ poperror();
+
off += nr;
uba += nr;
cnt += nr;
@@ -752,10 +688,9 @@
return cnt;
}
-void
+static void
mountrpc(Mnt *m, Mntrpc *r)
{
- char *sn, *cn;
int t;
r->reply.tag = 0;
@@ -772,14 +707,8 @@
default:
if(t == r->request.type+1)
break;
- sn = "?";
- if(m->c->name != nil)
- sn = m->c->name->s;
- cn = "?";
- if(r->c != nil && r->c->name != nil)
- cn = r->c->name->s;
- print("mnt: proc %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n",
- up->pid, sn, cn,
+ print("mnt: proc %s %lud: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
+ up->text, up->pid, chanpath(m->c), chanpath(r->c),
r, r->request.tag, r->request.fid, r->request.type,
r->reply.type, r->reply.tag);
error(Emountrpc);
@@ -786,22 +715,32 @@
}
}
-void
+static void
mountio(Mnt *m, Mntrpc *r)
{
+ Block *b;
int n;
while(waserror()) {
if(m->rip == up)
mntgate(m);
- if(strcmp(up->errstr, Eintr) != 0){
- mntflushfree(m, r);
+ if(strcmp(up->errstr, Eintr) != 0 || waserror()){
+ r = mntflushfree(m, r);
+ switch(r->request.type){
+ case Tremove:
+ case Tclunk:
+ /* botch, abandon fid */
+ if(strcmp(up->errstr, Ehungup) != 0)
+ r->c->fid = 0;
+ }
nexterror();
}
- r = mntflushalloc(r, m->msize);
+ r = mntflushalloc(r);
+ poperror();
}
lock(&m->lk);
+ r->z = &up->sleep;
r->m = m;
r->list = m->queue;
m->queue = r;
@@ -808,24 +747,30 @@
unlock(&m->lk);
/* Transmit a file system rpc */
- if(m->msize == 0)
- panic("msize");
- n = convS2M(&r->request, r->rpc, m->msize);
- if(n < 0)
- panic("bad message type in mountio");
- if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
+ n = sizeS2M(&r->request);
+ b = allocb(n);
+ if(waserror()){
+ freeb(b);
+ nexterror();
+ }
+ n = convS2M(&r->request, b->wp, n);
+ if(n <= 0 || n > m->msize) {
+ print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
+ up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
error(Emountrpc);
- r->stime = fastticks(nil);
- r->reqlen = n;
+ }
+ b->wp += n;
+ poperror();
+ devtab[m->c->type]->bwrite(m->c, b, 0);
/* Gate readers onto the mount point one at a time */
for(;;) {
lock(&m->lk);
- if(m->rip == 0)
+ if(m->rip == nil)
break;
unlock(&m->lk);
- sleep(&r->r, rpcattn, r);
- if(r->done){
+ sleep(r->z, rpcattn, r);
+ if(r->done) {
poperror();
mntflushfree(m, r);
return;
@@ -850,18 +795,13 @@
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(BLEN(b) == 0){
- freeblist(b);
- return -1;
- }
- qaddlist(m->q, b);
}
return 0;
}
-int
+static int
mntrpcread(Mnt *m, Mntrpc *r)
{
int i, t, len, hlen;
@@ -875,7 +815,7 @@
return -1;
nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
- /* read in the rest of the message, avoid rediculous (for now) message sizes */
+ /* read in the rest of the message, avoid ridiculous (for now) message sizes */
len = GBIT32(nb->rp);
if(len > m->msize){
qdiscard(m->q, qlen(m->q));
@@ -933,49 +873,50 @@
return 0;
}
-void
+static void
mntgate(Mnt *m)
{
Mntrpc *q;
lock(&m->lk);
- m->rip = 0;
- for(q = m->queue; q; q = q->list) {
+ m->rip = nil;
+ for(q = m->queue; q != nil; q = q->list) {
if(q->done == 0)
- if(wakeup(&q->r))
+ if(wakeup(q->z))
break;
}
unlock(&m->lk);
}
-void
+static void
mountmux(Mnt *m, Mntrpc *r)
{
Mntrpc **l, *q;
+ Rendez *z;
lock(&m->lk);
l = &m->queue;
- for(q = *l; q; q = q->list) {
+ for(q = *l; q != nil; q = q->list) {
/* look for a reply to a message */
if(q->request.tag == r->reply.tag) {
*l = q->list;
- if(q != r) {
- /*
- * Completed someone else.
- * Trade pointers to receive buffer.
- */
- q->reply = r->reply;
- q->b = r->b;
- r->b = nil;
+ if(q == r) {
+ q->done = 1;
+ unlock(&m->lk);
+ return;
}
+ /*
+ * Completed someone else.
+ * Trade pointers to receive buffer.
+ */
+ q->reply = r->reply;
+ q->b = r->b;
+ r->b = nil;
+ z = q->z;
+ // coherence();
q->done = 1;
+ wakeup(z);
unlock(&m->lk);
- if(mntstats != 0)
- (*mntstats)(q->request.type,
- m->c, q->stime,
- q->reqlen + r->replen);
- if(q != r)
- wakeup(&q->r);
return;
}
l = &q->list;
@@ -988,13 +929,12 @@
* Create a new flush request and chain the previous
* requests from it
*/
-Mntrpc*
-mntflushalloc(Mntrpc *r, ulong iounit)
+static Mntrpc*
+mntflushalloc(Mntrpc *r)
{
Mntrpc *fr;
- fr = mntralloc(0, iounit);
-
+ fr = mntralloc(r->c);
fr->request.type = Tflush;
if(r->request.type == Tflush)
fr->request.oldtag = r->request.oldtag;
@@ -1010,26 +950,28 @@
* flush and the original message from the unanswered
* request queue. Mark the original message as done
* and if it hasn't been answered set the reply to to
- * Rflush.
+ * Rflush. Return the original rpc.
*/
-void
+static Mntrpc*
mntflushfree(Mnt *m, Mntrpc *r)
{
Mntrpc *fr;
- while(r){
+ while(r != nil){
fr = r->flushed;
if(!r->done){
r->reply.type = Rflush;
mntqrm(m, r);
}
- if(fr)
- mntfree(r);
+ if(fr == nil)
+ break;
+ mntfree(r);
r = fr;
}
+ return r;
}
-int
+static int
alloctag(void)
{
int i, j;
@@ -1037,7 +979,7 @@
for(i = 0; i < NMASK; i++){
v = mntalloc.tagmask[i];
- if(v == ~0)
+ if(v == ~0UL)
continue;
for(j = 0; j < 1<<TAGSHIFT; j++)
if((v & (1<<j)) == 0){
@@ -1049,52 +991,33 @@
return NOTAG;
}
-void
+static void
freetag(int t)
{
mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
}
-Mntrpc*
-mntralloc(Chan *c, ulong msize)
+static Mntrpc*
+mntralloc(Chan *c)
{
Mntrpc *new;
- lock(&mntalloc.lk);
- new = mntalloc.rpcfree;
- if(new == nil){
+ if(mntalloc.nrpcfree == 0) {
+ Alloc:
new = malloc(sizeof(Mntrpc));
+ if(new == nil)
+ exhausted("mount rpc header");
+ lock(&mntalloc.lk);
+ new->request.tag = alloctag();
+ } else {
+ lock(&mntalloc.lk);
+ new = mntalloc.rpcfree;
if(new == nil) {
unlock(&mntalloc.lk);
- exhausted("mount rpc header");
+ goto Alloc;
}
- /*
- * The header is split from the data buffer as
- * mountmux may swap the buffer with another header.
- */
- new->rpc = mallocz(msize, 0);
- if(new->rpc == nil){
- free(new);
- unlock(&mntalloc.lk);
- exhausted("mount rpc buffer");
- }
- new->rpclen = msize;
- new->request.tag = alloctag();
- }
- else {
mntalloc.rpcfree = new->list;
mntalloc.nrpcfree--;
- if(new->rpclen < msize){
- free(new->rpc);
- new->rpc = mallocz(msize, 0);
- if(new->rpc == nil){
- free(new);
- mntalloc.nrpcused--;
- unlock(&mntalloc.lk);
- exhausted("mount rpc buffer");
- }
- new->rpclen = msize;
- }
}
mntalloc.nrpcused++;
unlock(&mntalloc.lk);
@@ -1105,27 +1028,25 @@
return new;
}
-void
+static void
mntfree(Mntrpc *r)
{
- if(r->b != nil)
- freeblist(r->b);
+ freeblist(r->b);
lock(&mntalloc.lk);
- if(mntalloc.nrpcfree >= 10){
- free(r->rpc);
- free(r);
- freetag(r->request.tag);
- }
- else{
+ mntalloc.nrpcused--;
+ if(mntalloc.nrpcfree < 32) {
r->list = mntalloc.rpcfree;
mntalloc.rpcfree = r;
mntalloc.nrpcfree++;
+ unlock(&mntalloc.lk);
+ return;
}
- mntalloc.nrpcused--;
+ freetag(r->request.tag);
unlock(&mntalloc.lk);
+ free(r);
}
-void
+static void
mntqrm(Mnt *m, Mntrpc *r)
{
Mntrpc **l, *f;
@@ -1134,7 +1055,7 @@
r->done = 1;
l = &m->queue;
- for(f = *l; f; f = f->list) {
+ for(f = *l; f != nil; f = f->list) {
if(f == r) {
*l = r->list;
break;
@@ -1144,23 +1065,21 @@
unlock(&m->lk);
}
-Mnt*
+static Mnt*
mntchk(Chan *c)
{
Mnt *m;
/* This routine is mostly vestiges of prior lives; now it's just sanity checking */
-
if(c->mchan == nil)
- panic("mntchk 1: nil mchan c %s\n", chanpath(c));
+ panic("mntchk 1: nil mchan c %s", chanpath(c));
m = c->mchan->mux;
-
if(m == nil)
print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
/*
- * Was it closed and reused (was error(Eshutdown); now, it can't happen)
+ * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
*/
if(m->id == 0 || m->id >= c->dev)
panic("mntchk 3: can't happen");
@@ -1173,7 +1092,7 @@
* reflect local values. These entries are known to be
* the first two in the Dir encoding after the count.
*/
-void
+static void
mntdirfix(uchar *dirbuf, Chan *c)
{
uint r;
@@ -1185,13 +1104,13 @@
PBIT32(dirbuf, c->dev);
}
-int
+static int
rpcattn(void *v)
{
Mntrpc *r;
r = v;
- return r->done || r->m->rip == 0;
+ return r->done || r->m->rip == nil;
}
Dev mntdevtab = {
@@ -1201,7 +1120,7 @@
mntreset,
devinit,
devshutdown,
- mntattach,
+ noattach,
mntwalk,
mntstat,
mntopen,
--- a/kern/fns.h
+++ b/kern/fns.h
@@ -10,7 +10,6 @@
int anyhigher(void);
int anyready(void);
Page* auxpage(void);
-Block* bl2mem(uchar*, Block*, int);
int blocklen(Block*);
void callwithureg(void(*)(Ureg*));
char* chanpath(Chan*);
@@ -27,7 +26,6 @@
void chanrec(Mnt*);
void checkalarms(void);
void checkb(Block*, char*);
-void cinit(void);
Chan* cclone(Chan*);
void cclose(Chan*);
char* clipread(void);
@@ -45,14 +43,10 @@
void confinit1(int);
int consactive(void);
extern void (*consdebug)(void);
-void copen(Chan*);
Block* concatblock(Block*);
Block* copyblock(Block*, int);
void copypage(Page*, Page*);
-int cread(Chan*, uchar*, int, vlong);
void cunmount(Chan*, Chan*);
-void cupdate(Chan*, uchar*, int, vlong);
-void cwrite(Chan*, uchar*, int, vlong);
ulong dbgpc(Proc*);
int decref(Ref*);
int decrypt(void*, void*, int);
@@ -119,7 +113,6 @@
void hzsched(void);
void iallocinit(void);
Block* iallocb(int);
-void iallocsummary(void);
long ibrk(ulong, int);
void ilock(Lock*);
void iunlock(Lock*);
@@ -161,8 +154,6 @@
void* mallocz(ulong, int);
#define malloc kmalloc
void* malloc(ulong);
-void mallocsummary(void);
-Block* mem2bl(uchar*, int);
void mfreeseg(Segment*, ulong, int);
void microdelay(int);
void mkqid(Qid*, vlong, ulong, int);
@@ -238,7 +229,8 @@
void putswap(Page*);
ulong pwait(Waitmsg*);
Label* pwaserror(void);
-void qaddlist(Queue*, Block*);
+long readblist(Block*, uchar *, long, long);
+int qaddlist(Queue*, Block*);
Block* qbread(Queue*, int);
long qbwrite(Queue*, Block*);
Queue* qbypass(void (*)(void*, Block*), void*);
--- a/kern/qio.c
+++ b/kern/qio.c
@@ -10,18 +10,17 @@
static ulong copyblockcnt;
static ulong consumecnt;
static ulong producecnt;
-static ulong qcopycnt;
-static int debugging;
-
#define QDEBUG if(0)
/*
* IO queues
*/
+typedef struct Queue Queue;
+
struct Queue
{
- Lock lk;
+ Lock lk;
Block* bfirst; /* buffer */
Block* blast;
@@ -53,17 +52,6 @@
uint qiomaxatomic = Maxatomic;
-void
-ixsummary(void)
-{
- debugging ^= 1;
- iallocsummary();
- print("pad %lud, concat %lud, pullup %lud, copy %lud\n",
- padblockcnt, concatblockcnt, pullupblockcnt, copyblockcnt);
- print("consume %lud, produce %lud, qcopy %lud\n",
- consumecnt, producecnt, qcopycnt);
-}
-
/*
* free a list of blocks
*/
@@ -72,9 +60,9 @@
{
Block *next;
- for(; b != 0; b = next){
+ for(; b != nil; b = next){
next = b->next;
- b->next = 0;
+ b->next = nil;
freeb(b);
}
}
@@ -88,40 +76,31 @@
int n;
Block *nbp;
- QDEBUG checkb(bp, "padblock 1");
+ QDEBUG checkb(bp, "padblock 0");
if(size >= 0){
if(bp->rp - bp->base >= size){
bp->rp -= size;
return bp;
}
-
- if(bp->next)
- panic("padblock 0x%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)
- panic("padblock 0x%p", getcallerpc(&bp));
-
if(bp->lim - bp->wp >= size)
return bp;
-
n = BLEN(bp);
- padblockcnt++;
- nbp = allocb(size+n);
+ nbp = allocb(n+size);
memmove(nbp->wp, bp->rp, n);
nbp->wp += n;
- freeb(bp);
}
+ nbp->next = bp->next;
+ freeb(bp);
+ padblockcnt++;
QDEBUG checkb(nbp, "padblock 1");
return nbp;
}
@@ -135,7 +114,7 @@
int len;
len = 0;
- while(bp) {
+ while(bp != nil) {
len += BLEN(bp);
bp = bp->next;
}
@@ -151,7 +130,7 @@
int len;
len = 0;
- while(bp) {
+ while(bp != nil) {
len += BALLOC(bp);
bp = bp->next;
}
@@ -159,7 +138,7 @@
}
/*
- * copy the string of blocks into
+ * copy the string of blocks into
* a single block and free the string
*/
Block*
@@ -166,21 +145,12 @@
concatblock(Block *bp)
{
int len;
- Block *nb, *f;
- if(bp->next == 0)
+ if(bp->next == nil)
return bp;
-
- nb = allocb(blocklen(bp));
- for(f = bp; f; f = f->next) {
- len = BLEN(f);
- memmove(nb->wp, f->rp, len);
- nb->wp += len;
- }
- concatblockcnt += BLEN(nb);
- freeblist(bp);
- QDEBUG checkb(nb, "concatblock 1");
- return nb;
+ len = blocklen(bp);
+ concatblockcnt += len;
+ return pullupblock(bp, len);
}
/*
@@ -189,8 +159,8 @@
Block*
pullupblock(Block *bp, int n)
{
- int i;
Block *nbp;
+ int i;
/*
* this should almost always be true, it's
@@ -213,11 +183,11 @@
* copy bytes from the trailing blocks into the first
*/
n -= BLEN(bp);
- while((nbp = bp->next)){
+ 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");
@@ -225,14 +195,14 @@
} else {
/* shouldn't happen but why crash if it does */
if(i < 0){
- print("pullup negative length packet\n");
+ print("pullup negative length packet, called from %#p\n",
+ getcallerpc(&bp));
i = 0;
}
memmove(bp->wp, nbp->rp, i);
- pullupblockcnt++;
bp->wp += i;
bp->next = nbp->next;
- nbp->next = 0;
+ nbp->next = nil;
freeb(nbp);
n -= i;
if(n == 0){
@@ -242,7 +212,7 @@
}
}
freeb(bp);
- return 0;
+ return nil;
}
/*
@@ -295,7 +265,7 @@
bp->wp -= (BLEN(bp) - len);
- if(bp->next) {
+ if(bp->next != nil) {
freeblist(bp->next);
bp->next = nil;
}
@@ -314,7 +284,7 @@
QDEBUG checkb(bp, "copyblock 0");
nbp = allocb(count);
- for(; count > 0 && bp != 0; bp = bp->next){
+ for(; count > 0 && bp != nil; bp = bp->next){
l = BLEN(bp);
if(l > count)
l = count;
@@ -412,11 +382,11 @@
iunlock(&q->lk);
return nil;
}
+ QDEBUG checkb(b, "qget");
q->bfirst = b->next;
- b->next = 0;
+ 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){
@@ -439,7 +409,7 @@
int
qdiscard(Queue *q, int len)
{
- Block *b;
+ Block *b, *tofree = nil;
int dowakeup, n, sofar;
ilock(&q->lk);
@@ -451,10 +421,12 @@
n = BLEN(b);
if(n <= len - sofar){
q->bfirst = b->next;
- b->next = 0;
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;
@@ -483,6 +455,9 @@
if(dowakeup)
wakeup(&q->wr);
+ if(tofree != nil)
+ freeblist(tofree);
+
return sofar;
}
@@ -492,10 +467,9 @@
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->lk);
@@ -502,10 +476,10 @@
for(;;) {
b = q->bfirst;
- if(b == 0){
+ if(b == nil){
q->state |= Qstarve;
- iunlock(&q->lk);
- return -1;
+ len = -1;
+ goto out;
}
QDEBUG checkb(b, "qconsume 1");
@@ -520,10 +494,10 @@
tofree = b;
};
+ consumecnt += n;
if(n < len)
len = n;
memmove(p, b->rp, len);
- consumecnt += n;
b->rp += len;
q->dlen -= len;
@@ -530,7 +504,6 @@
/* discard the block if we're done with it */
if((q->state & Qmsg) || len == n){
q->bfirst = b->next;
- b->next = 0;
q->len -= BALLOC(b);
q->dlen -= BLEN(b);
@@ -539,6 +512,7 @@
tofree = b;
}
+out:
/* if writer flow controlled, restart */
if((q->state & Qflow) && q->len < q->limit/2){
q->state &= ~Qflow;
@@ -560,39 +534,23 @@
int
qpass(Queue *q, Block *b)
{
- int dlen, len, dowakeup;
+ int len, dowakeup;
/* sync with qread */
dowakeup = 0;
ilock(&q->lk);
if(q->len >= q->limit){
- freeblist(b);
iunlock(&q->lk);
+ freeblist(b);
return -1;
}
if(q->state & Qclosed){
- freeblist(b);
iunlock(&q->lk);
- return BALLOC(b);
+ freeblist(b);
+ return 0;
}
- /* add buffer to queue */
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- len = BALLOC(b);
- dlen = BLEN(b);
- QDEBUG checkb(b, "qpass");
- while(b->next){
- 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;
@@ -612,7 +570,7 @@
int
qpassnolim(Queue *q, Block *b)
{
- int dlen, len, dowakeup;
+ int len, dowakeup;
/* sync with qread */
dowakeup = 0;
@@ -619,28 +577,12 @@
ilock(&q->lk);
if(q->state & Qclosed){
- freeblist(b);
iunlock(&q->lk);
- return BALLOC(b);
+ freeblist(b);
+ return 0;
}
- /* add buffer to queue */
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- len = BALLOC(b);
- dlen = BLEN(b);
- QDEBUG checkb(b, "qpass");
- while(b->next){
- 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;
@@ -667,8 +609,7 @@
Block **l, *nbp;
int n;
- for(l = &bp; *l; l = &(*l)->next){
- nbp = *l;
+ for(l = &bp; (nbp = *l) != nil; l = &(*l)->next){
n = BLEN(nbp);
if((n<<2) < BALLOC(nbp)){
*l = allocb(n);
@@ -689,6 +630,10 @@
int dowakeup;
uchar *p = vp;
+ b = iallocb(len);
+ if(b == nil)
+ return 0;
+
/* sync with qread */
dowakeup = 0;
ilock(&q->lk);
@@ -699,25 +644,12 @@
iunlock(&q->lk);
return -1;
}
+ producecnt += len;
/* save in buffer */
- b = iallocb(len);
- if(b == 0){
- iunlock(&q->lk);
- return 0;
- }
memmove(b->wp, p, len);
- producecnt += len;
b->wp += len;
- if(q->bfirst)
- 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;
@@ -740,49 +672,13 @@
Block*
qcopy(Queue *q, int len, ulong offset)
{
- int sofar;
- int n;
- Block *b, *nb;
- uchar *p;
+ Block *b;
- nb = allocb(len);
-
+ b = allocb(len);
ilock(&q->lk);
-
- /* go to offset */
- b = q->bfirst;
- for(sofar = 0; ; sofar += n){
- if(b == nil){
- iunlock(&q->lk);
- 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->lk);
-
- return nb;
+ return b;
}
/*
@@ -794,8 +690,8 @@
Queue *q;
q = malloc(sizeof(Queue));
- if(q == 0)
- return 0;
+ if(q == nil)
+ return nil;
q->limit = q->inilim = limit;
q->kick = kick;
@@ -816,8 +712,8 @@
Queue *q;
q = malloc(sizeof(Queue));
- if(q == 0)
- return 0;
+ if(q == nil)
+ return nil;
q->limit = 0;
q->arg = arg;
@@ -832,7 +728,7 @@
{
Queue *q = a;
- return (q->state & Qclosed) || q->bfirst != 0;
+ return (q->state & Qclosed) || q->bfirst != nil;
}
/*
@@ -864,21 +760,34 @@
}
/*
- * 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)
+ if(q->bfirst != nil)
q->blast->next = b;
else
q->bfirst = b;
- q->len += blockalloclen(b);
- q->dlen += blocklen(b);
- while(b->next)
+
+ 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;
}
/*
@@ -892,77 +801,45 @@
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;
}
/*
* copy the contents of a string of blocks into
- * memory. emptied blocks are freed. return
- * pointer to first unconsumed block.
+ * memory from an offset. blocklist kept unchanged.
+ * return number of copied bytes.
*/
-Block*
-bl2mem(uchar *p, Block *b, int n)
+long
+readblist(Block *b, uchar *p, long n, long o)
{
- int i;
- Block *next;
+ long m, r;
- for(; b != nil; b = next){
- i = BLEN(b);
- if(i > n){
- memmove(p, b->rp, n);
- b->rp += n;
- return b;
+ r = 0;
+ while(n > 0 && b != nil){
+ m = BLEN(b);
+ if(o >= m)
+ o -= m;
+ else {
+ m -= o;
+ if(n < m)
+ m = n;
+ memmove(p, b->rp + o, m);
+ p += m;
+ r += m;
+ n -= m;
+ o = 0;
}
- memmove(p, b->rp, i);
- n -= i;
- p += i;
- b->rp += i;
- next = b->next;
- freeb(b);
+ b = b->next;
}
- return nil;
+ return r;
}
/*
- * 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
*/
@@ -978,6 +855,35 @@
}
/*
+ * 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
*/
@@ -996,7 +902,7 @@
/* wakeup flow controlled writers */
if(dowakeup){
- if(q->kick)
+ if(q->kick != nil)
q->kick(q->arg);
wakeup(&q->wr);
}
@@ -1008,7 +914,7 @@
Block*
qbread(Queue *q, int len)
{
- Block *b, *nb;
+ Block *b;
int n;
qlock(&q->rlock);
@@ -1036,24 +942,21 @@
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;
}
/*
@@ -1063,7 +966,7 @@
long
qread(Queue *q, void *vp, int len)
{
- Block *b, *first, **l;
+ Block *b, *first, **last;
int m, n;
qlock(&q->rlock);
@@ -1088,32 +991,29 @@
}
/* 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;
- if(BLEN(b) <= 0){
+ m = BLEN(b);
+ if(m <= 0){
freeb(qremove(q));
goto again;
}
/* grab the first block plus as many
- * following blocks as will completely
+ * following blocks as will partially
* fit in the read.
*/
n = 0;
- l = &first;
- m = BLEN(b);
for(;;) {
- *l = qremove(q);
- l = &b->next;
+ *last = qremove(q);
n += m;
-
- b = q->bfirst;
- if(b == nil)
+ if(n >= len || q->bfirst == nil)
break;
+ last = &b->next;
+ b = q->bfirst;
m = BLEN(b);
- if(n+m > len)
- break;
}
} else {
first = qremove(q);
@@ -1120,25 +1020,24 @@
n = BLEN(first);
}
- /* copy to user space outside of the ilock */
- iunlock(&q->lk);
- b = bl2mem(vp, first, len);
- ilock(&q->lk);
+ /* 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));
- /* take care of any left over partial block */
- if(b != nil){
- n -= BLEN(b);
- if(q->state & Qmsg)
- freeb(b);
- else
- qputback(q, b);
- }
-
/* 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;
}
@@ -1150,8 +1049,31 @@
return q->len < q->limit || (q->state & Qclosed);
}
-ulong noblockcnt;
+/*
+ * flow control, wait for queue to get below the limit
+ */
+static void
+qflow(Queue *q)
+{
+ for(;;){
+ if(q->noblock || qnotfull(q))
+ break;
+ ilock(&q->lk);
+ q->state |= Qflow;
+ iunlock(&q->lk);
+
+ qlock(&q->wlock);
+ if(waserror()){
+ qunlock(&q->wlock);
+ nexterror();
+ }
+ sleep(&q->wr, qnotfull, q);
+ qunlock(&q->wlock);
+ poperror();
+ }
+}
+
/*
* add a block to a queue obeying flow control
*/
@@ -1158,24 +1080,19 @@
long
qbwrite(Queue *q, Block *b)
{
- int n, dowakeup;
+ int len, dowakeup;
- n = BLEN(b);
-
- if(q->bypass){
+ if(q->bypass != nil){
+ len = blocklen(b);
(*q->bypass)(q->arg, b);
- return n;
+ return len;
}
dowakeup = 0;
- qlock(&q->wlock);
if(waserror()){
- if(b != nil)
- freeb(b);
- qunlock(&q->wlock);
+ freeblist(b);
nexterror();
}
-
ilock(&q->lk);
/* give up if the queue is closed */
@@ -1184,29 +1101,16 @@
error(q->err);
}
- /* if nonblocking, don't queue over the limit */
- if(q->len >= q->limit){
- if(q->noblock){
- iunlock(&q->lk);
- freeb(b);
- noblockcnt += n;
- qunlock(&q->wlock);
- poperror();
- return n;
- }
+ /* don't queue over the limit */
+ if(q->len >= q->limit && q->noblock){
+ iunlock(&q->lk);
+ poperror();
+ len = blocklen(b);
+ freeblist(b);
+ return len;
}
- /* queue the block */
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- q->blast = b;
- b->next = 0;
- q->len += BALLOC(b);
- q->dlen += n;
- QDEBUG checkb(b, "qbwrite");
- b = nil;
+ len = qaddlist(q, b);
/* make sure other end gets awakened */
if(q->state & Qstarve){
@@ -1214,49 +1118,26 @@
dowakeup = 1;
}
iunlock(&q->lk);
+ poperror();
/* get output going again */
- if(q->kick && (dowakeup || (q->state&Qkick)))
+ if(q->kick != nil && (dowakeup || (q->state&Qkick)))
q->kick(q->arg);
/* wakeup anyone consuming at the other end */
- if(dowakeup){
+ if(dowakeup)
wakeup(&q->rr);
- /* if we just wokeup a higher priority process, let it run */
/*
- p = wakeup(&q->rr);
- if(p != nil && p->priority > up->priority)
- sched();
+ * flow control, before allowing the process to continue and
+ * queue more. We do this here so that postnote can only
+ * interrupt us after the data has been queued. This means that
+ * things like 9p flushes and ssl messages will not be disrupted
+ * by software interrupts.
*/
- }
+ qflow(q);
- /*
- * flow control, wait for queue to get below the limit
- * before allowing the process to continue and queue
- * more. We do this here so that postnote can only
- * interrupt us after the data has been queued. This
- * means that things like 9p flushes and ssl messages
- * will not be disrupted by software interrupts.
- *
- * Note - this is moderately dangerous since a process
- * that keeps getting interrupted and rewriting will
- * queue infinite crud.
- */
- for(;;){
- if(q->noblock || qnotfull(q))
- break;
-
- ilock(&q->lk);
- q->state |= Qflow;
- iunlock(&q->lk);
- sleep(&q->wr, qnotfull, q);
- }
- USED(b);
-
- qunlock(&q->wlock);
- poperror();
- return n;
+ return len;
}
/*
@@ -1270,8 +1151,16 @@
uchar *p = vp;
QDEBUG if(!islo())
- print("qwrite hi %p\n", getcallerpc(&q));
+ print("qwrite hi %#p\n", getcallerpc(&q));
+ /* stop queue bloat before allocating blocks */
+ if(q->len/2 >= q->limit && q->noblock == 0 && q->bypass == nil){
+ while(waserror())
+ ;
+ qflow(q);
+ poperror();
+ }
+
sofar = 0;
do {
n = len-sofar;
@@ -1279,7 +1168,6 @@
n = Maxatomic;
b = allocb(n);
- /* setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]); */
if(waserror()){
freeb(b);
nexterror();
@@ -1288,9 +1176,7 @@
poperror();
b->wp += n;
- qbwrite(q, b);
-
- sofar += n;
+ sofar += qbwrite(q, b);
} while(sofar < len && (q->state & Qmsg) == 0);
return len;
@@ -1323,15 +1209,17 @@
ilock(&q->lk);
- QDEBUG checkb(b, "qiwrite");
- if(q->bfirst)
- q->blast->next = b;
- else
- q->bfirst = b;
- q->blast = b;
- q->len += BALLOC(b);
- q->dlen += n;
+ /* we use an artificially high limit for kernel prints since anything
+ * over the limit gets dropped
+ */
+ if((q->state & Qclosed) != 0 || q->len/2 >= q->limit){
+ iunlock(&q->lk);
+ freeb(b);
+ break;
+ }
+ qaddlist(q, b);
+
if(q->state & Qstarve){
q->state &= ~Qstarve;
dowakeup = 1;
@@ -1340,7 +1228,7 @@
iunlock(&q->lk);
if(dowakeup){
- if(q->kick)
+ if(q->kick != nil)
q->kick(q->arg);
wakeup(&q->rr);
}
@@ -1378,9 +1266,9 @@
ilock(&q->lk);
q->state |= Qclosed;
q->state &= ~(Qflow|Qstarve);
- strcpy(q->err, Ehungup);
+ kstrcpy(q->err, Ehungup, ERRMAX);
bfirst = q->bfirst;
- q->bfirst = 0;
+ q->bfirst = nil;
q->len = 0;
q->dlen = 0;
q->noblock = 0;
@@ -1404,10 +1292,9 @@
/* mark it */
ilock(&q->lk);
q->state |= Qclosed;
- if(msg == 0 || *msg == 0)
- strcpy(q->err, Ehungup);
- else
- strncpy(q->err, msg, ERRMAX-1);
+ if(msg == nil || *msg == '\0')
+ msg = Ehungup;
+ kstrcpy(q->err, msg, ERRMAX);
iunlock(&q->lk);
/* wake up readers/writers */
@@ -1467,7 +1354,7 @@
int
qcanread(Queue *q)
{
- return q->bfirst!=0;
+ return q->bfirst != nil;
}
/*
@@ -1499,7 +1386,7 @@
/* mark it */
ilock(&q->lk);
bfirst = q->bfirst;
- q->bfirst = 0;
+ q->bfirst = nil;
q->len = 0;
q->dlen = 0;
iunlock(&q->lk);
@@ -1507,7 +1394,7 @@
/* free queued blocks */
freeblist(bfirst);
- /* wake up readers/writers */
+ /* wake up writers */
wakeup(&q->wr);
}
@@ -1515,10 +1402,4 @@
qfull(Queue *q)
{
return q->state & Qflow;
-}
-
-int
-qstate(Queue *q)
-{
- return q->state;
}