~kris/9p

9hist

7006c7f6676db78ea02e086c5c5713fc1bcaadd9 — David du Colombier 33 years ago fa7da55
Plan 9 from Bell Labs 1993-05-25
8 files changed, 610 insertions(+), 109 deletions(-)

M boot/boot.c
M port/dev.c
A port/netif.c
A port/netif.h
M port/portdat.h
M port/portfns.h
M port/stream.c
M port/taslock.c
M boot/boot.c => boot/boot.c +48 -1
@@ 25,6 25,51 @@ static void	recover(Method*);
static Method	*rootserver(char*);

void
ethertest(void)
{
	int cf, df, n, t;
	char buf[64];
	struct Etherpkt
	{
		uchar	d[6];
		uchar	s[6];
		uchar	type[2];
	} p;

	cf = open("#l/ether/clone", ORDWR);
	if(cf < 0){
		print("can't open #l/ether/clone: %r\n");
		exits(0);
	}
	n = read(cf, buf, 12);
	if(n < 0){
		print("can't read #l/ether/clone: %r\n");
		exits(0);
	}
	buf[n] = 0;
	sprint(buf, "#l/ether/%d/data", atoi(buf));
	df = open(buf, ORDWR);
	if(df < 0){
		print("can't open %s: %r\n", buf);
		exits(0);
	}
	if(write(cf, "connect -1", sizeof("connect -1")-1) < 0){
		print("can't connect -1: %r\n");
		exits(0);
	}
	close(cf);
	for(;;){
		n = read(df, &p, sizeof(p));
		if(n <= 0){
			print("read returns %d: %r\n", n);
			continue;
		}
		t = (p.type[0]<<8) | p.type[1];
		print("%d %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux -> %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux %ux\n", n, p.s[0], p.s[1], p.s[2], p.s[3], p.s[4], p.s[5], p.d[0], p.d[1], p.d[2], p.d[3], p.d[4], p.d[5], t);
	}
}

void
boot(int argc, char *argv[])
{
	int fd;


@@ 38,11 83,13 @@ boot(int argc, char *argv[])
	open("#c/cons", OREAD);
	open("#c/cons", OWRITE);
	open("#c/cons", OWRITE);
/*	print("argc=%d\n", argc);
	print("argc=%d\n", argc);
	for(fd = 0; fd < argc; fd++)
		print("%s ", argv[fd]);
	print("\n");/**/

	ethertest();

	if(argc <= 1)
		pflag = 1;


M port/dev.c => port/dev.c +1 -1
@@ 149,7 149,7 @@ devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen)
		 *  by namec.
		 */
			if(c->qid.path & CHDIR){
				devdir(c, c->qid, c->path->elem, i*DIRLEN, eve, CHDIR|0700, &dir);
				devdir(c, c->qid, c->path->elem, i*DIRLEN, eve, CHDIR|0555, &dir);
				convD2M(&dir, db);
				return;
			}

A port/netif.c => port/netif.c +378 -0
@@ 0,0 1,378 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"
#include	"../port/netif.h"

uchar etherbcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

static int netown(Netfile*, char*, int);
static int openfile(Netif*, int);
static char* matchtoken(char*, char*);

/*
 *  set up a new network interface
 */
void
netifinit(Netif *nif, char *name, int nfile, ulong limit)
{
	nif->name = name;
	nif->nfile = nfile;
	nif->f = xalloc(nfile*sizeof(Netfile*));
	memset(nif->f, 0, nfile*sizeof(Netfile*));
	nif->limit = limit;
	nif->out = qopen(limit, 0, 0);
}

/*
 *  generate a 3 level directory
 */
static int
netifgen(Chan *c, void *vp, int ntab, int i, Dir *dp)
{
	Qid q;
	char buf[32];
	Netif *nif = vp;
	Netfile *f;
	int t;
	int perm;
	char *o;

	USED(ntab);
	q.vers = 0;

	/* top level directory contains the name of the network */
	if(c->qid.path == CHDIR){
		switch(i){
		case 0:
			q.path = CHDIR | N2ndqid;
			strcpy(buf, nif->name);
			devdir(c, q, buf, 0, eve, 0555, dp);
			break;
		default:
			return -1;
		}
		return 1;
	}

	/* second level contains clone plus all the conversations */
	t = NETTYPE(c->qid.path);
	if(t == N2ndqid || t == Ncloneqid){
		if(i == 0){
			q.path = Ncloneqid;
			devdir(c, q, "clone", 0, eve, 0666, dp);
		}else if(i <= nif->nfile){
			if(nif->f[i-1] == 0)
				return 0;
			q.path = CHDIR|NETQID(i-1, N3rdqid);
			sprint(buf, "%d", i-1);
			devdir(c, q, buf, 0, eve, 0555, dp);
		}else
			return -1;
		return 1;
	}

	/* third level */
	f = nif->f[NETID(c->qid.path)];
	if(f == 0)
		return 0;
	if(*f->owner){
		o = f->owner;
		perm = f->mode;
	} else {
		o = eve;
		perm = 0666;
	}
	switch(i){
	case 0:
		q.path = NETQID(NETID(c->qid.path), Ndataqid);
		devdir(c, q, "data", 0, o, perm, dp);
		break;
	case 1:
		q.path = NETQID(NETID(c->qid.path), Nctlqid);
		devdir(c, q, "ctl", 0, o, perm, dp);
		break;
	case 2:
		q.path = NETQID(NETID(c->qid.path), Nstatqid);
		devdir(c, q, "stat", 0, eve, 0444, dp);
		break;
	case 3:
		q.path = NETQID(NETID(c->qid.path), Ntypeqid);
		devdir(c, q, "type", 0, eve, 0444, dp);
		break;
	default:
		return -1;
	}
	return 1;
}

int
netifwalk(Netif *nif, Chan *c, char *name)
{
	return devwalk(c, name, (Dirtab *)nif, 0, netifgen);
}

Chan*
netifopen(Netif *nif, Chan *c, int omode)
{
	int id = 0;
	Netfile *f;

	if(c->qid.path & CHDIR){
		if(omode != OREAD)
			error(Eperm);
	} else {
		switch(NETTYPE(c->qid.path)){
		case Ndataqid:
		case Nctlqid:
			id = NETID(c->qid.path);
			openfile(nif, id);
			break;
		case Ncloneqid:
			id = openfile(nif, -1);
			c->qid.path = NETQID(id, Nctlqid);
			ptclone(c, 0, id);
			break;
		default:
			if(omode != OREAD)
				error(Ebadarg);
		}
		switch(NETTYPE(c->qid.path)){
		case Ndataqid:
		case Nctlqid:
			f = nif->f[id];
			if(netown(f, up->user, omode&7) < 0)
				error(Eperm);
			break;
		}
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

long
netifread(Netif *nif, Chan *c, void *a, long n, ulong offset)
{
	Netfile *f;
	int i;
	char buf[256];

	if(c->qid.path&CHDIR)
		return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);

	switch(NETTYPE(c->qid.path)){
	case Ndataqid:
		f = nif->f[NETID(c->qid.path)];
		return qread(f->in, a, n);
	case Nctlqid:
		return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
	case Nstatqid:
		n = sprint(buf, "in: %d\n", nif->inpackets);
		n += sprint(buf+n, "out: %d\n", nif->outpackets);
		n += sprint(buf+n, "crc errs: %d\n", nif->crcs);
		n += sprint(buf+n, "overflows: %d\n", nif->overflows);
		n += sprint(buf+n, "framing errs: %d\n", nif->frames);
		n += sprint(buf+n, "buffer errs: %d\n", nif->buffs);
		n += sprint(buf+n, "output errs: %d\n", nif->oerrs);
		n += sprint(buf+n, "addr:", nif->oerrs);
		for(i = 0; i < nif->alen; i++)
			n += sprint(buf+n, "%2.2ux", nif->addr[i]);
		n += sprint(buf+n, "\n");
		return readstr(offset, a, n, buf);
	case Ntypeqid:
		f = nif->f[NETID(c->qid.path)];
		return readnum(offset, a, n, f->type, NUMSIZE);
	}
	error(Ebadarg);
	return -1;	/* not reached */
}

/*
 *  the devxxx.c that calls us handles writing data, it knows best
 */
long
netifwrite(Netif *nif, Chan *c, void *a, long n)
{
	Netfile *f;
	char *p;
	char buf[256];

	if(NETTYPE(c->qid.path) != Nctlqid)
		error(Eperm);

	if(n >= sizeof(buf))
		n = sizeof(buf)-1;
	memmove(buf, a, n);
	buf[n] = 0;

	qlock(nif);
	f = nif->f[NETID(c->qid.path)];
	if(p = matchtoken(buf, "connect")){
		f->type = atoi(p);
	} else if(matchtoken(buf, "promiscuous")){
		f->prom = 1;
		nif->prom++;
		if(nif->prom == 1)
			(*nif->promiscuous)(nif->arg, 1);
	}
	qunlock(nif);
	return n;
}

void
netifwstat(Netif *nif, Chan *c, char *db)
{
	Dir dir;
	Netfile *f;

	f = nif->f[NETID(c->qid.path)];
	if(f == 0)
		error(Enonexist);

	if(netown(f, up->user, OWRITE) < 0)
		error(Eperm);

	convM2D(db, &dir);
	strncpy(f->owner, dir.uid, NAMELEN);
	f->mode = dir.mode;
}

void
netifstat(Netif *nif, Chan *c, char *db)
{

	devstat(c, db, (Dirtab *)nif, 0, netifgen);
}

void
netifclose(Netif *nif, Chan *c)
{
	Netfile *f;
	int t;

	t = NETTYPE(c->qid.path);
	if(t != Ndataqid && t != Nctlqid)
		return;

	f = nif->f[NETID(c->qid.path)];
	qlock(f);
	if(--(f->inuse) == 0){
		if(f->prom){
			qlock(nif);
			if(--(nif->prom) == 0)
				(*nif->promiscuous)(nif->arg, 0);
			qunlock(nif);
		}
		f->owner[0] = 0;
	}
	qunlock(f);
}

Lock netlock;

static int
netown(Netfile *p, char *o, int omode)
{
	static int access[] = { 0400, 0200, 0600, 0100 };
	int mode;
	int t;

	lock(&netlock);
	if(*p->owner){
		if(strncmp(o, p->owner, NAMELEN) == 0)	/* User */
			mode = p->mode;
		else if(strncmp(o, eve, NAMELEN) == 0)	/* Bootes is group */
			mode = p->mode<<3;
		else
			mode = p->mode<<6;		/* Other */

		t = access[omode&3];
		if((t & mode) == t){
			unlock(&netlock);
			return 0;
		} else {
			unlock(&netlock);
			return -1;
		}
	}
	strncpy(p->owner, o, NAMELEN);
	p->mode = 0660;
	unlock(&netlock);
	return 0;
}

/*
 *  Increment the reference count of a network device.
 *  If id < 0, return an unused ether device.
 */
static int
openfile(Netif *nif, int id)
{
	Netfile *f, **fp, **efp;

	if(id >= 0){
		f = nif->f[id];
		if(f == 0)
			error(Enodev);
		qlock(f);
		f->inuse++;
		qunlock(f);
		return id;
	}

	qlock(nif);
	efp = &nif->f[nif->nfile];
	for(fp = nif->f; fp < efp; fp++){
		f = *fp;
		if(f == 0){
			f = malloc(sizeof(Netfile));
			if(f == 0){
				qunlock(nif);
				error(Enodev);
			}
			*fp = f;
			f->in = qopen(nif->limit, 0, 0);
			qlock(f);
		} else {
			qlock(f);
			if(f->inuse){
				qunlock(f);
				continue;
			}
		}
		f->inuse = 1;
		netown(f, up->user, 0);
		qunlock(f);
		qunlock(nif);
		return fp - nif->f;
	}
	qunlock(nif);
	error(Enodev);
	return -1;	/* not reached */
}

/*
 *  look for a token starting a string, return a pointer to first non-space char after it
 */
static char*
matchtoken(char *p, char *token)
{
	int n;

	n = strlen(token);
	if(strncmp(p, token, n))
		return 0;
	p += n;
	if(*p == 0)
		return p;
	if(*p != ' ' && *p != '\t' && *p != '\n')
		return 0;
	while(*p == ' ' || *p == '\t' || *p == '\n')
		p++;
	return p;
}

A port/netif.h => port/netif.h +109 -0
@@ 0,0 1,109 @@
typedef struct Etherpkt	Etherpkt;
typedef struct Netfile	Netfile;
typedef struct Netif	Netif;

enum
{
	Nmaxaddr=	64,

	Ncloneqid=	1,
	N2ndqid,
	N3rdqid,
	Ndataqid,
	Nctlqid,
	Nstatqid,
	Ntypeqid,
};

/*
 *  Macros to manage Qid's used for multiplexed devices
 */
#define NETTYPE(x)	((x)&0x1f)
#define NETID(x)	(((x)&~CHDIR)>>5)
#define NETQID(i,t)	(((i)<<5)|(t))

/*
 *  one per multiplexed connection
 */
struct Netfile
{
	QLock;

	int	inuse;
	ulong	mode;
	char	owner[NAMELEN];

	int	type;		/* multiplexor type */
	int	prom;		/* promiscuous mode */

	Queue	*in;		/* input buffer */
};

/*
 *  a network interface
 */
struct Netif
{
	QLock;

	/* multiplexing */
	char	*name;			/* for top level directory */
	int	nfile;			/* max number of Netfiles */
	Netfile	**f;
	Queue	*out;			/* output buffer */

	/* about net */
	int	limit;			/* flow control */
	int	alen;			/* address length */
	uchar	addr[Nmaxaddr];
	uchar	bcast[Nmaxaddr];
	int	prom;

	/* statistics */
	int	misses;
	int	inpackets;
	int	outpackets;
	int	crcs;		/* input crc errors */
	int	oerrs;		/* output erros */
	int	frames;		/* framing errors */
	int	overflows;	/* packet overflows */
	int	buffs;		/* buffering errors */

	/* routines for touching the hardware */
	void	*arg;
	void	(*promiscuous)(void*, int);
};

void	netifinit(Netif*, char*, int, ulong);
int	netifwalk(Netif*, Chan*, char*);
Chan*	netifopen(Netif*, Chan*, int);
void	netifclose(Netif*, Chan*);
long	netifread(Netif*, Chan*, void*, long, ulong);
long	netifwrite(Netif*, Chan*, void*, long);
void	netifwstat(Netif*, Chan*, char*);
void	netifstat(Netif*, Chan*, char*);

/*
 *  Ethernet specific
 */
enum
{
	Eaddrlen=	6,
	ETHERMINTU =	60,		/* minimum transmit size */
	ETHERMAXTU =	1514,		/* maximum transmit size */
	ETHERHDRSIZE =	14,		/* size of an ethernet header */
};

struct Etherpkt
{
	uchar	d[Eaddrlen];
	uchar	s[Eaddrlen];
	uchar	type[2];
	uchar	data[1500];
};

extern uchar etherbcast[6];

/*
 *  FDDI specific
 */

M port/portdat.h => port/portdat.h +1 -47
@@ 16,9 16,6 @@ typedef struct Mntrpc	Mntrpc;
typedef struct Mntwalk	Mntwalk;
typedef struct Mnt	Mnt;
typedef struct Mhead	Mhead;
typedef struct Netinf	Netinf;
typedef struct Netprot	Netprot;
typedef struct Network	Network;
typedef struct Note	Note;
typedef struct Page	Page;
typedef struct Path	Path;


@@ 678,53 675,10 @@ struct Queue
enum
{
	Qstarve=1,	/* consumer starved */
	Qmsg=1,		/* message oriented */
};
#define BLEN(b)		((b)->wp - (b)->rp)

/*
 *  Macros to manage Qid's used for multiplexed devices
 */
#define NETTYPE(x)	((x)&0x1f)
#define NETID(x)	(((x)&~CHDIR)>>5)
#define NETQID(i,t)	(((i)<<5)|(t))
enum
{
	Nhighqid	= NETQID(1,0) - 1,
	Ndataqid	= Nhighqid,
	Nctlqid		= Ndataqid-1,
	Nlowqid		= Nctlqid,
};

/*
 *  a multiplexed network
 */
struct Netprot
{
	int	id;
	Netprot	*next;		/* linked list of protections */
	ulong	mode;
	char	owner[NAMELEN];
	Network	*net;
};

struct Netinf
{
	char	*name;
	void	(*fill)(Netprot*, char*, int);
};

struct Network
{
	Lock;
	char	*name;
	int	nconv;			/* max # of conversations */
	int	(*listen)(Netprot*);
	int	(*open)(Netprot*, int);
	int	ninfo;
	Netinf	info[5];
	Netprot	*prot;			/* linked list of protections */
	void	*ptr;
};

enum
{

M port/portfns.h => port/portfns.h +3 -12
@@ 127,15 127,6 @@ void		mousescreenupdate(void);
int		msize(void*);
Chan*		namec(char*, int, int, ulong);
void		nameok(char*);
void		netdisown(Netprot*);
int		netgen(Chan*, void*, int, int, Dir*);
Chan*		netopen(Chan*, int, Network*);
int		netown(Netprot*, char*, int);
void		netadd(Network*, Netprot*, int);
long		netread(Chan*, void*, long, ulong, Network*);
void		netstat(Chan*, char*, Network*);
int		netwalk(Chan*, char*, Network*);
void		netwstat(Chan*, char*, Network*);
Chan*		newchan(void);
Mount*		newmount(Mhead*, Chan*, int, char*);
Page*		newpage(int, Segment **, ulong);


@@ 178,10 169,10 @@ void		putstr(char*);
void		putstrn(char*, long);
void		putswap(Page*);
ulong		pwait(Waitmsg*);
int		qconsume(Queue*, uchar*, int, int);
int		qconsume(Queue*, uchar*, int);
void		qlock(QLock*);
Queue*		qopen(int);
int		qproduce(Queue*, uchar*, int, int);
Queue*		qopen(int, void (*)(void*), void*);
int		qproduce(Queue*, uchar*, int);
long		qread(Queue*, char*, int, int);
void		qunlock(QLock*);
long		qwrite(Queue*, char*, int);

M port/stream.c => port/stream.c +69 -46
@@ 1,3 1,4 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"


@@ 19,19 20,20 @@ struct Chunk
	Chunk	*next;
};

struct Alloc
struct Chunkl
{
	Lock;
	Chunk	*first;
	int	had;
	int	have;
	int	goal;
	int	last;
	int	hist;
};

struct Arena
{
	Chunkl	alloc[Maxpow-Minpow+1];
	Chunkl	alloc[Maxpow+1];
	Chunkl	freed;
	Rendez r;
};

static Arena arena;


@@ 48,17 50,17 @@ iallockproc(void *arg)

	USED(arg);
	for(;;){
		tsleep(&freed->r, return0, 0, 500);
		tsleep(&arena.r, return0, 0, 500);

		/* really free what was freed at interrupt level */
		cl = &arena.freed;
		if(cl->first){
			x = slphi();
			x = splhi();
			lock(cl);
			first = cl->first;
			cl->first = 0;
			unlock(cl);
			spllo();
			splx(x);
	
			for(; first; first = p){
				p = first->next;


@@ 69,10 71,18 @@ iallockproc(void *arg)
		/* make sure we have blocks available for interrupt level */
		for(pow = Minpow; pow <= Maxpow; pow++){
			cl = &arena.alloc[pow];

			/*
			 *  if we've been ahead of the game for a while
			 *  start giving blocks back to the general pool
			 */
			if(cl->have >= cl->goal){
				cl->had = cl->have;
				cl->hist = ((cl->hist<<1) | 1) & 0xff;
				if(cl->hist == 0xff && cl->goal > 8)
					cl->goal--;
				continue;
			}
			} else
				cl->hist <<= 1;

			/*
			 *  increase goal if we've been drained, decrease


@@ 80,13 90,8 @@ iallockproc(void *arg)
			 */
			if(cl->have == 0)
				cl->goal += cl->goal>>2;
			else {
				x = cl->goal/2;
				if(cl->goal > 4 && cl->had > x && cl->have > x)
					cl->goal--;
			}

			cl->had = cl->have;
			first = 0;
			l = &first;
			for(i = x = cl->goal - cl->have; x > 0; x--){
				p = malloc(1<<pow);


@@ 102,7 107,7 @@ iallockproc(void *arg)
				cl->first = first;
				cl->have += i;
				unlock(cl);
				spllo(x);
				splx(x);
			}
		}
	}


@@ 130,7 135,7 @@ ialloc(int size)
	Chunkl *cl;
	Chunk *p;

	for(pow = Min; pow <= Maxpow; pow++)
	for(pow = Minpow; pow <= Maxpow; pow++)
		if(size <= (1<<pow)){
			cl = &arena.alloc[pow];
			lock(cl);


@@ 143,6 148,7 @@ ialloc(int size)
			return (void*)p;
		}
	panic("ialloc %d\n", size);
	return 0;			/* not reached */
}

void


@@ 183,7 189,7 @@ allocb(int size)
 *  set, any bytes left in a block afer a consume are discarded.
 */
int
consume(Queue *q, uchar *p, int len, int drop)
qconsume(Queue *q, uchar *p, int len)
{
	Block *b;
	int n;


@@ 199,28 205,29 @@ consume(Queue *q, uchar *p, int len, int drop)
	if(n < len)
		len = n;
	memmove(p, b->rp, len);
	if(drop || len == n)
	if((q->state&Qmsg) || len == n)
		q->bfirst = b->next;
	else
		b->rp += len;
	q->len -= len;

	/* wakeup flow controlled writers */
	if(q->len+len >= q->limit && q->len < q->limit)
	/* wakeup flow controlled writers (with a bit of histeresis) */
	if(q->len+len >= q->limit && q->len < q->limit/2)
		wakeup(&q->r);

	unlock(q);

	if(drop || len == n)
	if((q->state&Qmsg) || len == n)
		ifree(b);

	return len;
}

int
produce(Queue *q, uchar *p, int len, int append)
qproduce(Queue *q, uchar *p, int len)
{
	Block *b;
	int n;

	lock(q);
	b = q->rfirst;


@@ 237,17 244,23 @@ produce(Queue *q, uchar *p, int len, int append)
		return len;
	}

	/* no waiting receivers, buffer */
	if(q->len >= q->limit)
	/* no waiting receivers, room in buffer? */
	if(q->len >= q->limit){
		unlock(q);
		return -1;
	b = q->first;
	if(append && b && b->lim-b->wp <= len){
	}

	/* save in buffer */
	b = q->bfirst;
	if((q->state&Qmsg)==0 && b && b->lim-b->wp <= len){
		memmove(b->wp, p, len);
		b->wp += len;
	} else {
		b = ialloc(sizeof(Block)+len);
		if(b == 0)
		if(b == 0){
			unlock(q);
			return -1;
		}
		b->base = (uchar*)(b+1);
		b->rp = b->base;
		b->wp = b->lim = b->base + len;


@@ 256,7 269,7 @@ produce(Queue *q, uchar *p, int len, int append)
			q->blast->next = b;
		else
			q->bfirst = b;
		q->last = b;
		q->blast = b;
	}
	q->len += len;
	unlock(q);


@@ 277,6 290,9 @@ qopen(int limit, void (*kick)(void*), void *arg)
	q->limit = limit;
	q->kick = kick;
	q->arg = arg;
	q->state = Qmsg;

	return q;
}

static int


@@ 288,12 304,12 @@ bfilled(void *a)
}

long
qread(Queue *q, char *p, int len, int drop)
qread(Queue *q, char *p, int len)
{
	Block *b, *bb;
	int x, n;

	/* ... to be replaced by a mapping */
	/* ... to be replaced by a kmapping if need be */
	b = allocb(len);

	x = splhi();


@@ 311,24 327,31 @@ qread(Queue *q, char *p, int len, int drop)
		sleep(&b->r, bfilled, b);
		n = BLEN(b);
		memmove(p, b->rp, n);
		free(b);
		return n;
	}

	/* grab a block from the buffer */
	n = BLEN(b);
	if(drop || n <= len){
		q->bfirst = b->next;
		q->len -= n;
		unlock(q);
		slpx(x);
		memmove(p, b->rp, n);
	} else {
	/* copy from a buffered block */
	q->bfirst = bb->next;
	n = BLEN(bb);
	if(n > len)
		n = len;
		q->len -= n;
		memmove(p, b->rp, n);
		b->rp += n;
	q->len -= n;
	unlock(q);
	splx(x);
	memmove(p, bb->rp, n);
	bb->rp += n;

	/* free it or put it back */
	if(drop || bb->rp == bb->wp)
		free(bb);
	else {
		x = splhi();
		lock(q);
		bb->next = q->bfirst;
		q->bfirst = bb;
		unlock(q);
		slpx(x);
		splx(x);
	}
	free(b);
	return n;


@@ 346,7 369,7 @@ long
qwrite(Queue *q, char *p, int len)
{
	Block *b;
	int x, n;
	int x;

	b = allocb(len);
	memmove(b->rp, p, len);


@@ 368,7 391,7 @@ qwrite(Queue *q, char *p, int len)
	q->blast = b;
	q->len += len;
	if((q->state & Qstarve) && q->kick){
		q->stat &= ~Qstarve;
		q->state &= ~Qstarve;
		(*q->kick)(q->arg);
	}
	unlock(q);

M port/taslock.c => port/taslock.c +1 -2
@@ 19,9 19,8 @@ lock(Lock *l)
			return;
		}
	}
	l->key = 0;
	panic("lock loop 0x%lux key 0x%lux pc 0x%lux held by pc 0x%lux\n",
			l->key, i, pc, l->pc);
			i, l->key, pc, l->pc);
}

int