Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/devmnt.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/devmnt.c 1990/0227
## diff -e /dev/null /n/bootesdump/1990/0227/sys/src/9/mips/devmnt.c
0a
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"

#include	"devtab.h"

#include	"fcall.h"

/*
 * Easy version: multiple sessions but no intra-session multiplexing, copy the data
 */

typedef struct Mnt	Mnt;
struct Mnt
{
	Ref;			/* for number of chans, incl. mntpt but not msg */
	QLock;			/* for access */
	Chan	*msg;		/* for reading and writing messages */
	Chan	*mntpt;		/* channel in user's name space */
};

#define	BUFSIZE	(MAXFDATA+500) 	/* BUG */
typedef struct Mntbuf Mntbuf;
struct Mntbuf
{
	Mntbuf	*next;
	char	buf[BUFSIZE];
};

struct
{
	Lock;
	Mntbuf	*free;
}mntbufalloc;

typedef struct Mnthdr Mnthdr;
struct Mnthdr		/* next only meaningful when buffer isn't being used */
{
	Mnthdr	*next;
	Fcall	thdr;
	Fcall	rhdr;
};

struct
{
	Lock;
	Mnthdr	*free;
}mnthdralloc;

Mnt	*mnt;
void	mntxmit(Mnt*, Mnthdr*);

Mntbuf*
mballoc(void)
{
	Mntbuf *mb;

loop:
	lock(&mntbufalloc);
	if(mb = mntbufalloc.free){		/* assign = */
		mntbufalloc.free = mb->next;
		unlock(&mntbufalloc);
		return mb;
	}
	unlock(&mntbufalloc);
	print("no mntbufs\n");
	if(u == 0)
		panic("mballoc");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
}

void
mbfree(Mntbuf *mb)
{
	lock(&mntbufalloc);
	mb->next = mntbufalloc.free;
	mntbufalloc.free = mb;
	unlock(&mntbufalloc);
}

Mnthdr*
mhalloc(void)
{
	Mnthdr *mh;

loop:
	lock(&mnthdralloc);
	if(mh = mnthdralloc.free){		/* assign = */
		mnthdralloc.free = mh->next;
		unlock(&mnthdralloc);
		return mh;
	}
	unlock(&mnthdralloc);
	print("no mnthdrs\n");
	if(u == 0)
		panic("mballoc");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
}

void
mhfree(Mnthdr *mh)
{
	lock(&mnthdralloc);
	mh->next = mnthdralloc.free;
	mnthdralloc.free = mh;
	unlock(&mnthdralloc);
}

Mnt*
mntdev(int dev, int noerr)
{
	Mnt *m;

	if(dev<0 || conf.nmntdev<=dev){
		if(noerr)
			return 0;
		panic("mntdev out of range");
	}
	m = &mnt[dev];
	if(m->msg == 0){
		if(noerr)
			return 0;
		error(0, Eshutdown);
	}
	return m;
}

void
mntreset(void)
{
	int i;
	Mntbuf *mb;
	Mnthdr *mh;

	mnt = ialloc(conf.nmntdev*sizeof(Mnt), 0);

	mb = ialloc(conf.nmntbuf*sizeof(Mntbuf), 0);
	for(i=0; i<conf.nmntbuf-1; i++)
		mb[i].next = &mb[i+1];
	mb[i].next = 0;
	mntbufalloc.free = mb;

	mh = ialloc(conf.nmnthdr*sizeof(Mnthdr), 0);
	for(i=0; i<conf.nmnthdr-1; i++)
		mh[i].next = &mh[i+1];
	mh[i].next = 0;
	mnthdralloc.free = mh;
}

void
mntinit(void)
{
}

Chan*
mntattach(char *spec)
{
	int i;
	Mnt *m;
	Mnthdr *mh;
	Chan *c, *cm;
	struct bogus{
		Chan	*chan;
		char	*spec;
	}bogus;

	bogus = *((struct bogus *)spec);
	spec = bogus.spec;

	m = mnt;
	for(i=0; i<conf.nmntdev; i++,m++){
		lock(m);
		if(m->ref == 0)
			goto Found;
		unlock(m);
	}
	error(0, Enomntdev);
    Found:
	m->ref = 1;
	unlock(m);
	c = devattach('M', spec);
	c->dev = m - mnt;
	m->mntpt = c;
	cm = bogus.chan;
	m->msg = cm;
	incref(cm);
	mh = mhalloc();
	if(waserror()){
		mhfree(mh);
		close(c);
		nexterror();
	}
	mh->thdr.type = Tattach;
	mh->thdr.fid = c->fid;
	memcpy(mh->thdr.uname, u->p->pgrp->user, NAMELEN);
	strcpy(mh->thdr.aname, spec);
	mntxmit(m, mh);
	c->qid = mh->rhdr.qid;
	mhfree(mh);
	poperror();
	return c;
}

Chan*
mntclone(Chan *c, Chan *nc)
{
	Mnt *m;
	Mnthdr *mh;
	int new;

	new = 0;
	if(nc == 0){
		nc = newchan();
		new = 1;
		if(waserror()){
			close(nc);
			nexterror();
		}
	}
	m = mntdev(c->dev, 0);
	mh = mhalloc();
	if(waserror()){
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = Tclone;
	mh->thdr.fid = c->fid;
	mh->thdr.newfid = nc->fid;
	mntxmit(m, mh);
	nc->type = c->type;
	nc->dev = c->dev;
	nc->qid = c->qid;
	nc->mode = c->mode;
	nc->flag = c->flag;
	nc->offset = c->offset;
	nc->mnt = c->mnt;
	if(new)
		poperror();
	mhfree(mh);
	poperror();
	incref(m);
	return nc;
}

int	 
mntwalk(Chan *c, char *name)
{
	Mnt *m;
	Mnthdr *mh;
	int found;

	found = 1;
	m = mntdev(c->dev, 0);
	mh = mhalloc();
	mh->thdr.type = Twalk;
	mh->thdr.fid = c->fid;
	strcpy(mh->thdr.name, name);
	if(waserror()){	/* BUG: can check type of error? */
		found = 0;
		goto Out;
	}
	mntxmit(m, mh);
	c->qid = mh->rhdr.qid;
	poperror();
    Out:
	mhfree(mh);
	return found;
}

void	 
mntstat(Chan *c, char *dp)
{
	Mnt *m;
	Mnthdr *mh;

	m = mntdev(c->dev, 0);
	mh = mhalloc();
	if(waserror()){
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = Tstat;
	mh->thdr.fid = c->fid;
	mntxmit(m, mh);
	memcpy(dp, mh->rhdr.stat, DIRLEN);
	dp[DIRLEN-4] = devchar[c->type];
	dp[DIRLEN-3] = 0;
	dp[DIRLEN-2] = c->dev;
	dp[DIRLEN-1] = c->dev>>8;
	mhfree(mh);
	poperror();
}

Chan*
mntopen(Chan *c, int omode)
{
	Mnt *m;
	Mnthdr *mh;

	m = mntdev(c->dev, 0);
	mh = mhalloc();
	if(waserror()){
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = Topen;
	mh->thdr.fid = c->fid;
	mh->thdr.mode = omode;
	mntxmit(m, mh);
	c->qid = mh->rhdr.qid;
	mhfree(mh);
	poperror();
	c->offset = 0;
	c->mode = openmode(omode);
	c->flag |= COPEN;
	return c;
}

void	 
mntcreate(Chan *c, char *name, int omode, ulong perm)
{
	Mnt *m;
	Mnthdr *mh;

	m = mntdev(c->dev, 0);
	mh = mhalloc();
	if(waserror()){
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = Tcreate;
	mh->thdr.fid = c->fid;
	strcpy(mh->thdr.name, name);
	mh->thdr.mode = omode;
	mh->thdr.perm = perm;
	mntxmit(m, mh);
	c->qid = mh->rhdr.qid;
	mhfree(mh);
	poperror();
	c->flag |= COPEN;
	c->mode = openmode(omode);
	c->qid = mh->rhdr.qid;
}

void	 
mntclose(Chan *c)
{
	Mnt *m;
	Mnthdr *mh;

	m = mntdev(c->dev, 0);
	mh = mhalloc();
	if(waserror()){
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = Tclunk;
	mh->thdr.fid = c->fid;
	mntxmit(m, mh);
	mhfree(mh);
	if(c == m->mntpt)
		m->mntpt = 0;
	if(decref(m) == 0){		/* BUG: need to hang up all pending i/o */
		qlock(m);
		close(m->msg);
		m->msg = 0;
		qunlock(m);
	}
	poperror();
}

long
mntreadwrite(Chan *c, void *vbuf, long n, int type)
{
	Mnt *m;
	Mnthdr *mh;
	long nt, nr, count, offset;
	char *buf;

	buf = vbuf;
	count = 0;
	offset = c->offset;
	m = mntdev(c->dev, 0);
	mh = mhalloc();
	if(waserror()){
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = type;
	mh->thdr.fid = c->fid;
    Loop:
	nt = n;
	if(nt > MAXFDATA)
		nt = MAXFDATA;
	mh->thdr.offset = offset;
	mh->thdr.count = nt;
	mh->thdr.data = buf;
	mntxmit(m, mh);
	nr = mh->rhdr.count;
	offset += nr;
	count += nr;
	buf += nr;
	n -= nr;
	if(n && nr==nt)
		goto Loop;
	mhfree(mh);
	poperror();
	return count;
}

long	 
mntread(Chan *c, void *buf, long n)
{
	long i;
	uchar *b;

	n = mntreadwrite(c, buf, n, Tread);
	if(c->qid & CHDIR){
		b = (uchar*)buf;
		for(i=n-DIRLEN; i>=0; i-=DIRLEN){
			b[DIRLEN-4] = devchar[c->type];
			b[DIRLEN-3] = 0;
			b[DIRLEN-2] = c->dev;
			b[DIRLEN-1] = c->dev>>8;
			b += DIRLEN;
		}
	}
	return n;
}

long	 
mntwrite(Chan *c, void *buf, long n)
{
	return mntreadwrite(c, buf, n, Twrite);
}

void	 
mntremove(Chan *c)
{
	Mnt *m;
	Mnthdr *mh;

	m = mntdev(c->dev, 0);
	mh = mhalloc();
	if(waserror()){
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = Tremove;
	mh->thdr.fid = c->fid;
	mntxmit(m, mh);
	mhfree(mh);
	poperror();
}

void
mntwstat(Chan *c, char *dp)
{
	Mnt *m;
	Mnthdr *mh;

	m = mntdev(c->dev, 0);
	mh = mhalloc();
	if(waserror()){
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = Twstat;
	mh->thdr.fid = c->fid;
	memcpy(mh->thdr.stat, dp, DIRLEN);
	mntxmit(m, mh);
	mhfree(mh);
	poperror();
}

void	 
mnterrstr(Error *e, char *buf)
{
	Mnt *m;
	Mnthdr *mh;
	char *def="mounted device shut down";

	m = mntdev(e->dev, 1);
	if(m == 0){
		strcpy(buf, def);
		return;
	}
	mh = mhalloc();
	if(waserror()){
		strcpy(buf, def);
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = Terrstr;
	mh->thdr.fid = 0;
	mh->thdr.err = e->code;
	mntxmit(m, mh);
	strcpy(buf, (char*)mh->rhdr.ename);
	mhfree(mh);
	poperror();
}

void	 
mntuserstr(Error *e, char *buf)
{
	Mnt *m;
	Mnthdr *mh;
	char *def="mounted device shut down";

	m = mntdev(e->dev, 1);
	if(m == 0){
		strcpy(buf, def);
		return;
	}
	mh = mhalloc();
	if(waserror()){
		strcpy(buf, def);
		mhfree(mh);
		nexterror();
	}
	mh->thdr.type = Tuserstr;
	mh->thdr.fid = 0;
	mh->thdr.uid = e->code;
	mntxmit(m, mh);
	strcpy(buf, (char*)mh->rhdr.uname);
	mhfree(mh);
	poperror();
}

void
mntxmit(Mnt *m, Mnthdr *mh)
{
	ulong n;
	Mntbuf *mbr, *mbw;
	Chan *mntpt;

	mbr = mballoc();
	mbw = mballoc();
	if(waserror()){
		mbfree(mbr);
		mbfree(mbw);
		nexterror();
	}
	n = convS2M(&mh->thdr, mbw->buf);
	qlock(m);
	if(m->msg == 0){
		qunlock(m);
		error(0, Eshutdown);
	}
	qlock(m->msg);
	if(waserror()){
		qunlock(m);
		qunlock(m->msg);
		nexterror();
	}
	if((*devtab[m->msg->type].write)(m->msg, mbw->buf, n) != n){
		pprint("short write in mntxmit\n");
		error(0, Egreg);
	}

	/*
	 * Read response
	 */
	n = (*devtab[m->msg->type].read)(m->msg, mbr->buf, BUFSIZE);
	qunlock(m);
	qunlock(m->msg);
	poperror();

	if(convM2S(mbr->buf, &mh->rhdr, n) == 0){
		pprint("format error in mntxmit\n");
		error(0, Egreg);
	}

	/*
	 * Various checks
	 */
	if(mh->rhdr.type != mh->thdr.type+1){
		pprint("type mismatch %d %d\n", mh->rhdr.type, mh->thdr.type+1);
		error(0, Egreg);
	}
	if(mh->rhdr.fid != mh->thdr.fid){
		pprint("fid mismatch %d %d type %d\n", mh->rhdr.fid, mh->thdr.fid, mh->rhdr.type);
		error(0, Egreg);
	}
	if(mh->rhdr.err){
		mntpt = m->mntpt;	/* unsafe, but Errors are unsafe anyway */
		if(mntpt)
			error(mntpt, mh->rhdr.err);
		error(0, Eshutdown);
	}
	/*
	 * Copy out on read
	 */
	if(mh->thdr.type == Tread)
		memcpy(mh->thdr.data, mh->rhdr.data, mh->rhdr.count);
	mbfree(mbr);
	mbfree(mbw);
	poperror();
}
.
## diffname port/devmnt.c 1990/0303
## diff -e /n/bootesdump/1990/0227/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0303/sys/src/9/mips/devmnt.c
245a
	nc->mchan = c->mchan;
	nc->mqid = c->qid;
.
207a
	c->mchan = m->msg;
	c->mqid = c->qid;
.
191c
	c->dev = m->mntid;
.
189a
	lock(&mntid);
	m->mntid = ++mntid.id;
	unlock(&mntid);
.
123,134c
	for(m=mnt,i=0; i<conf.nmntdev; i++,m++)		/* use a hash table some day */
		if(m->mntid == dev){
			if(m->msg == 0)
				break;
			return m;
		}
	if(noerr)
		return 0;
	error(0, Eshutdown);
.
121a
	int i;
.
52a
struct
{
	Lock;
	long	id;
}mntid;

.
20a
	ulong	mntid;		/* serial # */
.
## diffname port/devmnt.c 1990/0306
## diff -e /n/bootesdump/1990/0303/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0306/sys/src/9/mips/devmnt.c
587c
	if(!isbit)
		qunlock(m->msg);
.
574c
		if(!isbit)
			qunlock(m->msg);
.
571c
	isbit = 0;
	if(devchar[m->msg->type] == 'b')
		isbit = 1;
	if(!isbit)
		qlock(m->msg);
.
556a
	int isbit;
.
## diffname port/devmnt.c 1990/03081
## diff -e /n/bootesdump/1990/0306/sys/src/9/mips/devmnt.c /n/bootesdump/1990/03081/sys/src/9/mips/devmnt.c
591,594c
	n = (*devtab[msg->type].read)(msg, mbr->buf, BUFSIZE);
	if(isbit)
		close(msg);
	else{
		qunlock(m);
		qunlock(msg);
	}
.
583c
	if((*devtab[msg->type].write)(msg, mbw->buf, n) != n){
.
578,580c
		if(isbit)
			close(msg);
		else{
			qunlock(m);
			qunlock(msg);
		}
.
575,576c
	/*
	 * Avoid qlock for bit, to maximize parallelism
	 */
	if(isbit){
		lock(&m->use);		/* spin rather than sleep */
		if((msg = m->msg) == 0){
			unlock(&m->use);
			error(0, Eshutdown);
		}
		incref(msg);
		unlock(&m->use);
	}else{
		qlock(m);
		if((msg = m->msg) == 0){
			qunlock(m);
			error(0, Eshutdown);
		}
		qlock(msg);
	}
.
567,571d
556c
	Chan *mntpt, *msg;
.
## diffname port/devmnt.c 1990/0310
## diff -e /n/bootesdump/1990/03081/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0310/sys/src/9/mips/devmnt.c
384a
print("close mount table %d\n", m->mntid);
.
## diffname port/devmnt.c 1990/0312
## diff -e /n/bootesdump/1990/0310/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0312/sys/src/9/mips/devmnt.c
470a
	decref(m);
.
## diffname port/devmnt.c 1990/0322
## diff -e /n/bootesdump/1990/0312/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0322/sys/src/9/mips/devmnt.c
612c
		qunlock(&m->q);
.
595c
			qunlock(&m->q);
.
586c
			qunlock(&m->q);
.
584c
		qlock(&m->q);
.
582c
		unlock(&m->q);
.
578c
			unlock(&m->q);
.
576c
		lock(&m->q);		/* spin rather than sleep */
.
389c
		qunlock(&m->q);
.
386c
		qlock(&m->q);
.
20c
	QLock	q;		/* for access */
.
## diffname port/devmnt.c 1990/0324
## diff -e /n/bootesdump/1990/0322/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0324/sys/src/9/mips/devmnt.c
612c
		qunlock(m);
.
595c
			qunlock(m);
.
586c
			qunlock(m);
.
584c
		qlock(m);
.
582c
		unlock(&m->use);
.
578c
			unlock(&m->use);
.
576c
		lock(&m->use);		/* spin rather than sleep */
.
570c
	if(devchar[m->msg->type] == '3')
.
389c
		qunlock(m);
.
386c
		qlock(m);
.
20c
	QLock;			/* for access */
.
## diffname port/devmnt.c 1990/0409
## diff -e /n/bootesdump/1990/0324/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0409/sys/src/9/mips/devmnt.c
385d
## diffname port/devmnt.c 1990/0511
## diff -e /n/bootesdump/1990/0409/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0511/sys/src/9/mips/devmnt.c
613a
	if((*devtab[msg->type].write)(msg, mbw->buf, n) != n){
		pprint("short write in mntxmit\n");
		error(0, Egreg);
	}

	/*
	 * Read response
	 */
	n = (*devtab[msg->type].read)(msg, mbr->buf, BUFSIZE);
	qunlock(m);
	qunlock(msg);
.
612a
		nexterror();
.
611a
		error(0, Eshutdown);
	}
	qlock(msg);
	if(waserror()){
		qunlock(m);
.
608,610c
	close(msg);
	poperror();

	if(convM2S(mbr->buf, &mh->rhdr, n) == 0){
		pprint("format error in mntxmit\n");
		error(0, Egreg);
	}

	/*
	 * Various checks
	 */
	if(mh->rhdr.type != mh->thdr.type+1){
		pprint("type mismatch %d %d\n", mh->rhdr.type, mh->thdr.type+1);
		error(0, Egreg);
	}
	if(mh->rhdr.fid != mh->thdr.fid){
		pprint("fid mismatch %d %d type %d\n", mh->rhdr.fid, mh->thdr.fid, mh->rhdr.type);
		error(0, Egreg);
	}
	if(mh->rhdr.err){
		mntpt = m->mntpt;	/* unsafe, but Errors are unsafe anyway */
		if(mntpt)
			error(mntpt, mh->rhdr.err);
		error(0, Eshutdown);
	}

	/*
	 * Copy out on read
	 */
	if(mh->thdr.type == Tread)
		memcpy(mh->thdr.data, mh->rhdr.data, mh->rhdr.count);
	mbfree(mbr);
	mbfree(mbw);
	poperror();
	return;

    Normal:
	qlock(m);
	if((msg = m->msg) == 0){
.
591,596c
		close(msg);
.
589a
	incref(msg);
	unlock(&m->use);
.
582,588c
		error(0, Eshutdown);
.
574,580c
	if(devchar[m->msg->type] != '3')
		goto Normal;
	lock(&m->use);		/* spin rather than sleep */
	if((msg = m->msg) == 0){
.
572c
	 * Bit3 does its own multiplexing.  (Well, the file server does.)
	 * The code is different enough that it's broken out separately here.
.
568,570d
558d
## diffname port/devmnt.c 1990/0513
## diff -e /n/bootesdump/1990/0511/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0513/sys/src/9/mips/devmnt.c
261a
	if(new)
		poperror();
.
258,259d
## diffname port/devmnt.c 1990/0604
## diff -e /n/bootesdump/1990/0513/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0604/sys/src/9/mips/devmnt.c
659,669c
    Respond:
	mqfree(q);
	poperror();
.
645,656c
	if(q->reader == 0){		/* i will read */
		q->reader = u->p;
    Read:
		qunlock(q);
		qlocked = 0;
		n = (*devtab[q->msg->type].read)(q->msg, mbr->buf, BUFSIZE);
		if(convM2S(mbr->buf, &mh->rhdr, n) == 0){
			print("format error in mntxmit\n");
			mnterrdequeue(q, mh);
			error(0, Ebadmsg);
		}
		/*
		 * Response might not be mine
		 */
		qlock(q);
		qlocked = 1;
		if(mh->rhdr.fid == mh->thdr.fid
		&& mh->rhdr.type == mh->thdr.type+1){	/* it's mine */
			q->reader = 0;
			if(w = q->writer){	/* advance a writer to reader */
				q->reader = w->p;
				q->writer = w->next;
				wakeup(&w->r);
			}
			qunlock(q);
			qlocked = 0;
			goto Respond;
		}
		/*
		 * Hand response to correct recipient
		 */
if(q->writer == 0) print("response with empty queue\n");
		for(ow=0,w=q->writer; w; ow=w,w=w->next)
			if(mh->rhdr.fid == w->thdr.fid
			&& mh->rhdr.type == w->thdr.type+1){
				Mntbuf *t;
				t = mbr;
				mbr = w->mbr;
				w->mbr = t;
				memcpy(&w->rhdr, &mh->rhdr, sizeof mh->rhdr);
				/* take recipient from queue */
				if(ow == 0)
					q->writer = w->next;
				else
					ow->next = w->next;
				wakeup(&w->r);
				goto Read;
			}
		goto Read;
	}else{
		mh->mbr = mbr;
		mh->p = u->p;
		/* put self in queue */
		mh->next = q->writer;
		q->writer = mh;
		qunlock(q);
		qlocked = 0;
		if(waserror()){		/* interrupted sleep */
			print("interrupted i/o\n");
			mnterrdequeue(q, mh);
			nexterror();
		}
		sleep(&mh->r, return0, 0);
		poperror();
		qlock(q);
		qlocked = 1;
		if(q->reader == u->p)	/* i got promoted */
			goto Read;
		mbr = mh->mbr;		/* pick up my buffer */
		qunlock(q);
		qlocked = 0;
		goto Respond;
.
641,643c
	if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n) != n){
		print("short write in mntxmit\n");
		error(0, Eshortmsg);
.
637,638c
		if(qlocked)
			qunlock(q);
		mqfree(q);
.
630,635c
#endif
	incref(q);
	qlock(q);
	qlocked = 1;
.
609,610c
		print("fid mismatch %d %d type %d\n", mh->rhdr.fid, mh->thdr.fid, mh->rhdr.type);
		error(0, Ebadmsg);
.
605,606c
		print("type mismatch %d %d\n", mh->rhdr.type, mh->thdr.type+1);
		error(0, Ebadmsg);
.
597,598c
		print("format error in mntxmit\n");
		error(0, Ebadmsg);
.
592,593c
	n = (*devtab[q->msg->type].read)(q->msg, mbr->buf, BUFSIZE);
	mqfree(q);
.
584,586c
	if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n) != n){
		print("short write in mntxmit\n");
		error(0, Eshortmsg);
.
581c
		mqfree(q);
.
573,579c

	incref(q);
.
571c
	if(devchar[q->msg->type] != '3')
.
566a
	q = m->q;
	if(q == 0)
		error(0, Eshutdown);
#ifdef	BIT3
.
557c
	Mnthdr *w, *ow;
	Chan *mntpt;
	MntQ *q;
	int qlocked;
.
552a
mnterrdequeue(MntQ *q, Mnthdr *mh)		/* queue is unlocked */
{
	Mnthdr *w;

	qlock(q);
	/* take self from queue if necessary */
	if(q->reader == u->p){	/* advance a writer to reader */
		w = q->writer;
		if(w){
			q->reader = w->p;
			q->writer = w->next;
			wakeup(&w->r);
		}else{
			q->reader = 0;
			q->writer = 0;
		}
	}else{
		w = q->writer;
		if(w == mh)
			q->writer = w->next;
		else{
			while(w){
				if(w->next == mh){
					w->next = mh->next;
					break;
				}
				w = w->next;
			}
		}
	}
	qunlock(q);

}
void
.
461,475c
	mntclunk(c, Tremove);
.
392a
void
mntclose(Chan *c)
{
	mntclunk(c, Tclunk);
}

.
384,389c
	lock(m);
	if(--m->ref == 0){		/* BUG: need to hang up all pending i/o */
		q = m->q;
		m->q = 0;
		m->mntid = 0;
		unlock(m);		/* mqfree can take time */
		mqfree(q);
	}else
		unlock(m);
	if(waserr)
		nexterror();
.
380c
	waserr = 0;
	if(waserror())		/* gotta clean up as if there wasn't */
		waserr = 1;
	else
		mntxmit(m, mh);
.
374,378c
	mh->thdr.type = t;
.
370a
	MntQ *q;
	int waserr;
int ne = u->nerrlab;
.
367c
mntclunk(Chan *c, int t)
.
216c
	c->mchan = m->q->msg;
.
206a
		mqfree(q);
.
203a

    out:
.
202c

	/*
	 * Look for queue to same msg channel
	 */
	q = mntqalloc.arena;
	for(i=0; i<conf.nmntdev; i++,q++)
		if(q->msg==cm){
			lock(q);
			if(q->ref && q->msg==cm){
				m->q = q;
				q->ref++;
				unlock(q);
				goto out;
			}
			unlock(q);
		}
	m->q = mqalloc();
	m->q->msg = cm;
.
191a

.
174a
	MntQ *q;
.
173c
	Mnt *m, *mm;
.
161a

	mq = ialloc(conf.nmntdev*sizeof(MntQ), 0);
	for(i=0; i<conf.nmntdev-1; i++)
		mq[i].next = &mq[i+1];
	mq[i].next = 0;
	mntqalloc.arena = mq;
	mntqalloc.free = mq;
.
147a
	MntQ *mq;
.
133c
			if(m->q == 0)
.
124a
MntQ*
mqalloc(void)
{
	MntQ *q;

	lock(&mntqalloc);
	if(q = mntqalloc.free){		/* assign = */
		mntqalloc.free = q->next;
		unlock(&mntqalloc);
		lock(q);
		q->ref = 1;
		q->writer = 0;
		q->reader = 0;
		unlock(q);
		return q;
	}
	unlock(&mntqalloc);
	panic("no mntqs\n");			/* there MUST be enough */
}

void
mqfree(MntQ *mq)
{
	Chan *msg = 0;

	lock(mq);
	if(--mq->ref == 0){
		msg = mq->msg;
		mq->msg = 0;
		lock(&mntqalloc);
		mq->next = mntqalloc.free;
		mntqalloc.free = mq;
		unlock(&mntqalloc);
	}
	unlock(mq);
	if(msg)		/* after locks are down */
		close(msg);
}

.
109c
		panic("mhalloc");
.
56a
	MntQ	*arena;
	MntQ	*free;
}mntqalloc;

struct
{
	Lock;
.
45a
	Rendez	r;
	Proc	*p;
	Mntbuf	*mbr;
.
43c
	Mnthdr	*next;	/* in free list or writers list */
.
40,41c
struct Mnthdr
.
25a
struct MntQ
{
	Ref;
	QLock;			/* for access */
	MntQ	*next;		/* for allocation */
	Chan	*msg;		/* for reading and writing messages */
	Proc	*reader;	/* process reading response */
	Mnthdr	*writer;	/* queue of headers of written messages */
};

.
23a
	MntQ	*q;
.
22d
20d
16a
typedef struct Mnthdr	Mnthdr;
typedef struct MntQ	MntQ;

.
12,14d
## diffname port/devmnt.c 1990/0617
## diff -e /n/bootesdump/1990/0604/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0617/sys/src/9/mips/devmnt.c
825c
			print("%lux interrupted i/o %d %d\n", u->p, mh->thdr.type, mh->thdr.fid);
.
798c
if(q->writer == 0) print("response with empty queue %d %d %d: %d %d\n", mh->rhdr.type, mh->rhdr.err, mh->rhdr.fid, mh->thdr.type, mh->thdr.fid);
.
774c
			print("%lux %lux %lux %d format error in mntxmit %s\n", u->p, q->reader, q->writer, n, u->p->text);
.
289a
	unlock(&mntqalloc);
.
285,287c
	m->q = mqalloc(cm);
.
273a
	lock(&mntqalloc);
.
169a
print("mqfree %lux %lux\n", mq->reader, mq->writer);
.
159d
156d
153a
		q->msg = msg;
		unlock(q);
		incref(msg);
.
151d
148d
144c
mqalloc(Chan *msg)	/* mntqalloc is locked */
.
## diffname port/devmnt.c 1990/0619
## diff -e /n/bootesdump/1990/0617/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0619/sys/src/9/mips/devmnt.c
855c
	mbfree(mh->mbr);
.
835d
825c
			print("interrupted i/o\n");
.
817d
803,804c
				t = mh->mbr;
				mh->mbr = w->mbr;
.
798c
		if(q->writer==0) print("response with empty queue\n");
.
772,774c
		n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE);
		if(convM2S(mh->mbr->buf, &mh->rhdr, n) == 0){
			print("format error in mntxmit\n");
.
747c
	mbfree(mh->mbr);
.
719c
	if(convM2S(mh->mbr->buf, &mh->rhdr, n) == 0){
.
715c
	n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE);
.
686c
		mbfree(mh->mbr);
.
683c
	mh->mbr = mballoc();
.
677c
	Mntbuf *mbw;
.
289c
	qunlock(&mntqalloc);
.
274c
	qlock(&mntqalloc);
.
169d
144c
mqalloc(Chan *msg)	/* mntqalloc is qlocked */
.
67a
	QLock;
.
## diffname port/devmnt.c 1990/0623
## diff -e /n/bootesdump/1990/0619/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0623/sys/src/9/mips/devmnt.c
824d
798d
774d
## diffname port/devmnt.c 1990/0629
## diff -e /n/bootesdump/1990/0623/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0629/sys/src/9/mips/devmnt.c
812a
print("devmnt: undelivered response fid %d type %d\n", mh->rhdr.fid, mh->rhdr.type);
print("reader pid %d fid %d type %d\n", u->p->pid, mh->thdr.fid, mh->thdr.type);
for(w=q->writer; w; w=w->next)print("writer pid %d fid %d type %d\n",w->p->pid,w->thdr.fid,w->thdr.type);

.
## diffname port/devmnt.c 1990/0703
## diff -e /n/bootesdump/1990/0629/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0703/sys/src/9/mips/devmnt.c
853a
	}
.
852c
	if(mh->thdr.type == Tread){
		if(mh->rhdr.count > mh->thdr.count)
			error(0, Ebadcnt);
.
813,816d
772a
		poperror();
.
771a
		if(waserror()){
			mnterrdequeue(q, mh);
			nexterror();
		}
.
## diffname port/devmnt.c 1990/0717
## diff -e /n/bootesdump/1990/0703/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0717/sys/src/9/mips/devmnt.c
860a
}

mntdump()
{
	int i;
	MntQ *q;
	Mnthdr *h;
	Proc *p;

	for(i=0; i<conf.nmntdev; i++){
		q = &mntqalloc.arena[i];
		if(!q->msg)
			continue;
		p = q->reader;
		print("q rdr %d wrtr ", p? p->pid : 0);
		for(h=q->writer; h; h=h->next)
			print("(%lux %lux %d)", h, &h->r, (p=h->p)? p->pid : 0);
		print("\n");
	}
.
830c
		sleep(&mh->r, mntreadreply, mh);
.
814a
				w->readreply = 1;
.
792a
				w->readreply = 1;
.
762a
	mh->readreply = 0;
.
672a
int
mntreadreply(void *a)
{
	return ((Mnthdr *)a)->readreply;
}
.
56a
	int	readreply;	/* true if we are reader or our reply has come */
.
## diffname port/devmnt.c 1990/0725
## diff -e /n/bootesdump/1990/0717/sys/src/9/mips/devmnt.c /n/bootesdump/1990/0725/sys/src/9/mips/devmnt.c
294d
## diffname port/devmnt.c 1990/1002
## diff -e /n/bootesdump/1990/0725/sys/src/9/mips/devmnt.c /n/bootesdump/1990/1002/sys/src/9/mips/devmnt.c
751a
	}
.
750c
	if(mh->thdr.type == Tread){
		if(mh->rhdr.count>497 && mh->rhdr.data[497]==011)
			print("*497==11 %lux\n", &mh->rhdr.data[497]);
.
## diffname port/devmnt.c 1990/1004
## diff -e /n/bootesdump/1990/1002/sys/src/9/mips/devmnt.c /n/bootesdump/1990/1004/sys/src/9/mips/devmnt.c
754d
750,752c
	if(mh->thdr.type == Tread)
.
## diffname port/devmnt.c 1990/11211
## diff -e /n/bootesdump/1990/1004/sys/src/9/mips/devmnt.c /n/bootesdump/1990/11211/sys/src/9/mips/devmnt.c
863c
			error(Ebadcnt);
.
852,856c
	if(mh->rhdr.type == Rerror){
		if(m->mntpt)
			errors(mh->rhdr.ename);
		error(Eshutdown);
.
810,811c
			if(mh->rhdr.tag == w->thdr.tag){
.
793,794c
		if(mh->rhdr.tag == mh->thdr.tag){	/* it's mine */
.
786c
			error(Ebadmsg);
.
771c
		error(Eshortmsg);
.
740,745d
738c
		error(Ebadmsg);
.
734c
		error(Ebadmsg);
.
731a
	if(mh->rhdr.tag != mh->thdr.tag){
		print("tag mismatch %d %d\n", mh->rhdr.tag, mh->thdr.tag);
		error(Ebadmsg);
	}
	if(mh->rhdr.type == Rerror){
		if(m->mntpt)
			errors(mh->rhdr.ename);
		error(Eshutdown);
	}
.
726c
		error(Ebadmsg);
.
714c
		error(Eshortmsg);
.
698c
		error(Eshutdown);
.
684d
677a

.
672a

.
585,638d
540c
	if(c->qid.path & CHDIR){
.
300c
	strcpy(mh->thdr.aname, bogus.spec);
	strcpy(mh->thdr.auth, bogus.auth);
.
266c
	c = devattach('M', bogus.spec);
.
258c
	error(Enomntdev);
.
248,249c
	bogus = *((struct bogus *)crud);
.
245a
		char	*auth;
.
236c
mntattach(char *crud)
.
219a
	mh[i].thdr.tag = i;
.
218a
		mh[i].thdr.tag = i;
	}
.
217c
	for(i=0; i<conf.nmnthdr-1; i++){
.
197c
	error(Eshutdown);
.
12d
## diffname port/devmnt.c 1990/1123
## diff -e /n/bootesdump/1990/11211/sys/src/9/mips/devmnt.c /n/bootesdump/1990/1123/sys/src/9/mips/devmnt.c
781a
		mh->prev = 0;
		mh->writing = 1;
		if(q->writer)
			q->writer->prev = mh;
.
761,776c
		if(tag<0 || tag>=conf.nmnthdr){
			print("unknown tag %d\n", tag);
			goto Read;
		}
		w = &mnthdralloc.arena[tag];
		if(!w->writing){
			print("reply not writing\n");
			goto Read;
		}
		t = mh->mbr;
		mh->mbr = w->mbr;
		w->mbr = t;
		memcpy(&w->rhdr, &mh->rhdr, sizeof mh->rhdr);
		mntwunlink(q, w);
		w->readreply = 1;
		wakeup(&w->r);
.
750a
				if(q->writer)
					q->writer->prev = 0;
.
746c
		tag = mh->rhdr.tag;
		if(tag == mh->thdr.tag){	/* it's mine */
.
636c
	int qlocked, tag;
.
633c
	Mntbuf *mbw, *t;
.
605,618c
	}else
		mntwunlink(q, mh);
.
599a
			q->writer->prev = 0;
.
590a
	if(w->next)
		w->next->prev = w->prev;
	if(w->prev)
		w->prev->next = w->next;
	else{
		q->writer = w->next;
		if(q->writer)
			q->writer->prev = 0;
	}
	w->writing = 0;
}

void
mnterrdequeue(MntQ *q, Mnthdr *mh)	/* queue is unlocked */
{
.
589c
mntwunlink(MntQ *q, Mnthdr *w)		/* queue is locked and w is a writer */
.
221a
	mnthdralloc.arena = mh;
.
61a
	Mnthdr	*arena;
.
50c
	Mnthdr	*next;		/* in free list or writers list */
	Mnthdr	*prev;		/* in writers list only */
	int	writing;	/* flag: in writers list */
.
## diffname port/devmnt.c 1990/1124
## diff -e /n/bootesdump/1990/1123/sys/src/9/mips/devmnt.c /n/bootesdump/1990/1124/sys/src/9/mips/devmnt.c
833c
	poperror();		/* 1 */
.
821a
	}else if(mh->rhdr.type != mh->thdr.type+1){
		print("bad type %d not %d in mntxmit\n", mh->rhdr.type, mh->thdr.type+1);
		error(Ebadmsg);
.
817c
	poperror();		/* 2 */
.
809a
		mh->active = 0;
.
801c
			mnterrdequeue(m, mh);
.
794d
780d
777,778c
		if(w->flushing || !w->active)	/* nothing to do; mntflush will clean up */
.
764a
			mh->active = 0;
.
759,761d
757a
				mntwunlink(q, w);
.
746c
			print("bad reply message\n");
			mnterrdequeue(m, mh);
.
744c
		poperror();		/* 3 */
.
739,740c
		if(waserror()){		/* 3 */
			mnterrdequeue(m, mh);
.
729a
	mh->active = 1;
.
723c
	if(waserror()){		/* 2 */
.
715c
	poperror();		/* 1 */
.
680c
	poperror();		/* 2 */
.
666c
	if(waserror()){		/* 2 */
.
648c
	if(waserror()){			/* 1 */
.
644c
	int qlocked, tag, written;
.
628c
	mntflush(m, mh);
.
618,619d
616a
			mntwunlink(q, w);
.
611a
	mh->flushing = 1;
	q = m->q;
.
610a
	MntQ *q;
.
609a
	Mnthdr *mh;

	if(omh->thdr.type == Tflush)
		return;

	mh = mhalloc();
	if(waserror()){
		omh->flushing = 0;
		mhfree(mh);
		return;		/* no more errors please */
	}
	mh->thdr.type = Tflush;
	mh->thdr.oldtag = omh->thdr.tag;
	mntxmit(m, mh);
	omh->flushing = 0;
	mhfree(mh);
	poperror();
}

void
mnterrdequeue(Mnt *m, Mnthdr *mh)	/* queue is unlocked */
{
.
608c
mntflush(Mnt *m, Mnthdr *omh)	/* queue is unlocked */
.
606a
/*
 * m->q is unlocked.  Send Tflush message to flush omh->tag.
 * Cut off all errors.   Caller will free omh
 */
.
604d
140a
	if(mh->flushing)
		return;
	mh->active = 0;
.
124a
		mh->flushing = 0;
.
52c
	short	active;
	short	flushing;	/* a Tflush has been sent */
.
## diffname port/devmnt.c 1990/1126
## diff -e /n/bootesdump/1990/1124/sys/src/9/mips/devmnt.c /n/bootesdump/1990/1126/sys/src/9/mips/devmnt.c
472d
## diffname port/devmnt.c 1990/1127
## diff -e /n/bootesdump/1990/1126/sys/src/9/mips/devmnt.c /n/bootesdump/1990/1127/sys/src/9/mips/devmnt.c
811,813c
		w->mbr = mh->mbr;
		mh->mbr = 0;
.
774a
		mh->mbr = mballoc();
.
708a
	mh->mbr = mballoc();
.
680c
		if(mh->mbr)
			mbfree(mh->mbr);
.
677c
	mh->mbr = 0;
.
672c
	Mntbuf *mbw;
.
## diffname port/devmnt.c 1990/12041
## diff -e /n/bootesdump/1990/1127/sys/src/9/mips/devmnt.c /n/bootesdump/1990/12041/sys/src/9/mips/devmnt.c
855a
		dumpmsg(mh->mbr);
.
808a
			dumpmsg(mh->mbr);
.
781a
			dumpmsg(mh->mbr);
.
779a
		mh->mbr->n = n;
.
667a
/*
 *  print out first few bytes of the message
 */
dumpmsg(Mntbuf *mb)
{
	int i;
	char *x;

	x = mb->buf;
	for(i = 0; i < mb->n; i++)
		print("%.2ux ", *x++);
	print("\n");
}

.
39a
	int	n;
.
## diffname port/devmnt.c 1990/1210
## diff -e /n/bootesdump/1990/1210/sys/src/9/mips/devmnt.c /n/bootesdump/1990/1210/sys/src/9/port/devmnt.c
874d
826d
798d
795d
669,682d
40d
## diffname port/devmnt.c 1990/1214
## diff -e /n/bootesdump/1990/1210/sys/src/9/port/devmnt.c /n/bootesdump/1990/1214/sys/src/9/port/devmnt.c
867a
	USED(qlocked);
.
841a
		USED(qlocked);
.
836a
		USED(qlocked);
.
799a
			USED(qlocked);
.
787a
		USED(qlocked);
.
770a
		USED(qlocked);
.
## diffname port/devmnt.c 1990/1220
## diff -e /n/bootesdump/1990/1214/sys/src/9/port/devmnt.c /n/bootesdump/1990/1220/sys/src/9/port/devmnt.c
877c
void
mntdump(void)
.
## diffname port/devmnt.c 1991/0117
## diff -e /n/bootesdump/1990/1220/sys/src/9/port/devmnt.c /n/bootesdump/1991/0117/sys/src/9/port/devmnt.c
816c
			goto FreeRead;
.
811a
	FreeRead:
			mbfree(mh->mbr);
			mh->mbr = 0;
.
## diffname port/devmnt.c 1991/0212
## diff -e /n/bootesdump/1991/0117/sys/src/9/port/devmnt.c /n/bootesdump/1991/0212/sys/src/9/port/devmnt.c
694c
	if(devchar[q->msg->type]!='3' && devchar[q->msg->type]!='H')
.
691c
	 * Bit3 and Hotrod do their own multiplexing.  (Well, the file server does.)
.
## diffname port/devmnt.c 1991/0220
## diff -e /n/bootesdump/1991/0212/sys/src/9/port/devmnt.c /n/bootesdump/1991/0220/sys/src/9/port/devmnt.c
39c
	char	buf[BUFSIZE+BITROUND]; 	/* BUG */
.
34c
#define	BITROUND 256
#define	BUFSIZE	(MAXFDATA+MAXMSG)
.
## diffname port/devmnt.c 1991/0306
## diff -e /n/bootesdump/1991/0220/sys/src/9/port/devmnt.c /n/bootesdump/1991/0306/sys/src/9/port/devmnt.c
712a
	poperror();		/* 3 */
.
710a
	if(waserror()){		/* 3 */
		mntflush(m, mh);
		nexterror();
	}
.
## diffname port/devmnt.c 1991/0315
## diff -e /n/bootesdump/1991/0306/sys/src/9/port/devmnt.c /n/bootesdump/1991/0315/sys/src/9/port/devmnt.c
788d
## diffname port/devmnt.c 1991/0318
## diff -e /n/bootesdump/1991/0315/sys/src/9/port/devmnt.c /n/bootesdump/1991/0318/sys/src/9/port/devmnt.c
877c
		memmove(mh->thdr.data, mh->rhdr.data, mh->rhdr.count);
.
827c
		memmove(&w->rhdr, &mh->rhdr, sizeof mh->rhdr);
.
751c
		memmove(mh->thdr.data, mh->rhdr.data, mh->rhdr.count);
.
591c
	memmove(mh->thdr.stat, dp, DIRLEN);
.
406c
	memmove(dp, mh->rhdr.stat, DIRLEN);
.
311c
	memmove(mh->thdr.uname, u->p->pgrp->user, NAMELEN);
.
## diffname port/devmnt.c 1991/0411
## diff -e /n/bootesdump/1991/0318/sys/src/9/port/devmnt.c /n/bootesdump/1991/0411/sys/src/9/port/devmnt.c
785c
		n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE, 0);
.
770c
	if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n, 0) != n){
.
716c
	n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE, 0);
.
703c
	if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n, 0) != n){
.
568c
	return mntreadwrite(c, buf, n, Twrite, offset);
.
566c
mntwrite(Chan *c, void *buf, long n, ulong offset)
.
551c
	n = mntreadwrite(c, buf, n, Tread, offset);
.
546c
mntread(Chan *c, void *buf, long n, ulong offset)
.
516d
511c
	long nt, nr, count;
.
507c
mntreadwrite(Chan *c, void *vbuf, long n, int type, ulong offset)
.
## diffname port/devmnt.c 1991/0414
## diff -e /n/bootesdump/1991/0411/sys/src/9/port/devmnt.c /n/bootesdump/1991/0414/sys/src/9/port/devmnt.c
390a
Chan *
mntclwalk(Chan *c, char *name)
{
	Mnt *m;
	Mnthdr *mh;
	Chan *nc;

	nc = newchan();
	m = mntdev(c->dev, 0);
	mh = mhalloc();
	mh->thdr.type = Tclwalk;
	mh->thdr.fid = c->fid;
	mh->thdr.newfid = nc->fid;
	strcpy(mh->thdr.name, name);
	if(waserror()){	/* BUG: can check type of error? */
		freechan(nc);
		nc = 0;
		goto Out;
	}
	mntxmit(m, mh);
	nc->qid = mh->rhdr.qid;
	poperror();
    Out:
	mhfree(mh);
	return nc;
}

.
## diffname port/devmnt.c 1991/0421
## diff -e /n/bootesdump/1991/0414/sys/src/9/port/devmnt.c /n/bootesdump/1991/0421/sys/src/9/port/devmnt.c
609c
	m = mntdev(c, 0);
.
543c
	m = mntdev(c, 0);
.
501c
	m = mntdev(c, 0);
.
473c
	m = mntdev(c, 0);
.
448c
	m = mntdev(c, 0);
.
424c
	m = mntdev(c, 0);
.
411a
	print("mntclwalk(%d %lux)->%d %lux\n", c->type, c->qid.path,
		nc->type, nc->qid.path);
.
405a
		print("mntclwalk(%d %lux) failed\n", c->type, c->qid.path);
.
399c
	m = mntdev(c, 0);
.
374c
	m = mntdev(c, 0);
.
355a
	nc->aux = c->aux;
	nc->mntindex = c->mntindex;
.
339c
	m = mntdev(c, 0);
.
279a
	c->mntindex = m-mnt;
.
197,202c
	m = &mnt[c->mntindex];
	if(m->mntid==c->dev && m->q!=0)
		return m;
.
192c
mntdev(Chan *c, int noerr)
.
## diffname port/devmnt.c 1991/0423
## diff -e /n/bootesdump/1991/0421/sys/src/9/port/devmnt.c /n/bootesdump/1991/0423/sys/src/9/port/devmnt.c
415a
	nc->qid = mh->rhdr.qid;
	incref(m);
.
412,414c
	if(mh->rhdr.fid == mh->thdr.fid)
		errors("directory entry not found");
.
405,410d
398a
	nc->type = c->type;
	nc->dev = c->dev;
	nc->qid = c->qid;
	nc->mode = c->mode;
	nc->flag = c->flag;
	nc->offset = c->offset;
	nc->mnt = c->mnt;
	nc->aux = c->aux;
	nc->mchan = c->mchan;
	nc->mqid = c->qid;
.
397a
	if(waserror()){	/* BUG: can check type of error? */
		freechan(nc);
		nc = 0;
		goto Out;
	}
.
201a
	print("mntdev shutdown %d %d %d %lux\n", c->dev, c->mntindex,
			m->mntid, m->q);
.
## diffname port/devmnt.c 1991/0425
## diff -e /n/bootesdump/1991/0423/sys/src/9/port/devmnt.c /n/bootesdump/1991/0425/sys/src/9/port/devmnt.c
786a
#endif
.
782a
#ifdef PHILW_HACK
.
426,428c
	if(mh->rhdr.fid == mh->thdr.fid){
		/*
		 *  just free the chan, the other side has
		 *  already clunked
		 */
		freechan(nc);
		nc = 0;
	} else {
		/*
		 *  it worked, keep the channel
		 */
		nc->qid = mh->rhdr.qid;
		incref(m);
	}
.
423,424d
415a
	mh = 0;
	if(waserror()){
		close(nc);
		if(mh)
			mhfree(mh);
		return 0;
	}
.
400,404d
## diffname port/devmnt.c 1991/0426
## diff -e /n/bootesdump/1991/0425/sys/src/9/port/devmnt.c /n/bootesdump/1991/0426/sys/src/9/port/devmnt.c
799d
794,795c
	if(mh->rhdr.fid!=mh->thdr.fid && mh->thdr.type!=Tclwalk){
.
439a
	nc->type = c->type;
	nc->dev = c->dev;
	nc->mode = c->mode;
	nc->flag = c->flag;
	nc->offset = c->offset;
	nc->mnt = c->mnt;
	nc->aux = c->aux;
	nc->mchan = c->mchan;
	nc->mqid = c->qid;
	nc->qid = mh->rhdr.qid;
	incref(m);
	poperror();
.
431,438c
		errors("directory entry not found");
.
428,429c
		 *  hack to indicate the most common error
.
425d
401,410d
## diffname port/devmnt.c 1991/0427
## diff -e /n/bootesdump/1991/0426/sys/src/9/port/devmnt.c /n/bootesdump/1991/0427/sys/src/9/port/devmnt.c
787c
	if(mh->rhdr.fid != mh->thdr.fid){
.
393,436d
355a
	nc->mountid = c->mountid;
.
## diffname port/devmnt.c 1991/0502
## diff -e /n/bootesdump/1991/0427/sys/src/9/port/devmnt.c /n/bootesdump/1991/0502/sys/src/9/port/devmnt.c
870a
/*XXX*/		print("chan %c %d %lux %lux\n", devchar[m->q->msg->type],
				m->q->msg->dev, m->q->msg->qid.path,
				m->q->msg->stream);	
.
789a
print("POO bad len %d %ux!\n", n, mh->mbr->buf[0]);
.
787c
		do{
			n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE, 0);
		}while(n == 0);
.
## diffname port/devmnt.c 1991/0808
## diff -e /n/bootesdump/1991/0502/sys/src/9/port/devmnt.c /n/bootesdump/1991/0808/sys/src/9/port/devmnt.c
887a
	mh->mbr = 0;
.
848a
print("%d after flush sleep %lux %lux %d %d\n", u->p->pid, mh, mh->mbr, mh->active, mh->flushing);
.
847a
print("%d interrupted queued sleep %lux %lux %d %d\n", u->p->pid, mh, mh->mbr, mh->active, mh->flushing);
.
792c
print("%d POO bad len %d %ux %lux %lux\n", u->p->pid, n, mh->mbr->buf[0], mh, mh->mbr);
.
782a
print("%d interrupted read %lux %lux\n", u->p->pid, mh, mh->mbr);
.
684a
			mh->mbr = 0;
		}
.
683c
		if(mh->mbr){
.
623a
	}
.
622c
	if(omh->thdr.type == Tflush){
		omh->flushing = 0;
.
127c
if(mh->active) print("mh->active\n");
if(mh->flushing) print("mh->flushing\n");
if(mh->mbr) print("mh->mbr\n");
		mh->mbr = 0;
.
## diffname port/devmnt.c 1991/0809
## diff -e /n/bootesdump/1991/0808/sys/src/9/port/devmnt.c /n/bootesdump/1991/0809/sys/src/9/port/devmnt.c
858d
856d
837a
		if(mh->rhdr.type != Rerror)
		if(mh->rhdr.type != w->thdr.type+1){
			print(" t%c ", devchar[m->q->msg->type]);
			goto FreeRead;
		}
.
811a
			if(mh->rhdr.type != Rerror)
			if(mh->rhdr.type != mh->thdr.type+1){
				print(" T%c ", devchar[m->q->msg->type]);
				goto FreeRead;
			}
.
800,802c
			if(1){	/* BUG? IS THIS RIGHT? IGNORE AND RETRY */
				print(" MR ");
				qlock(q);
				qlocked = 1;
				goto FreeRead;
			}else{
				mnterrdequeue(m, mh);
				error(Ebadmsg);
			}
.
790d
761a
	mh->mbr = 0;
.
## diffname port/devmnt.c 1991/0811
## diff -e /n/bootesdump/1991/0809/sys/src/9/port/devmnt.c /n/bootesdump/1991/0811/sys/src/9/port/devmnt.c
910a
if(mh->mbr->pid != u->p->pid) print("tail\n");
.
881a
}
if(mh->mbr->pid != u->p->pid) print("after promotion %d\n", mh->thdr.type);
.
880c
		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"); }
.
858a
lock(&w->r);
if(w->r.p) w->mbr->pid = w->p->pid;
unlock(&w->r);
.
851c
			print(" t%c %d %d ", devchar[m->q->msg->type],
				mh->rhdr.type, w->thdr.type+1);
.
841a
if(mh->mbr->pid != u->p->pid) print("FreeRead\n");
.
691a
if(mbw->pid != u->p->pid) print("top waserror mbw\n");
.
688a
if(mh->mbr->pid != u->p->pid) print("top waserror\n");
.
654a
{ Mnthdr *h; for(h=q->writer; h; h=h->next) if(h->p==u->p)print("reader and writer error\n"); }
.
652a
	mh->readreply = 0;
.
625a
print("flush flush\n");
.
146a
if(mh->pid != u->p->pid)print("mhfree pid %d\n", mh->flushing);
.
130a
mh->pid = u->p->pid;
.
129a
if(mh->readreply) print("mh->readreply\n");
.
111a
if(mb->pid != u->p->pid)print("mbfree pid\n");
.
95a
mb->pid = u->p->pid;
.
52a
int pid;
.
39a
int pid;
.
## diffname port/devmnt.c 1991/0812
## diff -e /n/bootesdump/1991/0811/sys/src/9/port/devmnt.c /n/bootesdump/1991/0812/sys/src/9/port/devmnt.c
932d
917,922d
901,902d
898,899c
		if(q->reader == u->p)	/* i got promoted */
.
873,875d
864c
			print(" t(%d)%c %d %d ", tag, devchar[m->q->msg->type],
.
859c
		/*
		 * Find writer in queue
		 */
		for(w=q->writer; w; w=w->next)
			if(w->thdr.tag == tag)
				goto Inqueue;
		goto FreeRead;
	Inqueue:
.
854d
851c
		if(tag<=0 || tag>NTAG){
.
832c
				print(" T(%d)%c %d %d ", tag, devchar[m->q->msg->type],
					mh->rhdr.type, mh->thdr.type+1);
.
812,820c
			/* BUG? IS THIS RIGHT? IGNORE AND RETRY */
			print(" MR ");
			qlock(q);
			qlocked = 1;
			goto FreeRead;
.
703d
699d
691c
	Mnthdr *w, *ow, *h;
.
664d
633d
239d
236,237d
234c
	for(i=0; i<conf.nmnthdr-1; i++)
.
172a
		q->tag = 0;
.
157a
	mh->active = 0;
	mh->thdr.tag = 0;
.
156d
153d
136c
		mh->thdr.tag = 1 + (incref(&mnttag) & (NTAG-1));
.
131,134d
115d
98d
87a
Ref	mnttag;
.
54d
40d
30a
	int	tag;		/* increments per message; lock Ref while changing */
.
11a
#define		NTAG	16384	/* 1 <= tag <= NTAG */

.
## diffname port/devmnt.c 1991/0813
## diff -e /n/bootesdump/1991/0812/sys/src/9/port/devmnt.c /n/bootesdump/1991/0813/sys/src/9/port/devmnt.c
935c
			print("(%lux %lux %d %d)", h, &h->r, h->thdr.tag,
				(p=h->p)? p->pid : 0);
.
857c
			print("mail rob: '%s w(%d)%c %d %d'\n",
				u->p->text, tag, devchar[m->q->msg->type],
.
818c
				print("mail rob: '%s T(%d)%c %d %d'\n", u->p->text,
					tag, devchar[m->q->msg->type],
.
686a
	if(&qlocked);	/* force qlocked not to be registerized */
.
169d
33d
## diffname port/devmnt.c 1991/0814
## diff -e /n/bootesdump/1991/0813/sys/src/9/port/devmnt.c /n/bootesdump/1991/0814/sys/src/9/port/devmnt.c
857c
			print("mail rob: '%s xxw(%d)%c %d %d'\n",
.
838c
		if(tag==0 || tag>=NTAG){
.
817c
				print("mail rob: '%s xxT(%d)%c %d %d'\n", u->p->text,
.
629c
	mh = mhalloc(m);
.
588c
	mh = mhalloc(m);
.
522c
	mh = mhalloc(m);
.
480c
	mh = mhalloc(m);
.
452c
	mh = mhalloc(m);
.
427c
	mh = mhalloc(m);
.
403c
	mh = mhalloc(m);
.
380c
	mh = mhalloc(m);
.
342c
	mh = mhalloc(m);
.
305c
	mh = mhalloc(m);
.
240a
	for(i=0; i<conf.nmntdev; i++,mq++)
		mq->next = mq+1;
	--mq;
	mq->next = 0;
.
236,238d
233c
	mnthdralloc.head = mh;
	for(i=0; i<conf.nmnthdr; i++,mh++){
		mh->seq = 0;
		mh->next = mh+1;
		mh->prev = mh-1;
	}
	--mh;
	mnthdralloc.tail = mh;
	mh->next = 0;
	mnthdralloc.head->prev = 0;
.
229,231d
226a
	for(i=0; i<conf.nmntbuf; i++,mb++)
		mb->next = mb+1;
	--mb;
	mb->next = 0;
.
223,225d
219a
	if(conf.nmnthdr > 512){
		print("conf.nmnthdr is %d set to 512\n", conf.nmnthdr);
		conf.nmnthdr = 512;
	}
.
153,154c
	mh->next = 0;
	mh->prev = mnthdralloc.tail;
	if(mnthdralloc.tail)
		mnthdralloc.tail->next = mh;
	else
		mnthdralloc.head = mh;
	mnthdralloc.tail = mh;
.
132a
		mh->mbr = 0;
		seq = ++mh->seq;
		if(seq == (1<<7)){
			mh->seq = 1;
			seq = 1;
		}
		mh->thdr.tag = (((mh-mnthdralloc.arena)<<7)|seq) & (NTAG-1);
.
128,131c
	if(mh = mnthdralloc.head){		/* assign = */
		mnthdralloc.head = mh->next;
		if(mnthdralloc.head)
			mnthdralloc.head->prev = 0;
		else
			mnthdralloc.tail = 0;
.
124a
	int seq;
.
122c
mhalloc(Mnt *m)
.
88d
69c
	Mnthdr	*head;
	Mnthdr	*tail;
.
55,56c
	char	active;
	char	flushing;	/* a Tflush has been sent */
	short	seq;
.
12c
#define		NTAG	65536	/*  1 <= tag < NTAG */
.
## diffname port/devmnt.c 1991/0901
## diff -e /n/bootesdump/1991/0814/sys/src/9/port/devmnt.c /n/bootesdump/1991/0901/sys/src/9/port/devmnt.c
968a

void
mntdump(void)
{
}

.
957,967c
int
rpcattn(Mntrpc *r)
{
	return r->done || r->m->rip == 0;
.
952,955c
	dirbuf[DIRLEN-4] = devchar[c->type];
	dirbuf[DIRLEN-3] = 0;
	dirbuf[DIRLEN-2] = c->dev;
	dirbuf[DIRLEN-1] = c->dev>>8;
}
.
950c
mntdirfix(uchar *dirbuf, Chan *c)
.
933,946c
	return m;
.
926,931c
Mnt *
mntchk(Chan *c)
{
	Mnt *m;

	m = &mntalloc.mntarena[c->mntindex];
	if(m->id != c->dev)
.
924a
	unlock(m);
}
.
823,923c
		l = &f->list;
.
807,821c
}

void
mntfree(Mntrpc *r)
{
	Mntrpc *q;
	Mnt *m, *e;
	int i;

	r->bfree = 1;
	if(r->flushed)
		return;

	lock(&mntalloc);
	r->list = mntalloc.rpcfree;
	mntalloc.rpcfree = r;
	unlock(&mntalloc);
}

void
mntqrm(Mnt *m, Mntrpc *r)
{
	Mntrpc **l, *f;

	lock(m);
	r->done = 1;
	r->flushed = 0;

	l = &m->queue;
	for(f = *l; f; f = f->list) {
		if(f == r) {
			*l = r->list;
			break;
.
796,805c
	for(;;) {
		lock(&mntalloc);
		if(new = mntalloc.rpcfree) {
			mntalloc.rpcfree = new->list;
			unlock(&mntalloc);
			new->done = 0;
			new->bfree = 0;
			return new;
		}
		unlock(&mntalloc);
		resrcwait("no mount buffers");
.
785,794c
Mntrpc *
mntralloc(void)
{
	Mntrpc *new;
.
771,783c
	(*devtab[m->c->type].write)(m->c, r->flush, n, 0);
	poperror();
	lock(m);
	if(!r->done)
		r->flushed = 1;
	unlock(m);
	return 1;
}
.
764,769c
	r->flushtag++;
	if((r->flushtag-r->flushbase) == Flushspace)
		r->flushtag -= Flushspace;

	flush.type = Tflush;
	flush.tag = r->flushtag;
	flush.oldtag = r->request.tag;
	n = convS2M(&flush, r->flush);

	if(waserror()) {
		if(strcmp(u->error, errstrtab[Eintr]) == 0)
			return 1;
		mntqrm(m, r);
		return 0;
.
759,762c
int
mntflush(Mnt *m, Mntrpc *r)
{
	Fcall flush;
	int n;
.
746,757c
}
.
741,744d
736,739c
dispatch:
	if(q != r) {		/* Completed someone else */
		dp = q->rpc;
		q->rpc = r->rpc;
		r->rpc = dp;
		memmove(&q->reply, &r->reply, sizeof(Fcall));
		wakeup(&q->r);					
.
724,734c
	unlock(m);
	return;
.
721,722c
		if(q->flushtag == r->reply.tag) {
			*l = q->list;
			q->flushed = 0;
			done = q->done;
			q->done = 1;
			unlock(m);
			if(done == 0) {
				r->reply.type = Rerror;
				strcpy(r->reply.ename, errstrtab[Eintr]);
				goto dispatch;
			}
			if(q->bfree)
				mntfree(q);
			return;
		}
		l = &q->list;
.
713,719c
	lock(m);
	l = &m->queue;
	for(q = *l; q; q = q->list) {
		if(q->request.tag == r->reply.tag) {
			if(q->flushed == 0)
				*l = q->list;
			q->done = 1;
			unlock(m);
			goto dispatch;
.
707,711c
	Mntrpc **l, *q;
	int done;
	char *dp;
.
705c
mountmux(Mnt *m, Mntrpc *r)
.
701c
	Mntrpc *q;

	lock(m);
	m->rip = 0;
	for(q = m->queue; q; q = q->list)
		if(q->done == 0) {
			lock(&q->r);
			if(q->r.p) {
				unlock(&q->r);
				unlock(m);
				wakeup(&q->r);
				return;
			}
			unlock(&q->r);
		}
	unlock(m);
.
698,699c
void
mntgate(Mnt *m)
.
692,695c
		n = (*devtab[m->c->type].read)(m->c, r->rpc, MAXRPC, 0);
		poperror();
		if(n == 0)
			continue;
		if(convM2S(r->rpc, &r->reply, n) != 0)
			break;
	}
.
677,690c
	for(;;) {
		if(waserror()) {
			if(mntflush(m, r) == 0) {
				if(m->mux == 0)
					mntgate(m);
				nexterror();
			}
			continue;
.
674,675c
	int n;
.
672c
mntrpcread(Mnt *m, Mntrpc *r)
.
663,668c
	m->rip = u->p;
	unlock(m);

	while(r->done == 0) {
		mntrpcread(m, r);
		mountmux(m, r);
	}
	mntgate(m);
.
657,661c
	/* Gate readers onto the mount point one at a time */
	for(;;) {
		lock(m);
		if(m->rip == 0)
			break;
		unlock(m);
		if(waserror()) {
			if(mntflush(m, r) == 0)
				nexterror();
			continue;
		}
		sleep(&r->r, rpcattn, r);
		poperror();
		if(r->done)
			return;
.
652,653c
	lock(m);
	r->m = m;
	r->list = m->queue;
	m->queue = r;
	unlock(m);

	/* Transmit a file system rpc */
	n = convS2M(&r->request, r->rpc);
	if(waserror()) {
		mntqrm(m, r);
		nexterror();
	}
	if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n)
		error(Eshortmsg);
	poperror();

	if(m->mux) {
		mntrpcread(m, r);
.
650c
	int n;
.
648c
mountio(Mnt *m, Mntrpc *r)
.
643,646d
632,639c
	mountio(m, r);
	if(r->reply.type == Rerror)
		errors(r->reply.ename);
	if(r->reply.type != r->request.type+1) {
		print("devmnt: mismatched reply T%d R%d tags req %d fls %d rep %d\n",
		r->request.type, r->reply.type, r->request.tag, r->flushtag, r->reply.tag);
			errors("protocol error");
.
630c
mountrpc(Mnt *m, Mntrpc *r)
.
626a
	mntfree(r);
	return cnt;
.
621,625c
	r->request.type = type;
	r->request.fid = c->fid;
	r->request.offset = offset;
	uba = buf;
	for(cnt = 0; n; n -= nr) {
		r->request.data = uba;
		r->request.count = limit(n, MAXFDATA);
		mountrpc(m, r);
		nr = r->reply.count;
		if(type == Tread)
			memmove(uba, r->reply.data, nr);
		r->request.offset += nr;
		uba += nr;
		cnt += nr;
		if(nr != r->request.count)
			break;
	}
.
615,618c
	r = mntralloc();
	m = mntchk(c);
	if(waserror()) {
		mntfree(r);
.
613c
	Mntrpc *r;
	ulong cnt, nr;
	char *uba;
.
606,611d
603,604c
long
mntrdwr(int type, Chan *c, void *buf, long n, ulong offset)
.
600c
	return mntrdwr(Twrite, c, buf, n, offset);	
.
583,593c
	n = mntrdwr(Tread, c, buf, n, offset);
	if(c->qid.path & CHDIR) 
		for(p = (uchar*)buf, e = &p[n]; p < e; p += DIRLEN)
			mntdirfix(p, c);

.
580,581c
	uchar *p, *e;
.
574c
	mntfree(r);
.
555,572c
	r->request.type = Twstat;
	r->request.fid = c->fid;
	memmove(r->request.stat, dp, DIRLEN);
	mountrpc(m, r);
.
547,552c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
.
543,545c
	Mntrpc *r;
.
541a
	mntclunk(c, Tremove);
}

void
mntwstat(Chan *c, char *dp)
{
.
539,540c
void	 
mntremove(Chan *c)
.
507,530c
	r->request.type = t;
	r->request.fid = c->fid;
	mountrpc(m, r);
	nexterror();
.
503,505c
	Mntrpc *r, *n, *q;
		
	m = mntchk(c);
	r = mntralloc();
	if(waserror()){
		mntfree(r);
		if(decref(m) == 0) {
			for(q = m->queue; q; q = r) {
				r = q->list;
				q->flushed = 0;
				mntfree(q);
			}
			m->id = 0;
			close(m->c);
			lock(&mntalloc);
			m->list = mntalloc.mntfree;
			mntalloc.mntfree = m;
			unlock(&mntalloc);
		}
		return;
	}
.
496c
	poperror();
	mntfree(r);
.
485,493c
	r->request.type = Tcreate;
	r->request.fid = c->fid;
	r->request.mode = omode;
	r->request.perm = perm;
	strncpy(r->request.name, name, NAMELEN);
	mountrpc(m, r);

	c->qid = r->reply.qid;
.
479,482c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
.
477c
	Mntrpc *r;
.
469a
	poperror();
	mntfree(r);
.
460,466c
	r->request.type = Topen;
	r->request.fid = c->fid;
	r->request.mode = omode;
	mountrpc(m, r);

	c->qid = r->reply.qid;
.
454,457c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
.
452c
	Mntrpc *r;
.
445a
	mntfree(r);
.
436,444c
	r->request.type = Tstat;
	r->request.fid = c->fid;
	mountrpc(m, r);

	memmove(dp, r->reply.stat, DIRLEN);
	mntdirfix((uchar*)dp, c);
.
430,433c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
.
428c
	Mntrpc *r;
.
419,421c
	mntfree(r);
	return 1;
.
416,417c
	r->request.type = Twalk;
	r->request.fid = c->fid;
	strncpy(r->request.name, name, NAMELEN);
	mountrpc(m, r);

	c->qid = r->reply.qid;

.
406,414c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
		return 0;
.
403,404c
	Mntrpc *r;
.
395a

	poperror();
	mntfree(r);
.
391,394d
388d
375,378c

	r->request.type = Tclone;
	r->request.fid = c->fid;
	r->request.newfid = nc->fid;
	mountrpc(m, r);

.
372c
		mntfree(r);
		if(alloc)
			close(nc);
.
369,370d
363,367c
		alloc = 1;
.
360,361c
	m = mntchk(c);
	r = mntralloc();
	if(nc == 0) {
.
357,358c
	Mntrpc *r;
	int alloc = 0;
.
349a
	mntfree(r);
.
348d
339,346c
	r->request.type = Tattach;
	r->request.fid = c->fid;
	memmove(r->request.uname, u->p->pgrp->user, NAMELEN);
	strncpy(r->request.aname, spec, NAMELEN);
	strncpy(r->request.auth, auth, NAMELEN);
	mountrpc(m, r);

	c->qid = r->reply.qid;
	c->mchan = m->c;
.
335c
		mntfree(r);
.
331,333c
Chan *
mattach(Mnt *m, char *spec, char *auth)
{
	Chan *c;
	Mntrpc *r;

	r = mntralloc();

	c = devattach('M', spec);
	c->dev = m->id;
	c->mntindex = m-mntalloc.mntarena;

.
313,329c
	return mattach(m, bogus.spec, bogus.auth);
}
.
304,311d
302a
	m->queue = 0;
	m->rip = 0;
	m->c = bogus.chan;

	switch(devchar[m->c->type]) {
	case 'H':			/* Hotrod */
	case '3':			/* BIT3 */
		m->mux = 1;
		break;
	default:
		m->mux = 0;
	}
	incref(m->c);
.
299,301c
	lock(&mntalloc);
	if(mntalloc.mntfree == 0) {
		unlock(&mntalloc);
		error(Enomntdev);
	}
	m = mntalloc.mntfree;
	mntalloc.mntfree = m->list;	
	m->id = mntalloc.id++;
	lock(m);
	unlock(&mntalloc);
.
290,297c
	bogus = *((struct bogus *)muxattach);
	e = &mntalloc.mntarena[conf.nmntdev];
	for(m = mntalloc.mntarena; m < e; m++) {
		if(m->c == bogus.chan && m->id) {
			lock(m);
			if(m->ref > 0 && m->id && m->c == bogus.chan) {
				m->ref++;
				unlock(m);
				return mattach(m, bogus.spec, bogus.auth);
			}
			unlock(m);	
		}
.
279,283c
	Mnt *m, *e;
.
277c
mntattach(char *muxattach)
.
229,271d
212,227d
193,209c
	mntalloc.id = 1;
.
190,191c
	re[-1].list = 0;
.
156,188c
	tag = Tagspace;
	ftag = Flushtag;
	mntalloc.rpcfree = ialloc(conf.nmntbuf*sizeof(Mntrpc), 0);
	re = &mntalloc.rpcfree[conf.nmntbuf];
	for(rd = mntalloc.rpcfree; rd < re; rd++) {
		rd->list = rd+1;
		rd->request.tag = tag++;
		rd->flushbase = ftag;
		rd->flushtag = ftag;
		ftag += Flushspace;
		rd->rpc = ialloc(MAXRPC, 0);
.
146,154d
128,144c
	if(conf.nmntbuf > Flushtag) {
		print("devmnt: buffers limited to %d\n", Flushtag);
		conf.nmntbuf = Flushtag;
.
122,126c
	mntalloc.mntarena = ialloc(conf.nmntdev*sizeof(Mnt), 0);
	mntalloc.mntfree = mntalloc.mntarena;
	me = &mntalloc.mntfree[conf.nmntdev];
	for(md = mntalloc.mntfree; md < me; md++)
		md->list = md+1;
	me[-1].list = 0;
.
116,120c
	Mnt *me, *md;
	Mntrpc *re, *rd;
	ushort tag, ftag;
.
114c
mntreset(void)
.
82,112d
76,80c
	Tagspace = 1,
	Flushspace = 64,
	Flushtag = 512,
};
.
74c
enum
.
66,72c
Chan 	*mattach(Mnt*, char*, char*);
Mntrpc	*mntralloc(void);
void	mntfree(Mntrpc*);
int	rpcattn(Mntrpc*);
void	mountrpc(Mnt*, Mntrpc*);
void	mountio(Mnt*, Mntrpc*);
Mnt	*mntchk(Chan*);
void	mountmux(Mnt*, Mntrpc*);
long	mntrdwr(int , Chan*, void*,long , ulong);
int	mntflush(Mnt*, Mntrpc*);
void	mntqrm(Mnt*, Mntrpc*);
void	mntdirfix(uchar*, Chan*);
void	mntgate(Mnt*);
void	mntrpcread(Mnt*, Mntrpc*);
.
51,64c
#define BITBOTCH	256
#define MAXRPC		(MAXFDATA+MAXMSG+BITBOTCH)
#define limit(n, max)	(n > max ? max : n)
.
48,49c
	Mnt	*mntfree;
	Mnt	*mntarena;
	Mntrpc	*rpcfree;
	int	id;
}mntalloc;
.
41,46d
36,39c
struct Mntalloc
.
28,33c
	Ref;			/* Count of attached channels */
	Chan	*c;		/* Channel to file service */
	Proc	*rip;		/* Reader in progress */
	Mntrpc	*queue;		/* Queue of pending requests on this channel */
	int	id;		/* Multiplexor id for channel check */
	Mnt	*list;		/* Free list */
	char	mux;		/* Set if the device aleady does the multiplexing */
.
26c
struct Mnt
.
20,23c
	Mntrpc	*list;		/* Free/pending list */
	Fcall	request;	/* Outgoing file system protocol message */
	Fcall	reply;		/* Incoming reply */
	Mnt	*m;		/* Mount device during rpc */
	Rendez	r;		/* Place to hang out */
	char	*rpc;		/* I/O Data buffer */
	char	done;		/* Rpc completed */
	char	bfree;		/* Buffer may be freed after flush */
	char	flushed;	/* Flush was sent */
	ushort	flushtag;	/* Tag to send flush on */
	ushort	flushbase;	/* Base tag of flush window for this buffer */
	char	flush[MAXMSG];	/* Somewhere to build flush */
.
14,18c
struct Mntrpc
.
12c
typedef struct Mntrpc Mntrpc;
typedef struct Mnt Mnt;
.
9d
7d
## diffname port/devmnt.c 1991/0904
## diff -e /n/bootesdump/1991/0901/sys/src/9/port/devmnt.c /n/bootesdump/1991/0904/sys/src/9/port/devmnt.c
732a
	for(i=0; i<conf.nmntdev; i++){
		q = &mntqalloc.arena[i];
		if(!q->msg)
			continue;
		p = q->reader;
		print("q rdr %d wrtr ", p? p->pid : 0);
		for(h=q->writer; h; h=h->next)
			print("(%lux %lux %d %d)", h, &h->r, h->thdr.tag,
				(p=h->p)? p->pid : 0);
		print("\n");
	}
}
.
731c
	int i;
	MntQ *q;
	Mnthdr *h;
	Proc *p;
.
714,728d
710c
	}
	/*
	 * Copy out on read
	 */
	if(mh->thdr.type == Tread){
		if(mh->rhdr.count > mh->thdr.count)
			error(Ebadcnt);
		memmove(mh->thdr.data, mh->rhdr.data, mh->rhdr.count);
	}
	mbfree(mh->mbr);
	mh->mbr = 0;
	mbfree(mbw);
	USED(qlocked);
	poperror();		/* 1 */
.
702,708c
    Respond:
	mqfree(q);
	poperror();		/* 2 */
	if(mh->rhdr.type == Rerror){
		if(m->mntpt)
			errors(mh->rhdr.ename);
.
699,700d
697c
		mh->mbr = mballoc();
		do{
			n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE, 0);
		}while(n == 0);
		poperror();		/* 3 */
		if(convM2S(mh->mbr->buf, &mh->rhdr, n) == 0){
			/* BUG? IS THIS RIGHT? IGNORE AND RETRY */
			print(" MR ");
			qlock(q);
			qlocked = 1;
			goto FreeRead;
		}
		/*
		 * Response might not be mine
		 */
		USED(qlocked);
		qlock(q);
		qlocked = 1;
		tag = mh->rhdr.tag;
		if(tag == mh->thdr.tag){	/* it's mine */
			if(mh->rhdr.type != Rerror)
			if(mh->rhdr.type != mh->thdr.type+1){
				print("mail rob: '%s xxT(%d)%c %d %d'\n", u->p->text,
					tag, devchar[m->q->msg->type],
					mh->rhdr.type, mh->thdr.type+1);
				goto FreeRead;
			}
			q->reader = 0;
			if(w = q->writer){	/* advance a writer to reader */
				mntwunlink(q, w);
				q->reader = w->p;
				w->readreply = 1;
				wakeup(&w->r);
			}
			mh->active = 0;
			USED(qlocked);
			qunlock(q);
			qlocked = 0;
			goto Respond;
		}
		/*
		 * Hand response to correct recipient
		 */
		if(tag==0 || tag>=NTAG){
			print("unknown tag %d\n", tag);
	FreeRead:
			mbfree(mh->mbr);
			mh->mbr = 0;
			goto Read;
		}
		/*
		 * Find writer in queue
		 */
		for(w=q->writer; w; w=w->next)
			if(w->thdr.tag == tag)
				goto Inqueue;
		goto FreeRead;
	Inqueue:
		if(w->flushing || !w->active)	/* nothing to do; mntflush will clean up */
			goto FreeRead;
		if(mh->rhdr.type != Rerror)
		if(mh->rhdr.type != w->thdr.type+1){
			print("mail rob: '%s xxw(%d)%c %d %d'\n",
				u->p->text, tag, devchar[m->q->msg->type],
				mh->rhdr.type, w->thdr.type+1);
			goto FreeRead;
		}
		w->mbr = mh->mbr;
		mh->mbr = 0;
		memmove(&w->rhdr, &mh->rhdr, sizeof mh->rhdr);
		mntwunlink(q, w);
		w->readreply = 1;
		wakeup(&w->r);
		goto Read;
	}else{
		mh->p = u->p;
		/* put self in queue */
		mh->next = q->writer;
		mh->prev = 0;
		if(q->writer)
			q->writer->prev = mh;
		q->writer = mh;
		qunlock(q);
		qlocked = 0;
		if(waserror()){		/* interrupted sleep */
			mnterrdequeue(m, mh);
			nexterror();
		}
		sleep(&mh->r, mntreadreply, mh);
		poperror();
		USED(qlocked);
		qlock(q);
		qlocked = 1;
		mh->readreply = 0;
		if(q->reader == u->p)	/* i got promoted */
			goto Read;
		mh->active = 0;
		USED(qlocked);
		qunlock(q);
		qlocked = 0;
		goto Respond;
.
672,695c
    Normal:
#endif
	incref(q);
	qlock(q);
	qlocked = 1;
	if(waserror()){		/* 2 */
		if(qlocked)
			qunlock(q);
		mqfree(q);
		nexterror();
	}
	mh->readreply = 0;
	mh->active = 1;
	if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n, 0) != n){
		print("short write in mntxmit\n");
		error(Eshortmsg);
	}
	if(q->reader == 0){		/* i will read */
		q->reader = u->p;
    Read:
		USED(qlocked);
		qunlock(q);
		qlocked = 0;
		if(waserror()){		/* 3 */
			mnterrdequeue(m, mh);
			nexterror();
.
665,670c
	/*
	 * Copy out on read
	 */
	if(mh->thdr.type == Tread)
		memmove(mh->thdr.data, mh->rhdr.data, mh->rhdr.count);
	mbfree(mh->mbr);
	mh->mbr = 0;
	mbfree(mbw);
	poperror();		/* 1 */
	return;
.
663c
	if(mh->rhdr.type == Rerror){
		if(m->mntpt)
			errors(mh->rhdr.ename);
		error(Eshutdown);
	}
	if(mh->rhdr.type != mh->thdr.type+1){
		print("type mismatch %d %d\n", mh->rhdr.type, mh->thdr.type+1);
		error(Ebadmsg);
	}
	if(mh->rhdr.fid != mh->thdr.fid){
		print("fid mismatch %d %d type %d\n", mh->rhdr.fid, mh->thdr.fid, mh->rhdr.type);
		error(Ebadmsg);
	}
.
646,661c
	/*
	 * Various checks
	 */
	if(mh->rhdr.tag != mh->thdr.tag){
		print("tag mismatch %d %d\n", mh->rhdr.tag, mh->thdr.tag);
		error(Ebadmsg);
.
637,644d
616,635c
	if(convM2S(mh->mbr->buf, &mh->rhdr, n) == 0){
		print("format error in mntxmit\n");
		error(Ebadmsg);
.
614c
	/*
	 * Read response
	 */
	if(waserror()){		/* 3 */
		mntflush(m, mh);
		nexterror();
	}
	mh->mbr = mballoc();
	n = (*devtab[q->msg->type].read)(q->msg, mh->mbr->buf, BUFSIZE, 0);
	poperror();		/* 3 */
	mqfree(q);
	poperror();		/* 2 */
.
612a
	if((*devtab[q->msg->type].write)(q->msg, mbw->buf, n, 0) != n){
		print("short write in mntxmit\n");
		error(Eshortmsg);
	}
.
605,611c
	incref(q);
	if(waserror()){		/* 2 */
		mqfree(q);
		nexterror();
.
602,603c
	n = convS2M(&mh->thdr, mbw->buf);
	q = m->q;
	if(q == 0)
		error(Eshutdown);
#ifdef	BIT3
	/*
	 * Bit3 and Hotrod do their own multiplexing.  (Well, the file server does.)
	 * The code is different enough that it's broken out separately here.
	 */
	if(devchar[q->msg->type]!='3' && devchar[q->msg->type]!='H')
		goto Normal;
.
585,600c
		mbfree(mbw);
		nexterror();
.
575,583c
	if(&qlocked);	/* force qlocked not to be registerized */
	mh->mbr = 0;
	mbw = mballoc();
	if(waserror()){			/* 1 */
		if(mh->mbr){
			mbfree(mh->mbr);
			mh->mbr = 0;
.
571,573c
	ulong n;
	Mntbuf *mbw;
	Mnthdr *w, *ow, *h;
	MntQ *q;
	int qlocked, tag, written;
.
569c
mntxmit(Mnt *m, Mnthdr *mh)
.
550,565c
	return ((Mnthdr *)a)->readreply;
.
547,548c
int
mntreadreply(void *a)
.
538,544c
	}else
		mntwunlink(q, mh);
	qunlock(q);
	mntflush(m, mh);
.
529,536c
	mh->flushing = 1;
	q = m->q;
	qlock(q);
	mh->readreply = 0;
	/* take self from queue if necessary */
	if(q->reader == u->p){	/* advance a writer to reader */
		w = q->writer;
		if(w){
			mntwunlink(q, w);
			q->reader = w->p;
			wakeup(&w->r);
		}else{
			q->reader = 0;
			q->writer = 0;
.
527c
	Mnthdr *w;
	MntQ *q;
.
525c
mnterrdequeue(Mnt *m, Mnthdr *mh)	/* queue is unlocked */
.
514,521c
	mh->thdr.type = Tflush;
	mh->thdr.oldtag = omh->thdr.tag;
	mntxmit(m, mh);
	omh->flushing = 0;
	mhfree(mh);
	poperror();
.
498,512c
	mh = mhalloc(m);
	if(waserror()){
		omh->flushing = 0;
		mhfree(mh);
		return;		/* no more errors please */
.
477,494c
	if(omh->thdr.type == Tflush){
		omh->flushing = 0;
.
475c
	Mnthdr *mh;
.
473c
mntflush(Mnt *m, Mnthdr *omh)	/* queue is unlocked */
.
471a
/*
 * m->q is unlocked.  Send Tflush message to flush omh->tag.
 * Cut off all errors.   Caller will free omh
 */
.
463,468c
	if(w->next)
		w->next->prev = w->prev;
	if(w->prev)
		w->prev->next = w->next;
	else{
		q->writer = w->next;
		if(q->writer)
			q->writer->prev = 0;
.
461c
mntwunlink(MntQ *q, Mnthdr *w)		/* queue is locked and w is a writer */
.
456,457d
438,454c
	mh->thdr.type = Twstat;
	mh->thdr.fid = c->fid;
	memmove(mh->thdr.stat, dp, DIRLEN);
	mntxmit(m, mh);
	mhfree(mh);
.
432,435c
	m = mntdev(c, 0);
	mh = mhalloc(m);
	if(waserror()){
		mhfree(mh);
.
428,430c
	Mnthdr *mh;
.
426a
	mntclunk(c, Tremove);
}

void
mntwstat(Chan *c, char *dp)
{
.
424,425c
void	 
mntremove(Chan *c)
.
421c
	return mntreadwrite(c, buf, n, Twrite, offset);
.
410,414c
	n = mntreadwrite(c, buf, n, Tread, offset);
	if(c->qid.path & CHDIR){
		b = (uchar*)buf;
		for(i=n-DIRLEN; i>=0; i-=DIRLEN){
			b[DIRLEN-4] = devchar[c->type];
			b[DIRLEN-3] = 0;
			b[DIRLEN-2] = c->dev;
			b[DIRLEN-1] = c->dev>>8;
			b += DIRLEN;
		}
	}
.
408c
	long i;
	uchar *b;
.
402c
	return count;
.
397,400c
	mh->thdr.type = type;
	mh->thdr.fid = c->fid;
    Loop:
	nt = n;
	if(nt > MAXFDATA)
		nt = MAXFDATA;
	mh->thdr.offset = offset;
	mh->thdr.count = nt;
	mh->thdr.data = buf;
	mntxmit(m, mh);
	nr = mh->rhdr.count;
	offset += nr;
	count += nr;
	buf += nr;
	n -= nr;
	if(n && nr==nt)
		goto Loop;
	mhfree(mh);
.
391,394c
	buf = vbuf;
	count = 0;
	m = mntdev(c, 0);
	mh = mhalloc(m);
	if(waserror()){
		mhfree(mh);
.
389c
	Mnthdr *mh;
	long nt, nr, count;
	char *buf;
.
382,387d
379,380c
long
mntreadwrite(Chan *c, void *vbuf, long n, int type, ulong offset)
.
367,370c
	m = mntdev(c, 0);
	mh = mhalloc(m);
	mh->thdr.type = t;
	mh->thdr.fid = c->fid;
	waserr = 0;
	if(waserror())		/* gotta clean up as if there wasn't */
		waserr = 1;
	else
		mntxmit(m, mh);
	mhfree(mh);
	if(c == m->mntpt)
		m->mntpt = 0;
	lock(m);
	if(--m->ref == 0){		/* BUG: need to hang up all pending i/o */
		q = m->q;
		m->q = 0;
		m->mntid = 0;
		unlock(m);		/* mqfree can take time */
		mqfree(q);
	}else
		unlock(m);
	if(waserr)
		nexterror();
	poperror();
.
345,365c
	Mnthdr *mh;
	MntQ *q;
	int waserr;
.
337,338c
	c->qid = mh->rhdr.qid;
.
327,334c
	mh->thdr.type = Tcreate;
	mh->thdr.fid = c->fid;
	strcpy(mh->thdr.name, name);
	mh->thdr.mode = omode;
	mh->thdr.perm = perm;
	mntxmit(m, mh);
	c->qid = mh->rhdr.qid;
	mhfree(mh);
	poperror();
.
321,324c
	m = mntdev(c, 0);
	mh = mhalloc(m);
	if(waserror()){
		mhfree(mh);
.
319c
	Mnthdr *mh;
.
310,311d
301,306c
	mh->thdr.type = Topen;
	mh->thdr.fid = c->fid;
	mh->thdr.mode = omode;
	mntxmit(m, mh);
	c->qid = mh->rhdr.qid;
	mhfree(mh);
	poperror();
.
295,298c
	m = mntdev(c, 0);
	mh = mhalloc(m);
	if(waserror()){
		mhfree(mh);
.
293c
	Mnthdr *mh;
.
286d
279,284c
	mh->thdr.type = Tstat;
	mh->thdr.fid = c->fid;
	mntxmit(m, mh);
	memmove(dp, mh->rhdr.stat, DIRLEN);
	dp[DIRLEN-4] = devchar[c->type];
	dp[DIRLEN-3] = 0;
	dp[DIRLEN-2] = c->dev;
	dp[DIRLEN-1] = c->dev>>8;
	mhfree(mh);
.
273,276c
	m = mntdev(c, 0);
	mh = mhalloc(m);
	if(waserror()){
		mhfree(mh);
.
271c
	Mnthdr *mh;
.
263,264c
    Out:
	mhfree(mh);
	return found;
.
255,261c
	mntxmit(m, mh);
	c->qid = mh->rhdr.qid;
.
249,253c
	found = 1;
	m = mntdev(c, 0);
	mh = mhalloc(m);
	mh->thdr.type = Twalk;
	mh->thdr.fid = c->fid;
	strcpy(mh->thdr.name, name);
	if(waserror()){	/* BUG: can check type of error? */
		found = 0;
		goto Out;
.
247c
	Mnthdr *mh;
	int found;
.
239c
	if(new)
		poperror();
	incref(m);
.
236,237c
	mhfree(mh);
.
233a
	nc->mntindex = c->mntindex;
.
219,224c
	mh->thdr.type = Tclone;
	mh->thdr.fid = c->fid;
	mh->thdr.newfid = nc->fid;
	mntxmit(m, mh);
.
214,216c
		mhfree(mh);
.
212a
	m = mntdev(c, 0);
	mh = mhalloc(m);
.
211c
		new = 1;
		if(waserror()){
			close(nc);
			nexterror();
		}
.
207,209c
	new = 0;
	if(nc == 0){
.
204,205c
	Mnthdr *mh;
	int new;
.
196d
194a
	mhfree(mh);
.
185,193c
	mh->thdr.type = Tattach;
	mh->thdr.fid = c->fid;
	memmove(mh->thdr.uname, u->p->pgrp->user, NAMELEN);
	strcpy(mh->thdr.aname, bogus.spec);
	strcpy(mh->thdr.auth, bogus.auth);
	mntxmit(m, mh);
	c->qid = mh->rhdr.qid;
	c->mchan = m->q->msg;
.
181c
		mhfree(mh);
.
168,179c
    out:
	qunlock(&mntqalloc);
	mh = mhalloc(m);
.
165,166c
	/*
	 * Look for queue to same msg channel
	 */
	q = mntqalloc.arena;
	qlock(&mntqalloc);
	for(i=0; i<conf.nmntdev; i++,q++)
		if(q->msg==cm){
			lock(q);
			if(q->ref && q->msg==cm){
				m->q = q;
				q->ref++;
				unlock(q);
				goto out;
			}
			unlock(q);
		}
	m->q = mqalloc(cm);
.
163a
	lock(&mntid);
	m->mntid = ++mntid.id;
	unlock(&mntid);
	c = devattach('M', bogus.spec);
	c->dev = m->mntid;
	c->mntindex = m-mnt;
	m->mntpt = c;
	cm = bogus.chan;
.
162c
	error(Enomntdev);

    Found:
	m->ref = 1;
.
154,160c
	m = mnt;
	for(i=0; i<conf.nmntdev; i++,m++){
		lock(m);
		if(m->ref == 0)
			goto Found;
		unlock(m);
.
126,152c
	bogus = *((struct bogus *)crud);
.
119c
	int i;
	Mnt *m, *mm;
	Mnthdr *mh;
	MntQ *q;
	Chan *c, *cm;
.
117c
mntattach(char *crud)
.
111a
mntreset(void)
{
	int i;
	Mntbuf *mb;
	Mnthdr *mh;
	MntQ *mq;

	if(conf.nmnthdr > 512){
		print("conf.nmnthdr is %d set to 512\n", conf.nmnthdr);
		conf.nmnthdr = 512;
	}
	mnt = ialloc(conf.nmntdev*sizeof(Mnt), 0);

	mb = ialloc(conf.nmntbuf*sizeof(Mntbuf), 0);
	mntbufalloc.free = mb;
	for(i=0; i<conf.nmntbuf; i++,mb++)
		mb->next = mb+1;
	--mb;
	mb->next = 0;

	mh = ialloc(conf.nmnthdr*sizeof(Mnthdr), 0);
	mnthdralloc.arena = mh;
	mnthdralloc.head = mh;
	for(i=0; i<conf.nmnthdr; i++,mh++){
		mh->seq = 0;
		mh->next = mh+1;
		mh->prev = mh-1;
	}
	--mh;
	mnthdralloc.tail = mh;
	mh->next = 0;
	mnthdralloc.head->prev = 0;

	mq = ialloc(conf.nmntdev*sizeof(MntQ), 0);
	mntqalloc.arena = mq;
	mntqalloc.free = mq;
	for(i=0; i<conf.nmntdev; i++,mq++)
		mq->next = mq+1;
	--mq;
	mq->next = 0;
}

void
.
110a
Mnt*
mntdev(Chan *c, int noerr)
{
	Mnt *m;
	int i;

	m = &mnt[c->mntindex];
	if(m->mntid==c->dev && m->q!=0)
		return m;
	if(noerr)
		return 0;
	print("mntdev shutdown %d %d %d %lux\n", c->dev, c->mntindex,
			m->mntid, m->q);
	error(Eshutdown);
}

.
108c
void
mqfree(MntQ *mq)
{
	Chan *msg = 0;

	lock(mq);
	if(--mq->ref == 0){
		msg = mq->msg;
		mq->msg = 0;
		lock(&mntqalloc);
		mq->next = mntqalloc.free;
		mntqalloc.free = mq;
		unlock(&mntqalloc);
	}
	unlock(mq);
	if(msg)		/* after locks are down */
		close(msg);
.
106c
	panic("no mntqs\n");			/* there MUST be enough */
}
.
94,104c
void
mhfree(Mnthdr *mh)
{
	if(mh->flushing)
		return;
	lock(&mnthdralloc);
	mh->active = 0;
	mh->thdr.tag = 0;
	mh->next = 0;
	mh->prev = mnthdralloc.tail;
	if(mnthdralloc.tail)
		mnthdralloc.tail->next = mh;
	else
		mnthdralloc.head = mh;
	mnthdralloc.tail = mh;
	unlock(&mnthdralloc);
}

MntQ*
mqalloc(Chan *msg)	/* mntqalloc is qlocked */
{
	MntQ *q;

	if(q = mntqalloc.free){		/* assign = */
		mntqalloc.free = q->next;
		lock(q);
		q->ref = 1;
		q->msg = msg;
		unlock(q);
		incref(msg);
		q->writer = 0;
		q->reader = 0;
		return q;
.
92a
	unlock(&mnthdralloc);
	print("no mnthdrs\n");
	if(u == 0)
		panic("mhalloc");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
}
.
89,91c
loop:
	lock(&mnthdralloc);
	if(mh = mnthdralloc.head){		/* assign = */
		mnthdralloc.head = mh->next;
		if(mnthdralloc.head)
			mnthdralloc.head->prev = 0;
		else
			mnthdralloc.tail = 0;
		unlock(&mnthdralloc);
		mh->mbr = 0;
		seq = ++mh->seq;
		if(seq == (1<<7)){
			mh->seq = 1;
			seq = 1;
		}
		mh->thdr.tag = (((mh-mnthdralloc.arena)<<7)|seq) & (NTAG-1);
		return mh;
.
82,87c
Mnthdr*
mhalloc(Mnt *m)
{
	Mnthdr *mh;
	int seq;
.
78,80c
	lock(&mntbufalloc);
	mb->next = mntbufalloc.free;
	mntbufalloc.free = mb;
	unlock(&mntbufalloc);
}
.
76c
mbfree(Mntbuf *mb)
.
74a
struct
{
	Lock;
	long	id;
}mntid;

Mnt	*mnt;
void	mntxmit(Mnt*, Mnthdr*);

Mntbuf*
mballoc(void)
{
	Mntbuf *mb;

loop:
	lock(&mntbufalloc);
	if(mb = mntbufalloc.free){		/* assign = */
		mntbufalloc.free = mb->next;
		unlock(&mntbufalloc);
		return mb;
	}
	unlock(&mntbufalloc);
	print("no mntbufs\n");
	if(u == 0)
		panic("mballoc");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
}

.
70,73c
	Lock;
	QLock;
	MntQ	*arena;
	MntQ	*free;
}mntqalloc;
.
68c
struct
.
53,66c
struct
{
	Lock;
	Mnthdr	*arena;
	Mnthdr	*head;
	Mnthdr	*tail;
}mnthdralloc;
.
49,51c
struct Mnthdr
{
	Mnthdr	*next;		/* in free list or writers list */
	Mnthdr	*prev;		/* in writers list only */
	char	active;
	char	flushing;	/* a Tflush has been sent */
	short	seq;
	Fcall	thdr;
	Fcall	rhdr;
	Rendez	r;
	Proc	*p;
	Mntbuf	*mbr;
	int	readreply;	/* true if we are reader or our reply has come */
};
.
43,47c
	Mntbuf	*free;
}mntbufalloc;
.
41a
	Mntbuf	*next;
	char	buf[BUFSIZE+BITROUND]; 	/* BUG */
};

struct
{
.
40c
#define	BITROUND 256
#define	BUFSIZE	(MAXFDATA+MAXMSG)
typedef struct Mntbuf Mntbuf;
struct Mntbuf
.
31,37c
	Ref;
	QLock;			/* for access */
	MntQ	*next;		/* for allocation */
	Chan	*msg;		/* for reading and writing messages */
	Proc	*reader;	/* process reading response */
	Mnthdr	*writer;	/* queue of headers of written messages */
.
29c
struct MntQ
.
15,26c
	Ref;			/* for number of chans, incl. mntpt but not msg */
	ulong	mntid;		/* serial # */
	Chan	*mntpt;		/* channel in user's name space */
	MntQ	*q;
.
13c
typedef struct Mnt	Mnt;
typedef struct Mnthdr	Mnthdr;
typedef struct MntQ	MntQ;

struct Mnt
.
10,11c
#define		NTAG	65536	/*  1 <= tag < NTAG */
.
7a

.
6a

.
## diffname port/devmnt.c 1991/0910
## diff -e /n/bootesdump/1991/0904/sys/src/9/port/devmnt.c /n/bootesdump/1991/0910/sys/src/9/port/devmnt.c
964,965c
			print("(%lux %lux %d)", h, &h->r, (p=h->p)? p->pid : 0);
.
932a
	}else if(mh->rhdr.type != mh->thdr.type+1){
		print("bad type %d not %d in mntxmit\n", mh->rhdr.type, mh->thdr.type+1);
/*XXX*/		print("chan %c %d %lux %lux\n", devchar[m->q->msg->type],
				m->q->msg->dev, m->q->msg->qid.path,
				m->q->msg->stream);	
		error(Ebadmsg);
.
916d
885,887c
			print(" t%c ", devchar[m->q->msg->type]);
.
873,880c
		w = &mnthdralloc.arena[tag];
.
866c
		if(tag<0 || tag>=conf.nmnthdr){
.
845,847c
				print(" T%c ", devchar[m->q->msg->type]);
.
829,833c
			if(1){	/* BUG? IS THIS RIGHT? IGNORE AND RETRY */
				print(" MR ");
				qlock(q);
				qlocked = 1;
				goto FreeRead;
			}else{
				mnterrdequeue(m, mh);
				error(Ebadmsg);
			}
.
713d
709c
	Mnthdr *w, *ow;
.
680d
657c
	mh = mhalloc();
.
616c
	mh = mhalloc();
.
550c
	mh = mhalloc();
.
508c
	mh = mhalloc();
.
480c
	mh = mhalloc();
.
455c
	mh = mhalloc();
.
431c
	mh = mhalloc();
.
408c
	mh = mhalloc();
.
370c
	mh = mhalloc();
.
333c
	mh = mhalloc();
.
265,268d
262a
	for(i=0; i<conf.nmntdev-1; i++)
		mq[i].next = &mq[i+1];
	mq[i].next = 0;
.
257,260c
	mh[i].next = 0;
	mh[i].thdr.tag = i;
	mnthdralloc.arena = mh;
	mnthdralloc.free = mh;
.
250,255c
	for(i=0; i<conf.nmnthdr-1; i++){
		mh[i].next = &mh[i+1];
		mh[i].thdr.tag = i;
.
244,247d
242a
	for(i=0; i<conf.nmntbuf-1; i++)
		mb[i].next = &mb[i+1];
	mb[i].next = 0;
.
236,239d
163,170c
	lock(&mnthdralloc);
	mh->next = mnthdralloc.free;
	mnthdralloc.free = mh;
.
161d
138,143c
		unlock(&mnthdralloc);
.
130,136c
	if(mh = mnthdralloc.free){		/* assign = */
		mnthdralloc.free = mh->next;
if(mh->active) print("mh->active\n");
if(mh->flushing) print("mh->flushing\n");
if(mh->mbr) print("mh->mbr\n");
.
126d
123c
mhalloc(void)
.
70,71c
	Mnthdr	*free;
.
55,57c
	short	active;
	short	flushing;	/* a Tflush has been sent */
.
12,13d
## diffname port/devmnt.c 1991/0911
## diff -e /n/bootesdump/1991/0910/sys/src/9/port/devmnt.c /n/bootesdump/1991/0911/sys/src/9/port/devmnt.c
936a

.
935a
	print("rpcfree 0x%lux\n", mntalloc.rpcfree);
	re = &mntalloc.rpcarena[conf.nmntbuf];
	for(r = mntalloc.rpcarena; r < re; r++) 
		print("%.8lux %.8lux T%d R%d tags req %d fls %d rep %d d %d b %d f %d\n",
			r, r->list, r->request.type, r->reply.type,
			r->request.tag, r->flushtag, r->reply.tag, 
			r->done, r->bfree, r->flushed);

.
930,934c
		print("mount %d: mux %d queue %lux rip 0x%lux %d %s\n", m->id, m->mux, m->queue,
			m->rip,
			m->rip ? m->rip->pid : 0, m->rip ? m->rip->text : "no");
.
926,928c
	me = &mntalloc.mntarena[conf.nmntdev];
	for(m = mntalloc.mntarena; m < me; m++) {
		if(m->ref == 0)
.
921,924c
	Mnt *me, *m;
	Mntrpc *re, *r;
.
918a
mntdirfix(uchar *dirbuf, Chan *c)
{
	dirbuf[DIRLEN-4] = devchar[c->type];
	dirbuf[DIRLEN-3] = 0;
	dirbuf[DIRLEN-2] = c->dev;
	dirbuf[DIRLEN-1] = c->dev>>8;
}

int
rpcattn(Mntrpc *r)
{
	return r->done || r->m->rip == 0;
}

void
.
896,915c
	return m;
.
889,894c
Mnt *
mntchk(Chan *c)
{
	Mnt *m;

	m = &mntalloc.mntarena[c->mntindex];
	if(m->id != c->dev)
.
887a
	unlock(m);
}
.
794,886c
		l = &f->list;
.
778,792c
}

void
mntfree(Mntrpc *r)
{
	Mntrpc *q;
	Mnt *m, *e;
	int i;

	r->bfree = 1;
	if(r->flushed)
		return;

	lock(&mntalloc);
	r->list = mntalloc.rpcfree;
	mntalloc.rpcfree = r;
	unlock(&mntalloc);
}

void
mntqrm(Mnt *m, Mntrpc *r)
{
	Mntrpc **l, *f;

	lock(m);
	r->done = 1;
	r->flushed = 0;

	l = &m->queue;
	for(f = *l; f; f = f->list) {
		if(f == r) {
			*l = r->list;
			break;
.
767,776c
	for(;;) {
		lock(&mntalloc);
		if(new = mntalloc.rpcfree) {
			mntalloc.rpcfree = new->list;
			unlock(&mntalloc);
			new->done = 0;
			new->bfree = 0;
			return new;
		}
		unlock(&mntalloc);
		resrcwait("no mount buffers");
.
756,765c
Mntrpc *
mntralloc(void)
{
	Mntrpc *new;
.
742,754c
	qlock(&m->c->wrl);
	(*devtab[m->c->type].write)(m->c, r->flush, n, 0);
	qunlock(&m->c->wrl);
	poperror();
	lock(m);
	if(!r->done)
		r->flushed = 1;
	unlock(m);
	return 1;
}
.
735,740c
	flush.type = Tflush;
	flush.tag = r->flushtag;
	flush.oldtag = r->request.tag;
	n = convS2M(&flush, r->flush);

	if(waserror()) {
		qunlock(&m->c->wrl);
		if(strcmp(u->error, errstrtab[Eintr]) == 0)
			return 1;
		mntqrm(m, r);
		return 0;
.
730,733c
	r->flushtag++;
	if((r->flushtag-r->flushbase) == Flushspace)
		r->flushtag -= Flushspace;
.
717,728c
int
mntflush(Mnt *m, Mntrpc *r)
{
	Fcall flush;
	int n;
.
712,715c
}
.
707,710c
dispatch:
	if(q != r) {		/* Completed someone else */
		dp = q->rpc;
		q->rpc = r->rpc;
		r->rpc = dp;
		memmove(&q->reply, &r->reply, sizeof(Fcall));
		wakeup(&q->r);
.
695,705c
	unlock(m);
	return;
.
692,693c
		if(q->flushtag == r->reply.tag) {
			*l = q->list;
			q->flushed = 0;
			done = q->done;
			q->done = 1;
			unlock(m);
			if(done == 0)
				goto dispatch;
			if(q->bfree)
				mntfree(q);
			return;
		}
		l = &q->list;
.
685,690c
	lock(m);
	l = &m->queue;
	for(q = *l; q; q = q->list) {
		if(q->request.tag == r->reply.tag) {
			if(q->flushed == 0)
				*l = q->list;
			q->done = 1;
			unlock(m);
			goto dispatch;
.
679,683c
	Mntrpc **l, *q;
	int done;
	char *dp;
.
677c
mountmux(Mnt *m, Mntrpc *r)
.
673c
	Mntrpc *q;

	lock(m);
	m->rip = 0;
	for(q = m->queue; q; q = q->list)
		if(q->done == 0) {
			lock(&q->r);
			if(q->r.p) {
				unlock(&q->r);
				unlock(m);
				wakeup(&q->r);
				return;
			}
			unlock(&q->r);
		}
	unlock(m);
.
670,671c
void
mntgate(Mnt *m)
.
664,667c
		qlock(&m->c->rdl);
		r->reply.type = 0;
		r->reply.tag = 0;
		n = (*devtab[m->c->type].read)(m->c, r->rpc, MAXRPC, 0);
		qunlock(&m->c->rdl);
		poperror();
		if(n == 0)
			continue;
		if(convM2S(r->rpc, &r->reply, n) != 0)
			return;
	}
.
650,662c
	for(;;) {
		if(waserror()) {
			qunlock(&m->c->rdl);
			if(mntflush(m, r) == 0) {
				if(m->mux == 0)
					mntgate(m);
				nexterror();
			}
			continue;
.
647,648c
	int n;
.
645c
mntrpcread(Mnt *m, Mntrpc *r)
.
636,641c
	m->rip = u->p;
	unlock(m);
	while(r->done == 0) {
		mntrpcread(m, r);
		mountmux(m, r);
	}
	mntgate(m);
.
630,634c
	/* Gate readers onto the mount point one at a time */
	for(;;) {
		lock(m);
		if(m->rip == 0)
			break;
		unlock(m);
		if(waserror()) {
			if(mntflush(m, r) == 0)
				nexterror();
			continue;
		}
		sleep(&r->r, rpcattn, r);
		poperror();
		if(r->done)
			return;
.
625,626c
	lock(m);
	r->m = m;
	r->list = m->queue;
	m->queue = r;
	unlock(m);

	/* Transmit a file system rpc */
	n = convS2M(&r->request, r->rpc);
	if(waserror()) {
		qunlock(&m->c->wrl);
		mntqrm(m, r);
		nexterror();
	}
	qlock(&m->c->wrl);
	if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n)
		error(Eshortmsg);
	qunlock(&m->c->wrl);
	poperror();

	if(m->mux) {
		mntqrm(m, r);
		mntrpcread(m, r);
.
623c
	int n;
.
621c
mountio(Mnt *m, Mntrpc *r)
.
616,619d
605,612c
	r->reply.tag = 0;		/* safety check */
	mountio(m, r);
	if(r->reply.type == Rerror)
		errors(r->reply.ename);
	if(r->reply.type == Rflush)
		errors(errstrtab[Eintr]);

	if(r->reply.type != r->request.type+1) {
		print("devmnt: mismatched reply 0x%lux T%d R%d tags req %d fls %d rep %d\n",
			r, r->request.type, r->reply.type,
			r->request.tag, r->flushtag, r->reply.tag);
		errors("protocol error");
.
603c
mountrpc(Mnt *m, Mntrpc *r)
.
594,599c
	return cnt;
.
588,592c
	m = mntchk(c);
	uba = buf;
	for(cnt = 0; n; n -= nr) {
		r = mntralloc();
		if(waserror()) {
			mntfree(r);
			nexterror();
		}
		r->request.type = type;
		r->request.fid = c->fid;
		r->request.offset = offset;
		r->request.data = uba;
		r->request.count = limit(n, MAXFDATA);
		mountrpc(m, r);
		nr = r->reply.count;
		if(type == Tread)
			memmove(uba, r->reply.data, nr);
		poperror();
		mntfree(r);
		offset += nr;
		uba += nr;
		cnt += nr;
		if(nr != r->request.count)
			break;
.
586c
	Mntrpc *r;
	ulong cnt, nr;
	char *uba;
.
579,584d
576,577c
long
mntrdwr(int type, Chan *c, void *buf, long n, ulong offset)
.
573c
	return mntrdwr(Twrite, c, buf, n, offset);	
.
556,566c
	n = mntrdwr(Tread, c, buf, n, offset);
	if(c->qid.path & CHDIR) 
		for(p = (uchar*)buf, e = &p[n]; p < e; p += DIRLEN)
			mntdirfix(p, c);

.
553,554c
	uchar *p, *e;
.
547c
	mntfree(r);
.
528,545c
	r->request.type = Twstat;
	r->request.fid = c->fid;
	memmove(r->request.stat, dp, DIRLEN);
	mountrpc(m, r);
.
520,525c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
.
516,518c
	Mntrpc *r;
.
514a
	mntclunk(c, Tremove);
}

void
mntwstat(Chan *c, char *dp)
{
.
512,513c
void	 
mntremove(Chan *c)
.
480,503c
	r->request.type = t;
	r->request.fid = c->fid;
	mountrpc(m, r);
	nexterror();
.
476,478c
	Mntrpc *r, *n, *q;
		
	m = mntchk(c);
	r = mntralloc();
	if(waserror()){
		mntfree(r);
		if(decref(m) == 0) {
			for(q = m->queue; q; q = r) {
				r = q->list;
				q->flushed = 0;
				mntfree(q);
			}
			m->id = 0;
			close(m->c);
			lock(&mntalloc);
			m->list = mntalloc.mntfree;
			mntalloc.mntfree = m;
			unlock(&mntalloc);
		}
		return;
	}
.
469c
	poperror();
	mntfree(r);
.
458,466c
	r->request.type = Tcreate;
	r->request.fid = c->fid;
	r->request.mode = omode;
	r->request.perm = perm;
	strncpy(r->request.name, name, NAMELEN);
	mountrpc(m, r);

	c->qid = r->reply.qid;
.
452,455c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
.
450c
	Mntrpc *r;
.
442a
	poperror();
	mntfree(r);
.
433,439c
	r->request.type = Topen;
	r->request.fid = c->fid;
	r->request.mode = omode;
	mountrpc(m, r);

	c->qid = r->reply.qid;
.
427,430c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
.
425c
	Mntrpc *r;
.
418a
	mntfree(r);
.
409,417c
	r->request.type = Tstat;
	r->request.fid = c->fid;
	mountrpc(m, r);

	memmove(dp, r->reply.stat, DIRLEN);
	mntdirfix((uchar*)dp, c);
.
403,406c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
.
401c
	Mntrpc *r;
.
392,394c
	mntfree(r);
	return 1;
.
389,390c
	r->request.type = Twalk;
	r->request.fid = c->fid;
	strncpy(r->request.name, name, NAMELEN);
	mountrpc(m, r);

	c->qid = r->reply.qid;

.
379,387c
	m = mntchk(c);
	r = mntralloc();
	if(waserror()) {
		mntfree(r);
		return 0;
.
376,377c
	Mntrpc *r;
.
368a

	poperror();
	mntfree(r);
.
364,367d
361d
348,351c

	r->request.type = Tclone;
	r->request.fid = c->fid;
	r->request.newfid = nc->fid;
	mountrpc(m, r);

.
345c
		mntfree(r);
		if(alloc)
			close(nc);
.
342,343d
336,340c
		alloc = 1;
.
333,334c
	m = mntchk(c);
	r = mntralloc();
	if(nc == 0) {
.
330,331c
	Mntrpc *r;
	int alloc = 0;
.
322a
	mntfree(r);
.
321d
312,319c
	r->request.type = Tattach;
	r->request.fid = c->fid;
	memmove(r->request.uname, u->p->pgrp->user, NAMELEN);
	strncpy(r->request.aname, spec, NAMELEN);
	strncpy(r->request.auth, auth, NAMELEN);
	mountrpc(m, r);

	c->qid = r->reply.qid;
	c->mchan = m->c;
.
308c
		mntfree(r);
.
304,306c
Chan *
mattach(Mnt *m, char *spec, char *auth)
{
	Chan *c;
	Mntrpc *r;

	r = mntralloc();

	c = devattach('M', spec);
	c->dev = m->id;
	c->mntindex = m-mntalloc.mntarena;

.
286,302c
	return mattach(m, bogus.spec, bogus.auth);
}
.
277,284d
275a
	m->queue = 0;
	m->rip = 0;
	m->c = bogus.chan;

	switch(devchar[m->c->type]) {
	case 'H':			/* Hotrod */
	case '3':			/* BIT3 */
		m->mux = 1;
		break;
	default:
		m->mux = 0;
	}
	incref(m->c);
.
272,274c
	lock(&mntalloc);
	if(mntalloc.mntfree == 0) {
		unlock(&mntalloc);
		error(Enomntdev);
	}
	m = mntalloc.mntfree;
	mntalloc.mntfree = m->list;	
	m->id = mntalloc.id++;
	lock(m);
	unlock(&mntalloc);
.
263,270c
	bogus = *((struct bogus *)muxattach);
	e = &mntalloc.mntarena[conf.nmntdev];
	for(m = mntalloc.mntarena; m < e; m++) {
		if(m->c == bogus.chan && m->id) {
			lock(m);
			if(m->ref > 0 && m->id && m->c == bogus.chan) {
				m->ref++;
				unlock(m);
				return mattach(m, bogus.spec, bogus.auth);
			}
			unlock(m);	
		}
.
252,256c
	Mnt *m, *e;
.
250c
mntattach(char *muxattach)
.
211,244d
194,209d
175,191c
	mntalloc.id = 1;
.
172,173c
	re[-1].list = 0;
.
144,170c
	tag = Tagspace;
	ftag = Flushtag;
	mntalloc.rpcfree = ialloc(conf.nmntbuf*sizeof(Mntrpc), 0);
	mntalloc.rpcarena = mntalloc.rpcfree;
	re = &mntalloc.rpcfree[conf.nmntbuf];
	for(rd = mntalloc.rpcfree; rd < re; rd++) {
		rd->list = rd+1;
		rd->request.tag = tag++;
		rd->flushbase = ftag;
		rd->flushtag = ftag;
		ftag += Flushspace;
		rd->rpc = ialloc(MAXRPC, 0);
.
134,142d
123,132c
	if(conf.nmntbuf > Flushtag) {
		print("devmnt: buffers limited to %d\n", Flushtag);
		conf.nmntbuf = Flushtag;
.
118,121c
	mntalloc.mntarena = ialloc(conf.nmntdev*sizeof(Mnt), 0);
	mntalloc.mntfree = mntalloc.mntarena;
	me = &mntalloc.mntfree[conf.nmntdev];
	for(md = mntalloc.mntfree; md < me; md++)
		md->list = md+1;
	me[-1].list = 0;
.
112,116c
	Mnt *me, *md;
	Mntrpc *re, *rd;
	ushort tag, ftag;
.
110c
mntreset(void)
.
78,108d
72,76c
	Tagspace = 1,
	Flushspace = 64,
	Flushtag = 512,
};
.
70c
enum
.
63,68c
Chan 	*mattach(Mnt*, char*, char*);
Mntrpc	*mntralloc(void);
void	mntfree(Mntrpc*);
int	rpcattn(Mntrpc*);
void	mountrpc(Mnt*, Mntrpc*);
void	mountio(Mnt*, Mntrpc*);
Mnt	*mntchk(Chan*);
void	mountmux(Mnt*, Mntrpc*);
long	mntrdwr(int , Chan*, void*,long , ulong);
int	mntflush(Mnt*, Mntrpc*);
void	mntqrm(Mnt*, Mntrpc*);
void	mntdirfix(uchar*, Chan*);
void	mntgate(Mnt*);
void	mntrpcread(Mnt*, Mntrpc*);
.
49,61c
#define BITBOTCH	256
#define MAXRPC		(MAXFDATA+MAXMSG+BITBOTCH)
#define limit(n, max)	(n > max ? max : n)
.
46,47c
	Mnt	*mntfree;
	Mnt	*mntarena;
	Mntrpc	*rpcfree;
	Mntrpc	*rpcarena;
	int	id;
}mntalloc;
.
39,44d
34,37c
struct Mntalloc
.
26,31c
	Ref;			/* Count of attached channels */
	Chan	*c;		/* Channel to file service */
	Proc	*rip;		/* Reader in progress */
	Mntrpc	*queue;		/* Queue of pending requests on this channel */
	int	id;		/* Multiplexor id for channel check */
	Mnt	*list;		/* Free list */
	char	mux;		/* Set if the device aleady does the multiplexing */
.
24c
struct Mnt
.
18,21c
	Mntrpc	*list;		/* Free/pending list */
	Fcall	request;	/* Outgoing file system protocol message */
	Fcall	reply;		/* Incoming reply */
	Mnt	*m;		/* Mount device during rpc */
	Rendez	r;		/* Place to hang out */
	char	*rpc;		/* I/O Data buffer */
	char	done;		/* Rpc completed */
	char	bfree;		/* Buffer may be freed after flush */
	char	flushed;	/* Flush was sent */
	ushort	flushtag;	/* Tag to send flush on */
	ushort	flushbase;	/* Base tag of flush window for this buffer */
	char	flush[MAXMSG];	/* Somewhere to build flush */
.
16c
struct Mntrpc
.
12,14c
typedef struct Mntrpc Mntrpc;
typedef struct Mnt Mnt;
.
9d
7d
## diffname port/devmnt.c 1991/0912
## diff -e /n/bootesdump/1991/0911/sys/src/9/port/devmnt.c /n/bootesdump/1991/0912/sys/src/9/port/devmnt.c
474,475c
		r, r->request.type, r->reply.type, r->request.tag, r->flushtag, r->reply.tag);
.
## diffname port/devmnt.c 1991/0918
## diff -e /n/bootesdump/1991/0912/sys/src/9/port/devmnt.c /n/bootesdump/1991/0918/sys/src/9/port/devmnt.c
722c
	/* Was it closed and reused ? */
	if(m->id == 0 || m->id >= c->dev)
.
179c
	lock(&mntalloc);
	c->dev = mntalloc.id++;
	unlock(&mntalloc);
.
## diffname port/devmnt.c 1991/0924
## diff -e /n/bootesdump/1991/0918/sys/src/9/port/devmnt.c /n/bootesdump/1991/0924/sys/src/9/port/devmnt.c
367a
		mntfree(r);
.
354d
## diffname port/devmnt.c 1991/0925
## diff -e /n/bootesdump/1991/0924/sys/src/9/port/devmnt.c /n/bootesdump/1991/0925/sys/src/9/port/devmnt.c
499,504c
	else {
		qlock(&m->c->wrl);
		if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n)
			error(Eshortmsg);
		qunlock(&m->c->wrl);
		poperror();
	}
.
496,497c
		if(mntflush(m, r) == 0)
			nexterror();
.
367d
355a
if(q->flushed == 0)
print("mail philw: %lux: not flushed\n", q);
.
353a
		mntfree(r);
.
## diffname port/devmnt.c 1991/0926
## diff -e /n/bootesdump/1991/0925/sys/src/9/port/devmnt.c /n/bootesdump/1991/0926/sys/src/9/port/devmnt.c
450c
		r->request.count = limit(n, m->blocksize);
.
154a
	m->blocksize = MAXFDATA;
.
37a
	int	blocksize;	/* read/write block size */
.
## diffname port/devmnt.c 1991/1004
## diff -e /n/bootesdump/1991/0926/sys/src/9/port/devmnt.c /n/bootesdump/1991/1004/sys/src/9/port/devmnt.c
378c
	mntdoclunk(m, r);
	poperror();
}

void
mntdoclunk(Mnt *m, Mntrpc *r)
{
	Mntrpc *q;

	mntfree(r);
	if(decref(m) == 0) {
		for(q = m->queue; q; q = r) {
			r = q->list;
			q->flushed = 0;
			mntfree(q);
		}
		m->id = 0;
		close(m->c);
		lock(&mntalloc);
		m->list = mntalloc.mntfree;
		mntalloc.mntfree = m;
		unlock(&mntalloc);
	}
.
356,372c
		mntdoclunk(m, r);
		nexterror();
.
351c
	Mntrpc *r;
.
68a
void	mntdoclunk(Mnt *, Mntrpc *);
.
## diffname port/devmnt.c 1991/1011
## diff -e /n/bootesdump/1991/1004/sys/src/9/port/devmnt.c /n/bootesdump/1991/1011/sys/src/9/port/devmnt.c
664,666c
	if(m->mux)
		(*devtab[m->c->type].write)(m->c, r->flush, n, 0);
	else {
		qlock(&m->c->wrl);
		(*devtab[m->c->type].write)(m->c, r->flush, n, 0);
		qunlock(&m->c->wrl);
	}
.
658c
		if(!m->mux)
			qunlock(&m->c->wrl);
.
567,568c
		if(m->mux) 
			n = (*devtab[m->c->type].read)(m->c, r->rpc, MAXRPC, 0);
		else {
			qlock(&m->c->rdl);
			n = (*devtab[m->c->type].read)(m->c, r->rpc, MAXRPC, 0);
			qunlock(&m->c->rdl);
		}
.
564d
556c
			if(!m->mux)
				qunlock(&m->c->rdl);
.
512,515c
		if(m->mux) {
			if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n)
				error(Eshortmsg);
		}
		else {
			qlock(&m->c->wrl);
			if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n)
				error(Eshortmsg);
			qunlock(&m->c->wrl);
		}
.
507c
		if(!m->mux)
			qunlock(&m->c->wrl);
.
156a
	m->c->flag |= CMSG;
.
## diffname port/devmnt.c 1991/1105
## diff -e /n/bootesdump/1991/1011/sys/src/9/port/devmnt.c /n/bootesdump/1991/1105/sys/src/9/port/devmnt.c
195c
	memmove(r->request.uname, u->p->user, NAMELEN);
.
## diffname port/devmnt.c 1992/0111
## diff -e /n/bootesdump/1991/1105/sys/src/9/port/devmnt.c /n/bootesdump/1992/0111/sys/src/9/port/devmnt.c
673c
		if(strcmp(u->error, Eintr) == 0)
.
485c
		error(Eintr);
.
6c
#include	"../port/error.h"
.
## diffname port/devmnt.c 1992/0112
## diff -e /n/bootesdump/1992/0111/sys/src/9/port/devmnt.c /n/bootesdump/1992/0112/sys/src/9/port/devmnt.c
483c
		error(r->reply.ename);
.
## diffname port/devmnt.c 1992/0113
## diff -e /n/bootesdump/1992/0112/sys/src/9/port/devmnt.c /n/bootesdump/1992/0113/sys/src/9/port/devmnt.c
521c
				error(Emountrpc);
.
516c
				error(Emountrpc);
.
490c
		error(Emountrpc);
.
## diffname port/devmnt.c 1992/0114
## diff -e /n/bootesdump/1992/0113/sys/src/9/port/devmnt.c /n/bootesdump/1992/0114/sys/src/9/port/devmnt.c
146c
		exhausted("mount devices");
.
## diffname port/devmnt.c 1992/0301
## diff -e /n/bootesdump/1992/0114/sys/src/9/port/devmnt.c /n/bootesdump/1992/0301/sys/src/9/port/devmnt.c
108c
		rd->rpc = ialloc(i, 0);
.
101a

	/* Align mount buffers to 256 byte boundaries so we can use burst mode vme transfers */
	p = (ulong)ialloc(0, 0);
	if(p&(ALIGN-1))
		ialloc(ALIGN-(p&(ALIGN-1)), 0);

	i = MAXRPC+(ALIGN-1);
	i &= ~(ALIGN-1);

.
83a
	ulong p;
	int i;
.
75a

	ALIGN = 256,		/* Vme block mode alignment */
.
## diffname port/devmnt.c 1992/0305
## diff -e /n/bootesdump/1992/0301/sys/src/9/port/devmnt.c /n/bootesdump/1992/0305/sys/src/9/port/devmnt.c
809c
			r->done, r->flushed);
.
806c
		print("%.8lux %.8lux T%d R%d tags req %d fls %d rep %d d %d f %d\n",
.
728,735d
717c
			new->flushed = 0;
.
699,702d
674,676c
	lock(m);
	r->flushtag = m->flushtag++;
	if(m->flushtag == Tagend)
		m->flushtag = m->flushbase;
	r->flushed = 1;
	unlock(m);
.
656,665d
647,650c
			if(q != r) {		/* Completed someone else */
				dp = q->rpc;
				q->rpc = r->rpc;
				r->rpc = dp;
				memmove(&q->reply, &r->reply, sizeof(Fcall));
				q->done = 1;
				wakeup(&q->r);
			}else
				q->done = 1;
.
643,645d
634,641c
		if(q->request.tag == r->reply.tag
		|| q->flushed && q->flushtag == r->reply.tag) {
.
628d
512a
	r->flushed = 0;
.
502a
		mntdump();
.
493a
	r->reply.type = 4;		/* safety check */
.
123a
	for(md = mntalloc.mntfree; md < me; md++){
		md->list = md+1;
		md->flushbase = tag;
		md->flushtag = tag;
	}
	me[-1].list = 0;
.
118,120d
114a
	tag = Tagspace;
.
96,102d
92,94d
85c
	ushort tag;
.
74,75c
	Tagend = 0xfffe,
.
38a
	ushort	flushtag;	/* Tag to send flush on */
	ushort	flushbase;	/* Base tag of flush window for this buffer */
.
24,25c
	ushort	flushtag;	/* Tag flush sent on */
.
22d
## diffname port/devmnt.c 1992/0312
## diff -e /n/bootesdump/1992/0305/sys/src/9/port/devmnt.c /n/bootesdump/1992/0312/sys/src/9/port/devmnt.c
251a
	USED(alloc);
.
203d
193a
	if(*serv && !waserror()){
		r->request.type = Tauth;
		r->request.fid = c->fid;
		memmove(r->request.uname, u->p->user, NAMELEN);
		chal[0] = 1;
		for(i = 1; i < sizeof chal; i++)
			chal[i++] = nrand(256);
		memmove(r->request.chal, chal, 8);
		strncpy(r->request.chal+8, serv, NAMELEN);
		encrypt(u->p->pgrp->crypt->key, r->request.chal, 8+NAMELEN);
		mountrpc(m, r);
		decrypt(u->p->pgrp->crypt->key, r->reply.chal, 2*8+2*DESKEYLEN);
		chal[0] = 4;
		if(memcmp(chal, r->reply.chal, 8) != 0)
			error(Eperm);
		memmove(r->request.auth, r->reply.chal+8+DESKEYLEN, 8+DESKEYLEN);
		poperror();
	}else
		memset(r->request.auth, 0, sizeof r->request.auth);

.
184a
	char chal[8];
	int i;
.
181c
mattach(Mnt *m, char *spec, char *serv)
.
177c
	return mattach(m, bogus.spec, bogus.serv);
.
144c
				return mattach(m, bogus.spec, bogus.serv);
.
133c
		char	*serv;
.
## diffname port/devmnt.c 1992/0313
## diff -e /n/bootesdump/1992/0312/sys/src/9/port/devmnt.c /n/bootesdump/1992/0313/sys/src/9/port/devmnt.c
519d
## diffname port/devmnt.c 1992/0314
## diff -e /n/bootesdump/1992/0313/sys/src/9/port/devmnt.c /n/bootesdump/1992/0314/sys/src/9/port/devmnt.c
216,220d
206,212c
		if(waserror())
			memset(r->request.auth, 0, sizeof r->request.auth);
		else{
			mountrpc(m, r);
			poperror();
			decrypt(u->p->pgrp->crypt->key, r->reply.chal, 2*8+2*DESKEYLEN);
			chal[0] = 4;
			if(memcmp(chal, r->reply.chal, 8) != 0)
				error(Eperm);
			memmove(r->request.auth, r->reply.chal+8+DESKEYLEN, 8+DESKEYLEN);
		}
		r->done = 0;
		r->flushed = 0;
.
196c
	if(waserror()){
		mntfree(r);
		close(c);
		nexterror();
	}

	if(*serv){
.
189d
## diffname port/devmnt.c 1992/0315
## diff -e /n/bootesdump/1992/0314/sys/src/9/port/devmnt.c /n/bootesdump/1992/0315/sys/src/9/port/devmnt.c
108c
		rd->rpc = iallocspan(MAXRPC, ALIGN, 0);
.
96,103c
	/*
	 *  Align mount buffers to 256 byte boundaries
	 *  so we can use burst mode vme transfers
	 */
.
## diffname port/devmnt.c 1992/0317
## diff -e /n/bootesdump/1992/0315/sys/src/9/port/devmnt.c /n/bootesdump/1992/0317/sys/src/9/port/devmnt.c
168a
	case 'H':			/* Cyclone */
		m->mux = 1;
		break;
.
163,166d
## diffname port/devmnt.c 1992/0318
## diff -e /n/bootesdump/1992/0317/sys/src/9/port/devmnt.c /n/bootesdump/1992/0318/sys/src/9/port/devmnt.c
793,794c
		print("mount %d: mux %d queue %lux rip 0x%lux %d %s\n", 
			m->id, m->mux, m->queue, m->rip,
.
235a
void
mntauth(Mnt *m, Mntrpc *f, char *serv, ushort fid)
{
	Mntrpc *r;
	uchar chal[CHLEN];
	int i;

	r = mntralloc();
	if(waserror()) {
		mntfree(r);
		return;
	}

	r->request.type = Tauth;
	r->request.fid = fid;
	memmove(r->request.uname, u->p->user, NAMELEN);
	chal[0] = FScchal;
	for(i = 1; i < CHLEN; i++)
		chal[i++] = nrand(256);

	memmove(r->request.chal, chal, CHLEN);
	strncpy(r->request.chal+CHLEN, serv, NAMELEN);
	encrypt(u->p->pgrp->crypt->key, r->request.chal, CHLEN+NAMELEN);

	mountrpc(m, r);
	decrypt(u->p->pgrp->crypt->key, r->reply.chal, 2*CHLEN+2*DESKEYLEN);
	chal[0] = FSctick;
	poperror();
	if(memcmp(chal, r->reply.chal, CHLEN) != 0) {
		mntfree(r);
		error(Eperm);
	}
	memmove(f->request.auth, r->reply.chal+CHLEN+DESKEYLEN, CHLEN+DESKEYLEN);
	mntfree(r);
}

.
221a

.
196,220c
	memset(r->request.auth, 0, sizeof r->request.auth);
	if(*serv)
		mntauth(m, r, serv, c->fid);
.
180,181d
164a
		break;
.
161a
	/* If we have a stream based protocol (TCP/IP) we push fcall to block
	 * up P9 protocol messages into single deliminted blocks
	 */
	s = m->c->stream;
	qi = qinfofind("fcall");
	if(s)
	if(s->procq->next)
	if(s->procq->next->info->nodelim) {
		if(qi == 0)
			error(Ebadctl);
		pushq(s, qi);
	}

.
125a
	Stream *s;
	Qinfo *qi;
.
69a
void	mntauth(Mnt *, Mntrpc *, char *, ushort);
.
## diffname port/devmnt.c 1992/0320
## diff -e /n/bootesdump/1992/0318/sys/src/9/port/devmnt.c /n/bootesdump/1992/0320/sys/src/9/port/devmnt.c
446a
}

void
mntpntfree(Mnt *m)
{
	lock(&mntalloc);
	m->list = mntalloc.mntfree;
	mntalloc.mntfree = m;
	unlock(&mntalloc);
.
442,445c
		mntpntfree(m);
.
215d
207c
		/* Close must not be called since it will call mnt recursively */
		chanfree(c);
.
189c
	if(waserror()) {
		close(m->c);
		mntpntfree(m);
		nexterror();
	}

	/* If we have a stream based protocol (TCP/IP) we push fcall to block
	 * up P9 protocol messages into single deliminted blocks
	 */
	s = m->c->stream;
	qi = qinfofind("fcall");
	if(s)
	if(s->procq->next)
	if(s->procq->next->info->nodelim) {
		if(qi == 0)
			error(Ebadctl);
		pushq(s, qi);
	}
	c = mattach(m, bogus.spec, bogus.serv);
	poperror();
	return c;
.
165,176d
140c
			if(m->id && m->ref > 0 && m->c == bogus.chan) {
.
128a
	Chan *c;
.
70a
void	mntpntfree(Mnt*);
.
## diffname port/devmnt.c 1992/0321
## diff -e /n/bootesdump/1992/0320/sys/src/9/port/devmnt.c /n/bootesdump/1992/0321/sys/src/9/port/devmnt.c
2c
#include	"../port/lib.h"
.
## diffname port/devmnt.c 1992/0322
## diff -e /n/bootesdump/1992/0321/sys/src/9/port/devmnt.c /n/bootesdump/1992/0322/sys/src/9/port/devmnt.c
272c
	memmove(f->request.auth, r->reply.chal+AUTHLEN+DESKEYLEN, AUTHLEN+DESKEYLEN);
.
268c
	if(memcmp(chal, r->reply.chal, AUTHLEN) != 0) {
.
265c

	decrypt(u->p->pgrp->crypt->key, r->reply.chal, 2*AUTHLEN+2*DESKEYLEN);
.
260,262c
	memmove(r->request.chal, chal, AUTHLEN);
	strncpy(r->request.chal+AUTHLEN, serv, NAMELEN);
	encrypt(u->p->pgrp->crypt->key, r->request.chal, AUTHLEN+NAMELEN);
.
257c
	for(i = 1; i < AUTHLEN; i++)
.
244c
	uchar chal[AUTHLEN];
.
## diffname port/devmnt.c 1992/0325
## diff -e /n/bootesdump/1992/0322/sys/src/9/port/devmnt.c /n/bootesdump/1992/0325/sys/src/9/port/devmnt.c
181c
		if(decref(m) == 0)
			mntpntfree(m);
.
## diffname port/devmnt.c 1992/0402
## diff -e /n/bootesdump/1992/0325/sys/src/9/port/devmnt.c /n/bootesdump/1992/0402/sys/src/9/port/devmnt.c
186,197d
128,129d
## diffname port/devmnt.c 1992/0503
## diff -e /n/bootesdump/1992/0402/sys/src/9/port/devmnt.c /n/bootesdump/1992/0503/sys/src/9/port/devmnt.c
649a
if(n > 2048)
for(i = 0; i < 256;) {
print("%.2ux ", r->rpc[i] & 0xff);
i++;
if((i%16) == 0) { print("\n"); prflush(); }
}

.
626c
int i;
.
578a

.
570a
memset(r->rpc, 0x55, 2048);
.
## diffname port/devmnt.c 1992/0505
## diff -e /n/bootesdump/1992/0503/sys/src/9/port/devmnt.c /n/bootesdump/1992/0505/sys/src/9/port/devmnt.c
652,657d
628c

.
571d
## diffname port/devmnt.c 1992/0520
## diff -e /n/bootesdump/1992/0505/sys/src/9/port/devmnt.c /n/bootesdump/1992/0520/sys/src/9/port/devmnt.c
760a
	return 0;		/* not reached */
.
## diffname port/devmnt.c 1992/0603
## diff -e /n/bootesdump/1992/0520/sys/src/9/port/devmnt.c /n/bootesdump/1992/0603/sys/src/9/port/devmnt.c
245c
		chal[i] = nrand(256);
.
## diffname port/devmnt.c 1992/0613
## diff -e /n/bootesdump/1992/0603/sys/src/9/port/devmnt.c /n/bootesdump/1992/0613/sys/src/9/port/devmnt.c
543,544c
	r->reply.tag = 0;		/* safety checks */
	r->reply.type = 4;
.
51,52c
#define MAXRPC		(MAXFDATA+MAXMSG)
.
## diffname port/devmnt.c 1992/0619
## diff -e /n/bootesdump/1992/0613/sys/src/9/port/devmnt.c /n/bootesdump/1992/0619/sys/src/9/port/devmnt.c
8d
## diffname port/devmnt.c 1992/0620
## diff -e /n/bootesdump/1992/0619/sys/src/9/port/devmnt.c /n/bootesdump/1992/0620/sys/src/9/port/devmnt.c
817,841d
798c
	if(m->id == 0 || m->id >= c->dev)	/* Sanity check */
.
796c
	m = c->mntptr;
.
759c
	unlock(&mntalloc);
	new->done = 0;
	new->flushed = 0;
	return new;
.
756,757c
		new->rpc = (char*)new+sizeof(Mntrpc);
		new->request.tag = mntalloc.rpctag++;
.
752,754c
			exhausted("mount rpc buffer");
.
747,750c
	lock(&mntalloc);
	new = mntalloc.rpcfree;
	if(new != 0)
		mntalloc.rpcfree = new->list;
	else {
		new = xalloc(sizeof(Mntrpc)+MAXRPC);
		if(new == 0) {
.
550,551c
		print("mnt: mismatched reply 0x%lux T%d R%d tags req %d fls %d rep %d\n",
				r, r->request.type, r->reply.type, r->request.tag, 
				r->flushtag, r->reply.tag);

.
545a

.
542a

.
541c
	r->reply.tag = 0;		/* poison the old values */
.
445a
	l = &mntalloc.list;
	for(f = *l; f; f = f->list) {
		if(f == m) {
			*l = m->list;
			break;
		}
		l = &f->list;
	}

.
444a
	Mnt *f, **l;

.
198c
	c->mntptr = m;
.
168c
	case 'C':			/* Cyclone */
.
163d
159c
	m->c = c;
.
155a

.
152c
	if(m != 0)
		mntalloc.mntfree = m->list;	
	else {
		m = malloc(sizeof(Mnt));
		if(m == 0) {
			unlock(&mntalloc);
			exhausted("mount devices");
		}
		m->flushbase = Tagfls;
		m->flushtag = Tagfls;
	}
	m->list = mntalloc.list;
	mntalloc.list = m;
.
146,150d
138c
			if(m->id && m->ref > 0 && m->c == c) {
				unlock(&mntalloc);
.
134,136c
	c = bogus.chan;

	lock(&mntalloc);
	for(m = mntalloc.list; m; m = m->list) {
		if(m->c == c && m->id) {
.
125c
	Mnt *m;
.
114a
	mntalloc.rpctag = Tagspace;
.
82,113d
73a
	Tagfls = 0x8000,
.
47a
	int	rpctag;
.
46d
43,44c
	Mnt	*list;		/* Mount devices in used */
	Mnt	*mntfree;	/* Free list */
.
10,11d
## diffname port/devmnt.c 1992/0824
## diff -e /n/bootesdump/1992/0620/sys/src/9/port/devmnt.c /n/bootesdump/1992/0824/sys/src/9/port/devmnt.c
253c
	if(waserror()) {
.
## diffname port/devmnt.c 1992/0825
## diff -e /n/bootesdump/1992/0824/sys/src/9/port/devmnt.c /n/bootesdump/1992/0825/sys/src/9/port/devmnt.c
724,730c
	(*devtab[m->c->type].write)(m->c, r->flush, n, 0);
.
717,718d
702a
	Fcall flush;
.
701d
673a
	Mntrpc **l, *q;
.
672d
632,638c
		n = (*devtab[m->c->type].read)(m->c, r->rpc, MAXRPC, 0);
.
621,622d
570,580c
		if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n)
			error(Emountrpc);
.
564,565d
497a
	ulong cnt, nr;
.
496d
208d
205a
	int i;
.
67a
void	mntqrm(Mnt*, Mntrpc*);
Mntrpc*	mntralloc(void);
long	mntrdwr(int , Chan*, void*,long , ulong);
void	mntrpcread(Mnt*, Mntrpc*);
void	mountio(Mnt*, Mntrpc*);
void	mountmux(Mnt*, Mntrpc*);
void	mountrpc(Mnt*, Mntrpc*);
int	rpcattn(Mntrpc*);
.
66c
int	mntflush(Mnt*, Mntrpc*);
void	mntfree(Mntrpc*);
void	mntgate(Mnt*);
.
63,64d
51,61c
Chan*	mattach(Mnt*, char*, char*);
void	mntauth(Mnt *, Mntrpc *, char *, ushort);
Mnt*	mntchk(Chan*);
.
## diffname port/devmnt.c 1992/0915
## diff -e /n/bootesdump/1992/0825/sys/src/9/port/devmnt.c /n/bootesdump/1992/0915/sys/src/9/port/devmnt.c
140c
	m->blocksize = MAXFDATA;/**/
.
## diffname port/devmnt.c 1992/1217
## diff -e /n/bootesdump/1992/0915/sys/src/9/port/devmnt.c /n/bootesdump/1992/1217/sys/src/9/port/devmnt.c
776,777c
	*(ushort*)&dirbuf[DIRLEN-4] = devchar[c->type];
.
## diffname port/devmnt.c 1992/1223
## diff -e /n/bootesdump/1992/1217/sys/src/9/port/devmnt.c /n/bootesdump/1992/1223/sys/src/9/port/devmnt.c
776c
	dirbuf[DIRLEN-4] = devchar[c->type]>>0;
	dirbuf[DIRLEN-3] = devchar[c->type]>>8;
.
## diffname port/devmnt.c 1993/0304
## diff -e /n/bootesdump/1992/1223/sys/src/9/port/devmnt.c /n/bootesdump/1993/0304/sys/src/9/port/devmnt.c
265,274c
	devclone(c, nc);
.
## diffname port/devmnt.c 1993/0321
## diff -e /n/bootesdump/1993/0304/sys/src/9/port/devmnt.c /n/bootesdump/1993/0321/sys/src/9/port/devmnt.c
398,408c
	if(decref(m) != 0)
		return;

	for(q = m->queue; q; q = r) {
		r = q->list;
		q->flushed = 0;
		mntfree(q);
	}
	m->id = 0;
	close(m->c);
	mntpntfree(m);
}

void
mntdoclunk(Mnt *m, Mntrpc *r)
{
	mntfree(r);
	mclose(m);
.
396c
	Mntrpc *q, *r;
.
394c
mclose(Mnt *m)
.
160a

	mc = m->c;
	if(mc->type == devno('M', 0)) {
		c->mntptr = mc->mntptr;
		c->mchan = c->mntptr->c;
		c->mqid = c->qid;
		incref(c->mntptr);
		mclose(m);
	}

.
154,156c
		mclose(m);
.
116a

.
94c
	Chan *c, *mc;
.
67a
void	mclose(Mnt*);
.
32c
	char	mux;		/* Set if the device does the multiplexing */
.
## diffname port/devmnt.c 1993/0323
## diff -e /n/bootesdump/1993/0321/sys/src/9/port/devmnt.c /n/bootesdump/1993/0323/sys/src/9/port/devmnt.c
165c
		c->mchan = mc->mntptr->c;
.
163c
	if(mc->type == devno('M', 0) && (c->qid.path&CHDIR) == 0) {
		c->qid.path |= CHDIR;
.
## diffname port/devmnt.c 1993/0330
## diff -e /n/bootesdump/1993/0323/sys/src/9/port/devmnt.c /n/bootesdump/1993/0330/sys/src/9/port/devmnt.c
212,248d
204a
	authreply(m->c->session, id, &r->reply);
.
203a
	id = authrequest(m->c->session, &r->request);
.
196,199d
180a
	ulong id;
.
177c
mattach(Mnt *m, char *spec)
.
161a
	/*
	 *  If exportfs mounts on behalf of a local devmnt, the mount
	 *  point is folded onto the original channel to preserve a single
	 *  fid/tag space.  CHDIR is cleared by exportfs to indicate it
	 *  is supplying the mount.
	 */
.
160c
	c = mattach(m, bogus.spec);
.
113c
				return mattach(m, bogus.spec);
.
99d
51,52c
Chan*	mattach(Mnt*, char*);
.
## diffname port/devmnt.c 1993/0403
## diff -e /n/bootesdump/1993/0330/sys/src/9/port/devmnt.c /n/bootesdump/1993/0403/sys/src/9/port/devmnt.c
203c
	memmove(r->request.uname, up->user, NAMELEN);
.
196c
		/* Close must not be called since
		 * it will call mnt recursively
		 */
.
## diffname port/devmnt.c 1993/0404
## diff -e /n/bootesdump/1993/0403/sys/src/9/port/devmnt.c /n/bootesdump/1993/0404/sys/src/9/port/devmnt.c
205c
	memmove(r->request.uname, u->p->user, NAMELEN);
.
## diffname port/devmnt.c 1993/0417
## diff -e /n/bootesdump/1993/0404/sys/src/9/port/devmnt.c /n/bootesdump/1993/0417/sys/src/9/port/devmnt.c
498c
		n -= nr;
		if(nr != r->request.count || n == 0)
.
478c
	cnt = 0;
	for(;;) {
.
## diffname port/devmnt.c 1993/0501
## diff -e /n/bootesdump/1993/0417/sys/src/9/port/devmnt.c /n/fornaxdump/1993/0501/sys/src/brazil/port/devmnt.c
764a
}

int
recdone(Mnt *m)
{
	return m->recprog == 0;
}

void
mntrecdel(Mnt *m, Mntrpc *r)
{
	Mntrpc *f, **l;

	lock(m);
	l = &m->recwait;
	for(f = *l; f; f = f->list) {
		if(f == r) {
			*l = r->list;
			break;
		}
	}
	unlock(m);
}

void
mntrecover(Mnt *m, Mntrpc *r)
{
	char *ps;

	lock(m);
	if(m->recprog == 0) {
		m->recprog = 1;
		unlock(m);
		chanrec(m);
		/*
		 * Send a message to boot via #/recover
		 */
		rootrecover(m->c->path, m->tree.root->elem);
		lock(m);
	}
	r->list = m->recwait;
	m->recwait = r;
	unlock(m);

	pprint("lost server connection, wait...\n");

	ps = up->psstate;
	up->psstate = "Recover";

	if(waserror()) {
		up->psstate = ps;
		mntrecdel(m, r);
		nexterror();
	}
	sleep(&r->r, recdone, m);
	poperror();

	r->done = 0;
	mntrecdel(m, r);
	recoverchan(m, r->c);

	up->psstate = ps;
}

void
mntrepl(char *buf)
{
	int fd;
	Mnt *m;
	char *p;
	Chan *c1;
	Mntrpc *r;

	/* reply from boot is 'fd #M23' */
	fd = strtoul(buf, &p, 0);

	p++;
	lock(&mntalloc);
	for(m = mntalloc.list; m; m = m->list) {
		if(strcmp(p, m->tree.root->elem) == 0)
			break;
	}
	unlock(&mntalloc);
	if(m == 0)
		error(Eunmount);

	c1 = fdtochan(fd, ORDWR, 0, 1);	/* error check and inc ref */

	/* If the channel was posted fix it up */
	srvrecover(m->c, c1);

	lock(m);
	close(m->c);
	m->c = c1;
	m->recprog = 0;

	/* Wakeup partially complete rpc */
	for(r = m->recwait; r; r = r->list)
		wakeup(&r->r);

	unlock(m);
.
748a

	/*
	 * Try and get the channel back
	 */
	if((c->flag&CRECOV) && m->recprog == 0)
		recoverchan(m, c);

.
746,747c

	/*
	 * Was it closed and reused
	 */
	if(m->id == 0 || m->id >= c->dev)
.
739a
void
recoverchan(Mnt *m, Chan *c)
{
	int i, n, flg;
	Path *safe, *p, **pav;

	if(m->c == 0)
		error(Eshutdown);

	flg = c->flag;
	/* Don't recursively recover */
	c->flag &= ~(COPEN|CRECOV);

	n = 0;
	for(p = c->path; p; p = p->parent)
		n++;
	pav = smalloc(sizeof(Path*)*n);
	i = n;
	for(p = c->path; p; p = p->parent)
		pav[--i] = p;

	safe = c->path;

	if(waserror()) {
		c->flag = flg;
		free(pav);
		nexterror();
	}

	/* Attach the fid onto the file server (sets c->path to #Mxxx) */
	mattach(m, c, c->xmnt->spec);
	poperror();

	/*
	 * c is now at the root so we free where
	 * the chan was before the server connection was lost
	 */
	decref(safe);

	for(i = 1; i < n; i++) {
		if(mntwalk(c, pav[i]->elem) == 0) {
			free(pav);
			/* Shut down the channel */
			c->dev = m->id-1;
			error(Erecover);
		}
	}
	free(pav);
	if(flg&COPEN)
		mntopen(c, c->mode);
}

.
705a
	new->c = c;
.
688c
mntralloc(Chan *c)
.
677c
		if(strcmp(up->error, Eintr) == 0)
.
646c
				q->reply = r->reply;
.
625a
	}
.
615c
	for(q = m->queue; q; q = q->list) {
.
573c
	m->rip = up;
.
518,523c
	default:
		if(t == r->request.type+1)
			break;
		print("mnt: mismatch rep 0x%lux T%d R%d rq %d fls %d rp %d\n",
			r, t, r->reply.type, r->request.tag, 
			r->flushtag, r->reply.tag);
.
516c
	t = r->reply.type;
	switch(t) {
	case Rerror:
		error(r->reply.ename);
	case Rflush:
.
513,514c
	poperror();
.
511a
	while(waserror()) {
		if(m->recov == 0)
			nexterror();
		mntrecover(m, r);
	}
.
509c
	int t;

	r->reply.tag = 0;
.
499,500c
		if(nr != r->request.count)
.
478,480c
	for(cnt = 0; n; n -= nr) {
		r = mntralloc(c);
.
436c
	r = mntralloc(c);
.
391,397d
379a
	c->path = 0;
	ptclose(&m->tree);

.
373c
mclose(Mnt *m, Chan *c)
.
368c
	mntfree(r);
	mclose(m, c);
.
361c
		mntfree(r);
		mclose(m, c);
.
359c
	r = mntralloc(c);
.
333c
	r = mntralloc(c);
.
307c
	r = mntralloc(c);
.
285c
	r = mntralloc(c);
.
271a
	op = c->path;
	c->path = ptenter(&m->tree, op, name);
/* ASSERT */
if(op->ref == 0) {
	char buf[128];
	ptpath(op, buf, sizeof(buf));
	print("PATH: '%s' walking %s\n", op, name);
}
	decref(op);
.
261c
	r = mntralloc(c);
.
257a
	Path *op;
.
227c
	r = mntralloc(c);
.
216d
213a
	c->path = m->tree.root;
	incref(c->path);

.
205c
	memmove(r->request.uname, up->user, NAMELEN);
.
196,199d
191a

	return c;
}

void
mattach(Mnt *m, Chan *c, char *spec)
{
	ulong id;
	Mntrpc *r;

	r = mntralloc(0);
.
187,188c
	c = devattach('M', 0);
.
184,185d
180,181c
Chan*
mntchan(void)
.
176d
173d
171a
		c->path = c->mntptr->tree.root;
		incref(c->path);
.
170c
		c->mchan = c->mntptr->c;
.
167a
		mclose(m, c);
.
160,165d
158c
	mattach(m, c, bogus.spec);
	poperror();
.
154c
		mclose(m, c);
		/* Close must not be called since it will
		 * call mnt recursively
		 */
		chanfree(c);
.
152a
	c = mntchan();
.
150a

	sprint(buf, "#M%d", m->id);
	m->tree.root = ptenter(&m->tree, 0, buf);

.
140c
	m->blocksize = MAXFDATA;	/**/
	m->recov = bogus.recov;
.
116d
111c
				c = mntchan();
				if(waserror()) {
					chanfree(c);
					nexterror();
				}
				mattach(m, c, bogus.spec);
				poperror();
				return c;
.
97a
		char	recov;
.
94a
	char buf[NAMELEN];
.
67c
void	mclose(Mnt*, Chan*);
void	mntrecover(Mnt*, Mntrpc*);
Chan*	mntchan(void);
.
60c
Mntrpc*	mntralloc(Chan*);
.
54d
51c
void	mattach(Mnt*, Chan*, char*);
void	mntauth(Mnt *, Mntrpc *, char *, ushort);
.
41c
	Mnt	*list;		/* Mount devices in use */
.
24,37d
11a
	Chan	*c;		/* Channel for whom we are working */
.
9d
## diffname port/devmnt.c 1993/0808
## diff -e /n/fornaxdump/1993/0501/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/0808/sys/src/brazil/port/devmnt.c
288a

.
283c

/* ASSERT do not remove */
.
167a
	while(mc) {
		if(mc->type != devno('M', 0))
			break;
		nest++;
		if(mc->mntptr == 0)
			break;
		mc = mc->mntptr->c;
	}
	m->blocksize -= nest * 32;

	/*
	 * Detect a recursive mount for a mount point served by exportfs.
	 * If CHDIR is clear in the returned qid the foreign server is
	 * requesting the mount point be folded into the connection
	 * to the exportfs. In this case the remote mount driver does
	 * the multiplexing.
	 */
	mc = m->c;
.
166a
	/* Work out how deep we are nested and reduce the blocksize
	 * accordingly
	 */
	nest = 0;
.
81a
	int nest;
.
## diffname port/devmnt.c 1993/0907
## diff -e /n/fornaxdump/1993/0808/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/0907/sys/src/brazil/port/devmnt.c
539c
		n -= nr;
		if(nr != r->request.count || n == 0)
.
531a
		if(nr > r->request.count)
			nr = r->request.count;
.
519c
	cnt = 0;
	for(;;) {
.
## diffname port/devmnt.c 1993/1006
## diff -e /n/fornaxdump/1993/0907/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/1006/sys/src/brazil/port/devmnt.c
654a
		}
.
653c
		if(n == 0) {
			if(++zrd > 3)
				error(Ehungup);
.
639a
	zrd = 0;
.
638c
	int n, zrd;
.
## diffname port/devmnt.c 1993/1011
## diff -e /n/fornaxdump/1993/1006/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/1011/sys/src/brazil/port/devmnt.c
865c
	 * Try and get the channel back after a crash
.
59,63c
	Tagspace	= 1,
	Tagfls		= 0x8000,
	Tagend		= 0xfffe,
.
## diffname port/devmnt.c 1993/1014
## diff -e /n/fornaxdump/1993/1011/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/1014/sys/src/brazil/port/devmnt.c
556c
		if((m->flags & MRECOV) == 0)
.
515d
510d
508c
mntrdwr(int type, Mnt *m, Chan *c, void *buf, long n, ulong offset)
.
504c
	m = mntchk(c);
	return mntrdwr(Twrite, m, c, buf, n, offset);	
.
497a
	if(nc != 0)
		cupdate(c, buf, n, offset);

.
493c
	m = mntchk(c);
	nc = 0;
	if((m->flags&MCACHE) && !isdir(c)) {
		nc = cread(c, buf, n, offset);
		if(nc == n)
			return n;

		buf = (uchar*)buf+nc;
		offset += nc;
		n -= nc;
	}

	n = mntrdwr(Tread, m, c, buf, n, offset);
.
490a
	int nc;
.
305,311d
136c
	m->flags = bogus.flags;
.
86c
		int	flag;
.
47c
long	mntrdwr(int , Mnt*, Chan*, void*,long , ulong);
.
## diffname port/devmnt.c 1993/1015
## diff -e /n/fornaxdump/1993/1014/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/1015/sys/src/brazil/port/devmnt.c
542a
		else if(cache)
			cwrite(c, (uchar*)r->reply.data, nr, offset);

.
540a

.
525a
	cache = m->flags & MCACHE;
.
521a
	int cache;
.
513,514c
	return mntrdwr(Twrite, mntchk(c), c, buf, n, offset);
.
505a
		n += nc;
	}
.
504c
	if(cached) {
.
494,496c
	SET(nc);
	if(cached) {
		nc = cread(c, buf, n, offset);
		if(nc > 0) {
			buf = (uchar*)buf+nc;
			offset += nc;
			n -= nc;
		}
.
488,492c
	cached = m->flags&MCACHE;
.
485a
	int nc, cached;
.
484c
	Mnt *m;
.
383a

	if(m->flags & MCACHE)
		copen(c);
.
356a

	if(m->flags&MCACHE)
		copen(c);

.
111a

.
94c
		if(m->c == c && m->id && m->flags == bogus.flags) {
.
86c
		int	flags;
.
68a

	cinit();
.
## diffname port/devmnt.c 1993/1016
## diff -e /n/fornaxdump/1993/1015/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/1016/sys/src/brazil/port/devmnt.c
583c
		if((m->flags&MRECOV) == 0)
.
560c
			cwrite(c, (uchar*)uba, nr, offset);
.
540c
	cache = c->flag & CCACHE;
.
537a
	m = mntchk(c);
.
533c
	Mnt *m;
 	Mntrpc *r;
.
531c
mntrdwr(int type, Chan *c, void *buf, long n, ulong offset)
.
527c
	return mntrdwr(Twrite, c, buf, n, offset);
.
515,516c
	}
	else if(cached) {
.
511,512c
	n = mntrdwr(Tread, c, buf, n, offset);
	if(c->qid.path & CHDIR) {
.
498,499c
	cached = c->flag & CCACHE;
.
494d
392c
	if(c->flag & CCACHE)
.
361c
	if(c->flag & CCACHE)
.
202a
	if(bogus.flags & MCACHE)
		c->flag |= CCACHE;

.
139c
	m->flags = bogus.flags & ~MCACHE;
.
108a
				if(bogus.flags&MCACHE)
					c->flag |= CCACHE;
.
96c
		if(m->c == c && m->id) {
.
47c
long	mntrdwr(int , Chan*, void*,long , ulong);
.
## diffname port/devmnt.c 1993/1102
## diff -e /n/fornaxdump/1993/1016/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/1102/sys/src/brazil/port/devmnt.c
573c
		if(nr != r->request.count || n == 0 || up->nnote)
.
510d
507a
			n -= nc;
			if(n == 0)
				return nc;
.
## diffname port/devmnt.c 1993/1103
## diff -e /n/fornaxdump/1993/1102/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/1103/sys/src/brazil/port/devmnt.c
690d
686,688c
		if(n == 0)
.
672d
670c
	int n;
.
## diffname port/devmnt.c 1993/1105
## diff -e /n/fornaxdump/1993/1103/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/1105/sys/src/brazil/port/devmnt.c
607c
			r, r->request.type, r->reply.type, r->request.tag, 
.
## diffname port/devmnt.c 1993/1122
## diff -e /n/fornaxdump/1993/1105/sys/src/brazil/port/devmnt.c /n/fornaxdump/1993/1122/sys/src/brazil/port/devmnt.c
1014a
}

static uchar
msglen[256] =
{
	[Tnop]		3,
	[Rnop]		3,
	[Tsession]	3+CHALLEN,
	[Rsession]	3+NAMELEN+DOMLEN+CHALLEN,
	[Terror]	0,
	[Rerror]	67,
	[Tflush]	5,
	[Rflush]	3,
	[Tattach]	5+2*NAMELEN+TICKETLEN+AUTHENTLEN,
	[Rattach]	13+AUTHENTLEN,
	[Tclone]	7,
	[Rclone]	5,
	[Twalk]		33,
	[Rwalk]		13,
	[Topen]		6,
	[Ropen]		13,
	[Tcreate]	38,
	[Rcreate]	13,
	[Tread]		15,
	[Rread]		8,
	[Twrite]	16,
	[Rwrite]	7,
	[Tclunk]	5,
	[Rclunk]	5,
	[Tremove]	5,
	[Rremove]	5,
	[Tstat]		5,
	[Rstat]		121,
	[Twstat]	121,
	[Rwstat]	5,
	[Tclwalk]	35,
	[Rclwalk]	13,
};

enum
{
	Twritehdr	= 16,	/* Min bytes for Twrite */
	Rreadhdr	= 8,	/* Min bytes for Rread */
	Twritecnt	= 13,	/* Offset in byte stream of write count */
	Rreadcnt	= 5,	/* Offset for Readcnt */
};

int
mntrpclen(char *d, int n)
{
	char t;
	int len, off;

	if(n < 1)
		return 0;

	t = d[0];
	switch(t) {			/* This is the type */
	default:
		len = msglen[t];
		if(len == 0)		/* Illegal type so consume */
			return n;
		if(n < len)
			return 0;
		return len;
	case Twrite:			/* Fmt: TGGFFOOOOOOOOCC */
		len = Twritehdr;	/* T = type, G = tag, F = fid */
		off = Twritecnt;	/* O = offset, C = count */
		break;
	case Rread:			/* Fmt: TGGFFCC */
		len = Rreadhdr;
		off = Rreadcnt;
		break;
	}
	if(n < off+2)
		return 0;

	len += d[off]+(d[off+1]<<8);
	if(n < len)
		return 0;
	return len;
.
683c
		n = devtab[m->c->type].read(m->c, r->rpc, MAXRPC, 0);
.
55a
int	mntrpclen(char*, int);
.
## diffname port/devmnt.c 1994/0107
## diff -e /n/fornaxdump/1993/1122/sys/src/brazil/port/devmnt.c /n/fornaxdump/1994/0107/sys/src/brazil/port/devmnt.c
1016,1096d
56d
## diffname port/devmnt.c 1994/0402
## diff -e /n/fornaxdump/1994/0107/sys/src/brazil/port/devmnt.c /n/fornaxdump/1994/0402/sys/src/brazil/port/devmnt.c
632,633c
		if(devchar[m->c->type] == L'M'){
			if(mntwrite9p(m->c, r->rpc, n, 0) != n)
				error(Emountrpc);
		}else{
			if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n)
				error(Emountrpc);
		}
.
558c
		if(p9msg)
			r->request.count = limit(n, m->blocksize + MAXMSG - 20);
		else
			r->request.count = limit(n, m->blocksize);
.
536c
mntrdwr(int type, Chan *c, void *buf, long n, ulong offset, int p9msg)
.
532c
	return mntrdwr(Twrite, c, buf, n, offset, 0);
.
529a
mntwrite9p(Chan *c, void *buf, long n, ulong offset)
{
	return mntrdwr(Twrite, c, buf, n, offset, 1);
}

long	 
.
516c
	n = mntrdwr(Tread, c, buf, n, offset, 0);
.
184a
#endif STUPIDHACK
.
170a
#ifdef STUPIDHACK
.
47c
long	mntrdwr(int , Chan*, void*,long , ulong, int);
.
## diffname port/devmnt.c 1994/0405
## diff -e /n/fornaxdump/1994/0402/sys/src/brazil/port/devmnt.c /n/fornaxdump/1994/0405/sys/src/brazil/port/devmnt.c
699c
		if(devchar[m->c->type] == L'M')
			n = mntrdwr(Tread, m->c, r->rpc, MAXRPC, 0, 1);
		else
			n = devtab[m->c->type].read(m->c, r->rpc, MAXRPC, 0);
.
644c
			if(mntrdwr(Twrite, m->c, r->rpc, n, 0, 1) != n)
.
566,568c
		if(p9msg) {
			if(n > MAXRPC-32){
				if(type == Twrite)
					error("write9p too long");
				n = MAXRPC-32;
			}
			r->request.count = n;
		} else
.
498a
mntread9p(Chan *c, void *buf, long n, ulong offset)
{
	return mntrdwr(Tread, c, buf, n, offset, 1);
}

long	 
.
171,187d
82d
## diffname port/devmnt.c 1994/0513
## diff -e /n/fornaxdump/1994/0405/sys/src/brazil/port/devmnt.c /n/fornaxdump/1994/0513/sys/src/brazil/port/devmnt.c
139c
	m->blocksize = defmaxmsg;
.
56a
int defmaxmsg = MAXFDATA;

.
## diffname port/devmnt.c 1994/0828
## diff -e /n/fornaxdump/1994/0513/sys/src/brazil/port/devmnt.c /n/fornaxdump/1994/0828/sys/src/brazil/port/devmnt.c
782c
	l = (*devtab[m->c->type].write)(m->c, r->flush, n, 0);
	if(l != n)
		error(Ehungup);
.
761c
	int n, l;
.
## diffname port/devmnt.c 1994/0831
## diff -e /n/fornaxdump/1994/0828/sys/src/brazil/port/devmnt.c /n/fornaxdump/1994/0831/sys/src/brazil/port/devmnt.c
141c
	if(strcmp(bogus.spec, "16k") == 0) {
		m->blocksize = 16*1024;
		bogus.spec = "";
	}
	else
		m->blocksize = defmaxmsg;
.
34c
#define MAXRPC		(16*1024+MAXMSG)
.
## diffname port/devmnt.c 1994/1124
## diff -e /n/fornaxdump/1994/0831/sys/src/brazil/port/devmnt.c /n/fornaxdump/1994/1124/sys/src/brazil/port/devmnt.c
30c
	ulong	id;
.
## diffname port/devmnt.c 1994/1212
## diff -e /n/fornaxdump/1994/1124/sys/src/brazil/port/devmnt.c /n/fornaxdump/1994/1212/sys/src/brazil/port/devmnt.c
994c
	if(r->c != 0)
		recoverchan(m, r->c);
.
224c
	if(waserror()) {
.
## diffname port/devmnt.c 1995/0107
## diff -e /n/fornaxdump/1994/1212/sys/src/brazil/port/devmnt.c /n/fornaxdump/1995/0107/sys/src/brazil/port/devmnt.c
27,29c
	Mnt*	list;		/* Mount devices in use */
	Mnt*	mntfree;	/* Free list */
	Mntrpc*	rpcfree;
.
17c
	char*	rpc;		/* I/O Data buffer */
.
15c
	Mnt*	m;		/* Mount device during rpc */
.
11,12c
	Chan*	c;		/* Channel for whom we are working */
	Mntrpc*	list;		/* Free/pending list */
.
## diffname port/devmnt.c 1995/0108
## diff -e /n/fornaxdump/1995/0107/sys/src/brazil/port/devmnt.c /n/fornaxdump/1995/0108/sys/src/brazil/port/devmnt.c
535a
}

long
mntbwrite(Chan *c, Block *bp, ulong offset)
{
	return devbwrite(c, bp, offset);
.
525a
Block*
mntbread(Chan *c, long n, ulong offset)
{
	return devbread(c, n, offset);
}

.
## diffname port/devmnt.c 1995/0129
## diff -e /n/fornaxdump/1995/0108/sys/src/brazil/port/devmnt.c /n/fornaxdump/1995/0129/sys/src/brazil/port/devmnt.c
712c
			n = mnt9prdwr(Tread, m->c, r->rpc, MAXRPC, 0);
.
656c
			if(mnt9prdwr(Twrite, m->c, r->rpc, n, 0) != n)
.
573,581c
		r->request.count = limit(n, m->blocksize);
.
553a
 	ulong nr;
	Mntrpc *r;

	if(n > MAXRPC-32) {
		if(type == Twrite)
			error("write9p too long");
		n = MAXRPC-32;
	}

	m = mntchk(c);
	r = mntralloc(c);
	if(waserror()) {
		mntfree(r);
		nexterror();
	}
	r->request.type = type;
	r->request.fid = c->fid;
	r->request.offset = offset;
	r->request.data = buf;
	r->request.count = n;
	mountrpc(m, r);
	nr = r->reply.count;
	if(nr > r->request.count)
		nr = r->request.count;

	if(type == Tread)
		memmove(buf, r->reply.data, nr);

	poperror();
	mntfree(r);
	return nr;
}

long
mntrdwr(int type, Chan *c, void *buf, long n, ulong offset)
{
	Mnt *m;
.
551c
mnt9prdwr(int type, Chan *c, void *buf, long n, ulong offset)
.
541c
	return mntrdwr(Twrite, c, buf, n, offset);
.
535c
	return mnt9prdwr(Twrite, c, buf, n, offset);
.
522a
	for(e = &p[n]; p < e; p += DIRLEN)
		mntdirfix(p, c);

.
513,521c
	n = mntrdwr(Tread, c, buf, n, offset);
	if((c->qid.path & CHDIR) == 0)
		return n;
.
510a
		n = mntrdwr(Tread, c, p, n, offset);
		cupdate(c, p, n, offset);
		return n + nc;
.
508c
			p += nc;
.
499,502c
	p = buf;
	if(c->flag & CCACHE) {
.
497d
495a
	int nc;
.
490c
	return mnt9prdwr(Tread, c, buf, n, offset);
.
47c
long	mntrdwr(int , Chan*, void*,long , ulong);
long	mnt9prdwr(int , Chan*, void*,long , ulong);
.
## diffname port/devmnt.c 1995/0202
## diff -e /n/fornaxdump/1995/0129/sys/src/brazil/port/devmnt.c /n/fornaxdump/1995/0202/sys/src/brazil/port/devmnt.c
180c
	 * If CHDIR is clear in the returned qid, the foreign server is
.
## diffname port/devmnt.c 1995/0204
## diff -e /n/fornaxdump/1995/0202/sys/src/brazil/port/devmnt.c /n/fornaxdump/1995/0204/sys/src/brazil/port/devmnt.c
598a
	if(c->path & CHDIR)
		cache = 0;
.
519,521d
516,517c
	if(isdir) {
		for(e = &p[n]; p < e; p += DIRLEN)
			mntdirfix(p, c);
	}
.
501c
	if(cache) {
.
499a
	isdir = 0;
	cache = c->flag & CCACHE;
	if(c->qid.path & CHDIR) {
		cache = 0;
		isdir = 1;
	}

.
498a
	int nc, cache, isdir;
.
497d
## diffname port/devmnt.c 1995/0206
## diff -e /n/fornaxdump/1995/0204/sys/src/brazil/port/devmnt.c /n/fornaxdump/1995/0206/sys/src/brazil/port/devmnt.c
605c
	if(c->qid.path & CHDIR)
.
## diffname port/devmnt.c 1995/0508
## diff -e /n/fornaxdump/1995/0206/sys/src/brazil/port/devmnt.c /n/fornaxdump/1995/0508/sys/src/brazil/port/devmnt.c
142,143c
	if(strncmp(bogus.spec, "mntblk=", 7) == 0) {
		m->blocksize = strtoul(bogus.spec+7, 0, 0);
		if(m->blocksize > MAXFDATA)
			m->blocksize = MAXFDATA;
		print("mount blk %d\n", m->blocksize);
.
## diffname port/devmnt.c 1996/0223
## diff -e /n/fornaxdump/1995/0508/sys/src/brazil/port/devmnt.c /n/fornaxdump/1996/0223/sys/src/brazil/port/devmnt.c
7d
## diffname port/devmnt.c 1996/0510
## diff -e /n/fornaxdump/1996/0223/sys/src/brazil/port/devmnt.c /n/fornaxdump/1996/0510/sys/src/brazil/port/devmnt.c
778a
			splx(x);
.
773a
				splx(x);
.
770a
			x = splhi();	/* because sleep also does */
.
765a
	int x;
.
## diffname port/devmnt.c 1997/0220
## diff -e /n/fornaxdump/1996/0510/sys/src/brazil/port/devmnt.c /n/emeliedump/1997/0220/sys/src/brazil/port/devmnt.c
771,783c
		if(q->done == 0)
		if(wakeup(&q->r))
			break;
.
## diffname port/devmnt.c 1997/0327
## diff -e /n/emeliedump/1997/0220/sys/src/brazil/port/devmnt.c /n/emeliedump/1997/0327/sys/src/brazil/port/devmnt.c
1081a

Dev mntdevtab = {
	mntreset,
	devinit,
	mntattach,
	mntclone,
	mntwalk,
	mntstat,
	mntopen,
	mntcreate,
	mntclose,
	mntread,
	devbread,
	mntwrite,
	devbwrite,
	mntremove,
	mntwstat,
};
.
1072c
	cclose(m->c);
.
944c
Mnt*
.
859a
	new->flushtag = 0;
.
838c
Mntrpc*
.
831c
	l = devtab[m->c->type]->write(m->c, r->flush, n, 0);
.
823a
	if(n < 0)
		panic("bad message type in mntflush");
.
766d
752c
			n = devtab[m->c->type]->read(m->c, r->rpc, MAXRPC, 0);
.
741,742c
				mntgate(m);
.
702,706d
697c
			if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
.
687a
	if(n < 0)
		panic("bad message type in mountio");
.
552,557d
545c
static long	 
.
533,538d
496c
static long	 
.
470c
static void
.
464c
static void	 
.
458c
static void
.
434c
	cclose(m->c);
.
395c
static void	 
.
366c
static void	 
.
336c
static Chan*
.
314c
static void	 
.
285c
static int	 
.
266c
			cclose(nc);
.
250c
static Chan*
.
152,159d
75,80c
static Chan*
.
66c
static void
.
46,47c
long	mntrdwr(int, Chan*, void*, long, ulong);
long	mnt9prdwr(int, Chan*, void*, long, ulong);
.
37c
void	mntauth(Mnt*, Mntrpc*, char*, ushort);
.
## diffname port/devmnt.c 1997/0405
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/port/devmnt.c /n/emeliedump/1997/0405/sys/src/brazil/port/devmnt.c
642c
		print("mnt: proc %s %d: mismatch rep 0x%lux T%d R%d rq %d fls %d rp %d\n",
			up->text, up->pid,
.
## diffname port/devmnt.c 1997/0408
## diff -e /n/emeliedump/1997/0405/sys/src/brazil/port/devmnt.c /n/emeliedump/1997/0408/sys/src/brazil/port/devmnt.c
1057a
	'm',
	"mnt",

.
943,944c
	int r;

	r = devtab[c->type]->dc;
	dirbuf[DIRLEN-4] = r>>0;
	dirbuf[DIRLEN-3] = r>>8;
.
721c
		if(devtab[m->c->type]->dc == L'M')
.
671c
		if(devtab[m->c->type]->dc == L'M'){
.
## diffname port/devmnt.c 1997/0409
## diff -e /n/emeliedump/1997/0408/sys/src/brazil/port/devmnt.c /n/emeliedump/1997/0409/sys/src/brazil/port/devmnt.c
1061c
	'M',
.
## diffname port/devmnt.c 1997/1104
## diff -e /n/emeliedump/1997/0409/sys/src/brazil/port/devmnt.c /n/emeliedump/1997/1104/sys/src/brazil/port/devmnt.c
702a
poot("M2", m->c->qid.path);
.
698a
poot("M1", m->c->qid.path);
.
## diffname port/devmnt.c 1997/1105
## diff -e /n/emeliedump/1997/1104/sys/src/brazil/port/devmnt.c /n/emeliedump/1997/1105/sys/src/brazil/port/devmnt.c
704d
699d
## diffname port/devmnt.c 1997/1205
## diff -e /n/emeliedump/1997/1105/sys/src/brazil/port/devmnt.c /n/emeliedump/1997/1205/sys/src/brazil/port/devmnt.c
130a
	lock(m);
.
128d
97a
				unlock(&mntalloc);
.
95d
## diffname port/devmnt.c 1998/0319
## diff -e /n/emeliedump/1997/1205/sys/src/brazil/port/devmnt.c /n/emeliedump/1998/0319/sys/src/brazil/port/devmnt.c
528a
	ulong offset = off;

.
527c
mntwrite(Chan *c, void *buf, long n, vlong off)
.
487a
	ulong offset = off;
.
484c
mntread(Chan *c, void *buf, long n, vlong off)
.
## diffname port/devmnt.c 1998/0327
## diff -e /n/emeliedump/1998/0319/sys/src/brazil/port/devmnt.c /n/emeliedump/1998/0327/sys/src/brazil/port/devmnt.c
610c
		off += nr;
.
606c
			cwrite(c, (uchar*)uba, nr, off);
.
595c
		r->request.offset = off;
.
573c
mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
.
556c
	r->request.offset = off;
.
536c
mnt9prdwr(int type, Chan *c, void *buf, long n, vlong off)
.
530,532c
	return mntrdwr(Twrite, c, buf, n, off);
.
524c
	return mnt9prdwr(Twrite, c, buf, n, off);
.
522c
mntwrite9p(Chan *c, void *buf, long n, vlong off)
.
512c
	n = mntrdwr(Tread, c, buf, n, off);
.
507,508c
		n = mntrdwr(Tread, c, p, n, off);
		cupdate(c, p, n, off);
.
505c
			off += nc;
.
499c
		nc = cread(c, buf, n, off);
.
488d
480c
	return mnt9prdwr(Tread, c, buf, n, off);
.
478c
mntread9p(Chan *c, void *buf, long n, vlong off)
.
46,47c
long	mntrdwr(int, Chan*, void*, long, vlong);
long	mnt9prdwr(int, Chan*, void*, long, vlong);
.
## diffname port/devmnt.c 1998/0512
## diff -e /n/emeliedump/1998/0327/sys/src/brazil/port/devmnt.c /n/emeliedump/1998/0512/sys/src/brazil/port/devmnt.c
644c
			r, r->request.type, r->reply.type, r->request.tag,
.
526c
static long
.
520c
long
.
483c
static long
.
477c
long
.
451c
static void
.
387c

.
382c
static void
.
353c
static void
.
301c
static void
.
272c
static int
.
115c
		mntalloc.mntfree = m->list;
.
109c
			unlock(m);
.
## diffname port/devmnt.c 1998/0724
## diff -e /n/emeliedump/1998/0512/sys/src/brazil/port/devmnt.c /n/emeliedump/1998/0724/sys/src/brazil/port/devmnt.c
1057a
	cclose(c2);
.
1049c
	c2 = m->c;
.
1027c
	Chan *c1, *c2;
.
## diffname port/devmnt.c 1998/0825
## diff -e /n/emeliedump/1998/0724/sys/src/brazil/port/devmnt.c /n/emeliedump/1998/0825/sys/src/brazil/port/devmnt.c
642c
		print("mnt: proc %s %lud: mismatch rep 0x%lux T%d R%d rq %d fls %d rp %d\n",
.
149c
	sprint(buf, "#M%lud", m->id);
.
## diffname port/devmnt.c 1998/0829
## diff -e /n/emeliedump/1998/0825/sys/src/brazil/port/devmnt.c /n/emeliedump/1998/0829/sys/src/brazil/port/devmnt.c
896c
	mattach(m, c, c->xmh->mount->spec);
.
## diffname port/devmnt.c 1998/0908
## diff -e /n/emeliedump/1998/0829/sys/src/brazil/port/devmnt.c /n/emeliedump/1998/0908/sys/src/brazil/port/devmnt.c
611c
		if(nr != nreq || n == 0 || up->nnote)
.
597,598c
		if(nr > nreq)
			nr = nreq;
.
595a
		nreq = r->request.count;
.
576c
	ulong cnt, nr, nreq;
.
## diffname port/devmnt.c 1998/0916
## diff -e /n/emeliedump/1998/0908/sys/src/brazil/port/devmnt.c /n/emeliedump/1998/0916/sys/src/brazil/port/devmnt.c
771a
			}
.
770c
			}else {
				if(mntstats != nil)
					(*mntstats)(r->request.type, m->c, q->stime);
.
768a
				if(mntstats != nil)
					(*mntstats)(q->request.type, m->c, q->stime);
.
678a
		r->stime = fastticks(nil);
		r->bytes = n;
.
57a
extern void (*mntstats)(int, Chan*, uvlong);
.
13a
	uvlong	stime;		/* start time */
.
## diffname port/devmnt.c 1998/0917
## diff -e /n/emeliedump/1998/0916/sys/src/brazil/port/devmnt.c /n/emeliedump/1998/0917/sys/src/brazil/port/devmnt.c
778c
					(*mntstats)(r->request.type, m->c, r->stime,
						r->reqlen + r->replen);
.
774c
					(*mntstats)(q->request.type, m->c, q->stime,
							q->reqlen + r->replen);
.
767a
				/* trade pointers to receive buffer */
.
733a
		r->replen = n;
.
682c
		r->reqlen = n;
.
59c
void (*mntstats)(int, Chan*, uvlong, ulong);
.
21a
	uvlong	stime;		/* start time for mnt statistics */
	ulong	reqlen;		/* request length for mnt statistics */
	ulong	replen;		/* reply length for mnt statistics */
.
14d
## diffname port/devmnt.c 1999/0212
## diff -e /n/emeliedump/1998/0917/sys/src/brazil/port/devmnt.c /n/emeliedump/1999/0212/sys/src/brazil/port/devmnt.c
857,858c
	if(mntalloc.nrpcfree >= 10){
		free(r->rpc);
		free(r);
	}
	else{
		r->list = mntalloc.rpcfree;
		mntalloc.rpcfree = r;
		mntalloc.nrpcfree++;
	}
	mntalloc.nrpcused--;
.
844a
	else {
		mntalloc.rpcfree = new->list;
		mntalloc.nrpcfree--;
	}
	mntalloc.nrpcused++;
.
842d
839a
			exhausted("mount rpc header");
		}
		/*
		 * The header is split from the data buffer as
		 * mountmux may swap the buffer with another header.
		 */
		new->rpc = mallocz(MAXRPC, 0);
		if(new->rpc == nil){
			free(new);
			unlock(&mntalloc);
.
834,838c
	if(new == nil){
		new = malloc(sizeof(Mntrpc));
		if(new == nil) {
.
783c
					(*mntstats)(r->request.type,
						m->c, r->stime,
.
778,779c
					(*mntstats)(q->request.type,
						m->c, q->stime,
						q->reqlen + r->replen);
.
770,771c
			if(q != r) {
				/*
				 * Completed someone else.
				 * Trade pointers to receive buffer.
				 */
.
31a
	int	nrpcfree;
	int	nrpcused;
.
## diffname port/devmnt.c 1999/0320
## diff -e /n/emeliedump/1999/0212/sys/src/brazil/port/devmnt.c /n/emeliedump/1999/0320/sys/src/brazil/port/devmnt.c
1003a
	Mnt *m;

	m = v;
.
1002c
recdone(void *v)
.
997a
	Mntrpc *r;

	r = v;
.
996c
rpcattn(void *v)
.
57c
int	rpcattn(void*);
.
## diffname port/devmnt.c 1999/0629
## diff -e /n/emeliedump/1999/0320/sys/src/brazil/port/devmnt.c /n/emeliedump/1999/0629/sys/src/brazil/port/devmnt.c
1107a
#endif
.
1072a
panic("mntrepl");
#ifdef asdf
.
1042c
panic("mntrecover\n");
//		rootrecover(m->c->path, m->tree.root->elem);
.
958a
#endif
.
911a
panic("recoverchan");
#ifdef asdf
BUG: WON'T WORK WITH PATHS GONE?
.
418,420d
300,301d
297,298d
282d
236,237d
187,188d
156d
## diffname port/devmnt.c 1999/0714
## diff -e /n/emeliedump/1999/0629/sys/src/brazil/port/devmnt.c /n/emeliedump/1999/0714/sys/src/brazil/port/devmnt.c
1063c
mntrepl(char*)
.
897c
recoverchan(Mnt*, Chan*)
.
401c
mclose(Mnt *m, Chan*)
.
## diffname port/devmnt.c 1999/0722
## diff -e /n/emeliedump/1999/0714/sys/src/brazil/port/devmnt.c /n/emeliedump/1999/0722/sys/src/brazil/port/devmnt.c
587c
		if(n > m->blocksize){
			if(c->qid.path & CHDIR)
				r->request.count = (m->blocksize/DIRLEN)*DIRLEN;
			else
				r->request.count = m->blocksize;
		} else
			r->request.count = n;
.
39d
## diffname port/devmnt.c 1999/1018
## diff -e /n/emeliedump/1999/0722/sys/src/brazil/port/devmnt.c /n/emeliedump/1999/1018/sys/src/brazil/port/devmnt.c
643c
			r, r->request.tag, r->request.fid, r->request.type, r->reply.type,
.
641c
		print("mnt: proc %s %lud: mismatch rep 0x%lux tag %d fid %d T%d R%d fls %d rp %d\n",
.
## diffname port/devmnt.c 1999/1105
## diff -e /n/emeliedump/1999/1018/sys/src/brazil/port/devmnt.c /n/emeliedump/1999/1105/sys/src/9/port/devmnt.c
998,1107d
970,975d
901,956d
630d
624,628d
58d
## diffname port/devmnt.c 1999/1109
## diff -e /n/emeliedump/1999/1105/sys/src/9/port/devmnt.c /n/emeliedump/1999/1109/sys/src/9/port/devmnt.c
148c
		m->blocksize = MAXFDATA;
.
60d
38,39d
## diffname port/devmnt.c 1999/1230
## diff -e /n/emeliedump/1999/1109/sys/src/9/port/devmnt.c /n/emeliedump/1999/1230/sys/src/9/port/devmnt.c
789a
	if(r->done){
		unlock(m);
		return 1;
	}
.
763d
752a
			q->done = 1;
.
750,751c
		if((q->flushed==0 && q->request.tag == r->reply.tag)
		|| (q->flushed && q->flushtag == r->reply.tag)) {
.
## diffname port/devmnt.c 2000/0101
## diff -e /n/emeliedump/1999/1230/sys/src/9/port/devmnt.c /n/emeliedump/2000/0101/sys/src/9/port/devmnt.c
775a
			if(mntstats != nil)
				(*mntstats)(q->request.type,
					m->c, q->stime,
					q->reqlen + r->replen);
			if(q != r)
				wakeup(&q->r);
.
764,774d
## diffname port/devmnt.c 2000/0102
## diff -e /n/emeliedump/2000/0101/sys/src/9/port/devmnt.c /n/emeliedump/2000/0102/sys/src/9/port/devmnt.c
764a
			q->done = 1;
			unlock(m);
.
753,754d
618c
	r->reply.type = Tmax;	/* can't ever be a valid message type */
.
## diffname port/devmnt.c 2000/0104
## diff -e /n/emeliedump/2000/0102/sys/src/9/port/devmnt.c /n/emeliedump/2000/0104/sys/src/9/port/devmnt.c
877d
848,849d
808,812d
806d
802,804c
	mountio(m, fr);
	mntfree(fr);

	if(!r->done){
		r->reply.type = Rflush;
.
795,800c
	fr->request.type = Tflush;
	if(r->request.type == Tflush)
		fr->request.oldtag = r->request.oldtag;
	else
		fr->request.oldtag = r->request.tag;
.
784,793c
	fr = mntralloc(0);
.
781,782c
	Mntrpc *fr;
.
778c
void
.
750,751c
		// look for a reply to a message
		if(q->request.tag == r->reply.tag) {
.
716d
703,709d
694a
	poperror();
.
686a
		}
.
684,685c
		if(r->done){
			poperror();
.
678,682d
670a
	r->stime = fastticks(nil);
	r->reqlen = n;
.
659,669c
	if(devtab[m->c->type]->dc == L'M'){
		if(mnt9prdwr(Twrite, m->c, r->rpc, n, 0) != n)
			error(Emountrpc);
	}else{
		if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
			error(Emountrpc);
.
657a
		mntflush(m, r);
		return;
.
656c
		if(m->rip == up)
			mntgate(m);
		if(strcmp(up->error, Eintr) != 0)
.
645d
634c
			r->reply.tag);
.
631c
		print("mnt: proc %s %lud: mismatch rep 0x%lux tag %d fid %d T%d R%d rp %d\n",
.
405d
123,124d
63,64d
42c
void	mntflush(Mnt*, Mntrpc*);
.
18,20d
## diffname port/devmnt.c 2000/0105
## diff -e /n/emeliedump/2000/0104/sys/src/9/port/devmnt.c /n/emeliedump/2000/0105/sys/src/9/port/devmnt.c
813a
	new->flushed = nil;
.
775,777c
/*
 *  Free a chain of flushes.  Remove each unanswered
 *  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.
 */
void
mntflushfree(Mnt *m, Mntrpc *r)
{
	Mntrpc *fr;

	while(r){
		fr = r->flushed;
		if(!r->done){
			r->reply.type = Rflush;
			mntqrm(m, r);
		}
		if(fr)
			mntfree(r);
		r = fr;
.
772,773c
	return fr;
}
.
770a
	fr->flushed = r;
.
759,760c
/*
 * Create a new flush request and chain the previous
 * requests from it
 */
Mntrpc*
mntflushalloc(Mntrpc *r)
.
731c
		/* look for a reply to a message */
.
683a
	mntflushfree(m, r);
.
672a
			mntflushfree(m, r);
.
646,653d
635a
	while(waserror()) {
		if(m->rip == up)
			mntgate(m);
		if(strcmp(up->error, Eintr) != 0){
			mntflushfree(m, r);
			nexterror();
		}
		r = mntflushalloc(r);
	}

.
39c
Mntrpc*	mntflushalloc(Mntrpc*);
void	mntflushfree(Mnt*, Mntrpc*);
.
20a
	Mntrpc*	flushed;	/* message this one flushes */
.
## diffname port/devmnt.c 2001/0503
## diff -e /n/emeliedump/2000/0105/sys/src/9/port/devmnt.c /n/emeliedump/2001/0503/sys/src/9/port/devmnt.c
911c
static int
.
899c
static void
.
883c
static Mnt*
.
864c
static void
.
847c
static void
.
810c
static Mntrpc*
.
793c
static void
.
769c
static Mntrpc*
.
728c
static void
.
713c
static void
.
692c
static void
.
633c
static void
.
625,628c
		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 %s %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n",
			up->text, up->pid, sn, cn,
			r, r->request.tag, r->request.fid, r->request.type,
			r->reply.type, r->reply.tag);
.
608a
	char *sn, *cn;
.
606c
static void
.
551c
static long
.
514c
static long
.
407c
static void
.
390c
static void
.
223a
	authreply(m->c->session, id, &r->reply);

.
219a
	c->type = devno('M', 0);
.
218d
198c
static void
.
190c
	c = devattach('/', 0);
.
185c
/*
 * start off the channel as a root device
 * until we've really gotten it started so
 * an early close won't run through devmnt again
 */
static Chan*
.
152,155c
		cclose(c);
.
98c
					cclose(c);
.
36,55c
static void	mattach(Mnt*, Chan*, char*);
static void	mntauth(Mnt*, Mntrpc*, char*, ushort);
static Mnt*	mntchk(Chan*);
static void	mntdirfix(uchar*, Chan*);
static Mntrpc*	mntflushalloc(Mntrpc*);
static void	mntflushfree(Mnt*, Mntrpc*);
static void	mntfree(Mntrpc*);
static void	mntgate(Mnt*);
static void	mntpntfree(Mnt*);
static void	mntqrm(Mnt*, Mntrpc*);
static Mntrpc*	mntralloc(Chan*);
static long	mntrdwr(int, Chan*, void*, long, vlong);
static long	mnt9prdwr(int, Chan*, void*, long, vlong);
static void	mntrpcread(Mnt*, Mntrpc*);
static void	mountio(Mnt*, Mntrpc*);
static void	mountmux(Mnt*, Mntrpc*);
static void	mountrpc(Mnt*, Mntrpc*);
static int	rpcattn(void*);
static void	mclose(Mnt*, Chan*);
static Chan*	mntchan(void);
.
## diffname port/devmnt.c 2001/0527
## diff -e /n/emeliedump/2001/0503/sys/src/9/port/devmnt.c /n/emeliedump/2001/0527/sys/src/9/port/devmnt.c
938d
922c
int
.
916,919c
	dirbuf += BIT16SZ;	/* skip count */
	PBIT16(dirbuf, r);
	dirbuf += BIT16SZ;
	PBIT32(dirbuf, c->dev);
.
913c
	uint r;
.
910c
/*
 * Rewrite channel type and dev for in-flight data to
 * reflect local values.  These entries are known to be
 * the first two in the Dir encoding after the count.
 */
void
.
894c
Mnt*
.
875c
void
.
858c
void
.
838c
		new->rpc = mallocz(iounit, 0);
.
821,822c
Mntrpc*
mntralloc(Chan *c, ulong iounit)
.
804c
void
.
785c
	fr = mntralloc(0, iounit);
.
780,781c
Mntrpc*
mntflushalloc(Mntrpc *r, ulong iounit)
.
773a
	print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
.
742c
	uchar *dp;
.
739c
void
.
724c
void
.
721a
	return 0;
.
718,720c
	r->replen = n;
	if(convM2S(r->rpc, n, &r->reply) == 0){
		int i;
		print("bad conversion of received message; %d bytes iounit %ld\n", n, m->c->iounit);
		for(i=0; i<n; i++)
			print("%.2ux ", (uchar)r->rpc[i]);
		print("\n");
		return -1;
.
708,716c
	chunk = m->c->iounit;
	if(chunk == 0 || chunk > m->c->iounit)
		chunk = m->c->iounit;
	r->reply.type = 0;
	r->reply.tag = 0;
	/* read size, then read exactly the right number of bytes */
	n = mntreadn(m->c, r->rpc, BIT32SZ);
	if(n != BIT32SZ){
		if(n > 0)
			print("devmnt expected BIT32SZ got %d\n", n);
		return -1;
	}
	len = GBIT32((uchar*)r->rpc);
	if(len <= BIT32SZ || len > chunk){
		print("devmnt: len %d max messagesize %ld\n", len, m->c->iounit);
		return -1;
	}
	n += mntreadn(m->c, r->rpc+BIT32SZ, len-BIT32SZ);
	if(n != len){
		print("devmnt: length %d expected %d\n", n, len);
		return -1;
	}
.
706c
	int n, len;
	ulong chunk;
.
703c
int
mntreadn(Chan *c, uchar *buf, int n)
{
	int m, dm;

	for(m=0; m<n; m+=dm){
		dm = devtab[c->type]->read(c, buf, n-m, 0);
		if(dm <= 0)
			return 0;
		buf += dm;
	}
	return n;
}

int
.
695c
		if(mntrpcread(m, r) < 0)
			error(Emountrpc);
.
669,675c
	if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
		error(Emountrpc);
.
666c
	if(m->c->iounit == 0)
		panic("iounit");
	n = convS2M(&r->request, r->rpc, m->c->iounit);
.
656c
		r = mntflushalloc(r, m->c->iounit);
.
644c
void
.
610c
void
.
580,586c
		nr = n;
		if(nr > m->c->iounit-IOHDRSZ)
			nr = m->c->iounit-IOHDRSZ;
		if(c->iounit != 0 && nr > c->iounit)
			nr = c->iounit;
		r->request.count = nr;
.
571c
		r = mntralloc(c, m->c->iounit);
.
568c
	if(c->qid.type & QTDIR)
.
518,555c
long
.
506,511d
500a
		}
		if(p != e)
			error(Esbadstat);
.
499c
		for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
			dirlen = BIT16SZ+GBIT16(p);
			if(p+dirlen > e)
				break;
			validstat(p, dirlen);
.
477c
	if(c->qid.type & QTDIR) {
.
473c
	int nc, cache, isdir, dirlen;
.
463,468d
460a
	return n;
.
457c
	r->request.nstat = n;
	r->request.stat = dp;
.
450c
	r = mntralloc(c, m->c->iounit);
.
443,444c
static int
mntwstat(Chan *c, uchar *dp, int n)
.
411c
void
.
394c
void
.
379c
	r = mntralloc(c, m->c->iounit);
.
346,369c
	mntopencreate(Tcreate, c, name, omode, perm);
.
342a
static Chan*
mntopen(Chan *c, int omode)
{
	return mntopencreate(Topen, c, nil, omode, 0);
}

.
332a
	c->iounit = r->reply.iounit;
.
327a
	if(type == Tcreate){
		r->request.perm = perm;
		r->request.name = name;
	}
.
325c
	r->request.type = type;
.
320c
	r = mntralloc(c, m->c->iounit);
.
314c
mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
.
310a
	return n;
.
307,308c
	if(r->reply.nstat >= 1<<(8*BIT16SZ))
		error("returned stat buffer count too large");

	if(r->reply.nstat > n){
		/* doesn't fit; just patch the count and return */
		PBIT16((uchar*)dp, r->reply.nstat);
		n = BIT16SZ;
	}else{
		n = r->reply.nstat;
		memmove(dp, r->reply.stat, n);
		validstat(dp, n);
		mntdirfix(dp, c);
	}
.
298c
	r = mntralloc(c, m->c->iounit);
.
296a
	if(n < BIT16SZ)
		error(Eshortstat);
.
291,292c
static int
mntstat(Chan *c, uchar *dp, int n)
.
288c
	poperror();
	return wq;
.
284,285c
    Return:
.
279,282c
	wq->nqid = r->reply.nwqid;
	for(i=0; i<wq->nqid; i++)
		wq->qid[i] = r->reply.wqid[i];
.
261,277c
	/* move new fid onto mnt device and update its qid */
	if(wq->clone != nil){
		if(wq->clone != c){
			wq->clone->type = c->type;
			incref(m);
		}
		if(r->reply.nwqid > 0)
			wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
.
257,259c
	if(r->reply.nwqid > nname)
		error("too many QIDs returned by walk");
	if(r->reply.nwqid < nname){
		if(alloc)
			cclose(nc);
		wq->clone = nil;
		if(r->reply.nwqid == 0){
			free(wq);
			wq = nil;
			goto Return;
		}
	}
.
254a
	r->request.nwname = nname;
	memmove(r->request.wname, name, nname*sizeof(char*));

.
251,252c
	r->request.type = Twalk;
.
249a
		return nil;
.
247,248d
244a
	wq->clone = nc;

.
240,242c
	r = mntralloc(c, m->c->iounit);
	if(nc == nil){
		nc = devclone(c);
		/*
		 * Until the other side accepts this fid, we can't mntclose it.
		 * Therefore set type to 0 for now; rootclose is known to be safe.
		 */
		nc->type = 0;
.
238a
	if(nname > MAXWELEM)
		error("devmnt: too many name elements");
	alloc = 0;
	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
	if(waserror()){
		if(alloc && wq->clone!=nil)
			cclose(wq->clone);
		free(wq);
		return nil;
	}

	alloc = 0;
.
237c
	Walkqid *wq;
extern int chandebug;
if(chandebug){
	print("mntwalk ");
	for(i=0; i<nname; i++)
		print("%s/", name[i]);
	print("\n");
}
.
234a
	int i, alloc;
.
232,233c
static Walkqid*
mntwalk(Chan *c, Chan *nc, char **name, int nname)
.
226,227d
221d
216,218c
	r->request.uname = up->user;
	r->request.aname = spec;
	r->request.nauth = 0;
	r->request.auth = (uchar*)"";
.
206c
	r = mntralloc(0, m->c->iounit);
.
203d
200c
void
.
192c
	c = devattach('M', 0);
.
182,187c
Chan*
.
169c
		c->qid.type |= QTDIR;
.
167c
	if(mc->type == devno('M', 0) && (c->qid.type&QTDIR) == 0) {
.
161c
	 * If QTDIR is clear in the returned qid, the foreign server is
.
152c
		/* Close must not be called since it will
		 * call mnt recursively
		 */
		chanfree(c);
.
145,146d
132,140c
	if(m->c->iounit == 0)
		m->c->iounit = MAXRPC;
.
98c
					chanfree(c);
.
78d
68a
	fmtinstall('F', fcallconv);
	fmtinstall('D', dirconv);
	fmtinstall('M', dirmodeconv);
.
56a
char	Esbadstat[] = "invalid directory entry received from server";

.
36,55c
void	mattach(Mnt*, Chan*, char*);
void	mntauth(Mnt*, Mntrpc*, char*, ushort);
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*);
void	mclose(Mnt*, Chan*);
Chan*	mntchan(void);
.
16c
	uchar*	rpc;		/* I/O Data buffer */
.
13c
	Fcall reply;		/* Incoming reply */
.
7a
#define MAXRPC (IOHDRSZ+8192)

.
## diffname port/devmnt.c 2001/0601
## diff -e /n/emeliedump/2001/0527/sys/src/9/port/devmnt.c /n/emeliedump/2001/0601/sys/src/9/port/devmnt.c
717c
	n += mntreadn(m->c, r->rpc+BIT32SZ, len-BIT32SZ, 1);
.
706c
	n = mntreadn(m->c, r->rpc, BIT32SZ, 0);
.
686a
		if(uninterruptable)
			poperror();
.
685a
		if(uninterruptable)
			if(waserror()){
				/* user DEL may stop assembly; wait for full 9P msg. */
				if(strstr(up->error, "interrupt") == nil)
					nexterror();
				dm = 0;
				continue;
			}
.
681c
mntreadn(Chan *c, uchar *buf, int n, int uninterruptable)
.
230,231c

if(0){
.
158,174d
83c
	Chan *c;
.
## diffname port/devmnt.c 2001/0619
## diff -e /n/emeliedump/2001/0601/sys/src/9/port/devmnt.c /n/emeliedump/2001/0619/sys/src/9/port/devmnt.c
865a
	if(r->b != nil)
		freeblist(r->b);
.
859a
	new->b = nil;
.
763a
				q->b = r->b;
				r->b = nil;
.
760,762d
746d
724a

	/* hang the data off of the fcall struct */
	l = &r->b;
	*l = nil;
	do {
		b = qremove(m->q);
		if(hlen > 0){
			b->rp += hlen;
			len -= hlen;
			hlen = 0;
		}
		i = BLEN(b);
		if(i <= len){
			len -= i;
			*l = b;
			l = &(b->next);
		} else {
			/* split block and put unused bit back */
			nb = allocb(i-len);
			memmove(nb->wp, b->rp+len, i-len);
			b->wp = b->rp+len;
			nb->wp += i-len;
			qputback(m->q, nb);
			*l = b;
			return 0;
		}
	}while(len > 0);

.
716,722c
	if(convM2S(nb->rp, len, &r->reply) <= 0){
		/* bad message, dump it */
		print("mntrpcread: convM2S failed\n");
		qdiscard(m->q, len);
.
714a
	nb = pullupqueue(m->q, hlen);
.
710,713c

	/* pullup the header (i.e. everything except data) */
	t = nb->rp[BIT32SZ];
	switch(t){
	case Rread:
		hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
		break;
	default:
		hlen = len;
		break;
.
705,708c
	nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
	len = GBIT32(nb->rp);

	/* read in the rest of the message */
	while(qlen(m->q) < len){
		b = devtab[m->c->type]->bread(m->c, 2*MAXRPC, 0);
		if(b == nil)
			return -1;
		qadd(m->q, b);
.
698,703c

	/* read at least length, type, and tag and pullup to a single block */
	while(qlen(m->q) < BIT32SZ+BIT8SZ+BIT16SZ){
		b = devtab[m->c->type]->bread(m->c, 2*MAXRPC, 0);
		if(b == nil)
			return -1;
		qadd(m->q, b);
.
693,695d
690,691c
	int i, t, len, hlen;
	Block *b, **l, *nb;
.
664,687d
556c
			r->b = bl2mem((uchar*)uba, r->b, nr);
.
431a

	qfree(q);
.
430a
	q = m->q;
.
428d
417a
	Queue *q;
.
214,220d
128a
	m->q = qopen(10*MAXRPC, 0, nil, nil);
.
18a
	Block	*b;		/* reply blocks */
.
15c
	Fcall 	reply;		/* Incoming reply */
.
## diffname port/devmnt.c 2001/0807
## diff -e /n/emeliedump/2001/0619/sys/src/9/port/devmnt.c /n/emeliedump/2001/0807/sys/src/9/port/devmnt.c
460a
	poperror();
	mntfree(r);
	return n;
}

int
mntauth(Chan *c, uchar *auth, int nauth, uchar *rauth, int nrauth)
{
	int n;
	Mnt *m;
	Mntrpc *r;

	m = mntchk(c);
	r = mntralloc(c, m->c->iounit);
	if(waserror()) {
		mntfree(r);
		nexterror();
	}
	r->request.type = Tauth;
	r->request.fid = c->fid;
	r->request.nauth = nauth;
	r->request.auth = auth;
	mountrpc(m, r);
	n = r->reply.nrauth;
	if(nrauth < n)
		error(Eshort);
	memmove(rauth, r->reply.rauth, n);
.
196,197d
40d
## diffname port/devmnt.c 2001/0808
## diff -e /n/emeliedump/2001/0807/sys/src/9/port/devmnt.c /n/emeliedump/2001/0808/sys/src/9/port/devmnt.c
458,484d
194a
	r->request.nauth = 0;
	r->request.auth = (uchar*)"";
.
39a
void	mntauth(Mnt*, Mntrpc*, char*, ushort);
.
## diffname port/devmnt.c 2001/0819
## diff -e /n/emeliedump/2001/0808/sys/src/9/port/devmnt.c /n/emeliedump/2001/0819/sys/src/9/port/devmnt.c
920c
		panic("mntchk 3: can't happen");
.
917c
	 * Was it closed and reused (was error(Eshutdown); now, it can't happen)
.
915a
	if(c->mchan == nil)
		panic("mntchk 1: nil mchan c %s\n", c2name(c));

	m = c->mchan->mux;

	if(m == nil)
		print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan));

.
914c
	/* This routine is mostly vestiges of prior lives; now it's just sanity checking */
.
860a
		if(new->rpclen < iounit){
			free(new->rpc);
			new->rpc = mallocz(iounit, 0);
			if(new->rpc == nil){
				free(new);
				mntalloc.nrpcused--;
				unlock(&mntalloc);
				exhausted("mount rpc buffer");
			}
			new->rpclen = iounit;
		}
.
855a
		new->rpclen = iounit;
.
405d
397,399d
393c
muxclose(Mnt *m)
.
388d
380d
271c
			wq->clone->mchan = c->mchan;
			incref(c->mchan);
.
215a
	if(nc != nil)
		print("mntwalk: nc != nil\n");
.
207a
Chan*
mntchan(void)
{
	Chan *c;

	c = devattach('M', 0);
	lock(&mntalloc);
	c->dev = mntalloc.id++;
	unlock(&mntalloc);

	if(c->mchan)
		panic("mntchan non-zero %p", c->mchan);
	return c;
}

.
205a

	poperror();	/* c */

	if(bogus.flags&MCACHE)
		c->flag |= CCACHE;
	return c;
.
204c
	poperror();	/* r */
.
201a
	incref(m->c);
.
195,197c
	r->request.aname = bogus.spec;
.
193a
	if(bogus.authchan == nil)
		r->request.afid = NOFID;
	else
		r->request.afid = bogus.authchan->fid;
.
185d
183a
	bogus = *((struct bogus *)muxattach);
	c = bogus.chan;

	m = c->mux;

	if(m == nil){
		mntversion(c, nil, 0, 0);
		m = c->mux;
		if(m == nil)
			error(Enoversion);
	}

	c = mntchan();
	if(waserror()) {
		/* Close must not be called since it will
		 * call mnt recursively
		 */
		chanfree(c);
		nexterror();
	}

.
182a
	struct bogus{
		Chan	*chan;
		Chan	*authchan;
		char	*spec;
		int	flags;
	}bogus;
.
181a
	Mnt *m;
	Chan *c;
.
179,180c
static Chan*
mntattach(char *muxattach)
.
176a

.
175a
	poperror();	/* c */

.
171,174c
	poperror();	/* r */
	mntfree(r);
.
166,169c
	c->qid = r->reply.aqid;
	c->mchan = m->c;
	incref(m->c);
	c->mqid = c->qid;
	c->mode = ORDWR;
.
163,164c
	r->request.type = Tauth;
	r->request.afid = c->fid;
	r->request.uname = up->user;
	r->request.aname = spec;
	mountrpc(m, r);
.
160,161c
	if(waserror()) {
		mntfree(r);
		nexterror();
	}
.
157,158c
	r = mntralloc(0, m->c->iounit);
.
149d
146a
	return k;
}

Chan*
mntauth(Chan *c, char *spec)
{
	Mnt *m;
	Mntrpc *r;

	m = c->mux;

	if(m == nil){
		mntversion(c, VERSION9P, MAXRPC, 0);
		m = c->mux;
		if(m == nil)
			error(Enoversion);
	}

.
145c
	k = strlen(f.version);
	if(returnlen > 0){
		if(returnlen < k)
			error(Eshort);
		memmove(version, f.version, k);
	}
.
143c
	poperror();	/* c */
	qunlock(&c->umqlock);
.
138,141c
	unlock(m);
.
136a

	c->flag |= CMSG;
	c->mux = m;
.
134d
132a
	poperror();	/* msg */
	free(msg);

.
128a
	kstrdup(&m->version, f.version);
.
116a
	f.type = Tversion;
	f.tag = NOTAG;
	f.msize = msize;
	f.version = v;
	msg = malloc(8192+IOHDRSZ);
	if(msg == nil)
		exhausted("version memory");
	if(waserror()){
		free(msg);
		nexterror();
	}
	k = convS2M(&f, msg, 8192+IOHDRSZ);
	if(k == 0)
		error("bad fversion conversion on send");

	lock(c);
	oo = c->offset;
	c->offset += k;
	unlock(c);

	l = devtab[c->type]->write(c, msg, k, oo);

	if(l < k){
		lock(c);
		c->offset -= k - l;
		unlock(c);
		error("short write in fversion");
	}

	/* 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");

	lock(c);
	c->offset += k;
	unlock(c);

	l = convM2S(msg, k, &f);
	if(l != k)
		error("bad fversion conversion on reply");
	if(f.type != Rversion)
		error("unexpected reply type in fversion");
	if(f.msize > msize)
		error("server tries to increase msize in fversion");
	if(f.msize<256 || f.msize>1024*1024)
		error("nonsense value of msize in fversion");
	if(strncmp(f.version, v, strlen(f.version)) != 0)
		error("bad 9P version returned from server");
	c->iounit = f.msize;
	if(c->iounit == 0)
		c->iounit = MAXRPC;

	/* now build Mnt associated with this connection */
	lock(&mntalloc);
.
114a
		if(returnlen > 0){
			if(returnlen < k)
				error(Eshort);
			memmove(version, buf, k);
		}
		return k;
.
94,113c
	/* defaults */
	if(msize == 0)
		msize = MAXRPC-IOHDRSZ;
	v = version;
	if(v == nil || v[0] == '\0')
		v = VERSION9P;

	/* validity */
	if(msize < 0)
		error("bad iounit in version call");
	if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
		error("bad 9P version specification");

	m = c->mux;

	if(m != nil){
		qunlock(&c->umqlock);
		poperror();

		strecpy(buf, buf+sizeof buf, m->version);
		k = strlen(buf);
		if(strncmp(buf, v, k) != 0){
			snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
			error(buf);
.
91,92c
	qlock(&c->umqlock);	/* make sure no one else does this until we've established ourselves */
	if(waserror()){
		qunlock(&c->umqlock);
		nexterror();
	}
.
84,89c
	char *v;
	long k, l;
	uvlong oo;
	char buf[128];
.
82a
	Fcall f;
	uchar *msg;
.
80,81c
/*
 * Version is not multiplexed: message sent only once per connection.
 */
long
mntversion(Chan *c, char *version, int msize, int returnlen)
.
59a
char Enoversion[] = "version not established for mount channel";
.
56d
40d
18a
	uint		rpclen;	/* len of buffer */
.
7a
/*
 * References are managed as follows:
 * The channel to the server - a network connection or pipe - has one
 * reference for every Chan open on the server.  The server channel has
 * c->mux set to the Mnt used for muxing control to that server.  Mnts
 * have no reference count; they go away when c goes away.
 * Each channel derived from the mount point has mchan set to c,
 * and increfs/decrefs mchan to manage references on the server
 * connection.
 */

.
## diffname port/devmnt.c 2001/0820
## diff -e /n/emeliedump/2001/0819/sys/src/9/port/devmnt.c /n/emeliedump/2001/0820/sys/src/9/port/devmnt.c
1034c
			new->rpclen = msize;
.
1027c
			new->rpc = mallocz(msize, 0);
.
1025c
		if(new->rpclen < msize){
.
1019c
		new->rpclen = msize;
.
1013c
		new->rpc = mallocz(msize, 0);
.
997c
mntralloc(Chan *c, ulong msize)
.
789,791c
	if(m->msize == 0)
		panic("msize");
	n = convS2M(&r->request, r->rpc, m->msize);
.
779c
		r = mntflushalloc(r, m->msize);
.
705,708c
		if(nr > m->msize-IOHDRSZ)
			nr = m->msize-IOHDRSZ;
.
695c
		r = mntralloc(c, m->msize);
.
614c
	r = mntralloc(c, m->msize);
.
568a
	free(m->version);
	m->version = nil;
.
546c
	r = mntralloc(c, m->msize);
.
516a
	if(c->iounit > m->msize-IOHDRSZ)
		c->iounit = m->msize-IOHDRSZ;
.
499c
	r = mntralloc(c, m->msize);
.
465c
	r = mntralloc(c, m->msize);
.
397c
	r = mntralloc(c, m->msize);
.
327c
	r = mntralloc(0, m->msize);
.
265c
	r = mntralloc(0, m->msize);
.
213a
	m->msize = f.msize;
.
210a
	m->version = nil;
.
193,195d
113c
		msize = MAXRPC;
	if(msize > c->iounit && c->iounit != 0)
		msize = c->iounit;
.
## diffname port/devmnt.c 2001/0822
## diff -e /n/emeliedump/2001/0820/sys/src/9/port/devmnt.c /n/emeliedump/2001/0822/sys/src/9/port/devmnt.c
413d
## diffname port/devmnt.c 2001/0825
## diff -e /n/emeliedump/2001/0822/sys/src/9/port/devmnt.c /n/emeliedump/2001/0825/sys/src/9/port/devmnt.c
850c
		qaddlist(m->q, b);
.
840c
		qaddlist(m->q, b);
.
## diffname port/devmnt.c 2001/0905
## diff -e /n/emeliedump/2001/0825/sys/src/9/port/devmnt.c /n/emeliedump/2001/0905/sys/src/9/port/devmnt.c
673d
## diffname port/devmnt.c 2001/0918
## diff -e /n/emeliedump/2001/0905/sys/src/9/port/devmnt.c /n/emeliedump/2001/0918/sys/src/9/port/devmnt.c
188a
	}
.
187c
	if(f.type != Rversion){
		if(f.type == Rerror)
			error(f.ename);
.
## diffname port/devmnt.c 2001/0924
## diff -e /n/emeliedump/2001/0918/sys/src/9/port/devmnt.c /n/emeliedump/2001/0924/sys/src/9/port/devmnt.c
779c
		if(strcmp(up->errstr, Eintr) != 0){
.
## diffname port/devmnt.c 2001/1206
## diff -e /n/emeliedump/2001/0924/sys/src/9/port/devmnt.c /n/emeliedump/2001/1206/sys/src/9/port/devmnt.c
520c
	if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
.
## diffname port/devmnt.c 2002/0104
## diff -e /n/emeliedump/2001/1206/sys/src/9/port/devmnt.c /n/emeliedump/2002/0104/sys/src/9/port/devmnt.c
452a

.
## diffname port/devmnt.c 2002/0109
## diff -e /n/emeliedump/2002/0104/sys/src/9/port/devmnt.c /n/emeliedump/2002/0109/sys/src/9/port/devmnt.c
1144a
	devshutdown,
.
453d
## diffname port/devmnt.c 2002/0217
## diff -e /n/emeliedump/2002/0109/sys/src/9/port/devmnt.c /n/emeliedump/2002/0217/sys/src/9/port/devmnt.c
84,86c
	fmtinstall('F', fcallfmt);
	fmtinstall('D', dirfmt);
	fmtinstall('M', dirmodefmt);
.
## diffname port/devmnt.c 2002/0615
## diff -e /n/emeliedump/2002/0217/sys/src/9/port/devmnt.c /n/emeliedump/2002/0615/sys/src/9/port/devmnt.c
849c
		b = devtab[m->c->type]->bread(m->c, m->msize, 0);
.
839c
		b = devtab[m->c->type]->bread(m->c, m->msize, 0);
.
86c
/*	fmtinstall('M', dirmodefmt);  No!  Clashes with eipfmt [sape] */
.
## diffname port/devmnt.c 2002/0919
## diff -e /n/emeliedump/2002/0615/sys/src/9/port/devmnt.c /n/emeliedump/2002/0919/sys/src/9/port/devmnt.c
1058a
		freetag(r->request.tag);
.
1024c
		new->request.tag = alloctag();
.
999a
int
alloctag(void)
{
	int i, j;
	ulong v;

	for(i = 0; i < NMASK; i++){
		v = mntalloc.tagmask[i];
		if(v == ~0UL)
			continue;
		for(j = 0; j < 1<<TAGSHIFT; j++)
			if((v & (1<<j)) == 0){
				mntalloc.tagmask[i] |= 1<<j;
				return (i<<TAGSHIFT) + j;
			}
	}
	panic("no friggin tags left");
	return NOTAG;
}

void
freetag(int t)
{
	mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
}

.
86c
/* We can't install %M since eipfmt does and is used in the kernel [sape] */
.
83c
	mntalloc.tagmask[0] = 1;			/* don't allow 0 as a tag */
	mntalloc.tagmask[NMASK-1] = 0x80000000UL;	/* don't allow NOTAG */
.
74,78d
71a

.
48c
	ulong	tagmask[NMASK];
.
38a
enum
{
	TAGSHIFT = 5,			/* ulong has to be 32 bits */
	TAGMASK = (1<<TAGSHIFT)-1,
	NMASK = (64*1024)>>TAGSHIFT,
};

.
## diffname port/devmnt.c 2002/1213
## diff -e /n/emeliedump/2002/0919/sys/src/9/port/devmnt.c /n/emeliedump/2002/1213/sys/src/9/port/devmnt.c
857a
	if(doread(m, len) < 0)
		return -1;
.
851,856c
	/* read in the rest of the message, avoid rediculous (for now) message sizes */
	len = GBIT32(nb->rp);
	if(len > m->msize){
		qdiscard(m->q, qlen(m->q));
		return -1;
.
849d
842,847c
	if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
		return -1;
.
831a
static int
doread(Mnt *m, int len)
{
	Block *b;

	while(qlen(m->q) < len){
		b = devtab[m->c->type]->bread(m->c, m->msize, 0);
		if(b == nil)
			return -1;
		if(BLEN(b) == 0){
			freeblist(b);
			return -1;
		}
		qaddlist(m->q, b);
	}
	return 0;
}

.
## diffname port/devmnt.c 2003/0101
## diff -e /n/emeliedump/2002/1213/sys/src/9/port/devmnt.c /n/emeliedump/2003/0101/sys/src/9/port/devmnt.c
484a
		/*
		 * 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).
		 */
.
## diffname port/devmnt.c 2003/0509
## diff -e /n/emeliedump/2003/0101/sys/src/9/port/devmnt.c /n/emeliedump/2003/0509/sys/src/9/port/devmnt.c
1159c
		print("mntchk 2: nil mux c %s c->mchan %s \n", channame(c), channame(c->mchan));
.
1154c
		panic("mntchk 1: nil mchan c %s\n", channame(c));
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.