git: 9front

Download patch

ref: 69481a8a50fc689c00b82fe96640856b6a83659b
parent: eefa37153ed374f925ad701a40eb8f8629252496
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Nov 29 12:23:00 EST 2025

devmnt: Implement bread/bwrite handlers

This is purely an optimisation, avoiding
the allocation of a block and the copying
of data involved.

The bread()/bwrite() handlers are used by
pio() and the network stack, so it mostly
has impact when using 9p-server network
device like nusb/ether or demand paging.

For mntbread():

We can just use the data blocks read from
the mount chan, no copying needed.

For mntbwrite():

Just prepend a Twrite header to the passed
in data  block.

Note, this is only done when request.count
is <= iounit and the mount is not cached,
to presereve the behaviour when transaction
must be split into multiple operations.

The mntcache() function was simplified
with the availability of Twritehdr constant,
which was needed for mntbwrite().

--- a/sys/src/9/port/devmnt.c
+++ b/sys/src/9/port/devmnt.c
@@ -38,6 +38,9 @@
 	TAGSHIFT = 5,
 	TAGMASK = (1<<TAGSHIFT)-1,
 	NMASK = (64*1024)>>TAGSHIFT,
+
+	/* offset to data in Twrite request */
+	Twritehdr = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ+BIT64SZ+BIT32SZ,
 };
 
 static struct Mntalloc
@@ -666,45 +669,105 @@
 mntcache(Mntrpc *r)
 {
 	ulong n, m;
-	vlong off;
+	vlong o;
 	Block *b;
-	Chan *c;
 
-	c = r->c;
-	if(!cachedchan(c))
-		return;
-	off = r->request.offset;
+	n = r->request.count;
+	o = r->request.offset;
+	if(r->reply.count < n)
+		n = r->reply.count;
 	switch(r->reply.type){
 	case Rread:
-		m = r->reply.count;
-		if(m > r->request.count)
-			m = r->request.count;
-		for(b = r->b; m > 0 && b != nil; m -= n, b = b->next) {
-			n = BLEN(b);
-			if(m < n)
-				n = m;
-			cupdate(c, b->rp, n, off);
-			off += n;
+		for(b = r->b; n > 0 && b != nil; n -= m, b = b->next) {
+			m = BLEN(b);
+			if(n < m)
+				m = n;
+			cupdate(r->c, b->rp, m, o);
+			o += m;
 		}
 		break;
 	case Rwrite:
-		b = r->w;
-		if(convM2S(b->rp, BLEN(b), &r->request) == 0)
-			panic("convM2S");
-		m = r->reply.count;
-		if(m > r->request.count)
-			m = r->request.count;
-		cwrite(c, (uchar*)r->request.data, m, off);
+		if((b = r->w) != nil)	/* saved Twrite request */
+			cwrite(r->c, b->rp + Twritehdr, n, o);
 		break;
 	}
 }
 
+static Block*
+mntbread(Chan *c, long n, ulong off)
+{
+	Mnt *m;
+ 	Mntrpc *r;
+	Block *b;
+
+	if(n > c->iounit || cachedchan(c))
+		return devbread(c, n, off);
+
+	m = mntchk(c);
+	r = mntralloc(c);
+	if(waserror()) {
+		mntfree(r);
+		nexterror();
+	}
+	r->request.type = Tread;
+	r->request.fid = c->fid;
+	r->request.offset = off;
+	r->request.count = n;
+	mountrpc(m, r);
+	b = concatblock(r->b);
+	r->b = nil;
+	if(r->reply.count < n)
+		n = r->reply.count;
+	if(BLEN(b) > n)
+		b->wp = b->rp + n;
+	mntfree(r);
+	poperror();
+
+	return b;
+}
+
 static long
+mntbwrite(Chan *c, Block *b, ulong off)
+{
+	Mnt *m;
+ 	Mntrpc *r;
+	long n;
+
+	n = BLEN(b);
+	if(n > c->iounit || cachedchan(c))
+		return devbwrite(c, b, off);
+
+	m = mntchk(c);
+	r = mntralloc(c);
+	if(waserror()) {
+		mntfree(r);
+		nexterror();
+	}
+	r->request.type = Twrite;
+	r->request.fid = c->fid;
+	r->request.offset = off;
+	r->request.count = n;
+	/* prepend Twrite header */
+	b = padblock(b, Twritehdr);
+	r->request.data = (char*)b->rp + Twritehdr;
+	r->w = b;
+	if(convS2M(&r->request, b->rp, BLEN(b)) <= 0)
+		error(Emsize);
+	mountrpc(m, r);
+	if(r->reply.count < n)
+		n = r->reply.count;
+	mntfree(r);
+	poperror();
+
+	return n;
+}
+
+static long
 mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
 {
 	Mnt *m;
  	Mntrpc *r;
-	char *uba;
+	uchar *uba;
 	ulong cnt, nr, nreq;
 
 	m = mntchk(c);
@@ -717,7 +780,7 @@
 			nreq = c->iounit;
 
 		if(type == Tread && cachedchan(c)) {
-			nr = cread(c, (uchar*)uba, nreq, off);
+			nr = cread(c, uba, nreq, off);
 			if(nr > 0) {
 				nreq = nr;
 				goto Next;
@@ -732,15 +795,16 @@
 		r->request.type = type;
 		r->request.fid = c->fid;
 		r->request.offset = off;
-		r->request.data = uba;
+		r->request.data = (char*)uba;
 		r->request.count = nreq;
 		mountrpc(m, r);
-		mntcache(r);
+		if(cachedchan(c))
+			mntcache(r);
 		nr = r->reply.count;
 		if(nr > nreq)
 			nr = nreq;
 		if(type == Tread)
-			nr = readblist(r->b, (uchar*)uba, nr, 0);
+			nr = readblist(r->b, uba, nr, 0);
 		mntfree(r);
 		poperror();
 
@@ -1037,19 +1101,27 @@
 	unlock(m);
 
 	/* Transmit a file system rpc */
-	n = sizeS2M(&r->request);
-	b = allocb(n);
-	if(waserror()){
-		freeb(b);
-		nexterror();
+	if((b = r->w) != nil) {
+		/* Already converted by mntbwrite() */
+		r->w = nil;
+	} else {
+		n = sizeS2M(&r->request);
+		b = allocb(n);
+		if(waserror()){
+			freeb(b);
+			nexterror();
+		}
+		n = convS2M(&r->request, b->wp, n);
+		if(n <= 0 || n > m->msize)
+			error(Emsize);
+		b->wp += n;
+
+		/* Save request for mntcache() */
+		if(r->request.type == Twrite && cachedchan(r->c))
+			r->w = copyblock(b, n);
+
+		poperror();
 	}
-	n = convS2M(&r->request, b->wp, n);
-	if(n <= 0 || n > m->msize)
-		error(Emsize);
-	b->wp += n;
-	if(r->request.type == Twrite && cachedchan(r->c))
-		r->w = copyblock(b, n);
-	poperror();
 	devtab[m->c->type]->bwrite(m->c, b, 0);
 
 	/* Gate readers onto the mount point one at a time */
@@ -1417,9 +1489,9 @@
 	mntcreate,
 	mntclose,
 	mntread,
-	devbread,
+	mntbread,
 	mntwrite,
-	devbwrite,
+	mntbwrite,
 	mntremove,
 	mntwstat,
 };
--